/** *######################################################################### * * A component of the Gatherer application, part of the Greenstone digital * library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * *

* * Author: John Thompson, Greenstone Digital Library, University of Waikato * *

* * Copyright (C) 1999 New Zealand Digital Library Project * *

* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * *

* * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * *

* * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *######################################################################## */ package org.greenstone.gatherer.cdm; /** * Title: The Gatherer
* Description: The Gatherer: a tool for gathering and enriching digital collections.
* Copyright: Copyright (c) 2001
* Company: The University of Waikato
* First Coded: 01/05/02 * @author John Thompson, Greenstone Digital Libraries * @version 2.1 */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.StringReader; import java.util.Collections; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTextArea; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.plaf.basic.BasicArrowButton; import org.apache.xerces.parsers.DOMParser; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.cdm.Argument; import org.greenstone.gatherer.cdm.ArgumentConfiguration; import org.greenstone.gatherer.cdm.CommandTokenizer; import org.greenstone.gatherer.cdm.DynamicListModel; import org.greenstone.gatherer.cdm.PlugIn; import org.greenstone.gatherer.util.Utility; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; /** This class is resposible for maintaining a list of known plug-ins, and importing new plugins using the parser. */ public class PlugInManager { /** A reference to the main manager for this module. */ private CollectionDesignManager manager = null; /** The controls for editing the contents of this manager. */ private Control controls = null; /** A list of assigned plugins. */ private DynamicListModel assigned = null; /** A list of those plugins that have not yet been assigned. Begins as a copy of reserve. */ private DynamicListModel available = null; /** A list of known, but currently unassigned, plug-ins. */ private DynamicListModel reserve = null; /** A reference to the Gatherer. */ private Gatherer gatherer = null; /** The current index of the separator. */ private JPanel separator = null; /** The default size for a label. */ static final private Dimension LABEL_SIZE = new Dimension(140, 20); /** Constructor. */ public PlugInManager(Gatherer gatherer, CollectionDesignManager manager) { this.assigned = new DynamicListModel(); this.gatherer = gatherer; this.manager = manager; this.separator = getSeparator(); // Add the movement separator assigned.addElement(separator); loadPlugIns(); savePlugIns(); } /** Method to add a new plugin to reserve. * @param plugin The new PlugIn. */ public void addPlugIn(PlugIn plugin) { if(!reserve.contains(plugin)) { reserve.addElement(plugin); available.addElement(plugin); } } /** Method to assign a plugin. * @param plugin The reserve PlugIn to assign. */ public void assignPlugIn(PlugIn plugin) { if(!assigned.contains(plugin)) { if(plugin.getName().equals("RecPlug") || plugin.getName().equals("ArcPlug")) { assigned.addElement(plugin); // Adds after separator } else { int index = assigned.indexOf(separator); assigned.add(index, plugin); } // Remove from available available.removeElement(plugin); gatherer.c_man.configurationChanged(); } } /** Method to retrieve the control for this manager. * @return A JPanel containing the controls. */ public JPanel getControls() { if(controls == null) { controls = new Control(); } return controls; } /** Method to retrieve the named plugin. * @param name The name of the desired plugin as a String. * @return The requested PlugIn or null if no such plugin exists. */ public PlugIn getPlugIn(String name) { for(int i = 0; i < reserve.size(); i++) { Object object = reserve.get(i); if(object instanceof PlugIn) { PlugIn plugin = (PlugIn) object; if(plugin.getName().equals(name)) { return plugin; } } } // No success. return null; } /** Method to invalidate controls after a significant change in the system state. */ public void invalidateControls() { if(controls != null) { controls.destroy(); } controls = null; } /** Method to load the details of a single plug-in. * @param plugin The plugin File you wish to load. */ public void loadPlugIn(File plugin) { Document document = null; // Run pluginfo on this plugin, and then send the results for parsing. try { String args[] = null; if(Utility.isWindows()) { args = new String[4]; if(gatherer.config.perl_path != null) { args[0] = gatherer.config.perl_path + "Perl.exe"; } else { args[0] = "Perl.exe"; } args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl"; args[2] = "-xml"; args[3] = getPlugInName(plugin); } else { args = new String[3]; args[0] = "pluginfo.pl"; args[1] = "-xml"; args[2] = getPlugInName(plugin); } for(int i = 0; i < args.length; i++) { ///ystem.out.print(args[i] + " "); } ///ystem.out.print("\n"); // Create the process. Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(args); //InputStream input_stream = process.getErrorStream(); BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream())); String line = ""; StringBuffer xml = new StringBuffer(""); while((line = error_in.readLine()) != null) { xml.append(line); xml.append("\n"); } line = null; error_in = null; ///ystem.out.println("\n"); // Then read the xml from the piped input stream. InputSource source = new InputSource(new StringReader(xml.toString())); DOMParser parser = new DOMParser(); parser.parse(source); document = parser.getDocument(); } catch (Exception error) { error.printStackTrace(); } if(document != null) { parse(document.getDocumentElement()); } } /** Method to move a plugin higher in the list order. * @param plugin The PlugIn you want to move. * @param direction true to move the plugin up, false to move it down. * @param all true to move to move all the way, false for a single step. */ public void movePlugIn(PlugIn plugin, boolean direction, boolean all) { // Can't ever move RecPlug or ArcPlug. if(plugin.getName().equals("ArcPlug") || plugin.getName().equals("RecPlug")) { JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Fixed"), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE); return; } if(all) { if(direction) { assigned.removeElement(plugin); assigned.add(0, plugin); gatherer.c_man.configurationChanged(); } else { assigned.removeElement(plugin); int index = assigned.size() - 1; boolean found = false; while(!found) { Object temp = assigned.get(index); if(temp instanceof PlugIn) { PlugIn current = (PlugIn) temp; if(current.getName().equals("ArcPlug") || current.getName().equals("RecPlug")) { index--; } else { found = true; } } else { found = true; } } assigned.add(index, plugin); gatherer.c_man.configurationChanged(); } } else { // Try to move the plugin one step in the desired direction. int index = assigned.indexOf(plugin); ///ystem.err.println("Index of " + plugin + " = " + index); if(direction) { index--; if(index < 0) { String args[] = new String[1]; args[0] = plugin.getName(); JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE); return; } assigned.removeElement(plugin); assigned.add(index, plugin); gatherer.c_man.configurationChanged(); } else { index++; Object object = assigned.get(index); if(index == assigned.size()) { String args[] = new String[1]; args[0] = plugin.getName(); JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Bottom", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE); // Still not going to move RecPlug or ArcPlug. return; } else if(!(object instanceof PlugIn) || ((PlugIn)object).getName().equals("ArcPlug") || ((PlugIn)object).getName().equals("RecPlug")) { String args[] = new String[1]; args[0] = plugin.getName(); JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Cannot", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE); // Still not going to move RecPlug or ArcPlug. return; } assigned.removeElement(plugin); assigned.add(index, plugin); gatherer.c_man.configurationChanged(); } } } /** This method attempts to parse a plugin command from a command string taken from the collection configuration file. This process is quite complex as not only must the correct plugin be matched by also all of the parameters given must be legal. If such a command is found, the plugin is immediately assigned. * @param command The coomand String that may include plugin information. * @return true if a plugin command was parsed, false otherwise. */ public boolean parse(String command) { String command_lc = command.toLowerCase(); if(command_lc.startsWith("plugin")) { CommandTokenizer tokenizer = new CommandTokenizer(command); if(tokenizer.countTokens() >= 2) { tokenizer.nextToken(); // Throw away 'plugin' String name = tokenizer.nextToken(); // Try to locate the plugin with this name. PlugIn plugin = getPlugIn(name); // And if successful start to parse the arguments. if(plugin != null) { // Take a copy. plugin = plugin.copy(); String key = null; while(tokenizer.hasMoreTokens()) { if(key == null) { key = tokenizer.nextToken(); } // Try to retrieve a matching argument. Argument argument = plugin.getArgument(key); if(argument != null) { // Set as assigned. argument.setAssigned(true); // And if the argument is of a parameter type, parse a parameter. if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) { argument.setValue(tokenizer.nextToken()); } key = null; } // Argument cannot be matched. else { String cur_key = key; String value = tokenizer.nextToken(); if(value.startsWith("-")) { key = value; value = null; } else { key = null; } String custom = plugin.getCustom(); if(custom == null) { if(value == null) { plugin.setCustom(cur_key); } else { plugin.setCustom(cur_key + " " + value); } } else { if(value == null) { plugin.setCustom(custom + " " + cur_key); } else { plugin.setCustom(custom + " " + cur_key + " " + value); } } } } // Slight tweak. If the plugin is the RecPlug we want to set use_metadata_files by default. if(plugin.getName().equalsIgnoreCase("RecPlug")) { Argument argument = plugin.getArgument("-use_metadata_files"); if(argument != null) { argument.setAssigned(true); } } // Second tweak. If the plugin is the HTMLPlug we want to modify the block expression so our backup files are ignored. if(plugin.getName().equalsIgnoreCase("HTMLPlug")) { Argument argument = plugin.getArgument("-block_exp"); if(argument != null) { argument.setValue(argument.getDefaultValue() + "|(~$)"); } } // Add the plugin to our reserve assignPlugIn(plugin); return true; } else { //ystem.err.println("Unknown plugin"); } } } return false; } /** This method removes an assigned plugin. I was tempted to call it unassign, by remove is more consistant. Note that there is no way to remove a plugin from the reserve. * @param plugin The PlugIn to remove. */ public void removePlugIn(PlugIn plugin) { assigned.removeElement(plugin); available.addElement(plugin); gatherer.c_man.configurationChanged(); } /** Method to cache the current contents of reserve (known plugins) to file. */ public void savePlugIns() { try { FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "plugins.dat"); ObjectOutputStream out = new ObjectOutputStream(file); out.writeObject(reserve); out.close(); } catch (Exception error) { } } /** Method used to determine the number of plugins that have been assigned. * @return An int which is the number of plugins. */ public int size() { return assigned.size(); } /** Method to print out a block of plugin commands, much like you'd find in a collection configuration file. * @return A String containing a series of plugin commands separated by new lines. */ public String toString() { String text = ""; for(int i = 0; i < assigned.size(); i++) { Object object = assigned.get(i); if(object instanceof PlugIn) { PlugIn plugin = (PlugIn) object; text = text + plugin.toString() + "\n"; } } text = text + "\n"; return text; } /* Retrieve a phrase from the dictionary based on a certain key. * @param key The search String. * @return The matching phrase from the Dictionary. */ private String get(String key) { return get(key, null); } /* Retrieve a phrase from the dictionary based on a certain key and arguments. * @param key The search String. * @param args A String[] of arguments used to complete and format the choosen phrase. * @return The matching phrase from the Dictionary. */ private String get(String key, String args[]) { if(key.indexOf(".") == -1) { key = "CDM.PlugInManager." + key; } return gatherer.dictionary.get(key, args); } /** Method to extract just the plugins name from a file object. * @param plugin The File which references a certain plugin. * @return A String containing just the plugins name, without extension. */ private String getPlugInName(File plugin) { String name = plugin.getName(); if(name.indexOf(".") != -1) { name = name.substring(0, name.indexOf(".")); } return name; } /** Method to retrieve the CData value from a node. Requires a search for the #text node. * @param node The Node whose value we wish to find. * @return The value of node as a String, or null if no value exists. */ private String getValue(Node node) { if(node.hasChildNodes()) { Node text = node.getFirstChild(); //ystem.err.println("Value of " + node.getNodeName() + " = " + text.getNodeValue()); return text.getNodeValue(); } return node.getNodeValue(); } /** Method to initially load information from the standard plug-ins within the gsdl Perl library. */ private void loadPlugIns() { // Attempt to restore the cached file. try { FileInputStream file = new FileInputStream(Utility.BASE_DIR + "plugins.dat"); ObjectInputStream input = new ObjectInputStream(file); reserve = (DynamicListModel) input.readObject(); available = reserve.shallowCopy(); } catch (Exception error) { } if(reserve == null) { available = new DynamicListModel(); reserve = new DynamicListModel(); reserve.setAutoOrder(true); // Retrieve the gsdl home directory... String directory = gatherer.config.gsdl_path; directory = directory + "perllib" + File.separator + "plugins" + File.separator; loadPlugIns(new File(directory)); } } /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location. * @param directory A File indicating the directory to be scanned for plug-ins. */ private void loadPlugIns(File directory) { File files[] = directory.listFiles(); if(files != null) { // Create a progress indicator. ParsingProgress progress = new ParsingProgress(get("CDM.PlugInManager.Parsing.Title"), get("CDM.PlugInManager.Parsing.Message"), files.length); for(int i = 0; i < files.length; i++) { // We only want to check Perl Modules. if(files[i].getName().endsWith(".pm")) { loadPlugIn(files[i]); } progress.inc(); } progress.dispose(); } } private PlugIn parse(Node root) { PlugIn plugin = new PlugIn(); String node_name = null; for(Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) { node_name = node.getNodeName(); if(node_name.equals("Name")) { String name = getValue(node); // We can save ourselves some processing time if a plugin with this name already exists in our manager. If so retrieve it and return it. PlugIn existing = getPlugIn(name); if(existing != null) { return existing; } plugin.setName(name); } else if(node_name.equals("Desc")) { plugin.setDesc(getValue(node)); } // Parse the multitude of arguments. else if(node_name.equals("Arguments")) { for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) { node_name = arg.getNodeName(); // An option. if(node_name.equals("Option")) { Argument argument = new Argument(); // If its an option we parse the multitude of details an options might have. for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) { node_name = det.getNodeName(); if(node_name.equals("Name")) { argument.setName(getValue(det)); } else if(node_name.equals("Desc")) { argument.setDesc(getValue(det)); } else if(node_name.equals("Type")) { argument.setType(getValue(det)); } else if(node_name.equals("Default")) { argument.setDefault(getValue(det)); } else if(node_name.equals("List")) { // Two final loops are required to parse lists. for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) { if(value.getNodeName().equals("Value")) { String key = null; String desc = ""; for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) { node_name = subvalue.getNodeName(); if(node_name.equals("Name")) { key = getValue(subvalue); } else if(node_name.equals("Desc")) { desc = getValue(subvalue); } } if(key != null) { argument.addOption(key, desc); } } } } else if(node_name.equals("Required")) { String v = getValue(det); if(v != null && v.equals("yes")) { argument.setRequired(true); } } } plugin.addArgument(argument); } // A super plugin class. else if(node_name.equals("PlugInfo")) { PlugIn super_plugin = parse(arg); plugin.setSuper(super_plugin); } } } } if(plugin.getName() != null) { addPlugIn(plugin); return plugin; } return null; } /** A class which provodes controls for assigned and editing plugins. */ private class Control extends JPanel { /** Button for adding plugins. */ private JButton add = null; /** Button for configuring the selected plugin. */ private JButton configure = null; /** Buttom to move an assinged plugin as low in the order as possible. */ private JButton move_bottom = null; /** Button to move an assigned plugin one position lower in the order. */ private JButton move_down = null; /** Button to move an assigned plugin as high in the order as possible. */ private JButton move_top = null; /** Button to move an assigned plugin one position higher in the order. */ private JButton move_up = null; /** Button to remove the selected plugin. */ private JButton remove = null; /** A combobox containing all of the known plugins, including those that may have already been assigned. */ private JComboBox plugin = null; /** The label next to the plugin combobox. */ private JLabel plugin_label = null; /** The label above the assigned plugin list. */ private JLabel plugin_list_label = null; /** The title of this view. */ private JLabel title = null; /** A list of assigned plugins. */ private JList plugin_list = null; /** The area where the add, configure and remove buttons are placed. */ private JPanel button_pane = null; /** The region which divides the central portion of the view into list and controls. */ private JPanel central_pane = null; /** The area where title label and instructions sit. */ private JPanel header_pane = null; /** The area where movement buttons are placed. */ private JPanel movement_pane = null; /** The small region containing the plugin combobox and its label. */ private JPanel plugin_pane = null; /** The pane containing the assigned plugin list and its label. */ private JPanel plugin_list_pane = null; /** The text area containing instructions on the use of this control. */ private JTextArea instructions = null; /** Constructor. */ public Control() { Object plugins[] = reserve.toArray(); Vector plugin_model = new Vector(); for(int i = 0; i < plugins.length; i++) { plugin_model.add(((PlugIn)plugins[i]).getName()); } Collections.sort(plugin_model); // Create add = new JButton(get("Add")); add.setMnemonic(KeyEvent.VK_A); button_pane = new JPanel(); central_pane = new JPanel(); configure = new JButton(get("Configure")); configure.setMnemonic(KeyEvent.VK_C); header_pane = new JPanel(); instructions = new JTextArea(get("Instructions")); instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false)); instructions.setEditable(false); instructions.setLineWrap(true); instructions.setRows(5); instructions.setWrapStyleWord(true); move_bottom = new JButton(); JLabel move_bottom_label = new JLabel(get("Move_Bottom")); move_bottom_label.setHorizontalAlignment(JLabel.CENTER); move_bottom_label.setPreferredSize(LABEL_SIZE); move_bottom.setLayout(new BorderLayout()); move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.WEST); move_bottom.add(move_bottom_label, BorderLayout.CENTER); move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.EAST); move_bottom.setMnemonic(KeyEvent.VK_B); move_down = new JButton(); JLabel move_down_label = new JLabel(get("Move_Down")); move_down_label.setHorizontalAlignment(JLabel.CENTER); move_down_label.setPreferredSize(LABEL_SIZE); move_down.setLayout(new BorderLayout()); move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.WEST); move_down.add(move_down_label, BorderLayout.CENTER); move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.EAST); move_down.setMnemonic(KeyEvent.VK_D); move_top = new JButton(); JLabel move_top_label = new JLabel(get("Move_Top")); move_top_label.setHorizontalAlignment(JLabel.CENTER); move_top_label.setPreferredSize(LABEL_SIZE); move_top.setLayout(new BorderLayout()); move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.WEST); move_top.add(move_top_label, BorderLayout.CENTER); move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.EAST); move_top.setMnemonic(KeyEvent.VK_T); move_up = new JButton(); JLabel move_up_label = new JLabel(get("Move_Up")); move_up_label.setHorizontalAlignment(JLabel.CENTER); move_up_label.setPreferredSize(LABEL_SIZE); move_up.setLayout(new BorderLayout()); move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.WEST); move_up.add(move_up_label, BorderLayout.CENTER); move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.EAST); move_up.setMnemonic(KeyEvent.VK_U); movement_pane = new JPanel(); plugin = new JComboBox(available); //plugin.setEditable(true); plugin.setSelectedIndex(0); plugin_label = new JLabel(get("PlugIn")); plugin_list = new JList(assigned); plugin_list.setCellRenderer(new ListRenderer()); plugin_list_label = new JLabel(get("Assigned")); plugin_list_label.setHorizontalAlignment(JLabel.CENTER); plugin_list_label.setOpaque(true); plugin_list_pane = new JPanel(); plugin_pane = new JPanel(); remove = new JButton(get("Remove")); remove.setMnemonic(KeyEvent.VK_R); title = new JLabel(get("Title")); title.setHorizontalAlignment(JLabel.CENTER); title.setOpaque(true); // Listeners add.addActionListener(new AddListener()); configure.addActionListener(new ConfigureListener()); MoveListener ml = new MoveListener(); move_bottom.addActionListener(ml); move_down.addActionListener(ml); move_top.addActionListener(ml); move_up.addActionListener(ml); remove.addActionListener(new RemoveListener()); plugin_list.addMouseListener(new ClickListener()); // Layout title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0)); instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5)); header_pane.setLayout(new BorderLayout()); header_pane.add(title, BorderLayout.NORTH); header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER); plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2)); movement_pane.setLayout(new GridLayout(4,1)); movement_pane.add(move_top); movement_pane.add(move_up); movement_pane.add(move_down); movement_pane.add(move_bottom); plugin_list_pane.setLayout(new BorderLayout()); plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH); plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER); plugin_list_pane.add(movement_pane, BorderLayout.EAST); plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0)); plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); plugin_pane.setLayout(new GridLayout(1,2)); plugin_pane.add(plugin_label); plugin_pane.add(plugin); // Scope these mad bordering skillz. JPanel temp = new JPanel(new BorderLayout()); temp.setBorder (BorderFactory.createCompoundBorder (BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder (BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2)))); temp.add(plugin_pane, BorderLayout.NORTH); temp.add(button_pane, BorderLayout.SOUTH); central_pane.setLayout(new BorderLayout()); central_pane.add(plugin_list_pane, BorderLayout.CENTER); central_pane.add(temp, BorderLayout.SOUTH); button_pane.setLayout(new GridLayout(3,1)); button_pane.add(add); button_pane.add(configure); button_pane.add(remove); setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); setLayout(new BorderLayout()); add(header_pane, BorderLayout.NORTH); add(central_pane, BorderLayout.CENTER); //add(button_pane, BorderLayout.SOUTH); } /** Method which acts like a destructor, tidying up references to persistant objects. */ public void destroy() { } /** This method is overridden in some control classes to allow for the updating of collection configuration when the focus is lost to another view. In this case however the updates are asynchronous and so no 'has the configuration changed without the user updating' check is needed. * @return true if this control has focus, false otherwise. */ public boolean hasFocus() { return super.hasFocus(); } /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called. */ public void updateUI() { if(instructions != null) { instructions.setCaretPosition(0); } super.updateUI(); } /** This class listens for actions upon the add button in the controls, and if detected calls the assignPlugIn() method. */ private class AddListener implements ActionListener { /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls. * @param event An ActionEvent containing information garnered from the control action. */ public void actionPerformed(ActionEvent event) { PlugIn new_plugin = null; Object object = plugin.getSelectedItem(); if(object instanceof PlugIn) { PlugIn target = (PlugIn)object; new_plugin = target.copy(); } else { new_plugin = new PlugIn(object.toString(), "", null); } object = null; // Automatically chain to configuration. This ensures required arguments are filled out. ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, new_plugin); if(ac.display()) { assignPlugIn(new_plugin); plugin_list.setSelectedValue(new_plugin, true); } ac = null; new_plugin = null; plugin.setSelectedIndex(0); } } /** This class listens for actions upon the configure button in the controls, and if detected creates a new ArgumentConfiguration dialog box to allow for configuration. * @see org.greenstone.gatherer.cdm.ArgumentConfiguration */ private class ConfigureListener implements ActionListener { /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls. * @param event An ActionEvent containing information garnered from the control action. */ public void actionPerformed(ActionEvent event) { if(!plugin_list.isSelectionEmpty()) { Object object = plugin_list.getSelectedValue(); if(object instanceof PlugIn) { ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object); if(ac.display()) { assigned.refresh(); } } } } } /** A special list renderer which is able to render separating lines as well. */ private class ListRenderer extends DefaultListCellRenderer { /** 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. * @param list - The JList we're painting. * @param value - The value returned by list.getModel().getElementAt(index) as an Object. * @param index - The cells index as an int. * @param isSelected - true if the specified cell was selected. * @param cellHasFocus - true if the specified cell has the focus. * @return A Component whose paint() method will render the specified value. * @see javax.swing.JList * @see javax.swing.JSeparator * @see javax.swing.ListModel * @see javax.swing.ListSelectionModel */ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if(value instanceof JPanel) { return (JPanel) value; } else { return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } } } /** Listens for double clicks apon the list and react as if the configure button was pushed. */ private class ClickListener extends MouseAdapter { /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt. * @param event A MouseEvent containing information about the mouse click. */ public void mouseClicked(MouseEvent event) { if(event.getClickCount() == 2 ) { if(!plugin_list.isSelectionEmpty()) { Object object = plugin_list.getSelectedValue(); if(object instanceof PlugIn) { ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object); if(ac.display()) { assigned.refresh(); } } } } } } /** Listens for actions apon the move buttons in the manager controls, and if detected calls the movePlugIn() method of the manager with the appropriate details. */ private class MoveListener implements ActionListener { /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls. * @param event An ActionEvent containing information garnered from the control action. */ public void actionPerformed(ActionEvent event) { if(!plugin_list.isSelectionEmpty()) { Object object = plugin_list.getSelectedValue(); if(object instanceof PlugIn) { PlugIn plugin = (PlugIn) object; if(event.getSource() == move_top) { movePlugIn(plugin, true, true); } else if(event.getSource() == move_up) { movePlugIn(plugin, true, false); } else if(event.getSource() == move_down) { movePlugIn(plugin, false, false); } else { movePlugIn(plugin, false, true); } plugin_list.setSelectedValue(plugin, true); } } } } /** This class listens for actions upon the remove button in the controls, and if detected calls the removePlugIn() method. */ private class RemoveListener implements ActionListener { /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls. * @param event An ActionEvent containing information garnered from the control action. */ public void actionPerformed(ActionEvent event) { if(!plugin_list.isSelectionEmpty()) { Object object = plugin_list.getSelectedValue(); if(object instanceof PlugIn) { removePlugIn((PlugIn)object); } } } } } /** Creates a list separator. * Code courtesy of Farwell, Paul. Contact PFarwell@Kronos.com */ static private JPanel getSeparator() { // we put the separator inside a panel to control // its appearance JPanel _sepPanel = new JPanel(); _sepPanel.setOpaque(false); _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3)); _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS)); _sepPanel.add(Box.createRigidArea(new Dimension(0, 4))); _sepPanel.add(new JPopupMenu.Separator()); _sepPanel.add(Box.createRigidArea(new Dimension(0, 4))); return _sepPanel; } }