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

Last change on this file since 4293 was 4293, checked in by jmt12, 21 years ago

Initial revision

  • Property svn:keywords set to Author Date Id Revision
File size: 38.7 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 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37
38
39
40
41
42
43/* GPL_HEADER */
44package org.greenstone.gatherer.cdm;
45/**************************************************************************************
46 * Title: Gatherer
47 * Description: The Gatherer: a tool for gathering and enriching a digital collection.
48 * Company: The University of Waikato
49 * Written: 01/05/02
50 * Revised: 16/08/02 Optimized and Commented.
51 **************************************************************************************/
52import java.awt.BorderLayout;
53import java.awt.Color;
54import java.awt.Component;
55import java.awt.Dimension;
56import java.awt.GridLayout;
57import java.awt.event.ActionEvent;
58import java.awt.event.ActionListener;
59import java.awt.event.MouseAdapter;
60import java.awt.event.MouseEvent;
61import java.io.BufferedReader;
62import java.io.File;
63import java.io.FileInputStream;
64import java.io.FileOutputStream;
65import java.io.InputStream;
66import java.io.InputStreamReader;
67import java.io.ObjectInputStream;
68import java.io.ObjectOutputStream;
69import java.io.StringReader;
70import java.lang.Exception;
71import java.util.ArrayList;
72import java.util.Collections;
73import java.util.Enumeration;
74import java.util.jar.JarFile;
75import javax.swing.BorderFactory;
76import javax.swing.DefaultListCellRenderer;
77import javax.swing.JButton;
78import javax.swing.JComboBox;
79import javax.swing.JLabel;
80import javax.swing.JList;
81import javax.swing.JOptionPane;
82import javax.swing.JPanel;
83import javax.swing.JScrollPane;
84import javax.swing.JTextArea;
85import javax.swing.event.ListSelectionEvent;
86import javax.swing.event.ListSelectionListener;
87import org.apache.xerces.parsers.DOMParser;
88import org.greenstone.gatherer.Gatherer;
89import org.greenstone.gatherer.cdm.Argument;
90import org.greenstone.gatherer.cdm.CollectionDesignManager;
91import org.greenstone.gatherer.cdm.CommandTokenizer;
92import org.greenstone.gatherer.cdm.Classifier;
93import org.greenstone.gatherer.cdm.CustomClassifier;
94import org.greenstone.gatherer.cdm.DynamicListModel;
95import org.greenstone.gatherer.file.FileNode;
96import org.greenstone.gatherer.msm.MSMEvent;
97import org.greenstone.gatherer.msm.MSMListener;
98import org.greenstone.gatherer.msm.MSMUtils;
99import org.greenstone.gatherer.util.Utility;
100import org.w3c.dom.Document;
101import org.w3c.dom.Node;
102import org.xml.sax.InputSource;
103/** This class is responsible for keeping track of all the classifiers assigned to this collection, and providing methods for adding and removing them.
104 * @author John Thompson, Greenstone Digital Library, University of Waikato
105 * @version 2.3
106 */
107// ####################################################################################
108// Optimization Saving
109// ####################################################################################
110// Vector -> ArrayList + Memory, + Processor, (pos. - Processor)
111// Unnecessary global references + Memory (5Kb+)
112// ####################################################################################
113public class ClassifierManager
114 implements MSMListener {
115 /** An interface to the Gatherer, the creator of this cdm module, for access to the Greenstone installation directory. */
116 private Gatherer gatherer = null;
117 /** A reference to the CollectionDesignManager for access to other configuration managers. */
118 private CollectionDesignManager manager = null;
119 /** The controls for editing the contents of this manager. */
120 private Control controls = null;
121 /** A list of assigned classifiers. */
122 private DynamicListModel assigned = null;
123 /** A list of known, but currently unassigned, classifiers. */
124 private DynamicListModel reserve = null;
125 /** We may have somehow recieved a classifier command that are, in fact, custom classifiers which can refer to classifiers that haven't been parsed yet, so this holds a list of failed commands which are retried after the loading is complete. */
126 private ArrayList unresolved_commands = null;
127 /** Constructor.
128 * @param gatherer A reference to the <strong>Gatherer</strong> for access to the Dictionary.
129 * @param manager A reference to the <strong>CollectionDesignManager</strong> itself.
130 * @see org.greenstone.gatherer.Gatherer
131 * @see org.greenstone.gatherer.cdm.DynamicListModel
132 * @see org.greenstone.gatherer.collection.CollectionManager
133 * @see org.greenstone.gatherer.msm.MetadataSetManager
134 * @see org.greenstone.gatherer.msm.MSMListener
135 */
136 public ClassifierManager(Gatherer gatherer, CollectionDesignManager manager) {
137 this.assigned = new DynamicListModel();
138 this.gatherer = gatherer;
139 this.manager = manager;
140 this.unresolved_commands = new ArrayList();
141 loadClassifiers();
142 saveClassifiers();
143 // Register as a MSMListener.
144 Gatherer.c_man.getCollection().msm.addMSMListener(this);
145 }
146 /** Method to add a new classifier to reserve.
147 * @param classifier The new <strong>Classifier</strong>.
148 * @see org.greenstone.gatherer.cdm.DynamicListModel
149 */
150 public void addClassifier(Classifier classifier) {
151 if(!reserve.contains(classifier)) {
152 reserve.addElement(classifier);
153 }
154 }
155 /** Method to assign a classifier.
156 * @param classifier The reserve <strong>Classifier</strong> to assign.
157 * @see org.greenstone.gatherer.cdm.DynamicListModel
158 */
159 public void assignClassifier(Classifier classifier) {
160 if(!assigned.contains(classifier)) {
161 assigned.addElement(classifier);
162 classifier.setManager(this);
163 gatherer.c_man.configurationChanged();
164 }
165 }
166 /** Method to assign a classifier.
167 * @param classifier The <strong>CustomClassifier</strong> to assign.
168 * @see org.greenstone.gatherer.cdm.DynamicListModel
169 */
170 public void assignClassifier(CustomClassifier classifier) {
171 if(!assigned.contains(classifier)) {
172 assigned.addElement(classifier);
173 classifier.setManager(this);
174 gatherer.c_man.configurationChanged();
175 }
176 }
177 /** Destructor.
178 * @see org.greenstone.gatherer.Gatherer
179 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
180 * @see org.greenstone.gatherer.cdm.DynamicListModel
181 */
182 public void destroy() {
183 // Deregister as a listener
184 if(gatherer.c_man != null && gatherer.c_man.msm != null) {
185 gatherer.c_man.msm.removeMSMListener(this);
186 }
187 // Null globals
188 assigned = null;
189 controls = null;
190 gatherer = null;
191 manager = null;
192 reserve = null;
193 unresolved_commands = null;
194 }
195 /** Method to retrieve the classifier with the given index.
196 * @param index The index of the desired classifier as an <i>int</i>.
197 * @return The requested Classifier as an <strong>Object</strong> or <i>null</i> if no such classifier exists.
198 * @see org.greenstone.gatherer.cdm.DynamicListModel
199 */
200 public Object getClassifier(int index) {
201 if(0 <= index && index < assigned.size()) {
202 return assigned.get(index);
203 }
204 return null;
205 }
206 /** Method to retrieve the named classifier.
207 * @param name The name of the desired classifier as a <strong>String</strong>.
208 * @return The requested <strong>Classifier</strong> or <i>null</i> if no such classifier exists.
209 * @see org.greenstone.gatherer.cdm.DynamicListModel
210 */
211 public Classifier getClassifier(String name) {
212 for(int i = 0; i < reserve.size(); i++) {
213 Classifier classifier = (Classifier)reserve.get(i);
214 if(classifier.getName().equals(name)) {
215 return classifier;
216 }
217 }
218 // No success.
219 return null;
220 }
221 /** Method to retrieve the control for this manager.
222 * @return A <strong>JPanel</strong> containing the controls.
223 */
224 public JPanel getControls() {
225 if(controls == null) {
226 controls = new Control();
227 }
228 return controls;
229 }
230 /** Called whenever a metadata element changes significantly.
231 * @param event A <strong>MSMEvent</strong> choc' full of event informationy goodness.
232 */
233 public void elementChanged(MSMEvent event) {
234 // Don't really care, as the elements dealt with here are all live references so changes like identifier change will propagate immediately.
235 }
236 /** Method to find the index of the given classifier within the assigned classifiers.
237 * @param classifier The <strong>Classifier</strong> whose index you wish to find.
238 * @return The index of the classifier as an <i>int</i>, which has a value of -1 if the classifier was not found.
239 * @see org.greenstone.gatherer.cdm.DynamicListModel
240 */
241 public int indexOf(Classifier classifier) {
242 for(int i = 0; i < assigned.size(); i++) {
243 Classifier sibling = (Classifier) assigned.get(i);
244 if(sibling.equals(classifier)) {
245 return i;
246 }
247 }
248 return -1;
249 }
250 /** Method to invalidate controls after a significant change in the system state.
251 */
252 public void invalidateControls() {
253 if(controls != null) {
254 controls.destroy();
255 }
256 controls = null;
257 }
258 /** Method to load the details of a single plug-in.
259 * @param classifier The classifier <strong>File</strong> you wish to load.
260 */
261 public void loadClassifier(File classifier) {
262 ///ystem.err.println("Attempting to parse " + classifier.toString());
263 Document document = null;
264 long start;
265 long end;
266 // Run classinfo on this classifier, and then send the results for parsing.
267 try {
268 String args[] = null;
269 if(Utility.isWindows()) {
270 args = new String[4];
271 if(Gatherer.config.perl_path != null) {
272 args[0] = gatherer.config.perl_path + "Perl.exe";
273 }
274 else {
275 args[0] = "Perl.exe";
276 }
277 args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl";
278 args[2] = "-xml";
279 args[3] = getClassifierName(classifier);
280 }
281 else {
282 args = new String[3];
283 args[0] = "classinfo.pl";
284 args[1] = "-xml";
285 args[2] = getClassifierName(classifier);
286 }
287
288 // Create the process.
289 Runtime runtime = Runtime.getRuntime();
290 Process process = runtime.exec(args);
291 InputStream input_stream = process.getErrorStream();
292 BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
293 String line = "";
294 StringBuffer xml = new StringBuffer("");
295 while((line = error_in.readLine()) != null) {
296 xml.append(line);
297 xml.append("\n");
298 }
299 // Then read the xml from the piped input stream.
300 InputSource source = new InputSource(new StringReader(xml.toString()));
301 DOMParser parser = new DOMParser();
302 parser.parse(source);
303 document = parser.getDocument();
304 }
305 catch (Exception error) {
306 error.printStackTrace();
307 //ystem.err.println("Error: Cannot parse " + getClassifierName(classifier));
308 }
309 if(document != null) {
310 parse(document.getDocumentElement());
311 }
312 }
313 /** Called whenever the metadata value associated to a certain record changes. */
314 public void metadataChanged(MSMEvent event) {
315 FileNode record = event.getRecord();
316 if(record != null) {
317 for(int i = 0; i < assigned.size(); i++) {
318 Object object = assigned.get(i);
319 if(object instanceof CustomClassifier) {
320 CustomClassifier classifier = (CustomClassifier) object;
321 classifier.process(record);
322 }
323 }
324 }
325 }
326 /** This method attempts to parse a classifier command from a command string taken from the collection configuration file. This process is quite complex as not only must the correct classifier be matched but also all of the parameters given must be legal. If such a command is found, the classifier is immediately assigned.
327 * @param command The command <strong>String</strong> that may include classifier information.
328 * @return <i>true</i> if a classifier command was parsed, <i>false</i> otherwise.
329 * @see org.greenstone.gatherer.cdm.Argument
330 * @see org.greenstone.gatherer.cdm.Classifier
331 * @see org.greenstone.gatherer.cdm.CommandTokenizer
332 */
333 public boolean parse(String command) {
334 String command_lc = command.toLowerCase();
335 if(command_lc.startsWith("classify")) {
336 CommandTokenizer tokenizer = new CommandTokenizer(command);
337 if(tokenizer.countTokens() >= 2) {
338 tokenizer.nextToken(); // Throw away 'classifier'
339 String name = tokenizer.nextToken();
340 // Try to locate the classifier with this name.
341 Classifier classifier = getClassifier(name);
342 // And if successful start to parse the arguments.
343 if(classifier != null) {
344 // Take a copy.
345 classifier = classifier.copy();
346 String key = null;
347 while((key = tokenizer.nextToken()) != null) {
348 // Try to retrieve a matching argument.
349 Argument argument = classifier.getArgument(key);
350 if(argument != null) {
351 // Set as assigned.
352 argument.setAssigned(true);
353 // And if the argument is of a parameter type, parse a parameter.
354 if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
355 String value = tokenizer.nextToken();
356 value = value.replace(':', MSMUtils.NS_SEP);
357 argument.setValue(value);
358 }
359 }
360 // Argument cannot be matched.
361 else {
362 String cur_key = key;
363 String value = tokenizer.nextToken();
364 if(value.startsWith("-")) {
365 key = value;
366 value = null;
367 }
368 else {
369 key = null;
370 }
371 String custom = classifier.getCustom();
372 if(custom == null) {
373 if(value == null) {
374 classifier.setCustom(cur_key);
375 }
376 else {
377 classifier.setCustom(cur_key + " " + value);
378 }
379 }
380 else {
381 if(value == null) {
382 classifier.setCustom(custom + " " + cur_key);
383 }
384 else {
385 classifier.setCustom(custom + " " + cur_key + " " + value);
386 }
387 }
388 }
389 }
390 assignClassifier(classifier);
391 return true;
392 }
393 else {
394 ///ystem.err.println("Unknown classifier");
395 }
396 }
397 }
398 else if(command_lc.startsWith("customclassifier")) {
399 unresolved_commands.add(command);
400 return true;
401 }
402 return false;
403 }
404 /** 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 reserve.
405 * @param classifier The Classifier or CustomClassifier, as an <strong>Object</strong>, to remove.
406 * @see org.greenstone.gatherer.cdm.DynamicListModel
407 */
408 public void removeClassifier(Object classifier) {
409 assigned.removeElement(classifier);
410 gatherer.c_man.configurationChanged();
411 }
412 /** Method which attempts to reparse obvious classifier commands which previously referenced unresovable Classifiers.
413 * @see org.greenstone.gatherer.cdm.Classifier
414 * @see org.greenstone.gatherer.cdm.CommandTokenizer
415 * @see org.greenstone.gatherer.cdm.CustomClassifier
416 */
417 public void reparseUnresolved() {
418 for(int i = 0; i < unresolved_commands.size(); i++) {
419 String command = (String) unresolved_commands.get(i);
420 CommandTokenizer tokenizer = new CommandTokenizer(command);
421 if(tokenizer.countTokens() >= 6) {
422 tokenizer.nextToken();// Loose customclassifier
423 // Get class name.
424 String class_name = tokenizer.nextToken();
425 // Parse arguments.
426 String replaces = null;
427 String separations = null;
428 while(tokenizer.hasMoreTokens()) {
429 String arg_name = tokenizer.nextToken();
430 if(arg_name.equalsIgnoreCase("-replaces")) {
431 replaces = tokenizer.nextToken();
432 }
433 else {
434 separations = tokenizer.nextToken();
435 }
436 }
437 try {
438 replaces = replaces.substring(2);
439 int index = Integer.parseInt(replaces);
440 Classifier original = (Classifier)getClassifier(index);
441 if(original != null) {
442 Class custom_classifier_class = Class.forName("org.greenstone.gatherer.cdm.custom." + class_name);
443 CustomClassifier custom_classifier = (CustomClassifier) custom_classifier_class.newInstance();
444 custom_classifier.setGatherer(gatherer);
445 custom_classifier.recreate(original, separations);
446 assigned.add(indexOf(original), custom_classifier);
447 assigned.removeElement(original);
448 }
449 else {
450 ///ystem.err.println("Missing original.");
451 }
452 }
453 catch (Exception error) {
454 error.printStackTrace();
455 }
456 }
457 }
458 // Regardless of if they work, clear the commands.
459 unresolved_commands.clear();
460 }
461 /** Method to cache the current contents of reserve (known classifiers) to file.
462 * @see org.greenstone.gatherer.util.Utility
463 */
464 public void saveClassifiers() {
465 try {
466 FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat");
467 ObjectOutputStream out = new ObjectOutputStream(file);
468 out.writeObject(reserve);
469 out.close();
470 }
471 catch (Exception error) {
472 }
473 }
474 /** Called when a metadata set changed significantly.
475 * @param event A <strong>MSMEvent</strong> containing information about the set change.
476 */
477 public void setChanged(MSMEvent event) {
478 // Again, we would only worry about this if we contained 'inanimate' references to elements or something, but our references are live, and controls are rebuilt everytime a pop-up is needed.
479 }
480 /** Method used to determine the number of classifiers that have been assigned.
481 * @return An <i>int</i> which is the number of classifiers.
482 */
483 public int size() {
484 return assigned.size();
485 }
486 /** Method to print out a block of classifier commands, much like you'd find in a collection configuration file.
487 * @return A <strong>String</strong> containing a series of classifier commands separated by new lines.
488 * @see org.greenstone.gatherer.cdm.Classifier
489 * @see org.greenstone.gatherer.cdm.CustomClassifier
490 */
491 public String toString() {
492 StringBuffer text = new StringBuffer();
493 for(int i = 0; i < assigned.size(); i++) {
494 Object object = assigned.get(i);
495 if(object instanceof Classifier) {
496 Classifier classifier = (Classifier) object;
497 text.append(classifier.toString());
498 }
499 else if(object instanceof CustomClassifier) {
500 CustomClassifier classifier = (CustomClassifier) object;
501 text.append(classifier.getCommand());
502 text.append("\n");
503 text.append(classifier.getCustomCommand(i));
504 }
505 text.append("\n");
506 }
507 text.append("\n");
508 return text.toString();
509 }
510 /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
511 * @param event A <strong>MSMEvent</strong> containing information relevant to the event.
512 */
513 public void valueChanged(MSMEvent event) {
514 }
515 /** Retrieve a phrase from the dictionary based on a certain key.
516 * @param key The search <strong>String</strong>.
517 * @return The matching phrase from the Dictionary.
518 */
519 private String get(String key) {
520 return get(key, null);
521 }
522 /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
523 * @param key The search <strong>String</strong>.
524 * @param args A <strong>String[]</strong> used to complete and format the returned phrase.
525 * @return The matching phrase from the Dictionary.
526 * @see org.greenstone.gatherer.Dictionary
527 * @see org.greenstone.gatherer.Gatherer
528 */
529 private String get(String key, String args[]) {
530 if(key.indexOf(".") == -1) {
531 key = "CDM.ClassifierManager." + key;
532 }
533 return gatherer.dictionary.get(key, args);
534 }
535 /** Method to extract just the classifiers name from a file object.
536 * @param classifier The <strong>File</strong> which references a certain classifier.
537 * @return A <strong>String</strong> containing just the classifiers name, without extension.
538 */
539 private String getClassifierName(File classifier) {
540 String name = classifier.getName();
541 if(name.indexOf(".") != -1) {
542 name = name.substring(0, name.indexOf("."));
543 }
544 return name;
545 }
546 /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
547 * @see org.greenstone.gatherer.cdm.DynamicListModel
548 * @see org.greenstone.gatherer.util.Utility
549 */
550 private void loadClassifiers() {
551 // Attempt to restore the cached file.
552 try {
553 FileInputStream file = new FileInputStream(Utility.BASE_DIR + "classifiers.dat");
554 ObjectInputStream input = new ObjectInputStream(file);
555 reserve = (DynamicListModel) input.readObject();
556 }
557 catch (Exception error) {
558 }
559 if(reserve == null) {
560 reserve = new DynamicListModel();
561 // Retrieve the gsdl home directory...
562 String directory = gatherer.config.gsdl_path;
563 directory = directory + "perllib" + File.separator + "classify" + File.separator;
564 loadClassifiers(new File(directory));
565 }
566 }
567 /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
568 * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
569 * @see org.greenstone.gatherer.cdm.ParsingProgress
570 */
571 private void loadClassifiers(File directory) {
572 File files[] = directory.listFiles();
573 if(files != null) {
574 // Create a progress indicator.
575 ParsingProgress progress = new ParsingProgress(get("CDM.ClassifierManager.Parsing.Title"), get("CDM.ClassifierManager.Parsing.Message"), files.length);
576 for(int i = 0; i < files.length; i++) {
577 // We only want to check Perl Modules.
578 if(files[i].getName().endsWith(".pm")) {
579 loadClassifier(files[i]);
580 }
581 progress.inc();
582 }
583 progress.dispose();
584 progress.destroy();
585 progress = null;
586 }
587 }
588 /** Parses a DOM tree model turning it into a Classifier and its associated arguments.
589 * @param root The <strong>Node</strong> at the root of the DOM model.
590 * @return A newly created <strong>Classifier</strong> based on the information parsed from the DOM model.
591 * @see org.greenstone.gatherer.cdm.Argument
592 */
593 private Classifier parse(Node root) {
594 Classifier classifier = new Classifier();
595 String node_name = null;
596 for(Node node = root.getFirstChild(); node != null;
597 node = node.getNextSibling()) {
598 node_name = node.getNodeName();
599 if(node_name.equals("Name")) {
600 String name = MSMUtils.getValue(node);
601 // 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.
602 Classifier existing = getClassifier(name);
603 if(existing != null) {
604 return existing;
605 }
606 classifier.setName(name);
607 }
608 else if(node_name.equals("Desc")) {
609 classifier.setDesc(MSMUtils.getValue(node));
610 }
611 // Parse the multitude of arguments.
612 else if(node_name.equals("Arguments")) {
613 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
614 node_name = arg.getNodeName();
615 // An option.
616 if(node_name.equals("Option")) {
617 Argument argument = new Argument();
618 // If its an option we parse the multitude of details an options might have.
619 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
620 node_name = det.getNodeName();
621 if(node_name.equals("Name")) {
622 argument.setName(MSMUtils.getValue(det));
623 }
624 else if(node_name.equals("Desc")) {
625 argument.setDesc(MSMUtils.getValue(det));
626 }
627 else if(node_name.equals("Type")) {
628 argument.setType(MSMUtils.getValue(det));
629 }
630 else if(node_name.equals("Default")) {
631 argument.setDefault(MSMUtils.getValue(det));
632 }
633 else if(node_name.equals("List")) {
634 // Two final loops are required to parse lists.
635 for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
636 if(value.getNodeName().equals("Value")) {
637 String key = null;
638 String desc = "";
639 for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
640 node_name = subvalue.getNodeName();
641 if(node_name.equals("Name")) {
642 key = MSMUtils.getValue(subvalue);
643 }
644 else if(node_name.equals("Desc")) {
645 desc = MSMUtils.getValue(subvalue);
646 }
647 }
648 if(key != null) {
649 argument.addOption(key, desc);
650 }
651 }
652 }
653 }
654 else if(node_name.equals("Required")) {
655 String v = MSMUtils.getValue(det);
656 ///ystem.err.println("Required = " + v);
657 if(v.equalsIgnoreCase("yes")) {
658 ///ystem.err.println("Setting required to true.");
659 argument.setRequired(true);
660 }
661 }
662 }
663 classifier.addArgument(argument);
664 }
665 // A super classifier class.
666 else if(node_name.equals("ClasInfo")) {
667 Classifier super_classifier = parse(arg);
668 classifier.setSuper(super_classifier);
669 }
670 }
671 }
672 }
673 if(classifier.getName() != null) {
674 addClassifier(classifier);
675 return classifier;
676 }
677 return null;
678 }
679 /** A class which provides controls for assigned and editing classifiers. */
680 private class Control
681 extends JPanel {
682 /** Button for adding classifiers. */
683 private JButton add = null;
684 /** Button for configuring the selected classifier. */
685 private JButton configure = null;
686 /** Button to remove the selected classifier. */
687 private JButton remove = null;
688 /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
689 private JComboBox classifier = null;
690 /** A list of assigned classifiers. */
691 private JList classifier_list = null;
692 /** The text area containing instructions on the use of this control. */
693 private JTextArea instructions = null;
694 /** Constructor.
695 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.AddListener
696 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.ConfigureListener
697 * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.RemoveListener
698 */
699 public Control() {
700 Object classifiers[] = reserve.toArray();
701 ArrayList classifier_model = new ArrayList();
702 for(int i = 0; i < classifiers.length; i++) {
703 classifier_model.add(((Classifier)classifiers[i]).getName());
704 }
705 // Now we add custom classifiers.
706 addCustomClassifiers(classifier_model);
707 Collections.sort(classifier_model);
708 // Create
709 add = new JButton(get("Add"));
710 JPanel button_pane = new JPanel();
711 JPanel central_pane = new JPanel();
712 configure = new JButton(get("Configure"));
713 JPanel header_pane = new JPanel();
714 instructions = new JTextArea(get("Instructions"));
715 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
716 instructions.setEditable(false);
717 instructions.setLineWrap(true);
718 instructions.setRows(5);
719 instructions.setWrapStyleWord(true);
720 classifier = new JComboBox(classifier_model.toArray());
721 classifier.setEditable(true);
722 JLabel classifier_label = new JLabel(get("Classifier"));
723 classifier_list = new JList(assigned);
724 JLabel classifier_list_label = new JLabel(get("Assigned"));
725 classifier_list_label.setHorizontalAlignment(JLabel.CENTER);
726 classifier_list_label.setOpaque(true);
727 JPanel classifier_list_pane = new JPanel();
728 JPanel classifier_pane = new JPanel();
729 remove = new JButton(get("Remove"));
730 JLabel title = new JLabel(get("Title"));
731 title.setHorizontalAlignment(JLabel.CENTER);
732 title.setOpaque(true);
733 JPanel temp = new JPanel(new BorderLayout());
734 // Listeners
735 add.addActionListener(new AddListener());
736 configure.addActionListener(new ConfigureListener());
737 remove.addActionListener(new RemoveListener());
738 classifier_list.addMouseListener(new ClickListener());
739 // Layout
740 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
741 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
742 header_pane.setLayout(new BorderLayout());
743 header_pane.add(title, BorderLayout.NORTH);
744 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
745 classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
746 classifier_list_pane.setLayout(new BorderLayout());
747 classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
748 classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
749 classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
750 classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
751 classifier_pane.setLayout(new GridLayout(1,2));
752 classifier_pane.add(classifier_label);
753 classifier_pane.add(classifier);
754 button_pane.setLayout(new GridLayout(3,1));
755 button_pane.add(add);
756 button_pane.add(configure);
757 button_pane.add(remove);
758 // Scope these mad bordering skillz.
759 temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
760 temp.add(classifier_pane, BorderLayout.NORTH);
761 temp.add(button_pane, BorderLayout.SOUTH);
762 central_pane.setLayout(new BorderLayout());
763 central_pane.add(classifier_list_pane, BorderLayout.CENTER);
764 central_pane.add(temp, BorderLayout.SOUTH);
765 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
766 setLayout(new BorderLayout());
767 add(header_pane, BorderLayout.NORTH);
768 add(central_pane, BorderLayout.CENTER);
769 }
770 /** Method which acts like a destructor, tidying up references to persistant objects.
771 */
772 public void destroy() {
773 add = null;
774 classifier = null;
775 classifier_list = null;
776 configure = null;
777 instructions = null;
778 remove = null;
779 }
780 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
781 */
782 public void updateUI() {
783 if(instructions != null) {
784 instructions.setCaretPosition(0);
785 }
786 super.updateUI();
787 }
788 /** Searches and adds a list of dynamically located CustomClassifiers. Note that the classes must be located under org.greenstone.gatherer.cdm.custom and have accompaning properties files which are used as dictionaries.
789 * @param classifier_model An <strong>ArrayList</strong> which will be used as the model for the combobox listing all known Classifiers.
790 */
791 private void addCustomClassifiers(ArrayList classifier_model) {
792 //classifier_model.add("CustomAZList");
793 // Search for classifiers under the org.greenstone.gatherer.cdm.custom directory.
794 File custom_directory = new File(Utility.BASE_DIR + "classes" + File.separator + "org" + File.separator + "greenstone" + File.separator + "gatherer" + File.separator + "cdm" + File.separator + "custom");
795 if(custom_directory.exists()) {
796 File children[] = custom_directory.listFiles();
797 for(int i = 0; i < children.length; i++) {
798 String temp = children[i].getName().toLowerCase();
799 // There are a whole bunch of conditions about what files are custom classifier main classes.
800 if(temp.endsWith(".class") && temp.indexOf("$") == -1) {
801 // Determine the name of this custom classifier.
802 String name = children[i].getName();
803 name = name.substring(0, name.indexOf("."));
804 classifier_model.add(name);
805 }
806 }
807 }
808 // Search for any other CustomClassifiers within the jar file (if present)
809 File jar_file = new File("Gatherer.jar");
810 if(jar_file.exists()) {
811 try {
812 JarFile jar = new JarFile(jar_file);
813 for(Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
814 String name = entries.nextElement().toString();
815 if(name.startsWith("org/greenstone/gatherer/cdm/custom/") && name.endsWith(".class") && name.indexOf("$") == -1) {
816 name = name.substring(35, name.length() - 6);
817 if(!classifier_model.contains(name)) {
818 classifier_model.add(name);
819 }
820 }
821 name = null;
822 }
823 jar = null;
824 }
825 catch (Exception error) {
826 error.printStackTrace();
827 }
828 }
829 jar_file = null;
830 }
831 /** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method.
832 */
833 private class AddListener
834 implements ActionListener {
835 /** 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.
836 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
837 * @see org.greenstone.gatherer.Gatherer
838 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
839 * @see org.greenstone.gatherer.cdm.Classifier
840 * @see org.greenstone.gatherer.cdm.CustomClassifier
841 */
842 public void actionPerformed(ActionEvent event) {
843 String name = (String)classifier.getSelectedItem();
844 Classifier target = getClassifier(name);
845 Classifier classifier = null;
846 CustomClassifier custom_classifier = null;
847 if(target != null) {
848 classifier = target.copy();
849 }
850 else {
851 // Try to retrieve custom classifier for name.
852 try {
853 Class custom_class = Class.forName("org.greenstone.gatherer.cdm.custom." + name);
854 custom_classifier = (CustomClassifier)custom_class.newInstance();
855 custom_classifier.setGatherer(gatherer);
856 }
857 catch (Exception error) {
858 gatherer.debug(error, "Error in ClassifierManager.AddListener.actionPerformed(): " + error);
859 }
860 // And if all else fails create a new classifier.
861 if(classifier == null && custom_classifier == null) {
862 classifier = new Classifier(name, "", null);
863 }
864 }
865 if(classifier != null) {
866 // Automatically chain to configuration. This ensures required arguments are filled out.
867 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, classifier);
868 if(ac.display()) {
869 assignClassifier(classifier);
870 }
871 ac.destroy();
872 ac = null;
873 }
874 // Custom classifier
875 else {
876 if(custom_classifier.display(true)) {
877 assignClassifier(custom_classifier);
878 }
879 custom_classifier.destroy(); // Remove gui prompt or else.
880 custom_classifier = null;
881 }
882 }
883 }
884 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
885 private class ClickListener
886 extends MouseAdapter {
887 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
888 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
889 */
890 public void mouseClicked(MouseEvent event) {
891 if(event.getClickCount() == 2 ) {
892 if(!classifier_list.isSelectionEmpty()) {
893 Object object = classifier_list.getSelectedValue();
894 if(object instanceof Classifier) {
895 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
896 if(ac.display()) {
897 assigned.refresh();
898 }
899 ac.destroy();
900 ac = null;
901 }
902 else if(object instanceof CustomClassifier) {
903 CustomClassifier cc = (CustomClassifier)object;
904 if(cc.display(true)) {
905 assigned.refresh();
906 }
907 cc.destroy(); // Remove gui prompt or else.
908 cc = null;
909 }
910 }
911 }
912 }
913 }
914 /** 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.
915 */
916 private class ConfigureListener
917 implements ActionListener {
918 /** 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.
919 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
920 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
921 * @see org.greenstone.gatherer.cdm.Classifier
922 * @see org.greenstone.gatherer.cdm.CustomClassifier
923 */
924 public void actionPerformed(ActionEvent event) {
925 if(!classifier_list.isSelectionEmpty()) {
926 Object object = classifier_list.getSelectedValue();
927 if(object instanceof Classifier) {
928 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
929 if(ac.display()) {
930 assigned.refresh();
931 }
932 ac.destroy();
933 ac = null;
934 }
935 else if(object instanceof CustomClassifier) {
936 CustomClassifier cc = (CustomClassifier)object;
937 if(cc.display(true)) {
938 assigned.refresh();
939 }
940 cc.destroy(); // Remove gui prompt or else.
941 cc = null;
942 }
943 }
944 }
945 }
946 /** This class listens for actions upon the remove button in the controls, and if detected calls the removeClassifier() method.
947 */
948 private class RemoveListener
949 implements ActionListener {
950 /** 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.
951 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
952 * @see org.greenstone.gatherer.cdm.Classifier
953 * @see org.greenstone.gatherer.cdm.CustomClassifier
954 */
955 public void actionPerformed(ActionEvent event) {
956 if(!classifier_list.isSelectionEmpty()) {
957 Object object = classifier_list.getSelectedValue();
958 if(object instanceof Classifier || object instanceof CustomClassifier) {
959 removeClassifier(object);
960 }
961 }
962 }
963 }
964 }
965}
966
967
968
969
970
971
Note: See TracBrowser for help on using the repository browser.