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

Last change on this file since 18370 was 18370, checked in by kjdon, 15 years ago

committed code submitted by Amin Hedjazi for making the GLI right to left. I worked on this code on the rtl-gli branch, then merged the branch back to the trunk at revision 18368. The branch code was slightly different in a couple of places where it shouldn't have been. So don't use the branch code next time. Start a new branch.

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