source: trunk/gli/src/org/greenstone/gatherer/cdm/PluginManager.java@ 9126

Last change on this file since 9126 was 9126, checked in by kjdon, 19 years ago

moved the argument details xml parsing code to Argument.parseXML - the same code was duplicated in BuildOptions, PluginManager, ClassifierManager

  • Property svn:keywords set to Author Date Id Revision
File size: 49.8 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 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.net.*;
33import java.util.*;
34import javax.swing.*;
35import javax.swing.event.*;
36import javax.swing.plaf.*;
37import javax.swing.plaf.basic.*;
38import org.apache.xerces.parsers.*;
39import org.greenstone.gatherer.Configuration;
40import org.greenstone.gatherer.DebugStream;
41import org.greenstone.gatherer.Dictionary;
42import org.greenstone.gatherer.Gatherer;
43import org.greenstone.gatherer.collection.CollectionContentsChangedListener;
44import org.greenstone.gatherer.gui.GComboBox;
45import org.greenstone.gatherer.gui.GLIButton;
46import org.greenstone.gatherer.gui.ModalDialog;
47import org.greenstone.gatherer.gui.WarningDialog;
48import org.greenstone.gatherer.util.StaticStrings;
49import org.greenstone.gatherer.util.Utility;
50import org.greenstone.gatherer.util.XMLTools;
51import org.w3c.dom.*;
52import org.xml.sax.*;
53
54/** This class is for maintaining a list of known plug-ins, and importing new plugins using the parser. */
55public class PluginManager
56 extends DOMProxyListModel
57 implements CollectionContentsChangedListener
58{
59 /** The library 'reserve' of base plugins. */
60 private ArrayList library = null;
61 /** When asking how many rows are in the model, and if this variables value is true, then this modifier alters the number returned. This funtionality is used to hide the last three rows of the list in low detail modes. */
62 private boolean modify_row_count = false;
63 /** The controls for editing the contents of this manager. */
64 private Control controls = null;
65 private DOMProxyListModel model;
66 private JPanel separator;
67 private Plugin separator_plugin;
68 /** Constructor.
69 */
70 public PluginManager() {
71 super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.PLUGIN_ELEMENT, new Plugin());
72 DebugStream.println("PluginManager: " + super.getSize() + " plugins parsed.");
73 model = this;
74 // Reload/Create the library
75 loadPlugins(); // adds all the plugins to the library
76 savePlugins();
77 // Create the separator, cause we can reuse it.
78 separator = getSeparator();
79
80 // Listen for CollectionContentsChanged events, so we can give plugin hints when new files are added
81 Gatherer.c_man.addCollectionContentsChangedListener(this);
82 }
83
84 /** Method to add a new plugin to the library
85 * @param plugin the new base Plugin
86 */
87 private void addPlugin(Plugin plugin) {
88 if(!library.contains(plugin)) {
89 library.add(plugin);
90 }
91 }
92
93 /** Method to assign a plugin
94 * @param plugin the Plugin to assign
95 */
96 private void assignPlugin(Plugin plugin) {
97 if(plugin.getName().equals(StaticStrings.RECPLUG_STR) || plugin.getName().equals(StaticStrings.ARCPLUG_STR)) {
98 addAfter(plugin, separator_plugin); // Adds after separator
99 } else {
100 addBefore(plugin, separator_plugin);
101 }
102 Gatherer.c_man.configurationChanged();
103 }
104
105 public static boolean clearPluginCache() {
106
107 DebugStream.println("deleting plugins.dat");
108 File plugin_file = new File(Utility.getGLIUserFolder(), "plugins.dat");
109 if (plugin_file.exists()) {
110 return Utility.delete(plugin_file);
111 }
112 return true;
113 }
114
115
116 /** Destructor. */
117 public void destroy()
118 {
119 Gatherer.c_man.removeCollectionContentsChangedListener(this);
120
121 if (controls != null) {
122 controls.destroy();
123 controls = null;
124 }
125
126 library.clear();
127 library = null;
128 }
129
130
131 /** This function listens for new files being added to the collection and hints about suitable plugins. */
132 public void fileAddedToCollection(File file)
133 {
134 // First check the plugins already assigned in the collection
135 for (int i = 0; i < super.getSize(); i++) {
136 Plugin assigned_plugin = (Plugin) getElementAt(i);
137 if (assigned_plugin.isSeparator() == false && assigned_plugin.doesProcessFile(file) == true) {
138 // This file will be processed by an assigned plugin, so no suggestion is necessary
139 System.err.println("Processed by assigned plugin: " + assigned_plugin);
140 // System.err.println("Explodes metadata databases: " + assigned_plugin.doesExplodeMetadataDatabases());
141 return;
142 }
143 }
144
145 // Next try the plugins NOT already assigned in the collection
146 ArrayList suitable_plugins = new ArrayList();
147 Object[] unassigned_plugins = getAvailable();
148 for (int i = 0; i < unassigned_plugins.length; i++) {
149 Plugin unassigned_plugin = (Plugin) unassigned_plugins[i];
150 if (unassigned_plugin.doesProcessFile(file) == true) {
151 System.err.println("Processed by unassigned plugin: " + unassigned_plugin);
152 suitable_plugins.add(unassigned_plugin);
153 }
154 }
155
156 // If there appear to be no suitable plugins, warn the user about this and be done
157 if (suitable_plugins.size() == 0) {
158 String[] args = new String[1];
159 args[0] = file.getName();
160 WarningDialog warning_dialog = new WarningDialog("warning.NoPluginExpectedToProcessFile", args, null, false);
161 warning_dialog.display();
162 warning_dialog.dispose();
163 return;
164 }
165
166 // Generate a dialog
167 new PluginSuggestionPrompt(file.getName(), suitable_plugins);
168 }
169
170
171 public boolean isFileExplodable(File file)
172 {
173
174 for (int i = 0; i < library.size(); i++) {
175 Plugin plugin = (Plugin) library.get(i);
176 if (plugin.doesProcessFile(file) == true && plugin.doesExplodeMetadataDatabases() == true) {
177 return true;
178 }
179 }
180
181 return false;
182 }
183
184 public Plugin getExploderPlugin(File file)
185 {
186 for (int i = 0; i < library.size(); i++) {
187 Plugin plugin = (Plugin) library.get(i);
188 if (plugin.doesProcessFile(file) == true && plugin.doesExplodeMetadataDatabases() == true) {
189 return plugin;
190 }
191 }
192 return null;
193
194 }
195
196 /** Method to retrieve the control for this manager.
197 * @return the Control
198 */
199 public Control getControls() {
200 if(controls == null) {
201 // Build controls
202 controls = new PluginControl();
203 }
204 return controls;
205 }
206
207 /** Retrieve the base pluging of the given name, or null if no such plugin.
208 * @param name the name of the base plugin to retrieve as a String
209 * @return the Plugin requested or null if no such plugin
210 */
211 public Plugin getBasePlugin(String name) {
212 int library_size = library.size();
213 for(int i = 0; i < library_size; i++) {
214 Plugin plugin = (Plugin) library.get(i);
215 if(plugin.getName().equals(name)) {
216 return plugin;
217 }
218 }
219 // No success.
220 return null;
221 }
222
223 /** Overrides getSize in DOMProxyListModel to take into account the row count modifier used to hide the last three rows in lower detail modes
224 * @return an int indicating the number of rows in the model, or more correctly the desired number of rows to display
225 */
226 public int getSize() {
227 int result = super.getSize();
228 if(modify_row_count) {
229 result = result-3;
230 }
231 return result;
232 }
233
234 /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
235 * @param mode the new mode as an int
236 */
237 public void modeChanged(int mode) {
238 if(controls != null) {
239 ((PluginControl)controls).modeChanged(mode);
240 }
241 }
242
243 /** Method to move a plugin in the list order.
244 * @param plugin the Plugin you want to move.
245 * @param direction true to move the plugin up, false to move it down.
246 * @param all true to move to move all the way, false for a single step.
247 */
248 // why are all the error notices there when the buttons are disabled is you cant move???
249 private void movePlugin(Plugin plugin, boolean direction, boolean all) {
250 // Can't ever move RecPlug or ArcPlug
251 if(super.getSize() < 4) {
252 //DebugStream.println("Not enough plugins to allow moving.");
253 return;
254 }
255 if(plugin.getName().equals(StaticStrings.ARCPLUG_STR) || plugin.getName().equals(StaticStrings.RECPLUG_STR)) {
256 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.Fixed"), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
257 return;
258 }
259 if(all) {
260 // Move to top
261 if(direction) {
262 // Remove the moving plugin
263 remove(plugin);
264 // Retrieve the first plugin
265 Plugin first_plugin = (Plugin) getElementAt(0);
266 // Add the moving plugin before the first plugin
267 addBefore(plugin, first_plugin);
268 first_plugin = null;
269 Gatherer.c_man.configurationChanged();
270 }
271 else {
272 // Remove the moving plugin
273 remove(plugin);
274 // Add the moving plugin before the separator
275 addBefore(plugin, separator_plugin);
276 Gatherer.c_man.configurationChanged();
277 }
278 }
279 else {
280 // Try to move the plugin one step in the desired direction.
281 int index = indexOf(plugin);
282 ///ystem.err.println("Index of " + plugin + " = " + index);
283 if(direction) {
284 index--;
285 if(index < 0) {
286 String args[] = new String[2];
287 args[0] = Dictionary.get("CDM.PlugInManager.PlugIn_Str");
288 args[1] = plugin.getName();
289 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Top", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
290 return;
291 }
292 remove(plugin);
293 add(index, plugin);
294 Gatherer.c_man.configurationChanged();
295 }
296 else {
297 index++;
298 Plugin next_plugin = (Plugin) getElementAt(index);
299 if(next_plugin.isSeparator()) {
300 String args[] = new String[1];
301 args[0] = plugin.getName();
302 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.Cannot", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
303 // Still not going to move RecPlug or ArcPlug.
304 return;
305 }
306 remove(plugin);
307 add(index, plugin);
308 Gatherer.c_man.configurationChanged();
309 }
310 }
311 }
312
313 /** We attempt to place the separator between the unfixed and the fixed plugins. Since we only know of two fixed plugins, we search for either of them, and place the separator before them.
314 */
315 public void placeSeparator() {
316 ///ystem.err.println("Placing separator.");
317 int separator_index = super.getSize();
318 if(separator_index > 0) {
319 boolean found_fixed = false;
320 int index = separator_index - 1;
321 while(index > 0) {
322 Plugin plugin = (Plugin) getElementAt(index);
323 String name = plugin.getName();
324 if(name.equals(StaticStrings.RECPLUG_STR) || name.equals(StaticStrings.ARCPLUG_STR)) {
325 found_fixed = true;
326 index--;
327 }
328 else {
329 if(found_fixed) {
330 separator_index = index + 1;
331 index = -1;
332 }
333 else {
334 index--;
335 }
336 }
337 name = null;
338 plugin = null;
339 }
340 }
341 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
342 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, CollectionConfiguration.SEPARATOR_ATTRIBUTE);
343 element.setAttribute(CollectionConfiguration.SEPARATOR_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
344 separator_plugin = new Plugin(element, null);
345 ///atherer.println("Adding plugin separator at: " + separator_index);
346 add(separator_index, separator_plugin);
347 }
348
349 /** This method removes an assigned plugin. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a plugin from the library.
350 * @param plugin The <strong>Plugin</strong> to remove.
351 */
352 private void removePlugin(Plugin plugin) {
353 remove(plugin);
354 Gatherer.c_man.configurationChanged();
355 }
356
357 /** Method to cache the current contents of library (known plugins) to file.
358 */
359 private void savePlugins() {
360 try {
361 File plugins_dat_file = new File(Utility.getGLIUserFolder(), "plugins.dat");
362 FileOutputStream file = new FileOutputStream(plugins_dat_file);
363 ObjectOutputStream out = new ObjectOutputStream(file);
364 out.writeObject(library);
365 out.close();
366 }
367 catch (Exception error) {
368 DebugStream.printStackTrace(error);
369 }
370 }
371
372 /** Inform the model to hide/show the last three lines on the list.
373 * @param modify_row_count true to hide the last three lines, false otherwise
374 */
375 private void setHideLines(boolean modify_row_count) {
376 this.modify_row_count = modify_row_count;
377 int original_size = super.getSize();
378 if(modify_row_count) {
379 fireIntervalRemoved(this, original_size - 4, original_size - 1);
380 }
381 else {
382 fireIntervalAdded(this, original_size - 4, original_size - 1);
383 }
384 }
385
386 /** Determine the current separator index. */
387 private int findSeparatorIndex() {
388 int separator_index = super.getSize() - 1;
389 while(separator_index >= 0) {
390 Plugin search = (Plugin) getElementAt(separator_index);
391 if(search.isSeparator()) {
392 return separator_index;
393 }
394 separator_index--;
395 }
396 return separator_index;
397 }
398
399
400 /** Retrieve a list of those plugins that are in library but not in the assigned plugins. */
401 private Object[] getAvailable() {
402 ArrayList available = new ArrayList();
403 int library_size = library.size();
404 for(int i = 0; i < library_size; i++) {
405 Plugin plugin = (Plugin) library.get(i);
406 if(!plugin.isAbstract()) {
407 available.add(plugin);
408 }
409 plugin = null;
410 }
411 // Now go through the assigned plugins, and remove any that match.
412 available.removeAll(children());
413 //DebugStream.println("There are a total of " + library.size() + " plugins in the library.");
414 //DebugStream.println("However " + children().size() + " are in use,");
415 //DebugStream.println("So only " + available.size() + " remain.");
416 Collections.sort(available);
417 return available.toArray();
418 }
419
420 /** Method to extract just the plugins name from a file object.
421 * @param plugin The <strong>File</strong> which references a certain plugin.
422 * @return A <strong>String</strong> containing just the plugins name, without extension.
423 */
424 private String getPluginName(String filename) {
425 String name = filename;
426 if(name.indexOf(".") != -1) {
427 name = name.substring(0, name.indexOf("."));
428 }
429 return name;
430 }
431
432
433 /** Method to load the details of a single plug-in.
434 * @param plugin The plugin <strong>File</strong> you wish to load.
435 */
436 private void loadPlugin(String plugin, String lang) {
437 Document document = null;
438 InputStream input_stream = null;
439
440 // Run pluginfo on this plugin, and then send the results for parsing.
441 try {
442 if (Gatherer.isGsdlRemote) {
443 String launch = Gatherer.cgiBase + "launch";
444 launch += "?cmd=pluginfo.pl";
445 launch += "&xml=&language="+lang;
446 launch += "&plug=" + getPluginName(plugin);
447
448 System.err.println("*** launch = " + launch);
449
450 URL launch_url = new URL(launch);
451 URLConnection launch_connection = launch_url.openConnection();
452 input_stream = launch_connection.getInputStream();
453 }
454 else {
455 String args[] = null;
456 if(Utility.isWindows()) {
457 args = new String[6];
458 if(Configuration.perl_path != null) {
459 args[0] = Configuration.perl_path;
460 }
461 else {
462 args[0] = "Perl.exe";
463 }
464 args[1] = Configuration.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl";
465 args[2] = "-xml";
466 args[3] = "-language";
467 args[4] = lang;
468 args[5] = getPluginName(plugin);
469 }
470 else {
471 args = new String[5];
472 args[0] = "pluginfo.pl";
473 args[1] = "-xml";
474 args[2] = "-language";
475 args[3] = lang;
476 args[4] = getPluginName(plugin);
477 }
478
479 // Create the process.
480 Runtime runtime = Runtime.getRuntime();
481 Process process = runtime.exec(args);
482 input_stream = process.getErrorStream();
483 }
484
485 StringBuffer xml = Utility.readXMLStream(input_stream);
486 document = CollectionDesignManager.XMLStringToDOM(xml,plugin);
487 }
488 catch (Exception error) {
489 System.err.println("Failed when trying to parse: " + plugin);
490 error.printStackTrace();
491 }
492 if(document != null) {
493 parseXML(document.getDocumentElement());
494 }
495 }
496
497 /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
498 */
499 private void loadPlugins() {
500 // Attempt to restore the cached file.
501 File plugins_dat_file = new File(Utility.getGLIUserFolder(), "plugins.dat");
502 try {
503 FileInputStream file = new FileInputStream(plugins_dat_file);
504 ObjectInputStream input = new ObjectInputStream(file);
505 library = (ArrayList) input.readObject();
506 }
507 catch (Exception error) {
508 DebugStream.println("Unable to open " + plugins_dat_file);
509 }
510
511 if(library == null) {
512 library = new ArrayList();
513 if (Gatherer.isGsdlRemote) {
514
515 String lang = Configuration.getLanguage();
516
517 String launch = Gatherer.cgiBase + "launch";
518 launch += "?cmd=pluginfo.pl";
519 launch += "&xml=&language="+lang;
520 launch += "&listall=";
521
522 System.err.println("*** launch = " + launch);
523
524 try {
525 URL launch_url = new URL(launch);
526 URLConnection launch_connection = launch_url.openConnection();
527 InputStream input_stream = launch_connection.getInputStream();
528 loadPlugins(input_stream);
529 }
530 catch (Exception error) {
531 System.err.println("Failed when trying to connect to : " + launch);
532 error.printStackTrace();
533 }
534
535 }
536 else {
537 // Retrieve the gsdl home directory...
538 String directory = Configuration.gsdl_path;
539 directory = directory + "perllib" + File.separator + "plugins" + File.separator;
540 loadPlugins(new File(directory));
541 }
542 }
543 }
544
545
546
547
548 /** Method to load plug-in information from a specified input stream (could be local or through URL). Of course no plug-ins may be found at this location.
549 * @param input_stream An <strong>InputStream</strong> indicating the where list of plugins -- encoded in XML -- can be read from
550 */
551 private void loadPlugins(InputStream input_stream)
552 {
553 StringBuffer xml = Utility.readXMLStream(input_stream);
554 Document document = CollectionDesignManager.XMLStringToDOM(xml, "-listall");
555
556 // Parse XML to build up list of plugin names
557 Node root = document.getDocumentElement();
558
559 NamedNodeMap attributes = root.getAttributes();
560 Node length_node = attributes.getNamedItem("length");
561 String num_plugins_str = length_node.getNodeValue();
562 int num_plugins = Integer.parseInt(num_plugins_str);
563 String plugin_list[] = new String[num_plugins];
564
565 Node node = root.getFirstChild();
566 int i = 0;
567 while (node != null) {
568 String node_name = node.getNodeName();
569 if (node_name.equalsIgnoreCase("PluginName")) {
570 String name = XMLTools.getValue(node);
571 plugin_list[i] = name;
572 i++;
573 }
574
575 node = node.getNextSibling();
576 }
577
578
579 boolean is_windows = Utility.isWindows();
580 boolean is_mac = Utility.isMac();
581
582 String current_lang = Configuration.getLanguage();
583 if (num_plugins>0) {
584 // Create a progress indicator.
585 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), num_plugins);
586
587 for (i=0; i<num_plugins; i++) {
588 String plugin = plugin_list[i];
589 if (plugin.equals("GMLPlug.pm") || ((is_windows || is_mac) && plugin.equals("DBPlug.pm"))) {
590 // don't load GMLPlug or DBPlug for windows
591 } else {
592 loadPlugin(plugin, current_lang);
593 }
594
595 progress.inc();
596 }
597 progress.dispose();
598 progress.destroy();
599 progress = null;
600 }
601 }
602
603
604 /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
605 * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
606 */
607 private void loadPlugins(File directory) {
608 File files[] = directory.listFiles();
609 boolean is_windows = Utility.isWindows();
610 boolean is_mac = Utility.isMac();
611 String current_lang = Configuration.getLanguage();
612 if(files != null) {
613 // Create a progress indicator.
614 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), files.length);
615 for(int i = 0; i < files.length; i++) {
616 // We only want to check Perl Modules.
617 if(files[i].getName().endsWith(".pm")) {
618 if (files[i].getName().equals("GMLPlug.pm") || ((is_windows || is_mac) && files[i].getName().equals("DBPlug.pm"))) {
619 // don't load GMLPlug or DBPlug for windows
620 } else {
621 loadPlugin(files[i].getName(), current_lang);
622 }
623 }
624 progress.inc();
625 }
626 progress.dispose();
627 progress.destroy();
628 progress = null;
629 }
630 }
631
632 private Plugin parseXML(Node root) {
633 Plugin plugin = new Plugin();
634 String node_name = null;
635 for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
636 node_name = node.getNodeName();
637 if(node_name.equalsIgnoreCase("Name")) {
638 String name = XMLTools.getValue(node);
639 // 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.
640 Plugin existing = getBasePlugin(name);
641 if(existing != null) {
642 return existing;
643 }
644 plugin.setName(name);
645 }
646 else if (node_name.equalsIgnoreCase("Desc")) {
647 plugin.setDescription(XMLTools.getValue(node));
648 }
649 else if (node_name.equalsIgnoreCase("Abstract")) {
650 plugin.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
651 }
652 else if (node_name.equalsIgnoreCase("Explodes")) {
653 plugin.setDoesExplodeMetadataDatabases(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
654 //System.err.println("Plugin " + plugin.getName() + " explodes metadata databases: " + plugin.doesExplodeMetadataDatabases());
655 }
656 // Parse the multitude of arguments
657 else if(node_name.equalsIgnoreCase("Arguments")) {
658 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
659 node_name = arg.getNodeName();
660 // An option.
661 if(node_name.equalsIgnoreCase("Option")) {
662 Argument argument = new Argument();
663 argument.parseXML((Element)arg);
664 plugin.addArgument(argument);
665 }
666 // A super plugin class.
667 else if(node_name.equalsIgnoreCase("PlugInfo")) {
668 Plugin super_plugin = parseXML(arg);
669 plugin.setSuper(super_plugin);
670 }
671 }
672 }
673 }
674 if(plugin.getName() != null) {
675 addPlugin(plugin);
676 return plugin;
677 }
678 return null;
679 }
680
681 /** A class which provodes controls for assigned and editing plugins. */
682 private class PluginControl
683 extends JPanel
684 implements Control {
685 /** Button for adding plugins. */
686 private JButton add = null;
687 /** Button for configuring the selected plugin. */
688 private JButton configure = null;
689 /** Buttom to move an assinged plugin as low in the order as possible. */
690 //private JButton move_bottom_button = null;
691 /** Button to move an assigned plugin one position lower in the order. */
692 private JButton move_down_button = null;
693 /** Button to move an assigned plugin as high in the order as possible. */
694 //private JButton move_top_button = null;
695 /** Button to move an assigned plugin one position higher in the order. */
696 private JButton move_up_button = null;
697 /** Button to remove the selected plugin. */
698 private JButton remove = null;
699 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
700 private GComboBox plugin = null;
701 /** The label next to the plugin combobox. */
702 private JLabel plugin_label = null;
703 /** The label above the assigned plugin list. */
704 private JLabel plugin_list_label = null;
705 /** The title of this view. */
706 private JLabel title = null;
707 /** A list of assigned plugins. */
708 private JList plugin_list = null;
709 /** The area where the add, configure and remove buttons are placed. */
710 private JPanel button_pane = null;
711 /** The region which divides the central portion of the view into list and controls */
712 private JPanel central_pane = null;
713 /** The area where title label and instructions sit. */
714 private JPanel header_pane = null;
715 /** The area where movement buttons are placed. */
716 private JPanel movement_pane = null;
717 /** The small region containing the plugin combobox and its label. */
718 private JPanel plugin_pane = null;
719 /** The pane containing the assigned plugin list and its label. */
720 private JPanel plugin_list_pane = null;
721 /** The text area containing instructions on the use of this control. */
722 private JTextArea instructions = null;
723
724 /** Constructor.
725 */
726 public PluginControl() {
727 // Create
728 add = new GLIButton();
729 add.setMnemonic(KeyEvent.VK_A);
730 Dictionary.registerBoth(add, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
731
732 button_pane = new JPanel();
733 central_pane = new JPanel();
734
735 configure = new GLIButton();
736 configure.setEnabled(false);
737 configure.setMnemonic(KeyEvent.VK_C);
738 Dictionary.registerBoth(configure, "CDM.PlugInManager.Configure", "CDM.PlugInManager.Configure_Tooltip");
739
740 header_pane = new JPanel();
741
742 instructions = new JTextArea();
743 instructions.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
744 instructions.setEditable(false);
745 instructions.setLineWrap(true);
746 instructions.setRows(6);
747 instructions.setWrapStyleWord(true);
748 Dictionary.registerText(instructions, "CDM.PlugInManager.Instructions");
749
750 move_up_button = new JButton("", Utility.getImage("arrow-up.gif"));
751 move_up_button.setEnabled(false);
752 move_up_button.setMnemonic(KeyEvent.VK_U);
753 //move_up_button.setPreferredSize(Utility.DOUBLE_IMAGE_BUTTON_SIZE);
754 Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
755
756 move_down_button = new JButton("", Utility.getImage("arrow-down.gif"));
757 move_down_button.setEnabled(false);
758 move_down_button.setMnemonic(KeyEvent.VK_D);
759 //move_down_button.setPreferredSize(Utility.DOUBLE_IMAGE_BUTTON_SIZE);
760 Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
761
762 movement_pane = new JPanel();
763
764 PluginComboboxListener picl = new PluginComboboxListener();
765 plugin = new GComboBox(getAvailable());
766 plugin.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
767 plugin.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
768 plugin.setEditable(true);
769 plugin.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
770 plugin.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
771 picl.itemStateChanged(new ItemEvent(plugin, 0, null, ItemEvent.SELECTED));
772
773 plugin_label = new JLabel();
774 Dictionary.registerText(plugin_label, "CDM.PlugInManager.PlugIn");
775
776 plugin_list = new JList(model);
777 plugin_list.setCellRenderer(new ListRenderer());
778 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
779 plugin_list_label = new JLabel();
780 plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
781 plugin_list_label.setOpaque(true);
782 Dictionary.registerText(plugin_list_label, "CDM.PlugInManager.Assigned");
783
784 plugin_list_pane = new JPanel();
785 plugin_pane = new JPanel();
786
787 remove = new GLIButton();
788 remove.setEnabled(false);
789 remove.setMnemonic(KeyEvent.VK_R);
790 Dictionary.registerBoth(remove, "CDM.PlugInManager.Remove", "CDM.PlugInManager.Remove_Tooltip");
791
792 title = new JLabel();
793 title.setHorizontalAlignment(JLabel.CENTER);
794 title.setOpaque(true);
795 Dictionary.registerText(title, "CDM.PlugInManager.Title");
796
797 // Listeners
798 add.addActionListener(new AddListener());
799 configure.addActionListener(new ConfigureListener());
800 MoveListener ml = new MoveListener();
801 //move_bottom_button.addActionListener(ml);
802 move_down_button.addActionListener(ml);
803 //move_top_button.addActionListener(ml);
804 move_up_button.addActionListener(ml);
805 plugin.addItemListener(picl);
806 remove.addActionListener(new RemoveListener());
807 plugin_list.addMouseListener(new ClickListener());
808 plugin_list.addListSelectionListener(new ListListener());
809 picl = null;
810
811 // Layout
812 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
813
814 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
815
816 header_pane.setLayout(new BorderLayout());
817 header_pane.add(title, BorderLayout.NORTH);
818 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
819
820 plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
821
822 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
823 movement_pane.setLayout(new GridLayout(4,1));
824 movement_pane.add(move_up_button);
825 movement_pane.add(new JPanel());
826 movement_pane.add(new JPanel());
827 movement_pane.add(move_down_button);
828
829 plugin_list_pane.setLayout(new BorderLayout());
830 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
831 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
832 modeChanged(Configuration.getMode()); // Whether the movement buttons are visible is mode dependant
833
834 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
835
836 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
837 plugin_pane.setLayout(new BorderLayout(5,0));
838 plugin_pane.add(plugin_label, BorderLayout.WEST);
839 plugin_pane.add(plugin, BorderLayout.CENTER);
840
841 button_pane.setLayout(new GridLayout(1,3));
842 button_pane.add(add);
843 button_pane.add(configure);
844 button_pane.add(remove);
845
846 // Scope these mad bordering skillz.
847 // !! TO DO: Dictionary registration !!
848 JPanel temp = new JPanel(new BorderLayout());
849 temp.setBorder
850 (BorderFactory.createCompoundBorder
851 (BorderFactory.createEmptyBorder(5,0,5,0),
852 BorderFactory.createCompoundBorder
853 (BorderFactory.createTitledBorder(Dictionary.get("CDM.PlugInManager.Controls")),
854 BorderFactory.createEmptyBorder(2,2,2,2))));
855
856 temp.add(plugin_pane, BorderLayout.NORTH);
857 temp.add(button_pane, BorderLayout.SOUTH);
858
859 central_pane.setLayout(new BorderLayout());
860 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
861 central_pane.add(temp, BorderLayout.SOUTH);
862
863 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
864 setLayout(new BorderLayout());
865 add(header_pane, BorderLayout.NORTH);
866 add(central_pane, BorderLayout.CENTER);
867 }
868
869 /** Method which acts like a destructor, tidying up references to persistant objects.
870 */
871 public void destroy() {
872 }
873
874 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
875 */
876 public void gainFocus() {
877 if(instructions != null) {
878 instructions.setCaretPosition(0);
879 }
880 super.updateUI();
881 }
882
883 public void loseFocus() {
884 }
885
886 /** The current detail mode controls two aspects of plugin manager: whether the movement buttons are visible and whether the fixed position plugins Arc and RecPlug are in the list
887 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
888 */
889 public void modeChanged(int mode) {
890 // First of all we clear the current selection, as there can be some serious problems if the user selects the plugins we're hiding, or had the last plugin selected before we unhid the last three
891 plugin_list.clearSelection();
892 // The first change is dependant on whether the user is systems mode or higher
893 if(mode >= Configuration.SYSTEMS_MODE) {
894 // Show movement buttons
895 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
896 // Do we show Arc and RecPlugs or hide them and the separator line
897 setHideLines(!(mode >= Configuration.EXPERT_MODE));
898 }
899 // Otherwise hide the movement buttons and fixed plugins
900 else {
901 plugin_list_pane.remove(movement_pane);
902 setHideLines(true);
903 }
904 plugin_list_pane.updateUI();
905 }
906
907 /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugin()</i> method. */
908 private class AddListener
909 implements ActionListener {
910 /** 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.
911 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
912 */
913 public void actionPerformed(ActionEvent event) {
914 Object selected_object = plugin.getSelectedItem();
915 if(selected_object != null) {
916 // Retrieve the base plugin if any
917 Plugin base_plugin = getBasePlugin(selected_object.toString());
918
919 // Create a new element in the DOM
920 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
921 // Remember that the plugin supplied might be a custom string rather than a base plugin
922 Plugin new_plugin = null;
923 if(base_plugin != null) {
924 //DebugStream.println("New Plugin based on existing Plugin");
925 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
926 new_plugin = new Plugin(element, base_plugin);
927 }
928 else {
929 //DebugStream.println("New Custom Plugin");
930 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
931 new_plugin = new Plugin(element, null);
932 }
933 if(!model.contains(new_plugin) || new_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
934 // Automatically chain to configuration. This ensures required arguments are filled out.
935 ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
936 if(ac.display()) {
937 assignPlugin(new_plugin);
938 plugin_list.setSelectedValue(new_plugin, true);
939 // Since we weren't cancelled, and if there was a base plugin, ensure it no longer is shown as available, unless it is the UnknownPlugin which can be added several times
940 if(base_plugin != null && !base_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
941 plugin.removeItem(base_plugin);
942 }
943 }
944 ac = null;
945 new_plugin = null;
946 plugin.setSelectedIndex(0);
947 }
948 else {
949 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
950 }
951 base_plugin = null;
952 }
953 }
954 }
955
956 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
957 private class ClickListener
958 extends MouseAdapter {
959 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
960 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
961 */
962 public void mouseClicked(MouseEvent event) {
963 if(event.getClickCount() == 2 ) {
964 if(!plugin_list.isSelectionEmpty()) {
965 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
966 if(!plugin.isSeparator()) {
967 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
968 if(ac.display()) {
969 refresh(plugin);
970 }
971 ac.destroy();
972 ac = null;
973 }
974 }
975 }
976 }
977 }
978
979 /** 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.
980 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
981 */
982 private class ConfigureListener
983 implements ActionListener {
984 /** 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.
985 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
986 */
987 public void actionPerformed(ActionEvent event) {
988 if(!plugin_list.isSelectionEmpty()) {
989 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
990 if(!plugin.isSeparator()) {
991 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
992 if(ac.display()) {
993 refresh(plugin);
994 }
995 ac.destroy();
996 ac = null;
997 }
998 }
999 }
1000 }
1001
1002 /** 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 */
1003 private class ListListener
1004 implements ListSelectionListener {
1005
1006 public void valueChanged(ListSelectionEvent e) {
1007 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one (the second one)
1008 if (plugin_list.isSelectionEmpty()) {
1009 //move_top_button.setEnabled(false);
1010 move_up_button.setEnabled(false);
1011 move_down_button.setEnabled(false);
1012 //move_bottom_button.setEnabled(false);
1013 configure.setEnabled(false);
1014 remove.setEnabled(false);
1015 }
1016 else {
1017 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
1018 if(selected_plugin.isSeparator()) {
1019 //move_top_button.setEnabled(false);
1020 move_up_button.setEnabled(false);
1021 move_down_button.setEnabled(false);
1022 //move_bottom_button.setEnabled(false);
1023 configure.setEnabled(false);
1024 remove.setEnabled(false);
1025 }
1026 else {
1027 configure.setEnabled(true);
1028 String plugin_name = selected_plugin.getName();
1029 // Some buttons are only available for plugins other than ArcPlug and RecPlug
1030 if(plugin_name.equals(StaticStrings.ARCPLUG_STR) || plugin_name.equals(StaticStrings.RECPLUG_STR) ) {
1031 //move_top_button.setEnabled(false);
1032 move_up_button.setEnabled(false);
1033 move_down_button.setEnabled(false);
1034 //move_bottom_button.setEnabled(false);
1035 remove.setEnabled(false);
1036 }
1037 else {
1038 // don't let people remove GAPlug
1039 if (plugin_name.equals(StaticStrings.GAPLUG_STR)) {
1040 remove.setEnabled(false);
1041 } else {
1042 remove.setEnabled(true);
1043 }
1044
1045 // Move ups are only enabled if the selected plugin isn't already at the top
1046 Plugin first_plugin = (Plugin) getElementAt(0);
1047 if(!first_plugin.equals(selected_plugin)) {
1048 //move_top_button.setEnabled(true);
1049 move_up_button.setEnabled(true);
1050 }
1051 else {
1052 //move_top_button.setEnabled(false);
1053 move_up_button.setEnabled(false);
1054 }
1055 // And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
1056 int separator_index = findSeparatorIndex();
1057 int selected_index = plugin_list.getSelectedIndex();
1058 if(selected_index < separator_index - 1) {
1059 move_down_button.setEnabled(true);
1060 //move_bottom_button.setEnabled(true);
1061 }
1062 else {
1063 move_down_button.setEnabled(false);
1064 //move_bottom_button.setEnabled(false);
1065 }
1066 }
1067 selected_plugin = null;
1068 plugin_name = null;
1069 }
1070 }
1071 }
1072 }
1073 }
1074
1075 /** A special list renderer which is able to render separating lines as well. */
1076 private class ListRenderer
1077 extends DefaultListCellRenderer {
1078 /** 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.
1079 * @param list - The <strong>JList</strong> we're painting.
1080 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
1081 * @param index - The cells index as an <i>int</i>.
1082 * @param isSelected - <i>true</i> if the specified cell was selected.
1083 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
1084 * @return A <strong>Component</strong> whose paint() method will render the specified value.
1085 * @see javax.swing.JList
1086 * @see javax.swing.JSeparator
1087 * @see javax.swing.ListModel
1088 * @see javax.swing.ListSelectionModel
1089 */
1090 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
1091 Plugin plugin = (Plugin) value;
1092 if(plugin.isSeparator()) {
1093 return separator;
1094 }
1095 else {
1096 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1097 }
1098 }
1099 }
1100
1101
1102 /** 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. */
1103 private class MoveListener
1104 implements ActionListener {
1105 /** 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.
1106 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1107 */
1108 public void actionPerformed(ActionEvent event) {
1109 if (!plugin_list.isSelectionEmpty()) {
1110 Object object = plugin_list.getSelectedValue();
1111 if (object instanceof Plugin) {
1112 Plugin plugin = (Plugin) object;
1113 //if (event.getSource() == move_top_button) {
1114 // movePlugin(plugin, true, true);
1115 //}
1116 //else
1117 if (event.getSource() == move_up_button) {
1118 movePlugin(plugin, true, false);
1119 }
1120 else if (event.getSource() == move_down_button) {
1121 movePlugin(plugin, false, false);
1122 }
1123 //else if (event.getSource() == move_bottom_button) {
1124 // movePlugin(plugin, false, true);
1125 //}
1126 plugin_list.setSelectedValue(plugin, true);
1127 }
1128 }
1129 }
1130 }
1131
1132 /** This listener reacts to changes in the current selection of the plugin combobox. */
1133 private class PluginComboboxListener
1134 implements ItemListener {
1135 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
1136 public void itemStateChanged(ItemEvent event) {
1137 if(event.getStateChange() == ItemEvent.SELECTED) {
1138 // Retrieve the selected plugin
1139 Object current_selection = plugin.getSelectedItem();
1140 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
1141 if(current_selection == null || current_selection instanceof String) {
1142 Dictionary.registerTooltip(plugin, "CDM.PlugInManager.PlugIn_Tooltip");
1143 }
1144 else {
1145 Plugin current_plugin = (Plugin) current_selection;
1146 Dictionary.registerTooltipText(plugin, Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
1147 current_plugin = null;
1148 }
1149 current_selection = null;
1150 }
1151 }
1152 }
1153
1154 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
1155 */
1156 private class RemoveListener
1157 implements ActionListener {
1158 /** 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.
1159 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1160 */
1161 public void actionPerformed(ActionEvent event) {
1162 int selected_index = plugin_list.getSelectedIndex();
1163 if(selected_index != -1) {
1164 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
1165 removePlugin(selected_plugin);
1166 selected_plugin = null;
1167 // Select the next plugin if available
1168 if(selected_index < plugin_list.getModel().getSize()) {
1169 // If the new selection is above the separator we can remove it
1170 if(selected_index < findSeparatorIndex()) {
1171 plugin_list.setSelectedIndex(selected_index);
1172 // don't allow removal of GAPlug
1173 if (((Plugin)plugin_list.getSelectedValue()).getName().equals(StaticStrings.GAPLUG_STR)) {
1174 remove.setEnabled(false);
1175 } else {
1176 remove.setEnabled(true);
1177 }
1178 }
1179 // Otherwise select the first non-removable plugin
1180 else {
1181 plugin_list.setSelectedIndex(selected_index + 1);
1182 remove.setEnabled(false);
1183 }
1184 }
1185 else {
1186 remove.setEnabled(false);
1187 }
1188 // Refresh the available plugins
1189 plugin.setModel(new DefaultComboBoxModel(getAvailable()));
1190 }
1191 else {
1192 remove.setEnabled(false);
1193 }
1194 }
1195 }
1196 }
1197
1198
1199 private class PluginSuggestionPrompt
1200 extends ModalDialog
1201 implements ActionListener
1202 {
1203 private Dimension size = new Dimension(400, 200);
1204 private GComboBox suitable_plugins_combobox = null;
1205 private GLIButton add_button = null;
1206 private GLIButton ignore_button = null;
1207
1208 public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
1209 {
1210 super(Gatherer.g_man, true);
1211 setModal(true);
1212 setSize(size);
1213 Dictionary.setText(this, "CDM.PluginManager.SuggestedPluginListTitle");
1214
1215 String[] args = new String[1];
1216 args[0] = filename;
1217
1218 JTextArea instructions_textarea = new JTextArea();
1219 instructions_textarea.setCaretPosition(0);
1220 instructions_textarea.setEditable(false);
1221 instructions_textarea.setLineWrap(true);
1222 instructions_textarea.setRows(5);
1223 instructions_textarea.setWrapStyleWord(true);
1224 Dictionary.setText(instructions_textarea, "CDM.PluginManager.Plugin_Suggestion_Prompt", args);
1225
1226 JLabel suitable_plugins_label = new JLabel();
1227 Dictionary.registerText(suitable_plugins_label, "CDM.PlugInManager.PlugIn");
1228 suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
1229
1230 suitable_plugins_combobox = new GComboBox(suitable_plugins);
1231 suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
1232 suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
1233 suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
1234 suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
1235
1236 JPanel suitable_plugins_pane = new JPanel();
1237 //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
1238 suitable_plugins_pane.setLayout(new BorderLayout(5,0));
1239 suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.WEST);
1240 suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
1241
1242 add_button = new GLIButton();
1243 Dictionary.setBoth(add_button, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
1244 ignore_button = new GLIButton();
1245 Dictionary.setBoth(ignore_button, "CDM.PlugInManager.Ignore","CDM.PlugInManager.Ignore_Tooltip" );
1246
1247 add_button.addActionListener(this);
1248 ignore_button.addActionListener(this);
1249
1250 JPanel button_pane = new JPanel();
1251 button_pane.setLayout(new GridLayout(1,2,5,0));
1252 button_pane.add(add_button);
1253 button_pane.add(ignore_button);
1254
1255 JPanel controls_pane = new JPanel();
1256 controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
1257 controls_pane.setLayout(new GridLayout(2,1,0,5));
1258 controls_pane.add(suitable_plugins_pane);
1259 controls_pane.add(button_pane);
1260
1261 JPanel content_pane = (JPanel) getContentPane();
1262 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
1263 content_pane.setLayout(new BorderLayout());
1264 content_pane.add(instructions_textarea, BorderLayout.CENTER);
1265 content_pane.add(controls_pane, BorderLayout.SOUTH);
1266
1267 // Show
1268 Dimension screen_size = Configuration.screen_size;
1269 setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
1270 setVisible(true);
1271 }
1272
1273 public void actionPerformed(ActionEvent event) {
1274
1275 if(event.getSource() == add_button) {
1276 // add the selected plugin to the list
1277 Object selected_object = suitable_plugins_combobox.getSelectedItem();
1278 Plugin base_plugin = getBasePlugin(selected_object.toString());
1279
1280 // Create a new element in the DOM
1281 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
1282 // Remember that the plugin supplied might be a custom string rather than a base plugin
1283 Plugin new_plugin = null;
1284 if(base_plugin != null) {
1285 //DebugStream.println("New Plugin based on existing Plugin");
1286 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
1287 new_plugin = new Plugin(element, base_plugin);
1288 }
1289 else {
1290 //DebugStream.println("New Custom Plugin");
1291 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
1292 new_plugin = new Plugin(element, null);
1293 }
1294 assignPlugin(new_plugin);
1295 } // else do nothing
1296
1297 // close the dialog
1298 setVisible(false);
1299 }
1300
1301 }
1302
1303
1304 /** Creates a list separator.
1305 * Found on Google Groups. Code courtesy of Paul Farwell.
1306 */
1307 private JPanel getSeparator() {
1308 // We put the separator inside a panel to control its appearance
1309 JPanel _sepPanel = new JPanel();
1310 _sepPanel.setOpaque(false);
1311 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1312 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1313 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1314 // We have to be a little careful here, as the default UI for separators under MacOS is a blank box. Instead we force a BasicUI look
1315 _sepPanel.add(new BasicSeparator());
1316 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1317 return _sepPanel;
1318 }
1319
1320 /** This class behaves just like a normal JSeparator except that, no matter what the current settings in the UIManager are, it always paints itself with BasicSeparatorUI. */
1321 private class BasicSeparator
1322 extends JSeparator {
1323
1324 private ComponentUI basic_ui;
1325
1326 public BasicSeparator() {
1327 super();
1328 basic_ui = new BasicSeparatorUI();
1329 }
1330
1331 public void paintComponent(Graphics g) {
1332 if (basic_ui != null) {
1333 basic_ui.update(g, this);
1334 }
1335 }
1336 }
1337}
Note: See TracBrowser for help on using the repository browser.