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

Last change on this file since 13195 was 13195, checked in by kjdon, 17 years ago

quan's changes to remove blue borders around buttons and comboboxes on macs

  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 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.setOpaque(false);
128 value.setEditable(false);
129 JPanel custom_pane = new JPanel();
130
131 JPanel first_pane = new JPanel();
132 first_method = new JComboBox();
133 first_method.setOpaque(false);
134 first_value = new JComboBox();
135 first_value.setOpaque(false);
136 first_value.setEditable(true);
137 first_value.addItem("");
138 first_value.setSelectedItem("");
139 first_case = new JCheckBox(Dictionary.get("Autofilter.Case_Sensitive"));
140 JPanel operator_pane = new JPanel();
141 JLabel operator_label = new JLabel(Dictionary.get("Autofilter.Operator"));
142 ButtonGroup operator_group = new ButtonGroup();
143 and_radiobutton = new JRadioButton(Dictionary.get("Autofilter.AND"));
144 and_radiobutton.setOpaque(false);
145 none_radiobutton = new JRadioButton(Dictionary.get("Autofilter.None"));
146 none_radiobutton.setOpaque(false);
147 none_radiobutton.setSelected(true);
148 or_radiobutton = new JRadioButton(Dictionary.get("Autofilter.OR"));
149 or_radiobutton.setOpaque(false);
150 operator_group.add(none_radiobutton);
151 operator_group.add(and_radiobutton);
152 operator_group.add(or_radiobutton);
153
154 JPanel second_pane = new JPanel();
155 second_method = new JComboBox();
156 second_method.setOpaque(false);
157 second_method.setEnabled(false);
158 second_value = new JComboBox();
159 second_value.setOpaque(false);
160 second_value.setEditable(true);
161 second_value.setEnabled(false);
162 second_value.addItem("");
163 second_value.setSelectedItem("");
164 second_case = new JCheckBox(Dictionary.get("Autofilter.Case_Sensitive"));
165 JPanel lower_pane = new JPanel();
166 JPanel order_pane = new JPanel();
167 order_pane.setToolTipText(Dictionary.get("Autofilter.Order_Tooltip"));
168 JLabel order_label = new JLabel(Dictionary.get("Autofilter.Order"));
169
170 ButtonGroup order_group = new ButtonGroup();
171 ascending_radiobutton = new JRadioButton(Dictionary.get("Autofilter.Ascending"));
172 ascending_radiobutton.setOpaque(false);
173 ascending_radiobutton.setSelected(true);
174 descending_radiobutton = new JRadioButton(Dictionary.get("Autofilter.Descending"));
175 descending_radiobutton.setOpaque(false);
176 order_group.add(ascending_radiobutton);
177 order_group.add(descending_radiobutton);
178
179 // Assign values to method comboboxes.
180 for(int i = 0; i < Autofilter.METHOD_LIST.length; i++) {
181 first_method.addItem(Dictionary.get(Autofilter.METHOD_LIST[i]));
182 second_method.addItem(Dictionary.get(Autofilter.METHOD_LIST[i]));
183 }
184 JPanel button_pane = new JPanel();
185 cancel_button = new GLIButton(Dictionary.get("General.Cancel"), Dictionary.get("General.Pure_Cancel_Tooltip"));
186 remove_button = new GLIButton(Dictionary.get("Autofilter.Remove"), Dictionary.get("Autofilter.Remove_Tooltip"));
187 set_button = new GLIButton(Dictionary.get("Autofilter.Set"), Dictionary.get("Autofilter.Set_Tooltip"));
188
189 // Connection
190 and_radiobutton.addActionListener(new CheckListener(true));
191 none_radiobutton.addActionListener(new CheckListener(false));
192 or_radiobutton.addActionListener(new CheckListener(true));
193 cancel_button.addActionListener(new ButtonListener()); // It returns any currently set filter
194 remove_button.addActionListener(new ButtonListener(false));
195 set_button.addActionListener(new ButtonListener(true));
196
197 // Layout
198 name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
199
200 name_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
201 name_pane.setLayout(new BorderLayout());
202 name_pane.add(name_label, BorderLayout.WEST);
203 name_pane.add(name, BorderLayout.CENTER);
204
205 value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
206
207 inner_value_pane.setLayout(new BorderLayout());
208 inner_value_pane.add(value_label, BorderLayout.WEST);
209 inner_value_pane.add(value, BorderLayout.CENTER);
210
211 value_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
212 value_pane.setLayout(new BorderLayout());
213 value_pane.add(inner_value_pane, BorderLayout.NORTH);
214
215 first_pane.setLayout(new BorderLayout());
216 first_pane.add(first_method, BorderLayout.WEST);
217 first_pane.add(first_value, BorderLayout.CENTER);
218 first_pane.add(first_case, BorderLayout.EAST);
219
220 operator_pane.setLayout(new GridLayout(1,4));
221 operator_pane.add(operator_label);
222 operator_pane.add(none_radiobutton);
223 operator_pane.add(and_radiobutton);
224 operator_pane.add(or_radiobutton);
225
226 second_pane.setLayout(new BorderLayout());
227 second_pane.add(second_method, BorderLayout.WEST);
228 second_pane.add(second_value, BorderLayout.CENTER);
229 second_pane.add(second_case, BorderLayout.EAST);
230
231 order_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
232 order_pane.setLayout(new GridLayout(1,2));
233 order_pane.add(order_label);
234 order_pane.add(ascending_radiobutton);
235 order_pane.add(descending_radiobutton);
236
237 custom_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
238 custom_pane.setLayout(new GridLayout(3,1));
239 custom_pane.add(first_pane);
240 custom_pane.add(operator_pane);
241 custom_pane.add(second_pane);
242
243 control.add(Dictionary.get("Autofilter.Filter_By_Value"), value_pane);
244 control.add(Dictionary.get("Autofilter.Custom_Filter"), custom_pane);
245
246 button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
247 button_pane.setLayout(new GridLayout(1, 3));
248 button_pane.add(set_button);
249 button_pane.add(remove_button);
250 button_pane.add(cancel_button);
251
252 lower_pane.setLayout(new BorderLayout());
253 lower_pane.add(order_pane, BorderLayout.CENTER);
254 lower_pane.add(button_pane, BorderLayout.SOUTH);
255
256 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
257 content_pane.setLayout(new BorderLayout());
258 content_pane.add(name_pane, BorderLayout.NORTH);
259 content_pane.add(control, BorderLayout.CENTER);
260 content_pane.add(lower_pane, BorderLayout.SOUTH);
261
262 Dimension screen_size = Configuration.screen_size;
263 setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
264 screen_size = null;
265 }
266
267 public boolean cancelled() {
268 return cancelled;
269 }
270
271 /** Destructor. */
272 public void destroy() {
273 dispose();
274 first_case = null;
275 second_case = null;
276 first_method = null;
277 first_value = null;
278 second_method = null;
279 second_value = null;
280 value = null;
281 control = null;
282 dialog = null;
283 self = null;
284 name = null;
285 }
286 /** 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.
287 * @return An <i>int</i> which indicates which button was pressed to dismiss the dialog.
288 */
289 public Autofilter display(Autofilter filter, ArrayList raw_values, String column_name) {
290 this.cancelled = false;
291 this.filter = filter;
292 name.setText(column_name);
293 // Prune values so it only contains unique entries, then order.
294 TreeSet values = new TreeSet(raw_values);
295 value.setModel(new DefaultComboBoxModel(values.toArray()));
296 String star = "*";
297 value.insertItemAt(star, 0);
298 value.setSelectedItem(star);
299 first_value.setModel(new DefaultComboBoxModel(values.toArray()));
300 second_value.setModel(new DefaultComboBoxModel(values.toArray()));
301 // Restore previous values.
302 if(filter != null && filter.value_one != null) {
303 value.setSelectedItem(filter.value_one);
304 first_method.setSelectedIndex(filter.method_one);
305 first_value.setSelectedItem(filter.value_one);
306 first_case.setSelected(filter.casesense_one);
307 if (filter.value_two == null) {
308 none_radiobutton.setSelected(true);
309 }
310 else {
311 if (filter.operation) {
312 and_radiobutton.setSelected(true);
313 }
314 else {
315 or_radiobutton.setSelected(true);
316 }
317 second_method.setSelectedIndex(filter.method_two);
318 second_value.setSelectedItem(filter.value_two);
319 second_case.setSelected(filter.casesense_two);
320 }
321 if (filter.sort) {
322 ascending_radiobutton.setSelected(true);
323 // order.setSelectedIndex(0);
324 }
325 else {
326 descending_radiobutton.setSelected(true);
327 // order.setSelectedIndex(1);
328 }
329 }
330 // Display
331 setVisible(true);
332 dialog.toFront();
333 return this.filter;
334 }
335
336 /** Listens for actions on the button it is attached to, and when notified sets the return_value and disposes of the dialog. */
337 private final class ButtonListener
338 implements ActionListener {
339 private boolean cancel_button;
340 private boolean return_filter;
341
342 /** Default constructor. Returns any filter that was already set */
343 public ButtonListener() {
344 this.cancel_button = true;
345 }
346
347 /** Does an action on this button cause a filter to be returned. */
348 /** Constructor takes an associated return value as an argument.
349 * @param return_filter <i>true</i> if we update then return the filter, <i>false</i> to clear existing filter.
350 */
351 public ButtonListener(boolean return_filter) {
352 this.cancel_button = false;
353 this.return_filter = return_filter;
354 }
355 /** 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.
356 * @param event An <strong>ActionEvent</strong> containing information about the action that caused this method call.
357 * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
358 */
359 public void actionPerformed(ActionEvent event) {
360 if(cancel_button) {
361 cancelled = true;
362 }
363 else if(return_filter) {
364 if(control.getSelectedIndex() == 0) {
365 filter.setFilter(1, 0, (String)value.getSelectedItem(), true);
366 filter.setFilter(2, 0, null, true);
367 }
368 else {
369 filter.setFilter(1, first_method.getSelectedIndex(), (String)first_value.getSelectedItem(), first_case.isSelected());
370 if(!none_radiobutton.isSelected()) {
371 if (and_radiobutton.isSelected()) {
372 filter.setOperation(Autofilter.AND);
373 }
374 else {
375 filter.setOperation(Autofilter.OR);
376 }
377 filter.setFilter(2, second_method.getSelectedIndex(), (String)second_value.getSelectedItem(), second_case.isSelected());
378 }
379 }
380 if (ascending_radiobutton.isSelected()) {
381 filter.setSort(Autofilter.ASCENDING);
382 }
383 else {
384 filter.setSort(Autofilter.DESCENDING);
385 }
386 }
387 else {
388 filter = null;
389 }
390 setVisible(false);
391 }
392 }
393 /** 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. */
394 private final class CheckListener
395 implements ActionListener {
396 /** The default desire state any check button this listens to. */
397 private boolean desired_state = false;
398 /** The constructor takes an associated desired state.
399 * @param desired_state The state that should be set when this is actioned, as a <i>boolean</i>.
400 */
401 public CheckListener(boolean desired_state) {
402 this.desired_state = desired_state;
403 }
404 /** Whenever our registered components are actioned apon, set the state of the second method and value to the desired state. */
405 public void actionPerformed(ActionEvent event) {
406 second_method.setEnabled(desired_state);
407 second_value.setEnabled(desired_state);
408 }
409 }
410}
Note: See TracBrowser for help on using the repository browser.