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