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

Last change on this file since 15109 was 15109, checked in by ak19, 16 years ago

Now works with replace_srcdoc_with_html.pl (mainly added 2 methods)

  • Property svn:keywords set to Author Date Id Revision
File size: 40.0 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.net.*;
33import java.util.*;
34import javax.swing.*;
35import javax.swing.event.*;
36import javax.swing.plaf.*;
37import javax.swing.plaf.basic.*;
38import org.apache.xerces.parsers.*;
39import org.greenstone.gatherer.Configuration;
40import org.greenstone.gatherer.DebugStream;
41import org.greenstone.gatherer.Dictionary;
42import org.greenstone.gatherer.Gatherer;
43import org.greenstone.gatherer.collection.CollectionContentsChangedListener;
44import org.greenstone.gatherer.collection.CollectionManager;
45import org.greenstone.gatherer.greenstone.Plugins;
46import org.greenstone.gatherer.gui.DesignPaneHeader;
47import org.greenstone.gatherer.gui.GComboBox;
48import org.greenstone.gatherer.gui.GLIButton;
49import org.greenstone.gatherer.gui.ModalDialog;
50import org.greenstone.gatherer.gui.WarningDialog;
51import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
52import org.greenstone.gatherer.util.JarTools;
53import org.greenstone.gatherer.util.StaticStrings;
54import org.greenstone.gatherer.util.Utility;
55import org.greenstone.gatherer.util.XMLTools;
56import org.w3c.dom.*;
57import org.xml.sax.*;
58
59
60/** This class is for maintaining a list of known plug-ins, and importing new plugins using the parser. */
61public class PluginManager
62 extends DOMProxyListModel
63 implements CollectionContentsChangedListener
64{
65 /** 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. */
66 private boolean modify_row_count = false;
67 /** The controls for editing the contents of this manager. */
68 private Control controls = null;
69 private DOMProxyListModel model;
70 private JPanel separator;
71 private Plugin separator_plugin;
72 /** Constructor.
73 */
74 public PluginManager() { super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.PLUGIN_ELEMENT, new Plugin());
75 DebugStream.println("PluginManager: " + super.getSize() + " plugins parsed.");
76 model = this;
77
78 // Force the assigned plugins to be loaded and cached now
79 for (int i = 0; i < getSize(); i++) {
80 getElementAt(i);
81 }
82
83 // Create the separator, cause we can reuse it.
84 separator = getSeparator();
85 placeSeparator();
86 // check for MetadataXMLPlug
87 ensureMetadataXMLPlugIsLoaded();
88 // Listen for CollectionContentsChanged events, so we can give plugin hints when new files are added
89 CollectionManager.addCollectionContentsChangedListener(this);
90
91 }
92
93 private void ensureMetadataXMLPlugIsLoaded() {
94
95 Plugin metaxmlplug = Plugins.getPlugin("MetadataXMLPlug", false);
96 if (metaxmlplug!= null) {
97 if (!contains(metaxmlplug)) {
98 // Create a new element in the DOM
99 Element new_plugin_element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
100 new_plugin_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, metaxmlplug.getName());
101 Plugin new_plugin = new Plugin(new_plugin_element, metaxmlplug);
102 assignPlugin(new_plugin);
103 }
104 }
105 }
106
107
108 /** Retrieve a list of the plugins that are available to be added to the collection. */
109 private Object[] getAvailablePlugins()
110 {
111 ArrayList available = new ArrayList();
112
113 // Add all the non-abstract core Greenstone plugins, except for ArcPlug and RecPlug
114 ArrayList plugins_list = Plugins.getPluginsList();
115 for (int i = 0; i < plugins_list.size(); i++) {
116 Plugin plugin = (Plugin) plugins_list.get(i);
117 if (!plugin.isAbstract()) {
118 String plugin_name = plugin.getName();
119 if (!plugin_name.equals(StaticStrings.ARCPLUG_STR) && !plugin_name.equals(StaticStrings.RECPLUG_STR)) {
120 available.add(plugin);
121 }
122 }
123 }
124
125 // Now remove any assigned plugins
126 if (Configuration.getMode() < Configuration.SYSTEMS_MODE) {
127 available.removeAll(children());
128 }
129
130 // Sort the available plugins into alphabetical order
131 Collections.sort(available);
132
133 return available.toArray();
134 }
135
136
137 public ArrayList getExploderPlugins(File file)
138 {
139 ArrayList exploder_plugins = new ArrayList();
140 ArrayList plugins_list = Plugins.getPluginsList();
141 for (int i = 0; i < plugins_list.size(); i++) {
142 Plugin plugin = (Plugin) plugins_list.get(i);
143 if (plugin.doesExplodeMetadataDatabases() == true && plugin.doesProcessFile(file)) {
144 exploder_plugins.add(plugin);
145 }
146 }
147
148 return exploder_plugins;
149 }
150
151 public boolean isFileExplodable(File file)
152 {
153 ArrayList plugins_list = Plugins.getPluginsList();
154 for (int i = 0; i < plugins_list.size(); i++) {
155 Plugin plugin = (Plugin) plugins_list.get(i);
156 if (plugin.doesExplodeMetadataDatabases() == true && plugin.doesProcessFile(file) == true) {
157 return true;
158 }
159 }
160
161 return false;
162 }
163
164 // Works with replace_srcdoc_with_html.pl
165 public ArrayList getSrcReplacerPlugins(File file)
166 {
167 ArrayList srcreplacer_plugins = new ArrayList();
168 ArrayList plugins_list = Plugins.getPluginsList();
169 for (int i = 0; i < plugins_list.size(); i++) {
170 Plugin plugin = (Plugin) plugins_list.get(i);
171 if (plugin.doesReplaceSrcDocsWithHtml() == true && plugin.doesProcessFile(file)) {
172 srcreplacer_plugins.add(plugin);
173 }
174 }
175
176 return srcreplacer_plugins;
177 }
178
179 // Works with replace_srcdoc_with_html.pl
180 public boolean isFileSrcReplaceable(File file)
181 {
182 ArrayList plugins_list = Plugins.getPluginsList();
183 for (int i = 0; i < plugins_list.size(); i++) {
184 Plugin plugin = (Plugin) plugins_list.get(i);
185
186 if (plugin.doesReplaceSrcDocsWithHtml() == true && plugin.doesProcessFile(file) == true) {
187 return true;
188 }
189 }
190
191 return false;
192 }
193
194 /** Method to assign a plugin
195 * @param plugin the Plugin to assign
196 */
197 private void assignPlugin(Plugin plugin) {
198 if(plugin.getName().equals(StaticStrings.RECPLUG_STR) || plugin.getName().equals(StaticStrings.ARCPLUG_STR)) {
199 addAfter(plugin, separator_plugin); // Adds after separator
200 } else {
201 addBefore(plugin, separator_plugin);
202 }
203 }
204
205
206 /** Destructor. */
207 public void destroy()
208 {
209 CollectionManager.removeCollectionContentsChangedListener(this);
210
211 if (controls != null) {
212 controls.destroy();
213 controls = null;
214 }
215 }
216
217
218 /** This function listens for new files being added to the collection and hints about suitable plugins. */
219 public void fileAddedToCollection(File file)
220 {
221 // First check the plugins already assigned in the collection
222 for (int i = 0; i < super.getSize(); i++) {
223 Plugin assigned_plugin = (Plugin) getElementAt(i);
224 if (assigned_plugin.isSeparator() == false && (assigned_plugin.doesProcessFile(file) == true || assigned_plugin.doesBlockFile(file) == true)) {
225 // This file will be processed by an assigned plugin, so no suggestion is necessary
226 DebugStream.println("Processed by assigned plugin: " + assigned_plugin);
227 return;
228 }
229 }
230
231 // Next try the plugins NOT already assigned in the collection
232 ArrayList suitable_plugins = new ArrayList();
233 Object[] unassigned_plugins = getAvailablePlugins();
234 for (int i = 0; i < unassigned_plugins.length; i++) {
235 Plugin unassigned_plugin = (Plugin) unassigned_plugins[i];
236 if (unassigned_plugin.doesProcessFile(file) == true) {
237 DebugStream.println("Processed by unassigned plugin: " + unassigned_plugin);
238 suitable_plugins.add(unassigned_plugin);
239 }
240 }
241
242 // If there appear to be no suitable plugins, warn the user about this and be done
243 if (suitable_plugins.size() == 0) {
244 String[] args = new String[1];
245 args[0] = file.getName();
246 WarningDialog warning_dialog = new WarningDialog("warning.NoPluginExpectedToProcessFile", Dictionary.get("NoPluginExpectedToProcessFile.Title"), Dictionary.get("NoPluginExpectedToProcessFile.Message", args), null, false);
247 warning_dialog.display();
248 warning_dialog.dispose();
249 return;
250 }
251
252 // Generate a dialog
253 new PluginSuggestionPrompt(file.getName(), suitable_plugins);
254 }
255
256
257 /** Method to retrieve the control for this manager.
258 * @return the Control
259 */
260 public Control getControls() {
261 if(controls == null) {
262 // Build controls
263 controls = new PluginControl();
264 }
265 return controls;
266 }
267
268
269 /** Overrides getSize in DOMProxyListModel to take into account the row count modifier used to hide the last three rows in lower detail modes
270 * @return an int indicating the number of rows in the model, or more correctly the desired number of rows to display
271 */
272 public int getSize() {
273 int result = super.getSize();
274 if(modify_row_count) {
275 result = result-3;
276 }
277 return result;
278 }
279
280 /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
281 * @param mode the new mode as an int
282 */
283 public void modeChanged(int mode) {
284 if(controls != null) {
285 ((PluginControl)controls).modeChanged(mode);
286 }
287 }
288
289 /** Method to move a plugin in the list order.
290 * @param plugin the Plugin you want to move.
291 * @param direction true to move the plugin up, false to move it down.
292 * @param all true to move to move all the way, false for a single step.
293 */
294 // why are all the error notices there when the buttons are disabled is you cant move???
295 private void movePlugin(Plugin plugin, boolean direction, boolean all) {
296 // Can't ever move RecPlug or ArcPlug
297 if(super.getSize() < 4) {
298 //DebugStream.println("Not enough plugins to allow moving.");
299 return;
300 }
301 if(plugin.getName().equals(StaticStrings.ARCPLUG_STR) || plugin.getName().equals(StaticStrings.RECPLUG_STR)) {
302 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.Fixed"), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
303 return;
304 }
305 if(all) {
306 // Move to top
307 if(direction) {
308 // Remove the moving plugin
309 remove(plugin);
310 // Retrieve the first plugin
311 Plugin first_plugin = (Plugin) getElementAt(0);
312 // Add the moving plugin before the first plugin
313 addBefore(plugin, first_plugin);
314 first_plugin = null;
315 }
316 else {
317 // Remove the moving plugin
318 remove(plugin);
319 // Add the moving plugin before the separator
320 addBefore(plugin, separator_plugin);
321 }
322 }
323 else {
324 // Try to move the plugin one step in the desired direction.
325 int index = indexOf(plugin);
326 ///ystem.err.println("Index of " + plugin + " = " + index);
327 if(direction) {
328 index--;
329 if(index < 0) {
330 String args[] = new String[2];
331 args[0] = Dictionary.get("CDM.PlugInManager.PlugIn_Str");
332 args[1] = plugin.getName();
333 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Top", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
334 return;
335 }
336 remove(plugin);
337 add(index, plugin);
338 }
339 else {
340 index++;
341 Plugin next_plugin = (Plugin) getElementAt(index);
342 if(next_plugin.isSeparator()) {
343 String args[] = new String[1];
344 args[0] = plugin.getName();
345 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.Cannot", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
346 // Still not going to move RecPlug or ArcPlug.
347 return;
348 }
349 remove(plugin);
350 add(index, plugin);
351 }
352 }
353 }
354
355 /** 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.
356 */
357 private void placeSeparator() {
358 ///ystem.err.println("Placing separator.");
359 int separator_index = super.getSize();
360 if(separator_index > 0) {
361 boolean found_fixed = false;
362 int index = separator_index - 1;
363 while(index > 0) {
364 Plugin plugin = (Plugin) getElementAt(index);
365 String name = plugin.getName();
366 if(name.equals(StaticStrings.RECPLUG_STR) || name.equals(StaticStrings.ARCPLUG_STR)) {
367 found_fixed = true;
368 index--;
369 }
370 else {
371 if(found_fixed) {
372 separator_index = index + 1;
373 index = -1;
374 }
375 else {
376 index--;
377 }
378 }
379 name = null;
380 plugin = null;
381 }
382 }
383 Element element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
384 element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, StaticStrings.SEPARATOR_ATTRIBUTE);
385 element.setAttribute(StaticStrings.SEPARATOR_ATTRIBUTE, StaticStrings.TRUE_STR);
386 separator_plugin = new Plugin(element, null);
387 ///atherer.println("Adding plugin separator at: " + separator_index);
388 add(separator_index, separator_plugin);
389 }
390
391 /** 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.
392 * @param plugin The <strong>Plugin</strong> to remove.
393 */
394 private void removePlugin(Plugin plugin) {
395 remove(plugin);
396
397 }
398
399
400 /** Inform the model to hide/show the last three lines on the list.
401 * @param modify_row_count true to hide the last three lines, false otherwise
402 */
403 private void setHideLines(boolean modify_row_count) {
404 this.modify_row_count = modify_row_count;
405 int original_size = super.getSize();
406 if(modify_row_count) {
407 fireIntervalRemoved(this, original_size - 4, original_size - 1);
408 }
409 else {
410 fireIntervalAdded(this, original_size - 4, original_size - 1);
411 }
412 }
413
414 /** Determine the current separator index. */
415 private int findSeparatorIndex() {
416 int separator_index = super.getSize() - 1;
417 while(separator_index >= 0) {
418 Plugin search = (Plugin) getElementAt(separator_index);
419 if(search.isSeparator()) {
420 return separator_index;
421 }
422 separator_index--;
423 }
424 return separator_index;
425 }
426
427
428 /** A class which provodes controls for assigned and editing plugins. */
429 private class PluginControl
430 extends JPanel
431 implements Control {
432 /** Button for adding plugins. */
433 private JButton add = null;
434 /** Button for configuring the selected plugin. */
435 private JButton configure = null;
436 /** Button to move an assigned plugin one position lower in the order. */
437 private JButton move_down_button = null;
438 /** Button to move an assigned plugin one position higher in the order. */
439 private JButton move_up_button = null;
440 /** Button to remove the selected plugin. */
441 private JButton remove = null;
442 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
443 private JComboBox plugin_combobox = null;
444 /** The label next to the plugin combobox. */
445 private JLabel plugin_label = null;
446 /** The label above the assigned plugin list. */
447 private JLabel plugin_list_label = null;
448 /** A list of assigned plugins. */
449 private JList plugin_list = null;
450 /** The area where the add, configure and remove buttons are placed. */
451 private JPanel button_pane = null;
452 /** The region which divides the central portion of the view into list and controls */
453 private JPanel central_pane = null;
454 /** The area where movement buttons are placed. */
455 private JPanel movement_pane = null;
456 /** The small region containing the plugin combobox and its label. */
457 private JPanel plugin_pane = null;
458 /** The pane containing the assigned plugin list and its label. */
459 private JPanel plugin_list_pane = null;
460
461 /** Constructor.
462 */
463 public PluginControl()
464 {
465 // Create
466 add = new GLIButton(Dictionary.get("CDM.PlugInManager.Add"), Dictionary.get("CDM.PlugInManager.Add_Tooltip"));
467
468 button_pane = new JPanel();
469 central_pane = new JPanel();
470
471 configure = new GLIButton(Dictionary.get("CDM.PlugInManager.Configure"), Dictionary.get("CDM.PlugInManager.Configure_Tooltip"));
472 configure.setEnabled(false);
473
474 JPanel header_pane = new DesignPaneHeader("CDM.GUI.Plugins", "plugins");
475 move_up_button = new GLIButton(Dictionary.get("CDM.Move.Move_Up"), JarTools.getImage("arrow-up.gif"), Dictionary.get("CDM.Move.Move_Up_Tooltip"));
476 move_up_button.setEnabled(false);
477
478 move_down_button = new GLIButton(Dictionary.get("CDM.Move.Move_Down"), JarTools.getImage("arrow-down.gif"), Dictionary.get("CDM.Move.Move_Down_Tooltip"));
479 move_down_button.setEnabled(false);
480
481 movement_pane = new JPanel();
482
483 PluginComboboxListener picl = new PluginComboboxListener();
484 plugin_combobox = new JComboBox(getAvailablePlugins());
485 plugin_combobox.setOpaque(!Utility.isMac());
486 plugin_combobox.setEditable(false);
487 picl.itemStateChanged(new ItemEvent(plugin_combobox, 0, null, ItemEvent.SELECTED));
488
489 plugin_label = new JLabel(Dictionary.get("CDM.PlugInManager.PlugIn"));
490
491 plugin_list = new JList(model);
492 plugin_list.setOpaque(true);
493 plugin_list.setCellRenderer(new ListRenderer());
494 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
495 plugin_list_label = new JLabel(Dictionary.get("CDM.PlugInManager.Assigned"));
496 //plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
497 plugin_list_label.setOpaque(true);
498
499 plugin_list_pane = new JPanel();
500 plugin_pane = new JPanel();
501 plugin_pane.setOpaque(true);
502
503 remove = new GLIButton(Dictionary.get("CDM.PlugInManager.Remove"), Dictionary.get("CDM.PlugInManager.Remove_Tooltip"));
504 remove.setEnabled(false);
505
506 // Listeners
507 add.addActionListener(new AddListener());
508 configure.addActionListener(new ConfigureListener());
509 MoveListener ml = new MoveListener();
510 move_down_button.addActionListener(ml);
511 move_down_button.addActionListener(CollectionDesignManager.all_change_listener);
512 move_up_button.addActionListener(ml);
513 move_up_button.addActionListener(CollectionDesignManager.all_change_listener);
514 plugin_combobox.addItemListener(picl);
515 remove.addActionListener(new RemoveListener());
516 remove.addActionListener(CollectionDesignManager.all_change_listener);
517 plugin_list.addMouseListener(new ClickListener());
518 plugin_list.addListSelectionListener(new ListListener());
519 picl = null;
520
521 // Layout
522 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
523 movement_pane.setLayout(new GridLayout(4,1));
524 movement_pane.add(move_up_button);
525 movement_pane.add(new JPanel());
526 movement_pane.add(new JPanel());
527 movement_pane.add(move_down_button);
528
529 plugin_list_pane.setLayout(new BorderLayout());
530 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
531 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
532 modeChanged(Configuration.getMode()); // Whether the movement buttons are visible is mode dependant
533
534 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
535
536 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
537 plugin_pane.setLayout(new BorderLayout(5,0));
538 plugin_pane.add(plugin_label, BorderLayout.WEST);
539 plugin_pane.add(plugin_combobox, BorderLayout.CENTER);
540
541 button_pane.setLayout(new GridLayout(1,3));
542 button_pane.add(add);
543 button_pane.add(configure);
544 button_pane.add(remove);
545
546 // Scope these mad bordering skillz.
547 JPanel temp = new JPanel(new BorderLayout());
548 temp.add(plugin_pane, BorderLayout.NORTH);
549 temp.add(button_pane, BorderLayout.SOUTH);
550
551 central_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
552 central_pane.setLayout(new BorderLayout());
553 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
554 central_pane.add(temp, BorderLayout.SOUTH);
555
556 setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
557 setLayout(new BorderLayout());
558 add(header_pane, BorderLayout.NORTH);
559 add(central_pane, BorderLayout.CENTER);
560 }
561
562 /** Method which acts like a destructor, tidying up references to persistant objects.
563 */
564 public void destroy() {
565 }
566
567 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
568 no longer have instructions, do we still need updateUI???
569 */
570 public void gainFocus() {
571 super.updateUI();
572 }
573
574 public void loseFocus() {
575 }
576
577 /** 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
578 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
579 */
580 public void modeChanged(int mode) {
581 // 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
582 plugin_list.clearSelection();
583 // The first change is dependant on whether the user is systems mode or higher
584
585 plugin_combobox.setModel(new DefaultComboBoxModel(getAvailablePlugins()));
586
587 if(mode >= Configuration.SYSTEMS_MODE) {
588 // Show movement buttons
589
590 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
591 // Do we show Arc and RecPlugs or hide them and the separator line
592 setHideLines(!(mode >= Configuration.EXPERT_MODE));
593 }
594 // Otherwise hide the movement buttons and fixed plugins
595 else {
596 plugin_list_pane.remove(movement_pane);
597 setHideLines(true);
598 }
599 plugin_list_pane.updateUI();
600 }
601
602
603 private class AddListener
604 implements ActionListener
605 {
606 public void actionPerformed(ActionEvent event)
607 {
608 if (plugin_combobox.getSelectedItem() != null) {
609 // This must be done on a new thread for the remote building code
610 new AddPluginTask(plugin_combobox.getSelectedItem().toString()).start();
611 }
612 }
613 }
614
615
616 private class AddPluginTask
617 extends Thread
618 {
619 private String plugin_name;
620
621 public AddPluginTask(String plugin_name)
622 {
623 this.plugin_name = plugin_name;
624 }
625
626 public void run()
627 {
628 // Retrieve the plugin
629 Plugin plugin = Plugins.getPlugin(plugin_name, true);
630 if (plugin == null) {
631 System.err.println("Error: getPlugin() returned null.");
632 return;
633 }
634
635 // Create a new element in the DOM
636 Element new_plugin_element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
637 new_plugin_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, plugin.getName());
638 Plugin new_plugin = new Plugin(new_plugin_element, plugin);
639
640 ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
641 ac.addOKButtonActionListener(CollectionDesignManager.all_change_listener);
642 if (ac.display()) {
643 assignPlugin(new_plugin);
644 plugin_list.setSelectedValue(new_plugin, true);
645
646 // Remove the plugin from the available list (unless we're in a high mode, or it's UnknownPlug)
647 if (Configuration.getMode() < Configuration.SYSTEMS_MODE && !plugin_name.equals(StaticStrings.UNKNOWNPLUG_STR)) {
648 plugin_combobox.removeItem(plugin);
649 plugin_combobox.setSelectedIndex(0);
650 }
651 }
652 }
653 }
654
655
656 /** Listens for double clicks apon the list and react as if the configure button was pushed. */
657 private class ClickListener
658 extends MouseAdapter {
659 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
660 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
661 */
662 public void mouseClicked(MouseEvent event) {
663 if(event.getClickCount() == 2 ) {
664 if(!plugin_list.isSelectionEmpty()) {
665 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
666 if(!plugin.isSeparator()) {
667 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
668 ac.addOKButtonActionListener(CollectionDesignManager.all_change_listener);
669 if (ac.display()) {
670 refresh(plugin);
671 }
672 ac.destroy();
673 ac = null;
674 }
675 }
676 }
677 }
678 }
679
680 /** 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.
681 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
682 */
683 private class ConfigureListener
684 implements ActionListener {
685 /** 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.
686 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
687 */
688 public void actionPerformed(ActionEvent event) {
689 if(!plugin_list.isSelectionEmpty()) {
690 Plugin plugin = (Plugin) plugin_list.getSelectedValue();
691 if(!plugin.isSeparator()) {
692 ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
693 ac.addOKButtonActionListener(CollectionDesignManager.all_change_listener);
694 if (ac.display()) {
695 refresh(plugin);
696 }
697 ac.destroy();
698 ac = null;
699 }
700 }
701 }
702 }
703
704 /** 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 */
705 private class ListListener
706 implements ListSelectionListener {
707
708 public void valueChanged(ListSelectionEvent e) {
709 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one (the second one)
710 if (plugin_list.isSelectionEmpty()) {
711 move_up_button.setEnabled(false);
712 move_down_button.setEnabled(false);
713 configure.setEnabled(false);
714 remove.setEnabled(false);
715 } else {
716 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
717 if(selected_plugin.isSeparator()) {
718 move_up_button.setEnabled(false);
719 move_down_button.setEnabled(false);
720 configure.setEnabled(false);
721 remove.setEnabled(false);
722 } else {
723 configure.setEnabled(true);
724 String plugin_name = selected_plugin.getName();
725 // Some buttons are only available for plugins other than ArcPlug and RecPlug
726 if(plugin_name.equals(StaticStrings.ARCPLUG_STR) || plugin_name.equals(StaticStrings.RECPLUG_STR) ) {
727 move_up_button.setEnabled(false);
728 move_down_button.setEnabled(false);
729 remove.setEnabled(false);
730 } else if (plugin_name.equals(StaticStrings.METADATAXMLPLUG_STR)) {
731 remove.setEnabled(false);
732 }
733
734 else {
735 // don't let people remove special plugins such GAPlug an METSPlug,
736 // unless they are in systems mode or above
737 int mode = Configuration.getMode();
738 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
739 if ((plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
740 (mode < Configuration.SYSTEMS_MODE)) {
741 remove.setEnabled(false);
742 break;
743 } else {
744 remove.setEnabled(true);
745 }
746 }
747
748 // Move ups are only enabled if the selected plugin isn't already at the top
749 Plugin first_plugin = (Plugin) getElementAt(0);
750 if(!first_plugin.equals(selected_plugin)) {
751 move_up_button.setEnabled(true);
752 } else {
753 move_up_button.setEnabled(false);
754 }
755 // And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
756 int separator_index = findSeparatorIndex();
757 int selected_index = plugin_list.getSelectedIndex();
758 if(selected_index < separator_index - 1) {
759 move_down_button.setEnabled(true);
760 } else {
761 move_down_button.setEnabled(false);
762 }
763 }
764 selected_plugin = null;
765 plugin_name = null;
766 }
767 }
768 }
769 }
770 }
771
772 /** A special list renderer which is able to render separating lines as well. */
773 private class ListRenderer
774 extends DefaultListCellRenderer {
775 /** 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.
776 * @param list - The <strong>JList</strong> we're painting.
777 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
778 * @param index - The cells index as an <i>int</i>.
779 * @param isSelected - <i>true</i> if the specified cell was selected.
780 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
781 * @return A <strong>Component</strong> whose paint() method will render the specified value.
782 * @see javax.swing.JList
783 * @see javax.swing.JSeparator
784 * @see javax.swing.ListModel
785 * @see javax.swing.ListSelectionModel
786 */
787 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
788 Plugin plugin = (Plugin) value;
789 if(plugin.isSeparator()) {
790 return separator;
791 }
792 else {
793 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
794 }
795 }
796 }
797
798
799 /** 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. */
800 private class MoveListener
801 implements ActionListener {
802 /** 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.
803 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
804 */
805 public void actionPerformed(ActionEvent event) {
806 if (!plugin_list.isSelectionEmpty()) {
807 Object object = plugin_list.getSelectedValue();
808 if (object instanceof Plugin) {
809 Plugin plugin = (Plugin) object;
810 if (event.getSource() == move_up_button) {
811 movePlugin(plugin, true, false);
812 }
813 else if (event.getSource() == move_down_button) {
814 movePlugin(plugin, false, false);
815 }
816 plugin_list.setSelectedValue(plugin, true);
817 }
818 }
819 }
820 }
821
822 /** This listener reacts to changes in the current selection of the plugin combobox. */
823 private class PluginComboboxListener
824 implements ItemListener {
825 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
826 public void itemStateChanged(ItemEvent event) {
827 if(event.getStateChange() == ItemEvent.SELECTED) {
828 // Retrieve the selected plugin
829 Object current_selection = plugin_combobox.getSelectedItem();
830 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
831 if(current_selection == null || current_selection instanceof String) {
832 plugin_combobox.setToolTipText(Dictionary.get("CDM.PlugInManager.PlugIn_Tooltip"));
833 }
834 else {
835 Plugin current_plugin = (Plugin) current_selection;
836 plugin_combobox.setToolTipText(Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
837 current_plugin = null;
838 }
839 current_selection = null;
840 }
841 }
842 }
843
844 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
845 */
846 private class RemoveListener
847 implements ActionListener {
848 /** 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.
849 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
850 */
851 public void actionPerformed(ActionEvent event) {
852 int selected_index = plugin_list.getSelectedIndex();
853 if(selected_index != -1) {
854 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
855 removePlugin(selected_plugin);
856 selected_plugin = null;
857 // Refresh the available plugins
858 plugin_combobox.setModel(new DefaultComboBoxModel(getAvailablePlugins()));
859
860 // Select the next plugin if available
861 if(selected_index < plugin_list.getModel().getSize()) {
862 // If the new selection is above the separator we can remove it
863 if(selected_index < findSeparatorIndex()) {
864 plugin_list.setSelectedIndex(selected_index);
865
866 // don't let people remove special plugins such GAPlug an METSPlug,
867 // unless they are in systems mode or above
868 int mode = Configuration.getMode();
869 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
870 String selected_plugin_name
871 = ((Plugin)plugin_list.getSelectedValue()).getName();
872
873 if (selected_plugin_name.equals(StaticStrings.METADATAXMLPLUG_STR)) {
874 //this plug cannot be removed under any conditions.
875 remove.setEnabled(false);
876 }else if ((selected_plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
877 (mode < Configuration.SYSTEMS_MODE)) {
878 remove.setEnabled(false);
879 break;
880 } else {
881 remove.setEnabled(true);
882 }
883 }
884 }
885 // Otherwise select the first non-removable plugin
886 else {
887 plugin_list.setSelectedIndex(selected_index + 1);
888 remove.setEnabled(false);
889 }
890 } else {
891 remove.setEnabled(false);
892 }
893 } else {
894 remove.setEnabled(false);
895 }
896 }
897 }
898 }
899
900
901 private class PluginSuggestionPrompt
902 extends ModalDialog
903 implements ActionListener
904 {
905 private Dimension size = new Dimension(480, 240);
906 private GComboBox suitable_plugins_combobox = null;
907 private GLIButton add_button = null;
908 private GLIButton ignore_button = null;
909
910 public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
911 {
912 super(Gatherer.g_man, true);
913 setModal(true);
914 setSize(size);
915 setTitle(Dictionary.get("CDM.PluginManager.SuggestedPluginListTitle"));
916
917 String[] args = new String[1];
918 args[0] = filename;
919
920 JTextArea instructions_textarea = new JTextArea(Dictionary.get("CDM.PluginManager.Plugin_Suggestion_Prompt", args));
921 instructions_textarea.setCaretPosition(0);
922 instructions_textarea.setEditable(false);
923 instructions_textarea.setLineWrap(true);
924 instructions_textarea.setRows(5);
925 instructions_textarea.setWrapStyleWord(true);
926
927 JLabel suitable_plugins_label = new JLabel(Dictionary.get("CDM.PlugInManager.PlugIn"));
928 suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
929
930 suitable_plugins_combobox = new GComboBox(suitable_plugins);
931 suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
932 suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
933 suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
934 suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
935
936 JPanel suitable_plugins_pane = new JPanel();
937 //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
938 suitable_plugins_pane.setLayout(new BorderLayout(5,0));
939 suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.WEST);
940 suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
941
942 add_button = new GLIButton(Dictionary.get("CDM.PlugInManager.QuickAdd"), Dictionary.get("CDM.PlugInManager.Add_Tooltip"));
943 ignore_button = new GLIButton(Dictionary.get("CDM.PlugInManager.Ignore"), Dictionary.get("CDM.PlugInManager.Ignore_Tooltip"));
944
945 add_button.addActionListener(this);
946 ignore_button.addActionListener(this);
947
948 JPanel button_pane = new JPanel();
949 button_pane.setLayout(new GridLayout(1,2,5,0));
950 button_pane.add(add_button);
951 button_pane.add(ignore_button);
952
953 JPanel controls_pane = new JPanel();
954 controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
955 controls_pane.setLayout(new GridLayout(2,1,0,5));
956 controls_pane.add(suitable_plugins_pane);
957 controls_pane.add(button_pane);
958
959 JPanel content_pane = (JPanel) getContentPane();
960 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
961 content_pane.setLayout(new BorderLayout());
962 content_pane.add(instructions_textarea, BorderLayout.CENTER);
963 content_pane.add(controls_pane, BorderLayout.SOUTH);
964
965 // Show
966 Dimension screen_size = Configuration.screen_size;
967 setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
968 setVisible(true);
969 }
970
971
972 public void actionPerformed(ActionEvent event)
973 {
974 // Close the dialog
975 setVisible(false);
976
977 if (event.getSource() == add_button) {
978 AddPluginWithoutConfigurationTask add_plugin_task = new AddPluginWithoutConfigurationTask(suitable_plugins_combobox.getSelectedItem().toString());
979 add_plugin_task.start();
980
981 // We have to wait for this task to complete before continuing, otherwise
982 // we might offer to add the same plugin again before the task has completed
983 try {
984 add_plugin_task.join();
985 }
986 catch (Exception exception) {
987 DebugStream.printStackTrace(exception);
988 }
989 }
990 }
991
992
993 private class AddPluginWithoutConfigurationTask
994 extends Thread
995 {
996 private String plugin_name;
997
998 public AddPluginWithoutConfigurationTask(String plugin_name)
999 {
1000 this.plugin_name = plugin_name;
1001 }
1002
1003 public void run()
1004 {
1005 // Retrieve the plugin
1006 Plugin plugin = Plugins.getPlugin(plugin_name, true);
1007 if (plugin == null) {
1008 System.err.println("Error: getPlugin() returned null.");
1009 return;
1010 }
1011
1012 // Create a new element in the DOM
1013 Element new_plugin_element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
1014 new_plugin_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, plugin.getName());
1015 Plugin new_plugin = new Plugin(new_plugin_element, plugin);
1016
1017 // Just assign the plugin with no argument configuration
1018 assignPlugin(new_plugin);
1019 }
1020 }
1021 }
1022
1023
1024 /** Creates a list separator.
1025 * Found on Google Groups. Code courtesy of Paul Farwell.
1026 */
1027 private JPanel getSeparator() {
1028 // We put the separator inside a panel to control its appearance
1029 JPanel _sepPanel = new JPanel();
1030 _sepPanel.setOpaque(false);
1031 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1032 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1033 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1034 // 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
1035 _sepPanel.add(new BasicSeparator());
1036 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1037 return _sepPanel;
1038 }
1039
1040 /** 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. */
1041 private static class BasicSeparator
1042 extends JSeparator {
1043
1044 private ComponentUI basic_ui;
1045
1046 public BasicSeparator() {
1047 super();
1048 basic_ui = new BasicSeparatorUI();
1049 }
1050
1051 public void paintComponent(Graphics g) {
1052 if (basic_ui != null) {
1053 basic_ui.update(g, this);
1054 }
1055 }
1056 }
1057}
Note: See TracBrowser for help on using the repository browser.