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

Last change on this file since 8841 was 8841, checked in by kjdon, 19 years ago

fixed spelling mistake on one of the strings names

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