source: trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/AutofilterDialog.java@ 5564

Last change on this file since 5564 was 5564, checked in by mdewsnip, 21 years ago

Many more small improvements and tooltips added. Still more to come!

  • Property svn:keywords set to Author Date Id Revision
File size: 16.3 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui.metaaudit;
38
39import java.awt.*;
40import java.awt.event.*;
41import java.util.*;
42import javax.swing.*;
43import org.greenstone.gatherer.Dictionary;
44import org.greenstone.gatherer.Gatherer;
45import org.greenstone.gatherer.gui.metaaudit.Autofilter;
46import org.greenstone.gatherer.gui.metaaudit.Filter;
47import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
48import org.greenstone.gatherer.gui.SimpleMenuBar;
49import org.greenstone.gatherer.gui.ModalDialog;
50
51/** The autofilter concept comes from Microsoft Excel spreadsheets that use autofilters to filter to the sheet. When you click on the heading of a column, a new prompt allows you to specify what filter should be acting apon the selected column. Any new filter is conjoined with any previous filters to provide a sheet containing only rows that match all current filters. Each column must also provide an indicator for determining if a filter is set (in this case a special icon) and and a method for removing a filter (use the clear filter button within the autofilter dialog). Having recently discovered that most JVMs aren't very good at recoving memory used by dialog and frame windows, special care must be made to deallocate all references properly, as a user may open several dozen autofilter prompts over the lifetime of a session.
52 * @author John Thompson, Greenstone Digital Library, University of Waikato
53 * @version 2.3
54 */
55public final class AutofilterDialog
56 extends ModalDialog {
57 /** The filter being edited. */
58 private Autofilter filter;
59 /** A reference to ourselves so our inner classes can reference us. */
60 private AutofilterDialog self;
61 /** The value returned from the filter dialog prompt. Used to determine if a prompt was set or unset, and what subsequent action to take. */
62 private byte return_value = 0;
63 /** The button used to cancel the prompt. */
64 private JButton cancel_button = null;
65 private JButton remove_button = null;
66 private JButton set_button = null;
67 /** Used to specify that the given filters should be applied conjunctly. */
68 private JRadioButton and_radiobutton = null;
69 /** The check box used to specify whether the first filter is case sensitive. */
70 private JCheckBox first_case = null;
71 /** Used to disable the second filter. */
72 private JRadioButton none_radiobutton = null;
73 /** Used to specify that the given filters should be applied disjunctly. */
74 private JRadioButton or_radiobutton = null;
75 /** The check box used to specify whether the second filter is case sensitive. */
76 private JCheckBox second_case = null;
77 /** Used to specify the order of the resulting set: Ascending or Descending. */
78 private JComboBox order = null;
79 /** The method used to match the first filter: Contains, Doesn't contain etc. */
80 private JComboBox first_method = null;
81 /** The value to be matched for the first filter. */
82 private JComboBox first_value = null;
83 /** The method used to match the first filter. Options as for the first method. */
84 private JComboBox second_method = null;
85 /** The value to be matched for the second filter. */
86 private JComboBox second_value = null;
87 /** Used for the most basic filter where an Equals, Case sensitive method is automatically used. */
88 private JComboBox value = null;
89 /** The label which displays the name of the currently selected column (the column that will be associated with the autofilter this dialog produces). */
90 private JLabel name;
91 /** The autofilter prompt contains two different panes, one for basic functionality and one for advanced. This containiner component is used to allow access to each via a 'tabbed' interface. */
92 private JTabbedPane control = null;
93 /** A reference back to the MetaAudit dialog that spawned this prompt. Used to make sure that any open dialog window is always in front of the audit pane. */
94 private MetaAuditFrame dialog;
95 /** The default size for the autofilter control. */
96 static final private Dimension SIZE = new Dimension(640, 245);
97
98 /** Constructor.
99 * @param dialog A reference to the <strong>MetaAuditFrame</strong> that spawned this dialog.
100 * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
101 * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.ButtonListener
102 * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.CheckListener
103 */
104 public AutofilterDialog(MetaAuditFrame dialog) {
105 super(Gatherer.g_man);
106 this.dialog = dialog;
107 this.self = this;
108 setModal(true);
109 setJMenuBar(new SimpleMenuBar("reviewingmetadata"));
110 setSize(SIZE);
111 Dictionary.setText(this, "Autofilter.Title");
112
113 // Creation
114 JPanel content_pane = (JPanel) getContentPane();
115 JPanel name_pane = new JPanel();
116 JLabel name_label = new JLabel();
117 Dictionary.setText(name_label, "Autofilter.Name");
118 JTextField name_template = new JTextField();
119 name = new JLabel();
120 name.setBorder(name_template.getBorder());
121 control = new JTabbedPane();
122 JPanel value_pane = new JPanel();
123 JPanel inner_value_pane = new JPanel();
124 JLabel value_label = new JLabel();
125 Dictionary.setText(value_label, "Autofilter.eqeq");
126 value = new JComboBox();
127 value.setEditable(false);
128 JPanel custom_pane = new JPanel();
129
130 JPanel first_pane = new JPanel();
131 first_method = new JComboBox();
132 first_value = new JComboBox();
133 first_value.setEditable(true);
134 first_value.addItem("");
135 first_value.setSelectedItem("");
136 first_case = new JCheckBox();
137 Dictionary.setText(first_case, "Autofilter.Case_Sensitive");
138 JPanel operator_pane = new JPanel();
139 JLabel operator_label = new JLabel();
140 Dictionary.setText(operator_label, "Autofilter.Operator");
141 ButtonGroup operator_group = new ButtonGroup();
142 and_radiobutton = new JRadioButton();
143 and_radiobutton.setOpaque(false);
144 Dictionary.setText(and_radiobutton, "Autofilter.AND");
145 none_radiobutton = new JRadioButton();
146 none_radiobutton.setOpaque(false);
147 none_radiobutton.setSelected(true);
148 Dictionary.setText(none_radiobutton, "Autofilter.None");
149 or_radiobutton = new JRadioButton();
150 or_radiobutton.setOpaque(false);
151 Dictionary.setText(or_radiobutton, "Autofilter.OR");
152 operator_group.add(none_radiobutton);
153 operator_group.add(and_radiobutton);
154 operator_group.add(or_radiobutton);
155
156 JPanel second_pane = new JPanel();
157 second_method = new JComboBox();
158 second_method.setEnabled(false);
159 second_value = new JComboBox();
160 second_value.setEditable(true);
161 second_value.setEnabled(false);
162 second_value.addItem("");
163 second_value.setSelectedItem("");
164 second_case = new JCheckBox();
165 Dictionary.setText(second_case, "Autofilter.Case_Sensitive");
166 JPanel lower_pane = new JPanel();
167 JPanel order_pane = new JPanel();
168 JLabel order_label = new JLabel();
169 Dictionary.setText(order_label, "Autofilter.Order");
170 order = new JComboBox();
171 order.addItem(Dictionary.newget("Autofilter.Ascending"));
172 order.addItem(Dictionary.newget("Autofilter.Descending"));
173 Dictionary.setTooltip(order, "Autofilter.Order_Tooltip");
174
175 // Assign values to method comboboxes.
176 for(int i = 0; i < Autofilter.METHOD_LIST.length; i++) {
177 first_method.addItem(Dictionary.newget("Autofilter." + Autofilter.METHOD_LIST[i]));
178 second_method.addItem(Dictionary.newget("Autofilter." + Autofilter.METHOD_LIST[i]));
179 }
180 JPanel button_pane = new JPanel();
181 cancel_button = new JButton();
182 cancel_button.setMnemonic(KeyEvent.VK_C);
183 Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
184 remove_button = new JButton();
185 remove_button.setMnemonic(KeyEvent.VK_R);
186 Dictionary.setBoth(remove_button, "Autofilter.Remove", "Autofilter.Remove_Tooltip");
187 set_button = new JButton();
188 set_button.setMnemonic(KeyEvent.VK_S);
189 Dictionary.setBoth(set_button, "Autofilter.Set", "Autofilter.Set_Tooltip");
190
191 // Connection
192 and_radiobutton.addActionListener(new CheckListener(true));
193 none_radiobutton.addActionListener(new CheckListener(false));
194 or_radiobutton.addActionListener(new CheckListener(true));
195 cancel_button.addActionListener(new ButtonListener(false));
196 remove_button.addActionListener(new ButtonListener(false));
197 set_button.addActionListener(new ButtonListener(true));
198
199 // Layout
200 name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
201
202 name_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
203 name_pane.setLayout(new BorderLayout());
204 name_pane.add(name_label, BorderLayout.WEST);
205 name_pane.add(name, BorderLayout.CENTER);
206
207 value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
208
209 inner_value_pane.setLayout(new BorderLayout());
210 inner_value_pane.add(value_label, BorderLayout.WEST);
211 inner_value_pane.add(value, BorderLayout.CENTER);
212
213 value_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
214 value_pane.setLayout(new BorderLayout());
215 value_pane.add(inner_value_pane, BorderLayout.NORTH);
216
217 first_pane.setLayout(new BorderLayout());
218 first_pane.add(first_method, BorderLayout.WEST);
219 first_pane.add(first_value, BorderLayout.CENTER);
220 first_pane.add(first_case, BorderLayout.EAST);
221
222 operator_pane.setLayout(new GridLayout(1,4));
223 operator_pane.add(operator_label);
224 operator_pane.add(none_radiobutton);
225 operator_pane.add(and_radiobutton);
226 operator_pane.add(or_radiobutton);
227
228 second_pane.setLayout(new BorderLayout());
229 second_pane.add(second_method, BorderLayout.WEST);
230 second_pane.add(second_value, BorderLayout.CENTER);
231 second_pane.add(second_case, BorderLayout.EAST);
232
233 order_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
234 order_pane.setLayout(new GridLayout(1,2));
235 order_pane.add(order_label);
236 order_pane.add(order);
237
238 custom_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
239 custom_pane.setLayout(new GridLayout(3,1));
240 custom_pane.add(first_pane);
241 custom_pane.add(operator_pane);
242 custom_pane.add(second_pane);
243
244 control.add(Dictionary.newget("Autofilter.Filter_By_Value"), value_pane);
245 control.add(Dictionary.newget("Autofilter.Custom_Filter"), custom_pane);
246
247 button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
248 button_pane.setLayout(new GridLayout(1, 3));
249 button_pane.add(set_button);
250 button_pane.add(remove_button);
251 button_pane.add(cancel_button);
252
253 lower_pane.setLayout(new BorderLayout());
254 lower_pane.add(order_pane, BorderLayout.CENTER);
255 lower_pane.add(button_pane, BorderLayout.SOUTH);
256
257 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
258 content_pane.setLayout(new BorderLayout());
259 content_pane.add(name_pane, BorderLayout.NORTH);
260 content_pane.add(control, BorderLayout.CENTER);
261 content_pane.add(lower_pane, BorderLayout.SOUTH);
262
263 Dimension screen_size = Gatherer.config.screen_size;
264 setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
265 screen_size = null;
266 }
267
268 /** Destructor. */
269 public void destroy() {
270 dispose();
271 first_case = null;
272 second_case = null;
273 order = null;
274 first_method = null;
275 first_value = null;
276 second_method = null;
277 second_value = null;
278 value = null;
279 control = null;
280 dialog = null;
281 self = null;
282 name = null;
283 }
284 /** Display the modal dialog box, allowing the user to define the filter. When the user presses one of the buttons, dispose and return to the caller providing an indication of which button was pressed.
285 * @return An <i>int</i> which indicates which button was pressed to dismiss the dialog.
286 */
287 public Autofilter display(Autofilter filter, ArrayList raw_values, String column_name) {
288 this.filter = filter;
289 name.setText(column_name);
290 // Prune values so it only contains unique entries, then order.
291 TreeSet values = new TreeSet(raw_values);
292 value.setModel(new DefaultComboBoxModel(values.toArray()));
293 String star = "*";
294 value.insertItemAt(star, 0);
295 value.setSelectedItem(star);
296 first_value.setModel(new DefaultComboBoxModel(values.toArray()));
297 second_value.setModel(new DefaultComboBoxModel(values.toArray()));
298 // Restore previous values.
299 if(filter != null && filter.value_one != null) {
300 value.setSelectedItem(filter.value_one);
301 first_method.setSelectedIndex(filter.method_one);
302 first_value.setSelectedItem(filter.value_one);
303 first_case.setSelected(filter.casesense_one);
304 if (filter.value_two == null) {
305 none_radiobutton.setSelected(true);
306 }
307 else {
308 if (filter.operation) {
309 and_radiobutton.setSelected(true);
310 }
311 else {
312 or_radiobutton.setSelected(true);
313 }
314 second_method.setSelectedIndex(filter.method_two);
315 second_value.setSelectedItem(filter.value_two);
316 second_case.setSelected(filter.casesense_two);
317 }
318 if(filter.sort) {
319 order.setSelectedIndex(0);
320 }
321 else {
322 order.setSelectedIndex(1);
323 }
324 }
325 // Display
326 setVisible(true);
327 dialog.toFront();
328 return this.filter;
329 }
330
331 /** Listens for actions on the button it is attached to, and when notified sets the return_value and disposes of the dialog. */
332 private final class ButtonListener
333 implements ActionListener {
334 private boolean return_filter;
335 /** Does an action on this button cause a filter to be returned. */
336 /** Constructor takes an associated return value as an argument.
337 * @param return_filter <i>true</i> if we update then return the filter, <i>false</i> to clear existing filter.
338 */
339 public ButtonListener(boolean return_filter) {
340 this.return_filter = return_filter;
341 }
342 /** When any registered component is actioned apon, set the value and hide the dialog. We hide rather than dispose, because hide assures the data values will be retained.
343 * @param event An <strong>ActionEvent</strong> containing information about the action that caused this method call.
344 * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
345 */
346 public void actionPerformed(ActionEvent event) {
347 if(return_filter) {
348 if(control.getSelectedIndex() == 0) {
349 filter.setFilter(1, 0, (String)value.getSelectedItem(), true);
350 filter.setFilter(2, 0, null, true);
351 }
352 else {
353 filter.setFilter(1, first_method.getSelectedIndex(), (String)first_value.getSelectedItem(), first_case.isSelected());
354 if(!none_radiobutton.isSelected()) {
355 if (and_radiobutton.isSelected()) {
356 filter.setOperation(Autofilter.AND);
357 }
358 else {
359 filter.setOperation(Autofilter.OR);
360 }
361 filter.setFilter(2, second_method.getSelectedIndex(), (String)second_value.getSelectedItem(), second_case.isSelected());
362 }
363 }
364 if(order.getSelectedIndex() == 0) {
365 filter.setSort(Autofilter.ASCENDING);
366 }
367 else {
368 filter.setSort(Autofilter.DESCENDING);
369 }
370 }
371 else {
372 filter = null;
373 }
374 setVisible(false);
375 }
376 }
377 /** Listens for actions on the check box it is attached to, and when notified sets the state of the second method and value to the specified state. */
378 private final class CheckListener
379 implements ActionListener {
380 /** The default desire state any check button this listens to. */
381 private boolean desired_state = false;
382 /** The constructor takes an associated desired state.
383 * @param desired_state The state that should be set when this is actioned, as a <i>boolean</i>.
384 */
385 public CheckListener(boolean desired_state) {
386 this.desired_state = desired_state;
387 }
388 /** Whenever our registered components are actioned apon, set the state of the second method and value to the desired state. */
389 public void actionPerformed(ActionEvent event) {
390 second_method.setEnabled(desired_state);
391 second_value.setEnabled(desired_state);
392 }
393 }
394}
395
396
397
398
399
400
401
402
403
Note: See TracBrowser for help on using the repository browser.