package prefuse.data.tuple;
import java.beans.PropertyChangeListener;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.event.SwingPropertyChangeSupport;
import prefuse.data.Schema;
import prefuse.data.Table;
import prefuse.data.Tuple;
import prefuse.data.event.EventConstants;
import prefuse.data.event.TupleSetListener;
import prefuse.data.expression.Expression;
import prefuse.data.expression.Predicate;
import prefuse.data.util.FilterIteratorFactory;
import prefuse.data.util.Sort;
import prefuse.data.util.SortedTupleIterator;
import prefuse.util.collections.CopyOnWriteArrayList;
/**
* Abstract base class for TupleSet implementations. Provides mechanisms for
* generating filtered tuple iterators, maintain listeners, and supporting
* bound client properties.
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public abstract class AbstractTupleSet implements TupleSet {
/**
* @see prefuse.data.tuple.TupleSet#tuples(prefuse.data.expression.Predicate)
*/
public Iterator tuples(Predicate filter) {
if ( filter == null ) {
return tuples();
} else {
return FilterIteratorFactory.tuples(this, filter);
}
}
/**
* @see prefuse.data.tuple.TupleSet#tuples(prefuse.data.expression.Predicate, prefuse.data.util.Sort)
*/
public Iterator tuples(Predicate filter, Sort sort) {
if ( sort == null ) {
return tuples(filter);
} else {
Comparator c = sort.getComparator(this);
return new SortedTupleIterator(tuples(filter),getTupleCount(),c);
}
}
// -- TupleSet Methods ----------------------------------------------------
private CopyOnWriteArrayList m_tupleListeners;
/**
* @see prefuse.data.tuple.TupleSet#addTupleSetListener(prefuse.data.event.TupleSetListener)
*/
public void addTupleSetListener(TupleSetListener tsl) {
if ( m_tupleListeners == null )
m_tupleListeners = new CopyOnWriteArrayList();
if ( !m_tupleListeners.contains(tsl) )
m_tupleListeners.add(tsl);
}
/**
* @see prefuse.data.tuple.TupleSet#removeTupleSetListener(prefuse.data.event.TupleSetListener)
*/
public void removeTupleSetListener(TupleSetListener tsl) {
if ( m_tupleListeners != null ) {
m_tupleListeners.remove(tsl);
}
}
/**
* Fire a Tuple event.
* @param t the Table on which the event has occurred
* @param start the first row changed
* @param end the last row changed
* @param type the type of event, one of
* {@link prefuse.data.event.EventConstants#INSERT} or
* {@link prefuse.data.event.EventConstants#DELETE}.
*/
protected void fireTupleEvent(Table t, int start, int end, int type) {
if ( m_tupleListeners != null && m_tupleListeners.size() > 0 ) {
Object[] lstnrs = m_tupleListeners.getArray();
Tuple[] tuples = new Tuple[end-start+1];
for ( int i=0, r=start; r <= end; ++r, ++i ) {
tuples[i] = t.getTuple(r);
}
for ( int i=0; i<lstnrs.length; ++i ) {
TupleSetListener tsl = (TupleSetListener)lstnrs[i];
if ( type == EventConstants.INSERT ) {
tsl.tupleSetChanged(this, tuples, EMPTY_ARRAY);
} else {
tsl.tupleSetChanged(this, EMPTY_ARRAY, tuples);
}
}
}
}
/**
* Fire a Tuple event.
* @param t the tuple that has been added or removed
* @param type the type of event, one of
* {@link prefuse.data.event.EventConstants#INSERT} or
* {@link prefuse.data.event.EventConstants#DELETE}.
*/
protected void fireTupleEvent(Tuple t, int type) {
if ( m_tupleListeners != null && m_tupleListeners.size() > 0 ) {
Object[] lstnrs = m_tupleListeners.getArray();
Tuple[] ts = new Tuple[] {t};
for ( int i=0; i<lstnrs.length; ++i ) {
TupleSetListener tsl = (TupleSetListener)lstnrs[i];
if ( type == EventConstants.INSERT ) {
tsl.tupleSetChanged(this, ts, EMPTY_ARRAY);
} else {
tsl.tupleSetChanged(this, EMPTY_ARRAY, ts);
}
}
}
}
/**
* Fire a Tuple event.
* @param added array of Tuples that have been added, can be null
* @param removed array of Tuples that have been removed, can be null
*/
protected void fireTupleEvent(Tuple[] added, Tuple[] removed) {
if ( m_tupleListeners != null && m_tupleListeners.size() > 0 ) {
Object[] lstnrs = m_tupleListeners.getArray();
added = added==null ? EMPTY_ARRAY : added;
removed = removed==null ? EMPTY_ARRAY : removed;
for ( int i=0; i<lstnrs.length; ++i ) {
TupleSetListener tsl = (TupleSetListener)lstnrs[i];
tsl.tupleSetChanged(this, added, removed);
}
}
}
// -- Data Field Methods --------------------------------------------------
/**
* False by default.
* @see prefuse.data.tuple.TupleSet#isAddColumnSupported()
*/
public boolean isAddColumnSupported() {
return false;
}
/**
* @see prefuse.data.tuple.TupleSet#addColumns(prefuse.data.Schema)
*/
public void addColumns(Schema schema) {
if ( isAddColumnSupported() ) {
for ( int i=0; i<schema.getColumnCount(); ++i ) {
try {
addColumn(schema.getColumnName(i),
schema.getColumnType(i),
schema.getDefault(i));
} catch ( IllegalArgumentException iae ) {}
}
} else {
throw new UnsupportedOperationException();
}
}
/**
* Unsupported by default.
* @see prefuse.data.tuple.TupleSet#addColumn(java.lang.String, java.lang.Class, java.lang.Object)
*/
public void addColumn(String name, Class type, Object defaultValue) {
throw new UnsupportedOperationException();
}
/**
* Unsupported by default.
* @see prefuse.data.tuple.TupleSet#addColumn(java.lang.String, java.lang.Class)
*/
public void addColumn(String name, Class type) {
throw new UnsupportedOperationException();
}
/**
* Unsupported by default.
* @see prefuse.data.tuple.TupleSet#addColumn(java.lang.String, prefuse.data.expression.Expression)
*/
public void addColumn(String name, Expression expr) {
throw new UnsupportedOperationException();
}
/**
* Unsupported by default.
* @see prefuse.data.tuple.TupleSet#addColumn(java.lang.String, java.lang.String)
*/
public void addColumn(String name, String expr) {
throw new UnsupportedOperationException();
}
// -- Client Properties ---------------------------------------------------
private HashMap m_props;
private SwingPropertyChangeSupport m_propSupport;
/**
* @see prefuse.data.tuple.TupleSet#addPropertyChangeListener(java.beans.PropertyChangeListener)
*/
public void addPropertyChangeListener(PropertyChangeListener lstnr) {
if ( lstnr == null ) return;
if ( m_propSupport == null )
m_propSupport = new SwingPropertyChangeSupport(this);
m_propSupport.addPropertyChangeListener(lstnr);
}
/**
* @see prefuse.data.tuple.TupleSet#addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
*/
public void addPropertyChangeListener(String key,
PropertyChangeListener lstnr)
{
if ( lstnr == null ) return;
if ( m_propSupport == null )
m_propSupport = new SwingPropertyChangeSupport(this);
m_propSupport.addPropertyChangeListener(key, lstnr);
}
/**
* @see prefuse.data.tuple.TupleSet#removePropertyChangeListener(java.beans.PropertyChangeListener)
*/
public void removePropertyChangeListener(PropertyChangeListener lstnr) {
if ( lstnr == null ) return;
if ( m_propSupport == null ) return;
m_propSupport.removePropertyChangeListener(lstnr);
}
/**
* @see prefuse.data.tuple.TupleSet#removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
*/
public void removePropertyChangeListener(String key,
PropertyChangeListener lstnr)
{
if ( lstnr == null ) return;
if ( m_propSupport == null ) return;
m_propSupport.removePropertyChangeListener(key, lstnr);
}
/**
* @see prefuse.data.tuple.TupleSet#putClientProperty(java.lang.String, java.lang.Object)
*/
public void putClientProperty(String key, Object value) {
Object prev = null;
if ( m_props == null && value == null ) {
// nothing to do
return;
} else if ( value == null ) {
prev = m_props.remove(key);
} else {
if ( m_props == null )
m_props = new HashMap(2);
prev = m_props.put(key, value);
}
if ( m_propSupport != null )
m_propSupport.firePropertyChange(key, prev, value);
}
/**
* @see prefuse.data.tuple.TupleSet#getClientProperty(java.lang.String)
*/
public Object getClientProperty(String key) {
return ( m_props == null ? null : m_props.get(key) );
}
} // end of class AbstractTupleSet