blob: feeff6896bc42b63b7bff9026a54527f0616b6d0 [file] [log] [blame]
/*
* Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
* DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
* RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE OR
* ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
* FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
* SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
* THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*/
package org.apache.cocoon.faces.samples.components.components;
import javax.faces.component.UICommand;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
/**
* <p>{@link MapComponent} is a JavaServer Faces component that corresponds
* to a client-side image map. It can have one or more children of type
* {@link AreaComponent}, each representing hot spots, which a user can
* click on and mouse over.</p>
*
* <p>This component is a source of {@link AreaSelectedEvent} events,
* which are fired whenever the current area is changed.</p>
*/
public class MapComponent extends UICommand {
// ------------------------------------------------------ Instance Variables
private String current = null;
private MethodBinding action = null;
private MethodBinding actionListener = null;
private boolean immediate = false;
private boolean immediateSet = false;
// --------------------------------------------------------------Constructors
public MapComponent() {
super();
addDefaultActionListener(getFacesContext());
}
// -------------------------------------------------------------- Properties
/**
* <p>Return the alternate text label for the currently selected
* child {@link AreaComponent}.</p>
*/
public String getCurrent() {
return (this.current);
}
/**
* <p>Set the alternate text label for the currently selected child.
* If this is different from the previous value, fire an
* {@link AreaSelectedEvent} to interested listeners.</p>
*
* @param current The new alternate text label
*/
public void setCurrent(String current) {
String previous = this.current;
this.current = current;
// Fire an {@link AreaSelectedEvent} if appropriate
if ((previous == null) && (current == null)) {
return;
} else if ((previous != null) && (current != null) &&
(previous.equals(current))) {
return;
} else {
this.queueEvent(new AreaSelectedEvent(this));
}
}
/**
* <p>Return the component family for this component.</p>
*/
public String getFamily() {
return ("Map");
}
// ----------------------------------------------------- Event Methods
//private static Class signature[] = {AreaSelectedEvent.class};
/**
* <p>In addition to to the default <code>UIComponentBase#broadcast</code>
* processing, pass the {@link ActionEvent} being broadcast to the
* method referenced by <code>actionListener</code> (if any).</p>
*
* @param event {@link FacesEvent} to be broadcast
*
* @throws AbortProcessingException Signal the JavaServer Faces
* implementation that no further processing on the current event
* should be performed
* @throws IllegalArgumentException if the implementation class
* of this {@link FacesEvent} is not supported by this component
* @throws IllegalStateException if PhaseId.ANY_PHASE is passed
* for the phase identifier
* @throws NullPointerException if <code>event</code> is
* <code>null</code>
*/
public void broadcast(FacesEvent event) throws AbortProcessingException {
// Perform standard superclass processing
super.broadcast(event);
// Notify the specified action listener method (if any)
MethodBinding mb = getActionListener();
if (mb != null) {
if ((isImmediate() &&
event.getPhaseId().equals(PhaseId.APPLY_REQUEST_VALUES)) ||
(!isImmediate() &&
event.getPhaseId().equals(PhaseId.INVOKE_APPLICATION))) {
FacesContext context = getFacesContext();
mb.invoke(context, new Object[]{event});
}
}
}
/**
* <p>Intercept <code>queueEvent</code> and mark the phaseId for the
* event to be <code>PhaseId.APPLY_REQUEST_VALUES</code> if the
* <code>immediate</code> flag is true,
* <code>PhaseId.INVOKE_APPLICATION</code> otherwise.</p>
*/
public void queueEvent(FacesEvent e) {
if (e instanceof ActionEvent) {
if (isImmediate()) {
e.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else {
e.setPhaseId(PhaseId.INVOKE_APPLICATION);
}
}
super.queueEvent(e);
}
// ----------------------------------------------------- StateHolder Methods
/**
* <p>Return the state to be saved for this component.</p>
*
* @param context <code>FacesContext</code> for the current request
*/
public Object saveState(FacesContext context) {
removeDefaultActionListener(context);
Object values[] = new Object[6];
values[0] = super.saveState(context);
values[1] = current;
values[2] = saveAttachedState(context, action);
values[3] = saveAttachedState(context, actionListener);
values[4] = immediate ? Boolean.TRUE : Boolean.FALSE;
values[5] = immediateSet ? Boolean.TRUE : Boolean.FALSE;
addDefaultActionListener(context);
return (values);
}
/**
* <p>Restore the state for this component.</p>
*
* @param context <code>FacesContext</code> for the current request
* @param state State to be restored
*/
public void restoreState(FacesContext context, Object state) {
removeDefaultActionListener(context);
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
current = (String) values[1];
action = (MethodBinding) restoreAttachedState(context, values[2]);
actionListener = (MethodBinding) restoreAttachedState(context,
values[3]);
immediate = ((Boolean) values[4]).booleanValue();
immediateSet = ((Boolean) values[5]).booleanValue();
addDefaultActionListener(context);
}
// ----------------------------------------------------- Private Methods
// Add the default action listener
private void addDefaultActionListener(FacesContext context) {
ActionListener listener =
context.getApplication().getActionListener();
addActionListener(listener);
}
// Remove the default action listener
private void removeDefaultActionListener(FacesContext context) {
removeActionListener(context.getApplication().getActionListener());
}
}