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

Last change on this file since 11031 was 11031, checked in by kjdon, 18 years ago

removed instructions, changed title to be the same string as in the contents, and use a new class DesignPaneHeader to create teh header which has title and help button

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