source: gli/trunk/src/org/greenstone/gatherer/cdm/ClassifierManager.java@ 18571

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

made List (was GenericList) the default classifier in the available classifiers list

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