001: package prefuse.controls;
002:
003: import java.awt.Cursor;
004: import java.awt.event.MouseEvent;
005: import java.util.logging.Logger;
006:
007: import prefuse.Display;
008: import prefuse.Visualization;
009: import prefuse.data.expression.Predicate;
010: import prefuse.data.tuple.TupleSet;
011: import prefuse.util.StringLib;
012: import prefuse.util.ui.UILib;
013: import prefuse.visual.VisualItem;
014:
015: /**
016: * <p>Updates the contents of a TupleSet of focus items in response to mouse
017: * actions. For example, clicking a node or double-clicking a node could
018: * update its focus status. This Control supports monitoring a specified
019: * number of clicks to executing a focus change. By default a click pattern
020: * will cause a VisualItem to become the sole member of the focus group.
021: * Hold down the control key while clicking to add an item to a group
022: * without removing the current members.</p>
023: *
024: * <p>Updating a focus group does not necessarily cause
025: * the display to change. For this functionality, either register an action
026: * with this control, or register a TupleSetListener with the focus group.
027: * </p>
028: *
029: * @author <a href="http://jheer.org">jeffrey heer</a>
030: */
031: public class FocusControl extends ControlAdapter {
032:
033: private String group = Visualization.FOCUS_ITEMS;
034: protected String activity;
035: protected VisualItem curFocus;
036: protected int ccount;
037: protected int button = Control.LEFT_MOUSE_BUTTON;
038: protected Predicate filter = null;
039:
040: /**
041: * Creates a new FocusControl that changes the focus to another item
042: * when that item is clicked once.
043: */
044: public FocusControl() {
045: this (1);
046: }
047:
048: /**
049: * Creates a new FocusControl that changes the focus to another item
050: * when that item is clicked once.
051: * @param focusGroup the name of the focus group to use
052: */
053: public FocusControl(String focusGroup) {
054: this (1);
055: group = focusGroup;
056: }
057:
058: /**
059: * Creates a new FocusControl that changes the focus when an item is
060: * clicked the specified number of times. A click value of zero indicates
061: * that the focus should be changed in response to mouse-over events.
062: * @param clicks the number of clicks needed to switch the focus.
063: */
064: public FocusControl(int clicks) {
065: ccount = clicks;
066: }
067:
068: /**
069: * Creates a new FocusControl that changes the focus when an item is
070: * clicked the specified number of times. A click value of zero indicates
071: * that the focus should be changed in response to mouse-over events.
072: * @param focusGroup the name of the focus group to use
073: * @param clicks the number of clicks needed to switch the focus.
074: */
075: public FocusControl(String focusGroup, int clicks) {
076: ccount = clicks;
077: group = focusGroup;
078: }
079:
080: /**
081: * Creates a new FocusControl that changes the focus when an item is
082: * clicked the specified number of times. A click value of zero indicates
083: * that the focus should be changed in response to mouse-over events.
084: * @param clicks the number of clicks needed to switch the focus.
085: * @param act an action run to upon focus change
086: */
087: public FocusControl(int clicks, String act) {
088: ccount = clicks;
089: activity = act;
090: }
091:
092: /**
093: * Creates a new FocusControl that changes the focus when an item is
094: * clicked the specified number of times. A click value of zero indicates
095: * that the focus should be changed in response to mouse-over events.
096: * @param focusGroup the name of the focus group to use
097: * @param clicks the number of clicks needed to switch the focus.
098: * @param act an action run to upon focus change
099: */
100: public FocusControl(String focusGroup, int clicks, String act) {
101: ccount = clicks;
102: activity = act;
103: this .group = focusGroup;
104: }
105:
106: // ------------------------------------------------------------------------
107:
108: /**
109: * Set a filter for processing items by this focus control. Only items for
110: * which the predicate returns true (or doesn't throw an exception) will
111: * be considered by this control. A null value indicates that no filtering
112: * should be applied. That is, all items will be considered.
113: * @param p the filtering predicate to apply
114: */
115: public void setFilter(Predicate p) {
116: this .filter = p;
117: }
118:
119: /**
120: * Get the filter for processing items by this focus control. Only items
121: * for which the predicate returns true (or doesn't throw an exception)
122: * are considered by this control. A null value indicates that no
123: * filtering is applied.
124: * @return the filtering predicate
125: */
126: public Predicate getFilter() {
127: return filter;
128: }
129:
130: /**
131: * Perform a filtering check on the input item.
132: * @param item the item to check against the filter
133: * @return true if the item should be considered, false otherwise
134: */
135: protected boolean filterCheck(VisualItem item) {
136: if (filter == null)
137: return true;
138:
139: try {
140: return filter.getBoolean(item);
141: } catch (Exception e) {
142: Logger.getLogger(getClass().getName()).warning(
143: e.getMessage() + "\n" + StringLib.getStackTrace(e));
144: return false;
145: }
146: }
147:
148: // ------------------------------------------------------------------------
149:
150: /**
151: * @see prefuse.controls.Control#itemEntered(prefuse.visual.VisualItem, java.awt.event.MouseEvent)
152: */
153: public void itemEntered(VisualItem item, MouseEvent e) {
154: if (!filterCheck(item))
155: return;
156: Display d = (Display) e.getSource();
157: d.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
158: if (ccount == 0) {
159: Visualization vis = item.getVisualization();
160: TupleSet ts = vis.getFocusGroup(group);
161: ts.setTuple(item);
162: curFocus = item;
163: runActivity(vis);
164: }
165: }
166:
167: /**
168: * @see prefuse.controls.Control#itemExited(prefuse.visual.VisualItem, java.awt.event.MouseEvent)
169: */
170: public void itemExited(VisualItem item, MouseEvent e) {
171: if (!filterCheck(item))
172: return;
173: Display d = (Display) e.getSource();
174: d.setCursor(Cursor.getDefaultCursor());
175: if (ccount == 0) {
176: curFocus = null;
177: Visualization vis = item.getVisualization();
178: TupleSet ts = vis.getFocusGroup(group);
179: ts.removeTuple(item);
180: runActivity(vis);
181: }
182: }
183:
184: /**
185: * @see prefuse.controls.Control#itemClicked(prefuse.visual.VisualItem, java.awt.event.MouseEvent)
186: */
187: public void itemClicked(VisualItem item, MouseEvent e) {
188: if (!filterCheck(item))
189: return;
190: if (UILib.isButtonPressed(e, button)
191: && e.getClickCount() == ccount) {
192: if (item != curFocus) {
193: Visualization vis = item.getVisualization();
194: TupleSet ts = vis.getFocusGroup(group);
195:
196: boolean ctrl = e.isControlDown();
197: if (!ctrl) {
198: curFocus = item;
199: ts.setTuple(item);
200: } else if (ts.containsTuple(item)) {
201: ts.removeTuple(item);
202: } else {
203: ts.addTuple(item);
204: }
205: runActivity(vis);
206:
207: } else if (e.isControlDown()) {
208: Visualization vis = item.getVisualization();
209: TupleSet ts = vis.getFocusGroup(group);
210: ts.removeTuple(item);
211: curFocus = null;
212: runActivity(vis);
213: }
214: }
215: }
216:
217: private void runActivity(Visualization vis) {
218: if (activity != null) {
219: vis.run(activity);
220: }
221: }
222:
223: } // end of class FocusControl
|