📄 cascadedtable.java
字号:
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;
/**
* <p>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.</p>
*
* <p>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.</p>
*
* <p>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 <em>will</em> update
* the value in the parent table.</p>
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
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_listener = new Listener();
setColumnProjection(colFilter);
setRowFilter(rowFilter);
m_parent.addTableListener(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<m_pnames.size(); ++i ) {
String name = (String)m_pnames.get(i);
Column col = m_parent.getColumn(i);
boolean contained = m_names.contains(name);
if ( !m_colFilter.include(col, name) || contained ) {
m_pnames.remove(i--);
if ( !contained ) {
((ColumnEntry)m_entries.get(name)).dispose();
m_entries.remove(name);
}
// fire notification
fireTableEvent(m_rows.getMinimumRow(),
m_rows.getMaximumRow(),
i, EventConstants.DELETE);
}
}
m_pnames.clear();
Iterator pcols = m_parent.getColumnNames();
for ( int i=0, j=m_columns.size(); pcols.hasNext(); ++i ) {
String name = (String)pcols.next();
Column col = m_parent.getColumn(i);
if ( m_colFilter.include(col, name) && !m_names.contains(name) ) {
m_pnames.add(name);
ColumnEntry entry = (ColumnEntry)m_entries.get(name);
if ( entry == null ) {
entry = new ColumnEntry(j++, col,
new ColumnMetadata(this, name));
m_entries.put(name, entry);
// fire notification
fireTableEvent(m_rows.getMinimumRow(),
m_rows.getMaximumRow(),
i, EventConstants.INSERT);
} else {
entry.colnum = j++;
}
m_lastCol = m_columns.size()-1;
}
}
}
/**
* Manually trigger a re-filtering of the rows of this table. If the
* filtering predicate concerns only items within this table, calling
* this method should be unnecessary. It is only when the filtering
* predicate references data outside of this table that a manual
* re-filtering request may be necessary. For example, filtering
* valid edges of a graph from a pool of candidate edges will depend
* on the available nodes.
* @see prefuse.data.util.ValidEdgePredicate
*/
public void filterRows() {
if ( m_parent == null ) return;
CascadedRowManager rowman = (CascadedRowManager)m_rows;
IntIterator crows = m_rows.rows();
while ( crows.hasNext() ) {
int crow = crows.nextInt();
if ( !m_rowFilter.getBoolean(
m_parent.getTuple(rowman.getParentRow(crow))) )
{
removeCascadedRow(crow);
}
}
Iterator ptuples = m_parent.tuples(m_rowFilter);
while ( ptuples.hasNext() ) {
Tuple pt = (Tuple)ptuples.next();
int prow = pt.getRow();
if ( rowman.getChildRow(prow) == -1 )
addCascadedRow(prow);
}
}
/**
* Get the ColumnProjection determining which columns of the
* parent table are included in this one.
* @return the ColumnProjection of this CascadedTable
*/
public ColumnProjection getColumnProjection() {
return m_colFilter;
}
/**
* Sets the ColumnProjection determining which columns of the
* parent table are included in this one.
* @param colFilter a ColumnProjection determining which columns of the
* parent table to include in this one.
*/
public void setColumnProjection(ColumnProjection colFilter) {
if ( m_colFilter != null ) {
m_colFilter.removeProjectionListener(m_listener);
}
m_colFilter = colFilter==null ? new AcceptAllColumnProjection() : colFilter;
m_colFilter.addProjectionListener(m_listener);
filterColumns();
}
/**
* Gets ths Predicate determining which rows of the parent
* table are included in this one.
* @return the row filtering Predicate of this CascadedTable
*/
public Predicate getRowFilter() {
return m_rowFilter;
}
/**
* Sets the Predicate determining which rows of the parent
* table are included in this one.
* @param rowFilter a Predicate determining which rows of the parent
* table to include in this one.
*/
public void setRowFilter(Predicate rowFilter) {
if ( m_rowFilter != null ) {
m_rowFilter.removeExpressionListener(m_listener);
}
m_rowFilter = rowFilter==null ? BooleanLiteral.TRUE : rowFilter;
if ( m_rowFilter != BooleanLiteral.TRUE )
m_rowFilter.addExpressionListener(m_listener);
filterRows();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -