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

Last change on this file since 4421 was 4421, checked in by kjdon, 21 years ago

the modal dialog now is one of our special ModalDialogs which only block the parent, enabling the use of help files while the dialog is open. A SimpleMenuBar with help on it has been added to the dialog.

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