source: gli/branches/rtl-gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java@ 18368

Last change on this file since 18368 was 14036, checked in by xiao, 17 years ago

Changes made to inform Format4gs3Manager after remove and add a classifier so that the feature combobox gets updated as well.

  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 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 add = new GLIButton (Dictionary.get ("CDM.ClassifierManager.Add"), Dictionary.get ("CDM.ClassifierManager.Add_Tooltip"));
292
293 JPanel button_pane = new JPanel ();
294 JPanel central_pane = new JPanel ();
295
296 configure = new GLIButton (Dictionary.get ("CDM.ClassifierManager.Configure"), Dictionary.get ("CDM.ClassifierManager.Configure_Tooltip"));
297 configure.setEnabled (false);
298
299 JPanel header_pane = new DesignPaneHeader ("CDM.GUI.Classifiers", "classifiers");
300
301 ClassifierComboboxListener ccl = new ClassifierComboboxListener ();
302 classifier_combobox = new JComboBox (getAvailableClassifiers ());
303 classifier_combobox.setOpaque (!Utility.isMac ());
304 classifier_combobox.setEditable (false);
305 if(classifier_combobox.getItemCount () > 0) {
306 classifier_combobox.setSelectedIndex (0);
307 ccl.itemStateChanged (new ItemEvent (classifier_combobox, 0, null, ItemEvent.SELECTED));
308 }
309
310 JLabel classifier_label = new JLabel (Dictionary.get ("CDM.ClassifierManager.Classifier"));
311
312 classifier_list = new JList (model);
313 classifier_list.setOpaque (true);
314 classifier_list.setSelectionMode (ListSelectionModel.SINGLE_SELECTION);
315 JLabel classifier_list_label = new JLabel (Dictionary.get ("CDM.ClassifierManager.Assigned"));
316
317 classifier_list_label.setOpaque (true);
318
319 JPanel classifier_list_pane = new JPanel ();
320 JPanel classifier_pane = new JPanel ();
321 remove = new GLIButton (Dictionary.get ("CDM.ClassifierManager.Remove"), Dictionary.get ("CDM.ClassifierManager.Remove_Tooltip"));
322 remove.setEnabled (false);
323
324 JPanel temp = new JPanel (new BorderLayout ());
325
326 JPanel move_button_pane = new JPanel ();
327
328 move_up_button = new GLIButton (Dictionary.get ("CDM.Move.Move_Up"), JarTools.getImage ("arrow-up.gif"), Dictionary.get ("CDM.Move.Move_Up_Tooltip"));
329 move_up_button.setEnabled (false);
330
331 move_down_button = new GLIButton (Dictionary.get ("CDM.Move.Move_Down"), JarTools.getImage ("arrow-down.gif"), Dictionary.get ("CDM.Move.Move_Down_Tooltip"));
332 move_down_button.setEnabled (false);
333
334 // Listeners
335 add.addActionListener (new AddListener ());
336 classifier_combobox.addItemListener (ccl);
337 configure.addActionListener (new ConfigureListener ());
338 remove.addActionListener (new RemoveListener ());
339 remove.addActionListener (CollectionDesignManager.buildcol_change_listener);
340 classifier_list.addMouseListener (new ClickListener ());
341 classifier_list.addListSelectionListener (new ListListener ());
342 ccl = null;
343
344 MoveListener ml = new MoveListener ();
345 move_down_button.addActionListener (ml);
346 move_down_button.addActionListener (CollectionDesignManager.buildcol_change_listener);
347 move_up_button.addActionListener (ml);
348 move_up_button.addActionListener (CollectionDesignManager.buildcol_change_listener);
349
350 // Layout
351 move_button_pane.setLayout (new GridLayout (4,1));
352 move_button_pane.add (move_up_button);
353 move_button_pane.add (new JPanel ());
354 move_button_pane.add (new JPanel ());
355 move_button_pane.add (move_down_button);
356
357 classifier_list_label.setBorder (BorderFactory.createEmptyBorder (0,2,0,2));
358
359 classifier_list_pane.setLayout (new BorderLayout ());
360 classifier_list_pane.add (classifier_list_label, BorderLayout.NORTH);
361 classifier_list_pane.add (new JScrollPane (classifier_list), BorderLayout.CENTER);
362 classifier_list_pane.add (move_button_pane, BorderLayout.EAST);
363
364 classifier_label.setBorder (BorderFactory.createEmptyBorder (0,0,5,0));
365
366 classifier_pane.setBorder (BorderFactory.createEmptyBorder (5,0,5,0));
367 classifier_pane.setLayout (new BorderLayout (5,0));
368 classifier_pane.add (classifier_label, BorderLayout.WEST);
369 classifier_pane.add (classifier_combobox, BorderLayout.CENTER);
370
371 button_pane.setLayout (new GridLayout (1, 3));
372 button_pane.add (add);
373 button_pane.add (configure);
374 button_pane.add (remove);
375
376 temp.add (classifier_pane, BorderLayout.NORTH);
377 temp.add (button_pane, BorderLayout.SOUTH);
378
379 central_pane.setBorder (BorderFactory.createEmptyBorder (5,0,0,0));
380 central_pane.setLayout (new BorderLayout ());
381 central_pane.add (classifier_list_pane, BorderLayout.CENTER);
382 central_pane.add (temp, BorderLayout.SOUTH);
383
384 setBorder (BorderFactory.createEmptyBorder (0,5,0,0));
385 setLayout (new BorderLayout ());
386 add (header_pane, BorderLayout.NORTH);
387 add (central_pane, BorderLayout.CENTER);
388 }
389
390 /** Method which acts like a destructor, tidying up references to persistant objects.
391 */
392 public void destroy () {
393 add = null;
394 classifier_combobox = null;
395 classifier_list = null;
396 configure = null;
397 //instructions = null;
398 remove = null;
399 }
400
401 public void gainFocus () {
402 }
403
404 public void loseFocus () {
405 }
406
407
408 private class AddListener
409 implements ActionListener {
410 public void actionPerformed (ActionEvent event) {
411 if (classifier_combobox.getSelectedItem () != null) {
412 // This must be done on a new thread for the remote building code
413 new AddClassifierTask (classifier_combobox.getSelectedItem ().toString ()).start ();
414 }
415 }
416 }
417
418
419 private class AddClassifierTask
420 extends Thread {
421 private String classifier_name;
422
423 public AddClassifierTask (String classifier_name) {
424 this.classifier_name = classifier_name;
425 }
426
427 public void run () {
428 // Retrieve the classifier
429 Classifier classifier = Classifiers.getClassifier (classifier_name, true);
430 if (classifier == null) {
431 System.err.println ("Error: getClassifier() returned null.");
432 return;
433 }
434
435 // Create a new element in the DOM
436 Element new_classifier_element = CollectionConfiguration.createElement (StaticStrings.CLASSIFY_ELEMENT);
437 new_classifier_element.setAttribute (StaticStrings.TYPE_ATTRIBUTE, classifier.getName ());
438
439 Classifier new_classifier = new Classifier (new_classifier_element, classifier);
440
441 ArgumentConfiguration ac = new ArgumentConfiguration (new_classifier);
442 ac.addOKButtonActionListener (CollectionDesignManager.buildcol_change_listener);
443 if (ac.display ()) {
444 assignClassifier (new_classifier);
445 classifier_list.setSelectedValue (new_classifier, true);
446 }
447 }
448 }
449
450
451 /** This listener reacts to changes in the current selection of the classifier combobox. */
452 private class ClassifierComboboxListener
453 implements ItemListener {
454 /** When a user selects a certain classifier, update the tooltip to show the classifier description. */
455 public void itemStateChanged (ItemEvent event) {
456 if(event.getStateChange () == ItemEvent.SELECTED) {
457 // Retrieve the selected classifier
458 Classifier current_selection = (Classifier) classifier_combobox.getSelectedItem ();
459 // And reset the tooltip.
460 classifier_combobox.setToolTipText (Utility.formatHTMLWidth (current_selection.getDescription (), 40));
461 current_selection = null;
462 }
463 }
464 }
465
466
467 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
468 private class ClickListener
469 extends MouseAdapter {
470 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
471 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
472 */
473 public void mouseClicked (MouseEvent event) {
474 if(event.getClickCount () == 2 ) {
475 if(!classifier_list.isSelectionEmpty ()) {
476 Classifier classifier = (Classifier) classifier_list.getSelectedValue ();
477 ArgumentConfiguration ac = new ArgumentConfiguration (classifier);
478 ac.addOKButtonActionListener (CollectionDesignManager.buildcol_change_listener);
479 if (ac.display ()) {
480 refresh (classifier);
481 }
482 ac.destroy ();
483 ac = null;
484 }
485 }
486 }
487 }
488
489 /** 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.
490 */
491 private class ConfigureListener
492 implements ActionListener {
493 /** 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.
494 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
495 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
496 * @see org.greenstone.gatherer.cdm.Classifier
497 */
498 public void actionPerformed (ActionEvent event) {
499 if(!classifier_list.isSelectionEmpty ()) {
500 Classifier classifier = (Classifier) classifier_list.getSelectedValue ();
501 ArgumentConfiguration ac = new ArgumentConfiguration (classifier);
502 ac.addOKButtonActionListener (CollectionDesignManager.buildcol_change_listener);
503 if (ac.display ()) {
504 refresh (classifier);
505 }
506 ac.destroy ();
507 ac = null;
508 }
509 }
510 }
511
512 /** 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 */
513 private class ListListener
514 implements ListSelectionListener {
515
516 public void valueChanged (ListSelectionEvent e) {
517 if (!e.getValueIsAdjusting ()) { // we get two events for one change in list selection - use the false one ( the second one)
518 if (classifier_list.isSelectionEmpty ()) {
519 move_up_button.setEnabled (false);
520 move_down_button.setEnabled (false);
521 configure.setEnabled (false);
522 remove.setEnabled (false);
523 }
524 else {
525 configure.setEnabled (true);
526 remove.setEnabled (true);
527 int selected_index = classifier_list.getSelectedIndex ();
528 move_up_button.setEnabled (selected_index !=0);
529 move_down_button.setEnabled (selected_index != model.getSize ()-1);
530 }
531 }
532 }
533 }
534
535 /** 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. */
536 private class MoveListener
537 implements ActionListener {
538 /** 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.
539 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
540 */
541 public void actionPerformed (ActionEvent event) {
542 if(!classifier_list.isSelectionEmpty ()) {
543 Object object = classifier_list.getSelectedValue ();
544 if(object instanceof Classifier) {
545 Classifier classifier = (Classifier) object;
546 if(event.getSource () == move_up_button) {
547 moveClassifier (classifier, true, false);
548 }
549 else if(event.getSource () == move_down_button) {
550 moveClassifier (classifier, false, false);
551 }
552 classifier_list.setSelectedValue (classifier, true);
553 }
554 }
555 }
556 }
557
558 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removeClassifier()</i> method.
559 */
560 private class RemoveListener
561 implements ActionListener {
562 /** 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.
563 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
564 */
565 public void actionPerformed (ActionEvent event) {
566 if(classifier_list.isSelectionEmpty ()) {
567 remove.setEnabled (false);
568 return;
569 }
570 int selected_index = classifier_list.getSelectedIndex ();
571 Object selected_classifier = classifier_list.getSelectedValue ();
572 if (!(selected_classifier instanceof Classifier)) {
573 return; // what else could we have here???
574 }
575 removeClassifier ((Classifier)selected_classifier);
576
577 if (selected_index >= classifier_list.getModel ().getSize ()) {
578 selected_index--;
579 }
580 if (selected_index >=0) {
581 classifier_list.setSelectedIndex (selected_index);
582 } else {
583 // no more classifiers in the list
584 remove.setEnabled (false);
585 }
586 }
587 }
588 }
589}
Note: See TracBrowser for help on using the repository browser.