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

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

Made some debug statements go to DebugStream now.

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