package prefuse.data.query; import javax.swing.JComponent; import prefuse.data.Tuple; import prefuse.data.event.TupleSetListener; import prefuse.data.expression.AbstractPredicate; import prefuse.data.search.PrefixSearchTupleSet; import prefuse.data.search.SearchTupleSet; import prefuse.data.tuple.TupleSet; import prefuse.util.ui.JSearchPanel; import prefuse.visual.VisualTupleSet; /** * DynamicQueryBinding supporting text search over data values. Implementations * of the {@link prefuse.data.search.SearchTupleSet} class from the * {@link prefuse.data.search} package can be used to control the type of * search index used. * * @author <a href="http://jheer.org">jeffrey heer</a> * @see prefuse.data.search.SearchTupleSet */ public class SearchQueryBinding extends DynamicQueryBinding { private SearchTupleSet m_set; private Listener m_lstnr; private Object m_lock; private TupleSet ts; /** * Create a new SearchQueryBinding over the given set and data field. * @param ts the TupleSet to query * @param field the data field (Table column) to query */ public SearchQueryBinding(TupleSet ts, String field) { this(ts, field, new PrefixSearchTupleSet()); this.ts = ts; } /** * Create a new SearchQueryBinding over the given set and data field, * using the specified SearchTupleSet instance. Use this constructor to * choose the type of search engine used, and to potentially reuse the * same search set over multiple dynamic query bindings. * @param ts the TupleSet to query * @param field the data field (Table column) to query * @param set the {@link prefuse.data.search.SearchTupleSet} to use. */ public SearchQueryBinding(TupleSet ts, String field, SearchTupleSet set) { super(ts, field); m_lstnr = new Listener(); setPredicate(new SearchBindingPredicate()); m_set = set; m_set.index(ts.tuples(), field); m_set.addTupleSetListener(m_lstnr); if ( ts instanceof VisualTupleSet ) m_lock = ((VisualTupleSet)ts).getVisualization(); } public void addField(String field){ m_set.index(ts.tuples(), field); } /** * Return the SearchTupleSet used for conducting searches. * @return the {@link prefuse.data.search.SearchTupleSet} used by this * dynamic query binding. */ public SearchTupleSet getSearchSet() { return m_set; } // ------------------------------------------------------------------------ /** * Create a new search text panel for searching over the data. * @return a {@link prefuse.util.ui.JSearchPanel} bound to this * dynamic query. * @see prefuse.data.query.DynamicQueryBinding#createComponent() */ public JComponent createComponent() { return createSearchPanel(); } /** * Create a new search text panel for searching over the data. * @return a {@link prefuse.util.ui.JSearchPanel} bound to this * dynamic query. */ public JSearchPanel createSearchPanel() { return createSearchPanel(m_set instanceof PrefixSearchTupleSet); } /** * Create a new search text panel for searching over the data. * @param monitorKeystrokes if true, each keystroke will cause the * search to be re-run (this is the default for prefix searches); * if false, searches will only re-run when the enter key is typed * (this is the default for the other search engine types). * @return a {@link prefuse.util.ui.JSearchPanel} bound to this * dynamic query. */ public JSearchPanel createSearchPanel(boolean monitorKeystrokes) { JSearchPanel jsp = new JSearchPanel(m_set, m_field, monitorKeystrokes); if ( m_lock != null ) { jsp.setLock(m_lock); } return jsp; } // ------------------------------------------------------------------------ private class SearchBindingPredicate extends AbstractPredicate { public boolean getBoolean(Tuple t) { String q = m_set.getQuery(); return (q==null || q.length()==0 || m_set.containsTuple(t)); } public void touch() { this.fireExpressionChange(); } } private class Listener implements TupleSetListener { public void tupleSetChanged(TupleSet tset, Tuple[] added, Tuple[] removed) { ((SearchBindingPredicate)getPredicate()).touch(); } } } // end of class SearchQueryBinding