001: package snow.sortabletable;
002:
003: import snow.utils.gui.*;
004: import snow.Language.Language;
005:
006: import java.awt.*;
007: import java.awt.event.*;
008: import javax.swing.*;
009: import javax.swing.border.*;
010: import javax.swing.event.*;
011: import java.util.*;
012:
013: /** a small utility to add a search panel to a sortable table viewer
014: */
015: public class AdvancedSearchPanel extends JPanel {
016: final protected JTextField searchFT = new JTextField(5);
017: final protected JTextField searchFT2 = new JTextField(5);
018:
019: final protected JButton activateAdvancedButton = new JButton(
020: new SortDirectionSelfDrawingIcon(
021: SortDirectionSelfDrawingIcon.Right));
022: final protected JButton deactivateAdvancedButton = new JButton(
023: new SortDirectionSelfDrawingIcon(
024: SortDirectionSelfDrawingIcon.Left));
025:
026: final protected JComboBox searchOperationCB = new JComboBox(
027: new String[] { "&", "||" });
028: final protected JComboBox searchColumnCB = new JComboBox();
029: final protected JCheckBox regExSearchCB = new JCheckBox(Language
030: .translate("RegEx"), false);
031:
032: protected SortableTableModel stm;
033:
034: boolean advancedMode = false;
035: boolean allowRegEx = false;
036:
037: private Vector<ChangeListener> searchChangeListeners = new Vector<ChangeListener>();
038:
039: final private AnimatedColorPanel backPanelToAnimate = new AnimatedColorPanel(
040: new FlowLayout(FlowLayout.LEFT, 2, 2), 100);
041:
042: /**
043: @param searchLabelText is normally "Search: "
044: */
045: public AdvancedSearchPanel(final String searchLabelText,
046: final Icon searchIcon, final SortableTableModel stm,
047: boolean allowRegEx) {
048: super (new FlowLayout(FlowLayout.LEFT, 0, 0)); // margin already in backPanelToAnimate
049: this .setOpaque(false);
050: backPanelToAnimate.setOpaque(false);
051: this .stm = stm;
052: this .allowRegEx = allowRegEx;
053:
054: // must be a vector for the combobox
055: final Vector<String> colNames = new Vector<String>();
056: colNames.addElement(Language.translate("All Columns"));
057: if (stm != null) {
058: for (int i = 0; i < stm.getBasicTableModel()
059: .getColumnCount(); i++) {
060: colNames.add(stm.getBasicTableModel().getColumnName(i));
061: }
062: searchColumnCB.setModel(new DefaultComboBoxModel(colNames));
063: }
064:
065: if (colNames.size() < 3) {
066: searchColumnCB.setVisible(false);
067: }
068:
069: // Components
070: //
071:
072: add(backPanelToAnimate);
073:
074: backPanelToAnimate.add(new JLabel(searchLabelText, searchIcon,
075: JLabel.LEFT));
076: backPanelToAnimate.add(searchFT);
077:
078: backPanelToAnimate.add(activateAdvancedButton);
079: activateAdvancedButton.setToolTipText(Language
080: .translate("Advanced Search"));
081: activateAdvancedButton.setFocusPainted(false);
082: activateAdvancedButton.addActionListener(new ActionListener() {
083: public void actionPerformed(ActionEvent e) {
084: setAdvancedMode(true);
085: }
086: });
087:
088: backPanelToAnimate.add(searchOperationCB);
089: backPanelToAnimate.add(searchFT2);
090:
091: backPanelToAnimate.add(searchColumnCB);
092: searchColumnCB.setMaximumRowCount(35); // see all, without scroll
093:
094: add(deactivateAdvancedButton);
095: deactivateAdvancedButton.setToolTipText(Language
096: .translate("Return to Simple Search"));
097: deactivateAdvancedButton.setFocusPainted(false);
098: deactivateAdvancedButton
099: .addActionListener(new ActionListener() {
100: public void actionPerformed(ActionEvent e) {
101: setAdvancedMode(false);
102: }
103: });
104:
105: if (allowRegEx) {
106: add(regExSearchCB);
107: regExSearchCB.setOpaque(false);
108: }
109:
110: // key listener
111: //
112: KeyAdapter kad = new KeyAdapter() {
113: @Override
114: public void keyReleased(KeyEvent ee) {
115: doSearch();
116: }
117: };
118:
119: searchOperationCB.addActionListener(new ActionListener() {
120: public void actionPerformed(ActionEvent e) {
121: doSearch();
122: }
123: });
124:
125: searchColumnCB.addActionListener(new ActionListener() {
126: public void actionPerformed(ActionEvent e) {
127: doSearch();
128: }
129: });
130:
131: searchFT.addKeyListener(kad);
132: searchFT2.addKeyListener(kad);
133:
134: // focus behaviour
135: //
136:
137: searchFT.addFocusListener(new FocusAdapter() {
138: @Override
139: public void focusGained(FocusEvent e) {
140: searchFT.selectAll();
141: }
142: });
143: searchFT2.addFocusListener(new FocusAdapter() {
144: @Override
145: public void focusGained(FocusEvent e) {
146: searchFT2.selectAll();
147: }
148: });
149:
150: // [Jan2006]: avoid focus on the UI comps
151: activateAdvancedButton.setFocusable(false);
152: deactivateAdvancedButton.setFocusable(false);
153:
154: // CTRL+F mapping
155: //
156:
157: this .registerKeyboardAction(new ActionListener() {
158: public void actionPerformed(ActionEvent e) {
159: searchFT.requestFocus();
160: }
161: }, KeyStroke.getKeyStroke(KeyEvent.VK_F,
162: KeyEvent.CTRL_DOWN_MASK),
163: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT // BAD when two present: .WHEN_IN_FOCUSED_WINDOW
164: ); // ### Maybe pass the parent as argument reference and register actions on it.
165: // It makes sense if several internal frames have searches...
166:
167: // UI
168:
169: activateAdvancedButton.setPreferredSize(new Dimension(
170: (int) searchFT2.getPreferredSize().getHeight(),
171: (int) searchFT2.getPreferredSize().getHeight()));
172:
173: deactivateAdvancedButton.setPreferredSize(new Dimension(
174: (int) searchFT2.getPreferredSize().getHeight(),
175: (int) searchFT2.getPreferredSize().getHeight()));
176:
177: this .searchOperationCB.setPreferredSize(new Dimension(
178: (int) searchOperationCB.getPreferredSize().getWidth(),
179: (int) searchFT2.getPreferredSize().getHeight()));
180:
181: this .searchColumnCB.setPreferredSize(new Dimension(
182: (int) searchColumnCB.getPreferredSize().getWidth(),
183: (int) searchFT2.getPreferredSize().getHeight()));
184:
185: // initial state
186: EventQueue.invokeLater(new Runnable() {
187: public void run() {
188: setAdvancedMode(advancedMode);
189: }
190: });
191:
192: //this.setBorder(new LineBorder(Color.red,1));
193: }
194:
195: public void setSortableTableModel(SortableTableModel stm) {
196: int fontSize = searchColumnCB.getFont().getSize();
197: int maxWidth = 0;
198:
199: this .stm = stm;
200: if (stm != null) {
201: Vector<String> colNames = new Vector<String>();
202: colNames.addElement(Language.translate("All Columns"));
203: for (int i = 0; i < stm.getBasicTableModel()
204: .getColumnCount(); i++) {
205: String name = stm.getBasicTableModel().getColumnName(i);
206: colNames.add(name);
207:
208: if (name.length() > maxWidth)
209: maxWidth = name.length();
210: }
211: searchColumnCB.setModel(new DefaultComboBoxModel(colNames));
212: } else {
213: searchColumnCB.setModel(new DefaultComboBoxModel(
214: new Vector<String>()));
215: }
216:
217: if (searchColumnCB.getModel().getSize() < 3) {
218: searchColumnCB.setVisible(false);
219: }
220:
221: Dimension dim = new Dimension(fontSize * maxWidth,
222: (int) searchColumnCB.getPreferredSize().getHeight());
223: searchColumnCB.setSize(dim);
224: searchColumnCB.setPreferredSize(dim);
225:
226: doSearch();
227: }
228:
229: /** must be called in the EDT !
230: */
231: public void setAdvancedMode(boolean active) {
232: advancedMode = active;
233: searchFT2.setVisible(active);
234: deactivateAdvancedButton.setVisible(active);
235: searchOperationCB.setVisible(active);
236: searchColumnCB.setVisible(active);
237:
238: this .regExSearchCB.setVisible(allowRegEx && active);
239:
240: activateAdvancedButton.setVisible(!active);
241:
242: doSearch();
243: }
244:
245: /** Must be called in the EDT !
246: All the searches are done from here. This also notify the listeners
247: */
248: public void doSearch() {
249: if (!SwingUtilities.isEventDispatchThread()) {
250: new Throwable("Should be called from EDT !")
251: .printStackTrace();
252: }
253:
254: if (searchFT.getText().length() > 0
255: || (this .advancedMode && searchFT2.getText().length() > 0)) {
256: backPanelToAnimate.activateAnimation(true);
257: backPanelToAnimate.setOpaque(true);
258: } else {
259: backPanelToAnimate.activateAnimation(false);
260: backPanelToAnimate.setOpaque(false);
261: }
262:
263: if (advancedMode) {
264: boolean andSearch = searchOperationCB.getSelectedIndex() == 0;
265: int col = searchColumnCB.getSelectedIndex() - 1; // -1 => all
266: if (stm != null) {
267: stm.advancedSearch(searchFT.getText(), searchFT2
268: .getText(), andSearch, regExSearchCB
269: .isSelected(), col);
270: }
271: } else {
272: // the second field is invisible => don't use it
273: if (stm != null) {
274: stm.search(searchFT.getText(), "", regExSearchCB
275: .isSelected());
276: }
277: }
278:
279: notifySearchChanged();
280: }
281:
282: public boolean hasSearchText() {
283: return searchFT.getText().length() > 0
284: || searchFT2.getText().length() > 0;
285: }
286:
287: public String getSearchText() {
288: return searchFT.getText();
289: }
290:
291: public JTextField getTextField() {
292: return searchFT;
293: }
294:
295: /** must be called in the EDT !
296: */
297: public void setSearchText(String t1, String t2) {
298: searchFT.setText(t1);
299: searchFT2.setText(t2);
300: // do the search
301: doSearch();
302: }
303:
304: //
305: // Listeners
306: //
307:
308: public void addSearchChangeListener(ChangeListener cl) {
309: searchChangeListeners.addElement(cl);
310: }
311:
312: private void notifySearchChanged() {
313: for (ChangeListener cl : searchChangeListeners) {
314: cl.stateChanged(new ChangeEvent(this));
315: }
316: }
317:
318: }
|