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

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

Rearranged a few things when using classinfo.pl and pluginfo.pl, to make this easier when using a remote Greenstone server.

  • Property svn:keywords set to Author Date Id Revision
File size: 51.1 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.net.*;
33import java.util.*;
34import javax.swing.*;
35import javax.swing.event.*;
36import javax.swing.plaf.*;
37import javax.swing.plaf.basic.*;
38import org.apache.xerces.parsers.*;
39import org.greenstone.gatherer.Configuration;
40import org.greenstone.gatherer.DebugStream;
41import org.greenstone.gatherer.Dictionary;
42import org.greenstone.gatherer.Gatherer;
43import org.greenstone.gatherer.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 StringBuffer xml = null;
444 if (Gatherer.isGsdlRemote) {
445 String launch = Gatherer.cgiBase + "launch";
446 launch += "?cmd=pluginfo.pl";
447 launch += "&xml=&language="+lang;
448 launch += "&plug=" + getPluginName(plugin);
449
450 System.err.println("*** launch = " + launch);
451
452 URL launch_url = new URL(launch);
453 URLConnection launch_connection = launch_url.openConnection();
454 input_stream = launch_connection.getInputStream();
455 xml = Utility.readXMLStream(input_stream);
456 }
457 else {
458 String args[] = null;
459 if(Utility.isWindows()) {
460 args = new String[6];
461 if(Configuration.perl_path != null) {
462 args[0] = Configuration.perl_path;
463 }
464 else {
465 args[0] = "Perl.exe";
466 }
467 args[1] = LocalGreenstone.getBinScriptDirectoryPath() + "pluginfo.pl";
468 args[2] = "-xml";
469 args[3] = "-language";
470 args[4] = lang;
471 args[5] = getPluginName(plugin);
472 }
473 else {
474 args = new String[5];
475 args[0] = "pluginfo.pl";
476 args[1] = "-xml";
477 args[2] = "-language";
478 args[3] = lang;
479 args[4] = getPluginName(plugin);
480 }
481
482 // Create the process.
483 Runtime runtime = Runtime.getRuntime();
484 Process process = runtime.exec(args);
485 input_stream = process.getErrorStream();
486 xml = Utility.readXMLStream(input_stream);
487 }
488
489 document = CollectionDesignManager.XMLStringToDOM(xml,plugin);
490 }
491 catch (Exception error) {
492 System.err.println("Failed when trying to parse: " + plugin);
493 error.printStackTrace();
494 }
495 if(document != null) {
496 parseXML(document.getDocumentElement());
497 }
498 }
499
500 /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
501 */
502 private void loadPlugins() {
503 // Attempt to restore the cached file.
504 File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
505 try {
506 FileInputStream file = new FileInputStream(plugins_dat_file);
507 ObjectInputStream input = new ObjectInputStream(file);
508 library = (ArrayList) input.readObject();
509 }
510 catch (Exception error) {
511 DebugStream.println("Unable to open " + plugins_dat_file);
512 }
513
514 if(library == null) {
515 library = new ArrayList();
516 if (Gatherer.isGsdlRemote) {
517
518 String lang = Configuration.getLanguage();
519
520 String launch = Gatherer.cgiBase + "launch";
521 launch += "?cmd=pluginfo.pl";
522 launch += "&xml=&language="+lang;
523 launch += "&listall=";
524
525 System.err.println("*** launch = " + launch);
526
527 try {
528 URL launch_url = new URL(launch);
529 URLConnection launch_connection = launch_url.openConnection();
530 InputStream input_stream = launch_connection.getInputStream();
531 StringBuffer xml = Utility.readXMLStream(input_stream);
532 loadPlugins(xml);
533 }
534 catch (Exception error) {
535 System.err.println("Failed when trying to connect to : " + launch);
536 error.printStackTrace();
537 }
538
539 }
540 else {
541 // Retrieve the gsdl home directory...
542 String directory = LocalGreenstone.getDirectoryPath();
543 directory = directory + "perllib" + File.separator + "plugins" + File.separator;
544 loadPlugins(new File(directory));
545 }
546 }
547 }
548
549
550
551
552 /** 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.
553 * @param input_stream An <strong>InputStream</strong> indicating the where list of plugins -- encoded in XML -- can be read from
554 */
555 private void loadPlugins(StringBuffer xml)
556 {
557 Document document = CollectionDesignManager.XMLStringToDOM(xml, "-listall");
558
559 // Parse XML to build up list of plugin names
560 Node root = document.getDocumentElement();
561
562 NamedNodeMap attributes = root.getAttributes();
563 Node length_node = attributes.getNamedItem("length");
564 String num_plugins_str = length_node.getNodeValue();
565 int num_plugins = Integer.parseInt(num_plugins_str);
566 String plugin_list[] = new String[num_plugins];
567
568 Node node = root.getFirstChild();
569 int i = 0;
570 while (node != null) {
571 String node_name = node.getNodeName();
572 if (node_name.equalsIgnoreCase("PluginName")) {
573 String name = XMLTools.getValue(node);
574 plugin_list[i] = name;
575 i++;
576 }
577
578 node = node.getNextSibling();
579 }
580
581
582 boolean is_windows = Utility.isWindows();
583 boolean is_mac = Utility.isMac();
584
585 String current_lang = Configuration.getLanguage();
586 if (num_plugins>0) {
587 // Create a progress indicator.
588 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), num_plugins);
589
590 for (i=0; i<num_plugins; i++) {
591 String plugin = plugin_list[i];
592 if (plugin.equals("GMLPlug.pm") || ((is_windows || is_mac) && plugin.equals("DBPlug.pm"))) {
593 // don't load GMLPlug or DBPlug for windows
594 } else {
595 loadPlugin(plugin, current_lang);
596 }
597
598 progress.inc();
599 }
600 progress.dispose();
601 progress.destroy();
602 progress = null;
603 }
604 }
605
606
607 /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
608 * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
609 */
610 private void loadPlugins(File directory) {
611 File files[] = directory.listFiles();
612 boolean is_windows = Utility.isWindows();
613 boolean is_mac = Utility.isMac();
614 String current_lang = Configuration.getLanguage();
615 if(files != null) {
616 // Create a progress indicator.
617 ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), files.length);
618 for(int i = 0; i < files.length; i++) {
619 // We only want to check Perl Modules.
620 if(files[i].getName().endsWith(".pm")) {
621 if (files[i].getName().equals("GMLPlug.pm") || ((is_windows || is_mac) && files[i].getName().equals("DBPlug.pm"))) {
622 // don't load GMLPlug or DBPlug for windows
623 } else {
624 loadPlugin(files[i].getName(), current_lang);
625 }
626 }
627 progress.inc();
628 }
629 progress.dispose();
630 progress.destroy();
631 progress = null;
632 }
633 }
634
635 private Plugin parseXML(Node root) {
636 Plugin plugin = new Plugin();
637 String node_name = null;
638 for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
639 node_name = node.getNodeName();
640 if(node_name.equalsIgnoreCase("Name")) {
641 String name = XMLTools.getValue(node);
642 // 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.
643 Plugin existing = getBasePlugin(name);
644 if(existing != null) {
645 return existing;
646 }
647 plugin.setName(name);
648 }
649 else if (node_name.equalsIgnoreCase("Desc")) {
650 plugin.setDescription(XMLTools.getValue(node));
651 }
652 else if (node_name.equalsIgnoreCase("Abstract")) {
653 plugin.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
654 }
655 else if (node_name.equalsIgnoreCase("Explodes")) {
656 plugin.setDoesExplodeMetadataDatabases(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
657 //System.err.println("Plugin " + plugin.getName() + " explodes metadata databases: " + plugin.doesExplodeMetadataDatabases());
658 }
659 // Parse the multitude of arguments
660 else if(node_name.equalsIgnoreCase("Arguments")) {
661 for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
662 node_name = arg.getNodeName();
663 // An option.
664 if(node_name.equalsIgnoreCase("Option")) {
665 Argument argument = new Argument();
666 argument.parseXML((Element)arg);
667 plugin.addArgument(argument);
668 }
669 // A super plugin class.
670 else if(node_name.equalsIgnoreCase("PlugInfo")) {
671 Plugin super_plugin = parseXML(arg);
672 plugin.setSuper(super_plugin);
673 }
674 }
675 }
676 }
677 if(plugin.getName() != null) {
678 addPlugin(plugin);
679 return plugin;
680 }
681 return null;
682 }
683
684 /** A class which provodes controls for assigned and editing plugins. */
685 private class PluginControl
686 extends JPanel
687 implements Control {
688 /** Button for adding plugins. */
689 private JButton add = null;
690 /** Button for configuring the selected plugin. */
691 private JButton configure = null;
692 /** Buttom to move an assinged plugin as low in the order as possible. */
693 //private JButton move_bottom_button = null;
694 /** Button to move an assigned plugin one position lower in the order. */
695 private JButton move_down_button = null;
696 /** Button to move an assigned plugin as high in the order as possible. */
697 //private JButton move_top_button = null;
698 /** Button to move an assigned plugin one position higher in the order. */
699 private JButton move_up_button = null;
700 /** Button to remove the selected plugin. */
701 private JButton remove = null;
702 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
703 private GComboBox plugin = null;
704 /** The label next to the plugin combobox. */
705 private JLabel plugin_label = null;
706 /** The label above the assigned plugin list. */
707 private JLabel plugin_list_label = null;
708 /** The title of this view. */
709 private JLabel title = null;
710 /** A list of assigned plugins. */
711 private JList plugin_list = null;
712 /** The area where the add, configure and remove buttons are placed. */
713 private JPanel button_pane = null;
714 /** The region which divides the central portion of the view into list and controls */
715 private JPanel central_pane = null;
716 /** The area where title label and instructions sit. */
717 private JPanel header_pane = null;
718 /** The area where movement buttons are placed. */
719 private JPanel movement_pane = null;
720 /** The small region containing the plugin combobox and its label. */
721 private JPanel plugin_pane = null;
722 /** The pane containing the assigned plugin list and its label. */
723 private JPanel plugin_list_pane = null;
724 /** The text area containing instructions on the use of this control. */
725 private JTextArea instructions = null;
726
727 /** Constructor.
728 */
729 public PluginControl() {
730 // Create
731 add = new GLIButton();
732 add.setMnemonic(KeyEvent.VK_A);
733 Dictionary.registerBoth(add, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
734
735 button_pane = new JPanel();
736 central_pane = new JPanel();
737
738 configure = new GLIButton();
739 configure.setEnabled(false);
740 configure.setMnemonic(KeyEvent.VK_C);
741 Dictionary.registerBoth(configure, "CDM.PlugInManager.Configure", "CDM.PlugInManager.Configure_Tooltip");
742
743 header_pane = new JPanel();
744
745 instructions = new JTextArea();
746 instructions.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
747 instructions.setEditable(false);
748 instructions.setLineWrap(true);
749 instructions.setRows(6);
750 instructions.setWrapStyleWord(true);
751 Dictionary.registerText(instructions, "CDM.PlugInManager.Instructions");
752
753 move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
754 move_up_button.setEnabled(false);
755 move_up_button.setMnemonic(KeyEvent.VK_U);
756 Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
757
758 move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
759 move_down_button.setEnabled(false);
760 move_down_button.setMnemonic(KeyEvent.VK_D);
761 Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
762
763 movement_pane = new JPanel();
764
765 PluginComboboxListener picl = new PluginComboboxListener();
766 plugin = new GComboBox(getAvailable());
767 plugin.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
768 plugin.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
769 plugin.setEditable(true);
770 plugin.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
771 plugin.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
772 picl.itemStateChanged(new ItemEvent(plugin, 0, null, ItemEvent.SELECTED));
773
774 plugin_label = new JLabel();
775 Dictionary.registerText(plugin_label, "CDM.PlugInManager.PlugIn");
776
777 plugin_list = new JList(model);
778 plugin_list.setCellRenderer(new ListRenderer());
779 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
780 plugin_list_label = new JLabel();
781 plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
782 plugin_list_label.setOpaque(true);
783 Dictionary.registerText(plugin_list_label, "CDM.PlugInManager.Assigned");
784
785 plugin_list_pane = new JPanel();
786 plugin_pane = new JPanel();
787
788 remove = new GLIButton();
789 remove.setEnabled(false);
790 remove.setMnemonic(KeyEvent.VK_R);
791 Dictionary.registerBoth(remove, "CDM.PlugInManager.Remove", "CDM.PlugInManager.Remove_Tooltip");
792
793 title = new JLabel();
794 title.setHorizontalAlignment(JLabel.CENTER);
795 title.setOpaque(true);
796 Dictionary.registerText(title, "CDM.PlugInManager.Title");
797
798 // Listeners
799 add.addActionListener(new AddListener()); //all_change_listener is listening to the ArgumentConfiguration
800 configure.addActionListener(new ConfigureListener());
801 MoveListener ml = new MoveListener();
802 //move_bottom_button.addActionListener(ml);
803 move_down_button.addActionListener(ml);
804 move_down_button.addActionListener(CollectionDesignManager.all_change_listener);
805 //move_top_button.addActionListener(ml);
806 move_up_button.addActionListener(ml);
807 move_up_button.addActionListener(CollectionDesignManager.all_change_listener);
808 plugin.addItemListener(picl);
809 remove.addActionListener(new RemoveListener());
810 remove.addActionListener(CollectionDesignManager.all_change_listener);
811 plugin_list.addMouseListener(new ClickListener());
812 plugin_list.addListSelectionListener(new ListListener());
813 picl = null;
814
815 // Layout
816 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
817
818 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
819
820 header_pane.setLayout(new BorderLayout());
821 header_pane.add(title, BorderLayout.NORTH);
822 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
823
824 plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
825
826 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
827 movement_pane.setLayout(new GridLayout(4,1));
828 movement_pane.add(move_up_button);
829 movement_pane.add(new JPanel());
830 movement_pane.add(new JPanel());
831 movement_pane.add(move_down_button);
832
833 plugin_list_pane.setLayout(new BorderLayout());
834 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
835 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
836 modeChanged(Configuration.getMode()); // Whether the movement buttons are visible is mode dependant
837
838 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
839
840 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
841 plugin_pane.setLayout(new BorderLayout(5,0));
842 plugin_pane.add(plugin_label, BorderLayout.WEST);
843 plugin_pane.add(plugin, BorderLayout.CENTER);
844
845 button_pane.setLayout(new GridLayout(1,3));
846 button_pane.add(add);
847 button_pane.add(configure);
848 button_pane.add(remove);
849
850 // Scope these mad bordering skillz.
851 JPanel temp = new JPanel(new BorderLayout());
852 temp.setBorder
853 (BorderFactory.createCompoundBorder
854 (BorderFactory.createEmptyBorder(5,0,5,0),
855 BorderFactory.createCompoundBorder
856 (BorderFactory.createTitledBorder(Dictionary.get("CDM.PlugInManager.Controls")),
857 BorderFactory.createEmptyBorder(2,2,2,2))));
858
859 temp.add(plugin_pane, BorderLayout.NORTH);
860 temp.add(button_pane, BorderLayout.SOUTH);
861
862 central_pane.setLayout(new BorderLayout());
863 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
864 central_pane.add(temp, BorderLayout.SOUTH);
865
866 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
867 setLayout(new BorderLayout());
868 add(header_pane, BorderLayout.NORTH);
869 add(central_pane, BorderLayout.CENTER);
870 }
871
872 /** Method which acts like a destructor, tidying up references to persistant objects.
873 */
874 public void destroy() {
875 }
876
877 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
878 */
879 public void gainFocus() {
880 if(instructions != null) {
881 instructions.setCaretPosition(0);
882 }
883 super.updateUI();
884 }
885
886 public void loseFocus() {
887 }
888
889 /** 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
890 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
891 */
892 public void modeChanged(int mode) {
893 // 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
894 plugin_list.clearSelection();
895 // The first change is dependant on whether the user is systems mode or higher
896 if(mode >= Configuration.SYSTEMS_MODE) {
897 // Show movement buttons
898 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
899 // Do we show Arc and RecPlugs or hide them and the separator line
900 setHideLines(!(mode >= Configuration.EXPERT_MODE));
901 }
902 // Otherwise hide the movement buttons and fixed plugins
903 else {
904 plugin_list_pane.remove(movement_pane);
905 setHideLines(true);
906 }
907 plugin_list_pane.updateUI();
908 }
909
910 /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugin()</i> method. */
911 private class AddListener
912 implements ActionListener {
913 /** 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.
914 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
915 */
916 public void actionPerformed(ActionEvent event) {
917 Object selected_object = plugin.getSelectedItem();
918 if(selected_object != null) {
919 // Retrieve the base plugin if any
920 Plugin base_plugin = getBasePlugin(selected_object.toString());
921
922 // Create a new element in the DOM
923 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
924 // Remember that the plugin supplied might be a custom string rather than a base plugin
925 Plugin new_plugin = null;
926 if(base_plugin != null) {
927 //DebugStream.println("New Plugin based on existing Plugin");
928 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
929 new_plugin = new Plugin(element, base_plugin);
930 }
931 else {
932 //DebugStream.println("New Custom Plugin");
933 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
934 new_plugin = new Plugin(element, null);
935 }
936 if(!model.contains(new_plugin) || new_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
937 // Automatically chain to configuration. This ensures required arguments are filled out.
938 ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
939 if(ac.display()) {
940 assignPlugin(new_plugin);
941 plugin_list.setSelectedValue(new_plugin, true);
942 // 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
943 if(base_plugin != null && !base_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
944 plugin.removeItem(base_plugin);
945 }
946 }
947 ac = null;
948 new_plugin = null;
949 plugin.setSelectedIndex(0);
950 }
951 else {
952 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
953 }
954 base_plugin = null;
955 }
956 }
957 }
958
959 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
960 private class ClickListener
961 extends MouseAdapter {
962 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
963 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
964 */
965 public void mouseClicked(MouseEvent event) {
966 if(event.getClickCount() == 2 ) {
967 if(!plugin_list.isSelectionEmpty()) {
968 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
969 if(!plugin.isSeparator()) {
970 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
971 if(ac.display()) {
972 refresh(plugin);
973 }
974 ac.destroy();
975 ac = null;
976 // cos I can't be bothered checking every argument to see if it has changed or not, we'll asasume that the configuration has changed if someone has clicked configure
977 Gatherer.c_man.configurationChanged();
978 }
979 }
980 }
981 }
982 }
983
984 /** 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.
985 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
986 */
987 private class ConfigureListener
988 implements ActionListener {
989 /** 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.
990 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
991 */
992 public void actionPerformed(ActionEvent event) {
993 if(!plugin_list.isSelectionEmpty()) {
994 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
995 if(!plugin.isSeparator()) {
996 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
997 if(ac.display()) {
998 refresh(plugin);
999 }
1000 ac.destroy();
1001 ac = null;
1002 // cos I can't be bothered checking every argument to see if it has changed or not, we'll asasume that the configuration has changed if someone has clicked configure
1003 Gatherer.c_man.configurationChanged();
1004 }
1005 }
1006 }
1007 }
1008
1009 /** 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 */
1010 private class ListListener
1011 implements ListSelectionListener {
1012
1013 public void valueChanged(ListSelectionEvent e) {
1014 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one (the second one)
1015 if (plugin_list.isSelectionEmpty()) {
1016 //move_top_button.setEnabled(false);
1017 move_up_button.setEnabled(false);
1018 move_down_button.setEnabled(false);
1019 //move_bottom_button.setEnabled(false);
1020 configure.setEnabled(false);
1021 remove.setEnabled(false);
1022 }
1023 else {
1024 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
1025 if(selected_plugin.isSeparator()) {
1026 //move_top_button.setEnabled(false);
1027 move_up_button.setEnabled(false);
1028 move_down_button.setEnabled(false);
1029 //move_bottom_button.setEnabled(false);
1030 configure.setEnabled(false);
1031 remove.setEnabled(false);
1032 }
1033 else {
1034 configure.setEnabled(true);
1035 String plugin_name = selected_plugin.getName();
1036 // Some buttons are only available for plugins other than ArcPlug and RecPlug
1037 if(plugin_name.equals(StaticStrings.ARCPLUG_STR) || plugin_name.equals(StaticStrings.RECPLUG_STR) ) {
1038 //move_top_button.setEnabled(false);
1039 move_up_button.setEnabled(false);
1040 move_down_button.setEnabled(false);
1041 //move_bottom_button.setEnabled(false);
1042 remove.setEnabled(false);
1043 }
1044 else {
1045 // don't let people remove special plugins such GAPlug an METSPlug,
1046 // unless they are in systems mode or above
1047 int mode = Configuration.getMode();
1048 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
1049 if ((plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
1050 (mode < Configuration.SYSTEMS_MODE)) {
1051 remove.setEnabled(false);
1052 break;
1053 } else {
1054 remove.setEnabled(true);
1055 }
1056 }
1057
1058 // Move ups are only enabled if the selected plugin isn't already at the top
1059 Plugin first_plugin = (Plugin) getElementAt(0);
1060 if(!first_plugin.equals(selected_plugin)) {
1061 //move_top_button.setEnabled(true);
1062 move_up_button.setEnabled(true);
1063 }
1064 else {
1065 //move_top_button.setEnabled(false);
1066 move_up_button.setEnabled(false);
1067 }
1068 // And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
1069 int separator_index = findSeparatorIndex();
1070 int selected_index = plugin_list.getSelectedIndex();
1071 if(selected_index < separator_index - 1) {
1072 move_down_button.setEnabled(true);
1073 //move_bottom_button.setEnabled(true);
1074 }
1075 else {
1076 move_down_button.setEnabled(false);
1077 //move_bottom_button.setEnabled(false);
1078 }
1079 }
1080 selected_plugin = null;
1081 plugin_name = null;
1082 }
1083 }
1084 }
1085 }
1086 }
1087
1088 /** A special list renderer which is able to render separating lines as well. */
1089 private class ListRenderer
1090 extends DefaultListCellRenderer {
1091 /** 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.
1092 * @param list - The <strong>JList</strong> we're painting.
1093 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
1094 * @param index - The cells index as an <i>int</i>.
1095 * @param isSelected - <i>true</i> if the specified cell was selected.
1096 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
1097 * @return A <strong>Component</strong> whose paint() method will render the specified value.
1098 * @see javax.swing.JList
1099 * @see javax.swing.JSeparator
1100 * @see javax.swing.ListModel
1101 * @see javax.swing.ListSelectionModel
1102 */
1103 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
1104 Plugin plugin = (Plugin) value;
1105 if(plugin.isSeparator()) {
1106 return separator;
1107 }
1108 else {
1109 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1110 }
1111 }
1112 }
1113
1114
1115 /** 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. */
1116 private class MoveListener
1117 implements ActionListener {
1118 /** 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.
1119 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1120 */
1121 public void actionPerformed(ActionEvent event) {
1122 if (!plugin_list.isSelectionEmpty()) {
1123 Object object = plugin_list.getSelectedValue();
1124 if (object instanceof Plugin) {
1125 Plugin plugin = (Plugin) object;
1126 //if (event.getSource() == move_top_button) {
1127 // movePlugin(plugin, true, true);
1128 //}
1129 //else
1130 if (event.getSource() == move_up_button) {
1131 movePlugin(plugin, true, false);
1132 }
1133 else if (event.getSource() == move_down_button) {
1134 movePlugin(plugin, false, false);
1135 }
1136 //else if (event.getSource() == move_bottom_button) {
1137 // movePlugin(plugin, false, true);
1138 //}
1139 plugin_list.setSelectedValue(plugin, true);
1140 }
1141 }
1142 }
1143 }
1144
1145 /** This listener reacts to changes in the current selection of the plugin combobox. */
1146 private class PluginComboboxListener
1147 implements ItemListener {
1148 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
1149 public void itemStateChanged(ItemEvent event) {
1150 if(event.getStateChange() == ItemEvent.SELECTED) {
1151 // Retrieve the selected plugin
1152 Object current_selection = plugin.getSelectedItem();
1153 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
1154 if(current_selection == null || current_selection instanceof String) {
1155 Dictionary.registerTooltip(plugin, "CDM.PlugInManager.PlugIn_Tooltip");
1156 }
1157 else {
1158 Plugin current_plugin = (Plugin) current_selection;
1159 Dictionary.registerTooltipText(plugin, Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
1160 current_plugin = null;
1161 }
1162 current_selection = null;
1163 }
1164 }
1165 }
1166
1167 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
1168 */
1169 private class RemoveListener
1170 implements ActionListener {
1171 /** 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.
1172 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
1173 */
1174 public void actionPerformed(ActionEvent event) {
1175 int selected_index = plugin_list.getSelectedIndex();
1176 if(selected_index != -1) {
1177 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
1178 removePlugin(selected_plugin);
1179 selected_plugin = null;
1180 // Select the next plugin if available
1181 if(selected_index < plugin_list.getModel().getSize()) {
1182 // If the new selection is above the separator we can remove it
1183 if(selected_index < findSeparatorIndex()) {
1184 plugin_list.setSelectedIndex(selected_index);
1185
1186 // don't let people remove special plugins such GAPlug an METSPlug,
1187 // unless they are in systems mode or above
1188 int mode = Configuration.getMode();
1189 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
1190 String selected_plugin_name
1191 = ((Plugin)plugin_list.getSelectedValue()).getName();
1192 if ((selected_plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
1193 (mode < Configuration.SYSTEMS_MODE)) {
1194 remove.setEnabled(false);
1195 break;
1196 } else {
1197 remove.setEnabled(true);
1198 }
1199 }
1200 }
1201 // Otherwise select the first non-removable plugin
1202 else {
1203 plugin_list.setSelectedIndex(selected_index + 1);
1204 remove.setEnabled(false);
1205 }
1206 }
1207 else {
1208 remove.setEnabled(false);
1209 }
1210 // Refresh the available plugins
1211 plugin.setModel(new DefaultComboBoxModel(getAvailable()));
1212 }
1213 else {
1214 remove.setEnabled(false);
1215 }
1216 }
1217 }
1218 }
1219
1220
1221 private class PluginSuggestionPrompt
1222 extends ModalDialog
1223 implements ActionListener
1224 {
1225 private Dimension size = new Dimension(480, 240);
1226 private GComboBox suitable_plugins_combobox = null;
1227 private GLIButton add_button = null;
1228 private GLIButton ignore_button = null;
1229
1230 public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
1231 {
1232 super(Gatherer.g_man, true);
1233 setModal(true);
1234 setSize(size);
1235 Dictionary.setText(this, "CDM.PluginManager.SuggestedPluginListTitle");
1236
1237 String[] args = new String[1];
1238 args[0] = filename;
1239
1240 JTextArea instructions_textarea = new JTextArea();
1241 instructions_textarea.setCaretPosition(0);
1242 instructions_textarea.setEditable(false);
1243 instructions_textarea.setLineWrap(true);
1244 instructions_textarea.setRows(5);
1245 instructions_textarea.setWrapStyleWord(true);
1246 Dictionary.setText(instructions_textarea, "CDM.PluginManager.Plugin_Suggestion_Prompt", args);
1247
1248 JLabel suitable_plugins_label = new JLabel();
1249 Dictionary.registerText(suitable_plugins_label, "CDM.PlugInManager.PlugIn");
1250 suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
1251
1252 suitable_plugins_combobox = new GComboBox(suitable_plugins);
1253 suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
1254 suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
1255 suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
1256 suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
1257
1258 JPanel suitable_plugins_pane = new JPanel();
1259 //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
1260 suitable_plugins_pane.setLayout(new BorderLayout(5,0));
1261 suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.WEST);
1262 suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
1263
1264 add_button = new GLIButton();
1265 Dictionary.setBoth(add_button, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
1266 ignore_button = new GLIButton();
1267 Dictionary.setBoth(ignore_button, "CDM.PlugInManager.Ignore","CDM.PlugInManager.Ignore_Tooltip" );
1268
1269 add_button.addActionListener(this);
1270 ignore_button.addActionListener(this);
1271
1272 JPanel button_pane = new JPanel();
1273 button_pane.setLayout(new GridLayout(1,2,5,0));
1274 button_pane.add(add_button);
1275 button_pane.add(ignore_button);
1276
1277 JPanel controls_pane = new JPanel();
1278 controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
1279 controls_pane.setLayout(new GridLayout(2,1,0,5));
1280 controls_pane.add(suitable_plugins_pane);
1281 controls_pane.add(button_pane);
1282
1283 JPanel content_pane = (JPanel) getContentPane();
1284 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
1285 content_pane.setLayout(new BorderLayout());
1286 content_pane.add(instructions_textarea, BorderLayout.CENTER);
1287 content_pane.add(controls_pane, BorderLayout.SOUTH);
1288
1289 // Show
1290 Dimension screen_size = Configuration.screen_size;
1291 setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
1292 setVisible(true);
1293 }
1294
1295 public void actionPerformed(ActionEvent event) {
1296
1297 if(event.getSource() == add_button) {
1298 // add the selected plugin to the list
1299 Object selected_object = suitable_plugins_combobox.getSelectedItem();
1300 Plugin base_plugin = getBasePlugin(selected_object.toString());
1301
1302 // Create a new element in the DOM
1303 Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
1304 // Remember that the plugin supplied might be a custom string rather than a base plugin
1305 Plugin new_plugin = null;
1306 if(base_plugin != null) {
1307 //DebugStream.println("New Plugin based on existing Plugin");
1308 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
1309 new_plugin = new Plugin(element, base_plugin);
1310 }
1311 else {
1312 //DebugStream.println("New Custom Plugin");
1313 element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
1314 new_plugin = new Plugin(element, null);
1315 }
1316 assignPlugin(new_plugin);
1317 } // else do nothing
1318
1319 // close the dialog
1320 setVisible(false);
1321 }
1322
1323 }
1324
1325
1326 /** Creates a list separator.
1327 * Found on Google Groups. Code courtesy of Paul Farwell.
1328 */
1329 private JPanel getSeparator() {
1330 // We put the separator inside a panel to control its appearance
1331 JPanel _sepPanel = new JPanel();
1332 _sepPanel.setOpaque(false);
1333 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1334 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1335 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1336 // 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
1337 _sepPanel.add(new BasicSeparator());
1338 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1339 return _sepPanel;
1340 }
1341
1342 /** 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. */
1343 private class BasicSeparator
1344 extends JSeparator {
1345
1346 private ComponentUI basic_ui;
1347
1348 public BasicSeparator() {
1349 super();
1350 basic_ui = new BasicSeparatorUI();
1351 }
1352
1353 public void paintComponent(Graphics g) {
1354 if (basic_ui != null) {
1355 basic_ui.update(g, this);
1356 }
1357 }
1358 }
1359}
Note: See TracBrowser for help on using the repository browser.