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

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

Fixed bug where CollectionContentsChangedListener isn't removed from destroyed PluginManager object.

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