001: /*
002: * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or
005: * without modification, are permitted provided that the following
006: * conditions are met:
007: *
008: * - Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: *
011: * - Redistribution in binary form must reproduce the above
012: * copyright notice, this list of conditions and the following
013: * disclaimer in the documentation and/or other materials
014: * provided with the distribution.
015: *
016: * Neither the name of Sun Microsystems, Inc. or the names of
017: * contributors may be used to endorse or promote products derived
018: * from this software without specific prior written permission.
019: *
020: * This software is provided "AS IS," without a warranty of any
021: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
022: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
023: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
024: * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
025: * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
026: * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE OR
027: * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
028: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
029: * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
030: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
031: * THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
032: * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
033: *
034: * You acknowledge that this software is not designed, licensed or
035: * intended for use in the design, construction, operation or
036: * maintenance of any nuclear facility.
037: */
038:
039: package org.apache.cocoon.faces.samples.components.components;
040:
041: import javax.faces.component.UICommand;
042: import javax.faces.context.FacesContext;
043: import javax.faces.el.MethodBinding;
044: import javax.faces.event.AbortProcessingException;
045: import javax.faces.event.ActionEvent;
046: import javax.faces.event.ActionListener;
047: import javax.faces.event.FacesEvent;
048: import javax.faces.event.PhaseId;
049:
050: /**
051: * <p>{@link MapComponent} is a JavaServer Faces component that corresponds
052: * to a client-side image map. It can have one or more children of type
053: * {@link AreaComponent}, each representing hot spots, which a user can
054: * click on and mouse over.</p>
055: *
056: * <p>This component is a source of {@link AreaSelectedEvent} events,
057: * which are fired whenever the current area is changed.</p>
058: */
059:
060: public class MapComponent extends UICommand {
061:
062: // ------------------------------------------------------ Instance Variables
063:
064: private String current = null;
065:
066: private MethodBinding action = null;
067: private MethodBinding actionListener = null;
068: private boolean immediate = false;
069: private boolean immediateSet = false;
070:
071: // --------------------------------------------------------------Constructors
072:
073: public MapComponent() {
074: super ();
075: addDefaultActionListener(getFacesContext());
076: }
077:
078: // -------------------------------------------------------------- Properties
079:
080: /**
081: * <p>Return the alternate text label for the currently selected
082: * child {@link AreaComponent}.</p>
083: */
084: public String getCurrent() {
085: return (this .current);
086: }
087:
088: /**
089: * <p>Set the alternate text label for the currently selected child.
090: * If this is different from the previous value, fire an
091: * {@link AreaSelectedEvent} to interested listeners.</p>
092: *
093: * @param current The new alternate text label
094: */
095: public void setCurrent(String current) {
096:
097: String previous = this .current;
098: this .current = current;
099:
100: // Fire an {@link AreaSelectedEvent} if appropriate
101: if ((previous == null) && (current == null)) {
102: return;
103: } else if ((previous != null) && (current != null)
104: && (previous.equals(current))) {
105: return;
106: } else {
107: this .queueEvent(new AreaSelectedEvent(this ));
108: }
109:
110: }
111:
112: /**
113: * <p>Return the component family for this component.</p>
114: */
115: public String getFamily() {
116:
117: return ("Map");
118:
119: }
120:
121: // ----------------------------------------------------- Event Methods
122:
123: //private static Class signature[] = {AreaSelectedEvent.class};
124:
125: /**
126: * <p>In addition to to the default <code>UIComponentBase#broadcast</code>
127: * processing, pass the {@link ActionEvent} being broadcast to the
128: * method referenced by <code>actionListener</code> (if any).</p>
129: *
130: * @param event {@link FacesEvent} to be broadcast
131: *
132: * @throws AbortProcessingException Signal the JavaServer Faces
133: * implementation that no further processing on the current event
134: * should be performed
135: * @throws IllegalArgumentException if the implementation class
136: * of this {@link FacesEvent} is not supported by this component
137: * @throws IllegalStateException if PhaseId.ANY_PHASE is passed
138: * for the phase identifier
139: * @throws NullPointerException if <code>event</code> is
140: * <code>null</code>
141: */
142: public void broadcast(FacesEvent event)
143: throws AbortProcessingException {
144:
145: // Perform standard superclass processing
146: super .broadcast(event);
147:
148: // Notify the specified action listener method (if any)
149: MethodBinding mb = getActionListener();
150: if (mb != null) {
151: if ((isImmediate() && event.getPhaseId().equals(
152: PhaseId.APPLY_REQUEST_VALUES))
153: || (!isImmediate() && event.getPhaseId().equals(
154: PhaseId.INVOKE_APPLICATION))) {
155: FacesContext context = getFacesContext();
156: mb.invoke(context, new Object[] { event });
157: }
158: }
159:
160: }
161:
162: /**
163: * <p>Intercept <code>queueEvent</code> and mark the phaseId for the
164: * event to be <code>PhaseId.APPLY_REQUEST_VALUES</code> if the
165: * <code>immediate</code> flag is true,
166: * <code>PhaseId.INVOKE_APPLICATION</code> otherwise.</p>
167: */
168:
169: public void queueEvent(FacesEvent e) {
170: if (e instanceof ActionEvent) {
171: if (isImmediate()) {
172: e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
173: } else {
174: e.setPhaseId(PhaseId.INVOKE_APPLICATION);
175: }
176: }
177: super .queueEvent(e);
178: }
179:
180: // ----------------------------------------------------- StateHolder Methods
181:
182: /**
183: * <p>Return the state to be saved for this component.</p>
184: *
185: * @param context <code>FacesContext</code> for the current request
186: */
187: public Object saveState(FacesContext context) {
188: removeDefaultActionListener(context);
189: Object values[] = new Object[6];
190: values[0] = super .saveState(context);
191: values[1] = current;
192: values[2] = saveAttachedState(context, action);
193: values[3] = saveAttachedState(context, actionListener);
194: values[4] = immediate ? Boolean.TRUE : Boolean.FALSE;
195: values[5] = immediateSet ? Boolean.TRUE : Boolean.FALSE;
196: addDefaultActionListener(context);
197: return (values);
198: }
199:
200: /**
201: * <p>Restore the state for this component.</p>
202: *
203: * @param context <code>FacesContext</code> for the current request
204: * @param state State to be restored
205: */
206: public void restoreState(FacesContext context, Object state) {
207: removeDefaultActionListener(context);
208: Object values[] = (Object[]) state;
209: super .restoreState(context, values[0]);
210: current = (String) values[1];
211: action = (MethodBinding) restoreAttachedState(context,
212: values[2]);
213: actionListener = (MethodBinding) restoreAttachedState(context,
214: values[3]);
215: immediate = ((Boolean) values[4]).booleanValue();
216: immediateSet = ((Boolean) values[5]).booleanValue();
217: addDefaultActionListener(context);
218: }
219:
220: // ----------------------------------------------------- Private Methods
221:
222: // Add the default action listener
223: private void addDefaultActionListener(FacesContext context) {
224: ActionListener listener = context.getApplication()
225: .getActionListener();
226: addActionListener(listener);
227: }
228:
229: // Remove the default action listener
230: private void removeDefaultActionListener(FacesContext context) {
231: removeActionListener(context.getApplication()
232: .getActionListener());
233: }
234:
235: }
|