package prefuse.action.assignment;
import java.util.logging.Logger;
import prefuse.Constants;
import prefuse.action.EncoderAction;
import prefuse.data.expression.Predicate;
import prefuse.data.expression.parser.ExpressionParser;
import prefuse.visual.VisualItem;
/**
* <p>Assignment Action that assigns shape values to VisualItems.
* Shape values are simple integer codes that indicate to
* appropriate renderer instances what shape should be drawn. The default
* list of shape values is included in the {@link prefuse.Constants} class,
* all beginning with the prefix <code>SHAPE</code>. Of course, clients can
* always create their own shape codes that are handled by a custom Renderer.
* </p>
*
* <p>
* By default, a ShapeAction simply sets each VisualItem to be a
* rectangle. Clients can change this default value to achieve uniform shape
* assignment, or can add any number of additional rules for shape assignment.
* Rules are specified by a Predicate instance which, if returning true, will
* trigger that rule, causing either the provided shape value or the result of
* a delegate ShapeAction to be applied. Rules are evaluated in the order in
* which they are added to the ShapeAction, so earlier rules will have
* precedence over rules added later.
* </p>
*
* <p>In addition, subclasses can simply override {@link #getShape(VisualItem)}
* to achieve custom shape assignment. In some cases, this may be the simplest
* or most flexible approach.</p>
*
* <p>This Action only sets the shape field of the VisualItem. For this value
* to have an effect, a renderer instance that takes this shape value
* into account must be used (e.g., {@link prefuse.render.ShapeRenderer}).
* </p>
*
* <p>To automatically assign shape values based on varying values of a
* particular data field, consider using the {@link DataShapeAction}.</p>
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class ShapeAction extends EncoderAction {
protected int m_defaultShape = Constants.SHAPE_RECTANGLE;
/**
* Constructor. A default rectangle shape will be used.
*/
public ShapeAction() {
super();
}
/**
* Constructor. A default rectangle shape will be used.
* @param group the data group processed by this Action.
*/
public ShapeAction(String group) {
super(group);
}
/**
* Constructor with a specified a default shape value.
* @param group the data group processed by this Action.
* @param shape the default shape value to use
*/
public ShapeAction(String group, int shape) {
super(group);
m_defaultShape = shape;
}
/**
* Returns the default shape value assigned to items.
* @return the default shape value
*/
public int getDefaultSize() {
return m_defaultShape;
}
/**
* Sets the default shape value assigned to items. Items will be assigned
* the default shape if they do not match any registered rules.
* @param defaultShape the new default shape value
*/
public void setDefaultShape(int defaultShape) {
m_defaultShape = defaultShape;
}
/**
* Add a shape mapping rule to this ShapeAction. VisualItems that match
* the provided predicate will be assigned the given shape value (assuming
* they do not match an earlier rule).
* @param p the rule Predicate
* @param shape the shape value
*/
public void add(Predicate p, int shape) {
super.add(p, new Integer(shape));
}
/**
* Add a shape mapping rule to this ShapeAction. VisualItems that match
* the provided expression will be assigned the given shape value (assuming
* they do not match an earlier rule). The provided expression String will
* be parsed to generate the needed rule Predicate.
* @param expr the expression String, should parse to a Predicate.
* @param shape the shape value
* @throws RuntimeException if the expression does not parse correctly or
* does not result in a Predicate instance.
*/
public void add(String expr, int shape) {
Predicate p = (Predicate)ExpressionParser.parse(expr);
add(p, shape);
}
/**
* Add a size mapping rule to this ShapeAction. VisualItems that match
* the provided predicate will be assigned the shape value returned by
* the given ShapeAction's getSize() method.
* @param p the rule Predicate
* @param f the delegate ShapeAction to use
*/
public void add(Predicate p, ShapeAction f) {
super.add(p, f);
}
/**
* Add a shape mapping rule to this ShapeAction. VisualItems that match
* the provided expression will be assigned the given shape value (assuming
* they do not match an earlier rule). The provided expression String will
* be parsed to generate the needed rule Predicate.
* @param expr the expression String, should parse to a Predicate.
* @param f the delegate ShapeAction to use
* @throws RuntimeException if the expression does not parse correctly or
* does not result in a Predicate instance.
*/
public void add(String expr, ShapeAction f) {
Predicate p = (Predicate)ExpressionParser.parse(expr);
super.add(p, f);
}
// ------------------------------------------------------------------------
/**
* @see prefuse.action.ItemAction#process(prefuse.visual.VisualItem, double)
*/
public void process(VisualItem item, double frac) {
item.setShape(getShape(item));
}
/**
* Returns a shape value for the given item.
* @param item the item for which to get the shape value
* @return the shape value for the item
*/
public int getShape(VisualItem item) {
Object o = lookup(item);
if ( o != null ) {
if ( o instanceof ShapeAction ) {
return ((ShapeAction)o).getShape(item);
} else if ( o instanceof Number ) {
return ((Number)o).intValue();
} else {
Logger.getLogger(this.getClass().getName())
.warning("Unrecognized Object from predicate chain.");
}
}
return m_defaultShape;
}
} // end of class ShapeAction