001: package prefuse.data.query;
002:
003: import javax.swing.JComboBox;
004: import javax.swing.JComponent;
005: import javax.swing.JList;
006: import javax.swing.event.ListSelectionEvent;
007: import javax.swing.event.ListSelectionListener;
008:
009: import prefuse.data.Table;
010: import prefuse.data.column.ColumnMetadata;
011: import prefuse.data.expression.BooleanLiteral;
012: import prefuse.data.expression.ColumnExpression;
013: import prefuse.data.expression.ComparisonPredicate;
014: import prefuse.data.expression.Expression;
015: import prefuse.data.expression.Literal;
016: import prefuse.data.expression.OrPredicate;
017: import prefuse.data.expression.Predicate;
018: import prefuse.data.tuple.TupleSet;
019: import prefuse.util.DataLib;
020: import prefuse.util.ui.JToggleGroup;
021:
022: /**
023: * DynamicQueryBinding supporting queries based on a list of included
024: * data values.
025: * @author <a href="http://jheer.org">jeffrey heer</a>
026: */
027: public class ListQueryBinding extends DynamicQueryBinding {
028:
029: /** String used to indicate inclusion of all data values. */
030: private static final String ALL = "All";
031:
032: private Class m_type;
033: private ListModel m_model;
034: private Listener m_lstnr;
035: private boolean m_includeAll;
036:
037: /**
038: * Create a new ListQueryBinding over the given set and data field.
039: * @param ts the TupleSet to query
040: * @param field the data field (Table column) to query
041: */
042: public ListQueryBinding(TupleSet ts, String field) {
043: this (ts, field, true);
044: }
045:
046: /**
047: * Create a new ListQueryBinding over the given set and data field.
048: * @param ts the TupleSet to query
049: * @param field the data field (Table column) to query
050: * @param includeAllOption indicates if the dynamic queries should
051: * include an "All" option for including all data values
052: */
053: public ListQueryBinding(TupleSet ts, String field,
054: boolean includeAllOption) {
055: super (ts, field);
056: m_type = DataLib.inferType(ts, field);
057: m_lstnr = new Listener();
058: m_includeAll = includeAllOption;
059: initPredicate();
060: initModel();
061: }
062:
063: private void initPredicate() {
064: // set up predicate
065: OrPredicate orP = new OrPredicate();
066: orP.add(BooleanLiteral.TRUE);
067: setPredicate(orP);
068: }
069:
070: private void initModel() {
071: if (m_model != null)
072: m_model.removeListSelectionListener(m_lstnr);
073:
074: // set up data / selection model
075: Object[] o = null;
076: if (m_tuples instanceof Table) {
077: ColumnMetadata md = ((Table) m_tuples).getMetadata(m_field);
078: o = md.getOrdinalArray();
079: } else {
080: o = DataLib.ordinalArray(m_tuples.tuples(), m_field);
081: }
082: m_model = new ListModel(o);
083: m_model.addListSelectionListener(m_lstnr);
084: if (m_includeAll) {
085: m_model.insertElementAt(ALL, 0);
086: m_model.setSelectedItem(ALL);
087: }
088: }
089:
090: // ------------------------------------------------------------------------
091:
092: /**
093: * Returns a list model for creating custom dynamic query widgets.
094: * This list model acts both as a data model and a selection model,
095: * and so must be registered as both with any custom widgets.
096: * @return the dynamic query list model
097: */
098: public ListModel getListModel() {
099: return m_model;
100: }
101:
102: /**
103: * Creates a new group of check boxes for interacting with the query.
104: * @return a {@link prefuse.util.ui.JToggleGroup} of check boxes bound to
105: * this dynamic query.
106: * @see prefuse.data.query.DynamicQueryBinding#createComponent()
107: */
108: public JComponent createComponent() {
109: return createCheckboxGroup();
110: }
111:
112: /**
113: * Create a new interactive list for interacting with the query.
114: * @return a {@link javax.swing.JList} bound to this dynamic query.
115: */
116: public JList createList() {
117: JList list = new JList(m_model);
118: list.setSelectionModel(m_model);
119: return list;
120: }
121:
122: /**
123: * Create a new drop-down combo box for interacting with the query.
124: * @return a {@link javax.swing.JComboBox} bound to this dynamic query.
125: */
126: public JComboBox createComboBox() {
127: return new JComboBox(m_model);
128: }
129:
130: /**
131: * Creates a new group of check boxes for interacting with the query.
132: * @return a {@link prefuse.util.ui.JToggleGroup} of check boxes bound to
133: * this dynamic query.
134: */
135: public JToggleGroup createCheckboxGroup() {
136: return createToggleGroup(JToggleGroup.CHECKBOX);
137: }
138:
139: /**
140: * Creates a new group of radio buttons for interacting with the query.
141: * @return a {@link prefuse.util.ui.JToggleGroup} of radio buttons bound to
142: * this dynamic query.
143: */
144: public JToggleGroup createRadioGroup() {
145: return createToggleGroup(JToggleGroup.RADIO);
146: }
147:
148: private JToggleGroup createToggleGroup(int type) {
149: return new JToggleGroup(type, m_model, m_model);
150: }
151:
152: // ------------------------------------------------------------------------
153:
154: /**
155: * Create a comparison predicate fof the given data value
156: */
157: private ComparisonPredicate getComparison(Object o) {
158: Expression left = new ColumnExpression(m_field);
159: Expression right = Literal.getLiteral(o, m_type);
160: return new ComparisonPredicate(ComparisonPredicate.EQ, left,
161: right);
162: }
163:
164: private class Listener implements ListSelectionListener {
165:
166: public void valueChanged(ListSelectionEvent e) {
167: ListModel model = (ListModel) e.getSource();
168: OrPredicate orP = (OrPredicate) m_query;
169:
170: if (model.isSelectionEmpty()) {
171: orP.clear();
172: } else if (m_includeAll && model.isSelectedIndex(0)) {
173: orP.set(BooleanLiteral.TRUE);
174: } else {
175: int min = model.getMinSelectionIndex();
176: int max = model.getMaxSelectionIndex();
177: int count = 0;
178: for (int i = min; i <= max; ++i) {
179: if (model.isSelectedIndex(i))
180: ++count;
181: }
182:
183: if (count == model.getSize()) {
184: orP.set(BooleanLiteral.TRUE);
185: } else if (count == 1) {
186: orP.set(getComparison(model.getElementAt(min)));
187: } else {
188: Predicate[] p = new Predicate[count];
189: for (int i = min, j = 0; i <= max; ++i) {
190: if (model.isSelectedIndex(i))
191: p[j++] = getComparison(model
192: .getElementAt(i));
193: }
194: orP.set(p);
195: }
196: }
197: }
198: }
199:
200: } // end of class ListQueryBinding
|