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

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

Tidied up plugin and classifier parsing and error output.

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