/** * Copyright (c) 2004-2006 Regents of the University of California. * See "license-prefuse.txt" for licensing terms. */ package prefuse.action; import prefuse.Visualization; import prefuse.data.expression.Expression; import prefuse.data.expression.ExpressionVisitor; import prefuse.data.expression.ObjectLiteral; import prefuse.data.expression.Predicate; import prefuse.util.PredicateChain; import prefuse.visual.VisualItem; /** * ItemAction instance that can also maintain a collection of rule mappings * that can be used by subclasses to create particular rule-mappings for * encoding data values. * * @author <a href="http://jheer.org">jeffrey heer</a> */ public abstract class EncoderAction extends ItemAction { private PredicateChain m_chain = null; /** * Create a new EncoderAction that processes all data groups. */ public EncoderAction() { super(); } /** * Create a new EncoderAction that processes all groups. * @param vis the {@link prefuse.Visualization} to process * @see Visualization#ALL_ITEMS */ public EncoderAction(Visualization vis) { super(vis); } /** * Create a new EncoderAction that processes the specified group. * @param group the name of the group to process */ public EncoderAction(String group) { super(group); } /** * Create a new EncoderAction that processes the specified group. * @param group the name of the group to process * @param filter the filtering {@link prefuse.data.expression.Predicate} */ public EncoderAction(String group, Predicate filter) { super(group, filter); } /** * Create a new EncoderAction that processes the specified group. * @param vis the {@link prefuse.Visualization} to process * @param group the data group to process */ public EncoderAction(Visualization vis, String group) { super(vis, group); } /** * Create a new EncoderAction that processes the specified group. * @param vis the {@link prefuse.Visualization} to process * @param group the name of the group to process * @param filter the filtering {@link prefuse.data.expression.Predicate} */ public EncoderAction(Visualization vis, String group, Predicate filter) { super(vis, group, filter); } // ------------------------------------------------------------------------ /** * Add a mapping rule to this EncoderAction. This method is protected, * subclasses should crate public add methods of their own to enforce * their own type constraints. * @param p the rule Predicate * @param value the value to map to */ protected void add(Predicate p, Object value) { if ( m_chain == null ) m_chain = new PredicateChain(); if ( value instanceof Action ) ((Action)value).setVisualization(m_vis); m_chain.add(p, value); } /** * Lookup the value mapped to by the given item. * @param item the item to lookup * @return the result of the rule lookup */ protected Object lookup(VisualItem item) { return (m_chain == null ? null : m_chain.get(item)); } /** * Remove all rule mappings from this encoder. */ public void clear() { if ( m_chain != null ) { m_chain.clear(); } } /** * Remove rules using the given predicate from this encoder. * This method will not remove rules in which this predicate is used * within a composite of clauses, such as an AND or OR. It only removes * rules using this predicate as the top-level trigger. * @param p the predicate to remove * @return true if a rule was successfully removed, false otherwise */ public boolean remove(Predicate p) { return ( m_chain != null ? m_chain.remove(p) : false ); } /** * @see prefuse.action.Action#setVisualization(prefuse.Visualization) */ public void setVisualization(Visualization vis) { super.setVisualization(vis); if ( m_chain != null ) m_chain.getExpression().visit(new SetVisualizationVisitor()); } // ------------------------------------------------------------------------ /** * @see prefuse.action.Action#run(double) */ public void run(double frac) { setup(); if ( m_chain != null ) m_chain.getExpression().visit(SetupVisitor.getInstance()); super.run(frac); if ( m_chain != null ) m_chain.getExpression().visit(FinishVisitor.getInstance()); finish(); } /** * Perform any necessary setup before this encoder can be used. By default * does nothing. Subclasses can override this method to perform custom * setup before the Action is used. */ protected void setup() { // do nothing be default } /** * Perform any necessary clean-up after this encoder can be used. By * default does nothing. Subclasses can override this method to perform * custom clean-up after the Action is used. */ protected void finish() { // do nothing be default } // ------------------------------------------------------------------------ /** * Abstract class for processing the Actions stored in the predicate chain. */ private static abstract class ActionVisitor implements ExpressionVisitor { public void visitExpression(Expression expr) { if ( expr instanceof ObjectLiteral ) { Object val = expr.get(null); if ( val instanceof Action ) visitAction(((Action)val)); } } public abstract void visitAction(Action a); public void down() { /* do nothing */ } public void up() { /* do nothing */ } } /** * Sets the visualization status for any Actions contained within the * predicate chain. */ private class SetVisualizationVisitor extends ActionVisitor { public void visitAction(Action a) { a.setVisualization(m_vis); } } /** * Calls the "setup" method for any delegate actions contained within * the rule-mappings for this encoder. */ private static class SetupVisitor extends ActionVisitor { private static SetupVisitor s_instance; public static SetupVisitor getInstance() { if ( s_instance == null ) s_instance = new SetupVisitor(); return s_instance; } public void visitAction(Action a) { if ( a instanceof EncoderAction ) ((EncoderAction)a).setup(); } } /** * Calls the "setup" method for any delegate actions contained within * the rule-mappings for this encoder. */ private static class FinishVisitor extends ActionVisitor { private static FinishVisitor s_instance; public static FinishVisitor getInstance() { if ( s_instance == null ) s_instance = new FinishVisitor(); return s_instance; } public void visitAction(Action a) { if ( a instanceof EncoderAction ) ((EncoderAction)a).setup(); } } } // end of class EncoderAction