source: trunk/gli/src/org/greenstone/gatherer/cdm/PlugInManager.java@ 4838

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

2030159: Had confused element name and identifier. Also added ability for ElementWrappers to be stored as Argument values, and thus have identifier appear within GLI while the name is written to the collect.cfg

  • Property svn:keywords set to Author Date Id Revision
File size: 37.5 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
43package org.greenstone.gatherer.cdm;
44/**
45 * Title: The Gatherer<br>
46 * Description: The Gatherer: a tool for gathering and enriching digital collections.<br>
47 * Copyright: Copyright (c) 2001<br>
48 * Company: The University of Waikato<br>
49 * First Coded: 01/05/02
50 * @author John Thompson, Greenstone Digital Libraries
51 * @version 2.1
52 */
53import java.awt.*;
54import java.awt.event.*;
55import java.io.*;
56import java.util.*;
57import javax.swing.*;
58import javax.swing.event.*;
59import javax.swing.plaf.basic.BasicArrowButton;
60import org.apache.xerces.parsers.DOMParser;
61import org.greenstone.gatherer.Gatherer;
62import org.greenstone.gatherer.cdm.Argument;
63import org.greenstone.gatherer.cdm.ArgumentConfiguration;
64import org.greenstone.gatherer.cdm.CommandTokenizer;
65import org.greenstone.gatherer.cdm.DynamicListModel;
66import org.greenstone.gatherer.cdm.PlugIn;
67import org.greenstone.gatherer.msm.ElementWrapper;
68import org.greenstone.gatherer.msm.MSMUtils;
69import org.greenstone.gatherer.util.Utility;
70import org.w3c.dom.*;
71import org.xml.sax.InputSource;
72/** This class is resposible for maintaining a list of known plug-ins, and importing new plugins using the parser. */
73public class PlugInManager {
74 /** A reference to the main manager for this module. */
75 private CollectionDesignManager manager = null;
76 /** The controls for editing the contents of this manager. */
77 private Control controls = null;
78 /** A list of assigned plugins. */
79 private DynamicListModel assigned = null;
80 /** A list of those plugins that have not yet been assigned. Begins as a copy of reserve. */
81 private DynamicListModel available = null;
82 /** A list of known, but currently unassigned, plug-ins. */
83 private DynamicListModel reserve = null;
84 /** A reference to the Gatherer. */
85 private Gatherer gatherer = null;
86 /** The current index of the separator. */
87 private JPanel separator = null;
88 /** The default size for a label. */
89 static final private Dimension LABEL_SIZE = new Dimension(140, 20);
90 /** Constructor.
91 */
92 public PlugInManager(Gatherer gatherer, CollectionDesignManager manager) {
93 this.assigned = new DynamicListModel();
94 this.gatherer = gatherer;
95 this.manager = manager;
96 this.separator = getSeparator();
97 // Add the movement separator
98 assigned.addElement(separator);
99 loadPlugIns();
100 savePlugIns();
101 }
102 /** Method to add a new plugin to reserve.
103 * @param plugin The new <strong>PlugIn</strong>.
104 */
105 public void addPlugIn(PlugIn plugin) {
106 if(!reserve.contains(plugin)) {
107 reserve.addElement(plugin);
108 available.addElement(plugin);
109 }
110 }
111 /** Method to assign a plugin.
112 * @param plugin The reserve <strong>PlugIn</strong> to assign.
113 */
114 public void assignPlugIn(PlugIn plugin) {
115 if(!assigned.contains(plugin)) {
116 if(plugin.getName().equals("RecPlug") || plugin.getName().equals("ArcPlug")) {
117 assigned.addElement(plugin); // Adds after separator
118 }
119 else {
120 int index = assigned.indexOf(separator);
121 assigned.add(index, plugin);
122 }
123 // Remove from available
124 available.removeElement(plugin);
125 gatherer.c_man.configurationChanged();
126 }
127 }
128 /** Method to retrieve the control for this manager.
129 * @return A <strong>JPanel</strong> containing the controls.
130 */
131 public JPanel getControls() {
132 if(controls == null) {
133 controls = new Control();
134 }
135 return controls;
136 }
137 /** Method to retrieve the named plugin.
138 * @param name The name of the desired plugin as a <strong>String</strong>.
139 * @return The requested <strong>PlugIn</strong> or <i>null</i> if no such plugin exists.
140 */
141 public PlugIn getPlugIn(String name) {
142 for(int i = 0; i < reserve.size(); i++) {
143 Object object = reserve.get(i);
144 if(object instanceof PlugIn) {
145 PlugIn plugin = (PlugIn) object;
146 if(plugin.getName().equals(name)) {
147 return plugin;
148 }
149 }
150 }
151 // No success.
152 return null;
153 }
154 /** Method to invalidate controls after a significant change in the system state.
155 */
156 public void invalidateControls() {
157 if(controls != null) {
158 controls.destroy();
159 }
160 controls = null;
161 }
162 /** Method to load the details of a single plug-in.
163 * @param plugin The plugin <strong>File</strong> you wish to load.
164 */
165 public void loadPlugIn(File plugin) {
166 Document document = null;
167 // Run pluginfo on this plugin, and then send the results for parsing.
168 try {
169 String args[] = null;
170 if(Utility.isWindows()) {
171 args = new String[4];
172 if(gatherer.config.perl_path != null) {
173 args[0] = gatherer.config.perl_path;
174 }
175 else {
176 args[0] = "Perl.exe";
177 }
178 args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl";
179 args[2] = "-xml";
180 args[3] = getPlugInName(plugin);
181 }
182 else {
183 args = new String[3];
184 args[0] = "pluginfo.pl";
185 args[1] = "-xml";
186 args[2] = getPlugInName(plugin);
187 }
188 // Create the process.
189 Runtime runtime = Runtime.getRuntime();
190 Process process = runtime.exec(args);
191 //InputStream input_stream = process.getErrorStream();
192 BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
193 String line = "";
194 StringBuffer xml = new StringBuffer("");
195 boolean xml_content = false;
196 while((line = error_in.readLine()) != null) {
197 if(xml_content) {
198 xml.append(line);
199 xml.append("\n");
200 }
201 else if(line.trim().startsWith("<?xml")) {
202 xml_content = true;
203 xml.append(line);
204 xml.append("\n");
205 }
206 }
207 error_in = null;
208 process = null;
209 runtime = null;
210 args = null;
211 // If something has gone horribly wrong then xml will be empty.
212 if(xml.length() != 0) {
213 // Then read the xml from the piped input stream.
214 InputSource source = new InputSource(new StringReader(xml.toString()));
215 DOMParser parser = new DOMParser();
216 parser.parse(source);
217 document = parser.getDocument();
218 parser = null;
219 source = null;
220 }
221 else {
222 String plugin_name = getPlugInName(plugin);
223 Gatherer.println("Zero length argument xml detected for: " + plugin_name);
224 JOptionPane.showMessageDialog(Gatherer.g_man, get("PlugIn_XML_Parse_Failed", plugin_name), get("General.Error"), JOptionPane.ERROR_MESSAGE);
225 }
226 }
227 catch (Exception error) {
228 error.printStackTrace();
229 }
230 if(document != null) {
231 parse(document.getDocumentElement());
232 }
233 }
234 /** Method to move a plugin higher in the list order.
235 * @param plugin The <strong>PlugIn</strong> you want to move.
236 * @param direction <i>true</i> to move the plugin up, <i>false</i> to move it down.
237 * @param all <i>true</i> to move to move all the way, <i>false</i> for a single step.
238 */
239 public void movePlugIn(PlugIn plugin, boolean direction, boolean all) {
240 // Can't ever move RecPlug or ArcPlug.
241 if(plugin.getName().equals("ArcPlug") || plugin.getName().equals("RecPlug")) {
242 JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Fixed"), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
243 return;
244 }
245 if(all) {
246 if(direction) {
247 assigned.removeElement(plugin);
248 assigned.add(0, plugin);
249 gatherer.c_man.configurationChanged();
250 }
251 else {
252 assigned.removeElement(plugin);
253 int index = assigned.size() - 1;
254 boolean found = false;
255 while(!found) {
256 Object temp = assigned.get(index);
257 if(temp instanceof PlugIn) {
258 PlugIn current = (PlugIn) temp;
259 if(current.getName().equals("ArcPlug") || current.getName().equals("RecPlug")) {
260 index--;
261 }
262 else {
263 found = true;
264 }
265 }
266 else {
267 found = true;
268 }
269 }
270 assigned.add(index, plugin);
271 gatherer.c_man.configurationChanged();
272 }
273 }
274 else {
275 // Try to move the plugin one step in the desired direction.
276 int index = assigned.indexOf(plugin);
277 ///ystem.err.println("Index of " + plugin + " = " + index);
278 if(direction) {
279 index--;
280 if(index < 0) {
281 String args[] = new String[1];
282 args[0] = plugin.getName();
283 JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
284 return;
285 }
286 assigned.removeElement(plugin);
287 assigned.add(index, plugin);
288 gatherer.c_man.configurationChanged();
289 }
290 else {
291 index++;
292 Object object = assigned.get(index);
293 if(index == assigned.size()) {
294 String args[] = new String[1];
295 args[0] = plugin.getName();
296 JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Bottom", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
297 // Still not going to move RecPlug or ArcPlug.
298 return;
299 }
300 else if(!(object instanceof PlugIn) || ((PlugIn)object).getName().equals("ArcPlug") || ((PlugIn)object).getName().equals("RecPlug")) {
301 String args[] = new String[1];
302 args[0] = plugin.getName();
303 JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Cannot", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
304 // Still not going to move RecPlug or ArcPlug.
305 return;
306 }
307 assigned.removeElement(plugin);
308 assigned.add(index, plugin);
309 gatherer.c_man.configurationChanged();
310 }
311 }
312 }
313
314 /** This method attempts to parse a plugin command from a command string taken from the collection configuration file. This process is quite complex as not only must the correct plugin be matched by also all of the parameters given must be legal. If such a command is found, the plugin is immediately assigned.
315 * @param command The coomand <strong>String</strong> that may include plugin information.
316 * @return <i>true</i> if a plugin command was parsed, <i>false</i> otherwise.
317 */
318 public boolean parse(String command) {
319 String command_lc = command.toLowerCase();
320 if(command_lc.startsWith("plugin")) {
321 CommandTokenizer tokenizer = new CommandTokenizer(command);
322 if(tokenizer.countTokens() >= 2) {
323 tokenizer.nextToken(); // Throw away 'plugin'
324 String name = tokenizer.nextToken();
325 // Try to locate the plugin with this name.
326 PlugIn plugin = getPlugIn(name);
327 // And if successful start to parse the arguments.
328 if(plugin != null) {
329 // Take a copy.
330 plugin = plugin.copy();
331 String key = null;
332 while(tokenizer.hasMoreTokens()) {
333 if(key == null) {
334 key = tokenizer.nextToken();
335 }
336 // Try to retrieve a matching argument.
337 Argument argument = plugin.getArgument(key);
338 if(argument != null) {
339 // Set as assigned.
340 argument.setAssigned(true);
341 // And if the argument is of a parameter type, parse a parameter.
342 if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
343 String value = tokenizer.nextToken();
344 ElementWrapper element = null;
345 if(argument.getType() == Argument.METADATA) {
346 value = value.replace(':', MSMUtils.NS_SEP);
347 if (value.indexOf(MSMUtils.NS_SEP)==-1){
348 value = Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP + value;
349 }
350 // Now retrieve the element this refers to, if available.
351 element = Gatherer.c_man.getCollection().msm.getElement(value);
352 }
353 if(element != null) {
354 argument.setElementValue(element);
355 element = null;
356 }
357 else {
358 argument.setValue(value);
359 }
360 }
361 key = null;
362 }
363 // Argument cannot be matched.
364 else {
365 String cur_key = key;
366 String value = tokenizer.nextToken();
367 if(value.startsWith("-")) {
368 key = value;
369 value = null;
370 }
371 else {
372 key = null;
373 }
374 String custom = plugin.getCustom();
375 if(custom == null) {
376 if(value == null) {
377 plugin.setCustom(cur_key);
378 }
379 else {
380 plugin.setCustom(cur_key + " " + value);
381 }
382 }
383 else {
384 if(value == null) {
385 plugin.setCustom(custom + " " + cur_key);
386 }
387 else {
388 plugin.setCustom(custom + " " + cur_key + " " + value);
389 }
390 }
391 }
392 }
393 // Slight tweak. If the plugin is the RecPlug we want to set use_metadata_files by default.
394 if(plugin.getName().equalsIgnoreCase("RecPlug")) {
395 Argument argument = plugin.getArgument("-use_metadata_files");
396 if(argument != null) {
397 argument.setAssigned(true);
398 }
399 }
400 // Second tweak. If the plugin is the HTMLPlug we want to modify the block expression so our backup files are ignored.
401 if(plugin.getName().equalsIgnoreCase("HTMLPlug")) {
402 Argument argument = plugin.getArgument("-block_exp");
403 if(argument != null) {
404 argument.setValue(argument.getDefaultValue() + "|(~$)");
405 }
406 }
407 // Add the plugin to our reserve
408 assignPlugIn(plugin);
409 return true;
410 }
411 else {
412 //ystem.err.println("Unknown plugin");
413 }
414 }
415 }
416 return false;
417 }
418 /** This method removes an assigned plugin. I was tempted to call it unassign, by remove is more consistant. Note that there is no way to remove a plugin from the reserve.
419 * @param plugin The <strong>PlugIn</strong> to remove.
420 */
421 public void removePlugIn(PlugIn plugin) {
422 assigned.removeElement(plugin);
423 available.addElement(plugin);
424 gatherer.c_man.configurationChanged();
425 }
426 /** Method to cache the current contents of reserve (known plugins) to file.
427 */
428 public void savePlugIns() {
429 try {
430 FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "plugins.dat");
431 ObjectOutputStream out = new ObjectOutputStream(file);
432 out.writeObject(reserve);
433 out.close();
434 }
435 catch (Exception error) {
436 }
437 }
438 /** Method used to determine the number of plugins that have been assigned.
439 * @return An <i>int</i> which is the number of plugins.
440 */
441 public int size() {
442 return assigned.size();
443 }
444 /** Method to print out a block of plugin commands, much like you'd find in a collection configuration file.
445 * @return A <strong>String</strong> containing a series of plugin commands separated by new lines.
446 */
447 public String toString() {
448 String text = "";
449 for(int i = 0; i < assigned.size(); i++) {
450 Object object = assigned.get(i);
451 if(object instanceof PlugIn) {
452 PlugIn plugin = (PlugIn) object;
453 text = text + plugin.toString() + "\n";
454 }
455 }
456 text = text + "\n";
457 return text;
458 }
459 /* Retrieve a phrase from the dictionary based on a certain key.
460 * @param key The search <strong>String</strong>.
461 * @return The matching phrase from the Dictionary.
462 */
463 private String get(String key) {
464 return get(key, (String[])null);
465 }
466
467 private String get(String key, String arg) {
468 String args[] = new String[1];
469 args[0] = arg;
470 return get(key, args);
471 }
472
473 /* Retrieve a phrase from the dictionary based on a certain key and arguments.
474 * @param key The search <strong>String</strong>.
475 * @param args A <strong>String[]</strong> of arguments used to complete and format the choosen phrase.
476 * @return The matching phrase from the Dictionary.
477 */
478 private String get(String key, String args[]) {
479 if(key.indexOf(".") == -1) {
480 key = "CDM.PlugInManager." + key;
481 }
482 return gatherer.dictionary.get(key, args);
483 }
484 /** Method to extract just the plugins name from a file object.
485 * @param plugin The <strong>File</strong> which references a certain plugin.
486 * @return A <strong>String</strong> containing just the plugins name, without extension.
487 */
488 private String getPlugInName(File plugin) {
489 String name = plugin.getName();
490 if(name.indexOf(".") != -1) {
491 name = name.substring(0, name.indexOf("."));
492 }
493 return name;
494 }
495 /** Method to retrieve the CData value from a node. Requires a search for the #text node.
496 * @param node The <strong>Node</strong> whose value we wish to find.
497 * @return The value of node as a <strong>String</strong>, or <i>null</i> if no value exists.
498 */
499 private String getValue(Node node) {
500 if(node.hasChildNodes()) {
501 Node text = node.getFirstChild();
502 //ystem.err.println("Value of " + node.getNodeName() + " = " + text.getNodeValue());
503 return text.getNodeValue();
504 }
505 return node.getNodeValue();
506 }
507 /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
508 */
509 private void loadPlugIns() {
510 // Attempt to restore the cached file.
511 try {
512 FileInputStream file = new FileInputStream(Utility.BASE_DIR + "plugins.dat");
513 ObjectInputStream input = new ObjectInputStream(file);
514 reserve = (DynamicListModel) input.readObject();
515 available = reserve.shallowCopy();
516 }
517 catch (Exception error) {
518 }
519 if(reserve == null) {
520 available = new DynamicListModel();
521 reserve = new DynamicListModel();
522 reserve.setAutoOrder(true);
523 // Retrieve the gsdl home directory...
524 String directory = gatherer.config.gsdl_path;
525 directory = directory + "perllib" + File.separator + "plugins" + File.separator;
526 loadPlugIns(new File(directory));
527 }
528 }
529 /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
530 * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
531 */
532 private void loadPlugIns(File directory) {
533 File files[] = directory.listFiles();
534 if(files != null) {
535 // Create a progress indicator.
536 ParsingProgress progress = new ParsingProgress(get("CDM.PlugInManager.Parsing.Title"), get("CDM.PlugInManager.Parsing.Message"), files.length);
537 for(int i = 0; i < files.length; i++) {
538 // We only want to check Perl Modules.
539 if(files[i].getName().endsWith(".pm")) {
540 loadPlugIn(files[i]);
541 }
542 progress.inc();
543 }
544 progress.dispose();
545 }
546 }
547
548 private PlugIn parse(Node root) {
549 PlugIn plugin = new PlugIn();
550 String node_name = null;
551 for(Node node = root.getFirstChild(); node != null;
552 node = node.getNextSibling()) {
553 node_name = node.getNodeName();
554 if(node_name.equals("Name")) {
555 String name = getValue(node);
556 // We can save ourselves some processing time if a plugin with this name already exists in our manager. If so retrieve it and return it.
557 PlugIn existing = getPlugIn(name);
558 if(existing != null) {
559 return existing;
560 }
561 plugin.setName(name);
562 }
563 else if(node_name.equals("Desc")) {
564 plugin.setDesc(getValue(node));
565 }
566 // Parse the multitude of arguments.
567 else if(node_name.equals("Arguments")) {
568 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
569 node_name = arg.getNodeName();
570 // An option.
571 if(node_name.equals("Option")) {
572 Argument argument = new Argument();
573 // If its an option we parse the multitude of details an options might have.
574 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
575 node_name = det.getNodeName();
576 if(node_name.equals("Name")) {
577 argument.setName(getValue(det));
578 }
579 else if(node_name.equals("Desc")) {
580 argument.setDesc(getValue(det));
581 }
582 else if(node_name.equals("Type")) {
583 argument.setType(getValue(det));
584 }
585 else if(node_name.equals("Default")) {
586 argument.setDefault(getValue(det));
587 }
588 else if(node_name.equals("List")) {
589 // Two final loops are required to parse lists.
590 for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
591 if(value.getNodeName().equals("Value")) {
592 String key = null;
593 String desc = "";
594 for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
595 node_name = subvalue.getNodeName();
596 if(node_name.equals("Name")) {
597 key = getValue(subvalue);
598 }
599 else if(node_name.equals("Desc")) {
600 desc = getValue(subvalue);
601 }
602 }
603 if(key != null) {
604 argument.addOption(key, desc);
605 }
606 }
607 }
608 }
609 else if(node_name.equals("Required")) {
610 String v = getValue(det);
611 if(v != null && v.equals("yes")) {
612 argument.setRequired(true);
613 }
614 }
615 }
616 plugin.addArgument(argument);
617 }
618 // A super plugin class.
619 else if(node_name.equals("PlugInfo")) {
620 PlugIn super_plugin = parse(arg);
621 plugin.setSuper(super_plugin);
622 }
623 }
624 }
625 }
626 if(plugin.getName() != null) {
627 addPlugIn(plugin);
628 return plugin;
629 }
630 return null;
631 }
632
633 /** A class which provodes controls for assigned and editing plugins. */
634 private class Control
635 extends JPanel {
636 /** Button for adding plugins. */
637 private JButton add = null;
638 /** Button for configuring the selected plugin. */
639 private JButton configure = null;
640 /** Buttom to move an assinged plugin as low in the order as possible. */
641 private JButton move_bottom = null;
642 /** Button to move an assigned plugin one position lower in the order. */
643 private JButton move_down = null;
644 /** Button to move an assigned plugin as high in the order as possible. */
645 private JButton move_top = null;
646 /** Button to move an assigned plugin one position higher in the order. */
647 private JButton move_up = null;
648 /** Button to remove the selected plugin. */
649 private JButton remove = null;
650 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
651 private JComboBox plugin = null;
652 /** The label next to the plugin combobox. */
653 private JLabel plugin_label = null;
654 /** The label above the assigned plugin list. */
655 private JLabel plugin_list_label = null;
656 /** The title of this view. */
657 private JLabel title = null;
658 /** A list of assigned plugins. */
659 private JList plugin_list = null;
660 /** The area where the add, configure and remove buttons are placed. */
661 private JPanel button_pane = null;
662 /** The region which divides the central portion of the view into list and controls. */
663 private JPanel central_pane = null;
664 /** The area where title label and instructions sit. */
665 private JPanel header_pane = null;
666 /** The area where movement buttons are placed. */
667 private JPanel movement_pane = null;
668 /** The small region containing the plugin combobox and its label. */
669 private JPanel plugin_pane = null;
670 /** The pane containing the assigned plugin list and its label. */
671 private JPanel plugin_list_pane = null;
672 /** The text area containing instructions on the use of this control. */
673 private JTextArea instructions = null;
674 /** Constructor.
675 */
676 public Control() {
677 Object plugins[] = reserve.toArray();
678 Vector plugin_model = new Vector();
679 for(int i = 0; i < plugins.length; i++) {
680 plugin_model.add(((PlugIn)plugins[i]).getName());
681 }
682 Collections.sort(plugin_model);
683 // Create
684 add = new JButton(get("Add"));
685 add.setMnemonic(KeyEvent.VK_A);
686 button_pane = new JPanel();
687 central_pane = new JPanel();
688 configure = new JButton(get("Configure"));
689 configure.setEnabled(false);
690 configure.setMnemonic(KeyEvent.VK_C);
691 header_pane = new JPanel();
692 instructions = new JTextArea(get("Instructions"));
693 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
694 instructions.setEditable(false);
695 instructions.setLineWrap(true);
696 instructions.setRows(5);
697 instructions.setWrapStyleWord(true);
698 move_bottom = new JButton();
699 JLabel move_bottom_label = new JLabel(get("Move_Bottom"));
700 move_bottom_label.setHorizontalAlignment(JLabel.CENTER);
701 move_bottom_label.setPreferredSize(LABEL_SIZE);
702 move_bottom.setLayout(new BorderLayout());
703 move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.WEST);
704 move_bottom.add(move_bottom_label, BorderLayout.CENTER);
705 move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.EAST);
706 move_bottom.setMnemonic(KeyEvent.VK_B);
707 move_down = new JButton();
708 JLabel move_down_label = new JLabel(get("Move_Down"));
709 move_down_label.setHorizontalAlignment(JLabel.CENTER);
710 move_down_label.setPreferredSize(LABEL_SIZE);
711 move_down.setLayout(new BorderLayout());
712 move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.WEST);
713 move_down.add(move_down_label, BorderLayout.CENTER);
714 move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.EAST);
715 move_down.setMnemonic(KeyEvent.VK_D);
716 move_top = new JButton();
717 JLabel move_top_label = new JLabel(get("Move_Top"));
718 move_top_label.setHorizontalAlignment(JLabel.CENTER);
719 move_top_label.setPreferredSize(LABEL_SIZE);
720 move_top.setLayout(new BorderLayout());
721 move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.WEST);
722 move_top.add(move_top_label, BorderLayout.CENTER);
723 move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.EAST);
724 move_top.setMnemonic(KeyEvent.VK_T);
725 move_up = new JButton();
726 JLabel move_up_label = new JLabel(get("Move_Up"));
727 move_up_label.setHorizontalAlignment(JLabel.CENTER);
728 move_up_label.setPreferredSize(LABEL_SIZE);
729 move_up.setLayout(new BorderLayout());
730 move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.WEST);
731 move_up.add(move_up_label, BorderLayout.CENTER);
732 move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.EAST);
733 move_up.setMnemonic(KeyEvent.VK_U);
734 movement_pane = new JPanel();
735 plugin = new JComboBox(available);
736 //plugin.setEditable(true);
737 plugin.setSelectedIndex(0);
738 plugin_label = new JLabel(get("PlugIn"));
739 plugin_list = new JList(assigned);
740 plugin_list.setCellRenderer(new ListRenderer());
741 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
742 plugin_list_label = new JLabel(get("Assigned"));
743 plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
744 plugin_list_label.setOpaque(true);
745 plugin_list_pane = new JPanel();
746 plugin_pane = new JPanel();
747 remove = new JButton(get("Remove"));
748 remove.setEnabled(false);
749 remove.setMnemonic(KeyEvent.VK_R);
750 title = new JLabel(get("Title"));
751 title.setHorizontalAlignment(JLabel.CENTER);
752 title.setOpaque(true);
753 // Listeners
754 add.addActionListener(new AddListener());
755 configure.addActionListener(new ConfigureListener());
756 MoveListener ml = new MoveListener();
757 move_bottom.addActionListener(ml);
758 move_down.addActionListener(ml);
759 move_top.addActionListener(ml);
760 move_up.addActionListener(ml);
761 remove.addActionListener(new RemoveListener());
762 plugin_list.addMouseListener(new ClickListener());
763 plugin_list.addListSelectionListener(new ListListener());
764 // Layout
765 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
766
767 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
768
769 header_pane.setLayout(new BorderLayout());
770 header_pane.add(title, BorderLayout.NORTH);
771 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
772
773 plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
774
775 movement_pane.setLayout(new GridLayout(4,1));
776 movement_pane.add(move_top);
777 movement_pane.add(move_up);
778 movement_pane.add(move_down);
779 movement_pane.add(move_bottom);
780
781 plugin_list_pane.setLayout(new BorderLayout());
782 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
783 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
784 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
785
786 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
787
788 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
789 plugin_pane.setLayout(new GridLayout(1,2));
790 plugin_pane.add(plugin_label);
791 plugin_pane.add(plugin);
792
793 // Scope these mad bordering skillz.
794 JPanel temp = new JPanel(new BorderLayout());
795 temp.setBorder
796 (BorderFactory.createCompoundBorder
797 (BorderFactory.createEmptyBorder(5,0,5,0),
798 BorderFactory.createCompoundBorder
799 (BorderFactory.createTitledBorder(get("Controls")),
800 BorderFactory.createEmptyBorder(2,2,2,2))));
801
802 temp.add(plugin_pane, BorderLayout.NORTH);
803 temp.add(button_pane, BorderLayout.SOUTH);
804
805 central_pane.setLayout(new BorderLayout());
806 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
807 central_pane.add(temp, BorderLayout.SOUTH);
808
809 button_pane.setLayout(new GridLayout(3,1));
810 button_pane.add(add);
811 button_pane.add(configure);
812 button_pane.add(remove);
813
814 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
815 setLayout(new BorderLayout());
816 add(header_pane, BorderLayout.NORTH);
817 add(central_pane, BorderLayout.CENTER);
818 //add(button_pane, BorderLayout.SOUTH);
819 }
820 /** Method which acts like a destructor, tidying up references to persistant objects.
821 */
822 public void destroy() {
823 }
824 /** This method is overridden in some control classes to allow for the updating of collection configuration when the focus is lost to another view. In this case however the updates are asynchronous and so no 'has the configuration changed without the user updating' check is needed.
825 * @return <i>true</i> if this control has focus, <i>false</i> otherwise.
826 */
827 public boolean hasFocus() {
828 return super.hasFocus();
829 }
830 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
831 */
832 public void updateUI() {
833 if(instructions != null) {
834 instructions.setCaretPosition(0);
835 }
836 super.updateUI();
837 }
838 /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugIn()</i> method.
839 */
840 private class AddListener
841 implements ActionListener {
842 /** 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.
843 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
844 */
845 public void actionPerformed(ActionEvent event) {
846 PlugIn new_plugin = null;
847 Object object = plugin.getSelectedItem();
848 if(object instanceof PlugIn) {
849 PlugIn target = (PlugIn)object;
850 new_plugin = target.copy();
851 }
852 else {
853 new_plugin = new PlugIn(object.toString(), "", null);
854 }
855 object = null;
856 // Automatically chain to configuration. This ensures required arguments are filled out.
857 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, new_plugin);
858 if(ac.display()) {
859 assignPlugIn(new_plugin);
860 plugin_list.setSelectedValue(new_plugin, true);
861 }
862 ac = null;
863 new_plugin = null;
864 plugin.setSelectedIndex(0);
865 }
866 }
867 /** This class listens for actions upon the configure button in the controls, and if detected creates a new <strong>ArgumentConfiguration</strong> dialog box to allow for configuration.
868 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
869 */
870 private class ConfigureListener
871 implements ActionListener {
872 /** 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.
873 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
874 */
875 public void actionPerformed(ActionEvent event) {
876 if(!plugin_list.isSelectionEmpty()) {
877 Object object = plugin_list.getSelectedValue();
878 if(object instanceof PlugIn) {
879 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
880 if(ac.display()) {
881 assigned.refresh();
882 }
883 }
884 }
885 }
886 }
887 /** A special list renderer which is able to render separating lines as well. */
888 private class ListRenderer
889 extends DefaultListCellRenderer {
890 /** Return a component that has been configured to display the specified value. That component's paint method is then called to "render" the cell. If it is necessary to compute the dimensions of a list because the list cells do not have a fixed size, this method is called to generate a component on which getPreferredSize can be invoked.
891 * @param list - The <strong>JList</strong> we're painting.
892 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
893 * @param index - The cells index as an <i>int</i>.
894 * @param isSelected - <i>true</i> if the specified cell was selected.
895 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
896 * @return A <strong>Component</strong> whose paint() method will render the specified value.
897 * @see javax.swing.JList
898 * @see javax.swing.JSeparator
899 * @see javax.swing.ListModel
900 * @see javax.swing.ListSelectionModel
901 */
902 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
903 if(value instanceof JPanel) {
904 return (JPanel) value;
905 }
906 else {
907 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
908 }
909 }
910 }
911 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
912 private class ClickListener
913 extends MouseAdapter {
914 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
915 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
916 */
917 public void mouseClicked(MouseEvent event) {
918 if(event.getClickCount() == 2 ) {
919 if(!plugin_list.isSelectionEmpty()) {
920 Object object = plugin_list.getSelectedValue();
921 if(object instanceof PlugIn) {
922 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
923 if(ac.display()) {
924 assigned.refresh();
925 }
926 }
927 }
928 }
929 }
930 }
931
932 /** 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 */
933 private class ListListener
934 implements ListSelectionListener {
935
936 public void valueChanged(ListSelectionEvent e) {
937 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
938 if (plugin_list.isSelectionEmpty()) {
939 configure.setEnabled(false);
940 remove.setEnabled(false);
941 } else {
942 configure.setEnabled(true);
943 remove.setEnabled(true);
944 }
945 }
946 }
947 }
948
949 /** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>movePlugIn()</i> method of the manager with the appropriate details. */
950 private class MoveListener
951 implements ActionListener {
952 /** 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.
953 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
954 */
955 public void actionPerformed(ActionEvent event) {
956 if(!plugin_list.isSelectionEmpty()) {
957 Object object = plugin_list.getSelectedValue();
958 if(object instanceof PlugIn) {
959 PlugIn plugin = (PlugIn) object;
960 if(event.getSource() == move_top) {
961 movePlugIn(plugin, true, true);
962 }
963 else if(event.getSource() == move_up) {
964 movePlugIn(plugin, true, false);
965 }
966 else if(event.getSource() == move_down) {
967 movePlugIn(plugin, false, false);
968 }
969 else {
970 movePlugIn(plugin, false, true);
971 }
972 plugin_list.setSelectedValue(plugin, true);
973 }
974 }
975 }
976 }
977 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugIn()</i> method.
978 */
979 private class RemoveListener
980 implements ActionListener {
981 /** 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.
982 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
983 */
984 public void actionPerformed(ActionEvent event) {
985 if(!plugin_list.isSelectionEmpty()) {
986 Object [] objects = plugin_list.getSelectedValues();
987 for(int i = 0; i < objects.length; i++) {
988 if(objects[i] instanceof PlugIn) {
989 removePlugIn((PlugIn)objects[i]);
990 }
991 }
992 //Object object = plugin_list.getSelectedValue();
993 //if(object instanceof PlugIn) {
994 //removePlugIn((PlugIn)object);
995 //}
996 }
997 }
998 }
999 }
1000 /** Creates a list separator.
1001 * Code courtesy of Farwell, Paul. Contact <a href="mailto:[email protected]">[email protected]</a>
1002 */
1003 static private JPanel getSeparator() {
1004 // we put the separator inside a panel to control
1005 // its appearance
1006 JPanel _sepPanel = new JPanel();
1007 _sepPanel.setOpaque(false);
1008 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1009 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1010 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1011 _sepPanel.add(new JPopupMenu.Separator());
1012 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1013 return _sepPanel;
1014 }
1015}
1016
1017
1018
1019
Note: See TracBrowser for help on using the repository browser.