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

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

2030124: Argument parsing now doesn't begin until the '<?xml' is detected, so as to avoid poorly formed XML errors because of PERL messages. PlugIn argument harvesting could fail silently or give less than useful error messages. Now it displays a handy message dialog. How handy.

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