KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > visual > AggregateTable


1 /**
2  * Copyright (c) 2004-2006 Regents of the University of California.
3  * See "license-prefuse.txt" for licensing terms.
4  */

5 package prefuse.visual;
6
7 import java.util.HashSet JavaDoc;
8 import java.util.Iterator JavaDoc;
9
10 import prefuse.Visualization;
11 import prefuse.data.Schema;
12 import prefuse.data.Table;
13 import prefuse.data.Tuple;
14 import prefuse.data.event.EventConstants;
15 import prefuse.data.util.Index;
16 import prefuse.util.collections.IntIterator;
17 import prefuse.visual.tuple.TableAggregateItem;
18
19 /**
20  * VisualTable instance that maintains visual items representing aggregates
21  * of items. This class maintains both a collection of AggregateItems and
22  * a mapping between AggregateItems and the VisualItems contained within
23  * those aggregates.
24  *
25  * @author <a HREF="http://jheer.org">jeffrey heer</a>
26  */

27 public class AggregateTable extends VisualTable {
28
29     /**
30      * Table storing the 1->Many aggregation mappings
31      */

32     protected Table m_aggregated;
33     
34     /**
35      * Create a new AggregateTable.
36      * @param vis the Visualization associated with the table
37      * @param group the data group the table contents belongs to
38      */

39     public AggregateTable(Visualization vis, String JavaDoc group) {
40         this(vis, group, VisualItem.SCHEMA);
41     }
42
43     /**
44      * Create a new AggregateTable.
45      * @param vis the Visualization associated with the table
46      * @param group the data group the table contents belongs to
47      * @param schema the Schema to use for this table
48      */

49     public AggregateTable(Visualization vis, String JavaDoc group, Schema schema) {
50         super(vis, group, schema, TableAggregateItem.class);
51         m_aggregated = AGGREGATED_SCHEMA.instantiate();
52         m_aggregated.index(AGGREGATE);
53         m_aggregated.index(MEMBER_HASH);
54     }
55     
56     // ------------------------------------------------------------------------
57

58     /**
59      * Get the size of the aggregate represented at the given table row.
60      * Returns the number of visual items contained in the aggregation.
61      * @return the aggregate size for the given row
62      */

63     public int getAggregateSize(int row) {
64         int size = 0;
65         AggregatedIterator ati = new AggregatedIterator(row);
66         for ( ; ati.hasNext(); ++size, ati.next() );
67         return size;
68     }
69     
70     /**
71      * Add an item to the aggregation at the given row.
72      * @param row the row index of the aggregate
73      * @param member the item to add to the aggregation
74      */

75     public void addToAggregate(int row, VisualItem member) {
76         validRowCheck(row, true);
77         if ( !aggregateContains(row, member) ) {
78             int ar = m_aggregated.addRow();
79             m_aggregated.setInt(ar, AGGREGATE, row);
80             m_aggregated.setInt(ar, MEMBER_HASH, getHashCode(member));
81             m_aggregated.set(ar, MEMBER, member);
82             fireTableEvent(row, row,
83                     EventConstants.ALL_COLUMNS, EventConstants.UPDATE);
84         }
85     }
86     
87     /**
88      * Remove an item from the aggregation at the given row
89      * @param row the row index of the aggregate
90      * @param member the item to remove from the aggregation
91      */

92     public void removeFromAggregate(int row, VisualItem member) {
93         validRowCheck(row, true);
94         int ar = getAggregatedRow(row, member);
95         if ( ar >= 0 ) {
96             m_aggregated.removeRow(ar);
97             fireTableEvent(row, row,
98                 EventConstants.ALL_COLUMNS, EventConstants.UPDATE);
99         }
100     }
101     
102     /**
103      * Remove all items contained in the aggregate at the given row
104      * @param row the row index of the aggregate
105      */

106     public void removeAllFromAggregate(int row) {
107         clearAggregateMappings(row, true);
108     }
109     
110     /**
111      * Clears all aggregates mappings for the aggregate at the given row,
112      * optionally issuing a table update.
113      * @param row the table row of the aggregate
114      * @param update indicates whether or not to fire a table update
115      */

116     protected void clearAggregateMappings(int row, boolean update) {
117         Index index = m_aggregated.index(AGGREGATE);
118         boolean fire = false;
119         for ( IntIterator rows = index.rows(row); rows.hasNext(); ) {
120             int r = rows.nextInt();
121             // this removal maneuver is ok because we know we are
122
// pulling row values directly from an index
123
// with intervening iterators, remove might throw an exception
124
rows.remove();
125             m_aggregated.removeRow(r);
126             fire = true;
127         }
128         if ( update && fire )
129             fireTableEvent(row, row,
130                 EventConstants.ALL_COLUMNS, EventConstants.UPDATE);
131     }
132     
133     /**
134      * Indicates if an item is a member of the aggregate at the given row
135      * @param row the table row of the aggregate
136      * @param member the item to check from containment
137      * @return true if the item is in the aggregate, false otherwise
138      */

139     public boolean aggregateContains(int row, VisualItem member) {
140         return getAggregatedRow(row, member) >= 0;
141     }
142     
143     /**
144      * Get the row index to the aggregate mapping table for the given
145      * aggregate and contained VisualItem.
146      * @param row the table row of the aggregate
147      * @param member the VisualItem to look up
148      * @return the row index into the internal aggregate mapping table for the
149      * mapping between the given aggregate row and given VisualItem
150      */

151     protected int getAggregatedRow(int row, VisualItem member) {
152         Index index = m_aggregated.index(MEMBER_HASH);
153         int hash = getHashCode(member);
154         int ar = index.get(hash);
155         if ( ar < 0 ) {
156             return -1;
157         } else if ( m_aggregated.getInt(ar, AGGREGATE) == row ) {
158             return ar;
159         } else {
160             for ( IntIterator rows = index.rows(hash); rows.hasNext(); ) {
161                 ar = rows.nextInt();
162                 if ( m_aggregated.getInt(ar, AGGREGATE) == row )
163                     return ar;
164             }
165             return -1;
166         }
167     }
168     
169     /**
170      * Get all VisualItems within the aggregate at the given table row.
171      * @param row the table row of the aggregate
172      * @return an iterator over the items in the aggregate
173      */

174     public Iterator JavaDoc aggregatedTuples(int row) {
175         return new AggregatedIterator(row);
176     }
177     
178     /**
179      * Get an iterator over all AggregateItems that contain the given Tuple.
180      * @param t the input tuple
181      * @return an iterator over all AggregateItems that contain the input Tuple
182      */

183     public Iterator JavaDoc getAggregates(Tuple t) {
184         int hash = getHashCode(t);
185         IntIterator iit = m_aggregated.getIndex(MEMBER_HASH).rows(hash);
186         HashSet JavaDoc set = new HashSet JavaDoc();
187         while ( iit.hasNext() ) {
188             int r = iit.nextInt();
189             set.add(getTuple(m_aggregated.getInt(r, AGGREGATE)));
190         }
191         return set.iterator();
192     }
193     
194     /**
195      * Get a hashcode that uniquely identifies a particular tuple
196      * @param t the tuple to compute the hash for
197      * @return a unique identifier for the tuple
198      */

199     protected int getHashCode(Tuple t) {
200         // this works for now because hashCode is not overloaded on
201
// the provided Tuple implementations
202
return t.hashCode();
203     }
204     
205     /**
206      * Check a row for validity, optionally throwing an exception when an
207      * invalid row is found.
208      * @param row the row to check
209      * @param throwException indicates if an exception should be thrown when an
210      * invalid row is encountered
211      * @return true if the row was valid, false otherwise
212      */

213     protected boolean validRowCheck(int row, boolean throwException) {
214         if ( isValidRow(row) ) {
215             return true;
216         } else if ( throwException ) {
217             throw new IllegalArgumentException JavaDoc("Invalid row value: "+row);
218         } else {
219             return false;
220         }
221     }
222     
223     // ------------------------------------------------------------------------
224
// Table Listener Interception
225

226     /**
227      * Clear all aggregate mappings for a row when it is deleted.
228      */

229     protected void fireTableEvent(int row0, int row1, int col, int type) {
230         if ( col==EventConstants.ALL_COLUMNS && type==EventConstants.DELETE ) {
231             for ( int r=row0; r<=row1; ++r )
232                 clearAggregateMappings(r, false);
233         }
234         super.fireTableEvent(row0, row1, col, type);
235     }
236     
237     
238     // ------------------------------------------------------------------------
239
// Aggregated Iterator
240

241     /**
242      * Iterator instance that iterates over the items contained in an aggregate.
243      */

244     protected class AggregatedIterator implements Iterator JavaDoc {
245         private IntIterator m_rows;
246         private Tuple m_next = null;
247
248         public AggregatedIterator(int row) {
249             Index index = m_aggregated.index(AGGREGATE);
250             m_rows = index.rows(row);
251             advance();
252         }
253         public boolean hasNext() {
254             return m_next != null;
255         }
256         public Object JavaDoc next() {
257             Tuple retval = m_next;
258             advance();
259             return retval;
260         }
261         private void advance() {
262             while ( m_rows.hasNext() ) {
263                 int ar = m_rows.nextInt();
264                 Tuple t = (Tuple)m_aggregated.get(ar, MEMBER);
265                 if ( t.isValid() ) {
266                     m_next = t;
267                     return;
268                 } else {
269                     m_aggregated.removeRow(ar);
270                 }
271             }
272             m_next = null;
273         }
274         public void remove() {
275             throw new UnsupportedOperationException JavaDoc();
276         }
277     }
278     
279     // ------------------------------------------------------------------------
280
// Aggregated Table Schema
281

282     protected static final String JavaDoc AGGREGATE = "aggregate";
283     protected static final String JavaDoc MEMBER_HASH = "hash";
284     protected static final String JavaDoc MEMBER = "member";
285     protected static final Schema AGGREGATED_SCHEMA = new Schema();
286     static {
287         AGGREGATED_SCHEMA.addColumn(AGGREGATE, int.class);
288         AGGREGATED_SCHEMA.addColumn(MEMBER_HASH, int.class);
289         AGGREGATED_SCHEMA.addColumn(MEMBER, Tuple.class);
290     }
291     
292 } // end of class AggregateTable
293
Popular Tags