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

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

(MAJOR CHANGE) This is the remote Greenstone building functionality implemented for the West Yorkshire Fire and Rescue Service. It allows collections to be built without having a local version of Greenstone, using either a stand-alone version of the GLI or the applet.

The collections are stored on the server (allowing people to collaborate on collections -- but not at the same time), and only what is necessary to let the user edit the collection is downloaded. Any changes to the collection are uploaded to the server.

An access restriction mechanism is implemented which uses the standard Greenstone user database to control who has access to collections.

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