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

Last change on this file since 10049 was 10011, checked in by mdewsnip, 19 years ago

Moved Utility.getImage into JarTools, as part of tidying up the Utility class.

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