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

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

made BasicSeparator a static class, removed some custom plugin code

  • Property svn:keywords set to Author Date Id Revision
File size: 47.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 ArrayList getExploderPlugins(File file)
189 {
190 ArrayList exp_plugins = new ArrayList();
191 for (int i = 0; i < library.size(); i++) {
192 Plugin plugin = (Plugin) library.get(i);
193 if (plugin.doesProcessFile(file) == true && plugin.doesExplodeMetadataDatabases() == true) {
194 exp_plugins.add(plugin);
195 }
196 }
197 return exp_plugins;
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 String plugin_name = plugin.getName();
411 if(!plugin.isAbstract() && !plugin_name.equals(StaticStrings.ARCPLUG_STR) && !plugin_name.equals(StaticStrings.RECPLUG_STR)) {
412 available.add(plugin);
413 }
414 plugin = null;
415 }
416 // Now go through the assigned plugins, and remove any that match.
417 // only for < lib sys specialist mode
418 if (Configuration.getMode()<=Configuration.SYSTEMS_MODE) {
419 available.removeAll(children());
420 }
421 //DebugStream.println("There are a total of " + library.size() + " plugins in the library.");
422 //DebugStream.println("However " + children().size() + " are in use,");
423 //DebugStream.println("So only " + available.size() + " remain.");
424 Collections.sort(available);
425 return available.toArray();
426 }
427
428 /** Method to extract just the plugins name from a file object.
429 * @param plugin The <strong>File</strong> which references a certain plugin.
430 * @return A <strong>String</strong> containing just the plugins name, without extension.
431 */
432 private String getPluginName(String filename) {
433 String name = filename;
434 if(name.indexOf(".") != -1) {
435 name = name.substring(0, name.indexOf("."));
436 }
437 return name;
438 }
439
440
441 /** Method to load the details of a single plug-in.
442 * @param plugin The plugin <strong>File</strong> you wish to load.
443 */
444 private void loadPlugin(String plugin, String lang, String collection_name) {
445 Document document = null;
446 InputStream input_stream = null;
447
448 // Run pluginfo on this plugin, and then send the results for parsing.
449 try {
450 StringBuffer xml = null;
451 if (Gatherer.isGsdlRemote) {
452 String pluginfo_output = RemoteGreenstoneServer.getScriptOptions("pluginfo.pl", "&plugin=" + plugin);
453 xml = new StringBuffer(pluginfo_output);
454 }
455 else {
456 ArrayList args = new ArrayList();
457 if (Utility.isWindows()) {
458 args.add(Configuration.perl_path);
459 args.add("-S");
460 }
461 args.add(LocalGreenstone.getBinScriptDirectoryPath() + "pluginfo.pl");
462 args.add("-xml");
463 args.add("-language");
464 args.add(lang);
465 args.add("-collect");
466 args.add(collection_name);
467 args.add(getPluginName(plugin));
468
469 // Create the process.
470 Runtime runtime = Runtime.getRuntime();
471 Process process = runtime.exec((String[])args.toArray(new String [0]));
472 input_stream = process.getErrorStream();
473 xml = XMLTools.readXMLStream(input_stream);
474 }
475
476 if (xml.length() > 0) {
477 document = CollectionDesignManager.XMLStringToDOM(xml, plugin);
478 }
479 else {
480 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_XML_Parse_Failed", plugin), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
481 }
482 }
483 catch (Exception exception) {
484 DebugStream.println("Failed when trying to parse: " + plugin);
485 DebugStream.printStackTrace(exception);
486 }
487
488 if (document != null) {
489 parseXML(document.getDocumentElement());
490 }
491 }
492
493 /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
494 */
495 private void loadPlugins() {
496 // Attempt to restore the cached file.
497 File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
498 try {
499 FileInputStream file = new FileInputStream(plugins_dat_file);
500 ObjectInputStream input = new ObjectInputStream(file);
501 library = (ArrayList) input.readObject();
502 }
503 catch (Exception error) {
504 DebugStream.println("Unable to open " + plugins_dat_file);
505 }
506
507 if(library == null) {
508 library = new ArrayList();
509
510 if (Gatherer.isGsdlRemote) {
511 String pluginfo_output = RemoteGreenstoneServer.getScriptOptions("pluginfo.pl", "&listall=");
512 loadPlugins(new StringBuffer(pluginfo_output));
513 }
514
515 else {
516 // Retrieve the gsdl home directory...
517 String directory = LocalGreenstone.getDirectoryPath();
518 directory = directory + "perllib" + File.separator + "plugins" + File.separator;
519 String current_lang = Configuration.getLanguage();
520 String collection_name = Gatherer.c_man.getCollection().getName();
521
522 boolean is_windows = Utility.isWindows();
523 boolean is_mac = Utility.isMac();
524
525 File files[] = (new File(directory)).listFiles();
526 File coll_files[] = (new File(Gatherer.c_man.getCollectionPluginsDirectoryPath())).listFiles();
527 int num_files = 0;
528 if (files != null) {
529 num_files += files.length;
530 }
531 if (coll_files != null) {
532 num_files += coll_files.length;
533 }
534 if(num_files > 0) {
535
536 // Create a progress indicator.
537 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), num_files);
538 if (coll_files != null) {
539 for (int i=0; i<coll_files.length; i++) {
540 if(coll_files[i].getName().endsWith(".pm")) {
541 loadPlugin(coll_files[i].getName(), current_lang, collection_name);
542 }
543 progress.inc();
544 }
545 }
546
547 if (files != null) {
548 for(int i = 0; i < files.length; i++) {
549 // We only want to check Perl Modules.
550 if(files[i].getName().endsWith(".pm")) {
551 if (files[i].getName().equals("GMLPlug.pm") || ((is_windows || is_mac) && files[i].getName().equals("DBPlug.pm"))) {
552 // don't load GMLPlug or DBPlug for windows
553 } else {
554 loadPlugin(files[i].getName(), current_lang, collection_name);
555 }
556 }
557 progress.inc();
558 }
559 }
560 progress.dispose();
561 progress.destroy();
562 progress = null;
563 }
564 }
565 }
566 }
567
568
569 /** 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.
570 * @param input_stream An <strong>InputStream</strong> indicating the where list of plugins -- encoded in XML -- can be read from
571 */
572 private void loadPlugins(StringBuffer xml)
573 {
574 Document document = CollectionDesignManager.XMLStringToDOM(xml, "-listall");
575
576 // Parse XML to build up list of plugin names
577 Node root = document.getDocumentElement();
578
579 NamedNodeMap attributes = root.getAttributes();
580 Node length_node = attributes.getNamedItem("length");
581 String num_plugins_str = length_node.getNodeValue();
582 int num_plugins = Integer.parseInt(num_plugins_str);
583 String plugin_list[] = new String[num_plugins];
584
585 Node node = root.getFirstChild();
586 int i = 0;
587 while (node != null) {
588 String node_name = node.getNodeName();
589 if (node_name.equalsIgnoreCase("PluginName")) {
590 String name = XMLTools.getValue(node);
591 plugin_list[i] = name;
592 i++;
593 }
594
595 node = node.getNextSibling();
596 }
597
598
599 boolean is_windows = Utility.isWindows();
600 boolean is_mac = Utility.isMac();
601
602 String current_lang = Configuration.getLanguage();
603 String collection_name = Gatherer.c_man.getCollection().getName();
604 if (num_plugins>0) {
605 // Create a progress indicator.
606 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), num_plugins);
607
608 for (i=0; i<num_plugins; i++) {
609 String plugin = plugin_list[i];
610 if (plugin.equals("GMLPlug.pm") || ((is_windows || is_mac) && plugin.equals("DBPlug.pm"))) {
611 // don't load GMLPlug or DBPlug for windows
612 } else {
613 loadPlugin(plugin, current_lang, collection_name);
614 }
615
616 progress.inc();
617 }
618 progress.dispose();
619 progress.destroy();
620 progress = null;
621 }
622 }
623
624
625 private Plugin parseXML(Node root) {
626 Plugin plugin = new Plugin();
627 String node_name = null;
628 for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
629 node_name = node.getNodeName();
630 if(node_name.equalsIgnoreCase("Name")) {
631 String name = XMLTools.getValue(node);
632 // 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.
633 Plugin existing = getBasePlugin(name);
634 if(existing != null) {
635 return existing;
636 }
637 plugin.setName(name);
638 }
639 else if (node_name.equalsIgnoreCase("Desc")) {
640 plugin.setDescription(XMLTools.getValue(node));
641 }
642 else if (node_name.equalsIgnoreCase("Abstract")) {
643 plugin.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
644 }
645 else if (node_name.equalsIgnoreCase("Explodes")) {
646 plugin.setDoesExplodeMetadataDatabases(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
647 //System.err.println("Plugin " + plugin.getName() + " explodes metadata databases: " + plugin.doesExplodeMetadataDatabases());
648 }
649 // Parse the multitude of arguments
650 else if(node_name.equalsIgnoreCase("Arguments")) {
651 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
652 node_name = arg.getNodeName();
653 // An option.
654 if(node_name.equalsIgnoreCase("Option")) {
655 Argument argument = new Argument();
656 argument.parseXML((Element)arg);
657 plugin.addArgument(argument);
658 }
659 }
660 }
661 // A super plugin class.
662 else if(node_name.equalsIgnoreCase("PlugInfo")) {
663 Plugin super_plugin = parseXML(node);
664 plugin.setSuper(super_plugin);
665 }
666
667 }
668 if(plugin.getName() != null) {
669 addPlugin(plugin);
670 return plugin;
671 }
672 return null;
673 }
674
675 /** A class which provodes controls for assigned and editing plugins. */
676 private class PluginControl
677 extends JPanel
678 implements Control {
679 /** Button for adding plugins. */
680 private JButton add = null;
681 /** Button for configuring the selected plugin. */
682 private JButton configure = null;
683 /** Button to move an assigned plugin one position lower in the order. */
684 private JButton move_down_button = null;
685 /** Button to move an assigned plugin one position higher in the order. */
686 private JButton move_up_button = null;
687 /** Button to remove the selected plugin. */
688 private JButton remove = null;
689 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
690 private JComboBox plugin_combobox = null;
691 /** The label next to the plugin combobox. */
692 private JLabel plugin_label = null;
693 /** The label above the assigned plugin list. */
694 private JLabel plugin_list_label = null;
695 /** A list of assigned plugins. */
696 private JList plugin_list = null;
697 /** The area where the add, configure and remove buttons are placed. */
698 private JPanel button_pane = null;
699 /** The region which divides the central portion of the view into list and controls */
700 private JPanel central_pane = null;
701 /** The area where movement buttons are placed. */
702 private JPanel movement_pane = null;
703 /** The small region containing the plugin combobox and its label. */
704 private JPanel plugin_pane = null;
705 /** The pane containing the assigned plugin list and its label. */
706 private JPanel plugin_list_pane = null;
707
708 /** Constructor.
709 */
710 public PluginControl() {
711 // Create
712 add = new GLIButton(Dictionary.get("CDM.PlugInManager.Add"), Dictionary.get("CDM.PlugInManager.Add_Tooltip"));
713
714 button_pane = new JPanel();
715 central_pane = new JPanel();
716
717 configure = new GLIButton(Dictionary.get("CDM.PlugInManager.Configure"), Dictionary.get("CDM.PlugInManager.Configure_Tooltip"));
718 configure.setEnabled(false);
719
720 JPanel header_pane = new DesignPaneHeader("CDM.GUI.Plugins", "plugins");
721 move_up_button = new GLIButton(Dictionary.get("CDM.Move.Move_Up"), JarTools.getImage("arrow-up.gif"), Dictionary.get("CDM.Move.Move_Up_Tooltip"));
722 move_up_button.setEnabled(false);
723
724 move_down_button = new GLIButton(Dictionary.get("CDM.Move.Move_Down"), JarTools.getImage("arrow-down.gif"), Dictionary.get("CDM.Move.Move_Down_Tooltip"));
725 move_down_button.setEnabled(false);
726
727 movement_pane = new JPanel();
728
729 PluginComboboxListener picl = new PluginComboboxListener();
730 plugin_combobox = new JComboBox(getAvailable());
731 plugin_combobox.setEditable(false);
732 picl.itemStateChanged(new ItemEvent(plugin_combobox, 0, null, ItemEvent.SELECTED));
733
734 plugin_label = new JLabel(Dictionary.get("CDM.PlugInManager.PlugIn"));
735
736 plugin_list = new JList(model);
737 plugin_list.setCellRenderer(new ListRenderer());
738 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
739 plugin_list_label = new JLabel(Dictionary.get("CDM.PlugInManager.Assigned"));
740 //plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
741 plugin_list_label.setOpaque(true);
742
743 plugin_list_pane = new JPanel();
744 plugin_pane = new JPanel();
745
746 remove = new GLIButton(Dictionary.get("CDM.PlugInManager.Remove"), Dictionary.get("CDM.PlugInManager.Remove_Tooltip"));
747 remove.setEnabled(false);
748
749 // Listeners
750 add.addActionListener(new AddListener()); //all_change_listener is listening to the ArgumentConfiguration
751 configure.addActionListener(new ConfigureListener());
752 MoveListener ml = new MoveListener();
753 move_down_button.addActionListener(ml);
754 move_down_button.addActionListener(CollectionDesignManager.all_change_listener);
755 move_up_button.addActionListener(ml);
756 move_up_button.addActionListener(CollectionDesignManager.all_change_listener);
757 plugin_combobox.addItemListener(picl);
758 remove.addActionListener(new RemoveListener());
759 remove.addActionListener(CollectionDesignManager.all_change_listener);
760 plugin_list.addMouseListener(new ClickListener());
761 plugin_list.addListSelectionListener(new ListListener());
762 picl = null;
763
764 // Layout
765 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
766 movement_pane.setLayout(new GridLayout(4,1));
767 movement_pane.add(move_up_button);
768 movement_pane.add(new JPanel());
769 movement_pane.add(new JPanel());
770 movement_pane.add(move_down_button);
771
772 plugin_list_pane.setLayout(new BorderLayout());
773 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
774 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
775 modeChanged(Configuration.getMode()); // Whether the movement buttons are visible is mode dependant
776
777 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
778
779 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
780 plugin_pane.setLayout(new BorderLayout(5,0));
781 plugin_pane.add(plugin_label, BorderLayout.WEST);
782 plugin_pane.add(plugin_combobox, BorderLayout.CENTER);
783
784 button_pane.setLayout(new GridLayout(1,3));
785 button_pane.add(add);
786 button_pane.add(configure);
787 button_pane.add(remove);
788
789 // Scope these mad bordering skillz.
790 JPanel temp = new JPanel(new BorderLayout());
791 temp.add(plugin_pane, BorderLayout.NORTH);
792 temp.add(button_pane, BorderLayout.SOUTH);
793
794 central_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
795 central_pane.setLayout(new BorderLayout());
796 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
797 central_pane.add(temp, BorderLayout.SOUTH);
798
799 setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
800 setLayout(new BorderLayout());
801 add(header_pane, BorderLayout.NORTH);
802 add(central_pane, BorderLayout.CENTER);
803 }
804
805 /** Method which acts like a destructor, tidying up references to persistant objects.
806 */
807 public void destroy() {
808 }
809
810 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
811 no longer have instructions, do we still need updateUI???
812 */
813 public void gainFocus() {
814 super.updateUI();
815 }
816
817 public void loseFocus() {
818 }
819
820 /** 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
821 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
822 */
823 public void modeChanged(int mode) {
824 // 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
825 plugin_list.clearSelection();
826 // The first change is dependant on whether the user is systems mode or higher
827 if(mode >= Configuration.SYSTEMS_MODE) {
828 // Show movement buttons
829 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
830 // Do we show Arc and RecPlugs or hide them and the separator line
831 setHideLines(!(mode >= Configuration.EXPERT_MODE));
832 }
833 // Otherwise hide the movement buttons and fixed plugins
834 else {
835 plugin_list_pane.remove(movement_pane);
836 setHideLines(true);
837 }
838 plugin_list_pane.updateUI();
839 }
840
841 /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugin()</i> method. */
842 private class AddListener
843 implements ActionListener {
844 /** 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.
845 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
846 */
847 public void actionPerformed(ActionEvent event) {
848 Object selected_object = plugin_combobox.getSelectedItem();
849 if(selected_object != null) {
850 // Retrieve the base plugin
851 Plugin base_plugin = getBasePlugin(selected_object.toString());
852 if (base_plugin == null) {
853 // shouldn't happen
854 return;
855 }
856
857 // Create a new element in the DOM
858 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
859 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
860 Plugin new_plugin = new Plugin(element, base_plugin);
861 element = null;
862
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, if we are in a low mode, remove the plugin from the available list (except for UnknownPlug
869 if(Configuration.getMode() <= Configuration.SYSTEMS_MODE && !base_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
870 plugin_combobox.removeItem(base_plugin);
871 plugin_combobox.setSelectedIndex(0);
872 }
873 }
874 ac = null;
875 new_plugin = null;
876 base_plugin = null;
877 }
878 }
879 }
880
881 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
882 private class ClickListener
883 extends MouseAdapter {
884 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
885 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
886 */
887 public void mouseClicked(MouseEvent event) {
888 if(event.getClickCount() == 2 ) {
889 if(!plugin_list.isSelectionEmpty()) {
890 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
891 if(!plugin.isSeparator()) {
892 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
893 if(ac.display()) {
894 refresh(plugin);
895 }
896 ac.destroy();
897 ac = null;
898 // 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
899 Gatherer.c_man.configurationChanged();
900 }
901 }
902 }
903 }
904 }
905
906 /** 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.
907 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
908 */
909 private class ConfigureListener
910 implements ActionListener {
911 /** 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.
912 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
913 */
914 public void actionPerformed(ActionEvent event) {
915 if(!plugin_list.isSelectionEmpty()) {
916 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
917 if(!plugin.isSeparator()) {
918 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
919 if(ac.display()) {
920 refresh(plugin);
921 }
922 ac.destroy();
923 ac = null;
924 // 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
925 Gatherer.c_man.configurationChanged();
926 }
927 }
928 }
929 }
930
931 /** 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 */
932 private class ListListener
933 implements ListSelectionListener {
934
935 public void valueChanged(ListSelectionEvent e) {
936 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one (the second one)
937 if (plugin_list.isSelectionEmpty()) {
938 move_up_button.setEnabled(false);
939 move_down_button.setEnabled(false);
940 configure.setEnabled(false);
941 remove.setEnabled(false);
942 }
943 else {
944 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
945 if(selected_plugin.isSeparator()) {
946 move_up_button.setEnabled(false);
947 move_down_button.setEnabled(false);
948 configure.setEnabled(false);
949 remove.setEnabled(false);
950 }
951 else {
952 configure.setEnabled(true);
953 String plugin_name = selected_plugin.getName();
954 // Some buttons are only available for plugins other than ArcPlug and RecPlug
955 if(plugin_name.equals(StaticStrings.ARCPLUG_STR) || plugin_name.equals(StaticStrings.RECPLUG_STR) ) {
956 move_up_button.setEnabled(false);
957 move_down_button.setEnabled(false);
958 remove.setEnabled(false);
959 }
960 else {
961 // don't let people remove special plugins such GAPlug an METSPlug,
962 // unless they are in systems mode or above
963 int mode = Configuration.getMode();
964 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
965 if ((plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
966 (mode < Configuration.SYSTEMS_MODE)) {
967 remove.setEnabled(false);
968 break;
969 } else {
970 remove.setEnabled(true);
971 }
972 }
973
974 // Move ups are only enabled if the selected plugin isn't already at the top
975 Plugin first_plugin = (Plugin) getElementAt(0);
976 if(!first_plugin.equals(selected_plugin)) {
977 move_up_button.setEnabled(true);
978 }
979 else {
980 move_up_button.setEnabled(false);
981 }
982 // And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
983 int separator_index = findSeparatorIndex();
984 int selected_index = plugin_list.getSelectedIndex();
985 if(selected_index < separator_index - 1) {
986 move_down_button.setEnabled(true);
987 }
988 else {
989 move_down_button.setEnabled(false);
990 }
991 }
992 selected_plugin = null;
993 plugin_name = null;
994 }
995 }
996 }
997 }
998 }
999
1000 /** A special list renderer which is able to render separating lines as well. */
1001 private class ListRenderer
1002 extends DefaultListCellRenderer {
1003 /** 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.
1004 * @param list - The <strong>JList</strong> we're painting.
1005 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
1006 * @param index - The cells index as an <i>int</i>.
1007 * @param isSelected - <i>true</i> if the specified cell was selected.
1008 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
1009 * @return A <strong>Component</strong> whose paint() method will render the specified value.
1010 * @see javax.swing.JList
1011 * @see javax.swing.JSeparator
1012 * @see javax.swing.ListModel
1013 * @see javax.swing.ListSelectionModel
1014 */
1015 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
1016 Plugin plugin = (Plugin) value;
1017 if(plugin.isSeparator()) {
1018 return separator;
1019 }
1020 else {
1021 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1022 }
1023 }
1024 }
1025
1026
1027 /** 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. */
1028 private class MoveListener
1029 implements ActionListener {
1030 /** 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.
1031 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1032 */
1033 public void actionPerformed(ActionEvent event) {
1034 if (!plugin_list.isSelectionEmpty()) {
1035 Object object = plugin_list.getSelectedValue();
1036 if (object instanceof Plugin) {
1037 Plugin plugin = (Plugin) object;
1038 if (event.getSource() == move_up_button) {
1039 movePlugin(plugin, true, false);
1040 }
1041 else if (event.getSource() == move_down_button) {
1042 movePlugin(plugin, false, false);
1043 }
1044 plugin_list.setSelectedValue(plugin, true);
1045 }
1046 }
1047 }
1048 }
1049
1050 /** This listener reacts to changes in the current selection of the plugin combobox. */
1051 private class PluginComboboxListener
1052 implements ItemListener {
1053 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
1054 public void itemStateChanged(ItemEvent event) {
1055 if(event.getStateChange() == ItemEvent.SELECTED) {
1056 // Retrieve the selected plugin
1057 Object current_selection = plugin_combobox.getSelectedItem();
1058 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
1059 if(current_selection == null || current_selection instanceof String) {
1060 plugin_combobox.setToolTipText(Dictionary.get("CDM.PlugInManager.PlugIn_Tooltip"));
1061 }
1062 else {
1063 Plugin current_plugin = (Plugin) current_selection;
1064 plugin_combobox.setToolTipText(Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
1065 current_plugin = null;
1066 }
1067 current_selection = null;
1068 }
1069 }
1070 }
1071
1072 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
1073 */
1074 private class RemoveListener
1075 implements ActionListener {
1076 /** 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.
1077 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1078 */
1079 public void actionPerformed(ActionEvent event) {
1080 int selected_index = plugin_list.getSelectedIndex();
1081 if(selected_index != -1) {
1082 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
1083 removePlugin(selected_plugin);
1084 selected_plugin = null;
1085 // Select the next plugin if available
1086 if(selected_index < plugin_list.getModel().getSize()) {
1087 // If the new selection is above the separator we can remove it
1088 if(selected_index < findSeparatorIndex()) {
1089 plugin_list.setSelectedIndex(selected_index);
1090
1091 // don't let people remove special plugins such GAPlug an METSPlug,
1092 // unless they are in systems mode or above
1093 int mode = Configuration.getMode();
1094 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
1095 String selected_plugin_name
1096 = ((Plugin)plugin_list.getSelectedValue()).getName();
1097 if ((selected_plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
1098 (mode < Configuration.SYSTEMS_MODE)) {
1099 remove.setEnabled(false);
1100 break;
1101 } else {
1102 remove.setEnabled(true);
1103 }
1104 }
1105 }
1106 // Otherwise select the first non-removable plugin
1107 else {
1108 plugin_list.setSelectedIndex(selected_index + 1);
1109 remove.setEnabled(false);
1110 }
1111 }
1112 else {
1113 remove.setEnabled(false);
1114 }
1115 // Refresh the available plugins
1116 plugin_combobox.setModel(new DefaultComboBoxModel(getAvailable()));
1117 }
1118 else {
1119 remove.setEnabled(false);
1120 }
1121 }
1122 }
1123 }
1124
1125
1126 private class PluginSuggestionPrompt
1127 extends ModalDialog
1128 implements ActionListener
1129 {
1130 private Dimension size = new Dimension(480, 240);
1131 private GComboBox suitable_plugins_combobox = null;
1132 private GLIButton add_button = null;
1133 private GLIButton ignore_button = null;
1134
1135 public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
1136 {
1137 super(Gatherer.g_man, true);
1138 setModal(true);
1139 setSize(size);
1140 setTitle(Dictionary.get("CDM.PluginManager.SuggestedPluginListTitle"));
1141
1142 String[] args = new String[1];
1143 args[0] = filename;
1144
1145 JTextArea instructions_textarea = new JTextArea(Dictionary.get("CDM.PluginManager.Plugin_Suggestion_Prompt", args));
1146 instructions_textarea.setCaretPosition(0);
1147 instructions_textarea.setEditable(false);
1148 instructions_textarea.setLineWrap(true);
1149 instructions_textarea.setRows(5);
1150 instructions_textarea.setWrapStyleWord(true);
1151
1152 JLabel suitable_plugins_label = new JLabel(Dictionary.get("CDM.PlugInManager.PlugIn"));
1153 suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
1154
1155 suitable_plugins_combobox = new GComboBox(suitable_plugins);
1156 suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
1157 suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
1158 suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
1159 suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
1160
1161 JPanel suitable_plugins_pane = new JPanel();
1162 //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
1163 suitable_plugins_pane.setLayout(new BorderLayout(5,0));
1164 suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.WEST);
1165 suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
1166
1167 add_button = new GLIButton(Dictionary.get("CDM.PlugInManager.QuickAdd"), Dictionary.get("CDM.PlugInManager.Add_Tooltip"));
1168 ignore_button = new GLIButton(Dictionary.get("CDM.PlugInManager.Ignore"), Dictionary.get("CDM.PlugInManager.Ignore_Tooltip"));
1169
1170 add_button.addActionListener(this);
1171 ignore_button.addActionListener(this);
1172
1173 JPanel button_pane = new JPanel();
1174 button_pane.setLayout(new GridLayout(1,2,5,0));
1175 button_pane.add(add_button);
1176 button_pane.add(ignore_button);
1177
1178 JPanel controls_pane = new JPanel();
1179 controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
1180 controls_pane.setLayout(new GridLayout(2,1,0,5));
1181 controls_pane.add(suitable_plugins_pane);
1182 controls_pane.add(button_pane);
1183
1184 JPanel content_pane = (JPanel) getContentPane();
1185 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
1186 content_pane.setLayout(new BorderLayout());
1187 content_pane.add(instructions_textarea, BorderLayout.CENTER);
1188 content_pane.add(controls_pane, BorderLayout.SOUTH);
1189
1190 // Show
1191 Dimension screen_size = Configuration.screen_size;
1192 setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
1193 setVisible(true);
1194 }
1195
1196 public void actionPerformed(ActionEvent event) {
1197
1198 if(event.getSource() == add_button) {
1199 // add the selected plugin to the list
1200 Object selected_object = suitable_plugins_combobox.getSelectedItem();
1201 Plugin base_plugin = getBasePlugin(selected_object.toString());
1202 if (base_plugin == null) {
1203 // shouldn't happen - we are not allowed custom plugins anymore
1204 setVisible(false);
1205 return;
1206 }
1207 // Create a new element in the DOM
1208 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
1209 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
1210 Plugin new_plugin = new Plugin(element, base_plugin);
1211 assignPlugin(new_plugin);
1212 } // else do nothing
1213
1214 // close the dialog
1215 setVisible(false);
1216 }
1217
1218 }
1219
1220
1221 /** Creates a list separator.
1222 * Found on Google Groups. Code courtesy of Paul Farwell.
1223 */
1224 private JPanel getSeparator() {
1225 // We put the separator inside a panel to control its appearance
1226 JPanel _sepPanel = new JPanel();
1227 _sepPanel.setOpaque(false);
1228 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1229 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1230 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1231 // 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
1232 _sepPanel.add(new BasicSeparator());
1233 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1234 return _sepPanel;
1235 }
1236
1237 /** 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. */
1238 private static class BasicSeparator
1239 extends JSeparator {
1240
1241 private ComponentUI basic_ui;
1242
1243 public BasicSeparator() {
1244 super();
1245 basic_ui = new BasicSeparatorUI();
1246 }
1247
1248 public void paintComponent(Graphics g) {
1249 if (basic_ui != null) {
1250 basic_ui.update(g, this);
1251 }
1252 }
1253 }
1254}
Note: See TracBrowser for help on using the repository browser.