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

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

more modifications for RTL GLI, thanks to Amin Hedjazi

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