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

Last change on this file since 12071 was 12071, checked in by kjdon, 18 years ago

fixed a typo

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