Ignore:
Timestamp:
2003-07-15T13:55:22+12:00 (21 years ago)
Author:
jmt12
Message:

Major CDM rewrite so it uses DOM.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java

    r4838 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3626 */
    3727package org.greenstone.gatherer.cdm;
    38 
    39 import java.awt.BorderLayout;
    40 import java.awt.Color;
    41 import java.awt.Component;
    42 import java.awt.Dimension;
    43 import java.awt.GridLayout;
    44 import java.awt.event.ActionEvent;
    45 import java.awt.event.ActionListener;
    46 import java.awt.event.MouseAdapter;
    47 import java.awt.event.MouseEvent;
    48 import java.io.BufferedReader;
    49 import java.io.File;
    50 import java.io.FileInputStream;
    51 import java.io.FileOutputStream;
    52 import java.io.InputStream;
    53 import java.io.InputStreamReader;
    54 import java.io.ObjectInputStream;
    55 import java.io.ObjectOutputStream;
    56 import java.io.StringReader;
    57 import java.lang.Exception;
    58 import java.util.ArrayList;
    59 import java.util.Collections;
    60 import java.util.Enumeration;
    61 import java.util.jar.JarFile;
    62 import javax.swing.BorderFactory;
    63 import javax.swing.DefaultListCellRenderer;
    64 import javax.swing.JButton;
    65 import javax.swing.JComboBox;
    66 import javax.swing.JLabel;
    67 import javax.swing.JList;
    68 import javax.swing.JOptionPane;
    69 import javax.swing.JPanel;
    70 import javax.swing.JScrollPane;
    71 import javax.swing.JTextArea;
    72 import javax.swing.ListSelectionModel;
    73 import javax.swing.event.ListSelectionEvent;
    74 import javax.swing.event.ListSelectionListener;
    75 import org.apache.xerces.parsers.DOMParser;
     28/**************************************************************************************
     29 * Written:      01/05/02
     30 * Revised:      16/08/02 Optimized and Commented.
     31 *               11/07/03 DOM support
     32 **************************************************************************************/
     33import java.awt.*;
     34import java.awt.event.*;
     35import java.io.*;
     36import java.util.*;
     37import java.util.jar.*;
     38import javax.swing.*;
     39import javax.swing.event.*;
     40import org.apache.xerces.parsers.*;
    7641import org.greenstone.gatherer.Gatherer;
    7742import org.greenstone.gatherer.cdm.Argument;
     43import org.greenstone.gatherer.cdm.CollectionConfiguration;
    7844import org.greenstone.gatherer.cdm.CollectionDesignManager;
    7945import org.greenstone.gatherer.cdm.CommandTokenizer;
     46import org.greenstone.gatherer.cdm.Control;
    8047import org.greenstone.gatherer.cdm.Classifier;
    8148import org.greenstone.gatherer.cdm.CustomClassifier;
    82 import org.greenstone.gatherer.cdm.DynamicListModel;
     49import org.greenstone.gatherer.cdm.DOMProxyListModel;
    8350import org.greenstone.gatherer.file.FileNode;
    84 import org.greenstone.gatherer.msm.ElementWrapper;
     51import org.greenstone.gatherer.gui.GComboBox;
    8552import org.greenstone.gatherer.msm.MSMEvent;
    8653import org.greenstone.gatherer.msm.MSMListener;
    8754import org.greenstone.gatherer.msm.MSMUtils;
    8855import org.greenstone.gatherer.util.Utility;
    89 import org.w3c.dom.Document;
    90 import org.w3c.dom.Node;
    91 import org.xml.sax.InputSource;
     56import org.w3c.dom.*;
     57import org.xml.sax.*;
    9258/** This class is responsible for keeping track of all the classifiers assigned to this collection, and providing methods for adding and removing them.
    9359 * @author John Thompson, Greenstone Digital Library, University of Waikato
    9460 * @version 2.3
    9561 */
    96 // ####################################################################################
    97 // Optimization                          Saving
    98 // ####################################################################################
    99 // Vector -> ArrayList                   + Memory, + Processor, (pos. - Processor)
    100 // Unnecessary global references         + Memory (5Kb+)
    101 // ####################################################################################
    10262public class ClassifierManager
    103     implements MSMListener {
    104     /** An interface to the Gatherer, the creator of this cdm module, for access to the Greenstone installation directory. */
    105     private Gatherer gatherer = null;
    106     /** A reference to the CollectionDesignManager for access to other configuration managers. */
    107     private CollectionDesignManager manager = null;
     63    extends DOMProxyListModel {
     64
     65    /** The default size for a label. */
     66    static final private Dimension LABEL_SIZE = new Dimension(140, 20);
     67
     68    /** A list of known, but currently unassigned, classifiers. */
     69    private ArrayList library = null;
    10870    /** The controls for editing the contents of this manager. */
    10971    private Control controls = null;
    110     /** A list of assigned classifiers. */
    111     private DynamicListModel assigned = null;
    112     /** A list of known, but currently unassigned, classifiers. */
    113     private DynamicListModel reserve = null;
    114     /** We may have somehow recieved a classifier command that are, in fact, custom classifiers which can refer to classifiers that haven't been parsed yet, so this holds a list of failed commands which are retried after the loading is complete. */
    115     private ArrayList unresolved_commands = null;
     72
     73    private DOMProxyListModel model;
     74
    11675    /** Constructor.
    117      * @param gatherer A reference to the <strong>Gatherer</strong> for access to the Dictionary.
    118      * @param manager A reference to the <strong>CollectionDesignManager</strong> itself.
    119      * @see org.greenstone.gatherer.Gatherer
    12076     * @see org.greenstone.gatherer.cdm.DynamicListModel
    12177     * @see org.greenstone.gatherer.collection.CollectionManager
     
    12379     * @see org.greenstone.gatherer.msm.MSMListener
    12480     */
    125     public ClassifierManager(Gatherer gatherer, CollectionDesignManager manager) {
    126     this.assigned = new DynamicListModel();
    127     this.gatherer = gatherer;
    128     this.manager = manager;
    129     this.unresolved_commands = new ArrayList();
     81    public ClassifierManager() {
     82    super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.CLASSIFY_ELEMENT, new Classifier());
     83    this.model = this;
     84    Gatherer.println("ClassifierManager: " + getSize() + " classifiers parsed.");
     85    // Reload/Create the library
    13086    loadClassifiers();
    13187    saveClassifiers();
    132     // Register as a MSMListener.
    133     Gatherer.c_man.getCollection().msm.addMSMListener(this);
    134     }
    135     /** Method to add a new classifier to reserve.
    136       * @param classifier The new <strong>Classifier</strong>.
     88    }
     89
     90    /** Method to add a new classifier to library.
     91     * @param classifier The new <strong>Classifier</strong>.
     92     * @see org.greenstone.gatherer.cdm.DynamicListModel
     93     */
     94    public void addClassifier(Classifier classifier) {
     95    if(!library.contains(classifier)) {
     96        library.add(classifier);
     97    }
     98    }
     99
     100    /** Method to assign a classifier.
     101     * @param classifier The base <strong>Classifier</strong> to assign.
     102     * @see org.greenstone.gatherer.cdm.DynamicListModel
     103     */
     104    public void assignClassifier(Classifier classifier) {
     105    if(!contains(classifier)) {
     106        Element element = classifier.getElement();
     107        // Locate where we should insert this new classifier.
     108        Node target_node = CollectionConfiguration.findInsertionPoint(element);
     109        add(root, classifier, target_node);
     110        Gatherer.c_man.configurationChanged();
     111    }
     112    }
     113
     114    /** Destructor.
     115     * @see org.greenstone.gatherer.Gatherer
     116     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     117     * @see org.greenstone.gatherer.cdm.DynamicListModel
     118     */
     119    public void destroy() {
     120    if(controls != null) {
     121        controls.destroy();
     122        controls = null;
     123    }
     124    library.clear();
     125    library = null;
     126    }
     127
     128    public Classifier getBaseClassifier(String name) {
     129    int library_size = library.size();
     130    for(int i = 0; i < library_size; i++) {
     131        Classifier classifier = (Classifier) library.get(i);
     132        if(classifier.getName().equals(name)) {
     133        return classifier;
     134        }
     135    }
     136    // No success.
     137    return null;
     138    }
     139
     140    /** Method to retrieve the classifier with the given index.
     141     * @param index The index of the desired classifier as an <i>int</i>.
     142     * @return The requested Classifier or <i>null</i> if no such classifier exists.
     143     */
     144    public Classifier getClassifier(int index) {
     145    if(0 <= index && index < getSize()) {
     146        return (Classifier) getElementAt(index);
     147    }
     148    return null;
     149    }
     150   
     151    /** Method to retrieve the control for this manager.
     152     * @return the Control for editing classifiers
     153     */
     154    public Control getControls() {
     155    if(controls == null) {
     156        // Build controls
     157        this.controls = new ClassifierControl();
     158    }
     159    return controls;
     160    }
     161
     162    /** Method to move a classifier in the list order.
     163     * @param classifier the Classifier you want to move.
     164     * @param direction true to move the classifier up, false to move it down.
     165     * @param all true to move to move all the way, false for a single step.
     166     */
     167    public void moveClassifier(Classifier classifier, boolean direction, boolean all) {
     168    if(getSize() < 2) {
     169        Gatherer.println("Not enough classifiers to allow moving.");
     170        return;
     171    }
     172    if(all) {
     173        // Move to top
     174        if(direction) {
     175        // Remove the moving classifier
     176        remove(classifier);
     177        // Retrieve the first classifier
     178        Classifier first_classifier = (Classifier) getElementAt(0);
     179        // Add the moving classifier before the first classifier
     180        addBefore(classifier, first_classifier);
     181        first_classifier = null;
     182        Gatherer.c_man.configurationChanged();
     183        }
     184        else {
     185        // Remove the moving classifier
     186        remove(classifier);
     187        // And add after last classifier
     188        add(getSize(), classifier);
     189        }
     190    }
     191    else {
     192        // Try to move the classifier one step in the desired direction.
     193        int index = indexOf(classifier);
     194        ///ystem.err.println("Index of " + classifier + " = " + index);
     195        if(direction) {
     196        index--;
     197        if(index < 0) {
     198            String args[] = new String[2];
     199            args[0] = get("CDM.ClassifierManager.Classifier");
     200            args[1] = classifier.getName();
     201            JOptionPane.showMessageDialog(Gatherer.g_man, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     202            return;
     203        }
     204        remove(classifier);
     205        add(index, classifier);
     206        Gatherer.c_man.configurationChanged();
     207        }
     208        else {
     209        index++;
     210        if(index >= getSize()) {
     211            String args[] = new String[2];
     212            args[0] = get("CDM.ClassifierManager.Classifier_Str");
     213            args[1] = classifier.getName();
     214            JOptionPane.showMessageDialog(Gatherer.g_man, get("CDM.Move.At_Bottom", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     215            return;
     216        }
     217        remove(classifier);
     218        add(index, classifier);
     219        Gatherer.c_man.configurationChanged();
     220        }
     221    }
     222    }
     223
     224    /** This method removes an assigned classifier. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a classifier from the library.
     225      * @param classifier The Classifier to remove
    137226      * @see org.greenstone.gatherer.cdm.DynamicListModel
    138227      */
    139     public void addClassifier(Classifier classifier) {
    140     if(!reserve.contains(classifier)) {
    141         reserve.addElement(classifier);
    142     }
    143     }
    144     /** Method to assign a classifier.
    145       * @param classifier The reserve <strong>Classifier</strong> to assign.
    146       * @see org.greenstone.gatherer.cdm.DynamicListModel
     228    public void removeClassifier(Classifier classifier) {
     229    remove(classifier);
     230    Gatherer.c_man.configurationChanged();
     231    }
     232
     233    /** Method to cache the current contents of library (known classifiers) to file.
     234     * @see org.greenstone.gatherer.util.Utility
     235     */
     236    public void saveClassifiers() {
     237    try {
     238        FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat");
     239        ObjectOutputStream out = new ObjectOutputStream(file);
     240        out.writeObject(library);
     241        out.close();
     242    }
     243    catch (Exception error) {
     244    }
     245    }
     246
     247    /** Retrieve a phrase from the dictionary based on a certain key.
     248      * @param key The search <strong>String</strong>.
     249      * @return The matching phrase from the Dictionary.
    147250      */
    148     public void assignClassifier(Classifier classifier) {
    149     if(!assigned.contains(classifier)) {
    150         assigned.addElement(classifier);
    151         classifier.setManager(this);
    152         gatherer.c_man.configurationChanged();
    153     }
    154     }
    155     /** Method to assign a classifier.
    156       * @param classifier The <strong>CustomClassifier</strong> to assign.
    157       * @see org.greenstone.gatherer.cdm.DynamicListModel
     251    private String get(String key) {
     252    return get(key, (String[])null);
     253    }
     254    /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
     255      * @param key The search <strong>String</strong>.
     256      * @param args A <strong>String[]</strong> used to complete and format the returned phrase.
     257      * @return The matching phrase from the Dictionary.
     258      * @see org.greenstone.gatherer.Dictionary
     259      * @see org.greenstone.gatherer.Gatherer
    158260      */
    159     public void assignClassifier(CustomClassifier classifier) {
    160     if(!assigned.contains(classifier)) {
    161         assigned.addElement(classifier);
    162         classifier.setManager(this);
    163         gatherer.c_man.configurationChanged();
    164     }
    165     }
    166     /** Destructor.
    167       * @see org.greenstone.gatherer.Gatherer
    168       * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    169       * @see org.greenstone.gatherer.cdm.DynamicListModel
    170       */
    171     public void destroy() {
    172     // Deregister as a listener
    173     if(gatherer.c_man != null && gatherer.c_man.msm != null) {
    174         gatherer.c_man.msm.removeMSMListener(this);
    175     }
    176     // Null globals
    177     assigned = null;
    178     controls = null;
    179     gatherer = null;
    180     manager = null;
    181     reserve = null;
    182     unresolved_commands = null;
    183     }
    184     /** Method to retrieve the classifier with the given index.
    185       * @param index The index of the desired classifier as an <i>int</i>.
    186       * @return The requested Classifier as an <strong>Object</strong> or <i>null</i> if no such classifier exists.
    187       * @see org.greenstone.gatherer.cdm.DynamicListModel
    188       */
    189     public Object getClassifier(int index) {
    190     if(0 <= index && index < assigned.size()) {
    191         return assigned.get(index);
    192     }
    193     return null;
    194     }
    195     /** Method to retrieve the named classifier.
    196       * @param name The name of the desired classifier as a <strong>String</strong>.
    197       * @return The requested <strong>Classifier</strong> or <i>null</i> if no such classifier exists.
    198       * @see org.greenstone.gatherer.cdm.DynamicListModel
    199       */
    200     public Classifier getClassifier(String name) {
    201     for(int i = 0; i < reserve.size(); i++) {
    202         Classifier classifier = (Classifier)reserve.get(i);
    203         if(classifier.getName().equals(name)) {
    204         return classifier;
    205         }
    206     }
    207     // No success.
    208     return null;
    209     }
    210     /** Method to retrieve the control for this manager.
    211       * @return A <strong>JPanel</strong> containing the controls.
    212       */
    213     public JPanel getControls() {
    214     if(controls == null) {
    215         controls = new Control();
    216     }
    217     return controls;
    218     }
    219     /** Called whenever a metadata element changes significantly.
    220       * @param event A <strong>MSMEvent</strong> choc' full of event informationy goodness.
    221       */
    222     public void elementChanged(MSMEvent event) {
    223     // Don't really care, as the elements dealt with here are all live references so changes like identifier change will propagate immediately.
    224     }
    225     /** Method to find the index of the given classifier within the assigned classifiers.
    226       * @param classifier The <strong>Classifier</strong> whose index you wish to find.
    227       * @return The index of the classifier as an <i>int</i>, which has a value of -1 if the classifier was not found.
    228       * @see org.greenstone.gatherer.cdm.DynamicListModel
    229       */
    230     public int indexOf(Classifier classifier) {
    231     for(int i = 0; i < assigned.size(); i++) {
    232         Object elem = assigned.get(i);
    233         if (elem instanceof Classifier) {
    234         Classifier sibling = (Classifier)elem;
    235         if(sibling.equals(classifier)) {
    236             return i;
    237         }
    238         }
    239     }
    240     return -1;
    241     }
    242     // these two methods assume that a custome classifier can never be the same as a classifier
    243     public int indexOf(CustomClassifier classifier) {
    244     for(int i = 0; i < assigned.size(); i++) {
    245         Object elem = assigned.get(i);
    246         if (elem instanceof CustomClassifier) {
    247         CustomClassifier sibling = (CustomClassifier) assigned.get(i);
    248         if(sibling.equals(classifier)) {
    249             return i;
    250         }
    251         }
    252     }
    253     return -1;
    254     }
    255     /** Method to invalidate controls after a significant change in the system state.
    256       */
    257     public void invalidateControls() {
    258     if(controls != null) {
    259         controls.destroy();
    260     }
    261     controls = null;
    262     }
     261    private String get(String key, String arg) {
     262    String[] args = null;
     263    if(arg != null) {
     264        args = new String[1];
     265        args[0] = arg;
     266    }
     267    return get(key, args);
     268    }
     269
     270    private String get(String key, String[] args) {
     271    if(key.indexOf(".") == -1) {
     272        key = "CDM.ClassifierManager." + key;
     273    }
     274    return Gatherer.dictionary.get(key, args);
     275    }
     276
     277    /** Method to extract just the classifiers name from a file object.
     278     * @param classifier The <strong>File</strong> which references a certain classifier.
     279     * @return A <strong>String</strong> containing just the classifiers name, without extension.
     280     */
     281    private String getClassifierName(File classifier) {
     282    String name = classifier.getName();
     283    if(name.indexOf(".") != -1) {
     284        name = name.substring(0, name.indexOf("."));
     285    }
     286    return name;
     287    }
     288
    263289    /** Method to load the details of a single plug-in.
    264       * @param classifier The classifier <strong>File</strong> you wish to load.
    265       */
    266     public void loadClassifier(File classifier) {
     290     * @param classifier The classifier <strong>File</strong> you wish to load.
     291     */
     292    private void loadClassifier(File classifier) {
    267293    ///ystem.err.println("Attempting to parse " + classifier.toString());
    268294    Document document = null;
     
    274300        if(Utility.isWindows()) {
    275301        args = new String[4];
    276         if(gatherer.config.perl_path != null) {
    277             args[0] = gatherer.config.perl_path;
     302        if(Gatherer.config.perl_path != null) {
     303            args[0] = Gatherer.config.perl_path;
    278304        }
    279305        else {
    280306            args[0] = "Perl.exe";
    281307        }
    282         args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl";
     308        args[1] = Gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl";
    283309        args[2] = "-xml";
    284310        args[3] = getClassifierName(classifier);
     
    334360    }
    335361    if(document != null) {
    336         parse(document.getDocumentElement());
    337     }
    338     }
    339     /** Called whenever the metadata value associated to a certain record changes. */
    340     public void metadataChanged(MSMEvent event) {
    341     FileNode record = event.getRecord();
    342     if(record != null) {
    343         for(int i = 0; i < assigned.size(); i++) {
    344         Object object = assigned.get(i);
    345         if(object instanceof CustomClassifier) {
    346             CustomClassifier classifier = (CustomClassifier) object;
    347             if(!classifier.isProcessing()) { // are we already in the middle of processing??
    348             classifier.process(record);
    349             }
    350         }
    351         }
    352     }
    353     }
    354     /** This method attempts to parse a classifier command from a command string taken from the collection configuration file. This process is quite complex as not only must the correct classifier be matched but also all of the parameters given must be legal. If such a command is found, the classifier is immediately assigned.
    355       * @param command The command <strong>String</strong> that may include classifier information.
    356       * @return <i>true</i> if a classifier command was parsed, <i>false</i> otherwise.
    357       * @see org.greenstone.gatherer.cdm.Argument
    358       * @see org.greenstone.gatherer.cdm.Classifier
    359       * @see org.greenstone.gatherer.cdm.CommandTokenizer
    360       */
    361     public boolean parse(String command) {
    362     String command_lc = command.toLowerCase();
    363     if(command_lc.startsWith("classify")) {
    364         CommandTokenizer tokenizer = new CommandTokenizer(command);
    365         if(tokenizer.countTokens() >= 2) {
    366         tokenizer.nextToken(); // Throw away 'classifier'
    367         String name = tokenizer.nextToken();
    368         // Try to locate the classifier with this name.
    369         Classifier classifier = getClassifier(name);
    370         // And if successful start to parse the arguments.
    371         if(classifier != null) {
    372             // Take a copy.
    373             classifier = classifier.copy();
    374             String key = null;
    375             while((key = tokenizer.nextToken()) != null) {
    376             // Try to retrieve a matching argument.
    377             Argument argument = classifier.getArgument(key);
    378             if(argument != null) {
    379                 // Set as assigned.
    380                 argument.setAssigned(true);
    381                 // And if the argument is of a parameter type, parse a parameter.
    382                 if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
    383                 String value = tokenizer.nextToken();
    384                 ElementWrapper element = null;
    385                 // special check for metadata
    386                 if (argument.getType() == Argument.METADATA) {
    387                     value = value.replace(':', MSMUtils.NS_SEP);
    388                     if (value.indexOf(MSMUtils.NS_SEP)==-1){
    389                     value = Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP + value;
    390                     }
    391                     // Now retrieve the element this refers to, if available.
    392                     element = Gatherer.c_man.getCollection().msm.getElement(value);
    393                 }
    394                 if(element != null) {
    395                     argument.setElementValue(element);
    396                     element = null;
    397                 }
    398                 else {
    399                     argument.setValue(value);
    400                 }
    401                 }
    402             }
    403             // Argument cannot be matched.
    404             else {
    405                 String cur_key = key;
    406                 String value = tokenizer.nextToken();
    407                 if(value.startsWith("-")) {
    408                 key = value;
    409                 value = null;
    410                 }
    411                 else {
    412                 key = null;
    413                 }
    414                 String custom = classifier.getCustom();
    415                 if(custom == null) {
    416                 if(value == null) {
    417                     classifier.setCustom(cur_key);
    418                 }
    419                 else {
    420                     classifier.setCustom(cur_key + " " + value);
    421                 }
    422                 }
    423                 else {
    424                 if(value == null) {
    425                     classifier.setCustom(custom + " " + cur_key);
    426                 }
    427                 else {
    428                     classifier.setCustom(custom + " " + cur_key + " " + value);
    429                 }
    430                 }
    431             }
    432             }
    433             assignClassifier(classifier);
    434             return true;
    435         }
    436         else {
    437             ///ystem.err.println("Unknown classifier");
    438         }
    439         }
    440     }
    441     else if(command_lc.startsWith("customclassifier")) {
    442         unresolved_commands.add(command);
    443         return true;
    444     }
    445     return false;
    446     }
    447     /** This method removes an assigned classifier. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a classifier from the reserve.
    448       * @param classifier The Classifier or CustomClassifier, as an <strong>Object</strong>, to remove.
    449       * @see org.greenstone.gatherer.cdm.DynamicListModel
    450       */
    451     public void removeClassifier(Object classifier) {
    452     assigned.removeElement(classifier);
    453     gatherer.c_man.configurationChanged();
    454     }
    455     /** Method which attempts to reparse obvious classifier commands which previously referenced unresovable Classifiers.
    456       * @see org.greenstone.gatherer.cdm.Classifier
    457       * @see org.greenstone.gatherer.cdm.CommandTokenizer
    458       * @see org.greenstone.gatherer.cdm.CustomClassifier
    459       */
    460     public void reparseUnresolved() {
    461     for(int i = 0; i < unresolved_commands.size(); i++) {
    462         String command = (String) unresolved_commands.get(i);
    463         CommandTokenizer tokenizer = new CommandTokenizer(command);
    464         if(tokenizer.countTokens() >= 6) {
    465         tokenizer.nextToken();// Lose customclassifier
    466         // Get class name.
    467         String class_name = tokenizer.nextToken();
    468         // Parse arguments.
    469         String replaces = null;
    470         String separations = null;
    471         while(tokenizer.hasMoreTokens()) {
    472             String arg_name = tokenizer.nextToken();
    473             if(arg_name.equalsIgnoreCase("-replaces")) {
    474             replaces = tokenizer.nextToken();
    475             }
    476             else if (arg_name.equalsIgnoreCase("-separations")){
    477             separations = tokenizer.nextToken();
    478             }
    479         }
    480         try {
    481             replaces = replaces.substring(2);
    482             int index = Integer.parseInt(replaces);
    483             Classifier original = (Classifier)getClassifier(index);
    484             if(original != null) {
    485             Class custom_classifier_class = Class.forName("org.greenstone.gatherer.cdm.custom." + class_name);
    486             CustomClassifier custom_classifier = (CustomClassifier) custom_classifier_class.newInstance();
    487             custom_classifier.setGatherer(gatherer);
    488             custom_classifier.recreate(original, separations);
    489             assigned.add(index, custom_classifier);
    490             assigned.removeElement(original);
    491             }
    492             else {
    493             ///ystem.err.println("Missing original.");
    494             }
    495         }
    496         catch (Exception error) {
    497             error.printStackTrace();
    498         }
    499         }
    500     }
    501     // Regardless of if they work, clear the commands.
    502     unresolved_commands.clear();
    503     }
    504     /** Method to cache the current contents of reserve (known classifiers) to file.
    505       * @see org.greenstone.gatherer.util.Utility
    506       */
    507     public void saveClassifiers() {
    508     try {
    509         FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat");
    510         ObjectOutputStream out = new ObjectOutputStream(file);
    511         out.writeObject(reserve);
    512         out.close();
    513     }
    514     catch (Exception error) {
    515     }
    516     }
    517     /** Called when a metadata set changed significantly.
    518       * @param event A <strong>MSMEvent</strong> containing information about the set change.
    519       */
    520     public void setChanged(MSMEvent event) {
    521     // Again, we would only worry about this if we contained 'inanimate' references to elements or something, but our references are live, and controls are rebuilt everytime a pop-up is needed.
    522     }
    523     /** Method used to determine the number of classifiers that have been assigned.
    524       * @return An <i>int</i> which is the number of classifiers.
    525       */
    526     public int size() {
    527     return assigned.size();
    528     }
    529     /** Method to print out a block of classifier commands, much like you'd find in a collection configuration file.
    530       * @return A <strong>String</strong> containing a series of classifier commands separated by new lines.
    531       * @see org.greenstone.gatherer.cdm.Classifier
    532       * @see org.greenstone.gatherer.cdm.CustomClassifier
    533       */
    534     public String toString() {
    535     StringBuffer text = new StringBuffer();
    536     for(int i = 0; i < assigned.size(); i++) {
    537         Object object = assigned.get(i);
    538         if(object instanceof Classifier) {
    539         Classifier classifier = (Classifier) object;
    540         text.append(classifier.toStringConfig());
    541         }
    542         else if(object instanceof CustomClassifier) {
    543         CustomClassifier classifier = (CustomClassifier) object;
    544         text.append(classifier.getCommand());
    545         text.append("\n");
    546         text.append(classifier.getCustomCommand(i));
    547         }
    548         text.append("\n");
    549     }
    550     text.append("\n");
    551     return text.toString();
    552     }
    553     /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
    554       * @param event A <strong>MSMEvent</strong> containing information relevant to the event.
    555       */
    556     public void valueChanged(MSMEvent event) {
    557     }
    558     /** Retrieve a phrase from the dictionary based on a certain key.
    559       * @param key The search <strong>String</strong>.
    560       * @return The matching phrase from the Dictionary.
    561       */
    562     private String get(String key) {
    563     return get(key, null);
    564     }
    565     /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
    566       * @param key The search <strong>String</strong>.
    567       * @param args A <strong>String[]</strong> used to complete and format the returned phrase.
    568       * @return The matching phrase from the Dictionary.
    569       * @see org.greenstone.gatherer.Dictionary
    570       * @see org.greenstone.gatherer.Gatherer
    571       */
    572     private String get(String key, String arg) {
    573     String[] args = null;
    574     if(arg != null) {
    575         args = new String[1];
    576         args[0] = arg;
    577     }
    578     if(key.indexOf(".") == -1) {
    579         key = "CDM.ClassifierManager." + key;
    580     }
    581     return gatherer.dictionary.get(key, args);
    582     }
    583     /** Method to extract just the classifiers name from a file object.
    584       * @param classifier The <strong>File</strong> which references a certain classifier.
    585       * @return A <strong>String</strong> containing just the classifiers name, without extension.
    586       */
    587     private String getClassifierName(File classifier) {
    588     String name = classifier.getName();
    589     if(name.indexOf(".") != -1) {
    590         name = name.substring(0, name.indexOf("."));
    591     }
    592     return name;
    593     }
     362        parseXML(document.getDocumentElement());
     363    }
     364    }
     365
    594366    /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
    595       * @see org.greenstone.gatherer.cdm.DynamicListModel
    596       * @see org.greenstone.gatherer.util.Utility
    597       */
     367     * @see org.greenstone.gatherer.util.Utility
     368     */
    598369    private void loadClassifiers() {
    599370    // Attempt to restore the cached file.
     
    601372        FileInputStream file = new FileInputStream(Utility.BASE_DIR + "classifiers.dat");
    602373        ObjectInputStream input = new ObjectInputStream(file);
    603         reserve = (DynamicListModel) input.readObject();
     374        library = (ArrayList) input.readObject();
    604375    }
    605376    catch (Exception error) {
    606377    }
    607     if(reserve == null) {
    608         reserve = new DynamicListModel();
    609                 // Retrieve the gsdl home directory...
    610         String directory = gatherer.config.gsdl_path;
     378    if(library == null) {
     379        library = new ArrayList();
     380        // Retrieve the gsdl home directory...
     381        String directory = Gatherer.config.gsdl_path;
    611382        directory = directory + "perllib" + File.separator + "classify" + File.separator;
    612         loadClassifiers(new File(directory));
    613     }
    614     }
    615     /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
    616       * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
    617       * @see org.greenstone.gatherer.cdm.ParsingProgress
    618       */
    619     private void loadClassifiers(File directory) {
    620     File files[] = directory.listFiles();
    621     if(files != null) {
    622         // Create a progress indicator.
    623         ParsingProgress progress = new ParsingProgress(get("CDM.ClassifierManager.Parsing.Title"), get("CDM.ClassifierManager.Parsing.Message"), files.length);
    624         for(int i = 0; i < files.length; i++) {
    625         // We only want to check Perl Modules.
    626         if(files[i].getName().endsWith(".pm")) {
    627             loadClassifier(files[i]);
    628         }
    629         progress.inc();
    630         }
    631         progress.dispose();
    632         progress.destroy();
    633         progress = null;
    634     }
    635     }
     383        File files[] = (new File(directory)).listFiles();
     384        if(files != null) {
     385        // Create a progress indicator.
     386        ParsingProgress progress = new ParsingProgress(get("CDM.ClassifierManager.Parsing.Title"), get("CDM.ClassifierManager.Parsing.Message"), files.length);
     387        for(int i = 0; i < files.length; i++) {
     388            // We only want to check Perl Modules.
     389            if(files[i].getName().endsWith(".pm")) {
     390            loadClassifier(files[i]);
     391            }
     392            progress.inc();
     393        }
     394        progress.dispose();
     395        progress.destroy();
     396        progress = null;
     397        }
     398    }
     399    }
     400
    636401    /** Parses a DOM tree model turning it into a Classifier and its associated arguments.
    637402      * @param root The <strong>Node</strong> at the root of the DOM model.
     
    639404      * @see org.greenstone.gatherer.cdm.Argument
    640405      */
    641     private Classifier parse(Node root) {
     406    private Classifier parseXML(Node root) {
    642407    Classifier classifier = new Classifier();
    643408    String node_name = null;
     
    648413        String name = MSMUtils.getValue(node);
    649414        // We can save ourselves some processing time if a classifier with this name already exists in our manager. If so retrieve it and return it.
    650         Classifier existing = getClassifier(name);
     415        Classifier existing = getBaseClassifier(name);
    651416        if(existing != null) {
    652417            return existing;
     
    655420        }
    656421        else if(node_name.equals("Desc")) {
    657         classifier.setDesc(MSMUtils.getValue(node));
     422        classifier.setDescription(MSMUtils.getValue(node));
    658423        }
    659424        // Parse the multitude of arguments.
     
    671436                }
    672437                else if(node_name.equals("Desc")) {
    673                 argument.setDesc(MSMUtils.getValue(det));
     438                argument.setDescription(MSMUtils.getValue(det));
    674439                }
    675440                else if(node_name.equals("Type")) {
     
    677442                }
    678443                else if(node_name.equals("Default")) {
    679                 argument.setDefault(MSMUtils.getValue(det));
     444                argument.setDefaultValue(MSMUtils.getValue(det));
    680445                }
    681446                else if(node_name.equals("List")) {
     
    713478            // A super classifier class.
    714479            else if(node_name.equals("ClasInfo")) {
    715             Classifier super_classifier = parse(arg);
     480            Classifier super_classifier = parseXML(arg);
    716481            classifier.setSuper(super_classifier);
    717482            }
     
    726491    }
    727492    /** A class which provides controls for assigned and editing classifiers. */
    728     private class Control
    729     extends JPanel {
     493    private class ClassifierControl
     494    extends JPanel
     495    implements Control {
     496    /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
     497    private GComboBox classifier = null;
    730498    /** Button for adding classifiers. */
    731499    private JButton add = null;
    732500    /** Button for configuring the selected classifier. */
    733501    private JButton configure = null;
     502
     503    private JButton move_bottom_button;
     504
     505    private JButton move_down_button;
     506
     507    private JButton move_top_button;
     508
     509    private JButton move_up_button;
     510
    734511    /** Button to remove the selected classifier. */
    735512    private JButton remove = null;
    736     /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
    737     private JComboBox classifier = null;
     513
    738514    /** A list of assigned classifiers. */
    739515    private JList classifier_list = null;
     
    745521     * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.RemoveListener
    746522     */
    747     public Control() {
    748         Object classifiers[] = reserve.toArray();
    749         ArrayList classifier_model = new ArrayList();
    750         for(int i = 0; i < classifiers.length; i++) {
    751         classifier_model.add(((Classifier)classifiers[i]).getName());
    752         }
    753         // Now we add custom classifiers.
    754         addCustomClassifiers(classifier_model);
    755         Collections.sort(classifier_model);
     523    public ClassifierControl() {
     524        Collections.sort(library);
    756525        // Create
    757526        add = new JButton(get("Add"));
     
    766535        instructions.setRows(5);
    767536        instructions.setWrapStyleWord(true);
    768         classifier = new JComboBox(classifier_model.toArray());
    769         classifier.setEditable(false);
     537
     538        classifier = new GComboBox(library.toArray());
     539        classifier.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.editable", false));
     540        classifier.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.collection_selection_background", false));
     541        classifier.setEditable(true);
     542        classifier.setSelectedIndex(0);
     543        classifier.setTextNonSelectionColor(Gatherer.config.getColor("coloring.workspace_tree_foreground", false));
     544        classifier.setTextSelectionColor(Gatherer.config.getColor("coloring.collection_selection_foreground", false));
     545
    770546        JLabel classifier_label = new JLabel(get("Classifier"));
    771         classifier_list = new JList(assigned);
     547        classifier_list = new JList(model);
    772548        classifier_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    773549        JLabel classifier_list_label = new JLabel(get("Assigned"));
     
    782558        title.setOpaque(true);
    783559        JPanel temp = new JPanel(new BorderLayout());
     560
     561        JPanel move_button_pane = new JPanel();
     562
     563        move_bottom_button = new JButton();
     564        JLabel move_bottom_label = new JLabel(get("CDM.Move.Move_Bottom"));
     565        move_bottom_label.setHorizontalAlignment(JLabel.CENTER);
     566        move_bottom_label.setPreferredSize(LABEL_SIZE);
     567        ImageIcon move_bottom_icon = Utility.getImage("arrow-bottom.gif");
     568        move_bottom_button.setLayout(new BorderLayout());
     569        move_bottom_button.add(new JLabel(move_bottom_icon), BorderLayout.WEST);
     570        move_bottom_button.add(move_bottom_label, BorderLayout.CENTER);
     571        move_bottom_button.add(new JLabel(move_bottom_icon), BorderLayout.EAST);
     572        move_bottom_button.setMnemonic(KeyEvent.VK_B);
     573
     574        move_down_button = new JButton();
     575        JLabel move_down_label = new JLabel(get("CDM.Move.Move_Down"));
     576        move_down_label.setHorizontalAlignment(JLabel.CENTER);
     577        move_down_label.setPreferredSize(LABEL_SIZE);
     578        ImageIcon move_down_icon = Utility.getImage("arrow-down.gif");
     579        move_down_button.setLayout(new BorderLayout());
     580        move_down_button.add(new JLabel(move_down_icon), BorderLayout.WEST);
     581        move_down_button.add(move_down_label, BorderLayout.CENTER);
     582        move_down_button.add(new JLabel(move_down_icon), BorderLayout.EAST);
     583        move_down_button.setMnemonic(KeyEvent.VK_D);
     584
     585        move_top_button = new JButton();
     586        JLabel move_top_label = new JLabel(get("CDM.Move.Move_Top"));
     587        move_top_label.setHorizontalAlignment(JLabel.CENTER);
     588        move_top_label.setPreferredSize(LABEL_SIZE);
     589        ImageIcon move_top_icon = Utility.getImage("arrow-top.gif");
     590        move_top_button.setLayout(new BorderLayout());
     591        move_top_button.add(new JLabel(move_top_icon), BorderLayout.WEST);
     592        move_top_button.add(move_top_label, BorderLayout.CENTER);
     593        move_top_button.add(new JLabel(move_top_icon), BorderLayout.EAST);
     594        move_top_button.setMnemonic(KeyEvent.VK_T);
     595
     596        move_up_button = new JButton();
     597        JLabel move_up_label = new JLabel(get("CDM.Move.Move_Up"));
     598        move_up_label.setHorizontalAlignment(JLabel.CENTER);
     599        move_up_label.setPreferredSize(LABEL_SIZE);
     600        ImageIcon move_up_icon = Utility.getImage("arrow-up.gif");
     601        move_up_button.setLayout(new BorderLayout());
     602        move_up_button.add(new JLabel(move_up_icon), BorderLayout.WEST);
     603        move_up_button.add(move_up_label, BorderLayout.CENTER);
     604        move_up_button.add(new JLabel(move_up_icon), BorderLayout.EAST);
     605        move_up_button.setMnemonic(KeyEvent.VK_U);
     606
    784607        // Listeners
    785608        add.addActionListener(new AddListener());
     
    788611        classifier_list.addMouseListener(new ClickListener());
    789612        classifier_list.addListSelectionListener(new ListListener());
     613
     614        MoveListener ml = new MoveListener();
     615        move_bottom_button.addActionListener(ml);
     616        move_down_button.addActionListener(ml);
     617        move_top_button.addActionListener(ml);
     618        move_up_button.addActionListener(ml);
    790619        // Layout
    791620        title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
     621
    792622        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     623
    793624        header_pane.setLayout(new BorderLayout());
    794625        header_pane.add(title, BorderLayout.NORTH);
    795626        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     627
     628        move_button_pane.setLayout(new GridLayout(4,1));
     629        move_button_pane.add(move_top_button);
     630        move_button_pane.add(move_up_button);
     631        move_button_pane.add(move_down_button);
     632        move_button_pane.add(move_bottom_button);
     633
    796634        classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
     635
    797636        classifier_list_pane.setLayout(new BorderLayout());
    798637        classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
    799638        classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
     639        classifier_list_pane.add(move_button_pane, BorderLayout.EAST);
     640
    800641        classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     642
    801643        classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    802644        classifier_pane.setLayout(new GridLayout(1,2));
    803645        classifier_pane.add(classifier_label);
    804646        classifier_pane.add(classifier);
     647
    805648        button_pane.setLayout(new GridLayout(3,1));
    806649        button_pane.add(add);
    807650        button_pane.add(configure);
    808651        button_pane.add(remove);
     652
    809653        // Scope these mad bordering skillz.
    810654        temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
    811655        temp.add(classifier_pane, BorderLayout.NORTH);
    812656        temp.add(button_pane, BorderLayout.SOUTH);
     657
    813658        central_pane.setLayout(new BorderLayout());
    814659        central_pane.add(classifier_list_pane, BorderLayout.CENTER);
    815660        central_pane.add(temp, BorderLayout.SOUTH);
     661
    816662        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    817663        setLayout(new BorderLayout());
     
    831677    /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
    832678            */
    833     public void updateUI() {
     679    public void gainFocus() {
    834680        if(instructions != null) {
    835681        instructions.setCaretPosition(0);
    836682        }
    837         super.updateUI();
    838     }
    839     /** Searches and adds a list of dynamically located CustomClassifiers. Note that the classes must be located under org.greenstone.gatherer.cdm.custom and have accompaning properties files which are used as dictionaries.
    840             * @param classifier_model An <strong>ArrayList</strong> which will be used as the model for the combobox listing all known Classifiers.
    841             */
    842     private void addCustomClassifiers(ArrayList classifier_model) {
    843         //classifier_model.add("CustomAZList");
    844         // Search for classifiers under the org.greenstone.gatherer.cdm.custom directory.
    845         File custom_directory = new File(Utility.BASE_DIR + "classes" + File.separator + "org" + File.separator + "greenstone" + File.separator + "gatherer" + File.separator + "cdm" + File.separator + "custom");
    846         if(custom_directory.exists()) {
    847         File children[] = custom_directory.listFiles();
    848         for(int i = 0; i < children.length; i++) {
    849             String temp = children[i].getName().toLowerCase();
    850             // There are a whole bunch of conditions about what files are custom classifier main classes.
    851             if(temp.endsWith(".class") && temp.indexOf("$") == -1) {
    852             // Determine the name of this custom classifier.
    853             String name = children[i].getName();
    854             name = name.substring(0, name.indexOf("."));
    855             classifier_model.add(name);
    856             }
    857         }
    858         }
    859         // Search for any other CustomClassifiers within the jar file (if present)
    860         File jar_file = new File(Utility.GLI_ARCHIVE);
    861         if(jar_file.exists()) {
    862         try {
    863             JarFile jar = new JarFile(jar_file);
    864             for(Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
    865             String name = entries.nextElement().toString();
    866             if(name.startsWith("org/greenstone/gatherer/cdm/custom/") && name.endsWith(".class") && name.indexOf("$") == -1) {
    867                 name = name.substring(35, name.length() - 6);
    868                 if(!classifier_model.contains(name)) {
    869                 classifier_model.add(name);
    870                 }
    871             }
    872             name = null;
    873             }
    874             jar = null;
    875         }
    876         catch (Exception error) {
    877             error.printStackTrace();
    878         }
    879         }
    880         jar_file = null;
    881     }
     683    }
     684
     685    public void loseFocus() {
     686    }
     687
    882688    /** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method.
    883             */
     689     */
    884690    private class AddListener
    885691        implements ActionListener {
     
    892698         */
    893699        public void actionPerformed(ActionEvent event) {
    894         String name = (String)classifier.getSelectedItem();
    895         Classifier target = getClassifier(name);
    896         Classifier classifier = null;
    897         CustomClassifier custom_classifier = null;
    898         if(target != null) {
    899             classifier = target.copy();
    900         }
    901         else {
    902             // Try to retrieve custom classifier for name.
    903             try {
    904             Class custom_class = Class.forName("org.greenstone.gatherer.cdm.custom." + name);
    905             custom_classifier = (CustomClassifier)custom_class.newInstance();
    906             custom_classifier.setGatherer(gatherer);
    907             }
    908             catch (Exception error) {
    909             Gatherer.println("Error in ClassifierManager.AddListener.actionPerformed(): " + error);
    910             Gatherer.printStackTrace(error);
    911            
    912             }
    913             // And if all else fails create a new classifier.
    914             if(classifier == null && custom_classifier == null) {
    915             classifier = new Classifier(name, "", null);
    916             }
    917         }
    918         if(classifier != null) {
     700        Object selected_object = classifier.getSelectedItem();
     701        // If there is something in the combobox, but we haven't registered a selection, then add the object and select it!
     702        if(selected_object != null && classifier.getSelectedIndex() == -1) {
     703            classifier.insertItemAt(selected_object, classifier.getItemCount());
     704        }
     705        if(selected_object != null) {
     706            // Create a new element in the DOM
     707            Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.CLASSIFY_ELEMENT);
     708            Classifier new_classifier = null;
     709            if(selected_object instanceof Classifier) {
     710            Classifier base_classifier = (Classifier) selected_object;
     711            element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_classifier.getName());
     712            new_classifier = new Classifier(element, base_classifier);
     713            base_classifier = null;
     714            }
     715            else {
     716            element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
     717            new_classifier = new Classifier(element, null);
     718            }
     719            element = null;
    919720            // Automatically chain to configuration. This ensures required arguments are filled out.
    920             ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, classifier);
     721            ArgumentConfiguration ac = new ArgumentConfiguration(new_classifier);
    921722            if(ac.display()) {
    922             assignClassifier(classifier);
    923             }
    924             ac.destroy();
     723            if(!model.contains(new_classifier)) {
     724                assignClassifier(new_classifier);
     725                classifier_list.setSelectedValue(new_classifier, true);
     726            }
     727            else {
     728                JOptionPane.showMessageDialog(Gatherer.g_man, get("Classifier_Exists"), get("General.Error"), JOptionPane.ERROR_MESSAGE);
     729            }
     730            }
    925731            ac = null;
    926         }
    927         // Custom classifier
    928         else {
    929             // Spawn a new thread to handle this, as custom_classifiers can be processor heavy.
    930             CustomClassifierTask task = new CustomClassifierTask(custom_classifier);
    931             task.start();
     732            new_classifier = null;
     733            classifier.setSelectedIndex(0);
    932734        }
    933735        }
     
    936738    private class ClickListener
    937739        extends MouseAdapter {
    938                 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
    939                 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
    940                 */
     740        /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
     741        * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
     742        */
    941743        public void mouseClicked(MouseEvent event) {
    942744        if(event.getClickCount() == 2 ) {
    943745            if(!classifier_list.isSelectionEmpty()) {
    944             Object object = classifier_list.getSelectedValue();
    945             if(object instanceof Classifier) {
    946                 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
    947                 if(ac.display()) {
    948                 assigned.refresh();
    949                 }
    950                 ac.destroy();
    951                 ac = null;
     746            Classifier classifier = (Classifier) classifier_list.getSelectedValue();
     747            ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
     748            if(ac.display()) {
     749                refresh(classifier);
    952750            }
    953             else if(object instanceof CustomClassifier) {
    954                 CustomClassifier cc = (CustomClassifier)object;
    955                 if(cc.display(true)) {
    956                 assigned.refresh();
    957                 }
    958                 cc.hide(); // Remove gui prompt or else.
    959                 cc = null;
    960             }
     751            ac.destroy();
     752            ac = null;
    961753            }
    962754        }
     
    975767        public void actionPerformed(ActionEvent event) {
    976768        if(!classifier_list.isSelectionEmpty()) {
    977             Object object = classifier_list.getSelectedValue();
    978             if(object instanceof Classifier) {
    979             ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
    980             if(ac.display()) {
    981                 assigned.refresh();
    982             }
    983             ac.destroy();
    984             ac = null;
    985             }
    986             else if(object instanceof CustomClassifier) {
    987             CustomClassifier cc = (CustomClassifier)object;
    988             if(cc.display(true)) {
    989                 assigned.refresh();
    990             }
    991             cc.hide(); // Remove gui prompt or else.
    992             cc = null;
    993             }
    994         }
    995         }
    996     }
    997 
    998     private class CustomClassifierTask
    999         extends Thread {
    1000 
    1001         private CustomClassifier custom_classifier;
    1002 
    1003         CustomClassifierTask(CustomClassifier custom_classifier) {
    1004         this.custom_classifier = custom_classifier;
    1005         }
    1006 
    1007         public void run() {
    1008         if(custom_classifier.display(true)) {
    1009             assignClassifier(custom_classifier);
    1010         }
    1011         custom_classifier.hide(); // Remove gui prompt or else.
    1012         custom_classifier = null;
     769           Classifier classifier = (Classifier) classifier_list.getSelectedValue();
     770           ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
     771           if(ac.display()) {
     772               refresh(classifier);
     773           }
     774           ac.destroy();
     775           ac = null;
     776        }
    1013777        }
    1014778    }
     
    1030794        }
    1031795    }
     796
     797    /** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>moveClassifier()</i> method of the manager with the appropriate details. */
     798    private class MoveListener
     799        implements ActionListener {
     800        /** 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.
     801         * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
     802         */
     803        public void actionPerformed(ActionEvent event) {
     804        if(!classifier_list.isSelectionEmpty()) {
     805            Object object = classifier_list.getSelectedValue();
     806            if(object instanceof Classifier) {
     807            Classifier classifier = (Classifier) object;
     808            if(event.getSource() == move_top_button) {
     809                moveClassifier(classifier, true, true);
     810            }
     811            else if(event.getSource() == move_up_button) {
     812                moveClassifier(classifier, true, false);
     813            }
     814            else if(event.getSource() == move_down_button) {
     815                moveClassifier(classifier, false, false);
     816            }
     817            else {
     818                moveClassifier(classifier, false, true);
     819            }
     820            classifier_list.setSelectedValue(classifier, true);
     821            }
     822        }
     823        }
     824    }
     825
    1032826    /** This class listens for actions upon the remove button in the controls, and if detected calls the removeClassifier() method.
    1033827            */
     
    1041835        public void actionPerformed(ActionEvent event) {
    1042836        if(!classifier_list.isSelectionEmpty()) {
    1043             Object object = classifier_list.getSelectedValue();
    1044             if(object instanceof Classifier || object instanceof CustomClassifier) {
    1045             removeClassifier(object);
     837            Object [] objects = classifier_list.getSelectedValues();
     838            for(int i = 0; i < objects.length; i++) {
     839            if(objects[i] instanceof Classifier) {
     840                removeClassifier((Classifier)objects[i]);
     841            }
    1046842            }
    1047843        }
     
    1050846    }
    1051847}
    1052 
    1053 
    1054 
    1055 
    1056 
    1057 
Note: See TracChangeset for help on using the changeset viewer.