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

Last change on this file since 4638 was 4638, checked in by kjdon, 21 years ago

the remove and configure plugin/classifier buttons are now disabled if there is no selection in the list. also teh two lists have been made singly selectable - no more multiple selections

  • Property svn:keywords set to Author Date Id Revision
File size: 36.9 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;
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.setEnabled(false);
672 configure.setMnemonic(KeyEvent.VK_C);
673 header_pane = new JPanel();
674 instructions = new JTextArea(get("Instructions"));
675 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
676 instructions.setEditable(false);
677 instructions.setLineWrap(true);
678 instructions.setRows(5);
679 instructions.setWrapStyleWord(true);
680 move_bottom = new JButton();
681 JLabel move_bottom_label = new JLabel(get("Move_Bottom"));
682 move_bottom_label.setHorizontalAlignment(JLabel.CENTER);
683 move_bottom_label.setPreferredSize(LABEL_SIZE);
684 move_bottom.setLayout(new BorderLayout());
685 move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.WEST);
686 move_bottom.add(move_bottom_label, BorderLayout.CENTER);
687 move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.EAST);
688 move_bottom.setMnemonic(KeyEvent.VK_B);
689 move_down = new JButton();
690 JLabel move_down_label = new JLabel(get("Move_Down"));
691 move_down_label.setHorizontalAlignment(JLabel.CENTER);
692 move_down_label.setPreferredSize(LABEL_SIZE);
693 move_down.setLayout(new BorderLayout());
694 move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.WEST);
695 move_down.add(move_down_label, BorderLayout.CENTER);
696 move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.EAST);
697 move_down.setMnemonic(KeyEvent.VK_D);
698 move_top = new JButton();
699 JLabel move_top_label = new JLabel(get("Move_Top"));
700 move_top_label.setHorizontalAlignment(JLabel.CENTER);
701 move_top_label.setPreferredSize(LABEL_SIZE);
702 move_top.setLayout(new BorderLayout());
703 move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.WEST);
704 move_top.add(move_top_label, BorderLayout.CENTER);
705 move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.EAST);
706 move_top.setMnemonic(KeyEvent.VK_T);
707 move_up = new JButton();
708 JLabel move_up_label = new JLabel(get("Move_Up"));
709 move_up_label.setHorizontalAlignment(JLabel.CENTER);
710 move_up_label.setPreferredSize(LABEL_SIZE);
711 move_up.setLayout(new BorderLayout());
712 move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.WEST);
713 move_up.add(move_up_label, BorderLayout.CENTER);
714 move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.EAST);
715 move_up.setMnemonic(KeyEvent.VK_U);
716 movement_pane = new JPanel();
717 plugin = new JComboBox(available);
718 //plugin.setEditable(true);
719 plugin.setSelectedIndex(0);
720 plugin_label = new JLabel(get("PlugIn"));
721 plugin_list = new JList(assigned);
722 plugin_list.setCellRenderer(new ListRenderer());
723 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
724 plugin_list_label = new JLabel(get("Assigned"));
725 plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
726 plugin_list_label.setOpaque(true);
727 plugin_list_pane = new JPanel();
728 plugin_pane = new JPanel();
729 remove = new JButton(get("Remove"));
730 remove.setEnabled(false);
731 remove.setMnemonic(KeyEvent.VK_R);
732 title = new JLabel(get("Title"));
733 title.setHorizontalAlignment(JLabel.CENTER);
734 title.setOpaque(true);
735 // Listeners
736 add.addActionListener(new AddListener());
737 configure.addActionListener(new ConfigureListener());
738 MoveListener ml = new MoveListener();
739 move_bottom.addActionListener(ml);
740 move_down.addActionListener(ml);
741 move_top.addActionListener(ml);
742 move_up.addActionListener(ml);
743 remove.addActionListener(new RemoveListener());
744 plugin_list.addMouseListener(new ClickListener());
745 plugin_list.addListSelectionListener(new ListListener());
746 // Layout
747 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
748
749 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
750
751 header_pane.setLayout(new BorderLayout());
752 header_pane.add(title, BorderLayout.NORTH);
753 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
754
755 plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
756
757 movement_pane.setLayout(new GridLayout(4,1));
758 movement_pane.add(move_top);
759 movement_pane.add(move_up);
760 movement_pane.add(move_down);
761 movement_pane.add(move_bottom);
762
763 plugin_list_pane.setLayout(new BorderLayout());
764 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
765 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
766 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
767
768 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
769
770 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
771 plugin_pane.setLayout(new GridLayout(1,2));
772 plugin_pane.add(plugin_label);
773 plugin_pane.add(plugin);
774
775 // Scope these mad bordering skillz.
776 JPanel temp = new JPanel(new BorderLayout());
777 temp.setBorder
778 (BorderFactory.createCompoundBorder
779 (BorderFactory.createEmptyBorder(5,0,5,0),
780 BorderFactory.createCompoundBorder
781 (BorderFactory.createTitledBorder(get("Controls")),
782 BorderFactory.createEmptyBorder(2,2,2,2))));
783
784 temp.add(plugin_pane, BorderLayout.NORTH);
785 temp.add(button_pane, BorderLayout.SOUTH);
786
787 central_pane.setLayout(new BorderLayout());
788 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
789 central_pane.add(temp, BorderLayout.SOUTH);
790
791 button_pane.setLayout(new GridLayout(3,1));
792 button_pane.add(add);
793 button_pane.add(configure);
794 button_pane.add(remove);
795
796 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
797 setLayout(new BorderLayout());
798 add(header_pane, BorderLayout.NORTH);
799 add(central_pane, BorderLayout.CENTER);
800 //add(button_pane, BorderLayout.SOUTH);
801 }
802 /** Method which acts like a destructor, tidying up references to persistant objects.
803 */
804 public void destroy() {
805 }
806 /** 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.
807 * @return <i>true</i> if this control has focus, <i>false</i> otherwise.
808 */
809 public boolean hasFocus() {
810 return super.hasFocus();
811 }
812 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
813 */
814 public void updateUI() {
815 if(instructions != null) {
816 instructions.setCaretPosition(0);
817 }
818 super.updateUI();
819 }
820 /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugIn()</i> method.
821 */
822 private class AddListener
823 implements ActionListener {
824 /** 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.
825 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
826 */
827 public void actionPerformed(ActionEvent event) {
828 PlugIn new_plugin = null;
829 Object object = plugin.getSelectedItem();
830 if(object instanceof PlugIn) {
831 PlugIn target = (PlugIn)object;
832 new_plugin = target.copy();
833 }
834 else {
835 new_plugin = new PlugIn(object.toString(), "", null);
836 }
837 object = null;
838 // Automatically chain to configuration. This ensures required arguments are filled out.
839 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, new_plugin);
840 if(ac.display()) {
841 assignPlugIn(new_plugin);
842 plugin_list.setSelectedValue(new_plugin, true);
843 }
844 ac = null;
845 new_plugin = null;
846 plugin.setSelectedIndex(0);
847 }
848 }
849 /** 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.
850 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
851 */
852 private class ConfigureListener
853 implements ActionListener {
854 /** 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.
855 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
856 */
857 public void actionPerformed(ActionEvent event) {
858 if(!plugin_list.isSelectionEmpty()) {
859 Object object = plugin_list.getSelectedValue();
860 if(object instanceof PlugIn) {
861 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
862 if(ac.display()) {
863 assigned.refresh();
864 }
865 }
866 }
867 }
868 }
869 /** A special list renderer which is able to render separating lines as well. */
870 private class ListRenderer
871 extends DefaultListCellRenderer {
872 /** 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.
873 * @param list - The <strong>JList</strong> we're painting.
874 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
875 * @param index - The cells index as an <i>int</i>.
876 * @param isSelected - <i>true</i> if the specified cell was selected.
877 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
878 * @return A <strong>Component</strong> whose paint() method will render the specified value.
879 * @see javax.swing.JList
880 * @see javax.swing.JSeparator
881 * @see javax.swing.ListModel
882 * @see javax.swing.ListSelectionModel
883 */
884 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
885 if(value instanceof JPanel) {
886 return (JPanel) value;
887 }
888 else {
889 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
890 }
891 }
892 }
893 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
894 private class ClickListener
895 extends MouseAdapter {
896 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
897 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
898 */
899 public void mouseClicked(MouseEvent event) {
900 if(event.getClickCount() == 2 ) {
901 if(!plugin_list.isSelectionEmpty()) {
902 Object object = plugin_list.getSelectedValue();
903 if(object instanceof PlugIn) {
904 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
905 if(ac.display()) {
906 assigned.refresh();
907 }
908 }
909 }
910 }
911 }
912 }
913
914 /** 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 */
915 private class ListListener
916 implements ListSelectionListener {
917
918 public void valueChanged(ListSelectionEvent e) {
919 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
920 if (plugin_list.isSelectionEmpty()) {
921 configure.setEnabled(false);
922 remove.setEnabled(false);
923 } else {
924 configure.setEnabled(true);
925 remove.setEnabled(true);
926 }
927 }
928 }
929 }
930
931 /** 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. */
932 private class MoveListener
933 implements ActionListener {
934 /** 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.
935 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
936 */
937 public void actionPerformed(ActionEvent event) {
938 if(!plugin_list.isSelectionEmpty()) {
939 Object object = plugin_list.getSelectedValue();
940 if(object instanceof PlugIn) {
941 PlugIn plugin = (PlugIn) object;
942 if(event.getSource() == move_top) {
943 movePlugIn(plugin, true, true);
944 }
945 else if(event.getSource() == move_up) {
946 movePlugIn(plugin, true, false);
947 }
948 else if(event.getSource() == move_down) {
949 movePlugIn(plugin, false, false);
950 }
951 else {
952 movePlugIn(plugin, false, true);
953 }
954 plugin_list.setSelectedValue(plugin, true);
955 }
956 }
957 }
958 }
959 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugIn()</i> method.
960 */
961 private class RemoveListener
962 implements ActionListener {
963 /** 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.
964 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
965 */
966 public void actionPerformed(ActionEvent event) {
967 if(!plugin_list.isSelectionEmpty()) {
968 Object [] objects = plugin_list.getSelectedValues();
969 for(int i = 0; i < objects.length; i++) {
970 if(objects[i] instanceof PlugIn) {
971 removePlugIn((PlugIn)objects[i]);
972 }
973 }
974 //Object object = plugin_list.getSelectedValue();
975 //if(object instanceof PlugIn) {
976 //removePlugIn((PlugIn)object);
977 //}
978 }
979 }
980 }
981 }
982 /** Creates a list separator.
983 * Code courtesy of Farwell, Paul. Contact <a href="mailto:[email protected]">[email protected]</a>
984 */
985 static private JPanel getSeparator() {
986 // we put the separator inside a panel to control
987 // its appearance
988 JPanel _sepPanel = new JPanel();
989 _sepPanel.setOpaque(false);
990 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
991 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
992 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
993 _sepPanel.add(new JPopupMenu.Separator());
994 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
995 return _sepPanel;
996 }
997}
998
999
1000
1001
Note: See TracBrowser for help on using the repository browser.