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

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

Changed text handling to use Dictionary.get rather than Dictionary.setText or Dictionary.registerBoth etc. also removed mnemonics cos they suck for other languages.

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