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

Last change on this file since 11378 was 11378, checked in by mdewsnip, 18 years ago

Now looks at a plugin's block_exp as well as its process_exp to determine if it will "process" a file.

  • 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 pluging 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 = Utility.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 // A super plugin class.
651 else if(node_name.equalsIgnoreCase("PlugInfo")) {
652 Plugin super_plugin = parseXML(arg);
653 plugin.setSuper(super_plugin);
654 }
655 }
656 }
657 }
658 if(plugin.getName() != null) {
659 addPlugin(plugin);
660 return plugin;
661 }
662 return null;
663 }
664
665 /** A class which provodes controls for assigned and editing plugins. */
666 private class PluginControl
667 extends JPanel
668 implements Control {
669 /** Button for adding plugins. */
670 private JButton add = null;
671 /** Button for configuring the selected plugin. */
672 private JButton configure = null;
673 /** Button to move an assigned plugin one position lower in the order. */
674 private JButton move_down_button = null;
675 /** Button to move an assigned plugin one position higher in the order. */
676 private JButton move_up_button = null;
677 /** Button to remove the selected plugin. */
678 private JButton remove = null;
679 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
680 private GComboBox plugin = null;
681 /** The label next to the plugin combobox. */
682 private JLabel plugin_label = null;
683 /** The label above the assigned plugin list. */
684 private JLabel plugin_list_label = null;
685 /** A list of assigned plugins. */
686 private JList plugin_list = null;
687 /** The area where the add, configure and remove buttons are placed. */
688 private JPanel button_pane = null;
689 /** The region which divides the central portion of the view into list and controls */
690 private JPanel central_pane = null;
691 /** The area where movement buttons are placed. */
692 private JPanel movement_pane = null;
693 /** The small region containing the plugin combobox and its label. */
694 private JPanel plugin_pane = null;
695 /** The pane containing the assigned plugin list and its label. */
696 private JPanel plugin_list_pane = null;
697
698 /** Constructor.
699 */
700 public PluginControl() {
701 // Create
702 add = new GLIButton();
703 add.setMnemonic(KeyEvent.VK_A);
704 Dictionary.registerBoth(add, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
705
706 button_pane = new JPanel();
707 central_pane = new JPanel();
708
709 configure = new GLIButton();
710 configure.setEnabled(false);
711 configure.setMnemonic(KeyEvent.VK_C);
712 Dictionary.registerBoth(configure, "CDM.PlugInManager.Configure", "CDM.PlugInManager.Configure_Tooltip");
713
714 JPanel header_pane = new DesignPaneHeader("CDM.GUI.Plugins", "plugins");
715 move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
716 move_up_button.setEnabled(false);
717 move_up_button.setMnemonic(KeyEvent.VK_U);
718 Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
719
720 move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
721 move_down_button.setEnabled(false);
722 move_down_button.setMnemonic(KeyEvent.VK_D);
723 Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
724
725 movement_pane = new JPanel();
726
727 PluginComboboxListener picl = new PluginComboboxListener();
728 plugin = new GComboBox(getAvailable());
729 plugin.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
730 plugin.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
731 plugin.setEditable(true);
732 plugin.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
733 plugin.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
734 picl.itemStateChanged(new ItemEvent(plugin, 0, null, ItemEvent.SELECTED));
735
736 plugin_label = new JLabel();
737 Dictionary.registerText(plugin_label, "CDM.PlugInManager.PlugIn");
738
739 plugin_list = new JList(model);
740 plugin_list.setCellRenderer(new ListRenderer());
741 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
742 plugin_list_label = new JLabel();
743 //plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
744 plugin_list_label.setOpaque(true);
745 Dictionary.registerText(plugin_list_label, "CDM.PlugInManager.Assigned");
746
747 plugin_list_pane = new JPanel();
748 plugin_pane = new JPanel();
749
750 remove = new GLIButton();
751 remove.setEnabled(false);
752 remove.setMnemonic(KeyEvent.VK_R);
753 Dictionary.registerBoth(remove, "CDM.PlugInManager.Remove", "CDM.PlugInManager.Remove_Tooltip");
754
755 // Listeners
756 add.addActionListener(new AddListener()); //all_change_listener is listening to the ArgumentConfiguration
757 configure.addActionListener(new ConfigureListener());
758 MoveListener ml = new MoveListener();
759 move_down_button.addActionListener(ml);
760 move_down_button.addActionListener(CollectionDesignManager.all_change_listener);
761 move_up_button.addActionListener(ml);
762 move_up_button.addActionListener(CollectionDesignManager.all_change_listener);
763 plugin.addItemListener(picl);
764 remove.addActionListener(new RemoveListener());
765 remove.addActionListener(CollectionDesignManager.all_change_listener);
766 plugin_list.addMouseListener(new ClickListener());
767 plugin_list.addListSelectionListener(new ListListener());
768 picl = null;
769
770 // Layout
771 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
772 movement_pane.setLayout(new GridLayout(4,1));
773 movement_pane.add(move_up_button);
774 movement_pane.add(new JPanel());
775 movement_pane.add(new JPanel());
776 movement_pane.add(move_down_button);
777
778 plugin_list_pane.setLayout(new BorderLayout());
779 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
780 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
781 modeChanged(Configuration.getMode()); // Whether the movement buttons are visible is mode dependant
782
783 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
784
785 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
786 plugin_pane.setLayout(new BorderLayout(5,0));
787 plugin_pane.add(plugin_label, BorderLayout.WEST);
788 plugin_pane.add(plugin, BorderLayout.CENTER);
789
790 button_pane.setLayout(new GridLayout(1,3));
791 button_pane.add(add);
792 button_pane.add(configure);
793 button_pane.add(remove);
794
795 // Scope these mad bordering skillz.
796 JPanel temp = new JPanel(new BorderLayout());
797 temp.add(plugin_pane, BorderLayout.NORTH);
798 temp.add(button_pane, BorderLayout.SOUTH);
799
800 central_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
801 central_pane.setLayout(new BorderLayout());
802 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
803 central_pane.add(temp, BorderLayout.SOUTH);
804
805 setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
806 setLayout(new BorderLayout());
807 add(header_pane, BorderLayout.NORTH);
808 add(central_pane, BorderLayout.CENTER);
809 }
810
811 /** Method which acts like a destructor, tidying up references to persistant objects.
812 */
813 public void destroy() {
814 }
815
816 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
817 no longer have instructions, do we still need updateUI???
818 */
819 public void gainFocus() {
820 super.updateUI();
821 }
822
823 public void loseFocus() {
824 }
825
826 /** 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
827 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
828 */
829 public void modeChanged(int mode) {
830 // 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
831 plugin_list.clearSelection();
832 // The first change is dependant on whether the user is systems mode or higher
833 if(mode >= Configuration.SYSTEMS_MODE) {
834 // Show movement buttons
835 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
836 // Do we show Arc and RecPlugs or hide them and the separator line
837 setHideLines(!(mode >= Configuration.EXPERT_MODE));
838 }
839 // Otherwise hide the movement buttons and fixed plugins
840 else {
841 plugin_list_pane.remove(movement_pane);
842 setHideLines(true);
843 }
844 plugin_list_pane.updateUI();
845 }
846
847 /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugin()</i> method. */
848 private class AddListener
849 implements ActionListener {
850 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
851 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
852 */
853 public void actionPerformed(ActionEvent event) {
854 Object selected_object = plugin.getSelectedItem();
855 if(selected_object != null) {
856 // Retrieve the base plugin if any
857 Plugin base_plugin = getBasePlugin(selected_object.toString());
858
859 // Create a new element in the DOM
860 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
861 // Remember that the plugin supplied might be a custom string rather than a base plugin
862 Plugin new_plugin = null;
863 if(base_plugin != null) {
864 //DebugStream.println("New Plugin based on existing Plugin");
865 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
866 new_plugin = new Plugin(element, base_plugin);
867 }
868 else {
869 //DebugStream.println("New Custom Plugin");
870 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
871 new_plugin = new Plugin(element, null);
872 }
873 if(!model.contains(new_plugin) || new_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
874 // Automatically chain to configuration. This ensures required arguments are filled out.
875 ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
876 if(ac.display()) {
877 assignPlugin(new_plugin);
878 plugin_list.setSelectedValue(new_plugin, true);
879 // 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
880 if(base_plugin != null && !base_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
881 plugin.removeItem(base_plugin);
882 }
883 }
884 ac = null;
885 new_plugin = null;
886 plugin.setSelectedIndex(0);
887 }
888 else {
889 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
890 }
891 base_plugin = null;
892 }
893 }
894 }
895
896 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
897 private class ClickListener
898 extends MouseAdapter {
899 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
900 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
901 */
902 public void mouseClicked(MouseEvent event) {
903 if(event.getClickCount() == 2 ) {
904 if(!plugin_list.isSelectionEmpty()) {
905 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
906 if(!plugin.isSeparator()) {
907 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
908 if(ac.display()) {
909 refresh(plugin);
910 }
911 ac.destroy();
912 ac = null;
913 // 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
914 Gatherer.c_man.configurationChanged();
915 }
916 }
917 }
918 }
919 }
920
921 /** 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.
922 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
923 */
924 private class ConfigureListener
925 implements ActionListener {
926 /** 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.
927 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
928 */
929 public void actionPerformed(ActionEvent event) {
930 if(!plugin_list.isSelectionEmpty()) {
931 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
932 if(!plugin.isSeparator()) {
933 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
934 if(ac.display()) {
935 refresh(plugin);
936 }
937 ac.destroy();
938 ac = null;
939 // 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
940 Gatherer.c_man.configurationChanged();
941 }
942 }
943 }
944 }
945
946 /** 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 */
947 private class ListListener
948 implements ListSelectionListener {
949
950 public void valueChanged(ListSelectionEvent e) {
951 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one (the second one)
952 if (plugin_list.isSelectionEmpty()) {
953 move_up_button.setEnabled(false);
954 move_down_button.setEnabled(false);
955 configure.setEnabled(false);
956 remove.setEnabled(false);
957 }
958 else {
959 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
960 if(selected_plugin.isSeparator()) {
961 move_up_button.setEnabled(false);
962 move_down_button.setEnabled(false);
963 configure.setEnabled(false);
964 remove.setEnabled(false);
965 }
966 else {
967 configure.setEnabled(true);
968 String plugin_name = selected_plugin.getName();
969 // Some buttons are only available for plugins other than ArcPlug and RecPlug
970 if(plugin_name.equals(StaticStrings.ARCPLUG_STR) || plugin_name.equals(StaticStrings.RECPLUG_STR) ) {
971 move_up_button.setEnabled(false);
972 move_down_button.setEnabled(false);
973 remove.setEnabled(false);
974 }
975 else {
976 // don't let people remove special plugins such GAPlug an METSPlug,
977 // unless they are in systems mode or above
978 int mode = Configuration.getMode();
979 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
980 if ((plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
981 (mode < Configuration.SYSTEMS_MODE)) {
982 remove.setEnabled(false);
983 break;
984 } else {
985 remove.setEnabled(true);
986 }
987 }
988
989 // Move ups are only enabled if the selected plugin isn't already at the top
990 Plugin first_plugin = (Plugin) getElementAt(0);
991 if(!first_plugin.equals(selected_plugin)) {
992 move_up_button.setEnabled(true);
993 }
994 else {
995 move_up_button.setEnabled(false);
996 }
997 // And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
998 int separator_index = findSeparatorIndex();
999 int selected_index = plugin_list.getSelectedIndex();
1000 if(selected_index < separator_index - 1) {
1001 move_down_button.setEnabled(true);
1002 }
1003 else {
1004 move_down_button.setEnabled(false);
1005 }
1006 }
1007 selected_plugin = null;
1008 plugin_name = null;
1009 }
1010 }
1011 }
1012 }
1013 }
1014
1015 /** A special list renderer which is able to render separating lines as well. */
1016 private class ListRenderer
1017 extends DefaultListCellRenderer {
1018 /** 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.
1019 * @param list - The <strong>JList</strong> we're painting.
1020 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
1021 * @param index - The cells index as an <i>int</i>.
1022 * @param isSelected - <i>true</i> if the specified cell was selected.
1023 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
1024 * @return A <strong>Component</strong> whose paint() method will render the specified value.
1025 * @see javax.swing.JList
1026 * @see javax.swing.JSeparator
1027 * @see javax.swing.ListModel
1028 * @see javax.swing.ListSelectionModel
1029 */
1030 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
1031 Plugin plugin = (Plugin) value;
1032 if(plugin.isSeparator()) {
1033 return separator;
1034 }
1035 else {
1036 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1037 }
1038 }
1039 }
1040
1041
1042 /** 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. */
1043 private class MoveListener
1044 implements ActionListener {
1045 /** 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.
1046 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1047 */
1048 public void actionPerformed(ActionEvent event) {
1049 if (!plugin_list.isSelectionEmpty()) {
1050 Object object = plugin_list.getSelectedValue();
1051 if (object instanceof Plugin) {
1052 Plugin plugin = (Plugin) object;
1053 if (event.getSource() == move_up_button) {
1054 movePlugin(plugin, true, false);
1055 }
1056 else if (event.getSource() == move_down_button) {
1057 movePlugin(plugin, false, false);
1058 }
1059 plugin_list.setSelectedValue(plugin, true);
1060 }
1061 }
1062 }
1063 }
1064
1065 /** This listener reacts to changes in the current selection of the plugin combobox. */
1066 private class PluginComboboxListener
1067 implements ItemListener {
1068 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
1069 public void itemStateChanged(ItemEvent event) {
1070 if(event.getStateChange() == ItemEvent.SELECTED) {
1071 // Retrieve the selected plugin
1072 Object current_selection = plugin.getSelectedItem();
1073 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
1074 if(current_selection == null || current_selection instanceof String) {
1075 Dictionary.registerTooltip(plugin, "CDM.PlugInManager.PlugIn_Tooltip");
1076 }
1077 else {
1078 Plugin current_plugin = (Plugin) current_selection;
1079 Dictionary.registerTooltipText(plugin, Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
1080 current_plugin = null;
1081 }
1082 current_selection = null;
1083 }
1084 }
1085 }
1086
1087 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
1088 */
1089 private class RemoveListener
1090 implements ActionListener {
1091 /** 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.
1092 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1093 */
1094 public void actionPerformed(ActionEvent event) {
1095 int selected_index = plugin_list.getSelectedIndex();
1096 if(selected_index != -1) {
1097 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
1098 removePlugin(selected_plugin);
1099 selected_plugin = null;
1100 // Select the next plugin if available
1101 if(selected_index < plugin_list.getModel().getSize()) {
1102 // If the new selection is above the separator we can remove it
1103 if(selected_index < findSeparatorIndex()) {
1104 plugin_list.setSelectedIndex(selected_index);
1105
1106 // don't let people remove special plugins such GAPlug an METSPlug,
1107 // unless they are in systems mode or above
1108 int mode = Configuration.getMode();
1109 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
1110 String selected_plugin_name
1111 = ((Plugin)plugin_list.getSelectedValue()).getName();
1112 if ((selected_plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
1113 (mode < Configuration.SYSTEMS_MODE)) {
1114 remove.setEnabled(false);
1115 break;
1116 } else {
1117 remove.setEnabled(true);
1118 }
1119 }
1120 }
1121 // Otherwise select the first non-removable plugin
1122 else {
1123 plugin_list.setSelectedIndex(selected_index + 1);
1124 remove.setEnabled(false);
1125 }
1126 }
1127 else {
1128 remove.setEnabled(false);
1129 }
1130 // Refresh the available plugins
1131 plugin.setModel(new DefaultComboBoxModel(getAvailable()));
1132 }
1133 else {
1134 remove.setEnabled(false);
1135 }
1136 }
1137 }
1138 }
1139
1140
1141 private class PluginSuggestionPrompt
1142 extends ModalDialog
1143 implements ActionListener
1144 {
1145 private Dimension size = new Dimension(480, 240);
1146 private GComboBox suitable_plugins_combobox = null;
1147 private GLIButton add_button = null;
1148 private GLIButton ignore_button = null;
1149
1150 public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
1151 {
1152 super(Gatherer.g_man, true);
1153 setModal(true);
1154 setSize(size);
1155 Dictionary.setText(this, "CDM.PluginManager.SuggestedPluginListTitle");
1156
1157 String[] args = new String[1];
1158 args[0] = filename;
1159
1160 JTextArea instructions_textarea = new JTextArea();
1161 instructions_textarea.setCaretPosition(0);
1162 instructions_textarea.setEditable(false);
1163 instructions_textarea.setLineWrap(true);
1164 instructions_textarea.setRows(5);
1165 instructions_textarea.setWrapStyleWord(true);
1166 Dictionary.setText(instructions_textarea, "CDM.PluginManager.Plugin_Suggestion_Prompt", args);
1167
1168 JLabel suitable_plugins_label = new JLabel();
1169 Dictionary.registerText(suitable_plugins_label, "CDM.PlugInManager.PlugIn");
1170 suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
1171
1172 suitable_plugins_combobox = new GComboBox(suitable_plugins);
1173 suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
1174 suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
1175 suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
1176 suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
1177
1178 JPanel suitable_plugins_pane = new JPanel();
1179 //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
1180 suitable_plugins_pane.setLayout(new BorderLayout(5,0));
1181 suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.WEST);
1182 suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
1183
1184 add_button = new GLIButton();
1185 Dictionary.setBoth(add_button, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
1186 ignore_button = new GLIButton();
1187 Dictionary.setBoth(ignore_button, "CDM.PlugInManager.Ignore","CDM.PlugInManager.Ignore_Tooltip" );
1188
1189 add_button.addActionListener(this);
1190 ignore_button.addActionListener(this);
1191
1192 JPanel button_pane = new JPanel();
1193 button_pane.setLayout(new GridLayout(1,2,5,0));
1194 button_pane.add(add_button);
1195 button_pane.add(ignore_button);
1196
1197 JPanel controls_pane = new JPanel();
1198 controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
1199 controls_pane.setLayout(new GridLayout(2,1,0,5));
1200 controls_pane.add(suitable_plugins_pane);
1201 controls_pane.add(button_pane);
1202
1203 JPanel content_pane = (JPanel) getContentPane();
1204 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
1205 content_pane.setLayout(new BorderLayout());
1206 content_pane.add(instructions_textarea, BorderLayout.CENTER);
1207 content_pane.add(controls_pane, BorderLayout.SOUTH);
1208
1209 // Show
1210 Dimension screen_size = Configuration.screen_size;
1211 setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
1212 setVisible(true);
1213 }
1214
1215 public void actionPerformed(ActionEvent event) {
1216
1217 if(event.getSource() == add_button) {
1218 // add the selected plugin to the list
1219 Object selected_object = suitable_plugins_combobox.getSelectedItem();
1220 Plugin base_plugin = getBasePlugin(selected_object.toString());
1221
1222 // Create a new element in the DOM
1223 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
1224 // Remember that the plugin supplied might be a custom string rather than a base plugin
1225 Plugin new_plugin = null;
1226 if(base_plugin != null) {
1227 //DebugStream.println("New Plugin based on existing Plugin");
1228 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
1229 new_plugin = new Plugin(element, base_plugin);
1230 }
1231 else {
1232 //DebugStream.println("New Custom Plugin");
1233 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
1234 new_plugin = new Plugin(element, null);
1235 }
1236 assignPlugin(new_plugin);
1237 } // else do nothing
1238
1239 // close the dialog
1240 setVisible(false);
1241 }
1242
1243 }
1244
1245
1246 /** Creates a list separator.
1247 * Found on Google Groups. Code courtesy of Paul Farwell.
1248 */
1249 private JPanel getSeparator() {
1250 // We put the separator inside a panel to control its appearance
1251 JPanel _sepPanel = new JPanel();
1252 _sepPanel.setOpaque(false);
1253 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1254 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1255 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1256 // 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
1257 _sepPanel.add(new BasicSeparator());
1258 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1259 return _sepPanel;
1260 }
1261
1262 /** 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. */
1263 private class BasicSeparator
1264 extends JSeparator {
1265
1266 private ComponentUI basic_ui;
1267
1268 public BasicSeparator() {
1269 super();
1270 basic_ui = new BasicSeparatorUI();
1271 }
1272
1273 public void paintComponent(Graphics g) {
1274 if (basic_ui != null) {
1275 basic_ui.update(g, this);
1276 }
1277 }
1278 }
1279}
Note: See TracBrowser for help on using the repository browser.