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

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

Added a new LocalGreenstone class which contains functions that only make sense with a local Greenstone.

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