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

Last change on this file since 6944 was 6861, checked in by kjdon, 20 years ago

more fixing up of label size and layout

  • Property svn:keywords set to Author Date Id Revision
File size: 34.2 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29/**************************************************************************************
30 * Written: 01/05/02
31 * Revised: 16/08/02 Optimized and Commented.
32 * 11/07/03 DOM support
33 **************************************************************************************/
34import java.awt.*;
35import java.awt.event.*;
36import java.io.*;
37import java.util.*;
38import java.util.jar.*;
39import javax.swing.*;
40import javax.swing.event.*;
41import org.apache.xerces.parsers.*;
42import org.greenstone.gatherer.Dictionary;
43import org.greenstone.gatherer.Gatherer;
44import org.greenstone.gatherer.cdm.Argument;
45import org.greenstone.gatherer.cdm.CollectionConfiguration;
46import org.greenstone.gatherer.cdm.CollectionDesignManager;
47import org.greenstone.gatherer.cdm.CommandTokenizer;
48import org.greenstone.gatherer.cdm.Control;
49import org.greenstone.gatherer.cdm.Classifier;
50import org.greenstone.gatherer.cdm.DOMProxyListModel;
51import org.greenstone.gatherer.file.FileNode;
52import org.greenstone.gatherer.gui.GComboBox;
53import org.greenstone.gatherer.gui.GLIButton;
54import org.greenstone.gatherer.msm.MSMEvent;
55import org.greenstone.gatherer.msm.MSMListener;
56import org.greenstone.gatherer.msm.MSMUtils;
57import org.greenstone.gatherer.util.StaticStrings;
58import org.greenstone.gatherer.util.Utility;
59import org.w3c.dom.*;
60import org.xml.sax.*;
61
62/** This class is responsible for keeping track of all the classifiers assigned to this collection, and providing methods for adding and removing them.
63 * @author John Thompson, Greenstone Digital Library, University of Waikato
64 * @version 2.3
65 */
66public class ClassifierManager
67 extends DOMProxyListModel {
68
69 /** The default size for a label. */
70 static final private Dimension LABEL_SIZE = new Dimension(140, 20);
71
72 /** A list of known, but currently unassigned, classifiers. */
73 private ArrayList library = null;
74 /** The controls for editing the contents of this manager. */
75 private Control controls = null;
76
77 private DOMProxyListModel model;
78
79 /** Constructor.
80 * @see org.greenstone.gatherer.cdm.DynamicListModel
81 * @see org.greenstone.gatherer.collection.CollectionManager
82 * @see org.greenstone.gatherer.msm.MetadataSetManager
83 * @see org.greenstone.gatherer.msm.MSMListener
84 */
85 public ClassifierManager() {
86 super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.CLASSIFY_ELEMENT, new Classifier());
87 this.model = this;
88 Gatherer.println("ClassifierManager: " + getSize() + " classifiers parsed.");
89 // Reload/Create the library
90 loadClassifiers();
91 saveClassifiers();
92 }
93
94 /** Method to add a new classifier to library.
95 * @param classifier The new <strong>Classifier</strong>.
96 * @see org.greenstone.gatherer.cdm.DynamicListModel
97 */
98 public void addClassifier(Classifier classifier) {
99 if(!library.contains(classifier)) {
100 library.add(classifier);
101 }
102 }
103
104 /** Method to assign a classifier.
105 * @param classifier The base <strong>Classifier</strong> to assign.
106 * @see org.greenstone.gatherer.cdm.DynamicListModel
107 */
108 public void assignClassifier(Classifier classifier) {
109 if(!contains(classifier)) {
110 Element element = classifier.getElement();
111 // Locate where we should insert this new classifier.
112 Node target_node = CollectionConfiguration.findInsertionPoint(element);
113 add(root, classifier, target_node);
114 Gatherer.c_man.configurationChanged();
115 }
116 }
117
118 /** Destructor.
119 * @see org.greenstone.gatherer.Gatherer
120 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
121 * @see org.greenstone.gatherer.cdm.DynamicListModel
122 */
123 public void destroy() {
124 if(controls != null) {
125 controls.destroy();
126 controls = null;
127 }
128 library.clear();
129 library = null;
130 }
131
132 public Classifier getBaseClassifier(String name) {
133 int library_size = library.size();
134 for(int i = 0; i < library_size; i++) {
135 Classifier classifier = (Classifier) library.get(i);
136 if(classifier.getName().equals(name)) {
137 return classifier;
138 }
139 }
140 // No success.
141 return null;
142 }
143
144 /** Method to retrieve the classifier with the given index.
145 * @param index The index of the desired classifier as an <i>int</i>.
146 * @return The requested Classifier or <i>null</i> if no such classifier exists.
147 */
148 public Classifier getClassifier(int index) {
149 if(0 <= index && index < getSize()) {
150 return (Classifier) getElementAt(index);
151 }
152 return null;
153 }
154
155 /** Method to retrieve the control for this manager.
156 * @return the Control for editing classifiers
157 */
158 public Control getControls() {
159 if(controls == null) {
160 // Build controls
161 this.controls = new ClassifierControl();
162 }
163 return controls;
164 }
165
166 public ArrayList getHierarchyClassifiers() {
167 ArrayList result = new ArrayList();
168 for(int i = 0; i < getSize(); i++) {
169 Classifier classifier = (Classifier) getElementAt(i);
170 if(classifier.getName().equalsIgnoreCase(StaticStrings.HIERARCHY_CLASSIFIER)) {
171 result.add(classifier);
172 }
173 classifier = null;
174 }
175 return result;
176
177 }
178
179 /** Determine if the Phind classifier has been assigned.
180 * @return true if it has, false otherwise
181 */
182 public boolean isPhindClassifierAssigned() {
183 for(int i = 0; i < getSize(); i++) {
184 Classifier classifier = (Classifier) getElementAt(i);
185 if(classifier.getName().equalsIgnoreCase(StaticStrings.PHIND_CLASSIFIER)) {
186 return true;
187 }
188 classifier = null;
189 }
190 return false;
191 }
192
193 /** Method to move a classifier in the list order.
194 * @param classifier the Classifier you want to move.
195 * @param direction true to move the classifier up, false to move it down.
196 * @param all true to move to move all the way, false for a single step.
197 */
198 public void moveClassifier(Classifier classifier, boolean direction, boolean all) {
199 if(getSize() < 2) {
200 Gatherer.println("Not enough classifiers to allow moving.");
201 return;
202 }
203 if(all) {
204 // Move to top
205 if(direction) {
206 // Remove the moving classifier
207 remove(classifier);
208 // Retrieve the first classifier
209 Classifier first_classifier = (Classifier) getElementAt(0);
210 // Add the moving classifier before the first classifier
211 addBefore(classifier, first_classifier);
212 first_classifier = null;
213 Gatherer.c_man.configurationChanged();
214 }
215 else {
216 // Remove the moving classifier
217 remove(classifier);
218 // And add after last classifier
219 add(getSize(), classifier);
220 }
221 }
222 else {
223 // Try to move the classifier one step in the desired direction.
224 int index = indexOf(classifier);
225 ///ystem.err.println("Index of " + classifier + " = " + index);
226 if(direction) {
227 index--;
228 if(index < 0) {
229 String args[] = new String[2];
230 args[0] = Dictionary.get("CDM.ClassifierManager.Classifier");
231 args[1] = classifier.getName();
232 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Top", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
233 return;
234 }
235 remove(classifier);
236 add(index, classifier);
237 Gatherer.c_man.configurationChanged();
238 }
239 else {
240 index++;
241 if(index >= getSize()) {
242 String args[] = new String[2];
243 args[0] = Dictionary.get("CDM.ClassifierManager.Classifier_Str");
244 args[1] = classifier.getName();
245 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Bottom", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
246 return;
247 }
248 remove(classifier);
249 add(index, classifier);
250 Gatherer.c_man.configurationChanged();
251 }
252 }
253 }
254
255 /** 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.
256 * @param classifier The Classifier to remove
257 * @see org.greenstone.gatherer.cdm.DynamicListModel
258 */
259 public void removeClassifier(Classifier classifier) {
260 remove(classifier);
261 Gatherer.c_man.configurationChanged();
262 }
263
264 /** Method to cache the current contents of library (known classifiers) to file.
265 * @see org.greenstone.gatherer.util.Utility
266 */
267 public void saveClassifiers() {
268 try {
269 FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat");
270 ObjectOutputStream out = new ObjectOutputStream(file);
271 out.writeObject(library);
272 out.close();
273 }
274 catch (Exception error) {
275 }
276 }
277
278 private Object[] getAvailable() {
279 ArrayList available = new ArrayList();
280 int library_size = library.size();
281 for(int i = 0; i < library_size; i++) {
282 Classifier classifier = (Classifier) library.get(i);
283 if(!classifier.isAbstract()) {
284 available.add(classifier);
285 }
286 classifier = null;
287 }
288 return available.toArray();
289 }
290
291 /** Method to extract just the classifiers name from a file object.
292 * @param classifier The <strong>File</strong> which references a certain classifier.
293 * @return A <strong>String</strong> containing just the classifiers name, without extension.
294 */
295 private String getClassifierName(File classifier) {
296 String name = classifier.getName();
297 if(name.indexOf(".") != -1) {
298 name = name.substring(0, name.indexOf("."));
299 }
300 return name;
301 }
302
303 /** Method to load the details of a single plug-in.
304 * @param classifier The classifier <strong>File</strong> you wish to load.
305 */
306 private void loadClassifier(File classifier) {
307 ///ystem.err.println("Attempting to parse " + classifier.toString());
308 Document document = null;
309 long start;
310 long end;
311 // Run classinfo on this classifier, and then send the results for parsing.
312 try {
313 String args[] = null;
314 if(Utility.isWindows()) {
315 args = new String[4];
316 if(Gatherer.config.perl_path != null) {
317 args[0] = Gatherer.config.perl_path;
318 }
319 else {
320 args[0] = "Perl.exe";
321 }
322 args[1] = Gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl";
323 args[2] = "-xml";
324 args[3] = getClassifierName(classifier);
325 }
326 else {
327 args = new String[3];
328 args[0] = "classinfo.pl";
329 args[1] = "-xml";
330 args[2] = getClassifierName(classifier);
331 }
332
333 // Create the process.
334 Runtime runtime = Runtime.getRuntime();
335 Process process = runtime.exec(args);
336 BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
337 String line = "";
338 StringBuffer xml = new StringBuffer("");
339 boolean xml_content = false;
340 while((line = error_in.readLine()) != null) {
341 if(xml_content) {
342 xml.append(line);
343 xml.append("\n");
344 }
345 else if(line.trim().startsWith("<?xml")) {
346 xml_content = true;
347 xml.append(line);
348 xml.append("\n");
349 }
350 }
351 error_in = null;
352 process = null;
353 runtime = null;
354 // If something has gone horribly wrong then xml will be empty.
355 if(xml.length() != 0) {
356 // Then read the xml from the piped input stream.
357 InputSource source = new InputSource(new StringReader(xml.toString()));
358 DOMParser parser = new DOMParser();
359 parser.parse(source);
360 document = parser.getDocument();
361 parser = null;
362 source = null;
363 }
364 else {
365 String classifier_name = getClassifierName(classifier);
366 Gatherer.println("Zero length argument xml detected for: " + classifier_name);
367 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.ClassifierManager.Classifier_XML_Parse_Failed", classifier_name), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
368 classifier_name = null;
369 }
370 }
371 catch (Exception error) {
372 error.printStackTrace();
373 ///ystem.err.println("Error: Cannot parse " + getClassifierName(classifier));
374 }
375 if(document != null) {
376 parseXML(document.getDocumentElement());
377 }
378 }
379
380 /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
381 * @see org.greenstone.gatherer.util.Utility
382 */
383 private void loadClassifiers() {
384 // Attempt to restore the cached file.
385 try {
386 FileInputStream file = new FileInputStream(Utility.BASE_DIR + "classifiers.dat");
387 ObjectInputStream input = new ObjectInputStream(file);
388 library = (ArrayList) input.readObject();
389 }
390 catch (Exception error) {
391 }
392 if(library == null) {
393 library = new ArrayList();
394 // Retrieve the gsdl home directory...
395 String directory = Gatherer.config.gsdl_path;
396 directory = directory + "perllib" + File.separator + "classify" + File.separator;
397 File files[] = (new File(directory)).listFiles();
398 if(files != null) {
399 // Create a progress indicator.
400 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.ClassifierManager.Parsing.Title"), Dictionary.get("CDM.ClassifierManager.Parsing.Message"), files.length);
401 for(int i = 0; i < files.length; i++) {
402 // We only want to check Perl Modules.
403 if(files[i].getName().endsWith(".pm")) {
404 loadClassifier(files[i]);
405 }
406 progress.inc();
407 }
408 progress.dispose();
409 progress.destroy();
410 progress = null;
411 }
412 }
413 }
414
415 /** Parses a DOM tree model turning it into a Classifier and its associated arguments.
416 * @param root The <strong>Node</strong> at the root of the DOM model.
417 * @return A newly created <strong>Classifier</strong> based on the information parsed from the DOM model.
418 * @see org.greenstone.gatherer.cdm.Argument
419 */
420 private Classifier parseXML(Node root) {
421 Classifier classifier = new Classifier();
422 String node_name = null;
423 for(Node node = root.getFirstChild(); node != null;
424 node = node.getNextSibling()) {
425 node_name = node.getNodeName();
426 if(node_name.equals("Name")) {
427 String name = MSMUtils.getValue(node);
428 // We can save ourselves some processing time if a classifier with this name already exists in our manager. If so retrieve it and return it.
429 Classifier existing = getBaseClassifier(name);
430 if(existing != null) {
431 return existing;
432 }
433 classifier.setName(name);
434 }
435 else if(node_name.equals("Desc")) {
436 classifier.setDescription(MSMUtils.getValue(node));
437 }
438 else if(node_name.equals(CollectionConfiguration.ABSTRACT_ELEMENT)) {
439 classifier.setIsAbstract(MSMUtils.getValue(node).equalsIgnoreCase(CollectionConfiguration.YES_STR));
440 }
441 // Parse the multitude of arguments.
442 else if(node_name.equals("Arguments")) {
443 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
444 node_name = arg.getNodeName();
445 // An option.
446 if(node_name.equals("Option")) {
447 Argument argument = new Argument();
448 // If its an option we parse the multitude of details an options might have.
449 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
450 node_name = det.getNodeName();
451 if(node_name.equals("Name")) {
452 argument.setName(MSMUtils.getValue(det));
453 }
454 else if(node_name.equals("Desc")) {
455 argument.setDescription(MSMUtils.getValue(det));
456 }
457 else if(node_name.equals("Type")) {
458 argument.setType(MSMUtils.getValue(det));
459 }
460 else if(node_name.equals("Default")) {
461 argument.setDefaultValue(MSMUtils.getValue(det));
462 }
463 else if(node_name.equals("List")) {
464 // Two final loops are required to parse lists.
465 for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
466 if(value.getNodeName().equals("Value")) {
467 String key = null;
468 String desc = "";
469 for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
470 node_name = subvalue.getNodeName();
471 if(node_name.equals("Name")) {
472 key = MSMUtils.getValue(subvalue);
473 }
474 else if(node_name.equals("Desc")) {
475 desc = MSMUtils.getValue(subvalue);
476 }
477 }
478 if(key != null) {
479 argument.addOption(key, desc);
480 }
481 }
482 }
483 }
484 else if(node_name.equals("Required")) {
485 String v = MSMUtils.getValue(det);
486 ///ystem.err.println("Required = " + v);
487 if(v.equalsIgnoreCase("yes")) {
488 ///ystem.err.println("Setting required to true.");
489 argument.setRequired(true);
490 }
491 }
492 else if(node_name.equals(StaticStrings.RANGE_ELEMENT)) {
493 String range_raw = MSMUtils.getValue(det);
494 int index = -1;
495 if((index = range_raw.indexOf(StaticStrings.COMMA_CHARACTER)) != -1) {
496 if(index > 0) {
497 try {
498 String first_number = range_raw.substring(0, index);
499 argument.setMinimum(Integer.parseInt(first_number));
500 first_number = null;
501 }
502 catch(Exception exception) {
503 }
504 }
505
506 if(index + 1 < range_raw.length()) {
507 try {
508 String second_number = range_raw.substring(index + 1);
509 argument.setMaximum(Integer.parseInt(second_number));
510 second_number = null;
511
512 }
513 catch(Exception exception) {
514 }
515 }
516
517 }
518 // Else it wasn't a valid range anyway, so ignore it
519 }
520 }
521 classifier.addArgument(argument);
522 }
523 // A super classifier class.
524 else if(node_name.equals("ClassInfo")) {
525 Classifier super_classifier = parseXML(arg);
526 classifier.setSuper(super_classifier);
527 }
528 }
529 }
530 }
531 if(classifier.getName() != null) {
532 addClassifier(classifier);
533 return classifier;
534 }
535 return null;
536 }
537
538 /** A class which provides controls for assigned and editing classifiers. */
539 private class ClassifierControl
540 extends JPanel
541 implements Control {
542 /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
543 private GComboBox classifier = null;
544 /** Button for adding classifiers. */
545 private JButton add = null;
546 /** Button for configuring the selected classifier. */
547 private JButton configure = null;
548
549 //private JButton move_bottom_button;
550
551 private JButton move_down_button;
552
553 //private JButton move_top_button;
554
555 private JButton move_up_button;
556
557 /** Button to remove the selected classifier. */
558 private JButton remove = null;
559
560 /** A list of assigned classifiers. */
561 private JList classifier_list = null;
562 /** The text area containing instructions on the use of this control. */
563 private JTextArea instructions = null;
564
565 /** Constructor.
566 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.AddListener
567 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.ConfigureListener
568 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.RemoveListener
569 */
570 public ClassifierControl() {
571 Collections.sort(library);
572 // Create
573 add = new GLIButton();
574 add.setMnemonic(KeyEvent.VK_A);
575 Dictionary.registerBoth(add, "CDM.ClassifierManager.Add", "CDM.ClassifierManager.Add_Tooltip");
576 JPanel button_pane = new JPanel();
577 JPanel central_pane = new JPanel();
578 configure = new GLIButton();
579 configure.setEnabled(false);
580 configure.setMnemonic(KeyEvent.VK_C);
581 Dictionary.registerBoth(configure, "CDM.ClassifierManager.Configure", "CDM.ClassifierManager.Configure_Tooltip");
582 JPanel header_pane = new JPanel();
583 instructions = new JTextArea();
584 instructions.setEditable(false);
585 instructions.setLineWrap(true);
586 instructions.setRows(6);
587 instructions.setWrapStyleWord(true);
588 Dictionary.registerText(instructions, "CDM.ClassifierManager.Instructions");
589
590 ClassifierComboboxListener ccl = new ClassifierComboboxListener();
591 classifier = new GComboBox(getAvailable());
592 classifier.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.editable_background", false));
593 classifier.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.collection_selection_background", false));
594 classifier.setEditable(true);
595 classifier.setTextNonSelectionColor(Gatherer.config.getColor("coloring.workspace_tree_foreground", false));
596 classifier.setTextSelectionColor(Gatherer.config.getColor("coloring.collection_selection_foreground", false));
597 if(classifier.getItemCount() > 0) {
598 classifier.setSelectedIndex(0);
599 ccl.itemStateChanged(new ItemEvent(classifier, 0, null, ItemEvent.SELECTED));
600 }
601
602 JLabel classifier_label = new JLabel();
603 Dictionary.registerText(classifier_label, "CDM.ClassifierManager.Classifier");
604 classifier_list = new JList(model);
605 classifier_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
606 JLabel classifier_list_label = new JLabel();
607 classifier_list_label.setHorizontalAlignment(JLabel.CENTER);
608 classifier_list_label.setOpaque(true);
609 Dictionary.registerText(classifier_list_label, "CDM.ClassifierManager.Assigned");
610 JPanel classifier_list_pane = new JPanel();
611 JPanel classifier_pane = new JPanel();
612 remove = new GLIButton();
613 remove.setEnabled(false);
614 remove.setMnemonic(KeyEvent.VK_R);
615 Dictionary.registerBoth(remove, "CDM.ClassifierManager.Remove", "CDM.ClassifierManager.Remove_Tooltip");
616
617 JLabel title = new JLabel();
618 title.setHorizontalAlignment(JLabel.CENTER);
619 title.setOpaque(true);
620 Dictionary.registerText(title, "CDM.ClassifierManager.Title");
621
622 JPanel temp = new JPanel(new BorderLayout());
623
624 JPanel move_button_pane = new JPanel();
625
626 move_up_button = new JButton("", Utility.getImage("arrow-up.gif"));
627 move_up_button.setEnabled(false);
628 move_up_button.setMnemonic(KeyEvent.VK_U);
629 //move_up_button.setPreferredSize(Utility.DOUBLE_IMAGE_BUTTON_SIZE);
630 Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
631
632 move_down_button = new JButton("", Utility.getImage("arrow-down.gif"));
633 move_down_button.setEnabled(false);
634 move_down_button.setMnemonic(KeyEvent.VK_D);
635 //move_down_button.setPreferredSize(Utility.DOUBLE_IMAGE_BUTTON_SIZE);
636 Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
637
638 // Listeners
639 add.addActionListener(new AddListener());
640 classifier.addItemListener(ccl);
641 configure.addActionListener(new ConfigureListener());
642 remove.addActionListener(new RemoveListener());
643 classifier_list.addMouseListener(new ClickListener());
644 classifier_list.addListSelectionListener(new ListListener());
645 ccl = null;
646
647 MoveListener ml = new MoveListener();
648 //move_bottom_button.addActionListener(ml);
649 move_down_button.addActionListener(ml);
650 //move_top_button.addActionListener(ml);
651 move_up_button.addActionListener(ml);
652
653 // Layout
654 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
655
656 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
657
658 header_pane.setLayout(new BorderLayout());
659 header_pane.add(title, BorderLayout.NORTH);
660 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
661
662 move_button_pane.setLayout(new GridLayout(4,1));
663 move_button_pane.add(move_up_button);
664 move_button_pane.add(new JPanel());
665 move_button_pane.add(new JPanel());
666 move_button_pane.add(move_down_button);
667
668 classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
669
670 classifier_list_pane.setLayout(new BorderLayout());
671 classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
672 classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
673 classifier_list_pane.add(move_button_pane, BorderLayout.EAST);
674
675 classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
676
677 classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
678 classifier_pane.setLayout(new BorderLayout(5,0));
679 classifier_pane.add(classifier_label, BorderLayout.WEST);
680 classifier_pane.add(classifier, BorderLayout.CENTER);
681
682 button_pane.setLayout(new GridLayout(1, 3));
683 button_pane.add(add);
684 button_pane.add(configure);
685 button_pane.add(remove);
686
687 // Scope these mad bordering skillz.
688 temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("CDM.ClassifierManager.Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
689 temp.add(classifier_pane, BorderLayout.NORTH);
690 temp.add(button_pane, BorderLayout.SOUTH);
691
692 central_pane.setLayout(new BorderLayout());
693 central_pane.add(classifier_list_pane, BorderLayout.CENTER);
694 central_pane.add(temp, BorderLayout.SOUTH);
695
696 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
697 setLayout(new BorderLayout());
698 add(header_pane, BorderLayout.NORTH);
699 add(central_pane, BorderLayout.CENTER);
700 }
701
702 /** Method which acts like a destructor, tidying up references to persistant objects.
703 */
704 public void destroy() {
705 add = null;
706 classifier = null;
707 classifier_list = null;
708 configure = null;
709 instructions = null;
710 remove = null;
711 }
712
713 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
714 */
715 public void gainFocus() {
716 if(instructions != null) {
717 instructions.setCaretPosition(0);
718 }
719 }
720
721 public void loseFocus() {
722 }
723
724 /** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method.
725 */
726 private class AddListener
727 implements ActionListener {
728 /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls, so that we can add the selected Classifier.
729 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
730 * @see org.greenstone.gatherer.Gatherer
731 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
732 * @see org.greenstone.gatherer.cdm.Classifier
733 */
734 public void actionPerformed(ActionEvent event) {
735 Object selected_object = classifier.getSelectedItem();
736 // If there is something in the combobox, but we haven't registered a selection, then add the object and select it!
737 if(selected_object != null) {
738 // Retrieve the base classifier
739 Classifier base_classifier = getBaseClassifier(selected_object.toString());
740
741 // Create a new element in the DOM
742 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.CLASSIFY_ELEMENT);
743 Classifier new_classifier = null;
744 if(base_classifier != null) {
745 Gatherer.println("Creating Classifier based on existing Classifer.");
746 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_classifier.getName());
747 new_classifier = new Classifier(element, base_classifier);
748 }
749 else {
750 Gatherer.println("Creating new custom Classifier.");
751 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
752 new_classifier = new Classifier(element, null);
753 // Also we add the custom classifier name to the combobox for convienence.
754 classifier.addItem(selected_object);
755 }
756 element = null;
757 // Automatically chain to configuration. This ensures required arguments are filled out.
758 ArgumentConfiguration ac = new ArgumentConfiguration(new_classifier);
759 if(ac.display()) {
760 if(!model.contains(new_classifier)) {
761 assignClassifier(new_classifier);
762 classifier_list.setSelectedValue(new_classifier, true);
763 }
764 else {
765 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.ClassifierManager.Classifier_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
766 }
767 }
768 ac = null;
769 new_classifier = null;
770 }
771 }
772 }
773
774 /** This listener reacts to changes in the current selection of the classifier combobox. */
775 private class ClassifierComboboxListener
776 implements ItemListener {
777 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
778 public void itemStateChanged(ItemEvent event) {
779 if(event.getStateChange() == ItemEvent.SELECTED) {
780 // Retrieve the selected plugin
781 Object current_selection = classifier.getSelectedItem();
782 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
783 if(current_selection == null || current_selection instanceof String) {
784 Dictionary.registerTooltip(classifier, "CDM.ClassifierManager.Classifier_Tooltip");
785 }
786 else {
787 Classifier current_classifier = (Classifier) current_selection;
788 Dictionary.registerTooltipText(classifier, Utility.formatHTMLWidth(current_classifier.getDescription(), 40));
789 current_classifier = null;
790 }
791 current_selection = null;
792 }
793 }
794 }
795
796 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
797 private class ClickListener
798 extends MouseAdapter {
799 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
800 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
801 */
802 public void mouseClicked(MouseEvent event) {
803 if(event.getClickCount() == 2 ) {
804 if(!classifier_list.isSelectionEmpty()) {
805 Classifier classifier = (Classifier) classifier_list.getSelectedValue();
806 ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
807 if(ac.display()) {
808 refresh(classifier);
809 }
810 ac.destroy();
811 ac = null;
812 }
813 }
814 }
815 }
816
817 /** 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.
818 */
819 private class ConfigureListener
820 implements ActionListener {
821 /** 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.
822 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
823 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
824 * @see org.greenstone.gatherer.cdm.Classifier
825 */
826 public void actionPerformed(ActionEvent event) {
827 if(!classifier_list.isSelectionEmpty()) {
828 Classifier classifier = (Classifier) classifier_list.getSelectedValue();
829 ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
830 if(ac.display()) {
831 refresh(classifier);
832 }
833 ac.destroy();
834 ac = null;
835 }
836 }
837 }
838
839 /** 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 */
840 private class ListListener
841 implements ListSelectionListener {
842
843 public void valueChanged(ListSelectionEvent e) {
844 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
845 if (classifier_list.isSelectionEmpty()) {
846 //move_top_button.setEnabled(false);
847 move_up_button.setEnabled(false);
848 move_down_button.setEnabled(false);
849 //move_bottom_button.setEnabled(false);
850 configure.setEnabled(false);
851 remove.setEnabled(false);
852 }
853 else {
854 //move_top_button.setEnabled(true);
855 move_up_button.setEnabled(true);
856 move_down_button.setEnabled(true);
857 //move_bottom_button.setEnabled(true);
858 configure.setEnabled(true);
859 remove.setEnabled(true);
860 }
861 }
862 }
863 }
864
865 /** 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. */
866 private class MoveListener
867 implements ActionListener {
868 /** 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.
869 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
870 */
871 public void actionPerformed(ActionEvent event) {
872 if(!classifier_list.isSelectionEmpty()) {
873 Object object = classifier_list.getSelectedValue();
874 if(object instanceof Classifier) {
875 Classifier classifier = (Classifier) object;
876 //if(event.getSource() == move_top_button) {
877 // moveClassifier(classifier, true, true);
878 //}
879 //else
880 if(event.getSource() == move_up_button) {
881 moveClassifier(classifier, true, false);
882 }
883 else if(event.getSource() == move_down_button) {
884 moveClassifier(classifier, false, false);
885 }
886 //else {
887 // moveClassifier(classifier, false, true);
888 //}
889 classifier_list.setSelectedValue(classifier, true);
890 }
891 }
892 }
893 }
894
895 /** This class listens for actions upon the remove button in the controls, and if detected calls the removeClassifier() method.
896 */
897 private class RemoveListener
898 implements ActionListener {
899 /** 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, so we can remove the selected Classifier.
900 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
901 * @see org.greenstone.gatherer.cdm.Classifier
902 */
903 public void actionPerformed(ActionEvent event) {
904 if(!classifier_list.isSelectionEmpty()) {
905 Object [] objects = classifier_list.getSelectedValues();
906 for(int i = 0; i < objects.length; i++) {
907 if(objects[i] instanceof Classifier) {
908 removeClassifier((Classifier)objects[i]);
909 }
910 }
911 }
912 }
913 }
914 }
915}
Note: See TracBrowser for help on using the repository browser.