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

Last change on this file since 22410 was 22410, checked in by ak19, 14 years ago

Getting collectgroup to work for a remote Greenstone server. Need to update gliserver.pl still to work with the collectgroup changes. 1. GLI side changes: no longer does the collectdir parameter to import and build include the colgroup at the end, it is now back to being everything upto the GS collect dir. Instead, the loaded collection is colgroup/subcolname. 2. Changed CollectionManager.getLoadedCollectionName() to return (colgroup/)subcolname instead of the subcolname excluding groupname. 3. This required changes in other classes, including replacing unnecessary explicit calls to getLoadedGroupQualifiedCollectionName(). 4. Added another variant: getLoadedCollectionName(boolean). If the parameter is true, it will put a url style slash between colgroup and subcolname, otherwise use the OS dependent FileSeparator. 5. Changes to RemoteGreenstoneServer to pass the group/subcol as the collectionname to gliserver.pl, with a vertical bar separator. 6. Minor changes like: WorkspaceTreeNode now knows not to load a collection group if it's already in the loaded collection (previously handed only sub collection name), removed old debugging statements and unused import statements.

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