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

Last change on this file since 13594 was 13594, checked in by mdewsnip, 17 years ago

Moved the LocalGreenstone class into the "greenstone" package.

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