source: trunk/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.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: 21.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 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.net.*;
33import java.util.*;
34import java.util.jar.*;
35import javax.swing.*;
36import javax.swing.event.*;
37import org.apache.xerces.parsers.*;
38import org.greenstone.gatherer.Configuration;
39import org.greenstone.gatherer.DebugStream;
40import org.greenstone.gatherer.Dictionary;
41import org.greenstone.gatherer.Gatherer;
42import org.greenstone.gatherer.LocalGreenstone;
43import org.greenstone.gatherer.greenstone.Classifiers;
44import org.greenstone.gatherer.gui.DesignPaneHeader;
45import org.greenstone.gatherer.gui.GComboBox;
46import org.greenstone.gatherer.gui.GLIButton;
47import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
48import org.greenstone.gatherer.util.JarTools;
49import org.greenstone.gatherer.util.StaticStrings;
50import org.greenstone.gatherer.util.Utility;
51import org.greenstone.gatherer.util.XMLTools;
52import org.w3c.dom.*;
53import org.xml.sax.*;
54
55/** This class is responsible for keeping track of all the classifiers assigned to this collection, and providing methods for adding and removing them.
56 * @author John Thompson, Greenstone Digital Library, University of Waikato
57 * @version 2.3
58 */
59public class ClassifierManager
60 extends DOMProxyListModel
61{
62 /** The controls for editing the contents of this manager. */
63 private Control controls = null;
64
65 private DOMProxyListModel model;
66
67 /** Constructor.
68 * @see org.greenstone.gatherer.cdm.DynamicListModel
69 * @see org.greenstone.gatherer.collection.CollectionManager
70 */
71 public ClassifierManager() {
72 super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.CLASSIFY_ELEMENT, new Classifier());
73 this.model = this;
74 DebugStream.println("ClassifierManager: " + getSize() + " classifiers parsed.");
75
76 // Force the assigned classifiers to be loaded and cached now
77 for (int i = 0; i < getSize(); i++) {
78 getElementAt(i);
79 }
80 }
81
82
83 /** Retrieve a list of the classifiers that are available to be added to the collection. */
84 private Object[] getAvailableClassifiers()
85 {
86 ArrayList available = new ArrayList();
87
88 // Add all the non-abstract core Greenstone classifiers
89 ArrayList classifiers_list = Classifiers.getClassifiersList();
90 for (int i = 0; i < classifiers_list.size(); i++) {
91 Classifier classifier = (Classifier) classifiers_list.get(i);
92 if (!classifier.isAbstract()) {
93 available.add(classifier);
94 }
95 }
96
97 // Sort the available classifiers into alphabetical order
98 Collections.sort(available);
99
100 return available.toArray();
101 }
102
103
104 /** Method to assign a classifier.
105 * @param classifier The base <strong>Classifier</strong> to assign.
106 * @see org.greenstone.gatherer.cdm.DynamicListModel
107 */
108 private void assignClassifier(Classifier classifier) {
109 if(!contains(classifier)) {
110 Element element = classifier.getElement();
111 // Locate where we should insert this new classifier.
112 Node target_node = CollectionConfiguration.findInsertionPoint(element);
113 add(root, classifier, target_node);
114 }
115 }
116
117
118 /** Destructor. */
119 public void destroy()
120 {
121 if (controls != null) {
122 controls.destroy();
123 controls = null;
124 }
125 }
126
127
128 /** Method to retrieve the classifier with the given index.
129 * @param index The index of the desired classifier as an <i>int</i>.
130 * @return The requested Classifier or <i>null</i> if no such classifier exists.
131 */
132 public Classifier getClassifier(int index) {
133 if(0 <= index && index < getSize()) {
134 return (Classifier) getElementAt(index);
135 }
136 return null;
137 }
138
139 /** Method to retrieve the control for this manager.
140 * @return the Control for editing classifiers
141 */
142 public Control getControls() {
143 if(controls == null) {
144 // Build controls
145 this.controls = new ClassifierControl();
146 }
147 return controls;
148 }
149
150 /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
151 * @param mode the new mode as an int
152 */
153 public void modeChanged(int mode) {
154
155 }
156
157
158
159 /** Determine if the Phind classifier has been assigned.
160 * @return true if it has, false otherwise
161 */
162 public boolean isPhindClassifierAssigned() {
163 for(int i = 0; i < getSize(); i++) {
164 Classifier classifier = (Classifier) getElementAt(i);
165 if(classifier.getName().equalsIgnoreCase(StaticStrings.PHIND_CLASSIFIER)) {
166 return true;
167 }
168 classifier = null;
169 }
170 return false;
171 }
172
173 /** Determine if a DateList classifier has been assigned
174 * @return true if it has, false otherwise
175 */
176 public boolean isDateListClassifierAssigned() {
177 for(int i = 0; i < getSize(); i++) {
178 Classifier classifier = (Classifier) getElementAt(i);
179 if(classifier.getName().equalsIgnoreCase(StaticStrings.DATELIST_CLASSIFIER)) {
180 return true;
181 }
182 classifier = null;
183 }
184 return false;
185
186 }
187 /** Method to move a classifier in the list order.
188 * @param classifier the Classifier you want to move.
189 * @param direction true to move the classifier up, false to move it down.
190 * @param all true to move to move all the way, false for a single step.
191 */
192 private void moveClassifier(Classifier classifier, boolean direction, boolean all) {
193 if(getSize() < 2) {
194 DebugStream.println("Not enough classifiers to allow moving.");
195 return;
196 }
197 if(all) {
198 // Move to top
199 if(direction) {
200 // Remove the moving classifier
201 remove(classifier);
202 // Retrieve the first classifier
203 Classifier first_classifier = (Classifier) getElementAt(0);
204 // Add the moving classifier before the first classifier
205 addBefore(classifier, first_classifier);
206 first_classifier = null;
207 }
208 else {
209 // Remove the moving classifier
210 remove(classifier);
211 // And add after last classifier
212 add(getSize(), classifier);
213 }
214 }
215 else {
216 // Try to move the classifier one step in the desired direction.
217 int index = indexOf(classifier);
218 ///ystem.err.println("Index of " + classifier + " = " + index);
219 if(direction) {
220 index--;
221 if(index < 0) {
222 String args[] = new String[2];
223 args[0] = Dictionary.get("CDM.ClassifierManager.Classifier");
224 args[1] = classifier.getName();
225 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Top", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
226 return;
227 }
228 remove(classifier);
229 add(index, classifier);
230 }
231 else {
232 index++;
233 if(index >= getSize()) {
234 String args[] = new String[2];
235 args[0] = Dictionary.get("CDM.ClassifierManager.Classifier_Str");
236 args[1] = classifier.getName();
237 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Bottom", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
238 return;
239 }
240 remove(classifier);
241 add(index, classifier);
242 }
243 }
244
245 // tell the format manager to update the names of its format statements
246 Gatherer.c_man.getCollection().cdm.format_manager.refresh();
247 }
248
249 /** This method removes an assigned classifier. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a classifier from the library.
250 * @param classifier The Classifier to remove
251 * @see org.greenstone.gatherer.cdm.DynamicListModel
252 */
253 private void removeClassifier(Classifier classifier) {
254 remove(classifier);
255 }
256
257
258 /** A class which provides controls for assigned and editing classifiers. */
259 private class ClassifierControl
260 extends JPanel
261 implements Control {
262 /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
263 private JComboBox classifier_combobox = null;
264 /** Button for adding classifiers. */
265 private JButton add = null;
266 /** Button for configuring the selected classifier. */
267 private JButton configure = null;
268 private JButton move_down_button;
269 private JButton move_up_button;
270
271 /** Button to remove the selected classifier. */
272 private JButton remove = null;
273
274 /** A list of assigned classifiers. */
275 private JList classifier_list = null;
276
277 /** Constructor.
278 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.AddListener
279 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.ConfigureListener
280 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.RemoveListener
281 */
282 public ClassifierControl()
283 {
284 // Create
285 add = new GLIButton(Dictionary.get("CDM.ClassifierManager.Add"), Dictionary.get("CDM.ClassifierManager.Add_Tooltip"));
286
287 JPanel button_pane = new JPanel();
288 JPanel central_pane = new JPanel();
289
290configure = new GLIButton(Dictionary.get("CDM.ClassifierManager.Configure"), Dictionary.get("CDM.ClassifierManager.Configure_Tooltip"));
291 configure.setEnabled(false);
292
293 JPanel header_pane = new DesignPaneHeader("CDM.GUI.Classifiers", "classifiers");
294
295 ClassifierComboboxListener ccl = new ClassifierComboboxListener();
296 classifier_combobox = new JComboBox(getAvailableClassifiers());
297 classifier_combobox.setOpaque(!Utility.isMac());
298 classifier_combobox.setEditable(false);
299 if(classifier_combobox.getItemCount() > 0) {
300 classifier_combobox.setSelectedIndex(0);
301 ccl.itemStateChanged(new ItemEvent(classifier_combobox, 0, null, ItemEvent.SELECTED));
302 }
303
304 JLabel classifier_label = new JLabel(Dictionary.get("CDM.ClassifierManager.Classifier"));
305
306 classifier_list = new JList(model);
307 classifier_list.setOpaque(true);
308 classifier_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
309 JLabel classifier_list_label = new JLabel(Dictionary.get("CDM.ClassifierManager.Assigned"));
310
311 classifier_list_label.setOpaque(true);
312
313 JPanel classifier_list_pane = new JPanel();
314 JPanel classifier_pane = new JPanel();
315 remove = new GLIButton(Dictionary.get("CDM.ClassifierManager.Remove"), Dictionary.get("CDM.ClassifierManager.Remove_Tooltip"));
316 remove.setEnabled(false);
317
318 JPanel temp = new JPanel(new BorderLayout());
319
320 JPanel move_button_pane = new JPanel();
321
322 move_up_button = new GLIButton(Dictionary.get("CDM.Move.Move_Up"), JarTools.getImage("arrow-up.gif"), Dictionary.get("CDM.Move.Move_Up_Tooltip"));
323 move_up_button.setEnabled(false);
324
325 move_down_button = new GLIButton(Dictionary.get("CDM.Move.Move_Down"), JarTools.getImage("arrow-down.gif"), Dictionary.get("CDM.Move.Move_Down_Tooltip"));
326 move_down_button.setEnabled(false);
327
328 // Listeners
329 add.addActionListener(new AddListener());
330 classifier_combobox.addItemListener(ccl);
331 configure.addActionListener(new ConfigureListener());
332 remove.addActionListener(new RemoveListener());
333 remove.addActionListener(CollectionDesignManager.buildcol_change_listener);
334 classifier_list.addMouseListener(new ClickListener());
335 classifier_list.addListSelectionListener(new ListListener());
336 ccl = null;
337
338 MoveListener ml = new MoveListener();
339 move_down_button.addActionListener(ml);
340 move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
341 move_up_button.addActionListener(ml);
342 move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
343
344 // Layout
345 move_button_pane.setLayout(new GridLayout(4,1));
346 move_button_pane.add(move_up_button);
347 move_button_pane.add(new JPanel());
348 move_button_pane.add(new JPanel());
349 move_button_pane.add(move_down_button);
350
351 classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
352
353 classifier_list_pane.setLayout(new BorderLayout());
354 classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
355 classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
356 classifier_list_pane.add(move_button_pane, BorderLayout.EAST);
357
358 classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
359
360 classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
361 classifier_pane.setLayout(new BorderLayout(5,0));
362 classifier_pane.add(classifier_label, BorderLayout.WEST);
363 classifier_pane.add(classifier_combobox, BorderLayout.CENTER);
364
365 button_pane.setLayout(new GridLayout(1, 3));
366 button_pane.add(add);
367 button_pane.add(configure);
368 button_pane.add(remove);
369
370 temp.add(classifier_pane, BorderLayout.NORTH);
371 temp.add(button_pane, BorderLayout.SOUTH);
372
373 central_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
374 central_pane.setLayout(new BorderLayout());
375 central_pane.add(classifier_list_pane, BorderLayout.CENTER);
376 central_pane.add(temp, BorderLayout.SOUTH);
377
378 setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
379 setLayout(new BorderLayout());
380 add(header_pane, BorderLayout.NORTH);
381 add(central_pane, BorderLayout.CENTER);
382 }
383
384 /** Method which acts like a destructor, tidying up references to persistant objects.
385 */
386 public void destroy() {
387 add = null;
388 classifier_combobox = null;
389 classifier_list = null;
390 configure = null;
391 //instructions = null;
392 remove = null;
393 }
394
395 public void gainFocus() {
396 }
397
398 public void loseFocus() {
399 }
400
401
402 private class AddListener
403 implements ActionListener
404 {
405 public void actionPerformed(ActionEvent event)
406 {
407 if (classifier_combobox.getSelectedItem() != null) {
408 // This must be done on a new thread for the remote building code
409 new AddClassifierTask(classifier_combobox.getSelectedItem().toString()).start();
410 }
411 }
412 }
413
414
415 private class AddClassifierTask
416 extends Thread
417 {
418 private String classifier_name;
419
420 public AddClassifierTask(String classifier_name)
421 {
422 this.classifier_name = classifier_name;
423 }
424
425 public void run()
426 {
427 // Retrieve the classifier
428 Classifier classifier = Classifiers.getClassifier(classifier_name, true);
429 if (classifier == null) {
430 System.err.println("Error: getClassifier() returned null.");
431 return;
432 }
433
434 // Create a new element in the DOM
435 Element new_classifier_element = CollectionConfiguration.createElement(StaticStrings.CLASSIFY_ELEMENT);
436 new_classifier_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, classifier.getName());
437 Classifier new_classifier = new Classifier(new_classifier_element, classifier);
438
439 ArgumentConfiguration ac = new ArgumentConfiguration(new_classifier);
440 ac.addOKButtonActionListener(CollectionDesignManager.buildcol_change_listener);
441 if (ac.display()) {
442 assignClassifier(new_classifier);
443 classifier_list.setSelectedValue(new_classifier, true);
444 }
445 }
446 }
447
448
449 /** This listener reacts to changes in the current selection of the classifier combobox. */
450 private class ClassifierComboboxListener
451 implements ItemListener {
452 /** When a user selects a certain classifier, update the tooltip to show the classifier description. */
453 public void itemStateChanged(ItemEvent event) {
454 if(event.getStateChange() == ItemEvent.SELECTED) {
455 // Retrieve the selected classifier
456 Classifier current_selection = (Classifier) classifier_combobox.getSelectedItem();
457 // And reset the tooltip.
458 classifier_combobox.setToolTipText(Utility.formatHTMLWidth(current_selection.getDescription(), 40));
459 current_selection = null;
460 }
461 }
462 }
463
464
465 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
466 private class ClickListener
467 extends MouseAdapter {
468 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
469 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
470 */
471 public void mouseClicked(MouseEvent event) {
472 if(event.getClickCount() == 2 ) {
473 if(!classifier_list.isSelectionEmpty()) {
474 Classifier classifier = (Classifier) classifier_list.getSelectedValue();
475 ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
476 ac.addOKButtonActionListener(CollectionDesignManager.buildcol_change_listener);
477 if (ac.display()) {
478 refresh(classifier);
479 }
480 ac.destroy();
481 ac = null;
482 }
483 }
484 }
485 }
486
487 /** This class listens for actions upon the configure button in the controls, and if detected creates a new ArgumentConfiguration dialog box to allow for configuration.
488 */
489 private class ConfigureListener
490 implements ActionListener {
491 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
492 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
493 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
494 * @see org.greenstone.gatherer.cdm.Classifier
495 */
496 public void actionPerformed(ActionEvent event) {
497 if(!classifier_list.isSelectionEmpty()) {
498 Classifier classifier = (Classifier) classifier_list.getSelectedValue();
499 ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
500 ac.addOKButtonActionListener(CollectionDesignManager.buildcol_change_listener);
501 if (ac.display()) {
502 refresh(classifier);
503 }
504 ac.destroy();
505 ac = null;
506 }
507 }
508 }
509
510 /** listens for changes in the list selection and enables the configure and remove buttons if there is a selection, disables them if there is no selection */
511 private class ListListener
512 implements ListSelectionListener {
513
514 public void valueChanged(ListSelectionEvent e) {
515 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
516 if (classifier_list.isSelectionEmpty()) {
517 move_up_button.setEnabled(false);
518 move_down_button.setEnabled(false);
519 configure.setEnabled(false);
520 remove.setEnabled(false);
521 }
522 else {
523 configure.setEnabled(true);
524 remove.setEnabled(true);
525 int selected_index = classifier_list.getSelectedIndex();
526 move_up_button.setEnabled(selected_index !=0);
527 move_down_button.setEnabled(selected_index != model.getSize()-1);
528 }
529 }
530 }
531 }
532
533 /** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>moveClassifier()</i> method of the manager with the appropriate details. */
534 private class MoveListener
535 implements ActionListener {
536 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
537 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
538 */
539 public void actionPerformed(ActionEvent event) {
540 if(!classifier_list.isSelectionEmpty()) {
541 Object object = classifier_list.getSelectedValue();
542 if(object instanceof Classifier) {
543 Classifier classifier = (Classifier) object;
544 if(event.getSource() == move_up_button) {
545 moveClassifier(classifier, true, false);
546 }
547 else if(event.getSource() == move_down_button) {
548 moveClassifier(classifier, false, false);
549 }
550 classifier_list.setSelectedValue(classifier, true);
551 }
552 }
553 }
554 }
555
556 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removeClassifier()</i> method.
557 */
558 private class RemoveListener
559 implements ActionListener {
560 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
561 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
562 */
563 public void actionPerformed(ActionEvent event) {
564 if(classifier_list.isSelectionEmpty()) {
565 remove.setEnabled(false);
566 return;
567 }
568 int selected_index = classifier_list.getSelectedIndex();
569 Object selected_classifier = classifier_list.getSelectedValue();
570 if (!(selected_classifier instanceof Classifier)) {
571 return; // what else could we have here???
572 }
573 removeClassifier((Classifier)selected_classifier);
574
575 if (selected_index >= classifier_list.getModel().getSize()) {
576 selected_index--;
577 }
578 if (selected_index >=0) {
579 classifier_list.setSelectedIndex(selected_index);
580 } else {
581 // no more classifiers in the list
582 remove.setEnabled(false);
583 }
584 }
585 }
586 }
587}
Note: See TracBrowser for help on using the repository browser.