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

Last change on this file since 18412 was 18412, checked in by kjdon, 15 years ago

more modifications for RTL GLI, thanks to Amin Hedjazi

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