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

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

Initial revision

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