KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > Visualization


1 package prefuse;
2
3 import java.awt.geom.Rectangle2D JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.Collections JavaDoc;
6 import java.util.HashMap JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.LinkedHashMap JavaDoc;
9 import java.util.Map JavaDoc;
10
11 import prefuse.action.Action;
12 import prefuse.activity.Activity;
13 import prefuse.activity.ActivityMap;
14 import prefuse.data.Graph;
15 import prefuse.data.Node;
16 import prefuse.data.Schema;
17 import prefuse.data.Table;
18 import prefuse.data.Tree;
19 import prefuse.data.Tuple;
20 import prefuse.data.expression.Expression;
21 import prefuse.data.expression.Predicate;
22 import prefuse.data.expression.parser.ExpressionParser;
23 import prefuse.data.tuple.CompositeTupleSet;
24 import prefuse.data.tuple.DefaultTupleSet;
25 import prefuse.data.tuple.TupleManager;
26 import prefuse.data.tuple.TupleSet;
27 import prefuse.render.DefaultRendererFactory;
28 import prefuse.render.Renderer;
29 import prefuse.render.RendererFactory;
30 import prefuse.util.PrefuseConfig;
31 import prefuse.util.PrefuseLib;
32 import prefuse.util.collections.CompositeIterator;
33 import prefuse.visual.AggregateTable;
34 import prefuse.visual.VisualGraph;
35 import prefuse.visual.VisualItem;
36 import prefuse.visual.VisualTable;
37 import prefuse.visual.VisualTree;
38 import prefuse.visual.VisualTupleSet;
39 import prefuse.visual.expression.ValidatedPredicate;
40 import prefuse.visual.expression.VisiblePredicate;
41 import prefuse.visual.tuple.TableDecoratorItem;
42 import prefuse.visual.tuple.TableEdgeItem;
43 import prefuse.visual.tuple.TableNodeItem;
44
45 /**
46  * <p>Central data structure representing an interactive Visualization.
47  * This class is responsible for
48  * managing the mappings between source data and onscreen VisualItems,
49  * maintaining a list of {@link Display} instances responsible for rendering
50  * of and interaction with the contents of this visualization, and
51  * providing a collection of named Action instances for performing
52  * data processing such as layout, animation, and size, shape, and color
53  * assignment.</p>
54  *
55  * <p>The primary responsibility of the Visualization class is the creation
56  * of <em>visual abstractions</em> of input data. Regardless of the data
57  * structure (i.e., {@link prefuse.data.Table}, {@link prefuse.data.Graph},
58  * or {@link prefuse.data.Tree}), this class takes source data such as that
59  * loaded from a file (see {@link prefuse.data.io}) or from a relational
60  * database (see {@link prefuse.data.io.sql}) and creates a visual
61  * representation of the data. These visual representations of the data are
62  * data sets in their own right, providing access to the underlying source
63  * data to be visualized while also adding addition data fields specific to a
64  * visualization. These fields include spatial location (x, y
65  * coordinates and item bounds), color (for stroke, fill, and text), size,
66  * shape, and font. For a given input data set of type
67  * {@link prefuse.data.Table}, {@link prefuse.data.Graph}, or
68  * or {@link prefuse.data.Tree}, a corresponding instance of
69  * {@link prefuse.visual.VisualTable}, {@link prefuse.visual.VisualGraph}, or
70  * {@link prefuse.visual.VisualTree} is created and stored in the
71  * visualization. These data types inherit the data values of the source
72  * data (and indeed, manipulate it directly) while additionally providing
73  * the aforementioned visual variables unique to that generated
74  * visual abstraction. Similarly, all {@link prefuse.data.Tuple},
75  * {@link prefuse.data.Node}, or {@link prefuse.data.Edge}
76  * instances used to represent an entry in the source data have a
77  * corresponding {@link prefuse.visual.VisualItem},
78  * {@link prefuse.visual.NodeItem}, or {@link prefuse.visual.EdgeItem}
79  * representing the interactive, visual realization of the backing data.</p>
80  *
81  * <p>The mapping of source data to a visual abstraction is accomplished
82  * using {@link #add(String, TupleSet)} and the other "add" methods. These
83  * methods will automatically create the visual abstraction, and store it
84  * in this visualization, associating it with a provided <em>data group name
85  * </em>. This group name allows for queries to this visualization that
86  * consider only VisualItem instances from that particular group. This is
87  * quite useful when crafting {@link prefuse.action.Action} instances that
88  * process only a particular group of visual data. The Visualization class
89  * provides mechanisms for querying any or all groups within the visualization,
90  * using one or both of the group name or a filtering
91  * {@link prefuse.data.expression.Predicate} to determine the items to
92  * include (see {@link #items(Predicate)} for an examples). Source data
93  * may be added multiple times to a Visualization under different group
94  * names, allowing for multiple representations of the same backing data.</p>
95  *
96  * <p>Additionally, the Visualization class supports VisualItem instances
97  * that are not directly grounded in backing source data. Examples include
98  * {@link prefuse.visual.DecoratorItem} which "decorates" another pre-existing
99  * VisualItem with a separate interactive visual object, and
100  * {@link prefuse.visual.AggregateItem} which provides an interactive visual
101  * representation of an aggregated of other VisualItems. Methods for adding
102  * data groups of these kinds include {@link #addDecorators(String, String)}
103  * and {@link #addAggregates(String)}.</p>
104  *
105  * <p>All of the examples discussed above are examples of <em>primary, or
106  * visual, data groups</em> of VisualItems. Visualizations also support
107  * <em>secondary, or focus data groups</em> that maintain additional
108  * collections of the VisualItems stored in the primary groups. Examples
109  * include a set of focus items (such as those that have been clicked
110  * by the user), selected items (items selected by a user), or search
111  * items (all matches to a search query). The exact semantics of these
112  * groups and the mechanisms by which they are populated is determined by
113  * application creators, but some defaults are provided. The Visualization
114  * class includes some default group names, namely {@link #FOCUS_ITEMS},
115  * {@link #SELECTED_ITEMS}, and {@link #SEARCH_ITEMS} for the above
116  * mentioned tasks. By default, both the {@link #FOCUS_ITEMS},
117  * {@link #SELECTED_ITEMS} focus groups are included in the Visualization,
118  * represented using {@link prefuse.data.tuple.DefaultTupleSet} instances.
119  * Also, some of the interactive controls provided by the
120  * {@link prefuse.controls} package populate these sets by default. See
121  * {@link prefuse.controls.FocusControl} for an example.</p>
122  *
123  * <p>Visualizations also maintain references to all the {@link Display}
124  * instances providing interactive views of the content of this
125  * visualization. {@link Display} instances registers themselves with
126  * the visualization either in their constructor or through
127  * the {@link Display#setVisualization(Visualization)} method, so they
128  * do not otherwise need to be added manually. Displays can be configured
129  * to show all or only a subset of the data in the Visualization. A
130  * filtering {@link prefuse.data.expression.Predicate} can be used to
131  * control what items are drawn by the displaying, including limiting
132  * the Display to particular data groups (for example, using a
133  * {@link prefuse.visual.expression.InGroupPredicate}). The Visualization's
134  * {@link #repaint()} method will trigger a repaint on all Displays
135  * associated with the visualization.</p>
136  *
137  * <p>Finally, the Visualization class provides a map of named
138  * {@link prefuse.action.Action} instances that can be invoked to perform
139  * processing on the VisualItems contained in the visualization.
140  * Using the {@link #putAction(String, Action)} will add a named Action
141  * to the visualization, registering the Action such that a reference
142  * to this Visualization will be available within the scope of the
143  * Action's {@link prefuse.action.Action#run(double)} method. Processing
144  * Actions can later be invoked by name using the {@link #run(String)}
145  * method and other similar methods. This functionality not only
146  * provides a convenient means of organizing a Visualization-specific
147  * collection of processing Actions, it also allows for a layer of indirection
148  * between an Action and its name. This allows Actions to be dynamically
149  * swapped at runtime. For example, an application may make a call to
150  * invoke an Action named "layout", but the actual layout processing maybe
151  * be dynamically swapped by changing the Action that corresponds to that
152  * name. For more information on processing Actions, see the
153  * {@link prefuse.action} packages and the top-level
154  * {@link prefuse.action.Action} class.</p>
155  *
156  * @author <a HREF="http://jheer.org">jeffrey heer</a>
157  */

158 public class Visualization {
159     
160     /** Data group name for indicating all groups */
161     public static final String JavaDoc ALL_ITEMS
162         = PrefuseConfig.get("visualization.allItems");
163     /** Default data group name for focus items */
164     public static final String JavaDoc FOCUS_ITEMS
165         = PrefuseConfig.get("visualization.focusItems");
166     /** Default data group name for selected items */
167     public static final String JavaDoc SELECTED_ITEMS
168         = PrefuseConfig.get("visualization.selectedItems");
169     /** Default data group name for search result items */
170     public static final String JavaDoc SEARCH_ITEMS
171         = PrefuseConfig.get("visualization.searchItems");
172     
173     // visual abstraction
174
// filtered tables and groups
175
private Map JavaDoc m_visual;
176     private Map JavaDoc m_source;
177     private Map JavaDoc m_focus;
178     
179     // actions
180
private ActivityMap m_actions;
181     
182     // renderers
183
private RendererFactory m_renderers;
184     
185     // displays
186
private ArrayList JavaDoc m_displays;
187     
188     // ------------------------------------------------------------------------
189
// Constructor
190

191     /**
192      * Create a new, empty Visualization. Uses a DefaultRendererFactory.
193      */

194     public Visualization() {
195         m_actions = new ActivityMap();
196         m_renderers = new DefaultRendererFactory();
197         m_visual = new LinkedHashMap JavaDoc();
198         m_source = new HashMap JavaDoc();
199         m_focus = new HashMap JavaDoc();
200         m_displays = new ArrayList JavaDoc();
201         
202         addFocusGroup(Visualization.FOCUS_ITEMS, new DefaultTupleSet());
203         addFocusGroup(Visualization.SELECTED_ITEMS, new DefaultTupleSet());
204     }
205     
206     // ------------------------------------------------------------------------
207
// Data Methods
208

209     /**
210      * Add a data set to this visualization, using the given data group name.
211      * A visual abstraction of the data will be created and registered with
212      * the visualization. An exception will be thrown if the group name is
213      * already in use.
214      * @param group the data group name for the visualized data
215      * @param data the data to visualize
216      * @return a visual abstraction of the input data, a VisualTupleSet
217      * instance
218      */

219     public synchronized VisualTupleSet add(String JavaDoc group, TupleSet data) {
220         return add(group, data, null);
221     }
222
223     /**
224      * Add a data set to this visualization, using the given data group name.
225      * A visual abstraction of the data will be created and registered with
226      * the visualization. An exception will be thrown if the group name is
227      * already in use.
228      * @param group the data group name for the visualized data
229      * @param data the data to visualize
230      * @param filter a filter Predicate determining which data Tuples in the
231      * input data set are visualized
232      * @return a visual abstraction of the input data, a VisualTupleSet
233      * instance
234      */

235     public synchronized VisualTupleSet add(
236             String JavaDoc group, TupleSet data, Predicate filter)
237     {
238         if ( data instanceof Table ) {
239             return addTable(group, (Table)data, filter);
240         } else if ( data instanceof Tree ) {
241             return addTree(group, (Tree)data, filter);
242         } else if ( data instanceof Graph ) {
243             return addGraph(group, (Graph)data, filter);
244         } else {
245             throw new IllegalArgumentException JavaDoc("Unsupported TupleSet type.");
246         }
247     }
248     
249     protected void checkGroupExists(String JavaDoc group) {
250         if ( m_visual.containsKey(group) || m_focus.containsKey(group) ) {
251             throw new IllegalArgumentException JavaDoc(
252                     "Group name \'"+group+"\' already in use");
253         }
254     }
255     
256     protected void addDataGroup(String JavaDoc group, VisualTupleSet ts, TupleSet src) {
257         checkGroupExists(group);
258         m_visual.put(group, ts);
259         if ( src != null )
260             m_source.put(group, src);
261     }
262     
263     // -- Tables --------------------------------------------------------------
264

265     /**
266      * Add an empty VisualTable to this visualization, using the given data
267      * group name. This adds a group of VisualItems that do not have a
268      * backing data set, useful for creating interactive visual objects
269      * that do not represent data. An exception will be thrown if the group
270      * name is already in use.
271      * @param group the data group name for the visualized data
272      * @return the added VisualTable
273      */

274     public synchronized VisualTable addTable(String JavaDoc group) {
275         VisualTable vt = new VisualTable(this, group);
276         addDataGroup(group, vt, null);
277         return vt;
278     }
279     
280     /**
281      * Add an empty VisualTable to this visualization, using the given data
282      * group name and table schema. This adds a group of VisualItems that do
283      * not have a backing data set, useful for creating interactive visual
284      * objects that do not represent data. An exception will be thrown if the
285      * group name is already in use.
286      * @param group the data group name for the visualized data
287      * @param schema the data schema to use for the VisualTable
288      * @return the added VisualTable
289      */

290     public synchronized VisualTable addTable(String JavaDoc group, Schema schema) {
291         VisualTable vt = new VisualTable(this, group, schema);
292         addDataGroup(group, vt, null);
293         return vt;
294     }
295     
296     /**
297      * Adds a data table to this visualization, using the given data group
298      * name. A visual abstraction of the data will be created and registered
299      * with the visualization. An exception will be thrown if the group name
300      * is already in use.
301      * @param group the data group name for the visualized data
302      * @param table the data table to visualize
303      */

304     public synchronized VisualTable addTable(String JavaDoc group, Table table) {
305         return addTable(group, table, (Predicate)null);
306     }
307     
308     /**
309      * Adds a data table to this visualization, using the given data group
310      * name. A visual abstraction of the data will be created and registered
311      * with the visualization. An exception will be thrown if the group name
312      * is already in use.
313      * @param group the data group name for the visualized data
314      * @param table the data table to visualize
315      * @param filter a filter Predicate determining which data Tuples in the
316      * input table are visualized
317      */

318     public synchronized VisualTable addTable(
319             String JavaDoc group, Table table, Predicate filter)
320     {
321         VisualTable vt = new VisualTable(table, this, group, filter);
322         addDataGroup(group, vt, table);
323         return vt;
324     }
325
326     /**
327      * Adds a data table to this visualization, using the given data group
328      * name. A visual abstraction of the data will be created and registered
329      * with the visualization. An exception will be thrown if the group name
330      * is already in use.
331      * @param group the data group name for the visualized data
332      * @param table the data table to visualize
333      * @param schema the data schema to use for the created VisualTable
334      */

335     public synchronized VisualTable addTable(
336             String JavaDoc group, Table table, Schema schema)
337     {
338         return addTable(group, table, null, schema);
339     }
340     
341     /**
342      * Adds a data table to this visualization, using the given data group
343      * name. A visual abstraction of the data will be created and registered
344      * with the visualization. An exception will be thrown if the group name
345      * is already in use.
346      * @param group the data group name for the visualized data
347      * @param table the data table to visualize
348      * @param filter a filter Predicate determining which data Tuples in the
349      * input table are visualized
350      * @param schema the data schema to use for the created VisualTable
351      */

352     public synchronized VisualTable addTable(
353             String JavaDoc group, Table table, Predicate filter, Schema schema)
354     {
355         VisualTable vt = new VisualTable(table, this, group, filter, schema);
356         addDataGroup(group, vt, table);
357         return vt;
358     }
359     
360     /**
361      * Add a VisualTable to this visualization, using the table's
362      * pre-set group name. An exception will be thrown if the group
363      * name is already in use. This method allows you to insert custom
364      * implementations of VisualTable into a Visualization. It is intended
365      * for advanced users and should <b>NOT</b> be used if you do not know
366      * what you are doing. In almost all cases, one of the other add methods
367      * is preferred.
368      * @param table the pre-built VisualTable to add
369      * @return the added VisualTable
370      */

371     public synchronized VisualTable addTable(VisualTable table) {
372         addDataGroup(table.getGroup(), table, table.getParentTable());
373         table.setVisualization(this);
374         return table;
375     }
376     
377     // -- Graphs and Trees ----------------------------------------------------
378

379     /**
380      * Adds a graph to this visualization, using the given data group
381      * name. A visual abstraction of the data will be created and registered
382      * with the visualization. An exception will be thrown if the group name
383      * is already in use.
384      * @param group the data group name for the visualized graph. The nodes
385      * and edges will be available in the "group.nodes" and "group.edges"
386      * subgroups.
387      * @param graph the graph to visualize
388      */

389     public synchronized VisualGraph addGraph(String JavaDoc group, Graph graph) {
390         return addGraph(group, graph, null);
391     }
392     
393     /**
394      * Adds a graph to this visualization, using the given data group
395      * name. A visual abstraction of the data will be created and registered
396      * with the visualization. An exception will be thrown if the group name
397      * is already in use.
398      * @param group the data group name for the visualized graph. The nodes
399      * and edges will be available in the "group.nodes" and "group.edges"
400      * subgroups.
401      * @param graph the graph to visualize
402      * @param filter a filter Predicate determining which data Tuples in the
403      * input graph are visualized
404      */

405     public synchronized VisualGraph addGraph(
406             String JavaDoc group, Graph graph, Predicate filter)
407     {
408         return addGraph(group, graph, filter, VisualItem.SCHEMA, VisualItem.SCHEMA);
409     }
410     
411     /**
412      * Adds a graph to this visualization, using the given data group
413      * name. A visual abstraction of the data will be created and registered
414      * with the visualization. An exception will be thrown if the group name
415      * is already in use.
416      * @param group the data group name for the visualized graph. The nodes
417      * and edges will be available in the "group.nodes" and "group.edges"
418      * subgroups.
419      * @param graph the graph to visualize
420      * @param filter a filter Predicate determining which data Tuples in the
421      * input graph are visualized
422      * @param nodeSchema the data schema to use for the visual node table
423      * @param edgeSchema the data schema to use for the visual edge table
424      */

425     public synchronized VisualGraph addGraph(String JavaDoc group, Graph graph,
426             Predicate filter, Schema nodeSchema, Schema edgeSchema)
427     {
428         checkGroupExists(group); // check before adding sub-tables
429
String JavaDoc ngroup = PrefuseLib.getGroupName(group, Graph.NODES);
430         String JavaDoc egroup = PrefuseLib.getGroupName(group, Graph.EDGES);
431
432         VisualTable nt, et;
433         nt = addTable(ngroup, graph.getNodeTable(), filter, nodeSchema);
434         et = addTable(egroup, graph.getEdgeTable(), filter, edgeSchema);
435         
436         VisualGraph vg = new VisualGraph(nt, et,
437                 graph.isDirected(), graph.getNodeKeyField(),
438                 graph.getEdgeSourceField(), graph.getEdgeTargetField());
439         vg.setVisualization(this);
440         vg.setGroup(group);
441      
442         addDataGroup(group, vg, graph);
443         
444         TupleManager ntm = new TupleManager(nt, vg, TableNodeItem.class);
445         TupleManager etm = new TupleManager(et, vg, TableEdgeItem.class);
446         nt.setTupleManager(ntm);
447         et.setTupleManager(etm);
448         vg.setTupleManagers(ntm, etm);
449         
450         return vg;
451     }
452     
453     /**
454      * Adds a tree to this visualization, using the given data group
455      * name. A visual abstraction of the data will be created and registered
456      * with the visualization. An exception will be thrown if the group name
457      * is already in use.
458      * @param group the data group name for the visualized tree. The nodes
459      * and edges will be available in the "group.nodes" and "group.edges"
460      * subgroups.
461      * @param tree the tree to visualize
462      */

463     public synchronized VisualTree addTree(String JavaDoc group, Tree tree) {
464         return addTree(group, tree, null);
465     }
466     
467     /**
468      * Adds a tree to this visualization, using the given data group
469      * name. A visual abstraction of the data will be created and registered
470      * with the visualization. An exception will be thrown if the group name
471      * is already in use.
472      * @param group the data group name for the visualized tree. The nodes
473      * and edges will be available in the "group.nodes" and "group.edges"
474      * subgroups.
475      * @param tree the tree to visualize
476      * @param filter a filter Predicate determining which data Tuples in the
477      * input graph are visualized
478      */

479     public synchronized VisualTree addTree(
480             String JavaDoc group, Tree tree, Predicate filter)
481     {
482         return addTree(group, tree, filter, VisualItem.SCHEMA, VisualItem.SCHEMA);
483     }
484     
485     /**
486      * Adds a tree to this visualization, using the given data group
487      * name. A visual abstraction of the data will be created and registered
488      * with the visualization. An exception will be thrown if the group name
489      * is already in use.
490      * @param group the data group name for the visualized tree. The nodes
491      * and edges will be available in the "group.nodes" and "group.edges"
492      * subgroups.
493      * @param tree the tree to visualize
494      * @param filter a filter Predicate determining which data Tuples in the
495      * input graph are visualized
496      * @param nodeSchema the data schema to use for the visual node table
497      * @param edgeSchema the data schema to use for the visual edge table
498      */

499     public synchronized VisualTree addTree(String JavaDoc group, Tree tree,
500             Predicate filter, Schema nodeSchema, Schema edgeSchema)
501     {
502         checkGroupExists(group); // check before adding sub-tables
503
String JavaDoc ngroup = PrefuseLib.getGroupName(group, Graph.NODES);
504         String JavaDoc egroup = PrefuseLib.getGroupName(group, Graph.EDGES);
505         
506         VisualTable nt, et;
507         nt = addTable(ngroup, tree.getNodeTable(), filter, nodeSchema);
508         et = addTable(egroup, tree.getEdgeTable(), filter, edgeSchema);
509
510         VisualTree vt = new VisualTree(nt, et, tree.getNodeKeyField(),
511                 tree.getEdgeSourceField(), tree.getEdgeTargetField());
512         vt.setVisualization(this);
513         vt.setGroup(group);
514         
515         addDataGroup(group, vt, tree);
516         
517         TupleManager ntm = new TupleManager(nt, vt, TableNodeItem.class);
518         TupleManager etm = new TupleManager(et, vt, TableEdgeItem.class);
519         nt.setTupleManager(ntm);
520         et.setTupleManager(etm);
521         vt.setTupleManagers(ntm, etm);
522         
523         return vt;
524     }
525     
526     // -- Aggregates ----------------------------------------------------------
527

528     /**
529      * Add a group of aggregates to this visualization. Aggregates are
530      * used to visually represent groups of VisualItems.
531      * @param group the data group name for the aggregates.
532      * @return the generated AggregateTable
533      * @see prefuse.visual.AggregateTable
534      */

535     public synchronized AggregateTable addAggregates(String JavaDoc group) {
536         return addAggregates(group, VisualItem.SCHEMA);
537     }
538     
539     /**
540      * Add a group of aggregates to this visualization. Aggregates are
541      * used to visually represent groups of VisualItems.
542      * @param group the data group name for the aggregates.
543      * @param schema the data schema to use for the AggregateTable
544      * @return the generated AggregateTable
545      * @see prefuse.visual.AggregateTable
546      */

547     public synchronized AggregateTable addAggregates(String JavaDoc group,
548                                                      Schema schema)
549     {
550         AggregateTable vat = new AggregateTable(this, group, schema);
551         addDataGroup(group, vat, null);
552         return vat;
553     }
554     
555     // -- Derived Tables and Decorators ---------------------------------------
556

557     /**
558      * Add a derived table, a VisualTable that is cascaded from an
559      * existing VisualTable. This is useful for creating VisualItems
560      * that inherit a set of visual properties from another group of
561      * VisualItems. This might be used, for example, in the creation
562      * of small multiples where only a few visual attributes vary
563      * across the multiples.
564      * @param group the data group to use for the derived table
565      * @param source the source data group to derive from
566      * @param filter a Predicate filter indicating which tuples of the
567      * source group should be inheritable by the new group
568      * @param override a data schema indicating which data fields
569      * should not be inherited, but managed locally by the derived group
570      * @return the derived VisualTable
571      */

572     public synchronized VisualTable addDerivedTable(
573             String JavaDoc group, String JavaDoc source, Predicate filter, Schema override)
574     {
575         VisualTable src = (VisualTable)getGroup(source);
576         VisualTable vt = new VisualTable(src, this, group, filter, override);
577      
578         addDataGroup(group, vt, getSourceData(source));
579         return vt;
580     }
581     
582     /**
583      * Add a group of decorators to an existing visual data group. Decorators
584      * are VisualItem instances intended to "decorate" another VisualItem,
585      * such as providing a label or dedicated interactive control, and are
586      * realizeed as {@link prefuse.visual.DecoratorItem} instances that provide
587      * access to the decorated item in addition to the standard VisualItem
588      * properties. The generated table is created using the
589      * {@link #addDerivedTable(String, String, Predicate, Schema)} method,
590      * but with no VisualItem properties inherited from the source group.
591      * @param group the data group to use for the decorators
592      * @param source the source data group to decorate
593      * @return the generated VisualTable of DecoratorItem instances
594      */

595     public synchronized VisualTable addDecorators(String JavaDoc group,String JavaDoc source) {
596         return addDecorators(group, source, (Predicate)null);
597     }
598     
599     /**
600      * Add a group of decorators to an existing visual data group. Decorators
601      * are VisualItem instances intended to "decorate" another VisualItem,
602      * such as providing a label or dedicated interactive control, and are
603      * realizeed as {@link prefuse.visual.DecoratorItem} instances that provide
604      * access to the decorated item in addition to the standard VisualItem
605      * properties.
606      * @param group the data group to use for the decorators
607      * @param source the source data group to decorate
608      * @param schema schema indicating which variables should <b>not</b> be
609      * inherited from the source data group and instead be managed locally
610      * by the generated VisualTable
611      * @return the generated VisualTable of DecoratorItem instances
612      */

613     public synchronized VisualTable addDecorators(
614             String JavaDoc group, String JavaDoc source, Schema schema)
615     {
616         return addDecorators(group, source, null, schema);
617     }
618     
619     /**
620      * Add a group of decorators to an existing visual data group. Decorators
621      * are VisualItem instances intended to "decorate" another VisualItem,
622      * such as providing a label or dedicated interactive control, and are
623      * realizeed as {@link prefuse.visual.DecoratorItem} instances that provide
624      * access to the decorated item in addition to the standard VisualItem
625      * properties.
626      * @param group the data group to use for the decorators
627      * @param source the source data group to decorate
628      * @param filter a Predicate filter indicating which tuples of the
629      * source group should be inheritable by the new group
630      * @return the generated VisualTable of DecoratorItem instances
631      */

632     public synchronized VisualTable addDecorators(
633             String JavaDoc group, String JavaDoc source, Predicate filter)
634     {
635         VisualTable t = addDerivedTable(group,source,filter,VisualItem.SCHEMA);
636         t.setTupleManager(new TupleManager(t, null, TableDecoratorItem.class));
637         return t;
638     }
639     
640     /**
641      * Add a group of decorators to an existing visual data group. Decorators
642      * are VisualItem instances intended to "decorate" another VisualItem,
643      * such as providing a label or dedicated interactive control, and are
644      * realizeed as {@link prefuse.visual.DecoratorItem} instances that provide
645      * access to the decorated item in addition to the standard VisualItem
646      * properties.
647      * @param group the data group to use for the decorators
648      * @param source the source data group to decorate
649      * @param filter a Predicate filter indicating which tuples of the
650      * source group should be inheritable by the new group
651      * @param schema schema indicating which variables should <b>not</b> be
652      * inherited from the source data group and instead be managed locally
653      * by the generated VisualTable
654      * @return the generated VisualTable of DecoratorItem instances
655      */

656     public synchronized VisualTable addDecorators(
657             String JavaDoc group, String JavaDoc source, Predicate filter, Schema schema)
658     {
659         VisualTable t = addDerivedTable(group, source, filter, schema);
660         t.setTupleManager(new TupleManager(t, null, TableDecoratorItem.class));
661         return t;
662     }
663     
664     // -- Data Removal --------------------------------------------------------
665

666     /**
667      * Removes a data group from this Visualization. If the group is a focus
668      * group, the group will simply be removed, and any subsequent attempts to
669      * retrieve the group will return null. If the group is a primary group, it
670      * will be removed, and any members of the group will also be removed
671      * from any registered focus groups.
672      * @param group the data group to remove
673      * @return true if the group was found and removed, false if the group
674      * was not found in this visualization.
675      */

676     public synchronized boolean removeGroup(String JavaDoc group) {
677         // check for focus group first
678
TupleSet ts = getFocusGroup(group);
679         if ( ts != null ) {
680             // invalidate the item to reflect group membership change
681
for ( Iterator JavaDoc items = ts.tuples(ValidatedPredicate.TRUE);
682                   items.hasNext(); )
683             {
684                 ((VisualItem)items.next()).setValidated(false);
685             }
686             ts.clear(); // trigger group removal callback
687
m_focus.remove(group);
688             return true;
689         }
690         
691         // focus group not found, check for primary group
692
ts = getVisualGroup(group);
693         if ( ts == null ) {
694             // exit with false if group not found
695
return false;
696         }
697         // remove group members from focus sets and invalidate them
698
TupleSet[] focus = new TupleSet[m_focus.size()];
699         m_focus.values().toArray(focus);
700         for ( Iterator JavaDoc items = ts.tuples(); items.hasNext(); ) {
701             VisualItem item = (VisualItem)items.next();
702             for ( int j=0; j<focus.length; ++j ) {
703                 focus[j].removeTuple(item);
704             }
705             item.setValidated(false);
706         }
707         // remove data
708
if ( ts instanceof CompositeTupleSet ) {
709             CompositeTupleSet cts = (CompositeTupleSet)ts;
710             for ( Iterator JavaDoc names = cts.setNames(); names.hasNext(); ) {
711                 String JavaDoc name = (String JavaDoc)names.next();
712                 String JavaDoc subgroup = PrefuseLib.getGroupName(group,name);
713                 m_visual.remove(subgroup);
714                 m_source.remove(subgroup);
715             }
716         }
717         m_visual.remove(group);
718         m_source.remove(group);
719         return true;
720     }
721     
722     /**
723      * Reset this visualization, clearing out all visualization tuples. All
724      * data sets added using the "addXXX" methods will be removed from the
725      * visualization. All registered focus groups added using the
726      * addFocusGroup() methods will be retained, but will be cleared of all
727      * tuples.
728      */

729     public synchronized void reset() {
730         // first clear out all the focus groups
731
Iterator JavaDoc iter = m_focus.entrySet().iterator();
732         while ( iter.hasNext() ) {
733             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iter.next();
734             TupleSet ts = (TupleSet)entry.getValue();
735             ts.clear();
736         }
737         // finally clear out all map entries
738
m_visual.clear();
739         m_source.clear();
740     }
741     
742     // ------------------------------------------------------------------------
743
// Groups
744

745     /**
746      * Get the source data TupleSet backing the given visual data group.
747      * @return the backing source data set, or null if there is no such
748      * data set
749      */

750     public TupleSet getSourceData(String JavaDoc group) {
751         return (TupleSet)m_source.get(group);
752     }
753     
754     /**
755      * Get the source data TupleSet backing the given visual tuple set.
756      * @return the backing source data set, or null if there is no such
757      * data set
758      */

759     public TupleSet getSourceData(VisualTupleSet ts) {
760         return (TupleSet)m_source.get(ts.getGroup());
761     }
762     
763     /**
764      * Get the Tuple from a backing source data set that corresponds most
765      * closely to the given VisualItem.
766      * @param item the VisualItem for which to retreive the source tuple
767      * @return the data source tuple, or null if no such tuple could
768      * be found
769      */

770     public Tuple getSourceTuple(VisualItem item) {
771         // get the source group and tuple set, exit if none
772
String JavaDoc group = item.getGroup();
773         TupleSet source = getSourceData(group);
774         if ( source == null ) return null;
775         
776         // first get the source table and row value
777
int row = item.getRow();
778         Table t = item.getTable();
779         while ( t instanceof VisualTable ) {
780             VisualTable vt = (VisualTable)t;
781             row = vt.getParentRow(row);
782             t = vt.getParentTable();
783         }
784         
785         // now get the appropriate source tuple
786
// graphs maintain their own tuple managers so treat them specially
787
String JavaDoc cgroup = PrefuseLib.getChildGroup(group);
788         if ( cgroup != null ) {
789             String JavaDoc pgroup = PrefuseLib.getParentGroup(group);
790             Graph g = (Graph)getSourceData(pgroup);
791             if ( t == g.getNodeTable() ) {
792                 return g.getNode(row);
793             } else {
794                 return g.getEdge(row);
795             }
796         } else {
797             return t.getTuple(row);
798         }
799     }
800     
801     /**
802      * Get the VisualItem associated with a source data tuple, if it exists.
803      * @param group the data group from which to lookup the source tuple,
804      * only primary visual groups are valid, focus groups will not work
805      * @param t the source data tuple
806      * @return the associated VisualItem from the given data group, or
807      * null if no such VisualItem exists
808      */

809     public VisualItem getVisualItem(String JavaDoc group, Tuple t) {
810         TupleSet ts = getVisualGroup(group);
811         VisualTable vt;
812         if ( ts instanceof VisualTable ) {
813             vt = (VisualTable)ts;
814         } else if ( ts instanceof Graph ) {
815             Graph g = (Graph)ts;
816             vt = (VisualTable)(t instanceof Node ? g.getNodeTable()
817                                                  : g.getEdgeTable());
818         } else {
819             return null;
820         }
821         int pr = t.getRow();
822         int cr = vt.getChildRow(pr);
823         return cr<0 ? null : vt.getItem(cr);
824     }
825     
826     // ------------------------------------------------------------------------
827

828     /**
829      * Get the TupleSet associated with the given data group name.
830      * @param group a visual data group name
831      * @return the data group TupleSet
832      */

833     public TupleSet getGroup(String JavaDoc group) {
834         TupleSet ts = getVisualGroup(group);
835         if ( ts == null )
836             ts = getFocusGroup(group);
837         return ts;
838     }
839     
840     /**
841      * Indicates if a given VisualItem is contained in the given visual
842      * data group.
843      * @param item the VisualItem instance
844      * @param group the data group to check for containment
845      * @return true if the VisualItem is in the group, false otherwise
846      */

847     public boolean isInGroup(VisualItem item, String JavaDoc group) {
848         if ( ALL_ITEMS.equals(group) )
849             return true;
850         if ( item.getGroup() == group )
851             return true;
852         
853         TupleSet tset = getGroup(group);
854         return ( tset==null ? false : tset.containsTuple(item) );
855     }
856     
857     /**
858      * Add a new secondary, or focus, group to this visualization. By
859      * default the added group is an instance of
860      * {@link prefuse.data.tuple.DefaultTupleSet}.
861      * @param group the name of the focus group to add
862      */

863     public void addFocusGroup(String JavaDoc group) {
864         checkGroupExists(group);
865         m_focus.put(group, new DefaultTupleSet());
866     }
867
868     /**
869      * Add a new secondary, or focus, group to this visualization.
870      * @param group the name of the focus group to add
871      * @param tset the TupleSet for the focus group
872      */

873     public void addFocusGroup(String JavaDoc group, TupleSet tset) {
874         checkGroupExists(group);
875         m_focus.put(group, tset);
876     }
877     
878     // ------------------------------------------------------------------------
879
// VisualItems
880

881     /**
882      * Get the size of the given visual data group.
883      * @param group the visual data group
884      * @return the size (number of tuples) of the group
885      */

886     public int size(String JavaDoc group) {
887         TupleSet tset = getGroup(group);
888         return ( tset==null ? 0 : tset.getTupleCount() );
889     }
890     
891     /**
892      * Retrieve the visual data group of the given group name. Only primary
893      * visual groups will be considered.
894      * @param group the visual data group
895      * @return the requested data group, or null if not found
896      */

897     public TupleSet getVisualGroup(String JavaDoc group) {
898         return (TupleSet)m_visual.get(group);
899     }
900     
901     /**
902      * Retrieve the focus data group of the given group name. Only secondary,
903      * or focus, groups will be considered.
904      * @param group the focus data group
905      * @return the requested data group, or null if not found
906      */

907     public TupleSet getFocusGroup(String JavaDoc group) {
908         return (TupleSet)m_focus.get(group);
909     }
910     
911     /**
912      * Invalidate the bounds of all VisualItems in the given group. This
913      * will cause the bounds to be recomputed for all items upon the next
914      * redraw.
915      * @param group the visual data group to invalidate
916      */

917     public void invalidate(String JavaDoc group) {
918         Iterator JavaDoc items = items(ValidatedPredicate.TRUE);
919         while ( items.hasNext() ) {
920             VisualItem item = (VisualItem)items.next();
921             item.setValidated(false);
922         }
923     }
924     
925     /**
926      * Invalidate the bounds of all VisualItems in this visualization. This
927      * will cause the bounds to be recomputed for all items upon the next
928      * redraw.
929      */

930     public void invalidateAll() {
931         invalidate(ALL_ITEMS);
932     }
933     
934     /**
935      * Get an iterator over all visible items.
936      * @return an iterator over all visible items.
937      */

938     public Iterator JavaDoc visibleItems() {
939         return items(VisiblePredicate.TRUE);
940     }
941     
942     /**
943      * Get an iterator over all visible items in the specified group.
944      * @param group the visual data group name
945      * @return an iterator over all visible items in the specified group
946      */

947     public Iterator JavaDoc visibleItems(String JavaDoc group) {
948         return items(group, VisiblePredicate.TRUE);
949     }
950     
951     /**
952      * Get an iterator over all items, visible or not.
953      * @return an iterator over all items, visible or not.
954      */

955     public Iterator JavaDoc items() {
956         return items((Predicate)null);
957     }
958     
959     /**
960      * Get an iterator over all items which match the given
961      * Predicate filter.
962      * @param filter a Predicate indicating which items should be included
963      * in the iteration
964      * @return a filtered iterator over VisualItems
965      */

966     public Iterator JavaDoc items(Predicate filter) {
967         int size = m_visual.size();
968         if ( size == 0 ) {
969             return Collections.EMPTY_LIST.iterator();
970         } else if ( size == 1 ) {
971             Iterator JavaDoc it = m_visual.keySet().iterator();
972             return items((String JavaDoc)it.next(), filter);
973         } else {
974             CompositeIterator iter = new CompositeIterator(m_visual.size());
975             Iterator JavaDoc it = m_visual.keySet().iterator();
976             for ( int i=0; it.hasNext(); ) {
977                 String JavaDoc group = (String JavaDoc)it.next();
978                 if ( !PrefuseLib.isChildGroup(group) )
979                     iter.setIterator(i++, items(group, filter));
980             }
981             return iter;
982         }
983     }
984     
985     /**
986      * Get an iterator over all items in the specified group.
987      * @param group the visual data group name
988      * @return an iterator over all items in the specified group.
989      */

990     public Iterator JavaDoc items(String JavaDoc group) {
991         return items(group, (Predicate)null);
992     }
993     
994     /**
995      * Get an iterator over all items in the given group which match the given
996      * filter expression.
997      * @param group the visual data group to iterate over
998      * @param expr an expression string that should parse to a Predicate
999      * indicating which items should be included in the iteration. The input
1000     * string will be parsed using the
1001     * {@link prefuse.data.expression.parser.ExpressionParser} class. If a
1002     * parse error occurs, an empty iterator is returned.
1003     * @return a filtered iterator over VisualItems
1004     */

1005    public Iterator JavaDoc items(String JavaDoc group, String JavaDoc expr) {
1006        Expression e = ExpressionParser.parse(expr);
1007        if ( !(e instanceof Predicate) || ExpressionParser.getError()!=null )
1008            return Collections.EMPTY_LIST.iterator();
1009        return items(group, (Predicate)e);
1010    }
1011    
1012    /**
1013     * Get an iterator over all items in the given group which match the given
1014     * Predicate filter.
1015     * @param group the visual data group to iterate over
1016     * @param filter a Predicate indicating which items should be included in
1017     * the iteration.
1018     * @return a filtered iterator over VisualItems
1019     */

1020    public Iterator JavaDoc items(String JavaDoc group, Predicate filter) {
1021        if ( ALL_ITEMS.equals(group) )
1022            return items(filter);
1023
1024        TupleSet t = getGroup(group);
1025        return ( t==null ? Collections.EMPTY_LIST.iterator()
1026                         : t.tuples(filter) );
1027    }
1028    
1029    // ------------------------------------------------------------------------
1030
// Batch Methods
1031

1032    /**
1033     * Set a data field value for all items in a given data group matching a
1034     * given filter predicate.
1035     * @param group the visual data group name
1036     * @param p the filter predicate determining which items to modify
1037     * @param field the data field / column name to set
1038     * @param val the value to set
1039     */

1040    public void setValue(String JavaDoc group, Predicate p, String JavaDoc field, Object JavaDoc val) {
1041        Iterator JavaDoc items = items(group, p);
1042        while ( items.hasNext() ) {
1043            VisualItem item = (VisualItem)items.next();
1044            item.set(field, val);
1045        }
1046    }
1047    
1048    /**
1049     * Sets the visbility status for all items in a given data group matching
1050     * a given filter predicate.
1051     * @param group the visual data group name
1052     * @param p the filter predicate determining which items to modify
1053     * @param value the visibility value to set
1054     */

1055    public void setVisible(String JavaDoc group, Predicate p, boolean value) {
1056        Iterator JavaDoc items = items(group, p);
1057        while ( items.hasNext() ) {
1058            VisualItem item = (VisualItem)items.next();
1059            item.setVisible(value);
1060        }
1061    }
1062
1063    /**
1064     * Sets the interactivity status for all items in a given data group
1065     * matching a given filter predicate.
1066     * @param group the visual data group name
1067     * @param p the filter predicate determining which items to modify
1068     * @param value the interactivity value to set
1069     */

1070    public void setInteractive(String JavaDoc group, Predicate p, boolean value) {
1071        Iterator JavaDoc items = items(group, p);
1072        while ( items.hasNext() ) {
1073            VisualItem item = (VisualItem)items.next();
1074            item.setInteractive(value);
1075        }
1076    }
1077    
1078    // ------------------------------------------------------------------------
1079
// Action Methods
1080

1081    /**
1082     * Add a data processing Action to this Visualization. The Action will be
1083     * updated to use this Visualization in its data processing.
1084     * @param name the name of the Action
1085     * @param action the Action to add
1086     */

1087    public Action putAction(String JavaDoc name, Action action) {
1088        action.setVisualization(this);
1089        m_actions.put(name, action);
1090        return action;
1091    }
1092    
1093    /**
1094     * Get the data processing Action with the given name.
1095     * @param name the name of the Action
1096     * @return the requested Action, or null if the name was not found
1097     */

1098    public Action getAction(String JavaDoc name) {
1099        return (Action)m_actions.get(name);
1100    }
1101    
1102    /**
1103     * Schedule the Action with the given name to run immediately. The running
1104     * of all Actions is managed by the
1105     * {@link prefuse.activity.ActivityManager}, which runs in a dedicated
1106     * thread.
1107     * @param action the name of the Action to run
1108     * @return the Action scheduled to run
1109     */

1110    public Activity run(String JavaDoc action) {
1111        return m_actions.run(action);
1112    }
1113
1114    /**
1115     * Schedule the Action with the given name to run after the specified
1116     * delay. The running of all Actions is managed by the
1117     * {@link prefuse.activity.ActivityManager}, which runs in a dedicated
1118     * thread.
1119     * @param action the name of the Action to run
1120     * @param delay the amount of time to wait, in milliseconds, before
1121     * running the Action
1122     * @return the Action scheduled to run
1123     */

1124    public Activity runAfter(String JavaDoc action, long delay) {
1125        return m_actions.runAt(action, System.currentTimeMillis()+delay);
1126    }
1127    
1128    /**
1129     * Schedule the Action with the given name to run at the specified
1130     * time. The running of all Actions is managed by the
1131     * {@link prefuse.activity.ActivityManager}, which runs in a dedicated
1132     * thread.
1133     * @param action the name of the Action to run
1134     * @param startTime the absolute system time, in milliseconds since the
1135     * epoch, at which to run the Action.
1136     * @return the Action scheduled to run
1137     */

1138    public Activity runAt(String JavaDoc action, long startTime) {
1139        return m_actions.runAt(action, startTime);
1140    }
1141    
1142    /**
1143     * Schedule the Action with the given name to run after another Action
1144     * finishes running. This relationship will only hold for one round of
1145     * scheduling. If the "before" Action is run a second time, the "after"
1146     * action will not be run a second time. The running of all Actions is
1147     * managed by the {@link prefuse.activity.ActivityManager}, which runs
1148     * in a dedicated thread.
1149     * @param before the name of the Action to wait for
1150     * @param after the name of the Action to run after the first one finishes
1151     * @return the Action scheduled to run after the first one finishes
1152     */

1153    public Activity runAfter(String JavaDoc before, String JavaDoc after) {
1154        return m_actions.runAfter(before, after);
1155    }
1156    
1157    /**
1158     * Schedule the Action with the given name to always run after another Action
1159     * finishes running. The running of all Actions is managed by the
1160     * {@link prefuse.activity.ActivityManager}, which runs in a dedicated
1161     * thread.
1162     * @param before the name of the Action to wait for
1163     * @param after the name of the Action to run after the first one finishes
1164     * @return the Action scheduled to always run after the first one finishes
1165     */

1166    public Activity alwaysRunAfter(String JavaDoc before, String JavaDoc after) {
1167        return m_actions.alwaysRunAfter(before, after);
1168    }
1169    
1170    /**
1171     * Cancel the Action with the given name, if it has been scheduled.
1172     * @param action the name of the Action to cancel
1173     * @return the canceled Action
1174     */

1175    public Activity cancel(String JavaDoc action) {
1176        return m_actions.cancel(action);
1177    }
1178    
1179    // ------------------------------------------------------------------------
1180
// Renderers
1181

1182    /**
1183     * Set the RendererFactory used by this Visualization. The RendererFactory
1184     * is responsible for providing the Renderer instances used to draw
1185     * the VisualItems.
1186     * @param rf the RendererFactory to use.
1187     */

1188    public void setRendererFactory(RendererFactory rf) {
1189        invalidateAll();
1190        m_renderers = rf;
1191    }
1192    
1193    /**
1194     * Get the RendererFactory used by this Visualization.
1195     * @return this Visualization's RendererFactory
1196     */

1197    public RendererFactory getRendererFactory() {
1198        return m_renderers;
1199    }
1200    
1201    /**
1202     * Get the renderer for the given item. Consults this visualization's
1203     * {@link prefuse.render.RendererFactory} and returns the result.
1204     * @param item the item to retreive the renderer for
1205     * @return the {@link prefuse.render.Renderer} for drawing the
1206     * given item
1207     */

1208    public Renderer getRenderer(VisualItem item) {
1209        if ( item.getVisualization() != this ) {
1210            throw new IllegalArgumentException JavaDoc(
1211                    "Input item not a member of this visualization.");
1212        }
1213        return m_renderers.getRenderer(item);
1214    }
1215    
1216    /**
1217     * Issue a repaint request, causing all displays associated with this
1218     * visualization to be repainted.
1219     */

1220    public synchronized void repaint() {
1221        Iterator JavaDoc items = items(ValidatedPredicate.FALSE);
1222        while ( items.hasNext() ) {
1223            ((VisualItem)items.next()).validateBounds();
1224        }
1225        for ( int i=0; i<m_displays.size(); ++i ) {
1226            getDisplay(i).repaint();
1227        }
1228    }
1229    
1230    /**
1231     * Get the bounding rectangle for all items in the given group.
1232     * @param group the visual data group
1233     * @return the bounding box of the items
1234     */

1235    public Rectangle2D JavaDoc getBounds(String JavaDoc group) {
1236        return getBounds(group, new Rectangle2D.Double JavaDoc());
1237    }
1238    
1239    /**
1240     * Get the bounding rectangle for all items in the given group.
1241     * @param group the visual data group name
1242     * @param r a rectangle in which to store the computed bounding box
1243     * @return the input rectangle r, updated to hold the computed
1244     * bounding box
1245     */

1246    public Rectangle2D JavaDoc getBounds(String JavaDoc group, Rectangle2D JavaDoc r) {
1247        Iterator JavaDoc iter = visibleItems(group);
1248        if ( iter.hasNext() ) {
1249            VisualItem item = (VisualItem)iter.next();
1250            r.setRect(item.getBounds());
1251        }
1252        while ( iter.hasNext() ) {
1253            VisualItem item = (VisualItem)iter.next();
1254            Rectangle2D.union(item.getBounds(), r, r);
1255        }
1256        return r;
1257    }
1258    
1259    // ------------------------------------------------------------------------
1260
// Displays
1261

1262    /**
1263     * Get the number of displays associated with this visualization.
1264     * @return the number of displays
1265     */

1266    public int getDisplayCount() {
1267        return m_displays.size();
1268    }
1269    
1270    /**
1271     * Add a display to this visualization. Called automatically by the
1272     * {@link prefuse.Display#setVisualization(Visualization)} method.
1273     * @param display the Display to add
1274     */

1275    void addDisplay(Display display) {
1276        m_displays.add(display);
1277    }
1278    
1279    /**
1280     * Get the display at the given list index. Displays are numbered by the
1281     * order in which they are added to this visualization.
1282     * @param idx the list index
1283     * @return the Display at the given index
1284     */

1285    public Display getDisplay(int idx) {
1286        return (Display)m_displays.get(idx);
1287    }
1288    
1289    /**
1290     * Remove a display from this visualization.
1291     * @param display the display to remove
1292     * @return true if the display was removed, false if it was not found
1293     */

1294    boolean removeDisplay(Display display) {
1295        return m_displays.remove(display);
1296    }
1297    
1298    /**
1299     * Report damage to associated displays, indicating a region that will need
1300     * to be redrawn.
1301     * @param item the item responsible for the damage
1302     * @param region the damaged region, in item-space coordinates
1303     */

1304    public void damageReport(VisualItem item, Rectangle2D JavaDoc region) {
1305        for ( int i=0; i<m_displays.size(); ++i ) {
1306            Display d = getDisplay(i);
1307            if ( d.getPredicate().getBoolean(item) ) {
1308                d.damageReport(region);
1309            }
1310        }
1311    }
1312    
1313} // end of class Visualization
1314
Popular Tags