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

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

Removed a couple of debug statements.

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