package prefuse.data; import java.util.ArrayList; import java.util.Iterator; import javax.swing.event.TableModelEvent; import prefuse.data.column.Column; import prefuse.data.column.ColumnMetadata; import prefuse.data.event.EventConstants; import prefuse.data.event.ExpressionListener; import prefuse.data.event.ProjectionListener; import prefuse.data.event.TableListener; import prefuse.data.expression.BooleanLiteral; import prefuse.data.expression.Expression; import prefuse.data.expression.Predicate; import prefuse.data.tuple.TableTuple; import prefuse.data.util.AcceptAllColumnProjection; import prefuse.data.util.CascadedRowManager; import prefuse.data.util.ColumnProjection; import prefuse.util.collections.CompositeIterator; import prefuse.util.collections.IntIterator; /** *
Table subclass featuring a "cascaded" table design - a CascadedTable can * have a parent table, from which it inherits a potentially filtered set of * rows and columns. Child tables may override the columns of the parent by * having a column of the same name as that of the parent, in which case the * parent's column will not be accessible.
* *Table rows of the parent table can be selectively included by providing * a {@link prefuse.data.expression.Predicate} that filters the parent rows. * Columns of the parent table can be selectively included by providing * a {@link prefuse.data.util.ColumnProjection} indicating the columns to * include.
* *Tuple instances backed by a CascadedTable will be not be equivalent to * the tuples backed by the parent table. However, setting a value in a * CascadedTable that is inherited from a parent table will update * the value in the parent table.
* * @author jeffrey heer */ public class CascadedTable extends Table { /** Cascaded parent table */ protected Table m_parent; /** List of included parent column names */ protected ArrayList m_pnames; /** ColumnProjection determining which columns of the parent table * are included in this table. */ protected ColumnProjection m_colFilter; /** Selection Predicate determining which rows of the parent table * are included in this table. */ protected Predicate m_rowFilter; /** An internal listener class */ protected Listener m_listener; // ------------------------------------------------------------------------ // Constructor /** * Create a new CascadedTable. By default all rows and columns of the * parent table are included in this one. * @param parent the parent Table to use */ public CascadedTable(Table parent) { this(parent, null, null); } /** * Create a new CascadedTable. By default all columns of the parent * table are included in this one. * @param parent the parent Table to use * @param rowFilter a Predicate determining which rows of the parent * table to include in this one. */ public CascadedTable(Table parent, Predicate rowFilter) { this(parent, rowFilter, null); } /** * Create a new CascadedTable. By default all rows of the parent * table are included in this one. * @param parent the parent Table to use * @param colFilter a ColumnProjection determining which columns of the * parent table to include in this one. */ public CascadedTable(Table parent, ColumnProjection colFilter) { this(parent, null, colFilter); } /** * Create a new CascadedTable. * @param parent the parent Table to use * @param rowFilter a Predicate determining which rows of the parent * table to include in this one. * @param colFilter a ColumnProjection determining which columns of the * parent table to include in this one. */ public CascadedTable(Table parent, Predicate rowFilter, ColumnProjection colFilter) { this(parent, rowFilter, colFilter, TableTuple.class); } /** * Create a new CascadedTable. * @param parent the parent Table to use * @param rowFilter a Predicate determining which rows of the parent * table to include in this one. * @param colFilter a ColumnProjection determining which columns of the * parent table to include in this one. * @param tupleType the class type of the Tuple instances to use */ protected CascadedTable(Table parent, Predicate rowFilter, ColumnProjection colFilter, Class tupleType) { super(0, 0, tupleType); m_parent = parent; m_pnames = new ArrayList(); m_rows = new CascadedRowManager(this); m_rowFilter = rowFilter==null ? BooleanLiteral.TRUE : rowFilter; m_colFilter = colFilter==null ? new AcceptAllColumnProjection() : colFilter; filterColumns(); filterRows(); m_listener = new Listener(); m_parent.addTableListener(m_listener); if ( m_rowFilter != BooleanLiteral.TRUE ) m_rowFilter.addExpressionListener(m_listener); m_colFilter.addProjectionListener(m_listener); } // -- non-cascading version ----------------------------------------------- /** * Create a CascadedTable without a backing parent table. */ protected CascadedTable() { this(TableTuple.class); } /** * Create a CascadedTable without a backing parent table. * @param tupleType the class type of the Tuple instances to use */ protected CascadedTable(Class tupleType) { super(0, 0, tupleType); m_pnames = new ArrayList(); } // ------------------------------------------------------------------------ // Filter Methods /** * Determines which columns are inherited from the backing parent table. */ protected void filterColumns() { if ( m_parent == null ) return; for ( int i=0; i