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

Last change on this file since 12156 was 12115, checked in by kjdon, 18 years ago

Changed text handling to use Dictionary.get rather than Dictionary.setText or Dictionary.registerBoth etc

  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 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.Configuration;
44import org.greenstone.gatherer.Dictionary;
45import org.greenstone.gatherer.Gatherer;
46import org.greenstone.gatherer.gui.GLIButton;
47import org.greenstone.gatherer.gui.SimpleMenuBar;
48import org.greenstone.gatherer.gui.ModalDialog;
49
50/** 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.
51 * @author John Thompson, Greenstone Digital Library, University of Waikato
52 * @version 2.3
53 */
54public final class AutofilterDialog
55 extends ModalDialog {
56 /** The filter being edited. */
57 private Autofilter filter;
58 /** A reference to ourselves so our inner classes can reference us. */
59 private AutofilterDialog self;
60
61 private boolean cancelled;
62 /** The value returned from the filter dialog prompt. Used to determine if a prompt was set or unset, and what subsequent action to take. */
63 private byte return_value = 0;
64 /** The button used to cancel the prompt. */
65 private JButton cancel_button = null;
66 private JButton remove_button = null;
67 private JButton set_button = null;
68 /** Used to specify that the given filters should be applied conjunctly. */
69 private JRadioButton and_radiobutton = null;
70 /** The check box used to specify whether the first filter is case sensitive. */
71 private JCheckBox first_case = null;
72 /** Used to disable the second filter. */
73 private JRadioButton none_radiobutton = null;
74 /** Used to specify that the given filters should be applied disjunctly. */
75 private JRadioButton or_radiobutton = null;
76 /** The check box used to specify whether the second filter is case sensitive. */
77 private JCheckBox second_case = null;
78 /** Used to specify the order of the resulting set: Ascending or Descending. */
79 private JRadioButton ascending_radiobutton = null;
80 private JRadioButton descending_radiobutton = null;
81 /** The method used to match the first filter: Contains, Doesn't contain etc. */
82 private JComboBox first_method = null;
83 /** The value to be matched for the first filter. */
84 private JComboBox first_value = null;
85 /** The method used to match the first filter. Options as for the first method. */
86 private JComboBox second_method = null;
87 /** The value to be matched for the second filter. */
88 private JComboBox second_value = null;
89 /** Used for the most basic filter where an Equals, Case sensitive method is automatically used. */
90 private JComboBox value = null;
91 /** The label which displays the name of the currently selected column (the column that will be associated with the autofilter this dialog produces). */
92 private JLabel name;
93 /** 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. */
94 private JTabbedPane control = null;
95 /** 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. */
96 private MetaAuditFrame dialog;
97 /** The default size for the autofilter control. */
98 static final private Dimension SIZE = new Dimension(640, 245);
99
100 /** Constructor.
101 * @param dialog A reference to the <strong>MetaAuditFrame</strong> that spawned this dialog.
102 * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
103 * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.ButtonListener
104 * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.CheckListener
105 */
106 public AutofilterDialog(MetaAuditFrame dialog) {
107 super(Gatherer.g_man);
108 this.dialog = dialog;
109 this.self = this;
110 setModal(true);
111 setJMenuBar(new SimpleMenuBar("reviewingmetadata"));
112 setSize(SIZE);
113 setTitle(Dictionary.get("Autofilter.Title"));
114
115 // Creation
116 JPanel content_pane = (JPanel) getContentPane();
117 JPanel name_pane = new JPanel();
118 JLabel name_label = new JLabel(Dictionary.get("Autofilter.Name"));
119 JTextField name_template = new JTextField();
120 name = new JLabel();
121 name.setBorder(name_template.getBorder());
122 control = new JTabbedPane();
123 JPanel value_pane = new JPanel();
124 JPanel inner_value_pane = new JPanel();
125 JLabel value_label = new JLabel(Dictionary.get("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(Dictionary.get("Autofilter.Case_Sensitive"));
137 JPanel operator_pane = new JPanel();
138 JLabel operator_label = new JLabel(Dictionary.get("Autofilter.Operator"));
139 ButtonGroup operator_group = new ButtonGroup();
140 and_radiobutton = new JRadioButton(Dictionary.get("Autofilter.AND"));
141 and_radiobutton.setOpaque(false);
142 none_radiobutton = new JRadioButton(Dictionary.get("Autofilter.None"));
143 none_radiobutton.setOpaque(false);
144 none_radiobutton.setSelected(true);
145 or_radiobutton = new JRadioButton(Dictionary.get("Autofilter.OR"));
146 or_radiobutton.setOpaque(false);
147 operator_group.add(none_radiobutton);
148 operator_group.add(and_radiobutton);
149 operator_group.add(or_radiobutton);
150
151 JPanel second_pane = new JPanel();
152 second_method = new JComboBox();
153 second_method.setEnabled(false);
154 second_value = new JComboBox();
155 second_value.setEditable(true);
156 second_value.setEnabled(false);
157 second_value.addItem("");
158 second_value.setSelectedItem("");
159 second_case = new JCheckBox(Dictionary.get("Autofilter.Case_Sensitive"));
160 JPanel lower_pane = new JPanel();
161 JPanel order_pane = new JPanel();
162 order_pane.setToolTipText(Dictionary.get("Autofilter.Order_Tooltip"));
163 JLabel order_label = new JLabel(Dictionary.get("Autofilter.Order"));
164
165 ButtonGroup order_group = new ButtonGroup();
166 ascending_radiobutton = new JRadioButton(Dictionary.get("Autofilter.Ascending"));
167 ascending_radiobutton.setOpaque(false);
168 ascending_radiobutton.setSelected(true);
169 descending_radiobutton = new JRadioButton(Dictionary.get("Autofilter.Descending"));
170 descending_radiobutton.setOpaque(false);
171 order_group.add(ascending_radiobutton);
172 order_group.add(descending_radiobutton);
173
174 // Assign values to method comboboxes.
175 for(int i = 0; i < Autofilter.METHOD_LIST.length; i++) {
176 first_method.addItem(Dictionary.get(Autofilter.METHOD_LIST[i]));
177 second_method.addItem(Dictionary.get(Autofilter.METHOD_LIST[i]));
178 }
179 JPanel button_pane = new JPanel();
180 cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("General.Pure_Cancel_Tooltip"));
181 remove_button = new GLIButton(Dictionary.get("Autofilter.Remove"), Dictionary.get("Autofilter.Remove_Tooltip"));
182 set_button = new GLIButton(Dictionary.get("Autofilter.Set"), Dictionary.get("Autofilter.Set_Tooltip"));
183
184 // Connection
185 and_radiobutton.addActionListener(new CheckListener(true));
186 none_radiobutton.addActionListener(new CheckListener(false));
187 or_radiobutton.addActionListener(new CheckListener(true));
188 cancel_button.addActionListener(new ButtonListener()); // It returns any currently set filter
189 remove_button.addActionListener(new ButtonListener(false));
190 set_button.addActionListener(new ButtonListener(true));
191
192 // Layout
193 name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
194
195 name_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
196 name_pane.setLayout(new BorderLayout());
197 name_pane.add(name_label, BorderLayout.WEST);
198 name_pane.add(name, BorderLayout.CENTER);
199
200 value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
201
202 inner_value_pane.setLayout(new BorderLayout());
203 inner_value_pane.add(value_label, BorderLayout.WEST);
204 inner_value_pane.add(value, BorderLayout.CENTER);
205
206 value_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
207 value_pane.setLayout(new BorderLayout());
208 value_pane.add(inner_value_pane, BorderLayout.NORTH);
209
210 first_pane.setLayout(new BorderLayout());
211 first_pane.add(first_method, BorderLayout.WEST);
212 first_pane.add(first_value, BorderLayout.CENTER);
213 first_pane.add(first_case, BorderLayout.EAST);
214
215 operator_pane.setLayout(new GridLayout(1,4));
216 operator_pane.add(operator_label);
217 operator_pane.add(none_radiobutton);
218 operator_pane.add(and_radiobutton);
219 operator_pane.add(or_radiobutton);
220
221 second_pane.setLayout(new BorderLayout());
222 second_pane.add(second_method, BorderLayout.WEST);
223 second_pane.add(second_value, BorderLayout.CENTER);
224 second_pane.add(second_case, BorderLayout.EAST);
225
226 order_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
227 order_pane.setLayout(new GridLayout(1,2));
228 order_pane.add(order_label);
229 order_pane.add(ascending_radiobutton);
230 order_pane.add(descending_radiobutton);
231
232 custom_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
233 custom_pane.setLayout(new GridLayout(3,1));
234 custom_pane.add(first_pane);
235 custom_pane.add(operator_pane);
236 custom_pane.add(second_pane);
237
238 control.add(Dictionary.get("Autofilter.Filter_By_Value"), value_pane);
239 control.add(Dictionary.get("Autofilter.Custom_Filter"), custom_pane);
240
241 button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
242 button_pane.setLayout(new GridLayout(1, 3));
243 button_pane.add(set_button);
244 button_pane.add(remove_button);
245 button_pane.add(cancel_button);
246
247 lower_pane.setLayout(new BorderLayout());
248 lower_pane.add(order_pane, BorderLayout.CENTER);
249 lower_pane.add(button_pane, BorderLayout.SOUTH);
250
251 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
252 content_pane.setLayout(new BorderLayout());
253 content_pane.add(name_pane, BorderLayout.NORTH);
254 content_pane.add(control, BorderLayout.CENTER);
255 content_pane.add(lower_pane, BorderLayout.SOUTH);
256
257 Dimension screen_size = Configuration.screen_size;
258 setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
259 screen_size = null;
260 }
261
262 public boolean cancelled() {
263 return cancelled;
264 }
265
266 /** Destructor. */
267 public void destroy() {
268 dispose();
269 first_case = null;
270 second_case = null;
271 first_method = null;
272 first_value = null;
273 second_method = null;
274 second_value = null;
275 value = null;
276 control = null;
277 dialog = null;
278 self = null;
279 name = null;
280 }
281 /** 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.
282 * @return An <i>int</i> which indicates which button was pressed to dismiss the dialog.
283 */
284 public Autofilter display(Autofilter filter, ArrayList raw_values, String column_name) {
285 this.cancelled = false;
286 this.filter = filter;
287 name.setText(column_name);
288 // Prune values so it only contains unique entries, then order.
289 TreeSet values = new TreeSet(raw_values);
290 value.setModel(new DefaultComboBoxModel(values.toArray()));
291 String star = "*";
292 value.insertItemAt(star, 0);
293 value.setSelectedItem(star);
294 first_value.setModel(new DefaultComboBoxModel(values.toArray()));
295 second_value.setModel(new DefaultComboBoxModel(values.toArray()));
296 // Restore previous values.
297 if(filter != null && filter.value_one != null) {
298 value.setSelectedItem(filter.value_one);
299 first_method.setSelectedIndex(filter.method_one);
300 first_value.setSelectedItem(filter.value_one);
301 first_case.setSelected(filter.casesense_one);
302 if (filter.value_two == null) {
303 none_radiobutton.setSelected(true);
304 }
305 else {
306 if (filter.operation) {
307 and_radiobutton.setSelected(true);
308 }
309 else {
310 or_radiobutton.setSelected(true);
311 }
312 second_method.setSelectedIndex(filter.method_two);
313 second_value.setSelectedItem(filter.value_two);
314 second_case.setSelected(filter.casesense_two);
315 }
316 if (filter.sort) {
317 ascending_radiobutton.setSelected(true);
318 // order.setSelectedIndex(0);
319 }
320 else {
321 descending_radiobutton.setSelected(true);
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 cancel_button;
335 private boolean return_filter;
336
337 /** Default constructor. Returns any filter that was already set */
338 public ButtonListener() {
339 this.cancel_button = true;
340 }
341
342 /** Does an action on this button cause a filter to be returned. */
343 /** Constructor takes an associated return value as an argument.
344 * @param return_filter <i>true</i> if we update then return the filter, <i>false</i> to clear existing filter.
345 */
346 public ButtonListener(boolean return_filter) {
347 this.cancel_button = false;
348 this.return_filter = return_filter;
349 }
350 /** 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.
351 * @param event An <strong>ActionEvent</strong> containing information about the action that caused this method call.
352 * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
353 */
354 public void actionPerformed(ActionEvent event) {
355 if(cancel_button) {
356 cancelled = true;
357 }
358 else if(return_filter) {
359 if(control.getSelectedIndex() == 0) {
360 filter.setFilter(1, 0, (String)value.getSelectedItem(), true);
361 filter.setFilter(2, 0, null, true);
362 }
363 else {
364 filter.setFilter(1, first_method.getSelectedIndex(), (String)first_value.getSelectedItem(), first_case.isSelected());
365 if(!none_radiobutton.isSelected()) {
366 if (and_radiobutton.isSelected()) {
367 filter.setOperation(Autofilter.AND);
368 }
369 else {
370 filter.setOperation(Autofilter.OR);
371 }
372 filter.setFilter(2, second_method.getSelectedIndex(), (String)second_value.getSelectedItem(), second_case.isSelected());
373 }
374 }
375 if (ascending_radiobutton.isSelected()) {
376 filter.setSort(Autofilter.ASCENDING);
377 }
378 else {
379 filter.setSort(Autofilter.DESCENDING);
380 }
381 }
382 else {
383 filter = null;
384 }
385 setVisible(false);
386 }
387 }
388 /** 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. */
389 private final class CheckListener
390 implements ActionListener {
391 /** The default desire state any check button this listens to. */
392 private boolean desired_state = false;
393 /** The constructor takes an associated desired state.
394 * @param desired_state The state that should be set when this is actioned, as a <i>boolean</i>.
395 */
396 public CheckListener(boolean desired_state) {
397 this.desired_state = desired_state;
398 }
399 /** Whenever our registered components are actioned apon, set the state of the second method and value to the desired state. */
400 public void actionPerformed(ActionEvent event) {
401 second_method.setEnabled(desired_state);
402 second_value.setEnabled(desired_state);
403 }
404 }
405}
Note: See TracBrowser for help on using the repository browser.