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

Last change on this file since 24414 was 24414, checked in by ak19, 13 years ago

To do with EmbeddedMetadataPlugin: 1.mkcol.pl and GLI changes puts the plugin in the bottom four plugins of the plugin pipeline. 2. EmbeddedMetadataPlugin and PDFPlugin are modified to work together again after the recent changes (introduction of overridable BasePlugin method can_process_file_for_metadata) which were needed to get the EmbeddedMetadataPlugin and OAIPlugin to work together.

  • Property svn:keywords set to Author Date Id Revision
File size: 41.7 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.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 /** When asking how many rows are in the model, and if this variables value is true, then this modifier alters the number returned. This funtionality is used to hide the last three rows of the list in low detail modes. */
65 private boolean modify_row_count = false;
66 /** The controls for editing the contents of this manager. */
67 private Control controls = null;
68 private DOMProxyListModel model;
69 private JPanel separator;
70 private Plugin separator_plugin;
71
72 /** The number of plugins that are fixed 'below the line' */
73 private static int NUM_FIXED_PLUGINS = 4;
74 /** Constructor.
75 */
76 public PluginManager() { super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.PLUGIN_ELEMENT, new Plugin());
77 DebugStream.println("PluginManager: " + super.getSize() + " plugins parsed.");
78 model = this;
79
80 // Force the assigned plugins to be loaded and cached now
81 for (int i = 0; i < getSize(); i++) {
82 getElementAt(i);
83 }
84
85 // Create the separator, cause we can reuse it.
86 separator = getSeparator();
87 placeSeparator();
88 // check for MetadataXMLPlug
89 ensureMetadataXMLPlugIsLoaded();
90 // Listen for CollectionContentsChanged events, so we can give plugin hints when new files are added
91 CollectionManager.addCollectionContentsChangedListener(this);
92
93 }
94
95 private void ensureMetadataXMLPlugIsLoaded() {
96
97 Plugin metaxmlplug = Plugins.getPlugin(StaticStrings.METADATAXMLPLUG_STR, false);
98 if (metaxmlplug!= null) {
99 if (!contains(metaxmlplug)) {
100 // Create a new element in the DOM
101 Element new_plugin_element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
102 new_plugin_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, metaxmlplug.getName());
103 Plugin new_plugin = new Plugin(new_plugin_element, metaxmlplug);
104 assignPlugin(new_plugin);
105 }
106 }
107 }
108
109
110 /** Retrieve a list of the plugins that are available to be added to the collection. */
111 private Object[] getAvailablePlugins()
112 {
113 ArrayList available = new ArrayList();
114
115 // Add all the non-abstract core Greenstone plugins, except for ArcPlug and RecPlug
116 ArrayList plugins_list = Plugins.getPluginsList();
117 for (int i = 0; i < plugins_list.size(); i++) {
118 Plugin plugin = (Plugin) plugins_list.get(i);
119 if (!plugin.isAbstract()) {
120 String plugin_name = plugin.getName();
121 if (!plugin_name.equals(StaticStrings.ARCPLUG_STR) && !plugin_name.equals(StaticStrings.RECPLUG_STR)
122 && !plugin_name.equals(StaticStrings.METADATAXMLPLUG_STR) && !plugin_name.equals(StaticStrings.EMBEDMETAPLUG_STR)) {
123 available.add(plugin);
124 }
125 }
126 }
127
128 // Sort the available plugins into alphabetical order
129 Collections.sort(available);
130
131 return available.toArray();
132 }
133
134
135 public ArrayList getExploderPlugins(File file)
136 {
137 ArrayList exploder_plugins = new ArrayList();
138 ArrayList plugins_list = Plugins.getPluginsList();
139 for (int i = 0; i < plugins_list.size(); i++) {
140 Plugin plugin = (Plugin) plugins_list.get(i);
141 if (plugin.doesExplodeMetadataDatabases() == true && plugin.doesProcessFile(file)) {
142 exploder_plugins.add(plugin);
143 }
144 }
145
146 return exploder_plugins;
147 }
148
149 public boolean isFileExplodable(File file)
150 {
151 ArrayList plugins_list = Plugins.getPluginsList();
152 for (int i = 0; i < plugins_list.size(); i++) {
153 Plugin plugin = (Plugin) plugins_list.get(i);
154 if (plugin.doesExplodeMetadataDatabases() == true && plugin.doesProcessFile(file) == true) {
155 return true;
156 }
157 }
158
159 return false;
160 }
161
162 // Works with replace_srcdoc_with_html.pl
163 public ArrayList getSrcReplacerPlugins(File file)
164 {
165 ArrayList srcreplacer_plugins = new ArrayList();
166 ArrayList plugins_list = Plugins.getPluginsList();
167 for (int i = 0; i < plugins_list.size(); i++) {
168 Plugin plugin = (Plugin) plugins_list.get(i);
169 if (plugin.doesReplaceSrcDocsWithHtml() == true && plugin.doesProcessFile(file)) {
170 srcreplacer_plugins.add(plugin);
171 }
172 }
173
174 return srcreplacer_plugins;
175 }
176
177 // Works with replace_srcdoc_with_html.pl
178 public boolean isFileSrcReplaceable(File file)
179 {
180 ArrayList plugins_list = Plugins.getPluginsList();
181 for (int i = 0; i < plugins_list.size(); i++) {
182 Plugin plugin = (Plugin) plugins_list.get(i);
183
184 if (plugin.doesReplaceSrcDocsWithHtml() == true && plugin.doesProcessFile(file) == true) {
185 return true;
186 }
187 }
188
189 return false;
190 }
191
192 /** Method to assign a plugin
193 * @param plugin the Plugin to assign
194 */
195 private void assignPlugin(Plugin plugin) {
196 if(plugin.getName().equals(StaticStrings.RECPLUG_STR) || plugin.getName().equals(StaticStrings.ARCPLUG_STR)
197 || plugin.getName().equals(StaticStrings.METADATAXMLPLUG_STR) || plugin.getName().equals(StaticStrings.EMBEDMETAPLUG_STR)) {
198 addAfter(plugin, separator_plugin); // Adds after separator
199 } else {
200 addBefore(plugin, separator_plugin);
201 }
202 }
203
204
205 /** Destructor. */
206 public void destroy()
207 {
208 CollectionManager.removeCollectionContentsChangedListener(this);
209
210 if (controls != null) {
211 controls.destroy();
212 controls = null;
213 }
214 }
215
216
217 /** This function listens for new files being added to the collection and hints about suitable plugins. */
218 public void fileAddedToCollection(File file)
219 {
220 // First check the plugins already assigned in the collection
221 for (int i = 0; i < super.getSize(); i++) {
222 Plugin assigned_plugin = (Plugin) getElementAt(i);
223 if (assigned_plugin.isSeparator() == false && (assigned_plugin.doesProcessFile(file) == true || assigned_plugin.doesBlockFile(file) == true)) {
224 // This file will be processed by an assigned plugin, so no suggestion is necessary
225 DebugStream.println("Processed by assigned plugin: " + assigned_plugin);
226 return;
227 }
228 }
229
230 // Next try the plugins NOT already assigned in the collection
231 ArrayList suitable_plugins = new ArrayList();
232 Object[] unassigned_plugins = getAvailablePlugins();
233 for (int i = 0; i < unassigned_plugins.length; i++) {
234 Plugin unassigned_plugin = (Plugin) unassigned_plugins[i];
235 if (unassigned_plugin.doesProcessFile(file) == true) {
236 DebugStream.println("Processed by unassigned plugin: " + unassigned_plugin);
237 suitable_plugins.add(unassigned_plugin);
238 }
239 }
240
241 // If there appear to be no suitable plugins, warn the user about this and be done
242 if (suitable_plugins.size() == 0) {
243 String[] args = new String[1];
244 args[0] = file.getName();
245 WarningDialog warning_dialog = new WarningDialog("warning.NoPluginExpectedToProcessFile", Dictionary.get("NoPluginExpectedToProcessFile.Title"), Dictionary.get("NoPluginExpectedToProcessFile.Message", args), null, false);
246 warning_dialog.display();
247 warning_dialog.dispose();
248 return;
249 }
250
251 // Generate a dialog
252 new PluginSuggestionPrompt(file.getName(), suitable_plugins);
253 }
254
255
256 /** Method to retrieve the control for this manager.
257 * @return the Control
258 */
259 public Control getControls() {
260 if(controls == null) {
261 // Build controls
262 controls = new PluginControl();
263 }
264 return controls;
265 }
266
267
268 /** Overrides getSize in DOMProxyListModel to take into account the row count modifier used to hide the last three rows in lower detail modes
269 * @return an int indicating the number of rows in the model, or more correctly the desired number of rows to display
270 */
271 public int getSize() {
272 int result = super.getSize();
273 if(modify_row_count) {
274 result = result-(NUM_FIXED_PLUGINS+1);
275 }
276 return result;
277 }
278
279 /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
280 * @param mode the new mode as an int
281 */
282 public void modeChanged(int mode) {
283 if(controls != null) {
284 ((PluginControl)controls).modeChanged(mode);
285 }
286 }
287
288 /** Method to move a plugin in the list order.
289 * @param plugin the Plugin you want to move.
290 * @param direction true to move the plugin up, false to move it down.
291 * @param all true to move to move all the way, false for a single step.
292 */
293 // why are all the error notices there when the buttons are disabled is you cant move???
294 private void movePlugin(Plugin plugin, boolean direction, boolean all) {
295 // Can't ever move RecPlug or ArcPlug
296 if(super.getSize() < (NUM_FIXED_PLUGINS+2)) {
297 //DebugStream.println("Not enough plugins to allow moving.");
298 return;
299 }
300 if(plugin.getName().equals(StaticStrings.ARCPLUG_STR) || plugin.getName().equals(StaticStrings.RECPLUG_STR)
301 || plugin.getName().equals(StaticStrings.METADATAXMLPLUG_STR) || plugin.getName().equals(StaticStrings.EMBEDMETAPLUG_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 || name.equals(StaticStrings.METADATAXMLPLUG_STR) || name.equals(StaticStrings.EMBEDMETAPLUG_STR)) {
368 found_fixed = true;
369 index--;
370 }
371 else {
372 if(found_fixed) {
373 separator_index = index + 1;
374 index = -1;
375 }
376 else {
377 index--;
378 }
379 }
380 name = null;
381 plugin = null;
382 }
383 }
384 Element element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
385 element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, StaticStrings.SEPARATOR_ATTRIBUTE);
386 element.setAttribute(StaticStrings.SEPARATOR_ATTRIBUTE, StaticStrings.TRUE_STR);
387 separator_plugin = new Plugin(element, null);
388 ///atherer.println("Adding plugin separator at: " + separator_index);
389 add(separator_index, separator_plugin);
390 }
391
392 /** 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.
393 * @param plugin The <strong>Plugin</strong> to remove.
394 */
395 private void removePlugin(Plugin plugin) {
396 remove(plugin);
397
398 }
399
400
401 /** Inform the model to hide/show the last four lines on the list.
402 * @param modify_row_count true to hide the last four lines, false otherwise
403 */
404 private void setHideLines(boolean modify_row_count) {
405 this.modify_row_count = modify_row_count;
406 int original_size = super.getSize();
407 if(modify_row_count) {
408 fireIntervalRemoved(this, original_size - (NUM_FIXED_PLUGINS+2), original_size - 1);
409 }
410 else {
411 fireIntervalAdded(this, original_size - (NUM_FIXED_PLUGINS+2), original_size - 1);
412 }
413 }
414
415 /** Determine the current separator index. */
416 private int findSeparatorIndex() {
417 int separator_index = super.getSize() - 1;
418 while(separator_index >= 0) {
419 Plugin search = (Plugin) getElementAt(separator_index);
420 if(search.isSeparator()) {
421 return separator_index;
422 }
423 separator_index--;
424 }
425 return separator_index;
426 }
427
428
429 /** A class which provodes controls for assigned and editing plugins. */
430 private class PluginControl
431 extends JPanel
432 implements Control {
433 /** Button for adding plugins. */
434 private JButton add = null;
435 /** Button for configuring the selected plugin. */
436 private JButton configure = null;
437 /** Button to move an assigned plugin one position lower in the order. */
438 private JButton move_down_button = null;
439 /** Button to move an assigned plugin one position higher in the order. */
440 private JButton move_up_button = null;
441 /** Button to remove the selected plugin. */
442 private JButton remove = null;
443 /** A combobox containing all of the known plugins, including those that may have already been assigned. */
444 private JComboBox plugin_combobox = null;
445 /** The label next to the plugin combobox. */
446 private JLabel plugin_label = null;
447 /** The label above the assigned plugin list. */
448 private JLabel plugin_list_label = null;
449 /** A list of assigned plugins. */
450 private JList plugin_list = null;
451 /** The area where the add, configure and remove buttons are placed. */
452 private JPanel button_pane = null;
453 /** The region which divides the central portion of the view into list and controls */
454 private JPanel central_pane = null;
455 /** The area where movement buttons are placed. */
456 private JPanel movement_pane = null;
457 /** The small region containing the plugin combobox and its label. */
458 private JPanel plugin_pane = null;
459 /** The pane containing the assigned plugin list and its label. */
460 private JPanel plugin_list_pane = null;
461
462 /** Constructor.
463 */
464 public PluginControl()
465 {
466 // Create
467 add = new GLIButton(Dictionary.get("CDM.PlugInManager.Add"), Dictionary.get("CDM.PlugInManager.Add_Tooltip"));
468
469 button_pane = new JPanel();
470 central_pane = new JPanel();
471 button_pane.setComponentOrientation(Dictionary.getOrientation());
472 central_pane.setComponentOrientation(Dictionary.getOrientation());
473
474 configure = new GLIButton(Dictionary.get("CDM.PlugInManager.Configure"), Dictionary.get("CDM.PlugInManager.Configure_Tooltip"));
475 configure.setEnabled(false);
476
477 JPanel header_pane = new DesignPaneHeader("CDM.GUI.Plugins", "plugins");
478 move_up_button = new GLIButton(Dictionary.get("CDM.Move.Move_Up"), JarTools.getImage("arrow-up.gif"), Dictionary.get("CDM.Move.Move_Up_Tooltip"));
479 move_up_button.setEnabled(false);
480
481 move_down_button = new GLIButton(Dictionary.get("CDM.Move.Move_Down"), JarTools.getImage("arrow-down.gif"), Dictionary.get("CDM.Move.Move_Down_Tooltip"));
482 move_down_button.setEnabled(false);
483
484 movement_pane = new JPanel();
485 movement_pane.setComponentOrientation(Dictionary.getOrientation());
486
487 PluginComboboxListener picl = new PluginComboboxListener();
488 plugin_combobox = new JComboBox(getAvailablePlugins());
489 plugin_combobox.setOpaque(!Utility.isMac());
490 plugin_combobox.setEditable(false);
491 plugin_combobox.setComponentOrientation(Dictionary.getOrientation());
492
493 picl.itemStateChanged(new ItemEvent(plugin_combobox, 0, null, ItemEvent.SELECTED));
494
495 plugin_label = new JLabel(Dictionary.get("CDM.PlugInManager.PlugIn"));
496 plugin_label.setComponentOrientation(Dictionary.getOrientation());
497
498 plugin_list = new JList(model);
499 plugin_list.setOpaque(true);
500 plugin_list.setCellRenderer(new ListRenderer());
501 plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
502 plugin_list.setComponentOrientation(Dictionary.getOrientation());
503
504 plugin_list_label = new JLabel(Dictionary.get("CDM.PlugInManager.Assigned"));
505 //plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
506 plugin_list_label.setOpaque(true);
507 plugin_list_label.setComponentOrientation(Dictionary.getOrientation());
508
509 plugin_list_pane = new JPanel();
510 plugin_list_pane.setComponentOrientation(Dictionary.getOrientation());
511
512 plugin_pane = new JPanel();
513 plugin_pane.setOpaque(true);
514 plugin_pane.setComponentOrientation(Dictionary.getOrientation());
515
516 remove = new GLIButton(Dictionary.get("CDM.PlugInManager.Remove"), Dictionary.get("CDM.PlugInManager.Remove_Tooltip"));
517 remove.setEnabled(false);
518
519 // Listeners
520 add.addActionListener(new AddListener());
521 configure.addActionListener(new ConfigureListener());
522 MoveListener ml = new MoveListener();
523 move_down_button.addActionListener(ml);
524 move_down_button.addActionListener(CollectionDesignManager.all_change_listener);
525 move_up_button.addActionListener(ml);
526 move_up_button.addActionListener(CollectionDesignManager.all_change_listener);
527 plugin_combobox.addItemListener(picl);
528 remove.addActionListener(new RemoveListener());
529 remove.addActionListener(CollectionDesignManager.all_change_listener);
530 plugin_list.addMouseListener(new ClickListener());
531 plugin_list.addListSelectionListener(new ListListener());
532 picl = null;
533
534 // Layout
535 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
536 movement_pane.setLayout(new GridLayout(4,1));
537 movement_pane.add(move_up_button);
538 JPanel tmp = new JPanel();
539 tmp.setComponentOrientation(Dictionary.getOrientation());
540 movement_pane.add(tmp);
541 tmp = new JPanel();
542 tmp.setComponentOrientation(Dictionary.getOrientation());
543 movement_pane.add(tmp);
544 movement_pane.add(move_down_button);
545
546 plugin_list_pane.setLayout(new BorderLayout());
547 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
548 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
549 plugin_list_pane.add(movement_pane, BorderLayout.LINE_END);
550 modeChanged(Configuration.getMode()); // Whether the special plugins are hidden or not is mode dependant
551
552 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
553
554 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
555 plugin_pane.setLayout(new BorderLayout(5,0));
556 plugin_pane.add(plugin_label, BorderLayout.LINE_START);
557 plugin_pane.add(plugin_combobox, BorderLayout.CENTER);
558
559 button_pane.setLayout(new GridLayout(1,3));
560 button_pane.add(add);
561 button_pane.add(configure);
562 button_pane.add(remove);
563
564 // Scope these mad bordering skillz.
565 JPanel temp = new JPanel(new BorderLayout());
566 temp.add(plugin_pane, BorderLayout.NORTH);
567 temp.add(button_pane, BorderLayout.SOUTH);
568 temp.setComponentOrientation(Dictionary.getOrientation());
569
570 central_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
571 central_pane.setLayout(new BorderLayout());
572 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
573 central_pane.add(temp, BorderLayout.SOUTH);
574
575 setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
576 setLayout(new BorderLayout());
577 add(header_pane, BorderLayout.NORTH);
578 add(central_pane, BorderLayout.CENTER);
579 }
580
581 /** Method which acts like a destructor, tidying up references to persistant objects.
582 */
583 public void destroy() {
584 }
585
586 /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
587 no longer have instructions, do we still need updateUI???
588 */
589 public void gainFocus() {
590 super.updateUI();
591 }
592
593 public void loseFocus() {
594 }
595
596 /** 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
597 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
598 */
599 public void modeChanged(int mode) {
600 // 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
601 plugin_list.clearSelection();
602 plugin_combobox.setModel(new DefaultComboBoxModel(getAvailablePlugins()));
603 setHideLines(!(mode >= Configuration.EXPERT_MODE));
604
605 plugin_list_pane.updateUI();
606 }
607
608
609 private class AddListener
610 implements ActionListener
611 {
612 public void actionPerformed(ActionEvent event)
613 {
614 if (plugin_combobox.getSelectedItem() != null) {
615 // This must be done on a new thread for the remote building code
616 new AddPluginTask(plugin_combobox.getSelectedItem().toString()).start();
617 }
618 }
619 }
620
621
622 private class AddPluginTask
623 extends Thread
624 {
625 private String plugin_name;
626
627 public AddPluginTask(String plugin_name)
628 {
629 this.plugin_name = plugin_name;
630 }
631
632 public void run()
633 {
634 // Retrieve the plugin
635 Plugin plugin = Plugins.getPlugin(plugin_name, true);
636 if (plugin == null) {
637 System.err.println("Error: getPlugin() returned null.");
638 return;
639 }
640
641 // Create a new element in the DOM
642 Element new_plugin_element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
643 new_plugin_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, plugin.getName());
644 Plugin new_plugin = new Plugin(new_plugin_element, plugin);
645
646 ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
647 ac.addOKButtonActionListener(CollectionDesignManager.all_change_listener);
648 if (ac.display()) {
649 assignPlugin(new_plugin);
650 plugin_list.setSelectedValue(new_plugin, true);
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 || plugin_name.equals(StaticStrings.METADATAXMLPLUG_STR) || plugin_name.equals(StaticStrings.EMBEDMETAPLUG_STR)) {
728 move_up_button.setEnabled(false);
729 move_down_button.setEnabled(false);
730 remove.setEnabled(false);
731 }
732
733 else {
734 // don't let people remove special plugins such GreenstoneXMLPlug and GreenstoneMETSPlug,
735 // unless they are in expert mode or above
736 int mode = Configuration.getMode();
737 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
738 if ((plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
739 (mode < Configuration.EXPERT_MODE)) {
740 remove.setEnabled(false);
741 break;
742 } else {
743 remove.setEnabled(true);
744 }
745 }
746
747 // Move ups are only enabled if the selected plugin isn't already at the top
748 Plugin first_plugin = (Plugin) getElementAt(0);
749 if(!first_plugin.equals(selected_plugin)) {
750 move_up_button.setEnabled(true);
751 } else {
752 move_up_button.setEnabled(false);
753 }
754 // And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
755 int separator_index = findSeparatorIndex();
756 int selected_index = plugin_list.getSelectedIndex();
757 if(selected_index < separator_index - 1) {
758 move_down_button.setEnabled(true);
759 } else {
760 move_down_button.setEnabled(false);
761 }
762 }
763 selected_plugin = null;
764 plugin_name = null;
765 }
766 }
767 }
768 }
769 }
770
771 /** A special list renderer which is able to render separating lines as well. */
772 private class ListRenderer
773 extends DefaultListCellRenderer {
774 /** 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.
775 * @param list - The <strong>JList</strong> we're painting.
776 * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
777 * @param index - The cells index as an <i>int</i>.
778 * @param isSelected - <i>true</i> if the specified cell was selected.
779 * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
780 * @return A <strong>Component</strong> whose paint() method will render the specified value.
781 * @see javax.swing.JList
782 * @see javax.swing.JSeparator
783 * @see javax.swing.ListModel
784 * @see javax.swing.ListSelectionModel
785 */
786 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
787 Plugin plugin = (Plugin) value;
788 if(plugin.isSeparator()) {
789 return separator;
790 }
791 else {
792 return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
793 }
794 }
795 }
796
797
798 /** 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. */
799 private class MoveListener
800 implements ActionListener {
801 /** 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.
802 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
803 */
804 public void actionPerformed(ActionEvent event) {
805 if (!plugin_list.isSelectionEmpty()) {
806 Object object = plugin_list.getSelectedValue();
807 if (object instanceof Plugin) {
808 Plugin plugin = (Plugin) object;
809 if (event.getSource() == move_up_button) {
810 movePlugin(plugin, true, false);
811 }
812 else if (event.getSource() == move_down_button) {
813 movePlugin(plugin, false, false);
814 }
815 plugin_list.setSelectedValue(plugin, true);
816 }
817 }
818 }
819 }
820
821 /** This listener reacts to changes in the current selection of the plugin combobox. */
822 private class PluginComboboxListener
823 implements ItemListener {
824 /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
825 public void itemStateChanged(ItemEvent event) {
826 if(event.getStateChange() == ItemEvent.SELECTED) {
827 // Retrieve the selected plugin
828 Object current_selection = plugin_combobox.getSelectedItem();
829 // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
830 if(current_selection == null || current_selection instanceof String) {
831 plugin_combobox.setToolTipText(Dictionary.get("CDM.PlugInManager.PlugIn_Tooltip"));
832 }
833 else {
834 Plugin current_plugin = (Plugin) current_selection;
835 plugin_combobox.setToolTipText(Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
836 current_plugin = null;
837 }
838 current_selection = null;
839 }
840 }
841 }
842
843 /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
844 */
845 private class RemoveListener
846 implements ActionListener {
847 /** 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.
848 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
849 */
850 public void actionPerformed(ActionEvent event) {
851 int selected_index = plugin_list.getSelectedIndex();
852 if(selected_index != -1) {
853 Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
854 removePlugin(selected_plugin);
855 selected_plugin = null;
856 // Refresh the available plugins
857 plugin_combobox.setModel(new DefaultComboBoxModel(getAvailablePlugins()));
858
859 // Select the next plugin if available
860 if(selected_index < plugin_list.getModel().getSize()) {
861 // If the new selection is above the separator we can remove it
862 if(selected_index < findSeparatorIndex()) {
863 plugin_list.setSelectedIndex(selected_index);
864
865 // don't let people remove special plugins such GAPlug an METSPlug,
866 // unless they are in expert mode or above
867 int mode = Configuration.getMode();
868 for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
869 String selected_plugin_name
870 = ((Plugin)plugin_list.getSelectedValue()).getName();
871
872 if (selected_plugin_name.equals(StaticStrings.METADATAXMLPLUG_STR)) {
873 //this plug cannot be removed under any conditions.
874 remove.setEnabled(false);
875 }else if ((selected_plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
876 (mode < Configuration.EXPERT_MODE)) {
877 remove.setEnabled(false);
878 break;
879 } else {
880 remove.setEnabled(true);
881 }
882 }
883 }
884 // Otherwise select the first non-removable plugin
885 else {
886 plugin_list.setSelectedIndex(selected_index + 1);
887 remove.setEnabled(false);
888 }
889 } else {
890 remove.setEnabled(false);
891 }
892 } else {
893 remove.setEnabled(false);
894 }
895 }
896 }
897 }
898
899
900 private class PluginSuggestionPrompt
901 extends ModalDialog
902 implements ActionListener
903 {
904 private Dimension size = new Dimension(480, 240);
905 private GComboBox suitable_plugins_combobox = null;
906 private GLIButton add_button = null;
907 private GLIButton ignore_button = null;
908
909 public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
910 {
911 super(Gatherer.g_man, true);
912 setModal(true);
913 setSize(size);
914 setTitle(Dictionary.get("CDM.PluginManager.SuggestedPluginListTitle"));
915 this.setComponentOrientation(Dictionary.getOrientation());
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 instructions_textarea.setComponentOrientation(Dictionary.getOrientation());
927
928 JLabel suitable_plugins_label = new JLabel(Dictionary.get("CDM.PlugInManager.PlugIn"));
929 suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
930 suitable_plugins_label.setComponentOrientation(Dictionary.getOrientation());
931
932 suitable_plugins_combobox = new GComboBox(suitable_plugins);
933 suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
934 suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
935 suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
936 suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
937 suitable_plugins_combobox.setComponentOrientation(Dictionary.getOrientation());
938
939 JPanel suitable_plugins_pane = new JPanel();
940 suitable_plugins_pane.setComponentOrientation(Dictionary.getOrientation());
941 //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
942 suitable_plugins_pane.setLayout(new BorderLayout(5,0));
943 suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.LINE_START);
944 suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
945
946 add_button = new GLIButton(Dictionary.get("CDM.PlugInManager.QuickAdd"), Dictionary.get("CDM.PlugInManager.Add_Tooltip"));
947 ignore_button = new GLIButton(Dictionary.get("CDM.PlugInManager.Ignore"), Dictionary.get("CDM.PlugInManager.Ignore_Tooltip"));
948
949 add_button.addActionListener(this);
950 ignore_button.addActionListener(this);
951
952 JPanel button_pane = new JPanel();
953 button_pane.setLayout(new GridLayout(1,2,5,0));
954 button_pane.add(add_button);
955 button_pane.add(ignore_button);
956 button_pane.setComponentOrientation(Dictionary.getOrientation());
957
958 JPanel controls_pane = new JPanel();
959 controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
960 controls_pane.setLayout(new GridLayout(2,1,0,5));
961 controls_pane.add(suitable_plugins_pane);
962 controls_pane.add(button_pane);
963 controls_pane.setComponentOrientation(Dictionary.getOrientation());
964
965 JPanel content_pane = (JPanel) getContentPane();
966 content_pane.setComponentOrientation(Dictionary.getOrientation());
967 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
968 content_pane.setLayout(new BorderLayout());
969 content_pane.add(instructions_textarea, BorderLayout.CENTER);
970 content_pane.add(controls_pane, BorderLayout.SOUTH);
971
972 // Show
973 Dimension screen_size = Configuration.screen_size;
974 setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
975 setVisible(true);
976 }
977
978
979 public void actionPerformed(ActionEvent event)
980 {
981 // Close the dialog
982 setVisible(false);
983
984 if (event.getSource() == add_button) {
985 AddPluginWithoutConfigurationTask add_plugin_task = new AddPluginWithoutConfigurationTask(suitable_plugins_combobox.getSelectedItem().toString());
986 add_plugin_task.start();
987
988 // We have to wait for this task to complete before continuing, otherwise
989 // we might offer to add the same plugin again before the task has completed
990 try {
991 add_plugin_task.join();
992 }
993 catch (Exception exception) {
994 DebugStream.printStackTrace(exception);
995 }
996 }
997 }
998
999
1000 private class AddPluginWithoutConfigurationTask
1001 extends Thread
1002 {
1003 private String plugin_name;
1004
1005 public AddPluginWithoutConfigurationTask(String plugin_name)
1006 {
1007 this.plugin_name = plugin_name;
1008 }
1009
1010 public void run()
1011 {
1012 // Retrieve the plugin
1013 Plugin plugin = Plugins.getPlugin(plugin_name, true);
1014 if (plugin == null) {
1015 System.err.println("Error: getPlugin() returned null.");
1016 return;
1017 }
1018
1019 // Create a new element in the DOM
1020 Element new_plugin_element = CollectionConfiguration.createElement(StaticStrings.PLUGIN_ELEMENT);
1021 new_plugin_element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, plugin.getName());
1022 Plugin new_plugin = new Plugin(new_plugin_element, plugin);
1023
1024 // Just assign the plugin with no argument configuration
1025 assignPlugin(new_plugin);
1026 Gatherer.c_man.getCollection().cdm.save();
1027 }
1028 }
1029 }
1030
1031
1032 /** Creates a list separator.
1033 * Found on Google Groups. Code courtesy of Paul Farwell.
1034 */
1035 private JPanel getSeparator() {
1036 // We put the separator inside a panel to control its appearance
1037 JPanel _sepPanel = new JPanel();
1038 _sepPanel.setOpaque(false);
1039 _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
1040 _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
1041 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1042 // 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
1043 _sepPanel.add(new BasicSeparator());
1044 _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
1045 return _sepPanel;
1046 }
1047
1048 /** 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. */
1049 private static class BasicSeparator
1050 extends JSeparator {
1051
1052 private ComponentUI basic_ui;
1053
1054 public BasicSeparator() {
1055 super();
1056 basic_ui = new BasicSeparatorUI();
1057 }
1058
1059 public void paintComponent(Graphics g) {
1060 if (basic_ui != null) {
1061 basic_ui.update(g, this);
1062 }
1063 }
1064 }
1065}
Note: See TracBrowser for help on using the repository browser.