Ignore:
Timestamp:
2003-05-27T15:57:37+12:00 (21 years ago)
Author:
kjdon
Message:

re-tabbed the code for java

Location:
trunk/gli/src/org/greenstone/gatherer/cdm
Files:
29 edited

Legend:

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

    r4293 r4366  
    6969
    7070public class Argument
    71     implements Comparable, Serializable {
    72     /** If this argument has multiple values, then they are stored here. This was originally a Hashtable, but since the synchronization overhead is unwarrented it was changed to a HashMap. */
    73     private ArrayList values = null;
    74     /** <i>true</i> if this argument is required for the applicable script to work properly, <i>false</i> otherwise. */
    75     private boolean required = false;
    76     /** The type of this argument. Initially an int, but bytes are cheaper. */
    77     private byte type = FLAG;
    78     /** If the argument is of type ENUM then this map holds all the various options. Each entry is an &lt;option value&gt; -&gt; &lt;description&gt; mapping. */
    79     private HashMap list = null;
    80     /** A default value for parameter-type arguments. May be a Perl pattern. */
    81     private String default_value = null;
    82     /** The text description of this argument parsed from the pluginfo output. */
    83     private String desc = null;
    84     /** The argument flag as it appears in the command. Also used as the unique identifier of an argument. */
    85     private String name = null;
    86     /** The plugin that owns this argument, for the purposes of visualising inheritance. */
    87     private String owner = null;
    88     /** If this argument has been assigned, what is its value. Must be non-null for the argument to be printed. */
    89     private String value = null;
    90     /** An element of the argument type enumeration. */
    91     static final public byte ENUM = 0;
    92     /** An element of the argument type enumeration. */
    93     static final public byte FLAG = 1;
    94     /** An element of the argument type enumeration. */
    95     static final public byte HIERARCHY = 2;
    96     /** An element of the argument type enumeration. */
    97     static final public byte INTEGER = 3;
    98     /** An element of the argument type enumeration. */
    99     static final public byte LANGUAGE = 4;
    100     /** An element of the argument type enumeration. */
    101     static final public byte METADATA = 5;
    102     /** An element of the argument type enumeration. */
    103     static final public byte METADATUM = 6;
    104     /** An element of the argument type enumeration. */
    105     static final public byte STRING = 7;
    106     /** Default Constructor. */
    107     public Argument() {
    108     }
    109     /** Normal Constructor, based on data parsed from an information script.
     71    implements Comparable, Serializable {
     72    /** If this argument has multiple values, then they are stored here. This was originally a Hashtable, but since the synchronization overhead is unwarrented it was changed to a HashMap. */
     73    private ArrayList values = null;
     74    /** <i>true</i> if this argument is required for the applicable script to work properly, <i>false</i> otherwise. */
     75    private boolean required = false;
     76    /** The type of this argument. Initially an int, but bytes are cheaper. */
     77    private byte type = FLAG;
     78    /** If the argument is of type ENUM then this map holds all the various options. Each entry is an &lt;option value&gt; -&gt; &lt;description&gt; mapping. */
     79    private HashMap list = null;
     80    /** A default value for parameter-type arguments. May be a Perl pattern. */
     81    private String default_value = null;
     82    /** The text description of this argument parsed from the pluginfo output. */
     83    private String desc = null;
     84    /** The argument flag as it appears in the command. Also used as the unique identifier of an argument. */
     85    private String name = null;
     86    /** The plugin that owns this argument, for the purposes of visualising inheritance. */
     87    private String owner = null;
     88    /** If this argument has been assigned, what is its value. Must be non-null for the argument to be printed. */
     89    private String value = null;
     90    /** An element of the argument type enumeration. */
     91    static final public byte ENUM = 0;
     92    /** An element of the argument type enumeration. */
     93    static final public byte FLAG = 1;
     94    /** An element of the argument type enumeration. */
     95    static final public byte HIERARCHY = 2;
     96    /** An element of the argument type enumeration. */
     97    static final public byte INTEGER = 3;
     98    /** An element of the argument type enumeration. */
     99    static final public byte LANGUAGE = 4;
     100    /** An element of the argument type enumeration. */
     101    static final public byte METADATA = 5;
     102    /** An element of the argument type enumeration. */
     103    static final public byte METADATUM = 6;
     104    /** An element of the argument type enumeration. */
     105    static final public byte STRING = 7;
     106    /** Default Constructor. */
     107    public Argument() {
     108    }
     109    /** Normal Constructor, based on data parsed from an information script.
    110110      * @param name The argument flag as it appears in the command, as a <strong>String</strong>. Also used as the unique identifier of an argument.
    111111      * @param desc The text description of this argument parsed from the output as a <strong>String</strong>.
     
    113113      * @param default_value The default value for a parameter type argument, which may include a Perl type regular expression, as a <strong>String</strong>.
    114114      */
    115     public Argument(String name, String desc, byte type, String default_value) {
    116           this.default_value = default_value;
    117           this.desc = desc;
    118           this.name = name;
    119           this.type = type;
    120           if(type == ENUM) {
    121                 this.list = new HashMap();
    122           }
    123           if(type == METADATUM) {
    124                 values = new ArrayList();
    125           }
    126     }
    127     /** Method to add an element to the option list.
     115    public Argument(String name, String desc, byte type, String default_value) {
     116    this.default_value = default_value;
     117    this.desc = desc;
     118    this.name = name;
     119    this.type = type;
     120    if(type == ENUM) {
     121        this.list = new HashMap();
     122    }
     123    if(type == METADATUM) {
     124        values = new ArrayList();
     125    }
     126    }
     127    /** Method to add an element to the option list.
    128128      * @param name The name value of the option as a <strong>String</strong>.
    129129      * @param desc The description of this options as a <strong>String</strong>.
    130130      */
    131     public void addOption(String name, String desc) {
    132           if(type == ENUM && name != null) {
    133                 if(desc == null) {
    134                      desc = "";
    135                 }
    136                 if(!list.containsKey(name)) {
    137                      list.put(name, desc);
    138                 }
    139           }
    140     }
    141     /** Method to compare two arguments for ordering.
     131    public void addOption(String name, String desc) {
     132    if(type == ENUM && name != null) {
     133        if(desc == null) {
     134        desc = "";
     135        }
     136        if(!list.containsKey(name)) {
     137        list.put(name, desc);
     138        }
     139    }
     140    }
     141    /** Method to compare two arguments for ordering.
    142142      * @param object The argument we are comparing to, as an <strong>Object</strong>.
    143143      * @return An <i>int</i> specifying the argument order, using values as set out in String.
     
    145145      * @see org.greenstone.gatherer.cdm.Argument
    146146      */
    147     public int compareTo(Object object) {
    148           Argument argument = (Argument)object;
    149           return getName().compareTo(argument.getName());
    150     }
    151     /** Method to deep copy this argument.
     147    public int compareTo(Object object) {
     148    Argument argument = (Argument)object;
     149    return getName().compareTo(argument.getName());
     150    }
     151    /** Method to deep copy this argument.
    152152      * @return A newly created <strong>Argument</strong> which has the same details as this one.
    153153      */
    154     public Argument copy() {
    155           Argument copy = new Argument(name, desc, type, default_value);
    156           copy.setRequired(required);
    157           if(values != null) {
    158                 copy.setValues(values);
    159           }
    160           if(list != null) {
    161                 HashMap list_deep_copy = new HashMap();
    162                 Iterator it = list.keySet().iterator();
    163                 while(it.hasNext()) {
    164                      String key = (String) it.next();
    165                      String desc = (String) list.get(key);
    166                      list_deep_copy.put(new String(key), new String(desc));
    167                 }
    168                 copy.setOptions(list_deep_copy);
    169           }
    170           return copy;
    171     }
    172     /** Method to determine if two arguments are equal.
     154    public Argument copy() {
     155    Argument copy = new Argument(name, desc, type, default_value);
     156    copy.setRequired(required);
     157    if(values != null) {
     158        copy.setValues(values);
     159    }
     160    if(list != null) {
     161        HashMap list_deep_copy = new HashMap();
     162        Iterator it = list.keySet().iterator();
     163        while(it.hasNext()) {
     164        String key = (String) it.next();
     165        String desc = (String) list.get(key);
     166        list_deep_copy.put(new String(key), new String(desc));
     167        }
     168        copy.setOptions(list_deep_copy);
     169    }
     170    return copy;
     171    }
     172    /** Method to determine if two arguments are equal.
    173173      * @param object The argument to test against, as an <strong>Object</strong>.
    174174      * @return <i>true</i> if the arguments names match, <i>false</i> otherwise.
    175175      */
    176     public boolean equals(Object object) {
    177           return (compareTo(object) == 0);
    178     }
    179     /** Method to retrieve the value of default_value.
     176    public boolean equals(Object object) {
     177    return (compareTo(object) == 0);
     178    }
     179    /** Method to retrieve the value of default_value.
    180180      * @return A <strong>String</strong> containing the default value.
    181181      */
    182     public String getDefaultValue() {
    183           return default_value;
    184     }
    185     /** Method to retrieve this arguments description.
     182    public String getDefaultValue() {
     183    return default_value;
     184    }
     185    /** Method to retrieve this arguments description.
    186186      * @return A <strong>String</strong> containing the description.
    187187      */
    188     public String getDesc() {
    189           return desc;
    190     }
    191     /** Method to retrieve the description of a certain list option value.
     188    public String getDesc() {
     189    return desc;
     190    }
     191    /** Method to retrieve the description of a certain list option value.
    192192      * @param key The <strong>String</strong> whose description we are searching for.
    193193      * @return The description of the desired key as a <strong>String</strong> which may be empty if no such key exists.
    194194      */
    195     public String getDesc(String key) {
    196           if(list.containsKey(key)) {
    197                 return (String)list.get(key);
    198           }
    199           return "";
    200     }
    201     /** Method to retrieve the option list for this argument.
     195    public String getDesc(String key) {
     196    if(list.containsKey(key)) {
     197        return (String)list.get(key);
     198    }
     199    return "";
     200    }
     201    /** Method to retrieve the option list for this argument.
    202202      * @return A <strong>HashMap</strong> containing &lt;option value&gt; -&gt; &lt;description&gt; entries.
    203203      */
    204     public HashMap getList() {
    205           return list;
    206     }
    207     /** Method to retrieve the value of name.
     204    public HashMap getList() {
     205    return list;
     206    }
     207    /** Method to retrieve the value of name.
    208208      * @return A <strong>String</strong> containing the argument name.
    209209      */
    210     public String getName() {
    211           return name;
    212     }
    213     /** Retrieve the name of the owner of this argument.
     210    public String getName() {
     211    return name;
     212    }
     213    /** Retrieve the name of the owner of this argument.
    214214      * @return The owners name as a <strong>String</strong>.
    215215      */
    216     public String getOwner() {
    217           return owner;
    218     }
    219     /** Method to determine the type of this argument.
     216    public String getOwner() {
     217    return owner;
     218    }
     219    /** Method to determine the type of this argument.
    220220      * @return An <i>byte</i> specifying the type.
    221221      */
    222     public byte getType() {
    223           return type;
    224     }
    225     /** Method to retrieve the value of value.
     222    public byte getType() {
     223    return type;
     224    }
     225    /** Method to retrieve the value of value.
    226226      * @return The value of value as a <strong>String</strong>.
    227227      */
    228     public String getValue() {
    229           return value;
    230     }
    231     /** Retrieve the vector of values.
     228    public String getValue() {
     229    return value;
     230    }
     231    /** Retrieve the vector of values.
    232232      * @return An <strong>ArrayList</strong> of values.
    233233      */
    234     public ArrayList getValues() {
    235           return values;
    236     }
    237     /** Method to determine if this argument has been assigned.
     234    public ArrayList getValues() {
     235    return values;
     236    }
     237    /** Method to determine if this argument has been assigned.
    238238      * @return <i>true</i> if it has, <i>false</i> otherwise.
    239239      */
    240     public boolean isAssigned() {
    241           return (required || value != null || (values != null && values.size() > 0));
    242     }
    243     /** Method to determine of this argument is required for the associated script to work.
     240    public boolean isAssigned() {
     241    return (required || value != null || (values != null && values.size() > 0));
     242    }
     243    /** Method to determine of this argument is required for the associated script to work.
    244244      * @return <i>true</i> if this argument is required, <i>false</i> otherwise.
    245245      */
    246     public boolean isRequired() {
    247           return required;
    248     }
    249     /** Method to allow for the activation of arguments that might never have their setValue() method called.
     246    public boolean isRequired() {
     247    return required;
     248    }
     249    /** Method to allow for the activation of arguments that might never have their setValue() method called.
    250250      * @param new_state The required state as a <i>boolean</i>.
    251251      */
    252     public void setAssigned(boolean new_state) {
    253           if(new_state && (value == null || values == null)) {
    254                 value = "";
    255           }
    256           else {
    257                 value = null;
    258           }
    259     }
    260     /** Sets the value of default_value.
     252    public void setAssigned(boolean new_state) {
     253    if(new_state && (value == null || values == null)) {
     254        value = "";
     255    }
     256    else {
     257        value = null;
     258    }
     259    }
     260    /** Sets the value of default_value.
    261261      * @param new_default_value The new value for default_value as a <strong>String</strong>.
    262262      */
    263     public void setDefault(String new_default_value) {
    264           default_value = new_default_value;
    265     }
    266     /** Set the value of desc.
     263    public void setDefault(String new_default_value) {
     264    default_value = new_default_value;
     265    }
     266    /** Set the value of desc.
    267267      * @param new_desc The new value of desc as a <strong>String</strong>.
    268268      */
    269     public void setDesc(String new_desc) {
    270           desc = new_desc;
    271     }
    272     /** Set the value of name.
     269    public void setDesc(String new_desc) {
     270    desc = new_desc;
     271    }
     272    /** Set the value of name.
    273273      * @param new_name The new value of name as a <strong>String</strong>.
    274274      */
    275     public void setName(String new_name) {
    276           name = new_name;
    277     }
    278     /** Sets the value of the options list.
     275    public void setName(String new_name) {
     276    name = new_name;
     277    }
     278    /** Sets the value of the options list.
    279279      * @param new_list The new options list as a <strong>HashMap</strong>.
    280280      */
    281     public void setOptions(HashMap new_list) {
    282           list = new_list;
    283     }
    284     /** Set the owner of this argument.
     281    public void setOptions(HashMap new_list) {
     282    list = new_list;
     283    }
     284    /** Set the owner of this argument.
    285285      * @param owner The name of the owner of this argument as a <strong>String</strong>.
    286286      */
    287     public void setOwner(String owner) {
    288           this.owner = owner;
    289     }
    290     /** Set the value of required.
     287    public void setOwner(String owner) {
     288    this.owner = owner;
     289    }
     290    /** Set the value of required.
    291291      * @param new_required The new value of required as a <i>boolean</i>.
    292292      */
    293     public void setRequired(boolean new_required) {
    294           required = new_required;
    295     }
    296     /** Set the value of type.
     293    public void setRequired(boolean new_required) {
     294    required = new_required;
     295    }
     296    /** Set the value of type.
    297297      * @param new_type The new value of type as an <i>byte</i>.
    298298      */
    299     public void setType(byte new_type) {
    300           type = new_type;
    301           if(type == ENUM) {
    302                 list = new HashMap();
    303           }
    304           if(type == METADATUM && values == null) {
    305                 values = new ArrayList();
    306           }
    307     }
    308     /** Set the value of type, by matching a type to the given string.
     299    public void setType(byte new_type) {
     300    type = new_type;
     301    if(type == ENUM) {
     302        list = new HashMap();
     303    }
     304    if(type == METADATUM && values == null) {
     305        values = new ArrayList();
     306    }
     307    }
     308    /** Set the value of type, by matching a type to the given string.
    309309      * @param new_type A <strong>String</strong> which contains the name of a certain argument type.
    310310      */
    311     public void setType(String new_type) {
    312           if(new_type.equalsIgnoreCase("enum")) {
    313                 this.type = ENUM;
    314                 list = new HashMap();
    315           }
    316           else if(new_type.equalsIgnoreCase("flag")) {
    317                 this.type = FLAG;
    318           }
    319           else if(new_type.equalsIgnoreCase("hierarchy")) {
    320                 this.type = HIERARCHY;
    321           }
    322           else if(new_type.equalsIgnoreCase("int")) {
    323                 this.type = INTEGER;
    324           }
    325           else if(new_type.equalsIgnoreCase("language")) {
    326                 this.type = LANGUAGE;
    327           }
    328           else if(new_type.equalsIgnoreCase("metadata")) {
    329                 this.type = METADATA;
    330           }
    331           else if(new_type.equalsIgnoreCase("metadatum")) {
    332                 this.type = METADATUM;
    333                 if(values == null) {
    334                      values = new ArrayList();
    335                 }
    336           }
    337           else if(new_type.equalsIgnoreCase("string")) {
    338                 this.type = STRING;
    339           }
    340     }
    341     /** Method to set the value of value.
     311    public void setType(String new_type) {
     312    if(new_type.equalsIgnoreCase("enum")) {
     313        this.type = ENUM;
     314        list = new HashMap();
     315    }
     316    else if(new_type.equalsIgnoreCase("flag")) {
     317        this.type = FLAG;
     318    }
     319    else if(new_type.equalsIgnoreCase("hierarchy")) {
     320        this.type = HIERARCHY;
     321    }
     322    else if(new_type.equalsIgnoreCase("int")) {
     323        this.type = INTEGER;
     324    }
     325    else if(new_type.equalsIgnoreCase("language")) {
     326        this.type = LANGUAGE;
     327    }
     328    else if(new_type.equalsIgnoreCase("metadata")) {
     329        this.type = METADATA;
     330    }
     331    else if(new_type.equalsIgnoreCase("metadatum")) {
     332        this.type = METADATUM;
     333        if(values == null) {
     334        values = new ArrayList();
     335        }
     336    }
     337    else if(new_type.equalsIgnoreCase("string")) {
     338        this.type = STRING;
     339    }
     340    }
     341    /** Method to set the value of value.
    342342      * @param new_value The new value of value as a <strong>String</strong>.
    343343      */
    344     public void setValue(String new_value) {
    345           this.value = new_value;
    346     }
    347     /** Set the values vector to the given values. Currently I just assign the new values, whereas I may later want to implement a deep clone.
     344    public void setValue(String new_value) {
     345    this.value = new_value;
     346    }
     347    /** Set the values vector to the given values. Currently I just assign the new values, whereas I may later want to implement a deep clone.
    348348      * @param new_values An <strong>ArrayList</strong> of values.
    349349      */
    350     public void setValues(ArrayList new_values) {
    351           values = new_values;
    352     }
    353     /** Method for translating the data of this class into a string.
     350    public void setValues(ArrayList new_values) {
     351    values = new_values;
     352    }
     353    /** Method for translating the data of this class into a string.
    354354      * @return A <strong>String</strong> containing a fragment of the total arguments string.
    355355      */
    356     public String toString() {
    357           switch(type) {
    358           case FLAG:
    359                 return "-" + name;
    360           case METADATUM:
    361                 String text = "-" + name + " ";
    362                 for(int i = 0; i < values.size(); i++) {
    363                      text = text + values.get(i).toString();
    364                      if(i < values.size() - 1) {
    365                           text = text + ",";
    366                      }
    367                 }
    368                 return text;
    369           default:
    370                 return "-" + name + " " + value;
    371           }
    372     }
     356    public String toString() {
     357    switch(type) {
     358    case FLAG:
     359        return "-" + name;
     360    case METADATUM:
     361        String text = "-" + name + " ";
     362        for(int i = 0; i < values.size(); i++) {
     363        text = text + values.get(i).toString();
     364        if(i < values.size() - 1) {
     365            text = text + ",";
     366        }
     367        }
     368        return text;
     369    default:
     370        return "-" + name + " " + value;
     371    }
     372    }
    373373}
    374374
  • trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java

    r4293 r4366  
    103103
    104104public class ArgumentConfiguration
    105     extends JDialog
    106     implements ActionListener {
    107     /** The data whose arguments we are editing. */
    108     private ArgumentContainer data = null;
    109     /** Argument these argument controls coloured or uncoloured (alternates to indicate inheritance). */
    110     private boolean coloured = false;
    111     /** Whether we have successfully edited the arguments associated with the ArgumentContainer or if we have failed to enter required arguments and have instead cancelled (which would cause argument additions to roll back). */
    112     private boolean success = false;
    113     /** A reference to the main CollectionDesignManager class for access to other managers. */
    114     private CollectionDesignManager manager = null;
    115     /** A reference to the Gatherer. */
    116     private Gatherer gatherer = null;
    117     /** A button to cancel this dialog. */
    118     private JButton cancel = null;
    119     /** A button to accept the changes and close the dialog. */
    120     private JButton ok = null;
    121     /** A reference to the ourselves so our inner classes can dispose us like a dialog. */
    122     private ArgumentConfiguration self = null;
    123     /** The central pane where a list of known arguments is displayed. */
    124     private JPanel central_pane = null;
    125     /** The field for entering custom arguments. */
    126     private JTextField custom = null;
    127     /** The name of the owner of the last argument control. */
    128     private String previous_owner = null;
    129     /** The size used for an argument label. */
    130     static final private Dimension LABEL_SIZE = new Dimension(225, 25);
    131     /** Size of a list. */
    132     static final private Dimension LIST_SIZE = new Dimension(380, 50);
    133     /** The size used for the dialog. */
    134     static final private Dimension SIZE = new Dimension(800, 400);
    135     /** Constructor.
    136       * @param gatherer A reference to the <strong>Gatherer</strong>.
    137       * @param manager The <strong>CollectionDesignManager</strong> for access to other configuration managers.
    138       * @param data The plugin or classifier whose arguments we are configuring, in the form of its supported <strong>ArgumentContainer</strong> interface.
    139       * @see org.greenstone.gatherer.Configuration
    140       */
    141     public ArgumentConfiguration(Gatherer gatherer, CollectionDesignManager manager, ArgumentContainer data) {
    142           super(gatherer.g_man);
    143           this.data = data;
    144           this.gatherer = gatherer;
    145           this.manager = manager;
    146           this.self = this;
    147           String custom_str = data.getCustom();
    148           // Create
    149           setModal(true);
    150           setSize(SIZE);
    151           setTitle(get("Title"));
    152           JPanel button_pane = new JPanel();
    153           cancel = new JButton(get("General.Cancel"));
    154           cancel.setMnemonic(KeyEvent.VK_C);
    155           central_pane = new JPanel();
    156           JPanel content_pane = (JPanel) getContentPane();
    157           if(custom_str != null) {
    158                 custom = new JTextField(custom_str);
    159           }
    160           else {
    161                 custom = new JTextField();
    162           }
    163           JLabel custom_label = new JLabel(get("Custom"));
    164           custom_label.setPreferredSize(LABEL_SIZE);
    165           JPanel custom_pane = new JPanel();
    166           String args[] = new String[1];
    167           args[0] = data.getName();
    168           JLabel header = new JLabel(get("Header",args));
    169           args = null;
    170           header.setHorizontalAlignment(JLabel.CENTER);
    171           header.setOpaque(true);
    172           JPanel header_pane = new JPanel();
    173           ok = new JButton(get("General.OK"));
    174           ok.setMnemonic(KeyEvent.VK_O);
    175           // Listeners
    176           cancel.addActionListener(this);
    177           ok.addActionListener(this);
    178           // Layout
    179           custom_pane.setLayout(new BorderLayout());
    180           custom_pane.add(custom_label, BorderLayout.WEST);
    181           custom_pane.add(custom, BorderLayout.CENTER);
    182 
    183           header_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
    184           header_pane.setLayout(new BorderLayout());
    185           header_pane.add(header, BorderLayout.NORTH);
    186           header_pane.add(custom_pane, BorderLayout.CENTER);
    187 
    188           button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    189           button_pane.setLayout(new GridLayout(1,2));
    190           button_pane.add(ok);
    191           button_pane.add(cancel);
    192 
    193           central_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    194           central_pane.setLayout(new BoxLayout(central_pane, BoxLayout.Y_AXIS));
    195 
    196           content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    197           content_pane.setLayout(new BorderLayout());
    198           content_pane.add(header_pane, BorderLayout.NORTH);
    199           content_pane.add(new JScrollPane(central_pane), BorderLayout.CENTER);
    200           content_pane.add(button_pane, BorderLayout.SOUTH);
    201 
    202           // Now generate a set of controls for each of the arguments.
    203           generateControls();
    204 
    205           // Display on screen.
    206           Dimension screen_size = gatherer.config.screen_size;
    207           setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
    208           screen_size = null;
    209     }
    210     /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of the controls we are listening to.
     105    extends JDialog
     106    implements ActionListener {
     107    /** The data whose arguments we are editing. */
     108    private ArgumentContainer data = null;
     109    /** Argument these argument controls coloured or uncoloured (alternates to indicate inheritance). */
     110    private boolean coloured = false;
     111    /** Whether we have successfully edited the arguments associated with the ArgumentContainer or if we have failed to enter required arguments and have instead cancelled (which would cause argument additions to roll back). */
     112    private boolean success = false;
     113    /** A reference to the main CollectionDesignManager class for access to other managers. */
     114    private CollectionDesignManager manager = null;
     115    /** A reference to the Gatherer. */
     116    private Gatherer gatherer = null;
     117    /** A button to cancel this dialog. */
     118    private JButton cancel = null;
     119    /** A button to accept the changes and close the dialog. */
     120    private JButton ok = null;
     121    /** A reference to the ourselves so our inner classes can dispose us like a dialog. */
     122    private ArgumentConfiguration self = null;
     123    /** The central pane where a list of known arguments is displayed. */
     124    private JPanel central_pane = null;
     125    /** The field for entering custom arguments. */
     126    private JTextField custom = null;
     127    /** The name of the owner of the last argument control. */
     128    private String previous_owner = null;
     129    /** The size used for an argument label. */
     130    static final private Dimension LABEL_SIZE = new Dimension(225, 25);
     131    /** Size of a list. */
     132    static final private Dimension LIST_SIZE = new Dimension(380, 50);
     133    /** The size used for the dialog. */
     134    static final private Dimension SIZE = new Dimension(800, 400);
     135    /** Constructor.
     136     * @param gatherer A reference to the <strong>Gatherer</strong>.
     137     * @param manager The <strong>CollectionDesignManager</strong> for access to other configuration managers.
     138     * @param data The plugin or classifier whose arguments we are configuring, in the form of its supported <strong>ArgumentContainer</strong> interface.
     139     * @see org.greenstone.gatherer.Configuration
     140     */
     141    public ArgumentConfiguration(Gatherer gatherer, CollectionDesignManager manager, ArgumentContainer data) {
     142    super(gatherer.g_man);
     143    this.data = data;
     144    this.gatherer = gatherer;
     145    this.manager = manager;
     146    this.self = this;
     147    String custom_str = data.getCustom();
     148    // Create
     149    setModal(true);
     150    setSize(SIZE);
     151    setTitle(get("Title"));
     152    JPanel button_pane = new JPanel();
     153    cancel = new JButton(get("General.Cancel"));
     154    cancel.setMnemonic(KeyEvent.VK_C);
     155    central_pane = new JPanel();
     156    JPanel content_pane = (JPanel) getContentPane();
     157    if(custom_str != null) {
     158        custom = new JTextField(custom_str);
     159    }
     160    else {
     161        custom = new JTextField();
     162    }
     163    JLabel custom_label = new JLabel(get("Custom"));
     164    custom_label.setPreferredSize(LABEL_SIZE);
     165    JPanel custom_pane = new JPanel();
     166    String args[] = new String[1];
     167    args[0] = data.getName();
     168    JLabel header = new JLabel(get("Header",args));
     169    args = null;
     170    header.setHorizontalAlignment(JLabel.CENTER);
     171    header.setOpaque(true);
     172    JPanel header_pane = new JPanel();
     173    ok = new JButton(get("General.OK"));
     174    ok.setMnemonic(KeyEvent.VK_O);
     175    // Listeners
     176    cancel.addActionListener(this);
     177    ok.addActionListener(this);
     178    // Layout
     179    custom_pane.setLayout(new BorderLayout());
     180    custom_pane.add(custom_label, BorderLayout.WEST);
     181    custom_pane.add(custom, BorderLayout.CENTER);
     182
     183    header_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     184    header_pane.setLayout(new BorderLayout());
     185    header_pane.add(header, BorderLayout.NORTH);
     186    header_pane.add(custom_pane, BorderLayout.CENTER);
     187
     188    button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
     189    button_pane.setLayout(new GridLayout(1,2));
     190    button_pane.add(ok);
     191    button_pane.add(cancel);
     192
     193    central_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     194    central_pane.setLayout(new BoxLayout(central_pane, BoxLayout.Y_AXIS));
     195
     196    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     197    content_pane.setLayout(new BorderLayout());
     198    content_pane.add(header_pane, BorderLayout.NORTH);
     199    content_pane.add(new JScrollPane(central_pane), BorderLayout.CENTER);
     200    content_pane.add(button_pane, BorderLayout.SOUTH);
     201
     202    // Now generate a set of controls for each of the arguments.
     203    generateControls();
     204
     205    // Display on screen.
     206    Dimension screen_size = gatherer.config.screen_size;
     207    setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
     208    screen_size = null;
     209    }
     210    /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of the controls we are listening to.
    211211      * @param event An <strong>ActionEvent</strong> containing pertinant information about the event that fired this call.
    212212      * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
    213213      * @see org.greenstone.gatherer.cdm.ArgumentContainer
    214214      */
    215     public void actionPerformed(ActionEvent event) {
    216           boolean cont = true;
    217           if(event.getSource() == ok) {
     215    public void actionPerformed(ActionEvent event) {
     216    boolean cont = true;
     217    if(event.getSource() == ok) {
    218218                // Update the details stored in the data objects arguments.
    219                 if(custom.getText().length() > 0) {
    220                      data.setCustom(custom.getText());
    221                 }
     219        if(custom.getText().length() > 0) {
     220        data.setCustom(custom.getText());
     221        }
    222222                // Loop through each of the controls in the central pane, updating the matching argument as necessary.
    223                 for(int i = 0; i < central_pane.getComponentCount(); i++) {
    224                      Component component = central_pane.getComponent(i);
    225                      if(component instanceof ArgumentControl) {
    226                           // Once cont goes false it stays false
    227                           cont = cont && ((ArgumentControl)component).updateArgument();
    228                      }
    229                 }
    230                 if(cont) {
    231                      success = true;
    232                 }
    233           }
    234           if(cont) {
    235                 dispose();
    236           }
    237     }
    238     /** Destructor. */
    239     public void destroy() {
    240           cancel = null;
    241           central_pane = null;
    242           custom = null;
    243           data = null;
    244           gatherer = null;
    245           manager = null;
    246           ok = null;
    247           self = null;
    248     }
    249     /** Method which actually forces the dialog to be shown on screen.
     223        for(int i = 0; i < central_pane.getComponentCount(); i++) {
     224        Component component = central_pane.getComponent(i);
     225        if(component instanceof ArgumentControl) {
     226            // Once cont goes false it stays false
     227            cont = cont && ((ArgumentControl)component).updateArgument();
     228        }
     229        }
     230        if(cont) {
     231        success = true;
     232        }
     233    }
     234    if(cont) {
     235        dispose();
     236    }
     237    }
     238    /** Destructor. */
     239    public void destroy() {
     240    cancel = null;
     241    central_pane = null;
     242    custom = null;
     243    data = null;
     244    gatherer = null;
     245    manager = null;
     246    ok = null;
     247    self = null;
     248    }
     249    /** Method which actually forces the dialog to be shown on screen.
    250250      * @return <i>true</i> if the user completed configuration and pressed ok, <i>false</i> otherwise.
    251251      */
    252     public boolean display() {
    253           show();
    254           return success;
    255     }
    256 
    257     private void addHeader(String name, Color color) {
    258           JPanel header = new JPanel();
    259           header.setBackground(color);
    260           JPanel inner_pane = new JPanel();
    261           inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()));
    262           inner_pane.setBackground(color);
    263           JLabel header_label = new JLabel("<html><strong>" + name + "</strong></html>");
    264           header_label.setBackground(Gatherer.config.getColor("coloring.collection_heading_background", false));
    265           header_label.setHorizontalAlignment(JLabel.CENTER);
    266           header_label.setOpaque(true);
    267           // Layout.
    268           inner_pane.setLayout(new BorderLayout());
    269           inner_pane.add(header_label, BorderLayout.CENTER);
    270 
    271           header.setLayout(new BorderLayout());
    272           header.add(inner_pane, BorderLayout.CENTER);
    273           central_pane.add(header);
    274     }
    275 
    276     /** Method to iterate through the arguments associated with whatever argument container we are building an argument control view for, creating the appropriate controls for each.
     252    public boolean display() {
     253    show();
     254    return success;
     255    }
     256
     257    private void addHeader(String name, Color color) {
     258    JPanel header = new JPanel();
     259    header.setBackground(color);
     260    JPanel inner_pane = new JPanel();
     261    inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()));
     262    inner_pane.setBackground(color);
     263    JLabel header_label = new JLabel("<html><strong>" + name + "</strong></html>");
     264    header_label.setBackground(Gatherer.config.getColor("coloring.collection_heading_background", false));
     265    header_label.setHorizontalAlignment(JLabel.CENTER);
     266    header_label.setOpaque(true);
     267    // Layout.
     268    inner_pane.setLayout(new BorderLayout());
     269    inner_pane.add(header_label, BorderLayout.CENTER);
     270
     271    header.setLayout(new BorderLayout());
     272    header.add(inner_pane, BorderLayout.CENTER);
     273    central_pane.add(header);
     274    }
     275
     276    /** Method to iterate through the arguments associated with whatever argument container we are building an argument control view for, creating the appropriate controls for each.
    277277      * @see org.greenstone.gatherer.cdm.Argument
    278278      * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
    279279      */
    280     private void generateControls() {
    281           ArrayList arguments = data.getArguments();
    282           int total_height = 250;
    283           int size = arguments.size();
    284           for(int i = 0; i < size; i++) {
    285                 Argument argument = (Argument) arguments.get(i);
    286                 ArgumentControl argument_control = new ArgumentControl(argument);
    287                 total_height = total_height - argument_control.getPreferredSize().height;
    288                 central_pane.add(argument_control);
    289           }
    290           if(total_height > 0) {
    291                 JPanel filler = new JPanel();
    292                 filler.setPreferredSize(new Dimension(100, total_height));
    293                 filler.setSize(new Dimension(100, total_height));
    294                 central_pane.add(filler);
    295           }
    296     }
    297     /** Method to retrieve a phrase from the dictionary based on a key.
     280    private void generateControls() {
     281    ArrayList arguments = data.getArguments();
     282    int total_height = 250;
     283    int size = arguments.size();
     284    for(int i = 0; i < size; i++) {
     285        Argument argument = (Argument) arguments.get(i);
     286        ArgumentControl argument_control = new ArgumentControl(argument);
     287        total_height = total_height - argument_control.getPreferredSize().height;
     288        central_pane.add(argument_control);
     289    }
     290    if(total_height > 0) {
     291        JPanel filler = new JPanel();
     292        filler.setPreferredSize(new Dimension(100, total_height));
     293        filler.setSize(new Dimension(100, total_height));
     294        central_pane.add(filler);
     295    }
     296    }
     297    /** Method to retrieve a phrase from the dictionary based on a key.
    298298      * @param key A <strong>String</strong> used to find the correct phrase.
    299299      * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
    300300      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    301301      */
    302     private String get(String key) {
    303           return get(key, null);
    304     }
    305     /** Method to retrieve a phrase from the dictionary based on a key.
     302    private String get(String key) {
     303    return get(key, null);
     304    }
     305    /** Method to retrieve a phrase from the dictionary based on a key.
    306306      * @param key A <strong>String</strong> used to find the correct phrase.
    307307      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    308308      */
    309     private String get(String key, String args[]) {
    310           if(key.indexOf(".") == -1) {
    311                 key = "CDM.ArgumentConfiguration." + key;
    312           }
    313           return gatherer.dictionary.get(key, args);
    314     }
    315     /** This class encapsulates all the technical difficulty of creating a specific control based on an Argument. */
    316     private class ArgumentControl
    317           extends JPanel {
    318           /** The Argument this control will be based on. */
    319           private Argument argument = null;
    320           /** One of a possible two buttons available for adding to this control. */
    321           private JButton one = null;
    322           /** The second of two buttons available for adding to this control. */
    323           private JButton two = null;
    324           /** A checkbox to allow enabling or diabling of this Argument. */
    325           private JCheckBox enabled = null;
    326           /** Some form of editor component, such as a JComboBox or JTextField, used to set parameters to an Argument. */
    327           private JComponent value = null;
    328           /** Can be used in place of the other editor components if a list is required. */
    329           private JList list = null;
    330           /** Constructor.
    331             * @param argument The <strong>Argument</strong> this control will be built around.
    332             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.AddListener
    333             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.EnabledListener
    334             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.HierarchyListener
    335             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ListOption
    336             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.RemoveListener
    337             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ToolTipUpdater
    338             */
    339           public ArgumentControl(Argument argument) {
    340                 this.argument = argument;
    341                 String tip = "<html>" + argument.getDesc() + "</html>";
    342                 tip = Utility.formatHTMLWidth(tip, 60);
     309    private String get(String key, String args[]) {
     310    if(key.indexOf(".") == -1) {
     311        key = "CDM.ArgumentConfiguration." + key;
     312    }
     313    return gatherer.dictionary.get(key, args);
     314    }
     315    /** This class encapsulates all the technical difficulty of creating a specific control based on an Argument. */
     316    private class ArgumentControl
     317    extends JPanel {
     318    /** The Argument this control will be based on. */
     319    private Argument argument = null;
     320    /** One of a possible two buttons available for adding to this control. */
     321    private JButton one = null;
     322    /** The second of two buttons available for adding to this control. */
     323    private JButton two = null;
     324    /** A checkbox to allow enabling or diabling of this Argument. */
     325    private JCheckBox enabled = null;
     326    /** Some form of editor component, such as a JComboBox or JTextField, used to set parameters to an Argument. */
     327    private JComponent value = null;
     328    /** Can be used in place of the other editor components if a list is required. */
     329    private JList list = null;
     330    /** Constructor.
     331     * @param argument The <strong>Argument</strong> this control will be built around.
     332     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.AddListener
     333     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.EnabledListener
     334     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.HierarchyListener
     335     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ListOption
     336     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.RemoveListener
     337     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ToolTipUpdater
     338     */
     339    public ArgumentControl(Argument argument) {
     340        this.argument = argument;
     341        String tip = "<html>" + argument.getDesc() + "</html>";
     342        tip = Utility.formatHTMLWidth(tip, 60);
    343343                // If this is the first control, there is no history.
    344                 if(previous_owner == null) {
    345                      previous_owner = argument.getOwner();
    346                      addHeader(previous_owner, Color.white);
     344        if(previous_owner == null) {
     345        previous_owner = argument.getOwner();
     346        addHeader(previous_owner, Color.white);
     347        }
     348                // Otherwise if the owner of the control has changed since the last argument, toggle the colouring of the control.
     349        else if(previous_owner != argument.getOwner()) {
     350        coloured = !coloured;
     351        previous_owner = argument.getOwner();
     352        addHeader(previous_owner, (coloured ? Gatherer.config.getColor("coloring.collection_tree_background", false) : Color.white));
     353        }
     354                // Create
     355        if(coloured) {
     356        setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     357        }
     358        else {
     359        setBackground(Color.white);
     360        }
     361        JLabel owner_label = new JLabel(argument.getOwner());
     362        owner_label.setOpaque(false);
     363        JLabel label = new JLabel(argument.getName());
     364        label.setOpaque(false);
     365        label.setPreferredSize(LABEL_SIZE);
     366        label.setToolTipText(tip);
     367        enabled = new JCheckBox(argument.getName());
     368        enabled.setOpaque(false);
     369        enabled.setPreferredSize(LABEL_SIZE);
     370        enabled.setToolTipText(tip);
     371        JPanel inner_pane = new JPanel();
     372        inner_pane.setOpaque(false);
     373        String existing_value = argument.getValue();
     374        String default_value = argument.getDefaultValue();
     375        switch(argument.getType()) {
     376        case Argument.ENUM:
     377        // Build an option model, wrapping each entry of the list table.
     378        HashMap arg_list = argument.getList();
     379        ArrayList options_model = new ArrayList();
     380        Iterator it = arg_list.keySet().iterator();
     381        while(it.hasNext()) {
     382            String key = (String) it.next();
     383            options_model.add(new ListOption(key, (String)arg_list.get(key)));
     384        }
     385        Collections.sort(options_model);
     386        value = new JComboBox(options_model.toArray());
     387        ((JComboBox)value).addActionListener(new ToolTipUpdater());
     388        if(existing_value != null) {
     389            // Select the correct value. Since they're all text strings we better iterate to be safe.
     390            selectValue((JComboBox)value, existing_value);
     391        }
     392        else if(default_value != null) {
     393            // Same as above except for default value.
     394            selectValue((JComboBox)value, default_value);
     395        }
     396        break;
     397        case Argument.FLAG:
     398        // Only need the check box.
     399        break;
     400        case Argument.HIERARCHY:
     401        value = new JComboBox(gatherer.c_man.msm.getAssignedElements(true));
     402        /** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
     403        ((JComboBox)value).setEditable(true);
     404        ((JComboBox)value).addItemListener(new HierarchyListener());
     405        // Now ensure we have the existing value or default value selected if either exist.
     406        if(existing_value != null) {
     407            selectValue((JComboBox)value, existing_value);
     408        }
     409        else if(default_value != null) {
     410            selectValue((JComboBox)value, default_value);
     411        }
     412        break;
     413        case Argument.INTEGER:
     414        case Argument.STRING:
     415        // Use a standard text field
     416        if(existing_value != null) {
     417            value = new JTextField(existing_value);
     418        }
     419        else {
     420            if(default_value != null) {
     421            value = new JTextField(default_value);
     422            }
     423            // Special test just for the hfile field.
     424            else if(argument.getName().equals("hfile")) {
     425            // Work through previous controls looking for the metadata one.
     426            for(int i = 0; i < central_pane.getComponentCount(); i++) {
     427                Object object = central_pane.getComponent(i);
     428                if(object instanceof ArgumentControl) {
     429                ArgumentControl control = (ArgumentControl) object;
     430                if(control.toString().equals("metadata")) {
     431                    Object temp = control.getValue();
     432                    if(temp != null) {
     433                    value = new JTextField(temp.toString() + ".txt");
     434                    }
    347435                }
    348                 // Otherwise if the owner of the control has changed since the last argument, toggle the colouring of the control.
    349                 else if(previous_owner != argument.getOwner()) {
    350                      coloured = !coloured;
    351                      previous_owner = argument.getOwner();
    352                      addHeader(previous_owner, (coloured ? Gatherer.config.getColor("coloring.collection_tree_background", false) : Color.white));
    353                 }
    354                 // Create
    355                 if(coloured) {
    356                      setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    357                 }
    358                 else {
    359                      setBackground(Color.white);
    360                 }
    361                 JLabel owner_label = new JLabel(argument.getOwner());
    362                 owner_label.setOpaque(false);
    363                 JLabel label = new JLabel(argument.getName());
    364                 label.setOpaque(false);
    365                 label.setPreferredSize(LABEL_SIZE);
    366                 label.setToolTipText(tip);
    367                 enabled = new JCheckBox(argument.getName());
    368                 enabled.setOpaque(false);
    369                 enabled.setPreferredSize(LABEL_SIZE);
    370                 enabled.setToolTipText(tip);
    371                 JPanel inner_pane = new JPanel();
    372                 inner_pane.setOpaque(false);
    373                 String existing_value = argument.getValue();
    374                 String default_value = argument.getDefaultValue();
    375                 switch(argument.getType()) {
    376                 case Argument.ENUM:
    377                      // Build an option model, wrapping each entry of the list table.
    378                      HashMap arg_list = argument.getList();
    379                      ArrayList options_model = new ArrayList();
    380                      Iterator it = arg_list.keySet().iterator();
    381                      while(it.hasNext()) {
    382                           String key = (String) it.next();
    383                           options_model.add(new ListOption(key, (String)arg_list.get(key)));
    384                      }
    385                      Collections.sort(options_model);
    386                      value = new JComboBox(options_model.toArray());
    387                      ((JComboBox)value).addActionListener(new ToolTipUpdater());
    388                      if(existing_value != null) {
    389                           // Select the correct value. Since they're all text strings we better iterate to be safe.
    390                           selectValue((JComboBox)value, existing_value);
    391                      }
    392                      else if(default_value != null) {
    393                           // Same as above except for default value.
    394                           selectValue((JComboBox)value, default_value);
    395                      }
    396                      break;
    397                 case Argument.FLAG:
    398                      // Only need the check box.
    399                      break;
    400                 case Argument.HIERARCHY:
    401                      value = new JComboBox(gatherer.c_man.msm.getAssignedElements(true));
    402                      /** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
    403                      ((JComboBox)value).setEditable(true);
    404                      ((JComboBox)value).addItemListener(new HierarchyListener());
    405                      // Now ensure we have the existing value or default value selected if either exist.
    406                      if(existing_value != null) {
    407                           selectValue((JComboBox)value, existing_value);
    408                      }
    409                      else if(default_value != null) {
    410                           selectValue((JComboBox)value, default_value);
    411                      }
    412                      break;
    413                 case Argument.INTEGER:
    414                 case Argument.STRING:
    415                      // Use a standard text field
    416                      if(existing_value != null) {
    417                           value = new JTextField(existing_value);
    418                      }
    419                      else {
    420                           if(default_value != null) {
    421                                 value = new JTextField(default_value);
    422                           }
    423                           // Special test just for the hfile field.
    424                           else if(argument.getName().equals("hfile")) {
    425                                 // Work through previous controls looking for the metadata one.
    426                                 for(int i = 0; i < central_pane.getComponentCount(); i++) {
    427                                      Object object = central_pane.getComponent(i);
    428                                      if(object instanceof ArgumentControl) {
    429                                           ArgumentControl control = (ArgumentControl) object;
    430                                           if(control.toString().equals("metadata")) {
    431                                                 Object temp = control.getValue();
    432                                                 if(temp != null) {
    433                                                      value = new JTextField(temp.toString() + ".txt");
    434                                                 }
    435                                           }
    436 
    437                                      }
    438                                 }
    439                           }
    440                           else {
    441                                 value = new JTextField();
    442                           }
    443                      }
    444                      break;
    445                 case Argument.LANGUAGE:
    446                      value = new JComboBox(manager.languages.getLanguageCodes().toArray());
    447                      // Now ensure we have the existing value or default value selected if either exist.
    448                      Language selected = null;
    449                      if(existing_value != null) {
    450                           selected = manager.languages.getLanguage(existing_value, false);
    451                      }
    452                      else if(default_value != null) {
    453                           selected = manager.languages.getLanguage(default_value, false);
    454                      }
    455                      if(selected != null) {
    456                           ((JComboBox)value).setSelectedItem(selected);
    457                      }
    458                      break;
    459                 case Argument.METADATA:
    460                      value = new JComboBox(gatherer.c_man.msm.getAssignedElements());
    461                      /** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
    462                      ((JComboBox)value).setEditable(true);
    463                      // Now ensure we have the existing value or default value selected if either exist.
    464                      if(existing_value != null) {
    465                           selectValue((JComboBox)value, existing_value);
    466                      }
    467                      else if(default_value != null) {
    468                           selectValue((JComboBox)value, default_value);
    469                      }
    470                      break;
    471                 case Argument.METADATUM:
    472                      // Comma separated metadata values.
    473                      ArrayList values = argument.getValues();
    474                      value = new JComboBox(gatherer.c_man.msm.getAssignedElements());
    475                      DefaultListModel model = new DefaultListModel();
    476                      list = new JList(model);
    477                      list.setVisibleRowCount(3);
    478                      for(int i = 0; i < values.size(); i++) {
    479                           model.addElement(values.get(i));
    480                      }
    481                      one = new JButton(get("Add"));
    482                      one.addActionListener(new AddListener((JComboBox)value, list));
    483                      two = new JButton(get("Remove"));
    484                      two.addActionListener(new RemoveListener(list));
    485                      if(argument.getValues().size() > 0 || argument.isRequired()) {
    486                           enabled.setSelected(true);
    487                           list.setBackground(Color.white);
    488                           list.setEnabled(true);
    489                           one.setEnabled(true);
    490                           two.setEnabled(true);
    491                           value.setEnabled(true);
    492                      }
    493                      else {
    494                           enabled.setSelected(false);
    495                           list.setBackground(Color.lightGray);
    496                           list.setEnabled(false);
    497                           one.setEnabled(false);
    498                           two.setEnabled(false);
    499                           value.setEnabled(false);
    500                      }
    501                      break;
    502                 }
     436
     437                }
     438            }
     439            }
     440            else {
     441            value = new JTextField();
     442            }
     443        }
     444        break;
     445        case Argument.LANGUAGE:
     446        value = new JComboBox(manager.languages.getLanguageCodes().toArray());
     447        // Now ensure we have the existing value or default value selected if either exist.
     448        Language selected = null;
     449        if(existing_value != null) {
     450            selected = manager.languages.getLanguage(existing_value, false);
     451        }
     452        else if(default_value != null) {
     453            selected = manager.languages.getLanguage(default_value, false);
     454        }
     455        if(selected != null) {
     456            ((JComboBox)value).setSelectedItem(selected);
     457        }
     458        break;
     459        case Argument.METADATA:
     460        value = new JComboBox(gatherer.c_man.msm.getAssignedElements());
     461        /** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
     462        ((JComboBox)value).setEditable(true);
     463        // Now ensure we have the existing value or default value selected if either exist.
     464        if(existing_value != null) {
     465            selectValue((JComboBox)value, existing_value);
     466        }
     467        else if(default_value != null) {
     468            selectValue((JComboBox)value, default_value);
     469        }
     470        break;
     471        case Argument.METADATUM:
     472        // Comma separated metadata values.
     473        ArrayList values = argument.getValues();
     474        value = new JComboBox(gatherer.c_man.msm.getAssignedElements());
     475        DefaultListModel model = new DefaultListModel();
     476        list = new JList(model);
     477        list.setVisibleRowCount(3);
     478        for(int i = 0; i < values.size(); i++) {
     479            model.addElement(values.get(i));
     480        }
     481        one = new JButton(get("Add"));
     482        one.addActionListener(new AddListener((JComboBox)value, list));
     483        two = new JButton(get("Remove"));
     484        two.addActionListener(new RemoveListener(list));
     485        if(argument.getValues().size() > 0 || argument.isRequired()) {
     486            enabled.setSelected(true);
     487            list.setBackground(Color.white);
     488            list.setEnabled(true);
     489            one.setEnabled(true);
     490            two.setEnabled(true);
     491            value.setEnabled(true);
     492        }
     493        else {
     494            enabled.setSelected(false);
     495            list.setBackground(Color.lightGray);
     496            list.setEnabled(false);
     497            one.setEnabled(false);
     498            two.setEnabled(false);
     499            value.setEnabled(false);
     500        }
     501        break;
     502        }
    503503                // Enable or disable as necessary.
    504                 if(argument.isRequired() || argument.isAssigned()) {
    505                      enabled.setSelected(true);
    506                      if(value != null) {
    507                           value.setOpaque(true);
    508                           value.setBackground(Color.white);
    509                           value.setEnabled(true);
    510                      }
    511                 }
    512                 else {
    513                      enabled.setSelected(false);
    514                      if(value != null) {
    515                           value.setOpaque(true);
    516                           value.setBackground(Color.lightGray);
    517                           value.setEnabled(false);
    518                      }
    519                 }
     504        if(argument.isRequired() || argument.isAssigned()) {
     505        enabled.setSelected(true);
     506        if(value != null) {
     507            value.setOpaque(true);
     508            value.setBackground(Color.white);
     509            value.setEnabled(true);
     510        }
     511        }
     512        else {
     513        enabled.setSelected(false);
     514        if(value != null) {
     515            value.setOpaque(true);
     516            value.setBackground(Color.lightGray);
     517            value.setEnabled(false);
     518        }
     519        }
    520520                // Listener
    521                 if(value != null && !argument.isRequired()) {
    522                      enabled.addActionListener(new EnabledListener(one, two, list, value));
    523                 }
     521        if(value != null && !argument.isRequired()) {
     522        enabled.addActionListener(new EnabledListener(one, two, list, value));
     523        }
    524524                // Layout
    525                 if(list == null) {
    526                      enabled.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
    527                      inner_pane.setLayout(new BorderLayout());
    528                      if(argument.isRequired()) {
    529                           inner_pane.add(label, BorderLayout.WEST);
    530                      }
    531                      else {
    532                           inner_pane.add(enabled, BorderLayout.WEST);
    533                      }
    534                      if(value != null) {
    535                           inner_pane.add(value, BorderLayout.CENTER);
    536                      }
    537                 }
    538                 else {
    539                      JPanel control_pane = new JPanel(new GridLayout(2,1));
    540                      control_pane.add(enabled);
    541                      control_pane.add(value);
    542                      control_pane.setOpaque(false);
    543 
    544                      JPanel left_pane = new JPanel(new BorderLayout());
    545                      left_pane.add(control_pane, BorderLayout.CENTER);
    546                      left_pane.add(one, BorderLayout.SOUTH);
    547                      left_pane.setOpaque(false);
    548 
    549                      JPanel right_pane = new JPanel(new BorderLayout());
    550                      right_pane.add(new JScrollPane(list), BorderLayout.CENTER);
    551                      right_pane.add(two, BorderLayout.SOUTH);
    552                      right_pane.setOpaque(false);
    553 
    554                      inner_pane.setLayout(new GridLayout(1,2));
    555                      inner_pane.add(left_pane);
    556                      inner_pane.add(right_pane);
    557                 }
    558                 setLayout(new BorderLayout());
     525        if(list == null) {
     526        enabled.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     527        inner_pane.setLayout(new BorderLayout());
     528        if(argument.isRequired()) {
     529            inner_pane.add(label, BorderLayout.WEST);
     530        }
     531        else {
     532            inner_pane.add(enabled, BorderLayout.WEST);
     533        }
     534        if(value != null) {
     535            inner_pane.add(value, BorderLayout.CENTER);
     536        }
     537        }
     538        else {
     539        JPanel control_pane = new JPanel(new GridLayout(2,1));
     540        control_pane.add(enabled);
     541        control_pane.add(value);
     542        control_pane.setOpaque(false);
     543
     544        JPanel left_pane = new JPanel(new BorderLayout());
     545        left_pane.add(control_pane, BorderLayout.CENTER);
     546        left_pane.add(one, BorderLayout.SOUTH);
     547        left_pane.setOpaque(false);
     548
     549        JPanel right_pane = new JPanel(new BorderLayout());
     550        right_pane.add(new JScrollPane(list), BorderLayout.CENTER);
     551        right_pane.add(two, BorderLayout.SOUTH);
     552        right_pane.setOpaque(false);
     553
     554        inner_pane.setLayout(new GridLayout(1,2));
     555        inner_pane.add(left_pane);
     556        inner_pane.add(right_pane);
     557        }
     558        setLayout(new BorderLayout());
    559559                //add(owner_label, BorderLayout.NORTH);
    560                 add(inner_pane, BorderLayout.CENTER);
    561           }
    562           public Object getValue() {
    563                 if(value instanceof JComboBox) {
    564                      return ((JComboBox)value).getSelectedItem();
    565                 }
    566                 else if(value instanceof JTextField) {
    567                      return ((JTextField)value).getText();
    568                 }
    569                 return null;
    570           }
    571           /** Identifies this control by returning the name of the Argument it is based on.
     560        add(inner_pane, BorderLayout.CENTER);
     561    }
     562    public Object getValue() {
     563        if(value instanceof JComboBox) {
     564        return ((JComboBox)value).getSelectedItem();
     565        }
     566        else if(value instanceof JTextField) {
     567        return ((JTextField)value).getText();
     568        }
     569        return null;
     570    }
     571    /** Identifies this control by returning the name of the Argument it is based on.
    572572            * @return The name of the Argument as a <strong>String</strong>.
    573573            * @see org.greenstone.gatherer.cdm.Argument
    574574            */
    575           public String toString() {
    576                 return argument.getName();
    577           }
    578           /** Updates the enwrapped Argument using the values provided by the controls.
     575    public String toString() {
     576        return argument.getName();
     577    }
     578    /** Updates the enwrapped Argument using the values provided by the controls.
    579579            * @return <i>true</i> if the update was successful, <i>false</i> otherwise.
    580580            * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ListOption
     
    582582            * @see org.greenstone.gatherer.msm.ElementWrapper
    583583            */
    584           public boolean updateArgument() {
    585                 if(enabled.isSelected() || argument.isRequired()) {
    586                      argument.setAssigned(true);
    587                      String result = null;
    588                      switch(argument.getType()) {
    589                      case Argument.ENUM:
    590                           ListOption option = (ListOption)((JComboBox)value).getSelectedItem();
    591                           result = option.getValue();
    592                           if(result.length() > 0) {
    593                                 argument.setValue(result);
    594                           }
    595                           else {
    596                                 if(argument.isRequired()) {
    597                                     String args[] = new String[1];
    598                                     args[0] = argument.getName();
    599                                     JOptionPane.showMessageDialog(self, get("Required_Argument", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
    600                                     args = null;
    601                                     return false;
    602                                 }
    603                                 else {
    604                                     argument.setValue(null);
    605                                 }
    606                           }
    607                           return true;
    608                      case Argument.FLAG:
    609                           // Should have already been handled above.
    610                           return true;
    611                      case Argument.INTEGER:
    612                           result = ((JTextField)value).getText();
    613                           if(result.length() > 0) {
    614                                 // Test if the value entered is a valid int.
    615                                 try {
    616                                     int x = Integer.parseInt(result);
    617                                 }
    618                                 catch(NumberFormatException nfe) {
    619                                     String args[] = new String[2];
    620                                     args[0] = argument.getName();
    621                                     args[1] = result;
    622                                     JOptionPane.showMessageDialog(self, get("Bad_Integer", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
    623                                     args = null;
    624                                     return false;
    625                                 }
    626                                 argument.setValue(result);
    627                           }
    628                           else {
    629                                 if(argument.isRequired()) {
    630                                     String args[] = new String[1];
    631                                     args[0] = argument.getName();
    632                                     JOptionPane.showMessageDialog(self, get("Required_Argument", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
    633                                     args = null;
    634                                     return false;
    635                                 }
    636                                 else {
    637                                     argument.setValue(null);
    638                                 }
    639                           }
    640                           return true;
    641                      case Argument.LANGUAGE:
    642                           Language language = (Language) ((JComboBox)value).getSelectedItem();
    643                           argument.setValue(language.getCode());
    644                           // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
    645                           return true;
    646                      case Argument.METADATA:
    647                      case Argument.HIERARCHY:
    648                           argument.setValue(((JComboBox)value).getSelectedItem().toString());
    649                           // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
    650                           return true;
    651                      case Argument.METADATUM:
    652                           DefaultListModel model = (DefaultListModel)list.getModel();
    653                           ArrayList values = new ArrayList();
    654                           for(int i = 0; i < model.size(); i++) {
    655                                 values.add(model.get(i));
    656                           }
    657                           argument.setValues(values);
    658                           return true;
    659                      case Argument.STRING:
    660                           result = ((JTextField)value).getText();
    661                           if(result.length() > 0) {
    662                                 argument.setValue(result);
    663                           }
    664                           else {
    665                                 if(argument.isRequired()) {
    666                                     String args[] = new String[1];
    667                                     args[0] = argument.getName();
    668                                     JOptionPane.showMessageDialog(self, get("Required_Argument", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
    669                                     return false;
    670                                 }
    671                                 else {
    672                                     argument.setValue(null);
    673                                 }
    674                           }
    675                           return true;
    676                      }
    677                      return false;
    678                 }
    679                 else {
    680                      argument.setAssigned(false);
    681                      return true;
    682                 }
    683           }
    684           /** Method to ensure that a certain value is selected, if it exists within that combobox to begin with.
     584    public boolean updateArgument() {
     585        if(enabled.isSelected() || argument.isRequired()) {
     586        argument.setAssigned(true);
     587        String result = null;
     588        switch(argument.getType()) {
     589        case Argument.ENUM:
     590            ListOption option = (ListOption)((JComboBox)value).getSelectedItem();
     591            result = option.getValue();
     592            if(result.length() > 0) {
     593            argument.setValue(result);
     594            }
     595            else {
     596            if(argument.isRequired()) {
     597                String args[] = new String[1];
     598                args[0] = argument.getName();
     599                JOptionPane.showMessageDialog(self, get("Required_Argument", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
     600                args = null;
     601                return false;
     602            }
     603            else {
     604                argument.setValue(null);
     605            }
     606            }
     607            return true;
     608        case Argument.FLAG:
     609            // Should have already been handled above.
     610            return true;
     611        case Argument.INTEGER:
     612            result = ((JTextField)value).getText();
     613            if(result.length() > 0) {
     614            // Test if the value entered is a valid int.
     615            try {
     616                int x = Integer.parseInt(result);
     617            }
     618            catch(NumberFormatException nfe) {
     619                String args[] = new String[2];
     620                args[0] = argument.getName();
     621                args[1] = result;
     622                JOptionPane.showMessageDialog(self, get("Bad_Integer", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
     623                args = null;
     624                return false;
     625            }
     626            argument.setValue(result);
     627            }
     628            else {
     629            if(argument.isRequired()) {
     630                String args[] = new String[1];
     631                args[0] = argument.getName();
     632                JOptionPane.showMessageDialog(self, get("Required_Argument", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
     633                args = null;
     634                return false;
     635            }
     636            else {
     637                argument.setValue(null);
     638            }
     639            }
     640            return true;
     641        case Argument.LANGUAGE:
     642            Language language = (Language) ((JComboBox)value).getSelectedItem();
     643            argument.setValue(language.getCode());
     644            // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
     645            return true;
     646        case Argument.METADATA:
     647        case Argument.HIERARCHY:
     648            argument.setValue(((JComboBox)value).getSelectedItem().toString());
     649            // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
     650            return true;
     651        case Argument.METADATUM:
     652            DefaultListModel model = (DefaultListModel)list.getModel();
     653            ArrayList values = new ArrayList();
     654            for(int i = 0; i < model.size(); i++) {
     655            values.add(model.get(i));
     656            }
     657            argument.setValues(values);
     658            return true;
     659        case Argument.STRING:
     660            result = ((JTextField)value).getText();
     661            if(result.length() > 0) {
     662            argument.setValue(result);
     663            }
     664            else {
     665            if(argument.isRequired()) {
     666                String args[] = new String[1];
     667                args[0] = argument.getName();
     668                JOptionPane.showMessageDialog(self, get("Required_Argument", args), get("Error_Title"), JOptionPane.ERROR_MESSAGE);
     669                return false;
     670            }
     671            else {
     672                argument.setValue(null);
     673            }
     674            }
     675            return true;
     676        }
     677        return false;
     678        }
     679        else {
     680        argument.setAssigned(false);
     681        return true;
     682        }
     683    }
     684    /** Method to ensure that a certain value is selected, if it exists within that combobox to begin with.
    685685            * @param combobox The <strong>JComboBox</strong> whose selection we are trying to preset.
    686686            * @param target The desired value of the selection as a <strong>String</strong>.
     
    688688            * @see org.greenstone.gatherer.msm.ElementWrapper
    689689            */
    690           public void selectValue(JComboBox combobox, String target) {
    691                 for(int i = 0; i < combobox.getItemCount(); i++) {
    692                      Object object = combobox.getItemAt(i);
    693                      if(object instanceof ListOption) {
    694                           ListOption lo = (ListOption) object;
    695                           if(lo.getValue().equals(target)) {
    696                                 combobox.setSelectedIndex(i);
    697                                 return;
    698                           }
    699                      }
    700                      else if(object instanceof ElementWrapper) {
    701                           if(object.toString().equals(target)) {
    702                                 combobox.setSelectedIndex(i);
    703                                 return;
    704                           }
    705                      }
    706                 }
    707           }
    708           /** Forces the control into an 'enabled' mode. */
    709           public void setEnabled() {
    710                 enabled.setSelected(true);
    711           }
    712           /** Explicitly sets the value of a JTextField type control to the given String.
     690    public void selectValue(JComboBox combobox, String target) {
     691        for(int i = 0; i < combobox.getItemCount(); i++) {
     692        Object object = combobox.getItemAt(i);
     693        if(object instanceof ListOption) {
     694            ListOption lo = (ListOption) object;
     695            if(lo.getValue().equals(target)) {
     696            combobox.setSelectedIndex(i);
     697            return;
     698            }
     699        }
     700        else if(object instanceof ElementWrapper) {
     701            if(object.toString().equals(target)) {
     702            combobox.setSelectedIndex(i);
     703            return;
     704            }
     705        }
     706        }
     707    }
     708    /** Forces the control into an 'enabled' mode. */
     709    public void setEnabled() {
     710        enabled.setSelected(true);
     711    }
     712    /** Explicitly sets the value of a JTextField type control to the given String.
    713713            * @param value_str The new value of the control as a <strong>String</strong>.
    714714            */
    715           public void setValue(String value_str) {
    716                 ((JTextField)value).setText(value_str);
    717           }
    718           /** Listener which adds entries to a list from a combobox when fired. */
    719           private class AddListener
    720                 implements ActionListener {
     715    public void setValue(String value_str) {
     716        ((JTextField)value).setText(value_str);
     717    }
     718    /** Listener which adds entries to a list from a combobox when fired. */
     719    private class AddListener
     720        implements ActionListener {
    721721                /** The model behind the target list. */
    722                 private DefaultListModel model = null;
     722        private DefaultListModel model = null;
    723723                /** The source for data to be added to the list. */
    724                 private JComboBox source = null;
     724        private JComboBox source = null;
    725725                /** The list to add data to. */
    726                 private JList target = null;
     726        private JList target = null;
    727727                /** Constructor.
    728728                 * @param source A <strong>JComboBox</strong> which serves as the source for data.
    729729                 * @param target A <strong>JList</strong> which serves as the target for data.
    730730                 */
    731                 public AddListener(JComboBox source, JList target) {
    732                      this.model = (DefaultListModel) target.getModel();
    733                      this.source = source;
    734                      this.target = target;
    735                 }
     731        public AddListener(JComboBox source, JList target) {
     732        this.model = (DefaultListModel) target.getModel();
     733        this.source = source;
     734        this.target = target;
     735        }
    736736                /** When the add button is clicked, we attempt to add the selected metadata from the source into the target.
    737737                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    738738                 * @see org.greenstone.gatherer.msm.ElementWrapper
    739739                 */
    740                 public void actionPerformed(ActionEvent event) {
    741                      ElementWrapper element = (ElementWrapper) source.getSelectedItem();
    742                      String name = element.toString();
    743                      if(!model.contains(name)) {
    744                           boolean found = false;
    745                           int index = 0;
    746                           while(!found && index < model.size()) {
    747                                 String sibling = (String) model.get(index);
    748                                 if(name.compareTo(sibling) < 0) {
    749                                     model.add(index, name);
    750                                     found = true;
    751                                 }
    752                                 else {
    753                                     index++;
    754                                 }
    755                           }
    756                           if(!found) {
    757                                 model.addElement(name);
    758                           }
    759                      }
    760                 }
    761           }
    762           /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
    763           private class EnabledListener
    764                 implements ActionListener {
     740        public void actionPerformed(ActionEvent event) {
     741        ElementWrapper element = (ElementWrapper) source.getSelectedItem();
     742        String name = element.toString();
     743        if(!model.contains(name)) {
     744            boolean found = false;
     745            int index = 0;
     746            while(!found && index < model.size()) {
     747            String sibling = (String) model.get(index);
     748            if(name.compareTo(sibling) < 0) {
     749                model.add(index, name);
     750                found = true;
     751            }
     752            else {
     753                index++;
     754            }
     755            }
     756            if(!found) {
     757            model.addElement(name);
     758            }
     759        }
     760        }
     761    }
     762    /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
     763    private class EnabledListener
     764        implements ActionListener {
    765765                /** One of two possible buttons that might have their enabled state changed by this listener. */
    766                 private JButton one = null;
     766        private JButton one = null;
    767767                /** One of two possible buttons that might have their enabled state changed by this listener. */
    768                 private JButton two = null;
     768        private JButton two = null;
    769769                /** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
    770                 private JComponent target = null;
     770        private JComponent target = null;
    771771                /** A list which might have its enabled state changed by this listener. */
    772                 private JList list = null;
     772        private JList list = null;
    773773                /** Constructor.
    774774                 * @param one A <strong>JButton</strong> whose enabled state is determined by the listener, or <i>null</i> if no button.
     
    777777                 * @param list A <strong>JComponent</strong> whose enabled state is determined by the listener, or <i>null</i> if no component.
    778778                 */
    779                 public EnabledListener(JButton one, JButton two, JList list, JComponent target) {
    780                      this.list = list;
    781                      this.one = one;
    782                      this.target = target;
    783                      this.two = two;
    784                 }
     779        public EnabledListener(JButton one, JButton two, JList list, JComponent target) {
     780        this.list = list;
     781        this.one = one;
     782        this.target = target;
     783        this.two = two;
     784        }
    785785                /** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on or registered check box, prompting us to change the state of the other controls as per the users request.
    786786                 * @param event An <strong>ActionEvent</strong> containing information about the click.
    787787                 */
    788                 public void actionPerformed(ActionEvent event) {
    789                      JCheckBox source = (JCheckBox)event.getSource();
    790                      if(source.isSelected()) {
    791                           target.setBackground(Color.white);
    792                           target.setEnabled(true);
    793                           if(one != null && two != null && list != null) {
    794                                 one.setEnabled(true);
    795                                 two.setEnabled(true);
    796                                 list.setBackground(Color.white);
    797                                 list.setEnabled(true);
    798                           }
    799                      }
    800                      else {
    801                           target.setBackground(Color.lightGray);
    802                           target.setEnabled(false);
    803                           if(one != null && two != null && list != null) {
    804                                 one.setEnabled(false);
    805                                 two.setEnabled(false);
    806                                 list.setBackground(Color.lightGray);
    807                                 list.setEnabled(false);
    808                           }
    809                      }
    810                 }
    811           }
    812           /** If a metadata element is selected that requires an hfile, then this listener defaults that hfile. */
    813           private class HierarchyListener
    814                 implements ItemListener {
     788        public void actionPerformed(ActionEvent event) {
     789        JCheckBox source = (JCheckBox)event.getSource();
     790        if(source.isSelected()) {
     791            target.setBackground(Color.white);
     792            target.setEnabled(true);
     793            if(one != null && two != null && list != null) {
     794            one.setEnabled(true);
     795            two.setEnabled(true);
     796            list.setBackground(Color.white);
     797            list.setEnabled(true);
     798            }
     799        }
     800        else {
     801            target.setBackground(Color.lightGray);
     802            target.setEnabled(false);
     803            if(one != null && two != null && list != null) {
     804            one.setEnabled(false);
     805            two.setEnabled(false);
     806            list.setBackground(Color.lightGray);
     807            list.setEnabled(false);
     808            }
     809        }
     810        }
     811    }
     812    /** If a metadata element is selected that requires an hfile, then this listener defaults that hfile. */
     813    private class HierarchyListener
     814        implements ItemListener {
    815815                /** Any implementation of ItemListener must include this method so that we can be informed when an item from the list is selected, and generate a predetermined hfile for that selection.
    816816                 * @param event An <strong>ItemEvent</strong> containing information about the selection.
     
    818818                 * @see org.greenstone.gatherer.valuetree.GValueModel
    819819                 */
    820                 public void itemStateChanged(ItemEvent event) {
    821                      // Determine if the selected element represents a hierarchy.
    822                      Object temp = ((JComboBox)value).getSelectedItem();
    823                      String filename = temp.toString();
    824                      // Search for a argument control called hfile and enable and set value.
    825                      for(int i = 0; i < central_pane.getComponentCount(); i++) {
    826                           Object object = central_pane.getComponent(i);
    827                           if(object instanceof ArgumentControl) {
    828                                 ArgumentControl control = (ArgumentControl) object;
    829                                 if(control.toString().equals("hfile")) {
    830                                     control.setValue(filename + ".txt");
    831                                     control.setEnabled(true);
    832                                 }
    833                           }
    834                      }
    835                 }
    836           }
    837           /** A ListOption is a compound item which is constructed from several Strings. That magic part is that the length of screen real-estate used by the text version of this item is limited. */
    838           private class ListOption
    839                 implements Comparable {
     820        public void itemStateChanged(ItemEvent event) {
     821        // Determine if the selected element represents a hierarchy.
     822        Object temp = ((JComboBox)value).getSelectedItem();
     823        String filename = temp.toString();
     824        // Search for a argument control called hfile and enable and set value.
     825        for(int i = 0; i < central_pane.getComponentCount(); i++) {
     826            Object object = central_pane.getComponent(i);
     827            if(object instanceof ArgumentControl) {
     828            ArgumentControl control = (ArgumentControl) object;
     829            if(control.toString().equals("hfile")) {
     830                control.setValue(filename + ".txt");
     831                control.setEnabled(true);
     832            }
     833            }
     834        }
     835        }
     836    }
     837    /** A ListOption is a compound item which is constructed from several Strings. That magic part is that the length of screen real-estate used by the text version of this item is limited. */
     838    private class ListOption
     839        implements Comparable {
    840840                /** The maximum length of this String version of this item. */
    841                 private int MAX_DESC = 35;
     841        private int MAX_DESC = 35;
    842842                /** The description of the value for this item. */
    843                 private String description = null;
     843        private String description = null;
    844844                /** A cached value for the text value of this option, as it never changes after the first call to toString(). */
    845                 private String text = null;
     845        private String text = null;
    846846                /** The value for this item. */
    847                 private String value = null;
     847        private String value = null;
    848848                /** Constructor.
    849849                 * @param value The value for this item as a <strong>String</strong>.
    850850                 * @param description The description of the value as a <strong>String</strong>.
    851851                 */
    852                 public ListOption(String value, String description) {
    853                      this.description = description;
    854                      this.value = value;
    855                 }
     852        public ListOption(String value, String description) {
     853        this.description = description;
     854        this.value = value;
     855        }
    856856                /** Compare two possible ListOption objects for ordering.
    857857                 * @param object The <strong>Object</strong> to compare to.
     
    859859                 * @see java.lang.String#compareTo
    860860                 */
    861                 public int compareTo(Object object) {
    862                      return toString().compareTo(object.toString());
    863                 }
     861        public int compareTo(Object object) {
     862        return toString().compareTo(object.toString());
     863        }
    864864                /** Tests two possible ListOption objects for equality. Uses the result from compareTo().
    865865                 * @param The <strong>Object</strong> which may be equal.
    866866                 * @return <i>true</i> if the objects are equal, <i>false</i> otherwise.
    867867                 */
    868                 public boolean equals(Object object) {
    869                      return (compareTo(object) == 0);
    870                 }
     868        public boolean equals(Object object) {
     869        return (compareTo(object) == 0);
     870        }
    871871                /** Retrieve the description of this list item.
    872872                 * @return The description as a <strong>String</strong>.
    873873                 */
    874                 public String getDesc() {
    875                      return description;
    876                 }
     874        public String getDesc() {
     875        return description;
     876        }
    877877                /** Retrieve the value of this list item.
    878878                 * @return The value as a <strong>String</strong>.
    879879                 */
    880                 public String getValue() {
    881                      return value;
    882                 }
     880        public String getValue() {
     881        return value;
     882        }
    883883                /** Convert this object into a nice readable String.
    884884                 * @return A <strong>String</strong> representing this object.
    885885                 */
    886                 public String toString() {
    887                      if(text == null) {
    888                           if(description.length() >= MAX_DESC) {
    889                                 text = value + " - " + description.substring(0, MAX_DESC);
    890                           }
    891                           else {
    892                                 text = value + " - " + description;
    893                           }
    894                      }
    895                      return text;
    896                 }
    897           }
    898           /** Listener which removes entries from a list from a combobox when fired. */
    899           private class RemoveListener
    900                 implements ActionListener {
     886        public String toString() {
     887        if(text == null) {
     888            if(description.length() >= MAX_DESC) {
     889            text = value + " - " + description.substring(0, MAX_DESC);
     890            }
     891            else {
     892            text = value + " - " + description;
     893            }
     894        }
     895        return text;
     896        }
     897    }
     898    /** Listener which removes entries from a list from a combobox when fired. */
     899    private class RemoveListener
     900        implements ActionListener {
    901901                /** The model behind the target list. */
    902                 private DefaultListModel model = null;
     902        private DefaultListModel model = null;
    903903                /** The list to remove data from. */
    904                 private JList target = null;
     904        private JList target = null;
    905905                /** Constructor.
    906906                 * @param target A <strong>JList</strong>.
    907907                 */
    908                 public RemoveListener(JList target) {
    909                      this.model = (DefaultListModel) target.getModel();
    910                      this.target = target;
    911                 }
     908        public RemoveListener(JList target) {
     909        this.model = (DefaultListModel) target.getModel();
     910        this.target = target;
     911        }
    912912                /** When the remove button is clicked, we attempt to remove the selected metadata from the target.
    913913                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    914914                 */
    915                 public void actionPerformed(ActionEvent event) {
    916                      if(!target.isSelectionEmpty()) {
    917                           int index = target.getSelectedIndex();
    918                           model.remove(index);
    919                      }
    920                 }
    921           }
    922           /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
    923           private class ToolTipUpdater
    924                 implements ActionListener {
     915        public void actionPerformed(ActionEvent event) {
     916        if(!target.isSelectionEmpty()) {
     917            int index = target.getSelectedIndex();
     918            model.remove(index);
     919        }
     920        }
     921    }
     922    /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
     923    private class ToolTipUpdater
     924        implements ActionListener {
    925925                /** Any implementation of an ActionListener must include this method so that we can be informed when the selection in a combobox has changed and update the tooltip accordingly.
    926926                 * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
    927927                 */
    928                 public void actionPerformed(ActionEvent event) {
    929                      JComboBox source = (JComboBox)event.getSource();
    930                      ListOption lo = (ListOption)source.getSelectedItem();
    931                      String description = Utility.formatHTMLWidth(lo.getDesc(), 60);
    932                      source.setToolTipText(description);
    933                 }
    934           }
    935     }
     928        public void actionPerformed(ActionEvent event) {
     929        JComboBox source = (JComboBox)event.getSource();
     930        ListOption lo = (ListOption)source.getSelectedItem();
     931        String description = Utility.formatHTMLWidth(lo.getDesc(), 60);
     932        source.setToolTipText(description);
     933        }
     934    }
     935    }
    936936}
  • trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentContainer.java

    r4293 r4366  
    5656 */
    5757public interface ArgumentContainer {
    58     /** Method to retrieve the list of arguments from this container. Note that this method returns both the containers arguments plus its 'supers' arguments if any, and alphabetically orders them.
    59       * @return The arguments within a <strong>ArrayList</strong>.
    60       */
    61     public ArrayList getArguments();
    62     /** Method to retrieve this containers custom argument string.
    63       * @return The custom arguments as a <strong>String</strong>.
    64       */
    65     public String getCustom();
    66     /** Method to retrieve the name associated with this argument container.
    67       * @return The name as a <strong>String</strong>.
    68       */
    69     public String getName();
    70     /** Method to set the custom arguments string.
    71       * @param custom The new custom argument <strong>String</strong>.
    72       */
    73     public void setCustom(String custom);
     58    /** Method to retrieve the list of arguments from this container. Note that this method returns both the containers arguments plus its 'supers' arguments if any, and alphabetically orders them.
     59     * @return The arguments within a <strong>ArrayList</strong>.
     60     */
     61    public ArrayList getArguments();
     62    /** Method to retrieve this containers custom argument string.
     63     * @return The custom arguments as a <strong>String</strong>.
     64     */
     65    public String getCustom();
     66    /** Method to retrieve the name associated with this argument container.
     67     * @return The name as a <strong>String</strong>.
     68     */
     69    public String getName();
     70    /** Method to set the custom arguments string.
     71     * @param custom The new custom argument <strong>String</strong>.
     72     */
     73    public void setCustom(String custom);
    7474}
    7575
  • trunk/gli/src/org/greenstone/gatherer/cdm/Classifier.java

    r4293 r4366  
    6666// ####################################################################################
    6767public class Classifier
    68     extends ArrayList
    69     implements ArgumentContainer, Comparable, Serializable {
    70     /** A reference to the classifier that this one inherits from. */
    71     private Classifier super_classifier = null;
    72     /** A reference to the manager of this classifier. Only available once the classifiers been assigned, always <i>null</i> for classifiers in reserve. */
    73     private ClassifierManager manager = null;
    74     /** Custom arguments (ie those unparsable from classinfo.pl) provided to this class. */
    75     private String custom = null;
    76     /** A description of this classifier. */
    77     private String desc = null;
    78     /** The name of the classifier as it would appear in the collect.cfg file. */
    79     private String name = null;
    80     /** A list of format commands that are dependant on this classifier. */
    81     private ArrayList dependant_formats = null;
    82     /** Default Constructor.
    83       */
    84     public Classifier() {
    85           super();
    86           dependant_formats = new ArrayList();
    87     }
    88     /** Constructor.
     68    extends ArrayList
     69    implements ArgumentContainer, Comparable, Serializable {
     70    /** A reference to the classifier that this one inherits from. */
     71    private Classifier super_classifier = null;
     72    /** A reference to the manager of this classifier. Only available once the classifiers been assigned, always <i>null</i> for classifiers in reserve. */
     73    private ClassifierManager manager = null;
     74    /** Custom arguments (ie those unparsable from classinfo.pl) provided to this class. */
     75    private String custom = null;
     76    /** A description of this classifier. */
     77    private String desc = null;
     78    /** The name of the classifier as it would appear in the collect.cfg file. */
     79    private String name = null;
     80    /** A list of format commands that are dependant on this classifier. */
     81    private ArrayList dependant_formats = null;
     82    /** Default Constructor.
     83     */
     84    public Classifier() {
     85    super();
     86    dependant_formats = new ArrayList();
     87    }
     88    /** Constructor.
    8989      * @param name The name of this classifier as a <strong>String</strong>.
    9090      * @param desc A description of this classifier as a <strong>String</strong>.
    9191      * @param super_classifier The super class of this classifier, as a <strong>Classifier</strong>.
    9292      */
    93     public Classifier(String name, String desc, Classifier super_classifier) {
    94           this();
    95           this.desc = desc;
    96           this.name = name;
    97           this.super_classifier = super_classifier;
    98     }
    99     /** Method to add an argument to this classifier. Only adds the argument if it isn't already present.
     93    public Classifier(String name, String desc, Classifier super_classifier) {
     94    this();
     95    this.desc = desc;
     96    this.name = name;
     97    this.super_classifier = super_classifier;
     98    }
     99    /** Method to add an argument to this classifier. Only adds the argument if it isn't already present.
    100100      * @param argument The <strong>Argument</strong> to add.
    101101      */
    102     public void addArgument(Argument argument) {
    103           if(!contains(argument)) {
    104                 add(argument);
    105                 argument.setOwner(name);
    106           }
    107     }
    108     /** Method to register a dependant format with this classifier. If the classifier changes, this format also needs to be updated.
     102    public void addArgument(Argument argument) {
     103    if(!contains(argument)) {
     104        add(argument);
     105        argument.setOwner(name);
     106    }
     107    }
     108    /** Method to register a dependant format with this classifier. If the classifier changes, this format also needs to be updated.
    109109      * @param format A <strong>Format</strong> which is dependant on this classifier.
    110110      */
    111     public void addDependantFormat(Format format) {
    112           dependant_formats.add(format);
    113     }
    114     /** Method to compare two classifiers for ordering.
     111    public void addDependantFormat(Format format) {
     112    dependant_formats.add(format);
     113    }
     114    /** Method to compare two classifiers for ordering.
    115115      * @param object The classifier we are comparing to, as an <strong>Object</strong>.
    116116      * @return An <i>int</i> specifying the classifier order, using values as set out in String.
    117117      * @see java.lang.String#compareTo
    118118      */
    119     public int compareTo(Object object) {
    120           if(object instanceof Classifier) {
    121                 Classifier classifier = (Classifier) object;
    122                 return name.compareTo(classifier.getName());
    123           }
    124           return name.compareTo(object.toString());
    125     }
    126     /** This method produces a deep copy of this classifier. Note that this also creates a new copy of each of the super classes of classifiers as well. This is the way it should be, as each assigned classifier may have different values for the higher classifiers (such as BasPlug).
     119    public int compareTo(Object object) {
     120    if(object instanceof Classifier) {
     121        Classifier classifier = (Classifier) object;
     122        return name.compareTo(classifier.getName());
     123    }
     124    return name.compareTo(object.toString());
     125    }
     126    /** This method produces a deep copy of this classifier. Note that this also creates a new copy of each of the super classes of classifiers as well. This is the way it should be, as each assigned classifier may have different values for the higher classifiers (such as BasPlug).
    127127      * @return A newly created <strong>Classifier</strong> with the same details and Arguments as this one.
    128128      * @see org.greenstone.gatherer.cdm.Argument
    129129      */
    130     public Classifier copy() {
    131           Classifier copy = null;
    132           if(super_classifier == null) {
    133                 copy = new Classifier(name, desc, null);
    134           }
    135           else {
    136                 copy = new Classifier(name, desc, super_classifier.copy());
    137           }
    138           for(int i = 0; i < size(); i++) {
    139                 copy.addArgument(((Argument)get(i)).copy());
    140           }
    141           return copy;
    142     }
    143     /** Method to determine if two classifiers are equal.
     130    public Classifier copy() {
     131    Classifier copy = null;
     132    if(super_classifier == null) {
     133        copy = new Classifier(name, desc, null);
     134    }
     135    else {
     136        copy = new Classifier(name, desc, super_classifier.copy());
     137    }
     138    for(int i = 0; i < size(); i++) {
     139        copy.addArgument(((Argument)get(i)).copy());
     140    }
     141    return copy;
     142    }
     143    /** Method to determine if two classifiers are equal.
    144144      * @param object The classifier to test against, as an <strong>Object</strong>.
    145145      * @return <i>true</i> if the classifier names match, <i>false</i> otherwise.
    146146      * @see org.greenstone.gatherer.cdm.CustomClassifier
    147147      */
    148     public boolean equals(Object object) {
    149           if(object instanceof CustomClassifier) {
    150                 CustomClassifier classifier = (CustomClassifier) object;
    151                 return (toString().equalsIgnoreCase(classifier.getCommand()));
    152           }
    153           else {
    154                 return(toString().equalsIgnoreCase(object.toString()));
    155           }
    156     }
    157     /** Method to retrieve an argument by its name.
     148    public boolean equals(Object object) {
     149    if(object instanceof CustomClassifier) {
     150        CustomClassifier classifier = (CustomClassifier) object;
     151        return (toString().equalsIgnoreCase(classifier.getCommand()));
     152    }
     153    else {
     154        return(toString().equalsIgnoreCase(object.toString()));
     155    }
     156    }
     157    /** Method to retrieve an argument by its name.
    158158      * @param name The name of the argument as a <strong>String</strong>.
    159159      * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
    160160      */
    161     public Argument getArgument(String name) {
    162           // The name given may still include the '-'
    163           if(name.startsWith("-")) {
    164                 name = name.substring(1);
    165           }
    166           ArrayList arguments = getArguments();
    167           for(int i = 0; i < arguments.size(); i++) {
    168                 Argument argument = (Argument)arguments.get(i);
    169                 if(argument.getName().equals(name)) {
    170                      return argument;
    171                 }
    172           }
    173           return null;
    174     }
    175     /** Method to retrieve all of the arguments available to a classifier, including both specific and general ones.
     161    public Argument getArgument(String name) {
     162    // The name given may still include the '-'
     163    if(name.startsWith("-")) {
     164        name = name.substring(1);
     165    }
     166    ArrayList arguments = getArguments();
     167    for(int i = 0; i < arguments.size(); i++) {
     168        Argument argument = (Argument)arguments.get(i);
     169        if(argument.getName().equals(name)) {
     170        return argument;
     171        }
     172    }
     173    return null;
     174    }
     175    /** Method to retrieve all of the arguments available to a classifier, including both specific and general ones.
    176176      * @return A <strong>Hashtable</strong> of arguments, with &lt;name&gt; -&gt; &lt;argument&gt; entries.
    177177      */
    178     public ArrayList getArguments() {
    179           ArrayList all_arguments = new ArrayList(this);
    180           if(super_classifier != null) {
    181                 ArrayList super_arguments = super_classifier.getArguments();
    182                 for(int i = 0; i < super_arguments.size(); i++) {
    183                      Object argument = super_arguments.get(i);
    184                      if(!all_arguments.contains(argument)) {
    185                           all_arguments.add(argument);
    186                      }
    187                 }
    188           }
    189           return all_arguments;
    190     }
    191     /** Method to retrieve a classifiers custom argument information.
     178    public ArrayList getArguments() {
     179    ArrayList all_arguments = new ArrayList(this);
     180    if(super_classifier != null) {
     181        ArrayList super_arguments = super_classifier.getArguments();
     182        for(int i = 0; i < super_arguments.size(); i++) {
     183        Object argument = super_arguments.get(i);
     184        if(!all_arguments.contains(argument)) {
     185            all_arguments.add(argument);
     186        }
     187        }
     188    }
     189    return all_arguments;
     190    }
     191    /** Method to retrieve a classifiers custom argument information.
    192192      * @return The custom arguments as a <strong>String</strong>.
    193193      */
    194     public String getCustom() {
    195           return custom;
    196     }
    197     /** Method to retrieve a classifiers name.
     194    public String getCustom() {
     195    return custom;
     196    }
     197    /** Method to retrieve a classifiers name.
    198198      * @return A <strong>String</strong> containing the classifiers name.
    199199      */
    200     public String getName() {
    201           return name;
    202     }
    203     /** Method to retrieve the position of this classifier as a special keyword or the form "CL#" where # is the classifiers order in the set of classifiers. Note that if this is called for a Classifier that has never been assigned a position of 'Search' is returned, as this is the only case where we will try to write a Classifier that does not have a manager.
     200    public String getName() {
     201    return name;
     202    }
     203    /** Method to retrieve the position of this classifier as a special keyword or the form "CL#" where # is the classifiers order in the set of classifiers. Note that if this is called for a Classifier that has never been assigned a position of 'Search' is returned, as this is the only case where we will try to write a Classifier that does not have a manager.
    204204      * @return A <strong>String</strong> containing the special position keyword.
    205205      * @see org.greenstone.gatherer.cdm.ClassifierManager
    206206      */
    207     public String getPositionString() {
    208           if(manager == null) {
    209                 return "Search";
    210           }
    211           return "CL" + (manager.indexOf(this) + 1);
    212     }
    213     /** Method to set the value of custom.
     207    public String getPositionString() {
     208    if(manager == null) {
     209        return "Search";
     210    }
     211    return "CL" + (manager.indexOf(this) + 1);
     212    }
     213    /** Method to set the value of custom.
    214214      * @param custom The new value of custom as a <strong>String</strong>.
    215215      */
    216     public void setCustom(String custom) {
    217           this.custom = custom;
    218     }
    219     /** Method to set the value of desc.
     216    public void setCustom(String custom) {
     217    this.custom = custom;
     218    }
     219    /** Method to set the value of desc.
    220220      * @param desc The new value of desc as a <strong>String</strong>.
    221221      */
    222     public void setDesc(String desc) {
    223           this.desc = desc;
    224     }
    225     /** Method to set the value of manager.
     222    public void setDesc(String desc) {
     223    this.desc = desc;
     224    }
     225    /** Method to set the value of manager.
    226226      * @param manager The new manager as a <strong>ClassifierManager</strong>.
    227227      */
    228     public void setManager(ClassifierManager manager) {
    229           this.manager = manager;
    230     }
    231     /** Method to set the value of name.
     228    public void setManager(ClassifierManager manager) {
     229    this.manager = manager;
     230    }
     231    /** Method to set the value of name.
    232232      * @param name The new value of name as a <strong>String</strong>.
    233233      */
    234     public void setName(String name) {
    235           this.name = name;
    236     }
    237     /** Method to set the value of the super_classifier.
     234    public void setName(String name) {
     235    this.name = name;
     236    }
     237    /** Method to set the value of the super_classifier.
    238238      * @param super_classifier The new value of super_classifier as a <strong>Classifier</strong>, or <i>null</i> if this class has no inheritance.
    239239      */
    240     public void setSuper(Classifier super_classifier) {
    241           this.super_classifier = super_classifier;
    242     }
    243     /** Method to print out this classifier as it would appear as a command within the collection configuration file.
     240    public void setSuper(Classifier super_classifier) {
     241    this.super_classifier = super_classifier;
     242    }
     243    /** Method to print out this classifier as it would appear as a command within the collection configuration file.
    244244      * @return A <strong>String</strong> containing a single classifier command.
    245245      */
    246     public String toString() {
    247           StringBuffer text = new StringBuffer("classify ");
    248           text.append(name);
    249           text.append(" ");
    250           ArrayList arguments = getArguments();
    251           for(int i = 0; i < arguments.size(); i++) {
    252                 Argument argument = (Argument)arguments.get(i);
    253                 if(argument.isAssigned()) {
    254                      text.append(argument.toString());
    255                      text.append(" ");
    256                 }
    257           }
    258           if(custom != null) {
    259                 text.append(custom);
    260           }
    261           return text.toString();
    262     }
     246    public String toString() {
     247    StringBuffer text = new StringBuffer("classify ");
     248    text.append(name);
     249    text.append(" ");
     250    ArrayList arguments = getArguments();
     251    for(int i = 0; i < arguments.size(); i++) {
     252        Argument argument = (Argument)arguments.get(i);
     253        if(argument.isAssigned()) {
     254        text.append(argument.toString());
     255        text.append(" ");
     256        }
     257    }
     258    if(custom != null) {
     259        text.append(custom);
     260    }
     261    return text.toString();
     262    }
    263263}
    264264
  • trunk/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java

    r4293 r4366  
    112112// ####################################################################################
    113113public class ClassifierManager
    114     implements MSMListener {
    115     /** An interface to the Gatherer, the creator of this cdm module, for access to the Greenstone installation directory. */
    116     private Gatherer gatherer = null;
    117     /** A reference to the CollectionDesignManager for access to other configuration managers. */
    118     private CollectionDesignManager manager = null;
    119     /** The controls for editing the contents of this manager. */
    120     private Control controls = null;
    121     /** A list of assigned classifiers. */
    122     private DynamicListModel assigned = null;
    123     /** A list of known, but currently unassigned, classifiers. */
    124     private DynamicListModel reserve = null;
    125     /** 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. */
    126     private ArrayList unresolved_commands = null;
    127     /** Constructor.
    128       * @param gatherer A reference to the <strong>Gatherer</strong> for access to the Dictionary.
    129       * @param manager A reference to the <strong>CollectionDesignManager</strong> itself.
    130       * @see org.greenstone.gatherer.Gatherer
    131       * @see org.greenstone.gatherer.cdm.DynamicListModel
    132       * @see org.greenstone.gatherer.collection.CollectionManager
    133       * @see org.greenstone.gatherer.msm.MetadataSetManager
    134       * @see org.greenstone.gatherer.msm.MSMListener
    135       */
    136     public ClassifierManager(Gatherer gatherer, CollectionDesignManager manager) {
    137           this.assigned = new DynamicListModel();
    138           this.gatherer = gatherer;
    139           this.manager = manager;
    140           this.unresolved_commands = new ArrayList();
    141           loadClassifiers();
    142           saveClassifiers();
    143           // Register as a MSMListener.
    144           Gatherer.c_man.getCollection().msm.addMSMListener(this);
    145     }
    146     /** Method to add a new classifier to reserve.
     114    implements MSMListener {
     115    /** An interface to the Gatherer, the creator of this cdm module, for access to the Greenstone installation directory. */
     116    private Gatherer gatherer = null;
     117    /** A reference to the CollectionDesignManager for access to other configuration managers. */
     118    private CollectionDesignManager manager = null;
     119    /** The controls for editing the contents of this manager. */
     120    private Control controls = null;
     121    /** A list of assigned classifiers. */
     122    private DynamicListModel assigned = null;
     123    /** A list of known, but currently unassigned, classifiers. */
     124    private DynamicListModel reserve = null;
     125    /** 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. */
     126    private ArrayList unresolved_commands = null;
     127    /** Constructor.
     128     * @param gatherer A reference to the <strong>Gatherer</strong> for access to the Dictionary.
     129     * @param manager A reference to the <strong>CollectionDesignManager</strong> itself.
     130     * @see org.greenstone.gatherer.Gatherer
     131     * @see org.greenstone.gatherer.cdm.DynamicListModel
     132     * @see org.greenstone.gatherer.collection.CollectionManager
     133     * @see org.greenstone.gatherer.msm.MetadataSetManager
     134     * @see org.greenstone.gatherer.msm.MSMListener
     135     */
     136    public ClassifierManager(Gatherer gatherer, CollectionDesignManager manager) {
     137    this.assigned = new DynamicListModel();
     138    this.gatherer = gatherer;
     139    this.manager = manager;
     140    this.unresolved_commands = new ArrayList();
     141    loadClassifiers();
     142    saveClassifiers();
     143    // Register as a MSMListener.
     144    Gatherer.c_man.getCollection().msm.addMSMListener(this);
     145    }
     146    /** Method to add a new classifier to reserve.
    147147      * @param classifier The new <strong>Classifier</strong>.
    148148      * @see org.greenstone.gatherer.cdm.DynamicListModel
    149149      */
    150     public void addClassifier(Classifier classifier) {
    151           if(!reserve.contains(classifier)) {
    152                 reserve.addElement(classifier);
    153           }
    154     }
    155     /** Method to assign a classifier.
     150    public void addClassifier(Classifier classifier) {
     151    if(!reserve.contains(classifier)) {
     152        reserve.addElement(classifier);
     153    }
     154    }
     155    /** Method to assign a classifier.
    156156      * @param classifier The reserve <strong>Classifier</strong> to assign.
    157157      * @see org.greenstone.gatherer.cdm.DynamicListModel
    158158      */
    159     public void assignClassifier(Classifier classifier) {
    160           if(!assigned.contains(classifier)) {
    161                 assigned.addElement(classifier);
    162                 classifier.setManager(this);
    163                 gatherer.c_man.configurationChanged();
    164           }
    165     }
    166     /** Method to assign a classifier.
     159    public void assignClassifier(Classifier classifier) {
     160    if(!assigned.contains(classifier)) {
     161        assigned.addElement(classifier);
     162        classifier.setManager(this);
     163        gatherer.c_man.configurationChanged();
     164    }
     165    }
     166    /** Method to assign a classifier.
    167167      * @param classifier The <strong>CustomClassifier</strong> to assign.
    168168      * @see org.greenstone.gatherer.cdm.DynamicListModel
    169169      */
    170     public void assignClassifier(CustomClassifier classifier) {
    171           if(!assigned.contains(classifier)) {
    172                 assigned.addElement(classifier);
    173                classifier.setManager(this);
    174                 gatherer.c_man.configurationChanged();
    175           }
    176     }
    177     /** Destructor.
     170    public void assignClassifier(CustomClassifier classifier) {
     171    if(!assigned.contains(classifier)) {
     172        assigned.addElement(classifier);
     173        classifier.setManager(this);
     174        gatherer.c_man.configurationChanged();
     175    }
     176    }
     177    /** Destructor.
    178178      * @see org.greenstone.gatherer.Gatherer
    179179      * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    180180      * @see org.greenstone.gatherer.cdm.DynamicListModel
    181181      */
    182     public void destroy() {
    183           // Deregister as a listener
    184           if(gatherer.c_man != null && gatherer.c_man.msm != null) {
    185                 gatherer.c_man.msm.removeMSMListener(this);
    186           }
    187           // Null globals
    188           assigned = null;
    189           controls = null;
    190           gatherer = null;
    191           manager = null;
    192           reserve = null;
    193           unresolved_commands = null;
    194     }
    195     /** Method to retrieve the classifier with the given index.
     182    public void destroy() {
     183    // Deregister as a listener
     184    if(gatherer.c_man != null && gatherer.c_man.msm != null) {
     185        gatherer.c_man.msm.removeMSMListener(this);
     186    }
     187    // Null globals
     188    assigned = null;
     189    controls = null;
     190    gatherer = null;
     191    manager = null;
     192    reserve = null;
     193    unresolved_commands = null;
     194    }
     195    /** Method to retrieve the classifier with the given index.
    196196      * @param index The index of the desired classifier as an <i>int</i>.
    197197      * @return The requested Classifier as an <strong>Object</strong> or <i>null</i> if no such classifier exists.
    198198      * @see org.greenstone.gatherer.cdm.DynamicListModel
    199199      */
    200     public Object getClassifier(int index) {
    201           if(0 <= index && index < assigned.size()) {
    202                 return assigned.get(index);
    203           }
    204           return null;
    205     }
    206     /** Method to retrieve the named classifier.
     200    public Object getClassifier(int index) {
     201    if(0 <= index && index < assigned.size()) {
     202        return assigned.get(index);
     203    }
     204    return null;
     205    }
     206    /** Method to retrieve the named classifier.
    207207      * @param name The name of the desired classifier as a <strong>String</strong>.
    208208      * @return The requested <strong>Classifier</strong> or <i>null</i> if no such classifier exists.
    209209      * @see org.greenstone.gatherer.cdm.DynamicListModel
    210210      */
    211     public Classifier getClassifier(String name) {
    212           for(int i = 0; i < reserve.size(); i++) {
    213                 Classifier classifier = (Classifier)reserve.get(i);
    214                 if(classifier.getName().equals(name)) {
    215                      return classifier;
    216                 }
    217           }
    218           // No success.
    219           return null;
    220     }
    221     /** Method to retrieve the control for this manager.
     211    public Classifier getClassifier(String name) {
     212    for(int i = 0; i < reserve.size(); i++) {
     213        Classifier classifier = (Classifier)reserve.get(i);
     214        if(classifier.getName().equals(name)) {
     215        return classifier;
     216        }
     217    }
     218    // No success.
     219    return null;
     220    }
     221    /** Method to retrieve the control for this manager.
    222222      * @return A <strong>JPanel</strong> containing the controls.
    223223      */
    224     public JPanel getControls() {
    225           if(controls == null) {
    226                 controls = new Control();
    227           }
    228           return controls;
    229     }
    230     /** Called whenever a metadata element changes significantly.
     224    public JPanel getControls() {
     225    if(controls == null) {
     226        controls = new Control();
     227    }
     228    return controls;
     229    }
     230    /** Called whenever a metadata element changes significantly.
    231231      * @param event A <strong>MSMEvent</strong> choc' full of event informationy goodness.
    232232      */
    233     public void elementChanged(MSMEvent event) {
    234           // Don't really care, as the elements dealt with here are all live references so changes like identifier change will propagate immediately.
    235     }
    236     /** Method to find the index of the given classifier within the assigned classifiers.
     233    public void elementChanged(MSMEvent event) {
     234    // Don't really care, as the elements dealt with here are all live references so changes like identifier change will propagate immediately.
     235    }
     236    /** Method to find the index of the given classifier within the assigned classifiers.
    237237      * @param classifier The <strong>Classifier</strong> whose index you wish to find.
    238238      * @return The index of the classifier as an <i>int</i>, which has a value of -1 if the classifier was not found.
    239239      * @see org.greenstone.gatherer.cdm.DynamicListModel
    240240      */
    241     public int indexOf(Classifier classifier) {
    242           for(int i = 0; i < assigned.size(); i++) {
    243                 Classifier sibling = (Classifier) assigned.get(i);
    244                 if(sibling.equals(classifier)) {
    245                      return i;
    246                 }
    247           }
    248           return -1;
    249     }
    250     /** Method to invalidate controls after a significant change in the system state.
    251       */
    252     public void invalidateControls() {
    253           if(controls != null) {
    254                 controls.destroy();
    255           }
    256           controls = null;
    257     }
    258     /** Method to load the details of a single plug-in.
     241    public int indexOf(Classifier classifier) {
     242    for(int i = 0; i < assigned.size(); i++) {
     243        Classifier sibling = (Classifier) assigned.get(i);
     244        if(sibling.equals(classifier)) {
     245        return i;
     246        }
     247    }
     248    return -1;
     249    }
     250    /** Method to invalidate controls after a significant change in the system state.
     251      */
     252    public void invalidateControls() {
     253    if(controls != null) {
     254        controls.destroy();
     255    }
     256    controls = null;
     257    }
     258    /** Method to load the details of a single plug-in.
    259259      * @param classifier The classifier <strong>File</strong> you wish to load.
    260260      */
    261     public void loadClassifier(File classifier) {
    262           ///ystem.err.println("Attempting to parse " + classifier.toString());
    263           Document document = null;
    264           long start;
    265           long end;
    266           // Run classinfo on this classifier, and then send the results for parsing.
    267           try {
    268                 String args[] = null;
    269                 if(Utility.isWindows()) {
    270                      args = new String[4];
    271                      if(Gatherer.config.perl_path != null) {
    272                           args[0] = gatherer.config.perl_path + "Perl.exe";
    273                      }
    274                      else {
    275                           args[0] = "Perl.exe";
    276                      }
    277                      args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl";
    278                      args[2] = "-xml";
    279                      args[3] = getClassifierName(classifier);
    280                 }
    281                 else {
    282                      args = new String[3];
    283                      args[0] = "classinfo.pl";
    284                      args[1] = "-xml";
    285                      args[2] = getClassifierName(classifier);
    286                 }
     261    public void loadClassifier(File classifier) {
     262    ///ystem.err.println("Attempting to parse " + classifier.toString());
     263    Document document = null;
     264    long start;
     265    long end;
     266    // Run classinfo on this classifier, and then send the results for parsing.
     267    try {
     268        String args[] = null;
     269        if(Utility.isWindows()) {
     270        args = new String[4];
     271        if(Gatherer.config.perl_path != null) {
     272            args[0] = gatherer.config.perl_path + "Perl.exe";
     273        }
     274        else {
     275            args[0] = "Perl.exe";
     276        }
     277        args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "classinfo.pl";
     278        args[2] = "-xml";
     279        args[3] = getClassifierName(classifier);
     280        }
     281        else {
     282        args = new String[3];
     283        args[0] = "classinfo.pl";
     284        args[1] = "-xml";
     285        args[2] = getClassifierName(classifier);
     286        }
    287287
    288288                // Create the process.
    289                 Runtime runtime = Runtime.getRuntime();
    290                 Process process = runtime.exec(args);
    291                 InputStream input_stream = process.getErrorStream();
    292                 BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    293                 String line = "";
    294                 StringBuffer xml = new StringBuffer("");
    295                 while((line = error_in.readLine()) != null) {
    296                      xml.append(line);
    297                      xml.append("\n");
    298                 }
     289        Runtime runtime = Runtime.getRuntime();
     290        Process process = runtime.exec(args);
     291        InputStream input_stream = process.getErrorStream();
     292        BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
     293        String line = "";
     294        StringBuffer xml = new StringBuffer("");
     295        while((line = error_in.readLine()) != null) {
     296        xml.append(line);
     297        xml.append("\n");
     298        }
    299299                // Then read the xml from the piped input stream.
    300                 InputSource source = new InputSource(new StringReader(xml.toString()));
    301                 DOMParser parser = new DOMParser();
    302                 parser.parse(source);
    303                 document = parser.getDocument();
    304           }
    305           catch (Exception error) {
    306                 error.printStackTrace();
     300        InputSource source = new InputSource(new StringReader(xml.toString()));
     301        DOMParser parser = new DOMParser();
     302        parser.parse(source);
     303        document = parser.getDocument();
     304    }
     305    catch (Exception error) {
     306        error.printStackTrace();
    307307                //ystem.err.println("Error: Cannot parse " + getClassifierName(classifier));
    308           }
    309           if(document != null) {
    310                 parse(document.getDocumentElement());
    311           }
    312     }
    313     /** Called whenever the metadata value associated to a certain record changes. */
    314     public void metadataChanged(MSMEvent event) {
    315           FileNode record = event.getRecord();
    316           if(record != null) {
    317                 for(int i = 0; i < assigned.size(); i++) {
    318                      Object object = assigned.get(i);
    319                      if(object instanceof CustomClassifier) {
    320                           CustomClassifier classifier = (CustomClassifier) object;
    321                           classifier.process(record);
    322                      }
    323                 }
    324           }
    325     }
    326     /** 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.
     308    }
     309    if(document != null) {
     310        parse(document.getDocumentElement());
     311    }
     312    }
     313    /** Called whenever the metadata value associated to a certain record changes. */
     314    public void metadataChanged(MSMEvent event) {
     315    FileNode record = event.getRecord();
     316    if(record != null) {
     317        for(int i = 0; i < assigned.size(); i++) {
     318        Object object = assigned.get(i);
     319        if(object instanceof CustomClassifier) {
     320            CustomClassifier classifier = (CustomClassifier) object;
     321            classifier.process(record);
     322        }
     323        }
     324    }
     325    }
     326    /** 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.
    327327      * @param command The command <strong>String</strong> that may include classifier information.
    328328      * @return <i>true</i> if a classifier command was parsed, <i>false</i> otherwise.
     
    331331      * @see org.greenstone.gatherer.cdm.CommandTokenizer
    332332      */
    333      public boolean parse(String command) {
    334           String command_lc = command.toLowerCase();
    335           if(command_lc.startsWith("classify")) {
    336                 CommandTokenizer tokenizer = new CommandTokenizer(command);
    337                 if(tokenizer.countTokens() >= 2) {
    338                      tokenizer.nextToken(); // Throw away 'classifier'
    339                      String name = tokenizer.nextToken();
    340                      // Try to locate the classifier with this name.
    341                      Classifier classifier = getClassifier(name);
    342                      // And if successful start to parse the arguments.
    343                      if(classifier != null) {
    344                           // Take a copy.
    345                           classifier = classifier.copy();
    346                           String key = null;
    347                           while((key = tokenizer.nextToken()) != null) {
    348                                 // Try to retrieve a matching argument.
    349                                 Argument argument = classifier.getArgument(key);
    350                                 if(argument != null) {
    351                                      // Set as assigned.
    352                                      argument.setAssigned(true);
    353                                      // And if the argument is of a parameter type, parse a parameter.
    354                                      if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
    355                                           String value = tokenizer.nextToken();
    356                                           value = value.replace(':', MSMUtils.NS_SEP);
    357                                           argument.setValue(value);
    358                                      }
    359                                 }
    360                                 // Argument cannot be matched.
    361                                 else {
    362                                      String cur_key = key;
    363                                      String value = tokenizer.nextToken();
    364                                      if(value.startsWith("-")) {
    365                                           key = value;
    366                                           value = null;
    367                                      }
    368                                      else {
    369                                           key = null;
    370                                      }
    371                                      String custom = classifier.getCustom();
    372                                      if(custom == null) {
    373                                           if(value == null) {
    374                                                 classifier.setCustom(cur_key);
    375                                           }
    376                                           else {
    377                                                 classifier.setCustom(cur_key + " " + value);
    378                                           }
    379                                      }
    380                                      else {
    381                                           if(value == null) {
    382                                                 classifier.setCustom(custom + " " + cur_key);
    383                                           }
    384                                           else {
    385                                                 classifier.setCustom(custom + " " + cur_key + " " + value);
    386                                           }
    387                                      }
    388                                 }
    389                           }
    390                           assignClassifier(classifier);
    391                           return true;
    392                      }
    393                      else {
    394                           ///ystem.err.println("Unknown classifier");
    395                      }
     333    public boolean parse(String command) {
     334    String command_lc = command.toLowerCase();
     335    if(command_lc.startsWith("classify")) {
     336        CommandTokenizer tokenizer = new CommandTokenizer(command);
     337        if(tokenizer.countTokens() >= 2) {
     338        tokenizer.nextToken(); // Throw away 'classifier'
     339        String name = tokenizer.nextToken();
     340        // Try to locate the classifier with this name.
     341        Classifier classifier = getClassifier(name);
     342        // And if successful start to parse the arguments.
     343        if(classifier != null) {
     344            // Take a copy.
     345            classifier = classifier.copy();
     346            String key = null;
     347            while((key = tokenizer.nextToken()) != null) {
     348            // Try to retrieve a matching argument.
     349            Argument argument = classifier.getArgument(key);
     350            if(argument != null) {
     351                // Set as assigned.
     352                argument.setAssigned(true);
     353                // And if the argument is of a parameter type, parse a parameter.
     354                if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
     355                String value = tokenizer.nextToken();
     356                value = value.replace(':', MSMUtils.NS_SEP);
     357                argument.setValue(value);
     358                }
     359            }
     360            // Argument cannot be matched.
     361            else {
     362                String cur_key = key;
     363                String value = tokenizer.nextToken();
     364                if(value.startsWith("-")) {
     365                key = value;
     366                value = null;
     367                }
     368                else {
     369                key = null;
     370                }
     371                String custom = classifier.getCustom();
     372                if(custom == null) {
     373                if(value == null) {
     374                    classifier.setCustom(cur_key);
    396375                }
    397           }
    398           else if(command_lc.startsWith("customclassifier")) {
    399                 unresolved_commands.add(command);
    400                 return true;
    401           }
    402           return false;
    403      }
    404      /** 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.
     376                else {
     377                    classifier.setCustom(cur_key + " " + value);
     378                }
     379                }
     380                else {
     381                if(value == null) {
     382                    classifier.setCustom(custom + " " + cur_key);
     383                }
     384                else {
     385                    classifier.setCustom(custom + " " + cur_key + " " + value);
     386                }
     387                }
     388            }
     389            }
     390            assignClassifier(classifier);
     391            return true;
     392        }
     393        else {
     394            ///ystem.err.println("Unknown classifier");
     395        }
     396        }
     397    }
     398    else if(command_lc.startsWith("customclassifier")) {
     399        unresolved_commands.add(command);
     400        return true;
     401    }
     402    return false;
     403    }
     404    /** 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.
    405405      * @param classifier The Classifier or CustomClassifier, as an <strong>Object</strong>, to remove.
    406406      * @see org.greenstone.gatherer.cdm.DynamicListModel
    407407      */
    408     public void removeClassifier(Object classifier) {
    409           assigned.removeElement(classifier);
    410           gatherer.c_man.configurationChanged();
    411     }
    412     /** Method which attempts to reparse obvious classifier commands which previously referenced unresovable Classifiers.
     408    public void removeClassifier(Object classifier) {
     409    assigned.removeElement(classifier);
     410    gatherer.c_man.configurationChanged();
     411    }
     412    /** Method which attempts to reparse obvious classifier commands which previously referenced unresovable Classifiers.
    413413      * @see org.greenstone.gatherer.cdm.Classifier
    414414      * @see org.greenstone.gatherer.cdm.CommandTokenizer
    415415      * @see org.greenstone.gatherer.cdm.CustomClassifier
    416416      */
    417     public void reparseUnresolved() {
    418           for(int i = 0; i < unresolved_commands.size(); i++) {
    419                 String command = (String) unresolved_commands.get(i);
    420                 CommandTokenizer tokenizer = new CommandTokenizer(command);
    421                 if(tokenizer.countTokens() >= 6) {
    422                      tokenizer.nextToken();// Loose customclassifier
    423                      // Get class name.
    424                      String class_name = tokenizer.nextToken();
    425                      // Parse arguments.
    426                      String replaces = null;
    427                      String separations = null;
    428                      while(tokenizer.hasMoreTokens()) {
    429                           String arg_name = tokenizer.nextToken();
    430                           if(arg_name.equalsIgnoreCase("-replaces")) {
    431                                 replaces = tokenizer.nextToken();
    432                           }
    433                           else {
    434                                 separations = tokenizer.nextToken();
    435                           }
    436                      }
    437                      try {
    438                           replaces = replaces.substring(2);
    439                           int index = Integer.parseInt(replaces);
    440                           Classifier original = (Classifier)getClassifier(index);
    441                           if(original != null) {
    442                                 Class custom_classifier_class = Class.forName("org.greenstone.gatherer.cdm.custom." + class_name);
    443                                 CustomClassifier custom_classifier = (CustomClassifier) custom_classifier_class.newInstance();
    444                                 custom_classifier.setGatherer(gatherer);
    445                                 custom_classifier.recreate(original, separations);
    446                                 assigned.add(indexOf(original), custom_classifier);
    447                                 assigned.removeElement(original);
    448                           }
    449                           else {
    450                                 ///ystem.err.println("Missing original.");
    451                           }
    452                      }
    453                      catch (Exception error) {
    454                           error.printStackTrace();
    455                      }
    456                 }
    457           }
    458           // Regardless of if they work, clear the commands.
    459           unresolved_commands.clear();
    460     }
    461     /** Method to cache the current contents of reserve (known classifiers) to file.
     417    public void reparseUnresolved() {
     418    for(int i = 0; i < unresolved_commands.size(); i++) {
     419        String command = (String) unresolved_commands.get(i);
     420        CommandTokenizer tokenizer = new CommandTokenizer(command);
     421        if(tokenizer.countTokens() >= 6) {
     422        tokenizer.nextToken();// Loose customclassifier
     423        // Get class name.
     424        String class_name = tokenizer.nextToken();
     425        // Parse arguments.
     426        String replaces = null;
     427        String separations = null;
     428        while(tokenizer.hasMoreTokens()) {
     429            String arg_name = tokenizer.nextToken();
     430            if(arg_name.equalsIgnoreCase("-replaces")) {
     431            replaces = tokenizer.nextToken();
     432            }
     433            else {
     434            separations = tokenizer.nextToken();
     435            }
     436        }
     437        try {
     438            replaces = replaces.substring(2);
     439            int index = Integer.parseInt(replaces);
     440            Classifier original = (Classifier)getClassifier(index);
     441            if(original != null) {
     442            Class custom_classifier_class = Class.forName("org.greenstone.gatherer.cdm.custom." + class_name);
     443            CustomClassifier custom_classifier = (CustomClassifier) custom_classifier_class.newInstance();
     444            custom_classifier.setGatherer(gatherer);
     445            custom_classifier.recreate(original, separations);
     446            assigned.add(indexOf(original), custom_classifier);
     447            assigned.removeElement(original);
     448            }
     449            else {
     450            ///ystem.err.println("Missing original.");
     451            }
     452        }
     453        catch (Exception error) {
     454            error.printStackTrace();
     455        }
     456        }
     457    }
     458    // Regardless of if they work, clear the commands.
     459    unresolved_commands.clear();
     460    }
     461    /** Method to cache the current contents of reserve (known classifiers) to file.
    462462      * @see org.greenstone.gatherer.util.Utility
    463463      */
    464     public void saveClassifiers() {
    465           try {
    466                 FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat");
    467                 ObjectOutputStream out = new ObjectOutputStream(file);
    468                 out.writeObject(reserve);
    469                 out.close();
    470           }
    471           catch (Exception error) {
    472           }
    473     }
    474     /** Called when a metadata set changed significantly.
     464    public void saveClassifiers() {
     465    try {
     466        FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "classifiers.dat");
     467        ObjectOutputStream out = new ObjectOutputStream(file);
     468        out.writeObject(reserve);
     469        out.close();
     470    }
     471    catch (Exception error) {
     472    }
     473    }
     474    /** Called when a metadata set changed significantly.
    475475      * @param event A <strong>MSMEvent</strong> containing information about the set change.
    476476      */
    477     public void setChanged(MSMEvent event) {
    478           // 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.
    479     }
    480     /** Method used to determine the number of classifiers that have been assigned.
     477    public void setChanged(MSMEvent event) {
     478    // 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.
     479    }
     480    /** Method used to determine the number of classifiers that have been assigned.
    481481      * @return An <i>int</i> which is the number of classifiers.
    482482      */
    483     public int size() {
    484           return assigned.size();
    485     }
    486     /** Method to print out a block of classifier commands, much like you'd find in a collection configuration file.
     483    public int size() {
     484    return assigned.size();
     485    }
     486    /** Method to print out a block of classifier commands, much like you'd find in a collection configuration file.
    487487      * @return A <strong>String</strong> containing a series of classifier commands separated by new lines.
    488488      * @see org.greenstone.gatherer.cdm.Classifier
    489489      * @see org.greenstone.gatherer.cdm.CustomClassifier
    490490      */
    491     public String toString() {
    492           StringBuffer text = new StringBuffer();
    493           for(int i = 0; i < assigned.size(); i++) {
    494                 Object object = assigned.get(i);
    495                 if(object instanceof Classifier) {
    496                      Classifier classifier = (Classifier) object;
    497                      text.append(classifier.toString());
    498                 }
    499                 else if(object instanceof CustomClassifier) {
    500                      CustomClassifier classifier = (CustomClassifier) object;
    501                      text.append(classifier.getCommand());
    502                      text.append("\n");
    503                      text.append(classifier.getCustomCommand(i));
    504                 }
    505                 text.append("\n");
    506           }
    507           text.append("\n");
    508           return text.toString();
    509     }
    510     /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
     491    public String toString() {
     492    StringBuffer text = new StringBuffer();
     493    for(int i = 0; i < assigned.size(); i++) {
     494        Object object = assigned.get(i);
     495        if(object instanceof Classifier) {
     496        Classifier classifier = (Classifier) object;
     497        text.append(classifier.toString());
     498        }
     499        else if(object instanceof CustomClassifier) {
     500        CustomClassifier classifier = (CustomClassifier) object;
     501        text.append(classifier.getCommand());
     502        text.append("\n");
     503        text.append(classifier.getCustomCommand(i));
     504        }
     505        text.append("\n");
     506    }
     507    text.append("\n");
     508    return text.toString();
     509    }
     510    /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
    511511      * @param event A <strong>MSMEvent</strong> containing information relevant to the event.
    512512      */
    513     public void valueChanged(MSMEvent event) {
    514     }
    515     /** Retrieve a phrase from the dictionary based on a certain key.
     513    public void valueChanged(MSMEvent event) {
     514    }
     515    /** Retrieve a phrase from the dictionary based on a certain key.
    516516      * @param key The search <strong>String</strong>.
    517517      * @return The matching phrase from the Dictionary.
    518518      */
    519     private String get(String key) {
    520           return get(key, null);
    521     }
    522     /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
     519    private String get(String key) {
     520    return get(key, null);
     521    }
     522    /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
    523523      * @param key The search <strong>String</strong>.
    524524      * @param args A <strong>String[]</strong> used to complete and format the returned phrase.
     
    527527      * @see org.greenstone.gatherer.Gatherer
    528528      */
    529     private String get(String key, String args[]) {
    530           if(key.indexOf(".") == -1) {
    531                 key = "CDM.ClassifierManager." + key;
    532           }
    533           return gatherer.dictionary.get(key, args);
    534     }
    535     /** Method to extract just the classifiers name from a file object.
     529    private String get(String key, String args[]) {
     530    if(key.indexOf(".") == -1) {
     531        key = "CDM.ClassifierManager." + key;
     532    }
     533    return gatherer.dictionary.get(key, args);
     534    }
     535    /** Method to extract just the classifiers name from a file object.
    536536      * @param classifier The <strong>File</strong> which references a certain classifier.
    537537      * @return A <strong>String</strong> containing just the classifiers name, without extension.
    538538      */
    539     private String getClassifierName(File classifier) {
    540           String name = classifier.getName();
    541           if(name.indexOf(".") != -1) {
    542                 name = name.substring(0, name.indexOf("."));
    543           }
    544           return name;
    545     }
    546     /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
     539    private String getClassifierName(File classifier) {
     540    String name = classifier.getName();
     541    if(name.indexOf(".") != -1) {
     542        name = name.substring(0, name.indexOf("."));
     543    }
     544    return name;
     545    }
     546    /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
    547547      * @see org.greenstone.gatherer.cdm.DynamicListModel
    548548      * @see org.greenstone.gatherer.util.Utility
    549549      */
    550     private void loadClassifiers() {
    551           // Attempt to restore the cached file.
    552           try {
    553                 FileInputStream file = new FileInputStream(Utility.BASE_DIR + "classifiers.dat");
    554                 ObjectInputStream input = new ObjectInputStream(file);
    555                 reserve = (DynamicListModel) input.readObject();
    556           }
    557           catch (Exception error) {
    558           }
    559           if(reserve == null) {
    560                 reserve = new DynamicListModel();
     550    private void loadClassifiers() {
     551    // Attempt to restore the cached file.
     552    try {
     553        FileInputStream file = new FileInputStream(Utility.BASE_DIR + "classifiers.dat");
     554        ObjectInputStream input = new ObjectInputStream(file);
     555        reserve = (DynamicListModel) input.readObject();
     556    }
     557    catch (Exception error) {
     558    }
     559    if(reserve == null) {
     560        reserve = new DynamicListModel();
    561561                // Retrieve the gsdl home directory...
    562                 String directory = gatherer.config.gsdl_path;
    563                 directory = directory + "perllib" + File.separator + "classify" + File.separator;
    564                 loadClassifiers(new File(directory));
    565           }
    566     }
    567     /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
     562        String directory = gatherer.config.gsdl_path;
     563        directory = directory + "perllib" + File.separator + "classify" + File.separator;
     564        loadClassifiers(new File(directory));
     565    }
     566    }
     567    /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
    568568      * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
    569569      * @see org.greenstone.gatherer.cdm.ParsingProgress
    570570      */
    571     private void loadClassifiers(File directory) {
    572           File files[] = directory.listFiles();
    573           if(files != null) {
     571    private void loadClassifiers(File directory) {
     572    File files[] = directory.listFiles();
     573    if(files != null) {
    574574                // Create a progress indicator.
    575                 ParsingProgress progress = new ParsingProgress(get("CDM.ClassifierManager.Parsing.Title"), get("CDM.ClassifierManager.Parsing.Message"), files.length);
    576                 for(int i = 0; i < files.length; i++) {
    577                      // We only want to check Perl Modules.
    578                      if(files[i].getName().endsWith(".pm")) {
    579                           loadClassifier(files[i]);
    580                      }
    581                      progress.inc();
    582                 }
    583                 progress.dispose();
    584                 progress.destroy();
    585                 progress = null;
    586           }
    587     }
    588     /** Parses a DOM tree model turning it into a Classifier and its associated arguments.
     575        ParsingProgress progress = new ParsingProgress(get("CDM.ClassifierManager.Parsing.Title"), get("CDM.ClassifierManager.Parsing.Message"), files.length);
     576        for(int i = 0; i < files.length; i++) {
     577        // We only want to check Perl Modules.
     578        if(files[i].getName().endsWith(".pm")) {
     579            loadClassifier(files[i]);
     580        }
     581        progress.inc();
     582        }
     583        progress.dispose();
     584        progress.destroy();
     585        progress = null;
     586    }
     587    }
     588    /** Parses a DOM tree model turning it into a Classifier and its associated arguments.
    589589      * @param root The <strong>Node</strong> at the root of the DOM model.
    590590      * @return A newly created <strong>Classifier</strong> based on the information parsed from the DOM model.
    591591      * @see org.greenstone.gatherer.cdm.Argument
    592592      */
    593      private Classifier parse(Node root) {
    594           Classifier classifier = new Classifier();
    595           String node_name = null;
    596           for(Node node = root.getFirstChild(); node != null;
    597                 node = node.getNextSibling()) {
    598                 node_name = node.getNodeName();
    599                 if(node_name.equals("Name")) {
    600                      String name = MSMUtils.getValue(node);
    601                      // 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.
    602                      Classifier existing = getClassifier(name);
    603                      if(existing != null) {
    604                           return existing;
    605                      }
    606                      classifier.setName(name);
     593    private Classifier parse(Node root) {
     594    Classifier classifier = new Classifier();
     595    String node_name = null;
     596    for(Node node = root.getFirstChild(); node != null;
     597        node = node.getNextSibling()) {
     598        node_name = node.getNodeName();
     599        if(node_name.equals("Name")) {
     600        String name = MSMUtils.getValue(node);
     601        // 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.
     602        Classifier existing = getClassifier(name);
     603        if(existing != null) {
     604            return existing;
     605        }
     606        classifier.setName(name);
     607        }
     608        else if(node_name.equals("Desc")) {
     609        classifier.setDesc(MSMUtils.getValue(node));
     610        }
     611                // Parse the multitude of arguments.
     612        else if(node_name.equals("Arguments")) {
     613        for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
     614            node_name = arg.getNodeName();
     615            // An option.
     616            if(node_name.equals("Option")) {
     617            Argument argument = new Argument();
     618            // If its an option we parse the multitude of details an options might have.
     619            for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
     620                node_name = det.getNodeName();
     621                if(node_name.equals("Name")) {
     622                argument.setName(MSMUtils.getValue(det));
     623                }
     624                else if(node_name.equals("Desc")) {
     625                argument.setDesc(MSMUtils.getValue(det));
     626                }
     627                else if(node_name.equals("Type")) {
     628                argument.setType(MSMUtils.getValue(det));
     629                }
     630                else if(node_name.equals("Default")) {
     631                argument.setDefault(MSMUtils.getValue(det));
     632                }
     633                else if(node_name.equals("List")) {
     634                // Two final loops are required to parse lists.
     635                for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
     636                    if(value.getNodeName().equals("Value")) {
     637                    String key = null;
     638                    String desc = "";
     639                    for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
     640                        node_name = subvalue.getNodeName();
     641                        if(node_name.equals("Name")) {
     642                        key = MSMUtils.getValue(subvalue);
     643                        }
     644                        else if(node_name.equals("Desc")) {
     645                        desc = MSMUtils.getValue(subvalue);
     646                        }
     647                    }
     648                    if(key != null) {
     649                        argument.addOption(key, desc);
     650                    }
     651                    }
    607652                }
    608                 else if(node_name.equals("Desc")) {
    609                      classifier.setDesc(MSMUtils.getValue(node));
     653                }
     654                else if(node_name.equals("Required")) {
     655                String v = MSMUtils.getValue(det);
     656                ///ystem.err.println("Required = " + v);
     657                if(v.equalsIgnoreCase("yes")) {
     658                    ///ystem.err.println("Setting required to true.");
     659                    argument.setRequired(true);
    610660                }
    611                 // Parse the multitude of arguments.
    612                 else if(node_name.equals("Arguments")) {
    613                      for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
    614                           node_name = arg.getNodeName();
    615                           // An option.
    616                           if(node_name.equals("Option")) {
    617                                 Argument argument = new Argument();
    618                                 // If its an option we parse the multitude of details an options might have.
    619                                 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
    620                                      node_name = det.getNodeName();
    621                                      if(node_name.equals("Name")) {
    622                                           argument.setName(MSMUtils.getValue(det));
    623                                      }
    624                                      else if(node_name.equals("Desc")) {
    625                                           argument.setDesc(MSMUtils.getValue(det));
    626                                      }
    627                                      else if(node_name.equals("Type")) {
    628                                           argument.setType(MSMUtils.getValue(det));
    629                                      }
    630                                      else if(node_name.equals("Default")) {
    631                                           argument.setDefault(MSMUtils.getValue(det));
    632                                      }
    633                                      else if(node_name.equals("List")) {
    634                                           // Two final loops are required to parse lists.
    635                                           for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
    636                                                 if(value.getNodeName().equals("Value")) {
    637                                                      String key = null;
    638                                                      String desc = "";
    639                                                      for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
    640                                                           node_name = subvalue.getNodeName();
    641                                                           if(node_name.equals("Name")) {
    642                                                                 key = MSMUtils.getValue(subvalue);
    643                                                           }
    644                                                           else if(node_name.equals("Desc")) {
    645                                                                 desc = MSMUtils.getValue(subvalue);
    646                                                           }
    647                                                      }
    648                                                      if(key != null) {
    649                                                           argument.addOption(key, desc);
    650                                                      }
    651                                                 }
    652                                           }
    653                                      }
    654                                      else if(node_name.equals("Required")) {
    655                                           String v = MSMUtils.getValue(det);
    656                                           ///ystem.err.println("Required = " + v);
    657                                           if(v.equalsIgnoreCase("yes")) {
    658                                                 ///ystem.err.println("Setting required to true.");
    659                                                 argument.setRequired(true);
    660                                           }
    661                                      }
    662                                 }
    663                                 classifier.addArgument(argument);
    664                           }
    665                           // A super classifier class.
    666                           else if(node_name.equals("ClasInfo")) {
    667                                 Classifier super_classifier = parse(arg);
    668                                 classifier.setSuper(super_classifier);
    669                           }
    670                      }
    671                 }
    672           }
    673           if(classifier.getName() != null) {
    674                 addClassifier(classifier);
    675                 return classifier;
    676           }
    677           return null;
    678      }
    679      /** A class which provides controls for assigned and editing classifiers. */
    680      private class Control
    681           extends JPanel {
    682           /** Button for adding classifiers. */
    683           private JButton add = null;
    684           /** Button for configuring the selected classifier. */
    685           private JButton configure = null;
    686           /** Button to remove the selected classifier. */
    687           private JButton remove = null;
    688           /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
    689           private JComboBox classifier = null;
    690           /** A list of assigned classifiers. */
    691           private JList classifier_list = null;
    692           /** The text area containing instructions on the use of this control. */
    693           private JTextArea instructions = null;
    694           /** Constructor.
    695             * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.AddListener
    696             * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.ConfigureListener
    697             * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.RemoveListener
     661                }
     662            }
     663            classifier.addArgument(argument);
     664            }
     665            // A super classifier class.
     666            else if(node_name.equals("ClasInfo")) {
     667            Classifier super_classifier = parse(arg);
     668            classifier.setSuper(super_classifier);
     669            }
     670        }
     671        }
     672    }
     673    if(classifier.getName() != null) {
     674        addClassifier(classifier);
     675        return classifier;
     676    }
     677    return null;
     678    }
     679    /** A class which provides controls for assigned and editing classifiers. */
     680    private class Control
     681    extends JPanel {
     682    /** Button for adding classifiers. */
     683    private JButton add = null;
     684    /** Button for configuring the selected classifier. */
     685    private JButton configure = null;
     686    /** Button to remove the selected classifier. */
     687    private JButton remove = null;
     688    /** A combobox containing all of the known classifiers, including those that may have already been assigned. */
     689    private JComboBox classifier = null;
     690    /** A list of assigned classifiers. */
     691    private JList classifier_list = null;
     692    /** The text area containing instructions on the use of this control. */
     693    private JTextArea instructions = null;
     694    /** Constructor.
     695     * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.AddListener
     696     * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.ConfigureListener
     697     * @see org.greenstone.gatherer.cdm.ClassifierManager.Control.RemoveListener
     698     */
     699    public Control() {
     700        Object classifiers[] = reserve.toArray();
     701        ArrayList classifier_model = new ArrayList();
     702        for(int i = 0; i < classifiers.length; i++) {
     703        classifier_model.add(((Classifier)classifiers[i]).getName());
     704        }
     705                // Now we add custom classifiers.
     706        addCustomClassifiers(classifier_model);
     707        Collections.sort(classifier_model);
     708                // Create
     709        add = new JButton(get("Add"));
     710        JPanel button_pane = new JPanel();
     711        JPanel central_pane = new JPanel();
     712        configure = new JButton(get("Configure"));
     713        JPanel header_pane = new JPanel();
     714        instructions = new JTextArea(get("Instructions"));
     715        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     716        instructions.setEditable(false);
     717        instructions.setLineWrap(true);
     718        instructions.setRows(5);
     719        instructions.setWrapStyleWord(true);
     720        classifier = new JComboBox(classifier_model.toArray());
     721        classifier.setEditable(true);
     722        JLabel classifier_label = new JLabel(get("Classifier"));
     723        classifier_list = new JList(assigned);
     724        JLabel classifier_list_label = new JLabel(get("Assigned"));
     725        classifier_list_label.setHorizontalAlignment(JLabel.CENTER);
     726        classifier_list_label.setOpaque(true);
     727        JPanel classifier_list_pane = new JPanel();
     728        JPanel classifier_pane = new JPanel();
     729        remove = new JButton(get("Remove"));
     730        JLabel title = new JLabel(get("Title"));
     731        title.setHorizontalAlignment(JLabel.CENTER);
     732        title.setOpaque(true);
     733        JPanel temp = new JPanel(new BorderLayout());
     734                // Listeners
     735        add.addActionListener(new AddListener());
     736        configure.addActionListener(new ConfigureListener());
     737        remove.addActionListener(new RemoveListener());
     738        classifier_list.addMouseListener(new ClickListener());
     739                // Layout
     740        title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
     741        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     742        header_pane.setLayout(new BorderLayout());
     743        header_pane.add(title, BorderLayout.NORTH);
     744        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     745        classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
     746        classifier_list_pane.setLayout(new BorderLayout());
     747        classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
     748        classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
     749        classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     750        classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     751        classifier_pane.setLayout(new GridLayout(1,2));
     752        classifier_pane.add(classifier_label);
     753        classifier_pane.add(classifier);
     754        button_pane.setLayout(new GridLayout(3,1));
     755        button_pane.add(add);
     756        button_pane.add(configure);
     757        button_pane.add(remove);
     758                // Scope these mad bordering skillz.
     759        temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
     760        temp.add(classifier_pane, BorderLayout.NORTH);
     761        temp.add(button_pane, BorderLayout.SOUTH);
     762        central_pane.setLayout(new BorderLayout());
     763        central_pane.add(classifier_list_pane, BorderLayout.CENTER);
     764        central_pane.add(temp, BorderLayout.SOUTH);
     765        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     766        setLayout(new BorderLayout());
     767        add(header_pane, BorderLayout.NORTH);
     768        add(central_pane, BorderLayout.CENTER);
     769    }
     770    /** Method which acts like a destructor, tidying up references to persistant objects.
    698771            */
    699           public Control() {
    700                 Object classifiers[] = reserve.toArray();
    701                 ArrayList classifier_model = new ArrayList();
    702                 for(int i = 0; i < classifiers.length; i++) {
    703                      classifier_model.add(((Classifier)classifiers[i]).getName());
    704                 }
    705                 // Now we add custom classifiers.
    706                 addCustomClassifiers(classifier_model);
    707                 Collections.sort(classifier_model);
    708                 // Create
    709                 add = new JButton(get("Add"));
    710                 JPanel button_pane = new JPanel();
    711                 JPanel central_pane = new JPanel();
    712                 configure = new JButton(get("Configure"));
    713                 JPanel header_pane = new JPanel();
    714                 instructions = new JTextArea(get("Instructions"));
    715                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    716                 instructions.setEditable(false);
    717                 instructions.setLineWrap(true);
    718                 instructions.setRows(5);
    719                 instructions.setWrapStyleWord(true);
    720                 classifier = new JComboBox(classifier_model.toArray());
    721                 classifier.setEditable(true);
    722                 JLabel classifier_label = new JLabel(get("Classifier"));
    723                 classifier_list = new JList(assigned);
    724                 JLabel classifier_list_label = new JLabel(get("Assigned"));
    725                 classifier_list_label.setHorizontalAlignment(JLabel.CENTER);
    726                 classifier_list_label.setOpaque(true);
    727                 JPanel classifier_list_pane = new JPanel();
    728                 JPanel classifier_pane = new JPanel();
    729                 remove = new JButton(get("Remove"));
    730                 JLabel title = new JLabel(get("Title"));
    731                 title.setHorizontalAlignment(JLabel.CENTER);
    732                 title.setOpaque(true);
    733                 JPanel temp = new JPanel(new BorderLayout());
    734                 // Listeners
    735                 add.addActionListener(new AddListener());
    736                 configure.addActionListener(new ConfigureListener());
    737                 remove.addActionListener(new RemoveListener());
    738                 classifier_list.addMouseListener(new ClickListener());
    739                 // Layout
    740                 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
    741                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    742                 header_pane.setLayout(new BorderLayout());
    743                 header_pane.add(title, BorderLayout.NORTH);
    744                 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    745                 classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
    746                 classifier_list_pane.setLayout(new BorderLayout());
    747                 classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
    748                 classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
    749                 classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
    750                 classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    751                 classifier_pane.setLayout(new GridLayout(1,2));
    752                 classifier_pane.add(classifier_label);
    753                 classifier_pane.add(classifier);
    754                 button_pane.setLayout(new GridLayout(3,1));
    755                 button_pane.add(add);
    756                 button_pane.add(configure);
    757                 button_pane.add(remove);
    758                 // Scope these mad bordering skillz.
    759                 temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(get("Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
    760                 temp.add(classifier_pane, BorderLayout.NORTH);
    761                 temp.add(button_pane, BorderLayout.SOUTH);
    762                 central_pane.setLayout(new BorderLayout());
    763                 central_pane.add(classifier_list_pane, BorderLayout.CENTER);
    764                 central_pane.add(temp, BorderLayout.SOUTH);
    765                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    766                 setLayout(new BorderLayout());
    767                 add(header_pane, BorderLayout.NORTH);
    768                 add(central_pane, BorderLayout.CENTER);
    769           }
    770           /** Method which acts like a destructor, tidying up references to persistant objects.
     772    public void destroy() {
     773        add = null;
     774        classifier = null;
     775        classifier_list = null;
     776        configure = null;
     777        instructions = null;
     778        remove = null;
     779    }
     780    /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
    771781            */
    772           public void destroy() {
    773                 add = null;
    774                 classifier = null;
    775                 classifier_list = null;
    776                 configure = null;
    777                 instructions = null;
    778                 remove = null;
    779           }
    780           /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
    781             */
    782           public void updateUI() {
    783                 if(instructions != null) {
    784                      instructions.setCaretPosition(0);
    785                 }
    786                 super.updateUI();
    787           }
    788           /** 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.
     782    public void updateUI() {
     783        if(instructions != null) {
     784        instructions.setCaretPosition(0);
     785        }
     786        super.updateUI();
     787    }
     788    /** 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.
    789789            * @param classifier_model An <strong>ArrayList</strong> which will be used as the model for the combobox listing all known Classifiers.
    790790            */
    791           private void addCustomClassifiers(ArrayList classifier_model) {
     791    private void addCustomClassifiers(ArrayList classifier_model) {
    792792                //classifier_model.add("CustomAZList");
    793793                // Search for classifiers under the org.greenstone.gatherer.cdm.custom directory.
    794                 File custom_directory = new File(Utility.BASE_DIR + "classes" + File.separator + "org" + File.separator + "greenstone" + File.separator + "gatherer" + File.separator + "cdm" + File.separator + "custom");
    795                 if(custom_directory.exists()) {
    796                      File children[] = custom_directory.listFiles();
    797                      for(int i = 0; i < children.length; i++) {
    798                           String temp = children[i].getName().toLowerCase();
    799                           // There are a whole bunch of conditions about what files are custom classifier main classes.
    800                           if(temp.endsWith(".class") && temp.indexOf("$") == -1) {
    801                                 // Determine the name of this custom classifier.
    802                                 String name = children[i].getName();
    803                                 name = name.substring(0, name.indexOf("."));
    804                                 classifier_model.add(name);
    805                           }
    806                      }
    807                 }
     794        File custom_directory = new File(Utility.BASE_DIR + "classes" + File.separator + "org" + File.separator + "greenstone" + File.separator + "gatherer" + File.separator + "cdm" + File.separator + "custom");
     795        if(custom_directory.exists()) {
     796        File children[] = custom_directory.listFiles();
     797        for(int i = 0; i < children.length; i++) {
     798            String temp = children[i].getName().toLowerCase();
     799            // There are a whole bunch of conditions about what files are custom classifier main classes.
     800            if(temp.endsWith(".class") && temp.indexOf("$") == -1) {
     801            // Determine the name of this custom classifier.
     802            String name = children[i].getName();
     803            name = name.substring(0, name.indexOf("."));
     804            classifier_model.add(name);
     805            }
     806        }
     807        }
    808808                // Search for any other CustomClassifiers within the jar file (if present)
    809                 File jar_file = new File("Gatherer.jar");
    810                 if(jar_file.exists()) {
    811                      try {
    812                           JarFile jar = new JarFile(jar_file);
    813                           for(Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
    814                                 String name = entries.nextElement().toString();
    815                                 if(name.startsWith("org/greenstone/gatherer/cdm/custom/") && name.endsWith(".class") && name.indexOf("$") == -1) {
    816                                     name = name.substring(35, name.length() - 6);
    817                                     if(!classifier_model.contains(name)) {
    818                                           classifier_model.add(name);
    819                                     }
    820                                 }
    821                                 name = null;
    822                           }
    823                           jar = null;
    824                      }
    825                      catch (Exception error) {
    826                           error.printStackTrace();
    827                      }
    828                 }
    829                 jar_file = null;
    830           }
    831           /** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method.
     809        File jar_file = new File("Gatherer.jar");
     810        if(jar_file.exists()) {
     811        try {
     812            JarFile jar = new JarFile(jar_file);
     813            for(Enumeration entries = jar.entries(); entries.hasMoreElements(); ) {
     814            String name = entries.nextElement().toString();
     815            if(name.startsWith("org/greenstone/gatherer/cdm/custom/") && name.endsWith(".class") && name.indexOf("$") == -1) {
     816                name = name.substring(35, name.length() - 6);
     817                if(!classifier_model.contains(name)) {
     818                classifier_model.add(name);
     819                }
     820            }
     821            name = null;
     822            }
     823            jar = null;
     824        }
     825        catch (Exception error) {
     826            error.printStackTrace();
     827        }
     828        }
     829        jar_file = null;
     830    }
     831    /** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method.
    832832            */
    833           private class AddListener
    834                 implements ActionListener {
     833    private class AddListener
     834        implements ActionListener {
    835835                /** 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, so that we can add the selected Classifier.
    836836                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
     
    840840                 * @see org.greenstone.gatherer.cdm.CustomClassifier
    841841                 */
    842                 public void actionPerformed(ActionEvent event) {
    843                      String name = (String)classifier.getSelectedItem();
    844                      Classifier target = getClassifier(name);
    845                      Classifier classifier = null;
    846                      CustomClassifier custom_classifier = null;
    847                      if(target != null) {
    848                           classifier = target.copy();
    849                      }
    850                      else {
    851                           // Try to retrieve custom classifier for name.
    852                           try {
    853                                 Class custom_class = Class.forName("org.greenstone.gatherer.cdm.custom." + name);
    854                                 custom_classifier = (CustomClassifier)custom_class.newInstance();
    855                                 custom_classifier.setGatherer(gatherer);
    856                           }
    857                           catch (Exception error) {
    858                                 gatherer.debug(error, "Error in ClassifierManager.AddListener.actionPerformed(): " + error);
    859                           }
    860                           // And if all else fails create a new classifier.
    861                           if(classifier == null && custom_classifier == null) {
    862                                 classifier = new Classifier(name, "", null);
    863                           }
    864                      }
    865                      if(classifier != null) {
    866                           // Automatically chain to configuration. This ensures required arguments are filled out.
    867                           ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, classifier);
    868                           if(ac.display()) {
    869                                 assignClassifier(classifier);
    870                           }
    871                           ac.destroy();
    872                           ac = null;
    873                      }
    874                      // Custom classifier
    875                      else {
    876                           if(custom_classifier.display(true)) {
    877                                 assignClassifier(custom_classifier);
    878                           }
    879                           custom_classifier.destroy(); // Remove gui prompt or else.
    880                           custom_classifier = null;
    881                      }
    882                 }
    883           }
    884           /** Listens for double clicks apon the list and react as if the configure button was pushed. */
    885           private class ClickListener
    886                 extends MouseAdapter {
     842        public void actionPerformed(ActionEvent event) {
     843        String name = (String)classifier.getSelectedItem();
     844        Classifier target = getClassifier(name);
     845        Classifier classifier = null;
     846        CustomClassifier custom_classifier = null;
     847        if(target != null) {
     848            classifier = target.copy();
     849        }
     850        else {
     851            // Try to retrieve custom classifier for name.
     852            try {
     853            Class custom_class = Class.forName("org.greenstone.gatherer.cdm.custom." + name);
     854            custom_classifier = (CustomClassifier)custom_class.newInstance();
     855            custom_classifier.setGatherer(gatherer);
     856            }
     857            catch (Exception error) {
     858            gatherer.debug(error, "Error in ClassifierManager.AddListener.actionPerformed(): " + error);
     859            }
     860            // And if all else fails create a new classifier.
     861            if(classifier == null && custom_classifier == null) {
     862            classifier = new Classifier(name, "", null);
     863            }
     864        }
     865        if(classifier != null) {
     866            // Automatically chain to configuration. This ensures required arguments are filled out.
     867            ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, classifier);
     868            if(ac.display()) {
     869            assignClassifier(classifier);
     870            }
     871            ac.destroy();
     872            ac = null;
     873        }
     874        // Custom classifier
     875        else {
     876            if(custom_classifier.display(true)) {
     877            assignClassifier(custom_classifier);
     878            }
     879            custom_classifier.destroy(); // Remove gui prompt or else.
     880            custom_classifier = null;
     881        }
     882        }
     883    }
     884    /** Listens for double clicks apon the list and react as if the configure button was pushed. */
     885    private class ClickListener
     886        extends MouseAdapter {
    887887                /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
    888888                 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
    889889                 */
    890                 public void mouseClicked(MouseEvent event) {
    891                      if(event.getClickCount() == 2 ) {
    892                           if(!classifier_list.isSelectionEmpty()) {
    893                                 Object object = classifier_list.getSelectedValue();
    894                                 if(object instanceof Classifier) {
    895                                     ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
    896                                     if(ac.display()) {
    897                                           assigned.refresh();
    898                                     }
    899                                     ac.destroy();
    900                                     ac = null;
    901                                 }
    902                                 else if(object instanceof CustomClassifier) {
    903                                     CustomClassifier cc = (CustomClassifier)object;
    904                                     if(cc.display(true)) {
    905                                           assigned.refresh();
    906                                     }
    907                                     cc.destroy(); // Remove gui prompt or else.
    908                                     cc = null;
    909                                 }
    910                           }
    911                      }
    912                 }
    913           }
    914           /** 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.
     890        public void mouseClicked(MouseEvent event) {
     891        if(event.getClickCount() == 2 ) {
     892            if(!classifier_list.isSelectionEmpty()) {
     893            Object object = classifier_list.getSelectedValue();
     894            if(object instanceof Classifier) {
     895                ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
     896                if(ac.display()) {
     897                assigned.refresh();
     898                }
     899                ac.destroy();
     900                ac = null;
     901            }
     902            else if(object instanceof CustomClassifier) {
     903                CustomClassifier cc = (CustomClassifier)object;
     904                if(cc.display(true)) {
     905                assigned.refresh();
     906                }
     907                cc.destroy(); // Remove gui prompt or else.
     908                cc = null;
     909            }
     910            }
     911        }
     912        }
     913    }
     914    /** 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.
    915915            */
    916           private class ConfigureListener
    917                 implements ActionListener {
     916    private class ConfigureListener
     917        implements ActionListener {
    918918                /** 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.
    919919                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
     
    922922                 * @see org.greenstone.gatherer.cdm.CustomClassifier
    923923                 */
    924                 public void actionPerformed(ActionEvent event) {
    925                      if(!classifier_list.isSelectionEmpty()) {
    926                           Object object = classifier_list.getSelectedValue();
    927                           if(object instanceof Classifier) {
    928                                 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
    929                                 if(ac.display()) {
    930                                     assigned.refresh();
    931                                 }
    932                                 ac.destroy();
    933                                 ac = null;
    934                           }
    935                           else if(object instanceof CustomClassifier) {
    936                                 CustomClassifier cc = (CustomClassifier)object;
    937                                 if(cc.display(true)) {
    938                                     assigned.refresh();
    939                                 }
    940                                 cc.destroy(); // Remove gui prompt or else.
    941                                 cc = null;
    942                           }
    943                      }
    944                 }
    945           }
    946           /** This class listens for actions upon the remove button in the controls, and if detected calls the removeClassifier() method.
     924        public void actionPerformed(ActionEvent event) {
     925        if(!classifier_list.isSelectionEmpty()) {
     926            Object object = classifier_list.getSelectedValue();
     927            if(object instanceof Classifier) {
     928            ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (Classifier)object);
     929            if(ac.display()) {
     930                assigned.refresh();
     931            }
     932            ac.destroy();
     933            ac = null;
     934            }
     935            else if(object instanceof CustomClassifier) {
     936            CustomClassifier cc = (CustomClassifier)object;
     937            if(cc.display(true)) {
     938                assigned.refresh();
     939            }
     940            cc.destroy(); // Remove gui prompt or else.
     941            cc = null;
     942            }
     943        }
     944        }
     945    }
     946    /** This class listens for actions upon the remove button in the controls, and if detected calls the removeClassifier() method.
    947947            */
    948           private class RemoveListener
    949                 implements ActionListener {
     948    private class RemoveListener
     949        implements ActionListener {
    950950                /** 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, so we can remove the selected Classifier.
    951951                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
     
    953953                 * @see org.greenstone.gatherer.cdm.CustomClassifier
    954954                 */
    955                 public void actionPerformed(ActionEvent event) {
    956                      if(!classifier_list.isSelectionEmpty()) {
    957                           Object object = classifier_list.getSelectedValue();
    958                           if(object instanceof Classifier || object instanceof CustomClassifier) {
    959                                 removeClassifier(object);
    960                           }
    961                      }
    962                 }
    963           }
    964     }
     955        public void actionPerformed(ActionEvent event) {
     956        if(!classifier_list.isSelectionEmpty()) {
     957            Object object = classifier_list.getSelectedValue();
     958            if(object instanceof Classifier || object instanceof CustomClassifier) {
     959            removeClassifier(object);
     960            }
     961        }
     962        }
     963    }
     964    }
    965965}
    966966
  • trunk/gli/src/org/greenstone/gatherer/cdm/CollectionDesignManager.java

    r4293 r4366  
    8484// ####################################################################################
    8585public class CollectionDesignManager {
    86     /** Whether this collection is to be made public or not. */
    87     public boolean public_col = false;
    88     /** Whether this collection is a beta version or not. */
    89     public boolean beta = true;
    90     /** A list of classifiers to use at build time. */
    91     public ClassifierManager classifiers = null;
    92     /** A manager of collection level metadata. */
    93     public CollectionMetaManager collectionmetadatum = null;
    94     /** E-mail address of the collection's creator. */
    95     public EmailAddress creator = null;
    96     /** E-mail address of the collection's maintainer. */
    97     public EmailAddress maintainer = null;
    98     /** The collection configuration file. */
    99     public File in_file = null;
    100     /** A list of formating strings to use at build time. */
    101     public FormatManager formats = null;
    102     /** The manager in charge of displaying this manager and the controls for other managers. */
    103     public GUI gui = null;
    104     /** List of indexes to be built, and the default index. */
    105     public IndexManager indexes = null;
    106     /** Contains instructions dealing with the collection language. */
    107     public LanguageManager languages = null;
    108     /** A simple manager for the visual review of metadata sets. */
    109     public MetadataSetManager metadatasets = null;
    110     /** A list of plugins to use at build time. */
    111     public PlugInManager plugins = null;
    112     /** Contains: A list of subcollections, (defined on metadatadata), a list of which subcollection indexes to build and the default subcollection index. */
    113     public SubcollectionManager subcollections = null;
    114     /** A list of whatever commands could not be parsed at all. */
    115     private ArrayList rest = null;
    116     /** A reference to the Gatherer. */
    117     private Gatherer gatherer = null;
    118     /** Constructor.
    119       * @param gatherer The <strong>Gatherer</strong> that created this class.
    120       * @see org.greenstone.gatherer.cdm.ClassifierManager
    121       * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    122       * @see org.greenstone.gatherer.cdm.FormatManager
    123       * @see org.greenstone.gatherer.cdm.IndexManager
    124       * @see org.greenstone.gatherer.cdm.LanguageManager
    125       * @see org.greenstone.gatherer.cdm.MetadataSetManager
    126       * @see org.greenstone.gatherer.cdm.PlugInManager
    127       * @see org.greenstone.gatherer.cdm.SubcollectionManager
    128       */
    129     public CollectionDesignManager() {
    130           this.gatherer = Gatherer.self;
    131           this.classifiers = new ClassifierManager(gatherer, this);
    132           this.collectionmetadatum = new CollectionMetaManager(gatherer, this);
    133           this.formats = new FormatManager(gatherer, this);
    134           this.indexes = new IndexManager(gatherer, this);
    135           this.languages = new LanguageManager(gatherer, this);
    136           this.metadatasets = new MetadataSetManager(gatherer);
    137           this.plugins = new PlugInManager(gatherer, this);
    138           this.rest = new ArrayList();
    139           this.subcollections = new SubcollectionManager(gatherer);
    140     }
    141     /** In order to prevent Components that have registered themselves wasting memory, this method invalidates each of the sub-managers controls, causing them to unregister listeners.
    142       * @see org.greenstone.gatherer.cdm.ClassifierManager
    143       * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    144       * @see org.greenstone.gatherer.cdm.FormatManager
    145       * @see org.greenstone.gatherer.cdm.IndexManager
    146       * @see org.greenstone.gatherer.cdm.LanguageManager
    147       * @see org.greenstone.gatherer.cdm.MetadataSetManager
    148       * @see org.greenstone.gatherer.cdm.PlugInManager
    149       * @see org.greenstone.gatherer.cdm.SubcollectionManager
    150       */
    151     public void destroy() {
    152           // Remove visual the component from its parent.
    153           if(gui.getParent() != null) {
    154                 gui.getParent().remove(gui);
    155           }
    156           // Remove references from persistant listeners.
    157           if(classifiers != null && formats != null && gui != null && indexes != null && languages != null && metadatasets != null && plugins != null && subcollections != null) {
    158                 classifiers.invalidateControls();
    159                 formats.invalidateControls();
    160                 gui.invalidateControls();
    161                 indexes.invalidateControls();
    162                 languages.invalidateControls();
    163                 metadatasets.invalidateControls();
    164                 plugins.invalidateControls();
    165                 subcollections.invalidateControls();
    166           }
    167           // Null globals.
    168           classifiers = null;
    169           collectionmetadatum = null;
    170           creator = null;
    171           maintainer = null;
    172           in_file = null;
    173           formats = null;
    174           gui = null;
    175           indexes = null;
    176           languages = null;
    177           metadatasets = null;
    178           plugins = null;
    179           subcollections = null;
    180           rest = null;
    181           gatherer = null;
    182     }
    183 
    184     /** Display the GUI interface for the CollectionDesignManager in the centre of the indicated panel.
    185       * @param target The <strong>JPanel</strong> you wish to display the GUI on.
    186       * @see org.greenstone.gatherer.cdm.GUI
    187       */
    188     public void display(JPanel target) {
    189          this.gui = new GUI(gatherer, this);
    190          target.add(gui, BorderLayout.CENTER);
    191     }
    192     /** When the tab on the JTabbedPane that contains the GUI is selected, this method is called to ensure that the controls are all up to date, in terms of references to metadata etc.
    193       * @see org.greenstone.gatherer.cdm.GUI
    194       */
    195     public void gainFocus() {
    196           gui.updateUI();
    197     }
    198     /** Retrieve the current set of indexes as defined by the user configuration.
    199       * @return An <strong>ArrayList</strong> of indexes.
    200       * @see org.greenstone.gatherer.cdm.Index
    201       * @see org.greenstone.gatherer.cdm.IndexManager
    202       */
    203     public ArrayList getIndexes() {
    204           ArrayList result = new ArrayList();
    205           int size = indexes.size();
    206           for(int i = 0; i < size; i++) {
    207                 result.add(indexes.getIndex(i));
    208           }
    209           return result;
    210     }
    211     /** Retrieve the name of the collection configuration file which is being used as the source of the information in this object.
    212       * @return The files absolute path as a <strong>String</strong>.
    213       */
    214     public String getFilename() {
    215           return in_file.getAbsolutePath();
    216     }
    217     /** Used to parse the given file as if it was a collection configuration file, passing any parsed commands to the relevant submanager. Currently ignores any comments, and marks any other lines as being unrecognizable if they can't be parsed.
    218       * @param filename The name of the file you wish to attempt to pass as a <strong>String</strong>.
    219       * @see org.greenstone.gatherer.cdm.ClassifierManager
    220       * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    221       * @see org.greenstone.gatherer.cdm.FormatManager
    222       * @see org.greenstone.gatherer.cdm.IndexManager
    223       * @see org.greenstone.gatherer.cdm.LanguageManager
    224       * @see org.greenstone.gatherer.cdm.MetadataSetManager
    225       * @see org.greenstone.gatherer.cdm.PlugInManager
    226       * @see org.greenstone.gatherer.cdm.SubcollectionManager
    227       * @see org.greenstone.gatherer.util.EmailAddress
    228       */
    229     public void parse(String filename) {
    230           try {
    231                 in_file = new File(filename);
    232                 FileReader in_reader = new FileReader(in_file);
    233                 BufferedReader in = new BufferedReader(in_reader);
    234                 String command = null;
    235                 while((command = in.readLine()) != null) {
    236                      if(command.length() > 0) {
    237                           // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
    238                           while(command.trim().endsWith("\\")) {
    239                                 command = command.substring(0, command.lastIndexOf("\\"));
    240                                 String next_line = in.readLine();
    241                                 if(next_line != null) {
    242                                     command = command + next_line;
    243                                 }
    244                           }
    245                           // Now we've finished parsing a command line, see what manager wants a piece of it.
    246                           boolean found = false;
    247                           String command_lc = command.toLowerCase();
    248                           if(command_lc.startsWith("creator")) {
    249                                 creator = new EmailAddress(gatherer, command);
    250                                 found = true;
    251                           }
    252                           if(command_lc.startsWith("maintainer")) {
    253                                 maintainer = new EmailAddress(gatherer, command);
    254                                 found = true;
    255                           }
    256                           if(command_lc.startsWith("public")) {
    257                                 if(command_lc.endsWith("true")) {
    258                                     public_col = true;
    259                                 }
    260                                 else {
    261                                     public_col = false;
    262                                 }
    263                                 found = true;
    264                           }
    265                           if(command_lc.startsWith("beta")) {
    266                                 if(command_lc.endsWith("false")) {
    267                                     beta = false;
    268                                 }
    269                                 else {
    270                                     beta = true;
    271                                 }
    272                                 found = true;
    273                           }
    274                           if(!found) {
    275                                 found = indexes.parse(command);
    276                           }
    277                           if(!found) {
    278                                 found = subcollections.parse(command, false);
    279                           }
    280                           if(!found) {
    281                                 found = languages.parse(command);
    282                           }
    283                           if(!found) {
    284                                 found = plugins.parse(command);
    285                           }
    286                           if(!found) {
    287                                 found = classifiers.parse(command);
    288                           }
    289                           if(!found) {
    290                                 found = formats.parse(command, false);
    291                           }
    292                           if(!found) {
    293                                 found = collectionmetadatum.parse(command, false);
    294                           }
    295                           // Metadataset commands
    296                           if(command_lc.startsWith("metadataset")) {
    297                                 // Nothing yet. Eventually used to import metadata.
    298                                 found = true;
    299                           }
    300                           // Comments we ignore.
    301                           if(command_lc.startsWith("# these instructions are not recognized by the gatherer.")) {
    302                                 // Ignore
    303                                 found = true;
    304                           }
    305                           // We have been unable to parse this command, add it to rest.
    306                           if(!found) {
    307                                 rest.add(command);
    308                           }
    309                      }
    310                 }
    311                 in.close();
     86    /** Whether this collection is to be made public or not. */
     87    public boolean public_col = false;
     88    /** Whether this collection is a beta version or not. */
     89    public boolean beta = true;
     90    /** A list of classifiers to use at build time. */
     91    public ClassifierManager classifiers = null;
     92    /** A manager of collection level metadata. */
     93    public CollectionMetaManager collectionmetadatum = null;
     94    /** E-mail address of the collection's creator. */
     95    public EmailAddress creator = null;
     96    /** E-mail address of the collection's maintainer. */
     97    public EmailAddress maintainer = null;
     98    /** The collection configuration file. */
     99    public File in_file = null;
     100    /** A list of formating strings to use at build time. */
     101    public FormatManager formats = null;
     102    /** The manager in charge of displaying this manager and the controls for other managers. */
     103    public GUI gui = null;
     104    /** List of indexes to be built, and the default index. */
     105    public IndexManager indexes = null;
     106    /** Contains instructions dealing with the collection language. */
     107    public LanguageManager languages = null;
     108    /** A simple manager for the visual review of metadata sets. */
     109    public MetadataSetManager metadatasets = null;
     110    /** A list of plugins to use at build time. */
     111    public PlugInManager plugins = null;
     112    /** Contains: A list of subcollections, (defined on metadatadata), a list of which subcollection indexes to build and the default subcollection index. */
     113    public SubcollectionManager subcollections = null;
     114    /** A list of whatever commands could not be parsed at all. */
     115    private ArrayList rest = null;
     116    /** A reference to the Gatherer. */
     117    private Gatherer gatherer = null;
     118    /** Constructor.
     119     * @param gatherer The <strong>Gatherer</strong> that created this class.
     120     * @see org.greenstone.gatherer.cdm.ClassifierManager
     121     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     122     * @see org.greenstone.gatherer.cdm.FormatManager
     123     * @see org.greenstone.gatherer.cdm.IndexManager
     124     * @see org.greenstone.gatherer.cdm.LanguageManager
     125     * @see org.greenstone.gatherer.cdm.MetadataSetManager
     126     * @see org.greenstone.gatherer.cdm.PlugInManager
     127     * @see org.greenstone.gatherer.cdm.SubcollectionManager
     128     */
     129    public CollectionDesignManager() {
     130    this.gatherer = Gatherer.self;
     131    this.classifiers = new ClassifierManager(gatherer, this);
     132    this.collectionmetadatum = new CollectionMetaManager(gatherer, this);
     133    this.formats = new FormatManager(gatherer, this);
     134    this.indexes = new IndexManager(gatherer, this);
     135    this.languages = new LanguageManager(gatherer, this);
     136    this.metadatasets = new MetadataSetManager(gatherer);
     137    this.plugins = new PlugInManager(gatherer, this);
     138    this.rest = new ArrayList();
     139    this.subcollections = new SubcollectionManager(gatherer);
     140    }
     141    /** In order to prevent Components that have registered themselves wasting memory, this method invalidates each of the sub-managers controls, causing them to unregister listeners.
     142     * @see org.greenstone.gatherer.cdm.ClassifierManager
     143     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     144     * @see org.greenstone.gatherer.cdm.FormatManager
     145     * @see org.greenstone.gatherer.cdm.IndexManager
     146     * @see org.greenstone.gatherer.cdm.LanguageManager
     147     * @see org.greenstone.gatherer.cdm.MetadataSetManager
     148     * @see org.greenstone.gatherer.cdm.PlugInManager
     149     * @see org.greenstone.gatherer.cdm.SubcollectionManager
     150     */
     151    public void destroy() {
     152    // Remove visual the component from its parent.
     153    if(gui.getParent() != null) {
     154        gui.getParent().remove(gui);
     155    }
     156    // Remove references from persistant listeners.
     157    if(classifiers != null && formats != null && gui != null && indexes != null && languages != null && metadatasets != null && plugins != null && subcollections != null) {
     158        classifiers.invalidateControls();
     159        formats.invalidateControls();
     160        gui.invalidateControls();
     161        indexes.invalidateControls();
     162        languages.invalidateControls();
     163        metadatasets.invalidateControls();
     164        plugins.invalidateControls();
     165        subcollections.invalidateControls();
     166    }
     167    // Null globals.
     168    classifiers = null;
     169    collectionmetadatum = null;
     170    creator = null;
     171    maintainer = null;
     172    in_file = null;
     173    formats = null;
     174    gui = null;
     175    indexes = null;
     176    languages = null;
     177    metadatasets = null;
     178    plugins = null;
     179    subcollections = null;
     180    rest = null;
     181    gatherer = null;
     182    }
     183
     184    /** Display the GUI interface for the CollectionDesignManager in the centre of the indicated panel.
     185     * @param target The <strong>JPanel</strong> you wish to display the GUI on.
     186     * @see org.greenstone.gatherer.cdm.GUI
     187     */
     188    public void display(JPanel target) {
     189    this.gui = new GUI(gatherer, this);
     190    target.add(gui, BorderLayout.CENTER);
     191    }
     192    /** When the tab on the JTabbedPane that contains the GUI is selected, this method is called to ensure that the controls are all up to date, in terms of references to metadata etc.
     193     * @see org.greenstone.gatherer.cdm.GUI
     194     */
     195    public void gainFocus() {
     196    gui.updateUI();
     197    }
     198    /** Retrieve the current set of indexes as defined by the user configuration.
     199     * @return An <strong>ArrayList</strong> of indexes.
     200     * @see org.greenstone.gatherer.cdm.Index
     201     * @see org.greenstone.gatherer.cdm.IndexManager
     202     */
     203    public ArrayList getIndexes() {
     204    ArrayList result = new ArrayList();
     205    int size = indexes.size();
     206    for(int i = 0; i < size; i++) {
     207        result.add(indexes.getIndex(i));
     208    }
     209    return result;
     210    }
     211    /** Retrieve the name of the collection configuration file which is being used as the source of the information in this object.
     212     * @return The files absolute path as a <strong>String</strong>.
     213     */
     214    public String getFilename() {
     215    return in_file.getAbsolutePath();
     216    }
     217    /** Used to parse the given file as if it was a collection configuration file, passing any parsed commands to the relevant submanager. Currently ignores any comments, and marks any other lines as being unrecognizable if they can't be parsed.
     218     * @param filename The name of the file you wish to attempt to pass as a <strong>String</strong>.
     219     * @see org.greenstone.gatherer.cdm.ClassifierManager
     220     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     221     * @see org.greenstone.gatherer.cdm.FormatManager
     222     * @see org.greenstone.gatherer.cdm.IndexManager
     223     * @see org.greenstone.gatherer.cdm.LanguageManager
     224     * @see org.greenstone.gatherer.cdm.MetadataSetManager
     225     * @see org.greenstone.gatherer.cdm.PlugInManager
     226     * @see org.greenstone.gatherer.cdm.SubcollectionManager
     227     * @see org.greenstone.gatherer.util.EmailAddress
     228     */
     229    public void parse(String filename) {
     230    try {
     231        in_file = new File(filename);
     232        FileReader in_reader = new FileReader(in_file);
     233        BufferedReader in = new BufferedReader(in_reader);
     234        String command = null;
     235        while((command = in.readLine()) != null) {
     236        if(command.length() > 0) {
     237            // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
     238            while(command.trim().endsWith("\\")) {
     239            command = command.substring(0, command.lastIndexOf("\\"));
     240            String next_line = in.readLine();
     241            if(next_line != null) {
     242                command = command + next_line;
     243            }
     244            }
     245            // Now we've finished parsing a command line, see what manager wants a piece of it.
     246            boolean found = false;
     247            String command_lc = command.toLowerCase();
     248            if(command_lc.startsWith("creator")) {
     249            creator = new EmailAddress(gatherer, command);
     250            found = true;
     251            }
     252            if(command_lc.startsWith("maintainer")) {
     253            maintainer = new EmailAddress(gatherer, command);
     254            found = true;
     255            }
     256            if(command_lc.startsWith("public")) {
     257            if(command_lc.endsWith("true")) {
     258                public_col = true;
     259            }
     260            else {
     261                public_col = false;
     262            }
     263            found = true;
     264            }
     265            if(command_lc.startsWith("beta")) {
     266            if(command_lc.endsWith("false")) {
     267                beta = false;
     268            }
     269            else {
     270                beta = true;
     271            }
     272            found = true;
     273            }
     274            if(!found) {
     275            found = indexes.parse(command);
     276            }
     277            if(!found) {
     278            found = subcollections.parse(command, false);
     279            }
     280            if(!found) {
     281            found = languages.parse(command);
     282            }
     283            if(!found) {
     284            found = plugins.parse(command);
     285            }
     286            if(!found) {
     287            found = classifiers.parse(command);
     288            }
     289            if(!found) {
     290            found = formats.parse(command, false);
     291            }
     292            if(!found) {
     293            found = collectionmetadatum.parse(command, false);
     294            }
     295            // Metadataset commands
     296            if(command_lc.startsWith("metadataset")) {
     297            // Nothing yet. Eventually used to import metadata.
     298            found = true;
     299            }
     300            // Comments we ignore.
     301            if(command_lc.startsWith("# these instructions are not recognized by the gatherer.")) {
     302            // Ignore
     303            found = true;
     304            }
     305            // We have been unable to parse this command, add it to rest.
     306            if(!found) {
     307            rest.add(command);
     308            }
     309        }
     310        }
     311        in.close();
    312312                // Now attempt to finalize any commands that were not immediately parsed as they were waiting for unresolved references.
    313                 subcollections.reparseUnresolved();
    314                 classifiers.reparseUnresolved();
    315                 formats.reparseUnresolved();
    316                 collectionmetadatum.reparseUnresolved();
    317           }
    318           catch(Exception error) {
    319                 error.printStackTrace();
    320           }
    321     }
    322     /** Cause the current definitions within the Collection Design Manager to be written back out to whatever collect.cfg it is based upon, taking care to change reference pointers into something more sensible within the text file.
    323       * @see org.greenstone.gatherer.cdm.ClassifierManager
    324       * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    325       * @see org.greenstone.gatherer.cdm.FormatManager
    326       * @see org.greenstone.gatherer.cdm.IndexManager
    327       * @see org.greenstone.gatherer.cdm.LanguageManager
    328       * @see org.greenstone.gatherer.cdm.MetadataSetManager
    329       * @see org.greenstone.gatherer.cdm.PlugInManager
    330       * @see org.greenstone.gatherer.cdm.SubcollectionManager
    331       * @see org.greenstone.gatherer.util.EmailAddress
    332       */
    333     public void save() {
    334           try {
     313        subcollections.reparseUnresolved();
     314        classifiers.reparseUnresolved();
     315        formats.reparseUnresolved();
     316        collectionmetadatum.reparseUnresolved();
     317    }
     318    catch(Exception error) {
     319        error.printStackTrace();
     320    }
     321    }
     322    /** Cause the current definitions within the Collection Design Manager to be written back out to whatever collect.cfg it is based upon, taking care to change reference pointers into something more sensible within the text file.
     323     * @see org.greenstone.gatherer.cdm.ClassifierManager
     324     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     325     * @see org.greenstone.gatherer.cdm.FormatManager
     326     * @see org.greenstone.gatherer.cdm.IndexManager
     327     * @see org.greenstone.gatherer.cdm.LanguageManager
     328     * @see org.greenstone.gatherer.cdm.MetadataSetManager
     329     * @see org.greenstone.gatherer.cdm.PlugInManager
     330     * @see org.greenstone.gatherer.cdm.SubcollectionManager
     331     * @see org.greenstone.gatherer.util.EmailAddress
     332     */
     333    public void save() {
     334    try {
    335335                // If the file already exists (it should) rename it.
    336                 if(in_file.exists()) {
    337                      String filename = in_file.getAbsolutePath();
    338                      File backup = new File(filename + "~");
    339                      backup.deleteOnExit();
    340                      if(!in_file.renameTo(backup)) {
    341                           gatherer.debug("Error in CollectionDesignManager.parse(): FileRenamedException");
    342                      }
    343                      in_file = new File(filename); // Just in case we moved it.
    344                 }
    345                 FileOutputStream out = new FileOutputStream(in_file);
    346 
    347                 StringBuffer text = new StringBuffer("");
    348                 if(creator != null) {
    349                      text.append(creator.toString());
    350                      text.append("\n");
    351                 }
    352                 if(maintainer != null) {
    353                      text.append(maintainer.toString());
    354                      text.append("\n");
    355                 }
    356                 if(public_col) {
    357                      text.append("public true\n");
    358                 }
    359                 else {
    360                      text.append("public false\n");
    361                 }
    362                 if(beta) {
    363                      text.append("beta true\n");
    364                 }
    365                 else {
    366                      text.append("beta false\n");
    367                 }
    368                 if(text.length() > 0) {
    369                      text.append("\n");
    370                 }
    371                 if(indexes.size() > 0) {
    372                      text.append(indexes.toString());
    373                 }
    374                 if(subcollections.size() > 0) {
    375                      text.append(subcollections.toString());
    376                 }
    377                 if(languages.size() > 0) {
    378                      text.append(languages.toString());
    379                 }
    380                 if(plugins.size() > 0) {
    381                      text.append(plugins.toString());
    382                 }
    383                 if(classifiers.size() > 0) {
    384                      text.append(classifiers.toString());
    385                 }
    386                 if(formats.size() > 0) {
    387                      text.append(formats.toString());
    388                 }
    389                 if(collectionmetadatum.size() > 0) {
    390                      text.append(collectionmetadatum.toString());
    391                 }
    392                 text.append(metadatasets.toString());
    393                 if(rest.size() > 0) {
    394                      // Write out rest at the bottom.
    395                      text.append("# These instructions are not recognized by the Gatherer.\n");
    396                      for(int i = 0; i < rest.size(); i++) {
    397                           text.append(rest.get(i));
    398                           text.append("\n");
    399                      }
    400                 }
    401                 out.write(text.toString().getBytes());
    402                 out.close();
    403                 out = null;
    404           }
    405           catch(Exception error) {
    406                 error.printStackTrace();
    407           }
    408     }
    409     /** Method used during a global search and replace to highlight the appropriate record within the Collection Design Managers version of the Metadata Set Manager (view only).
    410       * @param element The name of the desired element as a <strong>String</strong>.
    411       * @see org.greenstone.gatherer.cdm.GUI
    412       * @see org.greenstone.gatherer.cdm.MetadataSetManager
    413       */
    414     public Rectangle setSelectedElement(String element) {
    415           // First ensure that the metadata set controls are visible.
    416           gui.setSelectedView("CDM.GUI.MetadataSets");
    417           // Then tell them to select the given element.
    418           return metadatasets.setSelectedElement(element);
    419     }
     336        if(in_file.exists()) {
     337        String filename = in_file.getAbsolutePath();
     338        File backup = new File(filename + "~");
     339        backup.deleteOnExit();
     340        if(!in_file.renameTo(backup)) {
     341            gatherer.debug("Error in CollectionDesignManager.parse(): FileRenamedException");
     342        }
     343        in_file = new File(filename); // Just in case we moved it.
     344        }
     345        FileOutputStream out = new FileOutputStream(in_file);
     346
     347        StringBuffer text = new StringBuffer("");
     348        if(creator != null) {
     349        text.append(creator.toString());
     350        text.append("\n");
     351        }
     352        if(maintainer != null) {
     353        text.append(maintainer.toString());
     354        text.append("\n");
     355        }
     356        if(public_col) {
     357        text.append("public true\n");
     358        }
     359        else {
     360        text.append("public false\n");
     361        }
     362        if(beta) {
     363        text.append("beta true\n");
     364        }
     365        else {
     366        text.append("beta false\n");
     367        }
     368        if(text.length() > 0) {
     369        text.append("\n");
     370        }
     371        if(indexes.size() > 0) {
     372        text.append(indexes.toString());
     373        }
     374        if(subcollections.size() > 0) {
     375        text.append(subcollections.toString());
     376        }
     377        if(languages.size() > 0) {
     378        text.append(languages.toString());
     379        }
     380        if(plugins.size() > 0) {
     381        text.append(plugins.toString());
     382        }
     383        if(classifiers.size() > 0) {
     384        text.append(classifiers.toString());
     385        }
     386        if(formats.size() > 0) {
     387        text.append(formats.toString());
     388        }
     389        if(collectionmetadatum.size() > 0) {
     390        text.append(collectionmetadatum.toString());
     391        }
     392        text.append(metadatasets.toString());
     393        if(rest.size() > 0) {
     394        // Write out rest at the bottom.
     395        text.append("# These instructions are not recognized by the Gatherer.\n");
     396        for(int i = 0; i < rest.size(); i++) {
     397            text.append(rest.get(i));
     398            text.append("\n");
     399        }
     400        }
     401        out.write(text.toString().getBytes());
     402        out.close();
     403        out = null;
     404    }
     405    catch(Exception error) {
     406        error.printStackTrace();
     407    }
     408    }
     409    /** Method used during a global search and replace to highlight the appropriate record within the Collection Design Managers version of the Metadata Set Manager (view only).
     410     * @param element The name of the desired element as a <strong>String</strong>.
     411     * @see org.greenstone.gatherer.cdm.GUI
     412     * @see org.greenstone.gatherer.cdm.MetadataSetManager
     413     */
     414    public Rectangle setSelectedElement(String element) {
     415    // First ensure that the metadata set controls are visible.
     416    gui.setSelectedView("CDM.GUI.MetadataSets");
     417    // Then tell them to select the given element.
     418    return metadatasets.setSelectedElement(element);
     419    }
    420420}
  • trunk/gli/src/org/greenstone/gatherer/cdm/CollectionMeta.java

    r4293 r4366  
    5959 */
    6060public class CollectionMeta
    61     implements Comparable {
    62     /** A reference to the collection design manager for access to the language manager. */
    63     private CollectionDesignManager manager = null;
    64     /** The language of this metadata. Should be a two letter code. */
    65     private Language language = null;
    66     /** The name of the thing this metadata is assigned to, which may index an Index. */
    67     private Object name = null;
    68     /** The value of this metadata. */
    69     private String value = null;
    70     /** Constructor.
    71       * @param name The object the metadata is assigned to as an <strong>Object</strong>.
    72       * @param language The language of the metadata as a <strong>Language</strong>. Should be a two letter code.
    73       * @param value The value of this metadata, as a <strong>String</strong>.
     61    implements Comparable {
     62    /** A reference to the collection design manager for access to the language manager. */
     63    private CollectionDesignManager manager = null;
     64    /** The language of this metadata. Should be a two letter code. */
     65    private Language language = null;
     66    /** The name of the thing this metadata is assigned to, which may index an Index. */
     67    private Object name = null;
     68    /** The value of this metadata. */
     69    private String value = null;
     70    /** Constructor.
     71     * @param name The object the metadata is assigned to as an <strong>Object</strong>.
     72     * @param language The language of the metadata as a <strong>Language</strong>. Should be a two letter code.
     73     * @param value The value of this metadata, as a <strong>String</strong>.
    7474      */
    75     public CollectionMeta(CollectionDesignManager manager, Object name, Language language, String value) {
    76           this.language = language;
    77           this.manager = manager;
    78           this.name = name;
    79           this.value = value;
    80     }
    81     /** Method to compare two collection metadata objects to calculate their respective ordering.
     75    public CollectionMeta(CollectionDesignManager manager, Object name, Language language, String value) {
     76    this.language = language;
     77    this.manager = manager;
     78    this.name = name;
     79    this.value = value;
     80    }
     81    /** Method to compare two collection metadata objects to calculate their respective ordering.
    8282      * @param object The other metadata to compare to, as an <strong>Object</strong>.
    8383      * @return An <i>int</i> which is less than 0 if this object proceeds the given object, 0 if they are equal and greater than 0 otherwise.
    8484      * @see org.greenstone.gatherer.cdm.Language
    8585      */
    86     public int compareTo(Object object) {
    87           if(object instanceof CollectionMeta) {
    88                 CollectionMeta metadata = (CollectionMeta) object;
    89                 int result = name.toString().compareTo(metadata.getName().toString());
    90                 if(result == 0) {
    91                      Language other_language = metadata.getLanguage();
    92                      if(language != null && other_language != null) {
    93                           result = language.compareTo(metadata.getLanguage());
    94                           if(result == 0) {
    95                                 return value.compareTo(metadata.getValue());
    96                           }
    97                      }
    98                      else if(language != null) {
    99                           return -1;
    100                      }
    101                      else if(other_language != null) {
    102                           return 1;
    103                      }
    104                 }
    105                 return result;
    106           }
    107           return toString().compareTo(object.toString());
    108     }
    109     /** Method to compare two collection metadata objects for equality.
     86    public int compareTo(Object object) {
     87    if(object instanceof CollectionMeta) {
     88        CollectionMeta metadata = (CollectionMeta) object;
     89        int result = name.toString().compareTo(metadata.getName().toString());
     90        if(result == 0) {
     91        Language other_language = metadata.getLanguage();
     92        if(language != null && other_language != null) {
     93            result = language.compareTo(metadata.getLanguage());
     94            if(result == 0) {
     95            return value.compareTo(metadata.getValue());
     96            }
     97        }
     98        else if(language != null) {
     99            return -1;
     100        }
     101        else if(other_language != null) {
     102            return 1;
     103        }
     104        }
     105        return result;
     106    }
     107    return toString().compareTo(object.toString());
     108    }
     109    /** Method to compare two collection metadata objects for equality.
    110110      * @param object The other metadata to compare to, as an <strong>Object</strong>.
    111111      * @return A <i>boolean</i> value of <i>true</i> if the object are equal, <i>false</i> otherwise.
    112112      */
    113     public boolean equals(Object object) {
    114           if(compareTo(object) == 0) {
    115                 return true;
    116           }
    117           return false;
    118     }
    119     /** Method to retrieve the value of language.
     113    public boolean equals(Object object) {
     114    if(compareTo(object) == 0) {
     115        return true;
     116    }
     117    return false;
     118    }
     119    /** Method to retrieve the value of language.
    120120      * @return The value of language as a <strong>Language</strong>.
    121121      */
    122     public Language getLanguage() {
    123           return language;
    124     }
    125     /** Method to retrieve the value of name.
     122    public Language getLanguage() {
     123    return language;
     124    }
     125    /** Method to retrieve the value of name.
    126126      * @return The value of name as an <strong>Object</strong>.
    127127      */
    128     public Object getName() {
    129           return name;
    130     }
    131     /** Method to retrieve the value of value (well great choice of name there).
     128    public Object getName() {
     129    return name;
     130    }
     131    /** Method to retrieve the value of value (well great choice of name there).
    132132      * @return The value of value as a <strong>String</strong>.
    133133      */
    134     public String getValue() {
    135           return value;
    136     }
    137     /** Method to print out this class as it would appear within the collection configuration file.
     134    public String getValue() {
     135    return value;
     136    }
     137    /** Method to print out this class as it would appear within the collection configuration file.
    138138      * @return A <strong>String</strong> containing the text value of this class.
    139139      */
    140     public String toString() {
    141           String text = "collectionmeta ";
    142           if(name instanceof Index) {
    143                 text = text + ".";
    144                 Index index = (Index)name;
    145                 text = text + index.toString(false) + " ";
    146           }
    147           else {
    148                 text = text + name.toString() + " ";
    149           }
    150           if(language != null && manager.languages.size() > 0 && !manager.languages.isDefaultLanguage(language)) {
    151                 text = text + "[l=" + language.getCode() + "] ";
    152           }
    153           text = text + "\"" + Utility.encodeGreenstone(value) + "\"\n";
    154           return text;
    155     }
    156     /** Used to update the contents of this collection level metadata to the given 'new' values.
     140    public String toString() {
     141    String text = "collectionmeta ";
     142    if(name instanceof Index) {
     143        text = text + ".";
     144        Index index = (Index)name;
     145        text = text + index.toString(false) + " ";
     146    }
     147    else {
     148        text = text + name.toString() + " ";
     149    }
     150    if(language != null && manager.languages.size() > 0 && !manager.languages.isDefaultLanguage(language)) {
     151        text = text + "[l=" + language.getCode() + "] ";
     152    }
     153    text = text + "\"" + Utility.encodeGreenstone(value) + "\"\n";
     154    return text;
     155    }
     156    /** Used to update the contents of this collection level metadata to the given 'new' values.
    157157      * @param name The new name of the metadata, as a <strong>Object</strong>.
    158158      * @param language The new <strong>Language</strong> of the metadata.
    159159      * @param value And the value the metadata is assigned, as a <strong>String</strong>.
    160160      */
    161     public void update(Object name, Language language, String value) {
    162           this.name = name;
    163           this.language = language;
    164           this.value = value;
    165     }
    166     /** Ensure this is a valid metadata entry by checking that the value is non-null and non-zero length (after having removed whitespace).
     161    public void update(Object name, Language language, String value) {
     162    this.name = name;
     163    this.language = language;
     164    this.value = value;
     165    }
     166    /** Ensure this is a valid metadata entry by checking that the value is non-null and non-zero length (after having removed whitespace).
    167167      * @return <i>true</i> if this metadata has a valid value and should be added to the config, <i>false</i> otherwise.
    168168      */
    169     public boolean valid() {
    170           return(value != null && value.trim().length() > 0);
    171     }
     169    public boolean valid() {
     170    return(value != null && value.trim().length() > 0);
     171    }
    172172}
    173173
  • trunk/gli/src/org/greenstone/gatherer/cdm/CollectionMetaManager.java

    r4293 r4366  
    9595// ####################################################################################
    9696public class CollectionMetaManager
    97     extends DefaultListModel {
    98     /** A reference to the cdm manager so we can access indexes and languages. */
    99     private CollectionDesignManager manager = null;
    100     /** A reference to ourself so that inner classes can use us as a model. */
    101     private DefaultListModel model = null;
    102     /** A reference to the Gatherer. */
    103     private Gatherer gatherer = null;
    104     /** The language the most recent metadata returned was in. */
    105     private Language current_language = null;
    106     /** We can't safely parse metadata commands until after all the other commands have been parsed, so we store commands here for now. */
    107     private ArrayList unresolved_commands = null;
    108     /** Constructor.
    109       * @param gatherer A reference to the <strong>Gatherer</strong>.
    110       * @param manager A reference to the <strong>CollectionDesignManager</strong> for access to other configuration managers.
    111       */
    112     public CollectionMetaManager(Gatherer gatherer, CollectionDesignManager manager) {
    113           super();
    114           this.gatherer = gatherer;
    115           this.manager = manager;
    116           this.model = this;
    117           this.unresolved_commands = new ArrayList();
    118     }
    119     /** Method to add a new piece of metadata.
     97    extends DefaultListModel {
     98    /** A reference to the cdm manager so we can access indexes and languages. */
     99    private CollectionDesignManager manager = null;
     100    /** A reference to ourself so that inner classes can use us as a model. */
     101    private DefaultListModel model = null;
     102    /** A reference to the Gatherer. */
     103    private Gatherer gatherer = null;
     104    /** The language the most recent metadata returned was in. */
     105    private Language current_language = null;
     106    /** We can't safely parse metadata commands until after all the other commands have been parsed, so we store commands here for now. */
     107    private ArrayList unresolved_commands = null;
     108    /** Constructor.
     109     * @param gatherer A reference to the <strong>Gatherer</strong>.
     110     * @param manager A reference to the <strong>CollectionDesignManager</strong> for access to other configuration managers.
     111     */
     112    public CollectionMetaManager(Gatherer gatherer, CollectionDesignManager manager) {
     113    super();
     114    this.gatherer = gatherer;
     115    this.manager = manager;
     116    this.model = this;
     117    this.unresolved_commands = new ArrayList();
     118    }
     119    /** Method to add a new piece of metadata.
    120120      * @param metadata The new <strong>CollectionMeta</strong>.
    121121      */
    122     public void addMetadata(CollectionMeta metadata) {
    123           CollectionMeta existing = getMetadata(metadata.getName().toString(), metadata.getLanguage(), false);
    124           if(existing != null) {
    125                 removeElement(existing);
    126           }
    127           addElement(metadata);
    128           gatherer.c_man.configurationChanged();
    129     }
    130     /** Retrieve the collectionextra metadata in the default language, if present.
     122    public void addMetadata(CollectionMeta metadata) {
     123    CollectionMeta existing = getMetadata(metadata.getName().toString(), metadata.getLanguage(), false);
     124    if(existing != null) {
     125        removeElement(existing);
     126    }
     127    addElement(metadata);
     128    gatherer.c_man.configurationChanged();
     129    }
     130    /** Retrieve the collectionextra metadata in the default language, if present.
    131131      * @return A <strong>CollectionMeta</strong> containing the collectionextra in the default language if present, or else the first collectionextra of any language, otherwise <i>null</i>.
    132132      * @see org.greenstone.gatherer.cdm.Language
    133133      */
    134     public CollectionMeta getCollectionExtra() {
    135           CollectionMeta result = getMetadata("collectionextra", manager.languages.getDefaultLanguage(), true);
    136           if(result == null) {
    137                 result = new CollectionMeta(manager, "collectionextra", manager.languages.getDefaultLanguage(), "");
    138                 addMetadata(result);
    139           }
    140           return result;
    141     }
    142     /** Retrieve the collectionname metadata in the default language, if present.
     134    public CollectionMeta getCollectionExtra() {
     135    CollectionMeta result = getMetadata("collectionextra", manager.languages.getDefaultLanguage(), true);
     136    if(result == null) {
     137        result = new CollectionMeta(manager, "collectionextra", manager.languages.getDefaultLanguage(), "");
     138        addMetadata(result);
     139    }
     140    return result;
     141    }
     142    /** Retrieve the collectionname metadata in the default language, if present.
    143143      * @return A <strong>CollectionMeta</strong> containing the collectionname in the default language if present, or else the first collectionname of any language, otherwise <i>null</i>.
    144144      * @see org.greenstone.gatherer.cdm.Language
    145145      */
    146     public CollectionMeta getCollectionName() {
    147           return getMetadata("collectionname", manager.languages.getDefaultLanguage(), true);
    148     }
    149     /** Retrieve the iconcollection metadata in the default language, if present.
     146    public CollectionMeta getCollectionName() {
     147    return getMetadata("collectionname", manager.languages.getDefaultLanguage(), true);
     148    }
     149    /** Retrieve the iconcollection metadata in the default language, if present.
    150150      * @return A <strong>CollectionMeta</strong> containing the iconcollection in the default language if present, or else the first iconcollection of any language, otherwise <i>null</i>.
    151151      * @see org.greenstone.gatherer.cdm.Language
    152152      */
    153     public CollectionMeta getIconCollection() {
    154           CollectionMeta result = getMetadata("iconcollection", manager.languages.getDefaultLanguage(), true);
    155           if(result == null) {
    156                 result = new CollectionMeta(manager, "iconcollection", manager.languages.getDefaultLanguage(), "");
    157                 addMetadata(result);
    158           }
    159           return result;
    160     }
    161     /** Method to retrieve the list of metadata.
     153    public CollectionMeta getIconCollection() {
     154    CollectionMeta result = getMetadata("iconcollection", manager.languages.getDefaultLanguage(), true);
     155    if(result == null) {
     156        result = new CollectionMeta(manager, "iconcollection", manager.languages.getDefaultLanguage(), "");
     157        addMetadata(result);
     158    }
     159    return result;
     160    }
     161    /** Method to retrieve the list of metadata.
    162162      * @return An <strong>ArrayList</strong> containing the metadata.
    163163      */
    164     public ArrayList getMetadata() {
    165             ArrayList metadata = new ArrayList();
    166             for(int i = 0; i < size(); i++) {
    167                 metadata.add(get(i));
    168             }
    169           Collections.sort(metadata);
    170           return metadata;
    171     }
     164    public ArrayList getMetadata() {
     165    ArrayList metadata = new ArrayList();
     166    for(int i = 0; i < size(); i++) {
     167        metadata.add(get(i));
     168    }
     169    Collections.sort(metadata);
     170    return metadata;
     171    }
    172172     
    173     /** Retrieve all of the metadata for the given feature, regardless of language. */
    174     public ArrayList getMetadata(String name) {
    175           ArrayList result = new ArrayList();
    176           for(int i = 0; i < size(); i++) {
    177                 CollectionMeta metadata = (CollectionMeta) get(i);
    178                 if(metadata.getName().equals(name)) {
    179                      result.add(metadata);
    180                 }
    181           }
    182           return result;
    183     }
    184     /** Method to retrieve a certain piece of metadata based on its name and language.
     173    /** Retrieve all of the metadata for the given feature, regardless of language. */
     174    public ArrayList getMetadata(String name) {
     175    ArrayList result = new ArrayList();
     176    for(int i = 0; i < size(); i++) {
     177        CollectionMeta metadata = (CollectionMeta) get(i);
     178        if(metadata.getName().equals(name)) {
     179        result.add(metadata);
     180        }
     181    }
     182    return result;
     183    }
     184    /** Method to retrieve a certain piece of metadata based on its name and language.
    185185      * @param name The name of the metadata as a <strong>String</strong>.
    186186      * @param language The <strong>Language</strong> of the metadata.
     
    188188      * @return The <strong>CollectionMeta</strong> requested, or <i>null</i> if no such metadata.
    189189      */
    190     public CollectionMeta getMetadata(String name, Language language, boolean partial) {
    191           CollectionMeta partial_match = null;
    192           for(int i = 0; i < size(); i++) {
    193                 CollectionMeta metadata = (CollectionMeta) get(i);
    194                 if(metadata.getName().equals(name)) {
    195                      if (metadata.getLanguage().equals(language)) {
    196                           return metadata;
    197                      }
    198                      partial_match = metadata;
    199                 }
    200           }
    201           if(partial) {
    202                 return partial_match;
    203           }
    204           return null;
    205     }
    206     /** Method that attempts to parse a collection metadata command from the given text. If a command is parsed successfully it is immediately added to the the collections metadata.
     190    public CollectionMeta getMetadata(String name, Language language, boolean partial) {
     191    CollectionMeta partial_match = null;
     192    for(int i = 0; i < size(); i++) {
     193        CollectionMeta metadata = (CollectionMeta) get(i);
     194        if(metadata.getName().equals(name)) {
     195        if (metadata.getLanguage().equals(language)) {
     196            return metadata;
     197        }
     198        partial_match = metadata;
     199        }
     200    }
     201    if(partial) {
     202        return partial_match;
     203    }
     204    return null;
     205    }
     206    /** Method that attempts to parse a collection metadata command from the given text. If a command is parsed successfully it is immediately added to the the collections metadata.
    207207     * @param command The command text we wish to parse, as a <strong>String</strong>.
    208208     * @return A <i>boolean</i> which is <i>true</i> if a collection metadata command was successfully parsed, <i>false</i> otherwise.
     
    213213     * @see org.greenstone.gatherer.util.Utility
    214214     */
    215     public boolean parse(String command, boolean finished) {
    216          String temp = command.toLowerCase();
    217          if(temp.startsWith("collectionmeta")) {
    218               if(finished) {
    219                     CommandTokenizer ct = new CommandTokenizer(command);
    220                     if(ct.countTokens() >= 3) {
    221                         ct.nextToken(); // Throw away collectionmeta
    222                         Object key = ct.nextToken();
    223                         Language language = null;
    224                         String language_code = null;
    225                         String value = ct.nextToken();
    226                         // Arg. Remember a language token will be '[l=<code>]'
    227                         if(value.startsWith("[") && value.endsWith("]")) {
    228                               language_code = value.substring(3, value.length() - 1);
    229                               ///ystem.err.println("Language code = " + language_code);
    230                               value = ct.nextToken();
    231                         }
    232                         // Check if the key is an index, an if so retrieve it.
    233                         if(((String)key).startsWith(".")) {
    234                               String key_str = (String)key;
    235                               key_str = key_str.substring(1);
    236                               key = manager.indexes.getIndex(key_str);
    237                         }
    238                         // An if we have a language code, retrieve its object too.
    239                         if(language_code != null) {
    240                               language = manager.languages.getLanguage(language_code, false);
    241                         }
    242                         // Otherwise set language to the default language.
    243                         else {
    244                               language = manager.languages.getDefaultLanguage();
    245                         }
    246                         if(key != null) {
    247                               // Trim any "
    248                               if(value.equals("\"\"")) {
    249                                     value = "";
    250                               }
    251                               else {
    252                                     if(value.startsWith("\"")) {
    253                                          value = value.substring(1);
    254                                     }
    255                                     if(value.endsWith("\"")) {
    256                                          value = value.substring(0, value.length() - 1);
    257                                     }
    258                               }
    259                               CollectionMeta meta = new CollectionMeta(manager, key, language, Utility.decodeGreenstone(value));
    260                               addMetadata(meta);
    261                         }
    262                         return true;
    263                     }
    264               }
    265               else {
    266                     unresolved_commands.add(command);
    267                     return true;
    268               }
    269          }
    270          return false;
    271     }
    272     /** Ensure that the values being showed are the most up to date. */
    273     public void refresh() {
    274           fireContentsChanged(this, 0, size());
    275     }
    276 
    277     /** Method to remove a piece of metadata.
     215    public boolean parse(String command, boolean finished) {
     216    String temp = command.toLowerCase();
     217    if(temp.startsWith("collectionmeta")) {
     218        if(finished) {
     219        CommandTokenizer ct = new CommandTokenizer(command);
     220        if(ct.countTokens() >= 3) {
     221            ct.nextToken(); // Throw away collectionmeta
     222            Object key = ct.nextToken();
     223            Language language = null;
     224            String language_code = null;
     225            String value = ct.nextToken();
     226            // Arg. Remember a language token will be '[l=<code>]'
     227            if(value.startsWith("[") && value.endsWith("]")) {
     228            language_code = value.substring(3, value.length() - 1);
     229            ///ystem.err.println("Language code = " + language_code);
     230            value = ct.nextToken();
     231            }
     232            // Check if the key is an index, an if so retrieve it.
     233            if(((String)key).startsWith(".")) {
     234            String key_str = (String)key;
     235            key_str = key_str.substring(1);
     236            key = manager.indexes.getIndex(key_str);
     237            }
     238            // An if we have a language code, retrieve its object too.
     239            if(language_code != null) {
     240            language = manager.languages.getLanguage(language_code, false);
     241            }
     242            // Otherwise set language to the default language.
     243            else {
     244            language = manager.languages.getDefaultLanguage();
     245            }
     246            if(key != null) {
     247            // Trim any "
     248            if(value.equals("\"\"")) {
     249                value = "";
     250            }
     251            else {
     252                if(value.startsWith("\"")) {
     253                value = value.substring(1);
     254                }
     255                if(value.endsWith("\"")) {
     256                value = value.substring(0, value.length() - 1);
     257                }
     258            }
     259            CollectionMeta meta = new CollectionMeta(manager, key, language, Utility.decodeGreenstone(value));
     260            addMetadata(meta);
     261            }
     262            return true;
     263        }
     264        }
     265        else {
     266        unresolved_commands.add(command);
     267        return true;
     268        }
     269    }
     270    return false;
     271    }
     272    /** Ensure that the values being showed are the most up to date. */
     273    public void refresh() {
     274    fireContentsChanged(this, 0, size());
     275    }
     276
     277    /** Method to remove a piece of metadata.
    278278      * @param metadata The <strong>CollectionMeta</strong> you wish to remove.
    279279      */
    280     public void removeMetadata(CollectionMeta metadata) {
    281           removeElement(metadata);
    282           gatherer.c_man.configurationChanged();
    283     }
    284     /** Method which attempts to reparse obvious metadata commands which used unresovable references.
    285       */
    286     public void reparseUnresolved() {
    287           for(int i = 0; i < unresolved_commands.size(); i++) {
    288                 parse((String)unresolved_commands.get(i), true);
    289           }
    290           // Regardless of if they work, clear the commands.
    291           unresolved_commands.clear();
    292     }
    293     /** Sets the value of a certain metadata.
     280    public void removeMetadata(CollectionMeta metadata) {
     281    removeElement(metadata);
     282    gatherer.c_man.configurationChanged();
     283    }
     284    /** Method which attempts to reparse obvious metadata commands which used unresovable references.
     285      */
     286    public void reparseUnresolved() {
     287    for(int i = 0; i < unresolved_commands.size(); i++) {
     288        parse((String)unresolved_commands.get(i), true);
     289    }
     290    // Regardless of if they work, clear the commands.
     291    unresolved_commands.clear();
     292    }
     293    /** Sets the value of a certain metadata.
    294294      * @param name The name of the metadata as a <strong>String</strong>.
    295295      * @param language The <strong>Language</strong> to use.
    296296      * @param value The value of the metadata also as a <strong>String</strong>.
    297297      */
    298     public void setMetadata(String name, Language language, String value) {
    299           addMetadata(new CollectionMeta(manager, name, language, value));
    300     }
    301     /** Method to produce the list of metadata in a string such as you would find in the collection configuration file.
     298    public void setMetadata(String name, Language language, String value) {
     299    addMetadata(new CollectionMeta(manager, name, language, value));
     300    }
     301    /** Method to produce the list of metadata in a string such as you would find in the collection configuration file.
    302302      * @return A <strong>String</strong> containing the list of collection metadata.
    303303      */
    304     public String toString() {
    305           StringBuffer text = new StringBuffer("");
    306           for(int i = 0; i < size(); i++) {
    307                 CollectionMeta data = (CollectionMeta) get(i);
    308                 if(data.valid()) {
    309                      text.append(data.toString());
    310                 }
    311           }
    312           text.append("\n");
    313           return text.toString();
    314     }
    315     /** Overloaded to call get with both a key and an empty argument array.
     304    public String toString() {
     305    StringBuffer text = new StringBuffer("");
     306    for(int i = 0; i < size(); i++) {
     307        CollectionMeta data = (CollectionMeta) get(i);
     308        if(data.valid()) {
     309        text.append(data.toString());
     310        }
     311    }
     312    text.append("\n");
     313    return text.toString();
     314    }
     315    /** Overloaded to call get with both a key and an empty argument array.
    316316      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    317317      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
    318318      */
    319     private String get(String key) {
    320           return get(key, null);
    321     }
    322     /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
     319    private String get(String key) {
     320    return get(key, null);
     321    }
     322    /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
    323323      * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
    324324      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     
    328328      * @see org.greenstone.gatherer.Dictionary
    329329      */
    330     private String get(String key, String args[]) {
    331           if(key.indexOf('.') == -1) {
    332                 key = "CDM.CollectionMetaManager." + key;
    333           }
    334           return gatherer.dictionary.get(key, args);
    335     }
     330    private String get(String key, String args[]) {
     331    if(key.indexOf('.') == -1) {
     332        key = "CDM.CollectionMetaManager." + key;
     333    }
     334    return gatherer.dictionary.get(key, args);
     335    }
    336336}
  • trunk/gli/src/org/greenstone/gatherer/cdm/CommandTokenizer.java

    r4293 r4366  
    5656 */
    5757public class CommandTokenizer
    58     extends StringTokenizer {
     58    extends StringTokenizer {
    5959
    60     private int last_type = -1;
     60    private int last_type = -1;
    6161
    62     static final public int BRACKET_ENCLOSED      = 0;
    63     static final public int DOUBLE_QUOTE_ENCLOSED = 1;
    64     static final public int NORMAL                = 2;
    65     static final public int QUOTE_ENCLOSED        = 3;
     62    static final public int BRACKET_ENCLOSED      = 0;
     63    static final public int DOUBLE_QUOTE_ENCLOSED = 1;
     64    static final public int NORMAL                = 2;
     65    static final public int QUOTE_ENCLOSED        = 3;
    6666
    67     /** Constructor.
    68       * @param command The command <strong>String</strong> you wish to tokenize.
    69       */
    70     public CommandTokenizer(String command) {
    71           super(command);
    72     }
     67    /** Constructor.
     68     * @param command The command <strong>String</strong> you wish to tokenize.
     69     */
     70    public CommandTokenizer(String command) {
     71    super(command);
     72    }
    7373
    74     public int getLastType() {
    75           return last_type;
    76     }
     74    public int getLastType() {
     75    return last_type;
     76    }
    7777
    78     public boolean isComment() {
    79           return (last_type == DOUBLE_QUOTE_ENCLOSED || last_type == QUOTE_ENCLOSED);
    80     }
     78    public boolean isComment() {
     79    return (last_type == DOUBLE_QUOTE_ENCLOSED || last_type == QUOTE_ENCLOSED);
     80    }
    8181
    82     /** Method to retrieve the next token from the command, taking care to group tokens enclosed in speech marks.
    83       * @return A <strong>String</strong> containing the next token from the command.
    84       */
    85     public String nextToken() {
    86           String result = null;
    87           if(hasMoreTokens()) {
    88                 StringBuffer buffer = new StringBuffer(super.nextToken());
    89                 switch(buffer.charAt(0)) {
    90                 case '\"':
    91                      while((buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != '\"') && hasMoreTokens()) {
    92                           buffer.append(" ");
    93                           buffer.append(super.nextToken());
    94                           ///ystem.err.println("Current Buffer = '" + buffer.toString() + "'");
    95                      }
    96                      ///ystem.err.println("Final Buffer = '" + buffer.toString() + "'");
    97                      last_type = DOUBLE_QUOTE_ENCLOSED;
    98                      break;
    99                 case '\'':
    100                      while((buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != '\'') && hasMoreTokens()) {
    101                           buffer.append(" ");
    102                           buffer.append(super.nextToken());
    103                      }
    104                      last_type = QUOTE_ENCLOSED;
    105                      break;
    106                 case '[':
    107                      while((buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != ']') && hasMoreTokens()) {
    108                           buffer.append(" ");
    109                           buffer.append(super.nextToken());
    110                      }
    111                      last_type = BRACKET_ENCLOSED;
    112                      break;
    113                 default:
    114                      last_type = NORMAL;
    115                 }
    116                 result = buffer.toString();
    117           }
    118           return result;
    119     }
    120     /** Unfortunately the StringBuffer doesn't have a built in endsWith method, so I'll just have to implement my own.
    121       * @param str The <strong>StringBuffer</strong> we are checking the end of.
    122       * @param target The <strong>String</strong> fragment we are searching for.
    123       * @return <i>true</i> if str ends with target, <i>false</i> otherwise.
    124       */
    125     private boolean endsWith(StringBuffer str, String target) {
    126           String temp = str.toString();
    127           if(temp.endsWith(target) != (str.lastIndexOf(target) == str.length() - target.length())) {
     82    /** Method to retrieve the next token from the command, taking care to group tokens enclosed in speech marks.
     83     * @return A <strong>String</strong> containing the next token from the command.
     84     */
     85    public String nextToken() {
     86    String result = null;
     87    if(hasMoreTokens()) {
     88        StringBuffer buffer = new StringBuffer(super.nextToken());
     89        switch(buffer.charAt(0)) {
     90        case '\"':
     91        while((buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != '\"') && hasMoreTokens()) {
     92            buffer.append(" ");
     93            buffer.append(super.nextToken());
     94            ///ystem.err.println("Current Buffer = '" + buffer.toString() + "'");
     95        }
     96        ///ystem.err.println("Final Buffer = '" + buffer.toString() + "'");
     97        last_type = DOUBLE_QUOTE_ENCLOSED;
     98        break;
     99        case '\'':
     100        while((buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != '\'') && hasMoreTokens()) {
     101            buffer.append(" ");
     102            buffer.append(super.nextToken());
     103        }
     104        last_type = QUOTE_ENCLOSED;
     105        break;
     106        case '[':
     107        while((buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != ']') && hasMoreTokens()) {
     108            buffer.append(" ");
     109            buffer.append(super.nextToken());
     110        }
     111        last_type = BRACKET_ENCLOSED;
     112        break;
     113        default:
     114        last_type = NORMAL;
     115        }
     116        result = buffer.toString();
     117    }
     118    return result;
     119    }
     120    /** Unfortunately the StringBuffer doesn't have a built in endsWith method, so I'll just have to implement my own.
     121     * @param str The <strong>StringBuffer</strong> we are checking the end of.
     122     * @param target The <strong>String</strong> fragment we are searching for.
     123     * @return <i>true</i> if str ends with target, <i>false</i> otherwise.
     124     */
     125    private boolean endsWith(StringBuffer str, String target) {
     126    String temp = str.toString();
     127    if(temp.endsWith(target) != (str.lastIndexOf(target) == str.length() - target.length())) {
    128128                ///ystem.err.println("Holy error that'll crash the HFile creator if it happens twice, Batman!");
    129129                ///ystem.err.println("String = '" + temp + "'");
    130130                ///ystem.err.println("Target = '" + target + "'");
    131           }
    132           return str.lastIndexOf(target) == str.length() - target.length();
    133     }
     131    }
     132    return str.lastIndexOf(target) == str.length() - target.length();
     133    }
    134134}
    135135
  • trunk/gli/src/org/greenstone/gatherer/cdm/CustomClassifier.java

    r4293 r4366  
    4444 */
    4545public interface CustomClassifier
    46     extends Comparable {
    47     /** Constructor.
    48       * public CustomClassifier(Gatherer gatherer);
     46    extends Comparable {
     47    /** Constructor.
     48     * public CustomClassifier(Gatherer gatherer);
    4949      */
    5050     /** Create a blank copy of this pseudo-classifier.
    5151      * @return A newly allocated <strong>CustomClassifier</strong>.
    5252      */
    53     public CustomClassifier copy();
    54     /** Destructor. */
    55     public void destroy();
    56     /** Show the controls for configuring this pseudo-classifier.
     53    public CustomClassifier copy();
     54    /** Destructor. */
     55    public void destroy();
     56    /** Show the controls for configuring this pseudo-classifier.
    5757      * @param show <i>true</i> if the component should immediately show itself, <i>false</i> if you just wish to initialize components.
    5858      */
    59     public boolean display(boolean show);
    60     /** Method to return this pseudo-classifier represented as a String.
     59    public boolean display(boolean show);
     60    /** Method to return this pseudo-classifier represented as a String.
    6161      * @return A <strong>String</strong>.
    6262      */
    63     public String getCommand();
    64     /** Retrieve the custom command, a command line that overrides and replaces some other 'actual' classifier.
     63    public String getCommand();
     64    /** Retrieve the custom command, a command line that overrides and replaces some other 'actual' classifier.
    6565      * @param index The number of the classifer this one is replacing.
    6666      */
    67     public String getCustomCommand(int index);
    68     /** Get the name of this custom classifier.
     67    public String getCustomCommand(int index);
     68    /** Get the name of this custom classifier.
    6969      * @return A <strong>String</strong> representing the name.
    7070      */
    71     public String getName();
    72     public void process(FileNode record);
    73     /** Recreate a CustomAZList given several parameters including the real classifier created during custom design.
    74       * @param classifier The real <strong>Classifier</strong>.
    75       * @param separations A <strong>String</strong> representing the choosen separations.
    76       */
    77     public void recreate(Classifier classifier, String separations);
    78     /** Sets the value of Gatherer, for those classes loaded dynamically.
     71    public String getName();
     72    public void process(FileNode record);
     73    /** Recreate a CustomAZList given several parameters including the real classifier created during custom design.
     74     * @param classifier The real <strong>Classifier</strong>.
     75     * @param separations A <strong>String</strong> representing the choosen separations.
     76     */
     77    public void recreate(Classifier classifier, String separations);
     78    /** Sets the value of Gatherer, for those classes loaded dynamically.
    7979      * @param gatherer A reference to the <strong>Gatherer</strong>.
    8080      */
    81     public void setGatherer(Gatherer gatherer);
    82     /** Sets the Classifier manager in charge of this classifier.
     81    public void setGatherer(Gatherer gatherer);
     82    /** Sets the Classifier manager in charge of this classifier.
    8383      * @param manager This classifiers <strong>ClassifierManager</strong>.
    8484      */
    85     public void setManager(ClassifierManager manager);
     85    public void setManager(ClassifierManager manager);
    8686}
  • trunk/gli/src/org/greenstone/gatherer/cdm/DefaultSubIndex.java

    r4293 r4366  
    6060 */
    6161public class DefaultSubIndex
    62     extends SubIndex {
    63     /** Copy constructor.
    64       * @param subindex The <strong>SubIndex</strong> we are copying.
     62    extends SubIndex {
     63    /** Copy constructor.
     64     * @param subindex The <strong>SubIndex</strong> we are copying.
    6565      */
    66     public DefaultSubIndex(SubIndex subindex) {
    67           for(int i = 0; i < subindex.size(); i++) {
    68                 add(subindex.get(i));
    69           }
    70     }
    71     /** Parsed data Constructor.
     66    public DefaultSubIndex(SubIndex subindex) {
     67    for(int i = 0; i < subindex.size(); i++) {
     68        add(subindex.get(i));
     69    }
     70    }
     71    /** Parsed data Constructor.
    7272      * @param raw A <strong>String</strong> containing a comma separated list of subcollection names.
    7373      * @param manager A reference to the <strong>SubcollectionManager</strong> via which we retrieve the required <strong>Subcollection</strong>s.
    7474      */
    75     public DefaultSubIndex(String raw, SubcollectionManager manager) {
    76           super(raw, manager);
    77     }
    78     /** Method to extract just the subindex information from this class.
     75    public DefaultSubIndex(String raw, SubcollectionManager manager) {
     76    super(raw, manager);
     77    }
     78    /** Method to extract just the subindex information from this class.
    7979      * @return A <strong>SubIndex</strong> based on the information in this class.
    8080      */
    81     public SubIndex getSubIndex() {
    82           return new SubIndex(this);
    83     }
    84     /** Method to produce this class as a string much like you'd find in the collection configuration file.
     81    public SubIndex getSubIndex() {
     82    return new SubIndex(this);
     83    }
     84    /** Method to produce this class as a string much like you'd find in the collection configuration file.
    8585      * @return A <strong>String</string> with the default index entry.
    8686      */
    87     public String toString() {
    88           String text = "defaultsubcollection ";
    89           for(int i = 0; i < size(); i++) {
    90                 Object object = get(i);
    91                 Subcollection sub = (Subcollection) get(i);
    92                 text = text + sub.getName();
    93                 if(i < size() - 1) {
    94                      text = text + ",";
    95                 }
    96           }
    97           text = text + "\n";
    98           return text;
    99     }
     87    public String toString() {
     88    String text = "defaultsubcollection ";
     89    for(int i = 0; i < size(); i++) {
     90        Object object = get(i);
     91        Subcollection sub = (Subcollection) get(i);
     92        text = text + sub.getName();
     93        if(i < size() - 1) {
     94        text = text + ",";
     95        }
     96    }
     97    text = text + "\n";
     98    return text;
     99    }
    100100}
    101101
  • trunk/gli/src/org/greenstone/gatherer/cdm/DynamicListModel.java

    r4293 r4366  
    5757 */
    5858public class DynamicListModel
    59     extends DefaultListModel
    60     implements ComboBoxModel {
     59    extends DefaultListModel
     60    implements ComboBoxModel {
    6161
    62     private boolean auto_order = false;
     62    private boolean auto_order = false;
    6363
    64     private Object object = null;
     64    private Object object = null;
    6565
    66     public void addElement(Object element) {
    67           if(auto_order) {
     66    public void addElement(Object element) {
     67    if(auto_order) {
    6868                // Insert the object in its alphabetically correct place.
    69                 int position = 0;
    70                 boolean found = false;
    71                 while(!found && position < size()) {
    72                      ///ystem.err.print("Compare " + element.toString() + " to " + get(position).toString() + ": ");
    73                      int order = element.toString().compareTo(get(position).toString());
    74                      if(order < 0) {
    75                           add(position, element);
    76                           found = true;
    77                           ///ystem.err.println("Greater than. Insert");
    78                      }
    79                      else if(order == 0) {
    80                           found = true;
    81                           ///ystem.err.println("Equal. End.");
    82                      }
    83                      else {
    84                           position++;
    85                           ///ystem.err.println("Less than. Carry on.");
    86                      }
    87                 }
    88                 if(!found) {
    89                      super.addElement(element);
    90                      ///ystem.err.println("Out of elements. Insert");
    91                 }
    92           }
    93           else {
    94                 super.addElement(element);
    95           }
    96     }
     69        int position = 0;
     70        boolean found = false;
     71        while(!found && position < size()) {
     72        ///ystem.err.print("Compare " + element.toString() + " to " + get(position).toString() + ": ");
     73        int order = element.toString().compareTo(get(position).toString());
     74        if(order < 0) {
     75            add(position, element);
     76            found = true;
     77            ///ystem.err.println("Greater than. Insert");
     78        }
     79        else if(order == 0) {
     80            found = true;
     81            ///ystem.err.println("Equal. End.");
     82        }
     83        else {
     84            position++;
     85            ///ystem.err.println("Less than. Carry on.");
     86        }
     87        }
     88        if(!found) {
     89        super.addElement(element);
     90        ///ystem.err.println("Out of elements. Insert");
     91        }
     92    }
     93    else {
     94        super.addElement(element);
     95    }
     96    }
    9797
    98     public DynamicListModel shallowCopy() {
    99           DynamicListModel copy = new DynamicListModel();
    100           copy.setAutoOrder(auto_order);
    101           for(int i = 0; i < size(); i++) {
    102                 copy.addElement(get(i));
    103           }
    104           return copy;
    105     }
     98    public DynamicListModel shallowCopy() {
     99    DynamicListModel copy = new DynamicListModel();
     100    copy.setAutoOrder(auto_order);
     101    for(int i = 0; i < size(); i++) {
     102        copy.addElement(get(i));
     103    }
     104    return copy;
     105    }
    106106
    107     public Object getSelectedItem() {
    108           ///ystem.err.println("Get item: " + object);
    109           return object;
    110     }
    111     /** Notify all controls that are based on this list model that its contents have changed, and they should repaint themselves. */
    112     public void refresh() {
    113           fireContentsChanged(this, 0, size());
    114     }
     107    public Object getSelectedItem() {
     108    ///ystem.err.println("Get item: " + object);
     109    return object;
     110    }
     111    /** Notify all controls that are based on this list model that its contents have changed, and they should repaint themselves. */
     112    public void refresh() {
     113    fireContentsChanged(this, 0, size());
     114    }
    115115
    116     public void setAutoOrder(boolean auto_order) {
    117           this.auto_order = auto_order;
    118     }
     116    public void setAutoOrder(boolean auto_order) {
     117    this.auto_order = auto_order;
     118    }
    119119
    120     public void setSelectedItem(Object object) {
    121           ///ystem.err.println("Set item: " + object);
    122           this.object = object;
    123     }
     120    public void setSelectedItem(Object object) {
     121    ///ystem.err.println("Set item: " + object);
     122    this.object = object;
     123    }
    124124}
  • trunk/gli/src/org/greenstone/gatherer/cdm/ElementWrapper.java

    r4293 r4366  
    66 */
    77public class ElementWrapper
    8     implements Comparable {
    9     /** The element as the data from this object. */
    10     private Node element = null;
    11     /** Constructor.
    12       * @param element The <strong>Node</strong> this object is wrapped around.
     8    implements Comparable {
     9    /** The element as the data from this object. */
     10    private Node element = null;
     11    /** Constructor.
     12     * @param element The <strong>Node</strong> this object is wrapped around.
    1313      */
    14     public ElementWrapper(Node element) {
    15           this.element = element;
    16     }
    17     /** Compare two objects for ordering.
     14    public ElementWrapper(Node element) {
     15    this.element = element;
     16    }
     17    /** Compare two objects for ordering.
    1818      * @param object The other <strong>Object</strong> to compare to.
    1919      * @return An <i>int</i> indicating the ordering as is String.compareTo
    2020      */
    21     public int compareTo(Object object) {
    22           if(object == null) {
    23                 return 1;
    24           }
    25           return toString().compareTo(object.toString());
    26     }
    27     /** Compare two objects for equality.
     21    public int compareTo(Object object) {
     22    if(object == null) {
     23        return 1;
     24    }
     25    return toString().compareTo(object.toString());
     26    }
     27    /** Compare two objects for equality.
    2828      * @param object The <strong>Object</strong> to compare to.
    2929      * @return <i>true</i> if the objects are equal, <i>false</i> otherwise.
    3030      */
    31     public boolean equals(Object object) {
    32           if(compareTo(object) == 0) {
    33                 return true;
    34           }
    35           return false;
    36     }
    37     /** Retrieve the name of the element.
     31    public boolean equals(Object object) {
     32    if(compareTo(object) == 0) {
     33        return true;
     34    }
     35    return false;
     36    }
     37    /** Retrieve the name of the element.
    3838      * @return The fully qualified name as a <strong>String</strong>.
    3939      * @see org.greenstone.gatherer.msm.MSMUtils
    4040      */
    41     public String name() {
    42           return MSMUtils.getFullName((Element)element);
    43     }
    44     /** Retrieve a textual representation of this object.
     41    public String name() {
     42    return MSMUtils.getFullName((Element)element);
     43    }
     44    /** Retrieve a textual representation of this object.
    4545      * @return A <strong>String</strong>.
    4646      * @see org.greenstone.gatherer.msm.MSMUtils
    4747      */
    48     public String toString() {
    49           return MSMUtils.getIdentifier(element) + ": " + MSMUtils.getDescription(element);
    50     }
     48    public String toString() {
     49    return MSMUtils.getIdentifier(element) + ": " + MSMUtils.getDescription(element);
     50    }
    5151}
  • trunk/gli/src/org/greenstone/gatherer/cdm/Format.java

    r4293 r4366  
    5656 */
    5757public class Format {
    58     /** If this format is of a true/false type, the current state. */
    59     private boolean state = false;
    60     /** The type of this format command, either FLAG, FORMAT or PARAM. */
    61     private int type = -1;
    62     /** The feature this format command affects. */
    63     private Object feature = null;
    64     /** If this format refers to a specific part of a feature, this indicates the part. */
    65     private String part = null;
    66     /** A command string, which may include a specific HTML chunk used to format a control. */
    67     private String value = null;
    68     /** An element of the format type enumeration. A true/false option. */
    69     static final public int FLAG = 0;
    70     /** An element of the format type enumeration. A string parameter. */
    71     static final public int VALUE = 1;
    72     /** The default features as specified by the Greenstone Developers manual. */
    73     static final public String DEFAULT_FEATURES[] = {"", "DocumentArrowsBottom","DocumentButtons","DocumentContents","DocumentHeading","DocumentImages","DocumentText","DocumentUseHTML","Search"};
    74     /** The list of known feature parts. */
    75     static final public String DEFAULT_PARTS[] = {"","DateList","HList","Invisible","VList"};
    76     /** Constructor for a flag format command.
    77     * @param feature The <Strong>Object</strong> this format affects.
    78     * @param part The specific part of the control to format as a <strong>String</strong>.
    79     * @param state A <i>boolean</i> indicating this formats state.
    80     */
    81     public Format(Object feature, String part, boolean state) {
    82           this.feature = feature;
    83           this.part = part;
    84           this.state = state;
    85           this.type = FLAG;
    86     }
    87     /** Constructor for a format-string format command.
    88     * @param feature The <Strong>Object</strong> this format affects.
    89     * @param part The specific part of the control to format as a <strong>String</strong>.
    90     * @param value The format <strong>String</strong> which may be a label name, or a piece of HTML formatting.
    91     */
    92     public Format(Object feature, String part, String value) {
    93           this.feature = feature;
    94           this.part = part;
    95           this.type = VALUE;
    96           this.value = value;
    97     }
    98     /** Method to retrieve the value of feature, which may either be a String or a Classifier.
    99       * @return The value of feature as an <strong>Object</strong>.
    100       */
    101     public Object getFeature() {
    102           return feature;
    103     }
    104     /** Method to retrieve the value of part.
    105       * @return The value of part as a <Strong>String</strong>.
    106       */
    107     public String getPart() {
    108           return part;
    109     }
    110     /** Method to retrieve this formats special Greenstone position code.
    111       * @return A <strong>String</strong> which distinctly indicates this classifiers position.
    112       * @see org.greenstone.gatherer.cdm.Classifier
    113       */
    114     public String getPosition() {
    115           ///ystem.err.println("Retrieving the name of feature " + feature);
    116           String position = null;
    117           if(feature instanceof Classifier) {
    118                 position = ((Classifier)feature).getPositionString();
    119           }
    120           else {
    121                 position = feature.toString();
    122           }
    123           ///ystem.err.println("Result: " + position + part);
    124           return position + part;
    125     }
    126     /** Method to retrieve the value of state.
    127       * @param The value of state as a <i>boolean</i>.
    128       */
    129     public boolean getState() {
    130           return state;
    131     }
    132     /** Method to retrieve the value of type.
    133       * @param The value of type as an <i>int</i>.
    134       */
    135     public int getType() {
    136           return type;
    137     }
    138     /** Retrieve the value of value.
    139       * @return A <strong>String</strong> which is the value of value.
    140       */
    141     public String getValue() {
    142           return value;
    143     }
    144     /** Set the value of state.
    145       * @param state The new value for state as a <i>boolean</i>.
    146       */
    147     public void setState(boolean state) {
    148           this.state = state;
    149     }
    150     /** Set the value of type.
    151       * @param type The new value for type as an <i>int</i>.
    152       */
    153     public void setType(int type) {
    154           this.type = type;
    155     }
    156     /** Set the value of value. Hmmm.
    157       * @param value The new value from value as a <strong>String</strong>.
    158       */
    159     public void setValue(String value) {
    160           this.value = value;
    161     }
    162     /** Method to translate this classes information into a line of text as you would expect in the collection configuration file.
    163       * @return A <strong>String</strong> containing the format command.
    164       */
    165     public String toString() {
    166           String text = "format ";
    167           text = text + getPosition() + " ";
    168           switch(type) {
    169           case FLAG:
    170                 if(state) {
    171                      text = text + "true";
    172                 }
    173                 else {
    174                      text = text + "false";
    175                 }
    176                 break;
    177           default:
    178                 text = text + "\"" + value + "\"";
    179           }
    180           return text;
    181     }
    182     /** Retrieve the type of a certain named feature.
    183       * @param name The name of the feature as a <strong>String</strong>.
    184       * @return An <i>int</i> indicating the type, and hence the controls needed to edit this type.
    185       */
    186     static public int getType(String name) {
    187           int index = -1;
    188           for(int i = 1; i < DEFAULT_FEATURES.length; i++) {
    189                 if(name.equalsIgnoreCase(DEFAULT_FEATURES[i])) {
    190                      index = i;
    191                 }
    192           }
    193           if(index == 1 || index == 3 || index == 5 || index == 7) {
    194                 return FLAG;
    195           }
    196           return VALUE;
    197     }
     58    /** If this format is of a true/false type, the current state. */
     59    private boolean state = false;
     60    /** The type of this format command, either FLAG, FORMAT or PARAM. */
     61    private int type = -1;
     62    /** The feature this format command affects. */
     63    private Object feature = null;
     64    /** If this format refers to a specific part of a feature, this indicates the part. */
     65    private String part = null;
     66    /** A command string, which may include a specific HTML chunk used to format a control. */
     67    private String value = null;
     68    /** An element of the format type enumeration. A true/false option. */
     69    static final public int FLAG = 0;
     70    /** An element of the format type enumeration. A string parameter. */
     71    static final public int VALUE = 1;
     72    /** The default features as specified by the Greenstone Developers manual. */
     73    static final public String DEFAULT_FEATURES[] = {"", "DocumentArrowsBottom","DocumentButtons","DocumentContents","DocumentHeading","DocumentImages","DocumentText","DocumentUseHTML","Search"};
     74    /** The list of known feature parts. */
     75    static final public String DEFAULT_PARTS[] = {"","DateList","HList","Invisible","VList"};
     76    /** Constructor for a flag format command.
     77    * @param feature The <Strong>Object</strong> this format affects.
     78    * @param part The specific part of the control to format as a <strong>String</strong>.
     79    * @param state A <i>boolean</i> indicating this formats state.
     80    */
     81    public Format(Object feature, String part, boolean state) {
     82    this.feature = feature;
     83    this.part = part;
     84    this.state = state;
     85    this.type = FLAG;
     86    }
     87    /** Constructor for a format-string format command.
     88    * @param feature The <Strong>Object</strong> this format affects.
     89    * @param part The specific part of the control to format as a <strong>String</strong>.
     90    * @param value The format <strong>String</strong> which may be a label name, or a piece of HTML formatting.
     91    */
     92    public Format(Object feature, String part, String value) {
     93    this.feature = feature;
     94    this.part = part;
     95    this.type = VALUE;
     96    this.value = value;
     97    }
     98    /** Method to retrieve the value of feature, which may either be a String or a Classifier.
     99     * @return The value of feature as an <strong>Object</strong>.
     100     */
     101    public Object getFeature() {
     102    return feature;
     103    }
     104    /** Method to retrieve the value of part.
     105     * @return The value of part as a <Strong>String</strong>.
     106     */
     107    public String getPart() {
     108    return part;
     109    }
     110    /** Method to retrieve this formats special Greenstone position code.
     111     * @return A <strong>String</strong> which distinctly indicates this classifiers position.
     112     * @see org.greenstone.gatherer.cdm.Classifier
     113     */
     114    public String getPosition() {
     115    ///ystem.err.println("Retrieving the name of feature " + feature);
     116    String position = null;
     117    if(feature instanceof Classifier) {
     118        position = ((Classifier)feature).getPositionString();
     119    }
     120    else {
     121        position = feature.toString();
     122    }
     123    ///ystem.err.println("Result: " + position + part);
     124    return position + part;
     125    }
     126    /** Method to retrieve the value of state.
     127     * @param The value of state as a <i>boolean</i>.
     128     */
     129    public boolean getState() {
     130    return state;
     131    }
     132    /** Method to retrieve the value of type.
     133     * @param The value of type as an <i>int</i>.
     134     */
     135    public int getType() {
     136    return type;
     137    }
     138    /** Retrieve the value of value.
     139     * @return A <strong>String</strong> which is the value of value.
     140     */
     141    public String getValue() {
     142    return value;
     143    }
     144    /** Set the value of state.
     145     * @param state The new value for state as a <i>boolean</i>.
     146     */
     147    public void setState(boolean state) {
     148    this.state = state;
     149    }
     150    /** Set the value of type.
     151     * @param type The new value for type as an <i>int</i>.
     152     */
     153    public void setType(int type) {
     154    this.type = type;
     155    }
     156    /** Set the value of value. Hmmm.
     157     * @param value The new value from value as a <strong>String</strong>.
     158     */
     159    public void setValue(String value) {
     160    this.value = value;
     161    }
     162    /** Method to translate this classes information into a line of text as you would expect in the collection configuration file.
     163     * @return A <strong>String</strong> containing the format command.
     164     */
     165    public String toString() {
     166    String text = "format ";
     167    text = text + getPosition() + " ";
     168    switch(type) {
     169    case FLAG:
     170        if(state) {
     171        text = text + "true";
     172        }
     173        else {
     174        text = text + "false";
     175        }
     176        break;
     177    default:
     178        text = text + "\"" + value + "\"";
     179    }
     180    return text;
     181    }
     182    /** Retrieve the type of a certain named feature.
     183     * @param name The name of the feature as a <strong>String</strong>.
     184     * @return An <i>int</i> indicating the type, and hence the controls needed to edit this type.
     185     */
     186    static public int getType(String name) {
     187    int index = -1;
     188    for(int i = 1; i < DEFAULT_FEATURES.length; i++) {
     189        if(name.equalsIgnoreCase(DEFAULT_FEATURES[i])) {
     190        index = i;
     191        }
     192    }
     193    if(index == 1 || index == 3 || index == 5 || index == 7) {
     194        return FLAG;
     195    }
     196    return VALUE;
     197    }
    198198}
  • trunk/gli/src/org/greenstone/gatherer/cdm/FormatManager.java

    r4293 r4366  
    9494 */
    9595public class FormatManager
    96     extends DynamicListModel {
    97     /** The main manager so we can get to ClassifierManager which is needed to turn position reference such as "CL1" into the appropriate Classifier. */
    98     private CollectionDesignManager manager = null;
    99     /** The controls used to edit the format commands. */
    100     private Control controls = null;
    101     /** A reference to ourselves so inner classes can get at the model. */
    102     private DynamicListModel model = null;
    103     /** A reference to the Gatherer. */
    104     private Gatherer gatherer = null;
    105     /** We may have somehow recieved a format command which references a classifier that hasn't been parsed yet, so this variable holds a list of failed commands which are retried after the loading is complete. */
    106     private Vector unresolved_commands = null;
    107     /** Constructor.
    108       * @param gatherer A reference to the <strong>Gatherer</strong>.
    109       * @param manager A reference to the <strong>CollectionDesignManager</strong> that created this manager.
    110       */
    111     public FormatManager(Gatherer gatherer, CollectionDesignManager manager) {
    112           super();
    113           this.gatherer = gatherer;
    114           this.manager = manager;
    115           this.model = this;
    116           this.unresolved_commands = new Vector();
    117     }
    118     /** Method to add a new format to this manager.
     96    extends DynamicListModel {
     97    /** The main manager so we can get to ClassifierManager which is needed to turn position reference such as "CL1" into the appropriate Classifier. */
     98    private CollectionDesignManager manager = null;
     99    /** The controls used to edit the format commands. */
     100    private Control controls = null;
     101    /** A reference to ourselves so inner classes can get at the model. */
     102    private DynamicListModel model = null;
     103    /** A reference to the Gatherer. */
     104    private Gatherer gatherer = null;
     105    /** We may have somehow recieved a format command which references a classifier that hasn't been parsed yet, so this variable holds a list of failed commands which are retried after the loading is complete. */
     106    private Vector unresolved_commands = null;
     107    /** Constructor.
     108     * @param gatherer A reference to the <strong>Gatherer</strong>.
     109     * @param manager A reference to the <strong>CollectionDesignManager</strong> that created this manager.
     110     */
     111    public FormatManager(Gatherer gatherer, CollectionDesignManager manager) {
     112    super();
     113    this.gatherer = gatherer;
     114    this.manager = manager;
     115    this.model = this;
     116    this.unresolved_commands = new Vector();
     117    }
     118    /** Method to add a new format to this manager.
    119119      * @param format The <strong>Format</strong> to add.
    120120      */
    121     public void addFormat(Format format) {
    122           if(formatExists(format) == null) {
    123                 addElement(format);
    124                 gatherer.c_man.configurationChanged();
    125           }
    126     }
    127     /** Method which determines if a certain format exists, in which case it must be removed before a new format of the same component is added. For general formatting statements this compares types, for 'custom' ones it compares list and part.
     121    public void addFormat(Format format) {
     122    if(formatExists(format) == null) {
     123        addElement(format);
     124        gatherer.c_man.configurationChanged();
     125    }
     126    }
     127    /** Method which determines if a certain format exists, in which case it must be removed before a new format of the same component is added. For general formatting statements this compares types, for 'custom' ones it compares list and part.
    128128      * @param format The <strong>Format</strong> whose uniqueness we want to check.
    129129      * @return The <strong>Format</strong> that matches the one given, or <i>null</i> if no such format exists.
    130130      */
    131     public Format formatExists(Format format) {
    132           for(int i = 0; i < size(); i++) {
    133                 Format current = (Format) get(i);
    134                 if(format.getPosition().equals(current.getPosition())) {
    135                      return current;
    136                 }
    137           }
    138           return null;
    139     }
    140     /** Gets the format indicated by the index.
     131    public Format formatExists(Format format) {
     132    for(int i = 0; i < size(); i++) {
     133        Format current = (Format) get(i);
     134        if(format.getPosition().equals(current.getPosition())) {
     135        return current;
     136        }
     137    }
     138    return null;
     139    }
     140    /** Gets the format indicated by the index.
    141141      * @param index The location of the desired format, as an <i>int</i>.
    142142      */
    143     public Format getFormat(int index) {
    144           return (Format)get(index);
    145     }
    146     /** Method to retrieve this managers controls.
     143    public Format getFormat(int index) {
     144    return (Format)get(index);
     145    }
     146    /** Method to retrieve this managers controls.
    147147      * @return The <strong>Control</strong> for this collection.
    148148      */
    149     public Control getControls() {
    150           if(controls == null) {
    151                 controls = new Control();
    152           }
    153           return controls;
    154     }
    155     /** Method to invalidate controls when some significant change has occured within the collection. */
    156     public void invalidateControls() {
    157           if(controls != null) {
    158                 controls.destroy();
    159           }
    160           controls = null;
    161     }
    162     /** This method attempts to parse a format command from the given string. If a format is parsed, it is immediately added to this managers list of format commands.
     149    public Control getControls() {
     150    if(controls == null) {
     151        controls = new Control();
     152    }
     153    return controls;
     154    }
     155    /** Method to invalidate controls when some significant change has occured within the collection. */
     156    public void invalidateControls() {
     157    if(controls != null) {
     158        controls.destroy();
     159    }
     160    controls = null;
     161    }
     162    /** This method attempts to parse a format command from the given string. If a format is parsed, it is immediately added to this managers list of format commands.
    163163      * @param command The <strong>String</strong> we are trying to parse a command from.
    164164      * @param finished A <i>boolean</i> which is <i>true</i> if we are calling this after the the input has been completely parsed (i.e all legal Classifiers are know to exist), or <i>false</i> otherwise.
     
    168168      * @see org.greenstone.gatherer.cdm.Format
    169169      */
    170      public boolean parse(String command, boolean finished) {
    171           String temp = command.toLowerCase();
    172           if(temp.startsWith("format")) {
    173                 if(finished) {
    174                      CommandTokenizer ct = new CommandTokenizer(command);
    175                      ct.nextToken(); // Throw away 'format'
    176                      String position = ct.nextToken();
    177                      String value = ct.nextToken();
    178                      // String speech marks.
    179                      if(value.startsWith("\"") && value.endsWith("\"")) {
    180                           if(value.equals("\"\"")) {
    181                                 value = "";
    182                           }
    183                           else {
    184                                 value = value.substring(1, value.length() - 1);
    185                           }
    186                      }
    187                      // Ensure we parsed a good command.
    188                      if(position != null && value != null) {
    189                           // The trickiest bit of parsing format commands is figuring out how much of the position is feature, and how much part. Since the parts are far less likely to change or be customized in any way, we'll try to match them first (except "" of course).
    190                           String feature_name = null;
    191                           String part = null;
    192                           // If this works, then we're all finished. Yay.
    193                           for(int i = 1; i < Format.DEFAULT_PARTS.length; i++) {
    194                                 if(position.endsWith(Format.DEFAULT_PARTS[i])) {
    195                                      part = Format.DEFAULT_PARTS[i];
    196                                      feature_name = position.substring(0, position.length() - part.length());
    197                                 }
    198                           }
    199                           // Otherwise we can attempt to find the default features, but we have less chance of success.
    200                           if(feature_name == null || part == null) {
    201                                 for(int i = 1; i < Format.DEFAULT_FEATURES.length; i++) {
    202                                      if(position.startsWith(Format.DEFAULT_FEATURES[i])) {
    203                                           feature_name = Format.DEFAULT_FEATURES[i];
    204                                           if(position.length() > feature_name.length()) {
    205                                                 part = position.substring(feature_name.length());
    206                                           }
    207                                           else {
    208                                                 part = "";
    209                                           }
    210                                      }
    211                                 }
    212                           }
    213                           // Otherwise we can assume we are dealing with a classifier and split the position using...
    214                           // position            ::= <classifier_position><part>
    215                           // classifier_position ::= <alphanum>[0-9]$
    216                           // part                ::= ^![0-9]<alpha>
    217                           // But I don't like my chances of this working if someone does a scary like CL4Part8B. I just have
    218                           // to hope no-one uses numbers, and no-one expects CustomFeatureCustomPart to parse properly.
    219                           if(feature_name == null || part == null) {
    220                                 part = "";
    221                                 boolean found = false;
    222                                 int index = position.length() - 1;
    223                                 while(index >= 0 && !found) {
    224                                      if(Character.isDigit(position.charAt(index))) {
    225                                           found = true;
    226                                      }
    227                                      else {
    228                                           part = position.charAt(index) + part;
    229                                           index--;
    230                                      }
    231                                 }
    232                                 if(found) {
    233                                      feature_name = position.substring(0, index + 1);
    234                                 }
    235                                 // We ran out of string. No digits. Arg!
    236                                 else {
    237                                      part = null;
    238                                 }
    239                           }
    240                           // And if all else fails, stick it all in feature.
    241                           if(feature_name == null || part == null) {
    242                                 feature_name = position;
    243                                 part = "";
    244                           }
    245                           // Now try to retrieve a classifier with the feature name.
    246                           Object feature = null;
    247                           String feature_name_lc = feature_name.toLowerCase();
    248                           if(feature_name_lc.startsWith("cl") && feature_name.length() >= 3) {
    249                                 String raw_index = feature_name.substring(2); // Lose the 'CL'
    250                                 int index = -1;
    251                                 try {
    252                                      index = Integer.parseInt(raw_index);
    253                                 }
    254                                 catch(NumberFormatException nfe) {
    255                                      nfe.printStackTrace();
    256                                 }
    257                                 feature = manager.classifiers.getClassifier(index - 1);
    258                           }
    259                           else {
    260                                 ///ystem.err.println("name to short for classifier.");
    261                           }
    262                           if(feature == null) {
    263                                 feature = feature_name;
    264                           }
    265                           ///ystem.err.println("Feature name = " + feature_name + "\nPart = " + part);
    266                           if(feature instanceof Classifier) {
    267                                 ///ystem.err.println("Feature is a classifier.");
    268                           }
    269                           else {
    270                                 ///ystem.err.println("Feature is a String.");
    271                           }
    272                           // Now we have a quick look at value. If its true or false we create a FLAG type
    273                           if(value.equalsIgnoreCase("true")) {
    274                                 addFormat(new Format(feature, part, true));
    275                           }
    276                           else if(value.equalsIgnoreCase("false")) {
    277                                 addFormat(new Format(feature, part, false));
    278                           }
    279                           // Otherwise add a plain old value based format
    280                           else {
    281                                 addFormat(new Format(feature, part, value));
    282                           }
    283                           return true;
    284                      }
    285                      // Somethings gone terribly, terribly wrong.
    286                      return false;
     170    public boolean parse(String command, boolean finished) {
     171    String temp = command.toLowerCase();
     172    if(temp.startsWith("format")) {
     173        if(finished) {
     174        CommandTokenizer ct = new CommandTokenizer(command);
     175        ct.nextToken(); // Throw away 'format'
     176        String position = ct.nextToken();
     177        String value = ct.nextToken();
     178        // String speech marks.
     179        if(value.startsWith("\"") && value.endsWith("\"")) {
     180            if(value.equals("\"\"")) {
     181            value = "";
     182            }
     183            else {
     184            value = value.substring(1, value.length() - 1);
     185            }
     186        }
     187        // Ensure we parsed a good command.
     188        if(position != null && value != null) {
     189            // The trickiest bit of parsing format commands is figuring out how much of the position is feature, and how much part. Since the parts are far less likely to change or be customized in any way, we'll try to match them first (except "" of course).
     190            String feature_name = null;
     191            String part = null;
     192            // If this works, then we're all finished. Yay.
     193            for(int i = 1; i < Format.DEFAULT_PARTS.length; i++) {
     194            if(position.endsWith(Format.DEFAULT_PARTS[i])) {
     195                part = Format.DEFAULT_PARTS[i];
     196                feature_name = position.substring(0, position.length() - part.length());
     197            }
     198            }
     199            // Otherwise we can attempt to find the default features, but we have less chance of success.
     200            if(feature_name == null || part == null) {
     201            for(int i = 1; i < Format.DEFAULT_FEATURES.length; i++) {
     202                if(position.startsWith(Format.DEFAULT_FEATURES[i])) {
     203                feature_name = Format.DEFAULT_FEATURES[i];
     204                if(position.length() > feature_name.length()) {
     205                    part = position.substring(feature_name.length());
    287206                }
    288207                else {
    289                      unresolved_commands.add(command);
     208                    part = "";
    290209                }
    291                 return true;
    292           }
    293           return false;
    294      }
    295      /** Method to remove a format.
     210                }
     211            }
     212            }
     213            // Otherwise we can assume we are dealing with a classifier and split the position using...
     214            // position            ::= <classifier_position><part>
     215            // classifier_position ::= <alphanum>[0-9]$
     216            // part                ::= ^![0-9]<alpha>
     217            // But I don't like my chances of this working if someone does a scary like CL4Part8B. I just have
     218            // to hope no-one uses numbers, and no-one expects CustomFeatureCustomPart to parse properly.
     219            if(feature_name == null || part == null) {
     220            part = "";
     221            boolean found = false;
     222            int index = position.length() - 1;
     223            while(index >= 0 && !found) {
     224                if(Character.isDigit(position.charAt(index))) {
     225                found = true;
     226                }
     227                else {
     228                part = position.charAt(index) + part;
     229                index--;
     230                }
     231            }
     232            if(found) {
     233                feature_name = position.substring(0, index + 1);
     234            }
     235            // We ran out of string. No digits. Arg!
     236            else {
     237                part = null;
     238            }
     239            }
     240            // And if all else fails, stick it all in feature.
     241            if(feature_name == null || part == null) {
     242            feature_name = position;
     243            part = "";
     244            }
     245            // Now try to retrieve a classifier with the feature name.
     246            Object feature = null;
     247            String feature_name_lc = feature_name.toLowerCase();
     248            if(feature_name_lc.startsWith("cl") && feature_name.length() >= 3) {
     249            String raw_index = feature_name.substring(2); // Lose the 'CL'
     250            int index = -1;
     251            try {
     252                index = Integer.parseInt(raw_index);
     253            }
     254            catch(NumberFormatException nfe) {
     255                nfe.printStackTrace();
     256            }
     257            feature = manager.classifiers.getClassifier(index - 1);
     258            }
     259            else {
     260            ///ystem.err.println("name to short for classifier.");
     261            }
     262            if(feature == null) {
     263            feature = feature_name;
     264            }
     265            ///ystem.err.println("Feature name = " + feature_name + "\nPart = " + part);
     266            if(feature instanceof Classifier) {
     267            ///ystem.err.println("Feature is a classifier.");
     268            }
     269            else {
     270            ///ystem.err.println("Feature is a String.");
     271            }
     272            // Now we have a quick look at value. If its true or false we create a FLAG type
     273            if(value.equalsIgnoreCase("true")) {
     274            addFormat(new Format(feature, part, true));
     275            }
     276            else if(value.equalsIgnoreCase("false")) {
     277            addFormat(new Format(feature, part, false));
     278            }
     279            // Otherwise add a plain old value based format
     280            else {
     281            addFormat(new Format(feature, part, value));
     282            }
     283            return true;
     284        }
     285        // Somethings gone terribly, terribly wrong.
     286        return false;
     287        }
     288        else {
     289        unresolved_commands.add(command);
     290        }
     291        return true;
     292    }
     293    return false;
     294    }
     295    /** Method to remove a format.
    296296      * @param format The <strong>Format</strong> to remove.
    297297      */
    298     public void removeFormat(Format format) {
    299           removeElement(format);
    300           gatherer.c_man.configurationChanged();
    301     }
    302     /** Method which attempts to reparse obvious format commands which previously referenced unresovable Classifiers.
     298    public void removeFormat(Format format) {
     299    removeElement(format);
     300    gatherer.c_man.configurationChanged();
     301    }
     302    /** Method which attempts to reparse obvious format commands which previously referenced unresovable Classifiers.
    303303    */
    304     public void reparseUnresolved() {
    305         for(int i = 0; i < unresolved_commands.size(); i++) {
    306             if(!parse((String)unresolved_commands.get(i), true)) {
    307                  ///ystem.err.println("*** Error: Command " + unresolved_commands.get(i));
    308             }
    309         }
    310         // Regardless of if they work, clear the commands.
    311         unresolved_commands.clear();
    312     }
    313     /** Method to produce a block of text representing the format commands in this manager, ready to be used in the collection configuration file.
     304    public void reparseUnresolved() {
     305    for(int i = 0; i < unresolved_commands.size(); i++) {
     306        if(!parse((String)unresolved_commands.get(i), true)) {
     307        ///ystem.err.println("*** Error: Command " + unresolved_commands.get(i));
     308        }
     309    }
     310    // Regardless of if they work, clear the commands.
     311    unresolved_commands.clear();
     312    }
     313    /** Method to produce a block of text representing the format commands in this manager, ready to be used in the collection configuration file.
    314314    * @return A <strong>String</strong> containing a series of format commands.
    315315    */
    316     public String toString() {
    317         StringBuffer text = new StringBuffer("");
    318         for(int i = 0; i < size(); i++) {
    319             Format format = (Format) get(i);
    320             text.append(format.toString());
    321             text.append("\n");
    322         }
    323         text.append("\n");
    324         return text.toString();
    325     }
    326     /** Overloaded to call get with both a key and an empty argument array.
     316    public String toString() {
     317    StringBuffer text = new StringBuffer("");
     318    for(int i = 0; i < size(); i++) {
     319        Format format = (Format) get(i);
     320        text.append(format.toString());
     321        text.append("\n");
     322    }
     323    text.append("\n");
     324    return text.toString();
     325    }
     326    /** Overloaded to call get with both a key and an empty argument array.
    327327      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    328328      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
    329329      */
    330     private String get(String key) {
    331           return get(key, null);
    332     }
    333     /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
     330    private String get(String key) {
     331    return get(key, null);
     332    }
     333    /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
    334334      * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
    335335      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     
    339339      * @see org.greenstone.gatherer.Dictionary
    340340      */
    341     private String get(String key, String args[]) {
    342           if(key.indexOf('.') == -1) {
    343                 key = "CDM.FormatManager." + key;
    344           }
    345           return gatherer.dictionary.get(key, args);
    346     }
    347     private class Control
    348           extends JPanel {
    349           /** Do we ignore selection changing events (mainly because we're generating them!) */
    350           private boolean ignore = false;
    351           private boolean new_entry = true;
    352           private boolean ready = false;
    353           private ButtonGroup button_group = null;
    354           private CardLayout card_layout = null;
    355           private Dimension LABEL_SIZE = new Dimension(175,25);
    356           private Format current_format = null;
    357           private String view_type = "custom";
    358           private JButton add = null;
    359           private JButton insert = null;
    360           private JButton preview = null;
    361           private JButton remove = null;
    362           private JComboBox feature = null;
    363           private JComboBox part = null;
    364           private JComboBox special = null;
    365           private JLabel editor_label = null;
    366           private JLabel feature_label = null;
    367           private JLabel format_list_label = null;
    368           private JLabel part_label = null;
    369           private JLabel special_label = null;
    370           private JLabel title = null;
    371           private JLabel value_label = null;
    372           private JList format_list = null;
    373           private JPanel blank_pane = null;
    374           private JPanel control_pane = null;
    375           private JPanel editor_pane = null;
    376           private JPanel feature_pane = null;
    377           private JPanel format_list_pane = null;
    378           private JPanel header_pane = null;
    379           private JPanel inner_button_pane = null;
    380           private JPanel inner_state_pane = null;
    381           private JPanel inner_value_pane = null;
    382           private JPanel options_pane = null;
    383           private JPanel outer_button_pane = null;
    384           private JPanel part_pane = null;
    385           private JPanel special_pane = null;
    386           private JPanel state_pane = null;
    387           private JPanel value_pane = null;
    388           private JPanel view_pane = null;
    389           private JTextArea editor = null;
    390           private JTextArea instructions = null;
    391           private JTextField value = null;
    392           private JToggleButton off = null;
    393           private JToggleButton on = null;
    394           private String BLANK = "blank";
    395           private String CUSTOM = "custom";
    396           private String FLAG = "flag";
    397           private String PARAM = "param";
    398           private Vector part_model = null;
    399           private Vector special_model = null;
    400           public Control() {
    401                 ArrayList feature_model = new ArrayList();
     341    private String get(String key, String args[]) {
     342    if(key.indexOf('.') == -1) {
     343        key = "CDM.FormatManager." + key;
     344    }
     345    return gatherer.dictionary.get(key, args);
     346    }
     347    private class Control
     348    extends JPanel {
     349    /** Do we ignore selection changing events (mainly because we're generating them!) */
     350    private boolean ignore = false;
     351    private boolean new_entry = true;
     352    private boolean ready = false;
     353    private ButtonGroup button_group = null;
     354    private CardLayout card_layout = null;
     355    private Dimension LABEL_SIZE = new Dimension(175,25);
     356    private Format current_format = null;
     357    private String view_type = "custom";
     358    private JButton add = null;
     359    private JButton insert = null;
     360    private JButton preview = null;
     361    private JButton remove = null;
     362    private JComboBox feature = null;
     363    private JComboBox part = null;
     364    private JComboBox special = null;
     365    private JLabel editor_label = null;
     366    private JLabel feature_label = null;
     367    private JLabel format_list_label = null;
     368    private JLabel part_label = null;
     369    private JLabel special_label = null;
     370    private JLabel title = null;
     371    private JLabel value_label = null;
     372    private JList format_list = null;
     373    private JPanel blank_pane = null;
     374    private JPanel control_pane = null;
     375    private JPanel editor_pane = null;
     376    private JPanel feature_pane = null;
     377    private JPanel format_list_pane = null;
     378    private JPanel header_pane = null;
     379    private JPanel inner_button_pane = null;
     380    private JPanel inner_state_pane = null;
     381    private JPanel inner_value_pane = null;
     382    private JPanel options_pane = null;
     383    private JPanel outer_button_pane = null;
     384    private JPanel part_pane = null;
     385    private JPanel special_pane = null;
     386    private JPanel state_pane = null;
     387    private JPanel value_pane = null;
     388    private JPanel view_pane = null;
     389    private JTextArea editor = null;
     390    private JTextArea instructions = null;
     391    private JTextField value = null;
     392    private JToggleButton off = null;
     393    private JToggleButton on = null;
     394    private String BLANK = "blank";
     395    private String CUSTOM = "custom";
     396    private String FLAG = "flag";
     397    private String PARAM = "param";
     398    private Vector part_model = null;
     399    private Vector special_model = null;
     400    public Control() {
     401        ArrayList feature_model = new ArrayList();
    402402                // Add the set options
    403                 for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
    404                      feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
    405                 }
     403        for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
     404        feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
     405        }
    406406                // Now the classifiers.
    407                 for(int j = 0; j < manager.classifiers.size(); j++) {
    408                      feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
    409                 }
    410                 Collections.sort(feature_model);
    411                 part_model = new Vector();
    412                 part_model.add("");//get("Custom"));
    413                 part_model.add("DateList");
    414                 part_model.add("HList");
    415                 part_model.add("Invisible");
    416                 part_model.add("VList");
    417                 special_model = new Vector();
    418                 special_model.add("[Text]");
    419                 special_model.add("[link]");
    420                 special_model.add("[/link]");
    421                 special_model.add("[icon]");
    422                 special_model.add("[num]");
    423                 special_model.add("[parent():_]");
    424                 special_model.add("[parent(Top):_]");
    425                 special_model.add("[parent(All'_'):_]");
    426                 Vector elements = gatherer.c_man.msm.getAssignedElements();
    427                 for(int i = 0; i < elements.size(); i++) {
    428                      special_model.add("[" + ((ElementWrapper)elements.get(i)).toString() + "]");
    429                 }
    430                 Collections.sort(special_model);
     407        for(int j = 0; j < manager.classifiers.size(); j++) {
     408        feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
     409        }
     410        Collections.sort(feature_model);
     411        part_model = new Vector();
     412        part_model.add("");//get("Custom"));
     413        part_model.add("DateList");
     414        part_model.add("HList");
     415        part_model.add("Invisible");
     416        part_model.add("VList");
     417        special_model = new Vector();
     418        special_model.add("[Text]");
     419        special_model.add("[link]");
     420        special_model.add("[/link]");
     421        special_model.add("[icon]");
     422        special_model.add("[num]");
     423        special_model.add("[parent():_]");
     424        special_model.add("[parent(Top):_]");
     425        special_model.add("[parent(All'_'):_]");
     426        Vector elements = gatherer.c_man.msm.getAssignedElements();
     427        for(int i = 0; i < elements.size(); i++) {
     428        special_model.add("[" + ((ElementWrapper)elements.get(i)).toString() + "]");
     429        }
     430        Collections.sort(special_model);
    431431                // Create
    432                 add = new JButton(get("Add"));
    433                 add.setEnabled(false);
    434                 blank_pane = new JPanel();
    435                 button_group = new ButtonGroup();
    436                 card_layout = new CardLayout();
    437                 control_pane = new JPanel();
    438                 editor = new JTextArea();
    439                 editor.setCaretPosition(0);
    440                 editor.setLineWrap(true);
    441                 editor.setWrapStyleWord(true);
    442                 editor_label = new JLabel(get("Editor"));
    443                 editor_label.setHorizontalAlignment(JLabel.CENTER);
    444                 editor_pane = new JPanel();
    445                 feature = new JComboBox(feature_model.toArray());
    446                 feature.setEditable(true);
    447                 feature_label = new JLabel(get("Feature"));
    448                 feature_label.setPreferredSize(LABEL_SIZE);
    449                 format_list = new JList(model);
    450                 format_list_label = new JLabel(get("Assigned_Formats"));
    451                 format_list_pane = new JPanel();
    452                 feature_pane = new JPanel();
    453                 header_pane = new JPanel();
    454                 inner_button_pane = new JPanel();
    455                 inner_state_pane = new JPanel();
    456                 inner_value_pane = new JPanel();
    457                 insert = new JButton(get("Insert"));
    458                 instructions = new JTextArea(get("Instructions"));
    459                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    460                 instructions.setEditable(false);
    461                 instructions.setLineWrap(true);
    462                 instructions.setRows(4);
    463                 instructions.setWrapStyleWord(true);
    464                 off = new JToggleButton(get("Off"));
    465                 off.setSelected(false);
    466                 on = new JToggleButton(get("On"));
    467                 on.setSelected(true);
    468                 options_pane = new JPanel();
    469                 outer_button_pane = new JPanel();
    470                 part = new JComboBox(part_model);
    471                 part.setEditable(true);
    472                 part_label = new JLabel(get("Part"));
    473                 part_label.setPreferredSize(LABEL_SIZE);
    474                 part_pane = new JPanel();
    475                 preview = new JButton(get("Preview"));
    476                 preview.setEnabled(false);
    477                 remove = new JButton(get("Remove"));
    478                 remove.setEnabled(false);
    479                 special = new JComboBox(special_model);
    480                 special_label = new JLabel(get("Special"));
    481                 special_label.setHorizontalAlignment(JLabel.CENTER);
    482                 special_pane = new JPanel();
    483                 state_pane = new JPanel();
    484                 title = new JLabel(get("Title"));
    485                 title.setHorizontalAlignment(JLabel.CENTER);
    486                 title.setOpaque(true);
    487                 value = new JTextField();
    488                 value_label = new JLabel(get("Value"));
    489                 value_pane = new JPanel();
    490                 view_pane = new JPanel();
     432        add = new JButton(get("Add"));
     433        add.setEnabled(false);
     434        blank_pane = new JPanel();
     435        button_group = new ButtonGroup();
     436        card_layout = new CardLayout();
     437        control_pane = new JPanel();
     438        editor = new JTextArea();
     439        editor.setCaretPosition(0);
     440        editor.setLineWrap(true);
     441        editor.setWrapStyleWord(true);
     442        editor_label = new JLabel(get("Editor"));
     443        editor_label.setHorizontalAlignment(JLabel.CENTER);
     444        editor_pane = new JPanel();
     445        feature = new JComboBox(feature_model.toArray());
     446        feature.setEditable(true);
     447        feature_label = new JLabel(get("Feature"));
     448        feature_label.setPreferredSize(LABEL_SIZE);
     449        format_list = new JList(model);
     450        format_list_label = new JLabel(get("Assigned_Formats"));
     451        format_list_pane = new JPanel();
     452        feature_pane = new JPanel();
     453        header_pane = new JPanel();
     454        inner_button_pane = new JPanel();
     455        inner_state_pane = new JPanel();
     456        inner_value_pane = new JPanel();
     457        insert = new JButton(get("Insert"));
     458        instructions = new JTextArea(get("Instructions"));
     459        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     460        instructions.setEditable(false);
     461        instructions.setLineWrap(true);
     462        instructions.setRows(4);
     463        instructions.setWrapStyleWord(true);
     464        off = new JToggleButton(get("Off"));
     465        off.setSelected(false);
     466        on = new JToggleButton(get("On"));
     467        on.setSelected(true);
     468        options_pane = new JPanel();
     469        outer_button_pane = new JPanel();
     470        part = new JComboBox(part_model);
     471        part.setEditable(true);
     472        part_label = new JLabel(get("Part"));
     473        part_label.setPreferredSize(LABEL_SIZE);
     474        part_pane = new JPanel();
     475        preview = new JButton(get("Preview"));
     476        preview.setEnabled(false);
     477        remove = new JButton(get("Remove"));
     478        remove.setEnabled(false);
     479        special = new JComboBox(special_model);
     480        special_label = new JLabel(get("Special"));
     481        special_label.setHorizontalAlignment(JLabel.CENTER);
     482        special_pane = new JPanel();
     483        state_pane = new JPanel();
     484        title = new JLabel(get("Title"));
     485        title.setHorizontalAlignment(JLabel.CENTER);
     486        title.setOpaque(true);
     487        value = new JTextField();
     488        value_label = new JLabel(get("Value"));
     489        value_pane = new JPanel();
     490        view_pane = new JPanel();
    491491                // Connect
    492                 add.addActionListener(new AddListener());
    493                 button_group.add(on);
    494                 button_group.add(off);
    495                 editor.addKeyListener(new EditorListener());
    496                 feature.addActionListener(new FeatureListener());
    497                 format_list.addListSelectionListener(new FormatListListener());
    498                 insert.addActionListener(new InsertListener());
    499                 off.addActionListener(new StateListener());
    500                 on.addActionListener(new StateListener());
    501                 part.addActionListener(new PartListener());
    502                 preview.addActionListener(new PreviewListener());
    503                 remove.addActionListener(new RemoveListener());
    504                 value.addKeyListener(new ValueListener());
     492        add.addActionListener(new AddListener());
     493        button_group.add(on);
     494        button_group.add(off);
     495        editor.addKeyListener(new EditorListener());
     496        feature.addActionListener(new FeatureListener());
     497        format_list.addListSelectionListener(new FormatListListener());
     498        insert.addActionListener(new InsertListener());
     499        off.addActionListener(new StateListener());
     500        on.addActionListener(new StateListener());
     501        part.addActionListener(new PartListener());
     502        preview.addActionListener(new PreviewListener());
     503        remove.addActionListener(new RemoveListener());
     504        value.addKeyListener(new ValueListener());
    505505                // Layout
    506                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    507 
    508                 header_pane.setLayout(new BorderLayout());
    509                 header_pane.add(title, BorderLayout.NORTH);
    510                 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    511 
    512                 format_list_label.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    513 
    514                 format_list_pane.setLayout(new BorderLayout());
    515                 format_list_pane.add(format_list_label, BorderLayout.NORTH);
    516                 format_list_pane.add(new JScrollPane(format_list), BorderLayout.CENTER);
    517 
    518                 feature_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    519 
    520                 feature_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    521                 feature_pane.setLayout(new BorderLayout());
    522                 feature_pane.add(feature_label, BorderLayout.WEST);
    523                 feature_pane.add(feature, BorderLayout.CENTER);
    524 
    525                 part_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    526 
    527                 part_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    528                 part_pane.setLayout(new BorderLayout());
    529                 part_pane.add(part_label, BorderLayout.WEST);
    530                 part_pane.add(part, BorderLayout.CENTER);
    531 
    532                 options_pane.setLayout(new GridLayout(2,1));
    533                 options_pane.add(feature_pane);
    534                 options_pane.add(part_pane);
    535 
    536                 inner_state_pane = new JPanel(new GridLayout(1,2));
    537                 inner_state_pane.add(on);
    538                 inner_state_pane.add(off);
    539 
    540                 state_pane.setLayout(new BorderLayout());
    541                 state_pane.add(inner_state_pane, BorderLayout.NORTH);
    542                 state_pane.add(new JPanel(), BorderLayout.CENTER);
    543 
    544                 value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    545 
    546                 inner_value_pane.setLayout(new BorderLayout());
    547                 inner_value_pane.add(value_label, BorderLayout.WEST);
    548                 inner_value_pane.add(value, BorderLayout.CENTER);
    549 
    550                 value_pane.setLayout(new BorderLayout());
    551                 value_pane.add(inner_value_pane, BorderLayout.NORTH);
    552                 value_pane.add(new JPanel(), BorderLayout.CENTER);
    553 
    554                 special_pane.setLayout(new GridLayout(3,1));
    555                 special_pane.add(special_label);
    556                 special_pane.add(special);
    557                 special_pane.add(insert);
    558 
    559                 editor_pane.setLayout(new BorderLayout());
    560                 editor_pane.add(editor_label, BorderLayout.NORTH);
    561                 editor_pane.add(new JScrollPane(editor), BorderLayout.CENTER);
    562                 editor_pane.add(special_pane, BorderLayout.EAST);
     506        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     507
     508        header_pane.setLayout(new BorderLayout());
     509        header_pane.add(title, BorderLayout.NORTH);
     510        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     511
     512        format_list_label.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     513
     514        format_list_pane.setLayout(new BorderLayout());
     515        format_list_pane.add(format_list_label, BorderLayout.NORTH);
     516        format_list_pane.add(new JScrollPane(format_list), BorderLayout.CENTER);
     517
     518        feature_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     519
     520        feature_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     521        feature_pane.setLayout(new BorderLayout());
     522        feature_pane.add(feature_label, BorderLayout.WEST);
     523        feature_pane.add(feature, BorderLayout.CENTER);
     524
     525        part_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     526
     527        part_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     528        part_pane.setLayout(new BorderLayout());
     529        part_pane.add(part_label, BorderLayout.WEST);
     530        part_pane.add(part, BorderLayout.CENTER);
     531
     532        options_pane.setLayout(new GridLayout(2,1));
     533        options_pane.add(feature_pane);
     534        options_pane.add(part_pane);
     535
     536        inner_state_pane = new JPanel(new GridLayout(1,2));
     537        inner_state_pane.add(on);
     538        inner_state_pane.add(off);
     539
     540        state_pane.setLayout(new BorderLayout());
     541        state_pane.add(inner_state_pane, BorderLayout.NORTH);
     542        state_pane.add(new JPanel(), BorderLayout.CENTER);
     543
     544        value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     545
     546        inner_value_pane.setLayout(new BorderLayout());
     547        inner_value_pane.add(value_label, BorderLayout.WEST);
     548        inner_value_pane.add(value, BorderLayout.CENTER);
     549
     550        value_pane.setLayout(new BorderLayout());
     551        value_pane.add(inner_value_pane, BorderLayout.NORTH);
     552        value_pane.add(new JPanel(), BorderLayout.CENTER);
     553
     554        special_pane.setLayout(new GridLayout(3,1));
     555        special_pane.add(special_label);
     556        special_pane.add(special);
     557        special_pane.add(insert);
     558
     559        editor_pane.setLayout(new BorderLayout());
     560        editor_pane.add(editor_label, BorderLayout.NORTH);
     561        editor_pane.add(new JScrollPane(editor), BorderLayout.CENTER);
     562        editor_pane.add(special_pane, BorderLayout.EAST);
    563563
    564564                // Magic for view_pane card layout.
    565                 view_pane.setLayout(card_layout);
    566                 view_pane.add(editor_pane, CUSTOM);
    567                 view_pane.add(state_pane, FLAG);
     565        view_pane.setLayout(card_layout);
     566        view_pane.add(editor_pane, CUSTOM);
     567        view_pane.add(state_pane, FLAG);
    568568                //view_pane.add(value_pane, PARAM);
    569569
    570                 inner_button_pane.setLayout(new GridLayout(1,2));
    571                 inner_button_pane.add(add);
    572                 inner_button_pane.add(remove);
    573 
    574                 outer_button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    575                 outer_button_pane.setLayout(new GridLayout(1,1));
    576                 outer_button_pane.add(inner_button_pane);
     570        inner_button_pane.setLayout(new GridLayout(1,2));
     571        inner_button_pane.add(add);
     572        inner_button_pane.add(remove);
     573
     574        outer_button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
     575        outer_button_pane.setLayout(new GridLayout(1,1));
     576        outer_button_pane.add(inner_button_pane);
    577577                //outer_button_pane.add(preview);
    578578
    579                 control_pane.setLayout(new BorderLayout());
    580                 control_pane.add(options_pane, BorderLayout.NORTH);
    581                 control_pane.add(view_pane, BorderLayout.CENTER);
    582                 control_pane.add(outer_button_pane, BorderLayout.SOUTH);
    583 
    584                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    585                 setLayout(new BorderLayout());
    586                 add(header_pane, BorderLayout.NORTH);
    587                 add(format_list_pane, BorderLayout.CENTER);
    588                 add(control_pane, BorderLayout.SOUTH);
    589                 ready = true;
    590           }
    591           public void destroy() {
    592           }
    593           /** Overriden to ensure that the instructions pane is scrolled to the top.
     579        control_pane.setLayout(new BorderLayout());
     580        control_pane.add(options_pane, BorderLayout.NORTH);
     581        control_pane.add(view_pane, BorderLayout.CENTER);
     582        control_pane.add(outer_button_pane, BorderLayout.SOUTH);
     583
     584        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     585        setLayout(new BorderLayout());
     586        add(header_pane, BorderLayout.NORTH);
     587        add(format_list_pane, BorderLayout.CENTER);
     588        add(control_pane, BorderLayout.SOUTH);
     589        ready = true;
     590    }
     591    public void destroy() {
     592    }
     593    /** Overriden to ensure that the instructions pane is scrolled to the top.
    594594            */
    595           public void updateUI() {
    596                 if(ready) {
    597                      // Rebuild feature model.
    598                      ArrayList feature_model = new ArrayList();
    599                      // Add the set options
    600                      for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
    601                           feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
    602                      }
    603                      // Now the classifiers.
    604                      for(int j = 0; j < manager.classifiers.size(); j++) {
    605                           feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
    606                      }
    607                      feature.setModel(new DefaultComboBoxModel(feature_model.toArray()));
    608                      if(instructions != null) {
    609                           instructions.setCaretPosition(0);
    610                      }
    611                 }
    612                 super.updateUI();
    613           }
    614 
    615 
    616 
    617           /** Formats the formatting string so that it contains safe characters and isn't enclosed in speech marks etc. (Ironic eh?)
     595    public void updateUI() {
     596        if(ready) {
     597        // Rebuild feature model.
     598        ArrayList feature_model = new ArrayList();
     599        // Add the set options
     600        for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
     601            feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
     602        }
     603        // Now the classifiers.
     604        for(int j = 0; j < manager.classifiers.size(); j++) {
     605            feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
     606        }
     607        feature.setModel(new DefaultComboBoxModel(feature_model.toArray()));
     608        if(instructions != null) {
     609            instructions.setCaretPosition(0);
     610        }
     611        }
     612        super.updateUI();
     613    }
     614
     615
     616
     617    /** Formats the formatting string so that it contains safe characters and isn't enclosed in speech marks etc. (Ironic eh?)
    618618            * @see java.lang.StringBuffer
    619619            */
    620           private String format(String raw) {
    621                 String safe = null;
    622                 if(raw != null && raw.length() > 0) {
    623                      StringBuffer temp = new StringBuffer(raw);
    624                      // Remove quotes at start and end. Look at my wiggly save three lines of code skills.
    625                      char start = ' ';
    626                      while(temp.length() > 0 && (start = temp.charAt(0)) == '\"' || start == '\'') {
    627                           temp.delete(0, 1);
    628                      }
    629                      int length = 0;
    630                      char end = ' ';
    631                      while((length = temp.length()) > 0 && (end = temp.charAt(length - 1)) == '\"' || end == '\'') {
    632                           temp.delete(length - 1, length);
    633                      }
    634                      // Now escape quotes within the format string
    635                      int quote_index = -1;
    636                      while((quote_index = temp.indexOf("\"", quote_index + 1)) != -1) {
    637                           temp.replace(quote_index, quote_index + 1, "\\\"");
    638                           quote_index = quote_index + 1;
    639                      }
    640                      // Done.
    641                      safe = temp.toString();
    642                 }
    643                 return safe;
    644           }
    645           /** Remove safe characters from string replacing them with unsafe ones.
     620    private String format(String raw) {
     621        String safe = null;
     622        if(raw != null && raw.length() > 0) {
     623        StringBuffer temp = new StringBuffer(raw);
     624        // Remove quotes at start and end. Look at my wiggly save three lines of code skills.
     625        char start = ' ';
     626        while(temp.length() > 0 && (start = temp.charAt(0)) == '\"' || start == '\'') {
     627            temp.delete(0, 1);
     628        }
     629        int length = 0;
     630        char end = ' ';
     631        while((length = temp.length()) > 0 && (end = temp.charAt(length - 1)) == '\"' || end == '\'') {
     632            temp.delete(length - 1, length);
     633        }
     634        // Now escape quotes within the format string
     635        int quote_index = -1;
     636        while((quote_index = temp.indexOf("\"", quote_index + 1)) != -1) {
     637            temp.replace(quote_index, quote_index + 1, "\\\"");
     638            quote_index = quote_index + 1;
     639        }
     640        // Done.
     641        safe = temp.toString();
     642        }
     643        return safe;
     644    }
     645    /** Remove safe characters from string replacing them with unsafe ones.
    646646            * @see java.lang.StringBuffer
    647647            */
    648           private String unformat(String safe) {
    649                 String raw = null;
    650                 if(safe != null && safe.length() > 0) {
    651                      StringBuffer temp = new StringBuffer(safe);
    652                      int quote_index = -1;
    653                      while((quote_index = temp.indexOf("\\\"")) != -1) {
    654                           temp.replace(quote_index, quote_index + 2, "\"");
    655                      }
    656                      raw = temp.toString();
    657                 }
    658                 return raw;
    659           }
    660           /** Listens for clicks on the add button, and if the relevant details are provided adds a new format. */
    661           private class AddListener
    662                 implements ActionListener {
    663                 public void actionPerformed(ActionEvent event) {
    664                      ignore = true;
    665                      Entry entry = (Entry)feature.getSelectedItem();
    666                      Object f = entry.getFeature();
    667                      String p = (String)part.getSelectedItem();
    668                      if(view_type.equals(FLAG)) {
    669                           current_format = new Format(f, p, on.isSelected());
    670                      }
    671                      else {
    672                           current_format = new Format(f, p, format(Utility.stripNL(editor.getText())));
    673                      }
    674                      addFormat(current_format);
    675                      add.setEnabled(false);
    676                      remove.setEnabled(true);
    677                      // Update list selection
    678                      format_list.setSelectedValue(current_format, true);
    679                      new_entry = false;
    680                      ignore = false;
    681                 }
    682           }
    683           private class EditorListener
    684                 extends KeyAdapter {
    685                 public void keyReleased(KeyEvent event) {
    686                      String safe = format(editor.getText());
    687                      if(!ignore && current_format != null) {
    688                           // We have just performed an edit. Immediately update the format and model.
    689                           if(safe != null) {
    690                                 current_format.setValue(safe);
    691                           }
    692                           else {
    693                                 current_format.setValue("");
    694                           }
    695                           gatherer.c_man.configurationChanged();
    696                           model.refresh();
    697                      }
    698                      Entry entry = (Entry) feature.getSelectedItem();
    699                      String name = entry.toString();
    700                      if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && safe != null && safe.length() != 0 && new_entry) {
    701                           add.setEnabled(true);
    702                      }
    703                      else {
    704                           add.setEnabled(false);
    705                      }
    706                 }
    707           }
    708           /** This object provides a wrapping around an entry in the format target control, which is tranparent as to whether it is backed by a String or a Classifier. */
    709           private class Entry
    710                 implements Comparable {
    711                 private Classifier classifier = null;
    712                 private CustomClassifier custom_classifier = null;
    713                 private String text = null;
    714                 public Entry(Object object) {
    715                      if(object instanceof Classifier) {
    716                           classifier = (Classifier)object;
    717                      }
    718                      if(object instanceof CustomClassifier) {
    719                           custom_classifier = (CustomClassifier)object;
    720                      }
    721                      else if(object instanceof String) {
    722                           text = (String)object;
    723                      }
    724                      else {
    725                           text = "";
    726                      }
    727                 }
    728                 public Entry(String text) {
    729                      this.text = text;
    730                 }
    731                 public int compareTo(Object object) {
    732                      if(object == null) {
    733                           return 1;
    734                      }
    735                      if(toString() == null) {
    736                           return -1;
    737                      }
    738                      else {
    739                           String object_str = object.toString();
    740                           if(object_str == null) {
    741                                 return 1;
    742                           }
    743                           return toString().compareTo(object_str);
    744                      }
    745                 }
    746                 public boolean equals(Object object) {
    747                      if(compareTo(object) == 0) {
    748                           return true;
    749                      }
    750                      return false;
    751                 }
    752                 public Classifier getClassifier() {
    753                      return classifier;
    754                 }
    755                 public CustomClassifier getCustomClassifier() {
    756                      return custom_classifier;
    757                 }
    758                 public Object getFeature() {
    759                      if(classifier != null) {
    760                           return classifier;
    761                      }
    762                      return text;
    763                 }
    764                 public String toString() {
    765                      if(classifier != null) {
    766                           String name = classifier.toString();
    767                           return name.substring(9);
    768                      }
    769                      if(custom_classifier != null) {
    770                           String name = custom_classifier.toString();
    771                           return name;//.substring(17);
    772                      }
    773                      return text;
    774                 }
    775           }
    776           private class FeatureListener
    777                 implements ActionListener {
    778                 public void actionPerformed(ActionEvent event) {
    779                      if(!ignore) {
    780                           current_format = null;
    781                           Entry entry = (Entry) feature.getSelectedItem();
    782                           String name = entry.toString();
    783                           int type = Format.getType(name);
    784                           switch(type) {
    785                           case Format.FLAG:
    786                                 // Flags first.
    787                                 part.setEnabled(false);
    788                                 part_pane.remove(part);
    789                                 card_layout.show(view_pane, FLAG);
    790                                 view_type = FLAG;
    791                                 add.setEnabled(true); // One of the options must be selected.
    792                                 break;
    793                           default:
    794                                 part.setEnabled(true);
    795                                 part_pane.add(part, BorderLayout.CENTER);
    796                                 card_layout.show(view_pane, CUSTOM);
    797                                 view_type = CUSTOM;
    798                                 if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && editor.getText().length() != 0) {
    799                                     add.setEnabled(true);
    800                                 }
    801                                 else {
    802                                     add.setEnabled(false);
    803                                 }
    804                           }
    805                           control_pane.updateUI();
    806                           new_entry = true;
    807                      }
    808                 }
    809           }
    810           private class FormatListListener
    811                 implements ListSelectionListener {
    812                 public void valueChanged(ListSelectionEvent event) {
    813                      if(!ignore) {
    814                           if(!format_list.isSelectionEmpty()) {
    815                                 ignore = true;
    816                                 current_format = (Format)format_list.getSelectedValue();
    817                                 // Try to match the target, remembering the entries within are Entry's
    818                                 Entry an_entry = new Entry(current_format.getFeature());
    819                                 feature.setSelectedItem(an_entry);
    820                                 // Try to match the part.
    821                                 part.setSelectedItem(current_format.getPart());
    822                                 // Now use type to determine what controls are visible, and what have initial values.
    823                                 switch(current_format.getType()) {
    824                                 case Format.FLAG:
    825                                     // Flags first.
    826                                     part.setEnabled(false);
    827                                     part_pane.remove(part);
    828                                     card_layout.show(view_pane, FLAG);
    829                                     view_type = FLAG;
    830                                     // Initial value
    831                                     on.setSelected(current_format.getState());
    832                                     off.setSelected(!current_format.getState());
    833                                     add.setEnabled(false); // Can only update
    834                                     break;
    835                                 default:
    836                                     part.setEnabled(true);
    837                                     part_pane.add(part, BorderLayout.CENTER);
    838                                     card_layout.show(view_pane, CUSTOM);
    839                                     view_type = CUSTOM;
    840                                     // Initial value
    841                                     editor.setText(unformat(current_format.getValue()));
    842                                     add.setEnabled(false);
    843                                 }
    844                                 control_pane.updateUI();
    845                                 ignore = false;
    846                                 preview.setEnabled(true);
    847                                 remove.setEnabled(true);
    848                                 new_entry = false;
    849                           }
    850                           else {
    851                                 preview.setEnabled(false);
    852                                 remove.setEnabled(false);
    853                           }
    854                      }
    855                 }
    856           }
    857           private class InsertListener
    858                 implements ActionListener {
    859                 public void actionPerformed(ActionEvent event) {
    860                      editor.insert((String)special.getSelectedItem(), editor.getCaretPosition());
    861                 }
    862           }
    863           private class PartListener
    864                 implements ActionListener {
    865                 public void actionPerformed(ActionEvent event) {
    866                      if(!ignore) {
    867                           current_format = null;
    868                           Entry entry = (Entry) feature.getSelectedItem();
    869                           String name = entry.toString();
    870                           if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && editor.getText().length() != 0) {
    871                                 add.setEnabled(true);
    872                           }
    873                           else {
    874                                 add.setEnabled(false);
    875                           }
    876                           new_entry = true;
    877                      }
    878                 }
    879           }
    880           private class PreviewListener
    881                 implements ActionListener {
    882                 public void actionPerformed(ActionEvent event) {
    883                 }
    884           }
    885           private class RemoveListener
    886                 implements ActionListener {
    887                 public void actionPerformed(ActionEvent event) {
    888                      if(!format_list.isSelectionEmpty()) {
    889                           removeFormat((Format)format_list.getSelectedValue());
    890                           // Change buttons
    891                           add.setEnabled(true);
    892                           remove.setEnabled(false);
    893                      }
    894                 }
    895           }
    896           private class StateListener
    897                 implements ActionListener {
    898                 public void actionPerformed(ActionEvent event) {
    899                      if(!ignore && current_format != null) {
    900                           // We have just performed an edit. Immediately update the format and model.
    901                           current_format.setState(on.isSelected());
    902                           model.refresh();
    903                      }
    904                 }
    905           }
    906           private class ValueListener
    907                 extends KeyAdapter {
    908                 public void keyReleased(KeyEvent event) {
    909                      if(!ignore && current_format != null) {
    910                           // We have just performed an edit. Immediately update the format and model.
    911                           current_format.setValue(value.getText());
    912                           model.refresh();
    913                      }
    914                 }
    915           }
    916     }
     648    private String unformat(String safe) {
     649        String raw = null;
     650        if(safe != null && safe.length() > 0) {
     651        StringBuffer temp = new StringBuffer(safe);
     652        int quote_index = -1;
     653        while((quote_index = temp.indexOf("\\\"")) != -1) {
     654            temp.replace(quote_index, quote_index + 2, "\"");
     655        }
     656        raw = temp.toString();
     657        }
     658        return raw;
     659    }
     660    /** Listens for clicks on the add button, and if the relevant details are provided adds a new format. */
     661    private class AddListener
     662        implements ActionListener {
     663        public void actionPerformed(ActionEvent event) {
     664        ignore = true;
     665        Entry entry = (Entry)feature.getSelectedItem();
     666        Object f = entry.getFeature();
     667        String p = (String)part.getSelectedItem();
     668        if(view_type.equals(FLAG)) {
     669            current_format = new Format(f, p, on.isSelected());
     670        }
     671        else {
     672            current_format = new Format(f, p, format(Utility.stripNL(editor.getText())));
     673        }
     674        addFormat(current_format);
     675        add.setEnabled(false);
     676        remove.setEnabled(true);
     677        // Update list selection
     678        format_list.setSelectedValue(current_format, true);
     679        new_entry = false;
     680        ignore = false;
     681        }
     682    }
     683    private class EditorListener
     684        extends KeyAdapter {
     685        public void keyReleased(KeyEvent event) {
     686        String safe = format(editor.getText());
     687        if(!ignore && current_format != null) {
     688            // We have just performed an edit. Immediately update the format and model.
     689            if(safe != null) {
     690            current_format.setValue(safe);
     691            }
     692            else {
     693            current_format.setValue("");
     694            }
     695            gatherer.c_man.configurationChanged();
     696            model.refresh();
     697        }
     698        Entry entry = (Entry) feature.getSelectedItem();
     699        String name = entry.toString();
     700        if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && safe != null && safe.length() != 0 && new_entry) {
     701            add.setEnabled(true);
     702        }
     703        else {
     704            add.setEnabled(false);
     705        }
     706        }
     707    }
     708    /** This object provides a wrapping around an entry in the format target control, which is tranparent as to whether it is backed by a String or a Classifier. */
     709    private class Entry
     710        implements Comparable {
     711        private Classifier classifier = null;
     712        private CustomClassifier custom_classifier = null;
     713        private String text = null;
     714        public Entry(Object object) {
     715        if(object instanceof Classifier) {
     716            classifier = (Classifier)object;
     717        }
     718        if(object instanceof CustomClassifier) {
     719            custom_classifier = (CustomClassifier)object;
     720        }
     721        else if(object instanceof String) {
     722            text = (String)object;
     723        }
     724        else {
     725            text = "";
     726        }
     727        }
     728        public Entry(String text) {
     729        this.text = text;
     730        }
     731        public int compareTo(Object object) {
     732        if(object == null) {
     733            return 1;
     734        }
     735        if(toString() == null) {
     736            return -1;
     737        }
     738        else {
     739            String object_str = object.toString();
     740            if(object_str == null) {
     741            return 1;
     742            }
     743            return toString().compareTo(object_str);
     744        }
     745        }
     746        public boolean equals(Object object) {
     747        if(compareTo(object) == 0) {
     748            return true;
     749        }
     750        return false;
     751        }
     752        public Classifier getClassifier() {
     753        return classifier;
     754        }
     755        public CustomClassifier getCustomClassifier() {
     756        return custom_classifier;
     757        }
     758        public Object getFeature() {
     759        if(classifier != null) {
     760            return classifier;
     761        }
     762        return text;
     763        }
     764        public String toString() {
     765        if(classifier != null) {
     766            String name = classifier.toString();
     767            return name.substring(9);
     768        }
     769        if(custom_classifier != null) {
     770            String name = custom_classifier.toString();
     771            return name;//.substring(17);
     772        }
     773        return text;
     774        }
     775    }
     776    private class FeatureListener
     777        implements ActionListener {
     778        public void actionPerformed(ActionEvent event) {
     779        if(!ignore) {
     780            current_format = null;
     781            Entry entry = (Entry) feature.getSelectedItem();
     782            String name = entry.toString();
     783            int type = Format.getType(name);
     784            switch(type) {
     785            case Format.FLAG:
     786            // Flags first.
     787            part.setEnabled(false);
     788            part_pane.remove(part);
     789            card_layout.show(view_pane, FLAG);
     790            view_type = FLAG;
     791            add.setEnabled(true); // One of the options must be selected.
     792            break;
     793            default:
     794            part.setEnabled(true);
     795            part_pane.add(part, BorderLayout.CENTER);
     796            card_layout.show(view_pane, CUSTOM);
     797            view_type = CUSTOM;
     798            if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && editor.getText().length() != 0) {
     799                add.setEnabled(true);
     800            }
     801            else {
     802                add.setEnabled(false);
     803            }
     804            }
     805            control_pane.updateUI();
     806            new_entry = true;
     807        }
     808        }
     809    }
     810    private class FormatListListener
     811        implements ListSelectionListener {
     812        public void valueChanged(ListSelectionEvent event) {
     813        if(!ignore) {
     814            if(!format_list.isSelectionEmpty()) {
     815            ignore = true;
     816            current_format = (Format)format_list.getSelectedValue();
     817            // Try to match the target, remembering the entries within are Entry's
     818            Entry an_entry = new Entry(current_format.getFeature());
     819            feature.setSelectedItem(an_entry);
     820            // Try to match the part.
     821            part.setSelectedItem(current_format.getPart());
     822            // Now use type to determine what controls are visible, and what have initial values.
     823            switch(current_format.getType()) {
     824            case Format.FLAG:
     825                // Flags first.
     826                part.setEnabled(false);
     827                part_pane.remove(part);
     828                card_layout.show(view_pane, FLAG);
     829                view_type = FLAG;
     830                // Initial value
     831                on.setSelected(current_format.getState());
     832                off.setSelected(!current_format.getState());
     833                add.setEnabled(false); // Can only update
     834                break;
     835            default:
     836                part.setEnabled(true);
     837                part_pane.add(part, BorderLayout.CENTER);
     838                card_layout.show(view_pane, CUSTOM);
     839                view_type = CUSTOM;
     840                // Initial value
     841                editor.setText(unformat(current_format.getValue()));
     842                add.setEnabled(false);
     843            }
     844            control_pane.updateUI();
     845            ignore = false;
     846            preview.setEnabled(true);
     847            remove.setEnabled(true);
     848            new_entry = false;
     849            }
     850            else {
     851            preview.setEnabled(false);
     852            remove.setEnabled(false);
     853            }
     854        }
     855        }
     856    }
     857    private class InsertListener
     858        implements ActionListener {
     859        public void actionPerformed(ActionEvent event) {
     860        editor.insert((String)special.getSelectedItem(), editor.getCaretPosition());
     861        }
     862    }
     863    private class PartListener
     864        implements ActionListener {
     865        public void actionPerformed(ActionEvent event) {
     866        if(!ignore) {
     867            current_format = null;
     868            Entry entry = (Entry) feature.getSelectedItem();
     869            String name = entry.toString();
     870            if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && editor.getText().length() != 0) {
     871            add.setEnabled(true);
     872            }
     873            else {
     874            add.setEnabled(false);
     875            }
     876            new_entry = true;
     877        }
     878        }
     879    }
     880    private class PreviewListener
     881        implements ActionListener {
     882        public void actionPerformed(ActionEvent event) {
     883        }
     884    }
     885    private class RemoveListener
     886        implements ActionListener {
     887        public void actionPerformed(ActionEvent event) {
     888        if(!format_list.isSelectionEmpty()) {
     889            removeFormat((Format)format_list.getSelectedValue());
     890            // Change buttons
     891            add.setEnabled(true);
     892            remove.setEnabled(false);
     893        }
     894        }
     895    }
     896    private class StateListener
     897        implements ActionListener {
     898        public void actionPerformed(ActionEvent event) {
     899        if(!ignore && current_format != null) {
     900            // We have just performed an edit. Immediately update the format and model.
     901            current_format.setState(on.isSelected());
     902            model.refresh();
     903        }
     904        }
     905    }
     906    private class ValueListener
     907        extends KeyAdapter {
     908        public void keyReleased(KeyEvent event) {
     909        if(!ignore && current_format != null) {
     910            // We have just performed an edit. Immediately update the format and model.
     911            current_format.setValue(value.getText());
     912            model.refresh();
     913        }
     914        }
     915    }
     916    }
    917917}
  • trunk/gli/src/org/greenstone/gatherer/cdm/GUI.java

    r4293 r4366  
    8686*/
    8787public class GUI
    88     extends JPanel {
    89     /** A reference to the collection manager, as it is here that all of the other data members and managers reside. */
    90     private CollectionDesignManager manager = null;
    91     /** The controls used to modify the general options. */
    92     private Control controls = null;
    93     /** A tree to serve as a 'table of contents' for this design tool. We decided on a tree rather than a list, as it allows us to break sections into subsections if they become to complicated. */
    94     private DesignTree tree = null;
    95     /** A reference to the Gatherer. */
    96     private Gatherer gatherer = null;
    97     /** The title located just above the content tree. */
    98     private JLabel title = null;
    99     /** The panel containing both the title and the tree. */
    100     private JPanel tree_pane = null;
    101     /** The panel apon which is rendered the currently selected section screen. */
    102     private JPanel view = null;
    103     /** The available subscreens. */
    104     static final public String CONTENTS[] = {"General", "Indexes", "Subcollections", "Languages", "Plugins", "Classifiers", "Formats", "MetadataSets"};
    105     /** The preferred size of the collection design module screen real-estate. */
    106     static final private Dimension SIZE = new Dimension(760, 500);
    107     /** Constructor.
    108       * @see DesignTree
    109       * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    110       */
    111     public GUI(Gatherer gatherer, CollectionDesignManager manager) {
    112           super();
    113           // Assignments
    114           this.gatherer = gatherer;
    115           this.manager = manager;
    116           // Creation
    117           this.title = new JLabel(get("Design_Topics"));
    118           this.tree = new DesignTree();
    119           this.tree_pane = new JPanel();
    120           this.view = getControls();
    121           // Connect
    122           tree.addTreeSelectionListener(new TreeListener());
    123           tree_pane.setLayout(new BorderLayout());
    124           tree_pane.add(title, BorderLayout.NORTH);
    125           tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
    126           // Layout
    127           setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    128           setLayout(new BorderLayout());
    129           add(tree_pane, BorderLayout.WEST);
    130           add(view, BorderLayout.CENTER);
    131     }
    132     /** Mark the current set of controls as invalid. If they are needed again in the future new controls will be generate.
     88    extends JPanel {
     89    /** A reference to the collection manager, as it is here that all of the other data members and managers reside. */
     90    private CollectionDesignManager manager = null;
     91    /** The controls used to modify the general options. */
     92    private Control controls = null;
     93    /** A tree to serve as a 'table of contents' for this design tool. We decided on a tree rather than a list, as it allows us to break sections into subsections if they become to complicated. */
     94    private DesignTree tree = null;
     95    /** A reference to the Gatherer. */
     96    private Gatherer gatherer = null;
     97    /** The title located just above the content tree. */
     98    private JLabel title = null;
     99    /** The panel containing both the title and the tree. */
     100    private JPanel tree_pane = null;
     101    /** The panel apon which is rendered the currently selected section screen. */
     102    private JPanel view = null;
     103    /** The available subscreens. */
     104    static final public String CONTENTS[] = {"General", "Indexes", "Subcollections", "Languages", "Plugins", "Classifiers", "Formats", "MetadataSets"};
     105    /** The preferred size of the collection design module screen real-estate. */
     106    static final private Dimension SIZE = new Dimension(760, 500);
     107    /** Constructor.
     108     * @see DesignTree
     109     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     110     */
     111    public GUI(Gatherer gatherer, CollectionDesignManager manager) {
     112    super();
     113    // Assignments
     114    this.gatherer = gatherer;
     115    this.manager = manager;
     116    // Creation
     117    this.title = new JLabel(get("Design_Topics"));
     118    this.tree = new DesignTree();
     119    this.tree_pane = new JPanel();
     120    this.view = getControls();
     121    // Connect
     122    tree.addTreeSelectionListener(new TreeListener());
     123    tree_pane.setLayout(new BorderLayout());
     124    tree_pane.add(title, BorderLayout.NORTH);
     125    tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
     126    // Layout
     127    setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
     128    setLayout(new BorderLayout());
     129    add(tree_pane, BorderLayout.WEST);
     130    add(view, BorderLayout.CENTER);
     131    }
     132    /** Mark the current set of controls as invalid. If they are needed again in the future new controls will be generate.
    133133    * @see org.greenstone.gatherer.cdm.GUI.Control
    134134    */
    135     public void invalidateControls() {
    136           if(controls != null) {
    137                 controls.destroy();
    138           }
    139           controls = null;
    140     }
    141     /** Force the display to show a certain pane of controls.
     135    public void invalidateControls() {
     136    if(controls != null) {
     137        controls.destroy();
     138    }
     139    controls = null;
     140    }
     141    /** Force the display to show a certain pane of controls.
    142142    * @param type A <strong>String</strong> giving the name of the submanager view we wish to display.
    143143    */
    144     public void setSelectedView(String type) {
    145           tree.setSelectedView(type);
    146     }
    147     /** Overrides the normal updateUI to ensure that the current view also recieves an update message.
     144    public void setSelectedView(String type) {
     145    tree.setSelectedView(type);
     146    }
     147    /** Overrides the normal updateUI to ensure that the current view also recieves an update message.
    148148    */
    149     public void updateUI() {
    150           if(view != null) {
    151                 view.updateUI();
    152           }
    153           super.updateUI();
    154     }
    155     /**Overridden so we can exit when window is closed
     149    public void updateUI() {
     150    if(view != null) {
     151        view.updateUI();
     152    }
     153    super.updateUI();
     154    }
     155    /**Overridden so we can exit when window is closed
    156156      * @param event A <strong>WindowsEvent</strong> that encapsulates all the information gathered about the event that called this method.
    157157      * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    158158      */
    159     protected void processWindowEvent(WindowEvent event) {
    160           if(event.getID() == WindowEvent.WINDOW_CLOSING) {
    161                 manager.save();
    162                 System.exit(0);
    163           }
    164     }
    165     /** Overloaded to call get with both a key and an empty argument array.
     159    protected void processWindowEvent(WindowEvent event) {
     160    if(event.getID() == WindowEvent.WINDOW_CLOSING) {
     161        manager.save();
     162        System.exit(0);
     163    }
     164    }
     165    /** Overloaded to call get with both a key and an empty argument array.
    166166      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    167167      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
    168168      */
    169     private String get(String key) {
    170           return get(key, null);
    171     }
    172     /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
     169    private String get(String key) {
     170    return get(key, null);
     171    }
     172    /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
    173173      * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
    174174      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     
    178178      * @see org.greenstone.gatherer.Dictionary
    179179      */
    180     private String get(String key, String args[]) {
    181           if(key.indexOf('.') == -1) {
    182                 key = "CDM.GUI." + key;
    183           }
    184           return gatherer.dictionary.get(key, args);
    185     }
    186     /** Because the CollectionDesignManager has enough to do, this class is resposible for generating the controls for the general options, all of which are stored in the aforementioned manager.
     180    private String get(String key, String args[]) {
     181    if(key.indexOf('.') == -1) {
     182        key = "CDM.GUI." + key;
     183    }
     184    return gatherer.dictionary.get(key, args);
     185    }
     186    /** Because the CollectionDesignManager has enough to do, this class is resposible for generating the controls for the general options, all of which are stored in the aforementioned manager.
    187187      * @return A <strong>JPanel</strong> containing controls for editing the general options.
    188188      */
    189     private JPanel getControls() {
    190           if(controls == null) {
    191                 controls = new Control();
    192           }
    193           return controls;
    194     }
    195     /** This class represents the visual component of the general options stored in the CollectionDesignManager. */
    196     private class Control
    197           extends JPanel {
    198             /** The collection metadata representing the extra or description of the collection. */
    199           private CollectionMeta collection_extra_data = null;
    200           /** The collection metadata representing the name of the collection. */
    201           private CollectionMeta collection_name_data = null;
    202           /** The collection metadata representing the icon file location of the collection. */
    203           private CollectionMeta icon_collection_data = null;
    204           /** The default size of label on this control. */
    205           private Dimension LABEL_SIZE = new Dimension(200,25);
    206           /** The checkbox controlling public access to the collection. */
    207           private JCheckBox access = null;
    208           /** The checkbox controlling the state of the collection. */
    209           private JCheckBox beta = null;
    210           /** The label denoting the collection extra area. */
    211           private JLabel collection_extra_label = null;
    212           /** The label denoting the collection extra language (Default). */
    213           private JLabel collection_extra_language = null;
    214           /** The label denoting the collection name area. */
    215           private JLabel collection_name_label = null;
    216           /** The label denoting the name language (Default). */
    217           private JLabel collection_name_language = null;
    218           /** The label denoting the collection icon area. */
    219           private JLabel icon_collection_label = null;
    220           /** The label denoting the icon language (Default). */
    221           private JLabel icon_collection_language = null;
    222           /** The label which serves as the title of this view. */
    223           private JLabel title = null;
    224           /** The panel containing the access controls. */
    225           private JPanel access_pane = null;
    226           /** The panel containing the state controls. */
    227           private JPanel beta_pane = null;
    228           /** The central pane that will contain the view. */
    229           private JPanel central_pane = null;
    230           /** A panel used to affect internal layout of the collection extra area. */
    231           private JPanel collection_extra_inner_pane = null;
    232           /** The panel containing the collection extra area. */
    233           private JPanel collection_extra_pane = null;
    234           /** A panel used to affect internal layout of the collection name area. */
    235           private JPanel collection_name_inner_pane = null;
    236           /** The panel containing the collection name area. */
    237           private JPanel collection_name_pane = null;
    238           /** A panel used to affect internal layout of the collection icon area. */
    239           private JPanel icon_collection_inner_pane = null;
    240           /** The panel containing the icon area. */
    241           private JPanel icon_collection_pane = null;
    242           /** A text area used to display the inline help for this manager. */
    243           private JTextArea instructions = null;
    244           /** The text field used to edit the collections title. */
    245           private JTextField collection_name = null;
    246           /** The text field used to edit the file name of the collections icon. */
    247           private JTextField icon_collection = null;
    248           /** A text area used to modify the collection description. */
    249           private JTextArea collection_extra = null;
    250           /** Constructor.
    251           * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    252           * @see org.greenstone.gatherer.cdm.CollectionMeta
    253           * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    254           * @see org.greenstone.gatherer.cdm.Language
    255           * @see org.greenstone.gatherer.cdm.LanguageManager
    256           */
    257           public Control() {
    258                 super();
    259                 collection_extra_data = manager.collectionmetadatum.getCollectionExtra();
    260                 collection_name_data = manager.collectionmetadatum.getCollectionName();
    261                 icon_collection_data = manager.collectionmetadatum.getIconCollection();
     189    private JPanel getControls() {
     190    if(controls == null) {
     191        controls = new Control();
     192    }
     193    return controls;
     194    }
     195    /** This class represents the visual component of the general options stored in the CollectionDesignManager. */
     196    private class Control
     197    extends JPanel {
     198    /** The collection metadata representing the extra or description of the collection. */
     199    private CollectionMeta collection_extra_data = null;
     200    /** The collection metadata representing the name of the collection. */
     201    private CollectionMeta collection_name_data = null;
     202    /** The collection metadata representing the icon file location of the collection. */
     203    private CollectionMeta icon_collection_data = null;
     204    /** The default size of label on this control. */
     205    private Dimension LABEL_SIZE = new Dimension(200,25);
     206    /** The checkbox controlling public access to the collection. */
     207    private JCheckBox access = null;
     208    /** The checkbox controlling the state of the collection. */
     209    private JCheckBox beta = null;
     210    /** The label denoting the collection extra area. */
     211    private JLabel collection_extra_label = null;
     212    /** The label denoting the collection extra language (Default). */
     213    private JLabel collection_extra_language = null;
     214    /** The label denoting the collection name area. */
     215    private JLabel collection_name_label = null;
     216    /** The label denoting the name language (Default). */
     217    private JLabel collection_name_language = null;
     218    /** The label denoting the collection icon area. */
     219    private JLabel icon_collection_label = null;
     220    /** The label denoting the icon language (Default). */
     221    private JLabel icon_collection_language = null;
     222    /** The label which serves as the title of this view. */
     223    private JLabel title = null;
     224    /** The panel containing the access controls. */
     225    private JPanel access_pane = null;
     226    /** The panel containing the state controls. */
     227    private JPanel beta_pane = null;
     228    /** The central pane that will contain the view. */
     229    private JPanel central_pane = null;
     230    /** A panel used to affect internal layout of the collection extra area. */
     231    private JPanel collection_extra_inner_pane = null;
     232    /** The panel containing the collection extra area. */
     233    private JPanel collection_extra_pane = null;
     234    /** A panel used to affect internal layout of the collection name area. */
     235    private JPanel collection_name_inner_pane = null;
     236    /** The panel containing the collection name area. */
     237    private JPanel collection_name_pane = null;
     238    /** A panel used to affect internal layout of the collection icon area. */
     239    private JPanel icon_collection_inner_pane = null;
     240    /** The panel containing the icon area. */
     241    private JPanel icon_collection_pane = null;
     242    /** A text area used to display the inline help for this manager. */
     243    private JTextArea instructions = null;
     244    /** The text field used to edit the collections title. */
     245    private JTextField collection_name = null;
     246    /** The text field used to edit the file name of the collections icon. */
     247    private JTextField icon_collection = null;
     248    /** A text area used to modify the collection description. */
     249    private JTextArea collection_extra = null;
     250    /** Constructor.
     251    * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     252    * @see org.greenstone.gatherer.cdm.CollectionMeta
     253    * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     254    * @see org.greenstone.gatherer.cdm.Language
     255    * @see org.greenstone.gatherer.cdm.LanguageManager
     256    */
     257    public Control() {
     258        super();
     259        collection_extra_data = manager.collectionmetadatum.getCollectionExtra();
     260        collection_name_data = manager.collectionmetadatum.getCollectionName();
     261        icon_collection_data = manager.collectionmetadatum.getIconCollection();
    262262                // Creation.
    263                 access = new JCheckBox(get("CDM.General.Access"));
    264                 access.setSelected(manager.public_col);
    265                 access_pane = new JPanel();
    266                 beta = new JCheckBox(get("CDM.General.Beta"));
    267                 beta.setSelected(manager.beta);
    268                 beta_pane = new JPanel();
    269                 central_pane = new JPanel();
    270                 collection_extra = new JTextArea();
    271                 collection_extra_inner_pane = new JPanel();
    272                 collection_extra_label = new JLabel(get("CDM.General.Collection_Extra"));
    273                 collection_extra_label.setHorizontalAlignment(JLabel.CENTER);
    274                 collection_extra_language = new JLabel();
    275                 collection_extra_pane = new JPanel();
    276                 if(collection_extra_data != null) {
    277                      collection_extra.setText(collection_extra_data.getValue());
    278                      Language language = null;
    279                      if((language = collection_extra_data.getLanguage()) != null) {
    280                           collection_extra_language.setText(language.toString());
    281                      }
    282                      else {
    283                           collection_extra_language.setText(manager.languages.getDefaultLanguage().toString());
    284                      }
    285                 }
    286                 collection_name = new JTextField();
    287                 collection_name_inner_pane = new JPanel();
    288                 collection_name_label = new JLabel(get("CDM.General.Collection_Name"));
    289                 collection_name_label.setPreferredSize(LABEL_SIZE);
    290                 collection_name_language = new JLabel();
    291                 collection_name_pane = new JPanel();
    292                 if(collection_name_data != null) {
    293                      collection_name.setText(collection_name_data.getValue());
    294                      Language language = null;
    295                      if((language = collection_name_data.getLanguage()) != null) {
    296                           collection_name_language.setText(language.toString());
    297                      }
    298                      else {
    299                           collection_name_language.setText(manager.languages.getDefaultLanguage().toString());
    300                      }
    301                 }
    302                 icon_collection = new JTextField();
    303                 icon_collection_inner_pane = new JPanel();
    304                 icon_collection_label = new JLabel(get("CDM.General.Icon_Collection"));
    305                 icon_collection_label.setPreferredSize(LABEL_SIZE);
    306                 icon_collection_language = new JLabel();
    307                 icon_collection_pane = new JPanel();
    308                 if(icon_collection_data != null) {
    309                      icon_collection.setText(icon_collection_data.getValue());
    310                      Language language = null;
    311                      if((language = icon_collection_data.getLanguage()) != null) {
    312                           icon_collection_language.setText(language.toString());
    313                      }
    314                      else {
    315                           icon_collection_language.setText(manager.languages.getDefaultLanguage().toString());
    316                      }
    317                 }
    318                 instructions = new JTextArea(get("CDM.General.Instructions"));
    319                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    320                 instructions.setEditable(false);
    321                 instructions.setLineWrap(true);
    322                 instructions.setRows(4);
    323                 instructions.setWrapStyleWord(true);
    324                 JPanel lower = new JPanel();
    325                 title = new JLabel(get("CDM.General.Title"));
    326                 title.setHorizontalAlignment(JLabel.CENTER);
    327                 title.setOpaque(true);
    328                 JPanel upper = new JPanel();
     263        access = new JCheckBox(get("CDM.General.Access"));
     264        access.setSelected(manager.public_col);
     265        access_pane = new JPanel();
     266        beta = new JCheckBox(get("CDM.General.Beta"));
     267        beta.setSelected(manager.beta);
     268        beta_pane = new JPanel();
     269        central_pane = new JPanel();
     270        collection_extra = new JTextArea();
     271        collection_extra_inner_pane = new JPanel();
     272        collection_extra_label = new JLabel(get("CDM.General.Collection_Extra"));
     273        collection_extra_label.setHorizontalAlignment(JLabel.CENTER);
     274        collection_extra_language = new JLabel();
     275        collection_extra_pane = new JPanel();
     276        if(collection_extra_data != null) {
     277        collection_extra.setText(collection_extra_data.getValue());
     278        Language language = null;
     279        if((language = collection_extra_data.getLanguage()) != null) {
     280            collection_extra_language.setText(language.toString());
     281        }
     282        else {
     283            collection_extra_language.setText(manager.languages.getDefaultLanguage().toString());
     284        }
     285        }
     286        collection_name = new JTextField();
     287        collection_name_inner_pane = new JPanel();
     288        collection_name_label = new JLabel(get("CDM.General.Collection_Name"));
     289        collection_name_label.setPreferredSize(LABEL_SIZE);
     290        collection_name_language = new JLabel();
     291        collection_name_pane = new JPanel();
     292        if(collection_name_data != null) {
     293        collection_name.setText(collection_name_data.getValue());
     294        Language language = null;
     295        if((language = collection_name_data.getLanguage()) != null) {
     296            collection_name_language.setText(language.toString());
     297        }
     298        else {
     299            collection_name_language.setText(manager.languages.getDefaultLanguage().toString());
     300        }
     301        }
     302        icon_collection = new JTextField();
     303        icon_collection_inner_pane = new JPanel();
     304        icon_collection_label = new JLabel(get("CDM.General.Icon_Collection"));
     305        icon_collection_label.setPreferredSize(LABEL_SIZE);
     306        icon_collection_language = new JLabel();
     307        icon_collection_pane = new JPanel();
     308        if(icon_collection_data != null) {
     309        icon_collection.setText(icon_collection_data.getValue());
     310        Language language = null;
     311        if((language = icon_collection_data.getLanguage()) != null) {
     312            icon_collection_language.setText(language.toString());
     313        }
     314        else {
     315            icon_collection_language.setText(manager.languages.getDefaultLanguage().toString());
     316        }
     317        }
     318        instructions = new JTextArea(get("CDM.General.Instructions"));
     319        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     320        instructions.setEditable(false);
     321        instructions.setLineWrap(true);
     322        instructions.setRows(4);
     323        instructions.setWrapStyleWord(true);
     324        JPanel lower = new JPanel();
     325        title = new JLabel(get("CDM.General.Title"));
     326        title.setHorizontalAlignment(JLabel.CENTER);
     327        title.setOpaque(true);
     328        JPanel upper = new JPanel();
    329329                // Add listeners.
    330                 access.addActionListener(new AccessListener());
    331                 beta.addActionListener(new BetaListener());
    332                 collection_extra.addKeyListener(new ChangeListener(collection_extra_data, collection_extra, "collectionextra"));
    333                 collection_name.addKeyListener(new ChangeListener(collection_name_data, collection_name, "collectionname"));
    334                 collection_name.addKeyListener(new CollectionTitleListener());
    335                 icon_collection.addKeyListener(new ChangeListener(icon_collection_data, icon_collection, "iconcollection"));
     330        access.addActionListener(new AccessListener());
     331        beta.addActionListener(new BetaListener());
     332        collection_extra.addKeyListener(new ChangeListener(collection_extra_data, collection_extra, "collectionextra"));
     333        collection_name.addKeyListener(new ChangeListener(collection_name_data, collection_name, "collectionname"));
     334        collection_name.addKeyListener(new CollectionTitleListener());
     335        icon_collection.addKeyListener(new ChangeListener(icon_collection_data, icon_collection, "iconcollection"));
    336336                // Layout
    337                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    338 
    339                 upper.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    340                 upper.setLayout(new BorderLayout());
    341                 upper.add(title, BorderLayout.NORTH);
    342                 upper.add(new JScrollPane(instructions), BorderLayout.CENTER);
    343 
    344                 collection_name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    345                 collection_name_language.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
    346 
    347                 collection_name_inner_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    348                 collection_name_inner_pane.setLayout(new BorderLayout());
    349                 collection_name_inner_pane.add(collection_name);
    350 
    351                 collection_name_pane.setLayout(new BorderLayout());
    352                 collection_name_pane.add(collection_name_label, BorderLayout.WEST);
    353                 collection_name_pane.add(collection_name_inner_pane, BorderLayout.CENTER);
    354                 collection_name_pane.add(collection_name_language, BorderLayout.EAST);
    355 
    356                 icon_collection_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    357                 icon_collection_language.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
    358 
    359                 icon_collection_inner_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    360                 icon_collection_inner_pane.setLayout(new BorderLayout());
    361                 icon_collection_inner_pane.add(icon_collection, BorderLayout.CENTER);
    362 
    363                 icon_collection_pane.setLayout(new BorderLayout());
    364                 icon_collection_pane.add(icon_collection_label, BorderLayout.WEST);
    365                 icon_collection_pane.add(icon_collection_inner_pane, BorderLayout.CENTER);
    366                 icon_collection_pane.add(icon_collection_language, BorderLayout.EAST);
    367 
    368                 access_pane.add(access);
    369 
    370                 beta_pane.add(beta);
    371 
    372                 lower.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    373                 lower.setLayout(new GridLayout(6,1));
    374                 lower.add(manager.creator.getControls());
    375                 lower.add(manager.maintainer.getControls());
    376                 lower.add(access_pane);
    377                 lower.add(beta_pane);
    378                 lower.add(collection_name_pane);
    379                 lower.add(icon_collection_pane);
    380 
    381                 collection_extra_inner_pane.setLayout(new BorderLayout());
    382                 collection_extra_inner_pane.add(collection_extra_label, BorderLayout.WEST);
    383                 collection_extra_inner_pane.add(collection_extra_language, BorderLayout.EAST);
    384 
    385                 collection_extra.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    386 
    387                 collection_extra_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    388                 collection_extra_pane.setLayout(new BorderLayout());
    389                 collection_extra_pane.add(collection_extra_inner_pane, BorderLayout.NORTH);
    390                 collection_extra_pane.add(new JScrollPane(collection_extra), BorderLayout.CENTER);
    391 
    392                 central_pane.setLayout(new BorderLayout());
    393                 central_pane.add(lower, BorderLayout.NORTH);
    394                 central_pane.add(collection_extra_pane, BorderLayout.CENTER);
    395 
    396                 setLayout(new BorderLayout());
    397                 add(upper, BorderLayout.NORTH);
    398                 add(central_pane, BorderLayout.CENTER);
    399           }
    400           /** Destructor.
     337        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     338
     339        upper.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     340        upper.setLayout(new BorderLayout());
     341        upper.add(title, BorderLayout.NORTH);
     342        upper.add(new JScrollPane(instructions), BorderLayout.CENTER);
     343
     344        collection_name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     345        collection_name_language.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
     346
     347        collection_name_inner_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     348        collection_name_inner_pane.setLayout(new BorderLayout());
     349        collection_name_inner_pane.add(collection_name);
     350
     351        collection_name_pane.setLayout(new BorderLayout());
     352        collection_name_pane.add(collection_name_label, BorderLayout.WEST);
     353        collection_name_pane.add(collection_name_inner_pane, BorderLayout.CENTER);
     354        collection_name_pane.add(collection_name_language, BorderLayout.EAST);
     355
     356        icon_collection_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     357        icon_collection_language.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
     358
     359        icon_collection_inner_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     360        icon_collection_inner_pane.setLayout(new BorderLayout());
     361        icon_collection_inner_pane.add(icon_collection, BorderLayout.CENTER);
     362
     363        icon_collection_pane.setLayout(new BorderLayout());
     364        icon_collection_pane.add(icon_collection_label, BorderLayout.WEST);
     365        icon_collection_pane.add(icon_collection_inner_pane, BorderLayout.CENTER);
     366        icon_collection_pane.add(icon_collection_language, BorderLayout.EAST);
     367
     368        access_pane.add(access);
     369
     370        beta_pane.add(beta);
     371
     372        lower.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
     373        lower.setLayout(new GridLayout(6,1));
     374        lower.add(manager.creator.getControls());
     375        lower.add(manager.maintainer.getControls());
     376        lower.add(access_pane);
     377        lower.add(beta_pane);
     378        lower.add(collection_name_pane);
     379        lower.add(icon_collection_pane);
     380
     381        collection_extra_inner_pane.setLayout(new BorderLayout());
     382        collection_extra_inner_pane.add(collection_extra_label, BorderLayout.WEST);
     383        collection_extra_inner_pane.add(collection_extra_language, BorderLayout.EAST);
     384
     385        collection_extra.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     386
     387        collection_extra_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
     388        collection_extra_pane.setLayout(new BorderLayout());
     389        collection_extra_pane.add(collection_extra_inner_pane, BorderLayout.NORTH);
     390        collection_extra_pane.add(new JScrollPane(collection_extra), BorderLayout.CENTER);
     391
     392        central_pane.setLayout(new BorderLayout());
     393        central_pane.add(lower, BorderLayout.NORTH);
     394        central_pane.add(collection_extra_pane, BorderLayout.CENTER);
     395
     396        setLayout(new BorderLayout());
     397        add(upper, BorderLayout.NORTH);
     398        add(central_pane, BorderLayout.CENTER);
     399    }
     400    /** Destructor.
    401401            */
    402           public void destroy() {
    403           }
    404           /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
     402    public void destroy() {
     403    }
     404    /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
    405405            */
    406           public void updateUI() {
    407                 if(instructions != null) {
    408                      instructions.setCaretPosition(0);
    409                 }
    410                 if(collection_extra != null) {
    411                      collection_extra.setCaretPosition(0);
    412                 }
    413                 super.updateUI();
    414           }
    415           /** Detect when the collection access changes, and update the configuration as necessary.
     406    public void updateUI() {
     407        if(instructions != null) {
     408        instructions.setCaretPosition(0);
     409        }
     410        if(collection_extra != null) {
     411        collection_extra.setCaretPosition(0);
     412        }
     413        super.updateUI();
     414    }
     415    /** Detect when the collection access changes, and update the configuration as necessary.
    416416          * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    417417          */
    418           private class AccessListener
    419                 implements ActionListener {
    420                 public void actionPerformed(ActionEvent event) {
    421                      manager.public_col = access.isSelected();
    422                 }
    423           }
    424           /** Detect when the collection state changes and update the configuration as necessary.
     418    private class AccessListener
     419        implements ActionListener {
     420        public void actionPerformed(ActionEvent event) {
     421        manager.public_col = access.isSelected();
     422        }
     423    }
     424    /** Detect when the collection state changes and update the configuration as necessary.
    425425          * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    426426          */
    427           private class BetaListener
    428                 implements ActionListener {
    429                 public void actionPerformed(ActionEvent event) {
    430                      manager.beta = beta.isSelected();
    431                 }
    432           }
    433           /** This class listens for any changes its registered controls, including enter actions and keys typed, and updates the fields stored in CollectionDesignManager as necessary. */
    434           private class ChangeListener
    435                 extends KeyAdapter {
     427    private class BetaListener
     428        implements ActionListener {
     429        public void actionPerformed(ActionEvent event) {
     430        manager.beta = beta.isSelected();
     431        }
     432    }
     433    /** This class listens for any changes its registered controls, including enter actions and keys typed, and updates the fields stored in CollectionDesignManager as necessary. */
     434    private class ChangeListener
     435        extends KeyAdapter {
    436436                /** The collection metadata to alter. */
    437                 private CollectionMeta metadata = null;
     437        private CollectionMeta metadata = null;
    438438                /** The control we are watching for changes. */
    439                 private JTextComponent component = null;
     439        private JTextComponent component = null;
    440440                /** The name of the metadata to monitor. */
    441                 private String name = null;
     441        private String name = null;
    442442                /** Construstor.
    443                 * @param metadata The <strong>CollectionMeta</strong> to alter.
    444                 * @param component The <strong>JTextComponent</strong> we are monitoring for changes.
    445                 * @param name The name of the metadata as a <strong>String</strong>.
     443                 * @param metadata The <strong>CollectionMeta</strong> to alter.
     444                 * @param component The <strong>JTextComponent</strong> we are monitoring for changes.
     445                 * @param name The name of the metadata as a <strong>String</strong>.
    446446                */
    447                 public ChangeListener(CollectionMeta metadata, JTextComponent component, String name) {
    448                      this.component = component;
    449                      this.metadata = metadata;
    450                      if(metadata != null) {
    451                           this.name = metadata.getName().toString();
    452                      }
    453                      else {
    454                           this.name = name;
    455                      }
    456                 }
     447        public ChangeListener(CollectionMeta metadata, JTextComponent component, String name) {
     448        this.component = component;
     449        this.metadata = metadata;
     450        if(metadata != null) {
     451            this.name = metadata.getName().toString();
     452        }
     453        else {
     454            this.name = name;
     455        }
     456        }
    457457                /** Any extension of a KeyAdapter may override this method so we can be informed when a key has been released (ie after the character etc has been added). In this case we want to update the appropriate metadata, however there are three distinct cases to consider:<br>&nbsp;1. A simple update of the value field is all that is necessary,<br>&nbsp;2. The metadata exists but it currently has no language, so we must set the language to default and update the value, or<br>&nbsp;3. The metadata doesn't exist so we'll create a new one with the specified name, default language and new value.<br>This final case is highly unlikely but still possible.
    458458                * @param event An <strong>Event</strong> containing information about the key release.
     
    465465                * @see org.greenstone.gatherer.collection.CollectionManager
    466466                */
    467                 public void keyReleased(KeyEvent event) {
    468                      if(metadata != null) {
    469                           Language language = metadata.getLanguage();
    470                           if(language == null) {
    471                                 metadata.update(metadata.getName(), manager.languages.getDefaultLanguage(), component.getText());
    472                           }
    473                           else {
    474                                 metadata.update(metadata.getName(), metadata.getLanguage(), component.getText());
    475                           }
    476                      }
    477                      else {
    478                           metadata = new CollectionMeta(manager, name, manager.languages.getDefaultLanguage(), component.getText());
    479                           manager.collectionmetadatum.addMetadata(metadata);
    480                      }
    481                      gatherer.c_man.configurationChanged();
    482                }
    483           }
    484           /** Listens for changes to the collection name and updates the windows title bar appropriately and collection file. */
    485           private class CollectionTitleListener
    486                 extends KeyAdapter {
     467        public void keyReleased(KeyEvent event) {
     468        if(metadata != null) {
     469            Language language = metadata.getLanguage();
     470            if(language == null) {
     471            metadata.update(metadata.getName(), manager.languages.getDefaultLanguage(), component.getText());
     472            }
     473            else {
     474            metadata.update(metadata.getName(), metadata.getLanguage(), component.getText());
     475            }
     476        }
     477        else {
     478            metadata = new CollectionMeta(manager, name, manager.languages.getDefaultLanguage(), component.getText());
     479            manager.collectionmetadatum.addMetadata(metadata);
     480        }
     481        gatherer.c_man.configurationChanged();
     482        }
     483    }
     484    /** Listens for changes to the collection name and updates the windows title bar appropriately and collection file. */
     485    private class CollectionTitleListener
     486        extends KeyAdapter {
    487487                /** Any extension of a KeyAdapter may override this method so we can be informed when a key has been released (ie after the character etc has been added). When such a change occurs update the main guis title bar to reflect the change and fix the collection name.
    488488                 * @param event An <strong>Event</strong> containing information about the key release.
    489489                 */
    490                 public void keyReleased(KeyEvent event) {
    491                      String name = collection_name.getText();
    492                      if(name != null && name.length() > 0) {
    493                           gatherer.g_man.setTitle(Utility.PROGRAM_NAME + ":\"" + name + "\"");
    494                           gatherer.c_man.getCollection().setTitle(name);
    495                      }
    496                 }
    497           }
    498     }
    499     /** This tree provides a 'table of contents' for the various components of the design process (collection configuration in more technical terms). */
    500     private class DesignTree
    501           extends JTree {
    502           private DesignNode root = null;
    503           /** Constructor. Automatically generates all of the nodes, in the order of CONTENTS.
    504             */
    505           public DesignTree() {
    506                 super();
    507                 root = new DesignNode("Root");
    508                 this.setModel(new DefaultTreeModel(root));
     490        public void keyReleased(KeyEvent event) {
     491        String name = collection_name.getText();
     492        if(name != null && name.length() > 0) {
     493            gatherer.g_man.setTitle(Utility.PROGRAM_NAME + ":\"" + name + "\"");
     494            gatherer.c_man.getCollection().setTitle(name);
     495        }
     496        }
     497    }
     498    }
     499    /** This tree provides a 'table of contents' for the various components of the design process (collection configuration in more technical terms). */
     500    private class DesignTree
     501    extends JTree {
     502    private DesignNode root = null;
     503    /** Constructor. Automatically generates all of the nodes, in the order of CONTENTS.
     504     */
     505    public DesignTree() {
     506        super();
     507        root = new DesignNode("Root");
     508        this.setModel(new DefaultTreeModel(root));
    509509                // Now add the design categories.
    510                 for(int i = 0; i < CONTENTS.length; i++) {
    511                      root.add(new DesignNode(CONTENTS[i]));
    512                 }
    513                 expandRow(0);
    514                 setRootVisible(false);
    515                 setSelectionRow(0);
    516           }
    517             /** Set the current view to the one specified.
    518             * @param type The name of the desired view as a <strong>String</strong>.
    519             * @see org.greenstone.gatherer.Gatherer
    520             * @see org.greenstone.gatherer.cdm.GUI.DesignNode
    521             */
    522           public void setSelectedView(String type) {
    523                 type = gatherer.get(type);
    524                 for(int i = 0; i < root.getChildCount(); i++) {
    525                      DesignNode child = (DesignNode) root.getChildAt(i);
    526                      if(child.toString().equals(type)) {
    527                           TreePath path = new TreePath(child.getPath());
    528                           setSelectionPath(path);
    529                      }
    530                 }
    531           }
    532     }
    533     /** A tree node that retains a reference to one of the possible design sub-views relating to the different sub-managers. */
    534     private class DesignNode
    535           extends DefaultMutableTreeNode {
    536           /** Constructor.
    537           * @param object The <strong>Object</strong> assigned to this node.
     510        for(int i = 0; i < CONTENTS.length; i++) {
     511        root.add(new DesignNode(CONTENTS[i]));
     512        }
     513        expandRow(0);
     514        setRootVisible(false);
     515        setSelectionRow(0);
     516    }
     517    /** Set the current view to the one specified.
     518     * @param type The name of the desired view as a <strong>String</strong>.
     519     * @see org.greenstone.gatherer.Gatherer
     520     * @see org.greenstone.gatherer.cdm.GUI.DesignNode
     521     */
     522    public void setSelectedView(String type) {
     523        type = gatherer.get(type);
     524        for(int i = 0; i < root.getChildCount(); i++) {
     525        DesignNode child = (DesignNode) root.getChildAt(i);
     526        if(child.toString().equals(type)) {
     527            TreePath path = new TreePath(child.getPath());
     528            setSelectionPath(path);
     529        }
     530        }
     531    }
     532    }
     533    /** A tree node that retains a reference to one of the possible design sub-views relating to the different sub-managers. */
     534    private class DesignNode
     535    extends DefaultMutableTreeNode {
     536    /** Constructor.
     537    * @param object The <strong>Object</strong> assigned to this node.
    538538          */
    539           public DesignNode(String object) {
    540                 super(object);
    541           }
    542           /** Retrieve a textual representation of the object.
     539    public DesignNode(String object) {
     540        super(object);
     541    }
     542    /** Retrieve a textual representation of the object.
    543543          * @return A <strong>String</strong>.
    544544          */
    545           public String toString() {
    546                 return get((String)getUserObject());
    547           }
    548     }
    549     /** Listens for selection changes in the 'contents' tree, and switches to the appropriate view. */
    550     private class TreeListener
    551           implements TreeSelectionListener {
    552           /** Called whenever the selection changes, we must update the view so it matches the node selected.
    553           * @param event A <strong>TreeSelectionEvent</strong> containing more information about the tree selection.
    554           * @see org.greenstone.gatherer.cdm.ClassifierManager
    555           * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    556           * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    557           * @see org.greenstone.gatherer.cdm.FormatManager
    558           * @see org.greenstone.gatherer.cdm.LanguageManager
    559           * @see org.greenstone.gatherer.cdm.MetadataSetManager
    560           * @see org.greenstone.gatherer.cdm.SubcollectionManager
    561           * @see org.greenstone.gatherer.cdm.PlugInManager
    562           */
    563           public void valueChanged(TreeSelectionEvent event) {
    564                 if(!tree.isSelectionEmpty()) {
    565                      TreePath path = tree.getSelectionPath();
    566                      DesignNode node = (DesignNode)path.getLastPathComponent();
    567                      String type = (String)node.getUserObject();
    568                      // Assure user
    569                      // Build and change panes.
    570                      remove(view);
    571                      view.hasFocus(); // Trigger pending information update events.
    572                      if(type.equals("General")) {
    573                           view = getControls();
    574                      }
    575                      else if(type.equals("Indexes")) {
    576                           view = manager.indexes.getControls();
    577                      }
    578                      else if(type.equals("Subcollections")) {
    579                           view = manager.subcollections.getControls();
    580                      }
    581                      else if(type.equals("Languages")) {
    582                           view = manager.languages.getControls();
    583                      }
    584                      else if(type.equals("Plugins")) {
    585                           view = manager.plugins.getControls();
    586                      }
    587                      else if(type.equals("Classifiers")) {
    588                           view = manager.classifiers.getControls();
    589                      }
    590                      else if(type.equals("Formats")) {
    591                           view = manager.formats.getControls();
    592                      }
    593                      else if(type.equals("MetadataSets")) {
    594                           view = manager.metadatasets.getControls();
    595                      }
    596                      add(view, BorderLayout.CENTER);
    597                      view.updateUI();
    598                      // Ready
    599                 }
    600           }
    601     }
     545    public String toString() {
     546        return get((String)getUserObject());
     547    }
     548    }
     549    /** Listens for selection changes in the 'contents' tree, and switches to the appropriate view. */
     550    private class TreeListener
     551    implements TreeSelectionListener {
     552    /** Called whenever the selection changes, we must update the view so it matches the node selected.
     553    * @param event A <strong>TreeSelectionEvent</strong> containing more information about the tree selection.
     554    * @see org.greenstone.gatherer.cdm.ClassifierManager
     555    * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     556    * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     557    * @see org.greenstone.gatherer.cdm.FormatManager
     558    * @see org.greenstone.gatherer.cdm.LanguageManager
     559    * @see org.greenstone.gatherer.cdm.MetadataSetManager
     560    * @see org.greenstone.gatherer.cdm.SubcollectionManager
     561    * @see org.greenstone.gatherer.cdm.PlugInManager
     562    */
     563    public void valueChanged(TreeSelectionEvent event) {
     564        if(!tree.isSelectionEmpty()) {
     565        TreePath path = tree.getSelectionPath();
     566        DesignNode node = (DesignNode)path.getLastPathComponent();
     567        String type = (String)node.getUserObject();
     568        // Assure user
     569        // Build and change panes.
     570        remove(view);
     571        view.hasFocus(); // Trigger pending information update events.
     572        if(type.equals("General")) {
     573            view = getControls();
     574        }
     575        else if(type.equals("Indexes")) {
     576            view = manager.indexes.getControls();
     577        }
     578        else if(type.equals("Subcollections")) {
     579            view = manager.subcollections.getControls();
     580        }
     581        else if(type.equals("Languages")) {
     582            view = manager.languages.getControls();
     583        }
     584        else if(type.equals("Plugins")) {
     585            view = manager.plugins.getControls();
     586        }
     587        else if(type.equals("Classifiers")) {
     588            view = manager.classifiers.getControls();
     589        }
     590        else if(type.equals("Formats")) {
     591            view = manager.formats.getControls();
     592        }
     593        else if(type.equals("MetadataSets")) {
     594            view = manager.metadatasets.getControls();
     595        }
     596        add(view, BorderLayout.CENTER);
     597        view.updateUI();
     598        // Ready
     599        }
     600    }
     601    }
    602602}
  • trunk/gli/src/org/greenstone/gatherer/cdm/Index.java

    r4293 r4366  
    5757import org.w3c.dom.Element;
    5858/** This class encapsulates a single indexing pair.
    59 * @author John Thompson, Greenstone Digital Library, University of Waikato
    60 * @version 2.2
    61 */
     59 * @author John Thompson, Greenstone Digital Library, University of Waikato
     60 * @version 2.2
     61 */
    6262public class Index
    63     implements Comparable {
    64     /** A refernce to the main manager for access to other sub-managers. */
    65     private CollectionDesignManager manager = null;
    66     /** The level of this index. */
    67     private int level = 0;
    68     /** The sources for data this index is built apon, which are either fully qualified metadata element names or 'text'. */
    69     private Vector sources = null;
    70     /** An element in the index level enumeration. */
    71     static public final int DOCUMENT = 0;
    72     /** An element in the index level enumeration. */
    73     static public final int PARAGRAPH = 1;
    74     /** An element in the index level enumeration. */
    75     static public final int SECTION = 2;
    76     /** An values of items in the index level enumeration. */
    77     static public final String LEVEL[] = {"document","paragraph","section"};
    78     /** Constructor.
    79       * @param level The level of this index as a <strong>String</string>.
    80       * @param metadata The fully qualified name of the metadata this index is built on as a <strong>String</strong>, or <i>null</i> in which case the data defaults to "text".
    81       */
    82     public Index(int level, Vector sources, CollectionDesignManager manager) {
    83           this.level = level;
    84           this.manager = manager;
    85           this.sources = sources;
    86           if(this.sources == null) {
    87                 this.sources = new Vector();
    88                 this.sources.add("text");
    89           }
    90     }
    91     /** Method to compare two indexes.
     63    implements Comparable {
     64    /** A refernce to the main manager for access to other sub-managers. */
     65    private CollectionDesignManager manager = null;
     66    /** The level of this index. */
     67    private int level = 0;
     68    /** The sources for data this index is built apon, which are either fully qualified metadata element names or 'text'. */
     69    private Vector sources = null;
     70    /** An element in the index level enumeration. */
     71    static public final int DOCUMENT = 0;
     72    /** An element in the index level enumeration. */
     73    static public final int PARAGRAPH = 1;
     74    /** An element in the index level enumeration. */
     75    static public final int SECTION = 2;
     76    /** An values of items in the index level enumeration. */
     77    static public final String LEVEL[] = {"document","paragraph","section"};
     78    /** Constructor.
     79     * @param level The level of this index as a <strong>String</string>.
     80     * @param metadata The fully qualified name of the metadata this index is built on as a <strong>String</strong>, or <i>null</i> in which case the data defaults to "text".
     81     */
     82    public Index(int level, Vector sources, CollectionDesignManager manager) {
     83    this.level = level;
     84    this.manager = manager;
     85    this.sources = sources;
     86    if(this.sources == null) {
     87        this.sources = new Vector();
     88        this.sources.add("text");
     89    }
     90    }
     91    /** Method to compare two indexes.
    9292      * @param object The other index as an <strong>Object</strong>.
    9393      * @return An <i>int</i> which indicates how the indexes compare.
    9494      * @see java.lang.String
    9595      */
    96     public int compareTo(Object object) {
    97           if(object instanceof Index) {
    98                 Index index = (Index) object;
    99                 return toString(false).compareTo(index.toString(false));
    100           }
    101           return toString(false).compareTo(object.toString());
    102     }
    103     /** Method to test for the equality of two indexes.
     96    public int compareTo(Object object) {
     97    if(object instanceof Index) {
     98        Index index = (Index) object;
     99        return toString(false).compareTo(index.toString(false));
     100    }
     101    return toString(false).compareTo(object.toString());
     102    }
     103    /** Method to test for the equality of two indexes.
    104104      * @param object The other index as an <strong>Object</strong>.
    105105      * @return A <i>boolean</i> which is <i>true</i> if the two indexes are equal, <i>false</i> otherwise.
    106106      */
    107     public boolean equals(Object object) {
    108           if(compareTo(object) == 0) {
    109                 return true;
    110           }
    111           return false;
    112     }
    113     /** Method to get the data source of this index.
     107    public boolean equals(Object object) {
     108    if(compareTo(object) == 0) {
     109        return true;
     110    }
     111    return false;
     112    }
     113    /** Method to get the data source of this index.
    114114      * @return A <strong>String</string> which is a comma separated list of either fully qualified names of an assigned metadata elements, or "text".
    115115      */
    116     public String getData() {
    117           String result = "";
    118           Collections.sort(sources, new IndexComparator());
    119           for(int i = 0; i < sources.size(); i++) {
    120                 result = result + sources.get(i).toString();
    121                 if(i < sources.size() - 1) {
    122                      result = result + ",";
    123                 }
    124           }
    125           return result;
    126     }
    127     /** Method to get the value of level.
     116    public String getData() {
     117    String result = "";
     118    Collections.sort(sources, new IndexComparator());
     119    for(int i = 0; i < sources.size(); i++) {
     120        result = result + sources.get(i).toString();
     121        if(i < sources.size() - 1) {
     122        result = result + ",";
     123        }
     124    }
     125    return result;
     126    }
     127    /** Method to get the value of level.
    128128      * @return The value of level as a <strong>String</strong>.
    129129      */
    130     public int getLevel() {
    131           return level;
    132     }
    133     /** Method to get the value of metadata.
     130    public int getLevel() {
     131    return level;
     132    }
     133    /** Method to get the value of metadata.
    134134      * @return The value of metadata as an <strong>Vector</strong>.
    135135      */
    136     public Vector getMetadata() {
    137           return sources;
    138     }
    139     /** Method to retrieve this indexes name.
     136    public Vector getMetadata() {
     137    return sources;
     138    }
     139    /** Method to retrieve this indexes name.
    140140      * @return A <strong>String</strong>.
    141141      */
    142     public String getName() {
    143           if(manager != null) {
    144                 String name = LEVEL[level] + ":" + getData();
    145                 Language language = manager.languages.getDefaultLanguage();
    146                 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(name, language, true);
    147                 if(metadata != null) {
    148                      return metadata.getValue();
    149                 }
    150           }
    151           return "";
    152     }
    153     /** Method to turn this object into a string representation ready to be placed in the collection configuration file.
     142    public String getName() {
     143    if(manager != null) {
     144        String name = LEVEL[level] + ":" + getData();
     145        Language language = manager.languages.getDefaultLanguage();
     146        CollectionMeta metadata = manager.collectionmetadatum.getMetadata(name, language, true);
     147        if(metadata != null) {
     148        return metadata.getValue();
     149        }
     150    }
     151    return "";
     152    }
     153    /** Method to turn this object into a string representation ready to be placed in the collection configuration file.
    154154      * @return A <strong>String</strong> containing the information of this class.
    155155      */
    156     public String toString() {
    157           return LEVEL[level] + ":" + getData() + "  \"" + getName() + "\"";
    158     }
    159     /** Retrieve a textual representation of this index.
     156    public String toString() {
     157    return LEVEL[level] + ":" + getData() + "  \"" + getName() + "\"";
     158    }
     159    /** Retrieve a textual representation of this index.
    160160    * @param show_name <i>true</i> if you want the name of this index, <i>false</i> for the gsdl index reference.
    161161    */
    162     public String toString(boolean show_name) {
    163           if(show_name) {
    164                 return getName();
    165           }
    166           return LEVEL[level] + ":" + getData();
    167     }
    168     /** A custom comparator for comparing Indexes. */
    169     private class IndexComparator
    170           implements Comparator {
    171           /** Method to compare two objects, which may be either indexes or strings.
    172             * @param object1 One object as an <strong>Object</strong>.
    173             * @param object2 Another object as an <strong>Object</strong>.
    174             * @return An <i>int</i> which indicates how they compare.
    175             * @see java.lang.String
    176             */
    177           public int compare(Object object1, Object object2) {
    178                 if(object1 instanceof Index && object2 instanceof Index) {
    179                      Index index1 = (Index)object1;
    180                      Index index2 = (Index)object2;
    181                      return index1.toString(false).compareTo(index2.toString(false));
    182                 }
    183                 else if(object1 instanceof Index) {
    184                      Index index = (Index) object1;
    185                      return index.toString(false).compareTo(object2.toString());
    186                 }
    187                 else if(object2 instanceof Index) {
    188                      Index index = (Index) object2;
    189                      return object1.toString().compareTo(index.toString(false));
    190                 }
    191                 return object1.toString().compareTo(object2.toString());
    192           }
    193           /** Method to test for the equality of two objects, which may be indexes or strings.
     162    public String toString(boolean show_name) {
     163    if(show_name) {
     164        return getName();
     165    }
     166    return LEVEL[level] + ":" + getData();
     167    }
     168    /** A custom comparator for comparing Indexes. */
     169    private class IndexComparator
     170    implements Comparator {
     171    /** Method to compare two objects, which may be either indexes or strings.
     172     * @param object1 One object as an <strong>Object</strong>.
     173     * @param object2 Another object as an <strong>Object</strong>.
     174     * @return An <i>int</i> which indicates how they compare.
     175     * @see java.lang.String
     176     */
     177    public int compare(Object object1, Object object2) {
     178        if(object1 instanceof Index && object2 instanceof Index) {
     179        Index index1 = (Index)object1;
     180        Index index2 = (Index)object2;
     181        return index1.toString(false).compareTo(index2.toString(false));
     182        }
     183        else if(object1 instanceof Index) {
     184        Index index = (Index) object1;
     185        return index.toString(false).compareTo(object2.toString());
     186        }
     187        else if(object2 instanceof Index) {
     188        Index index = (Index) object2;
     189        return object1.toString().compareTo(index.toString(false));
     190        }
     191        return object1.toString().compareTo(object2.toString());
     192    }
     193    /** Method to test for the equality of two objects, which may be indexes or strings.
    194194            * @param object Another object as an <strong>Object</strong>.
    195195            * @return A <i>boolean</i> which is <i>true</i> if the two objects are equal, <i>false</i> otherwise.
    196196            */
    197           public boolean equals(Object object) {
    198                 if(compareTo(object) == 0) {
    199                      return true;
    200                 }
    201                 return false;
    202           }
    203     }
     197    public boolean equals(Object object) {
     198        if(compareTo(object) == 0) {
     199        return true;
     200        }
     201        return false;
     202    }
     203    }
    204204}
  • trunk/gli/src/org/greenstone/gatherer/cdm/IndexManager.java

    r4293 r4366  
    8383import org.w3c.dom.Element;
    8484/** This class is resposible for storing the indexes which have been assigned to this collection and the default index, and providing methods for interacting with both these data pools. It also knows how to turn itself into a String as it would be displayed in the collection configuration file.
    85 * @author John Thompson, Greenstone Digital Library, University of Waikato
    86 * @version 2.3
    87 */
     85 * @author John Thompson, Greenstone Digital Library, University of Waikato
     86 * @version 2.3
     87 */
    8888public class IndexManager
    89     extends DefaultListModel {
    90     /** A reference to our creator, the collection design manager. */
    91     private CollectionDesignManager manager = null;
    92     /** The controls for editing the indexes. */
    93     private Control controls = null;
    94     /** A reference to ourselves so our inner methods have access. */
    95     private DefaultListModel model = null;
    96     /** A reference to the Gatherer, for access to the Dictionary and messaging purposes. */
    97     private Gatherer gatherer = null;
    98     /** The default index. */
    99     private Index default_index = null;
    100     /** Constructor.
    101     * @param gatherer A reference to the <strong>Gatherer</strong>.
    102     * @param manager A reference to the <strong>CollectionDesignManager</strong>.
    103     */
    104     public IndexManager(Gatherer gatherer, CollectionDesignManager manager) {
    105           super();
    106           this.gatherer = gatherer;
    107           this.manager = manager;
    108           this.model = this;
    109     }
    110     /** Method to add a new index.
     89    extends DefaultListModel {
     90    /** A reference to our creator, the collection design manager. */
     91    private CollectionDesignManager manager = null;
     92    /** The controls for editing the indexes. */
     93    private Control controls = null;
     94    /** A reference to ourselves so our inner methods have access. */
     95    private DefaultListModel model = null;
     96    /** A reference to the Gatherer, for access to the Dictionary and messaging purposes. */
     97    private Gatherer gatherer = null;
     98    /** The default index. */
     99    private Index default_index = null;
     100    /** Constructor.
     101    * @param gatherer A reference to the <strong>Gatherer</strong>.
     102    * @param manager A reference to the <strong>CollectionDesignManager</strong>.
     103    */
     104    public IndexManager(Gatherer gatherer, CollectionDesignManager manager) {
     105    super();
     106    this.gatherer = gatherer;
     107    this.manager = manager;
     108    this.model = this;
     109    }
     110    /** Method to add a new index.
    111111      * @param index The <strong>Index</strong> to add.
    112112      * @see org.greenstone.gatherer.Gatherer
    113113      * @see org.greenstone.gatherer.collection.CollectionManager
    114114      */
    115     public void addIndex(Index index) {
    116           if(!contains(index)) {
    117                 String index_str = index.toString(false).toLowerCase();
     115    public void addIndex(Index index) {
     116    if(!contains(index)) {
     117        String index_str = index.toString(false).toLowerCase();
    118118                // Add alphabetically.
    119                 for(int i = 0; i < size(); i++) {
    120                      Index sibling = (Index) get(i);
    121                      String sibling_str = sibling.toString(false).toLowerCase();
    122                      int position = index_str.compareTo(sibling_str);
    123                      // Sibling is before index.
    124                      if(position > 0) {
    125                           // Carry on.
    126                      }
    127                      // Index is equal to, or before sibling. Insert it.
    128                      else if(position == 0 || position < 0) {
    129                           add(i, index);
    130                           gatherer.c_man.configurationChanged();
    131                           return;
    132                      }
    133                 }
     119        for(int i = 0; i < size(); i++) {
     120        Index sibling = (Index) get(i);
     121        String sibling_str = sibling.toString(false).toLowerCase();
     122        int position = index_str.compareTo(sibling_str);
     123        // Sibling is before index.
     124        if(position > 0) {
     125            // Carry on.
     126        }
     127        // Index is equal to, or before sibling. Insert it.
     128        else if(position == 0 || position < 0) {
     129            add(i, index);
     130            gatherer.c_man.configurationChanged();
     131            return;
     132        }
     133        }
    134134                // If we got this far, we haven't inserted index, and we are out of model so.
    135                 addElement(index);
    136                 gatherer.c_man.configurationChanged();
    137           }
    138           else {
    139                 JOptionPane.showMessageDialog(manager.gui, get("CDM.IndexManager.Index_Exists"), get("General.Warning"), JOptionPane.WARNING_MESSAGE);
    140           }
    141     }
    142     /** Method to acquire the controls for editing the indexes.
     135        addElement(index);
     136        gatherer.c_man.configurationChanged();
     137    }
     138    else {
     139        JOptionPane.showMessageDialog(manager.gui, get("CDM.IndexManager.Index_Exists"), get("General.Warning"), JOptionPane.WARNING_MESSAGE);
     140    }
     141    }
     142    /** Method to acquire the controls for editing the indexes.
    143143      * @return A <strong>JPanel</strong> containing the controls.
    144144      * @see org.greenstone.gatherer.cdm.IndexManager.Control
    145145      */
    146     public JPanel getControls() {
    147           if(controls == null) {
    148                 controls = new Control();
    149           }
    150           return controls;
    151     }
    152     /** Method to get the default index.
     146    public JPanel getControls() {
     147    if(controls == null) {
     148        controls = new Control();
     149    }
     150    return controls;
     151    }
     152    /** Method to get the default index.
    153153      * @return The default <strong>Index</strong>.
    154154      */
    155     public Index getDefault() {
    156           return default_index;
    157     }
    158     /** Method to retrieve a certain index, as referenced by an index number.
     155    public Index getDefault() {
     156    return default_index;
     157    }
     158    /** Method to retrieve a certain index, as referenced by an index number.
    159159      * @param index An <i>int</i> which indicates the position of the desired index.
    160160      * @return The <strong>Index</strong> at the given index, or <i>null</i> if no such index exists.
    161161      */
    162     public Index getIndex(int index) {
    163           if(0 <= index && index < size()) {
    164                 return (Index)get(index);
    165           }
    166           return null;
    167     }
    168     /** Method to retrieve a certain index, given its name.
     162    public Index getIndex(int index) {
     163    if(0 <= index && index < size()) {
     164        return (Index)get(index);
     165    }
     166    return null;
     167    }
     168    /** Method to retrieve a certain index, given its name.
    169169      * @param name The name of the index as a <Strong>String</strong>.
    170170      * @return The <strong>Index</strong> that matches name, or <i>null</i> if no such index exists.
    171171      */
    172     public Index getIndex(String name) {
    173           ///ystem.err.println("Searching for index " + name);
    174           for(int i = 0; i < size(); i++) {
    175                 Index index = (Index) get(i);
    176                 if(index.toString(false).equals(name)) {
    177                      ///ystem.err.println("Found.");
    178                      return (Index)get(i);
    179                 }
    180           }
    181           ///ystem.err.println("No such index.");
    182           return null;
    183     }
    184     /** A method to retrieve all of the indexes associated with this manager.
     172    public Index getIndex(String name) {
     173    ///ystem.err.println("Searching for index " + name);
     174    for(int i = 0; i < size(); i++) {
     175        Index index = (Index) get(i);
     176        if(index.toString(false).equals(name)) {
     177        ///ystem.err.println("Found.");
     178        return (Index)get(i);
     179        }
     180    }
     181    ///ystem.err.println("No such index.");
     182    return null;
     183    }
     184    /** A method to retrieve all of the indexes associated with this manager.
    185185      * @return A <strong>Vector</strong> of <strong>Index</strong>es.
    186186      */
    187     public Vector getIndexes() {
    188           Vector indexes = new Vector();
    189           for(int i = 0; i < size(); i++) {
    190                 indexes.add(get(i));
    191           }
    192           Collections.sort(indexes);
    193           return indexes;
    194     }
    195     /** Mark the current set of controls, if any, as obsolete and deallocate them. If further need of the controls will cause new controls to be created.
     187    public Vector getIndexes() {
     188    Vector indexes = new Vector();
     189    for(int i = 0; i < size(); i++) {
     190        indexes.add(get(i));
     191    }
     192    Collections.sort(indexes);
     193    return indexes;
     194    }
     195    /** Mark the current set of controls, if any, as obsolete and deallocate them. If further need of the controls will cause new controls to be created.
    196196    * @see org.greenstone.gatherer.cdm.IndexManager.Control
    197197    */
    198     public void invalidateControls() {
    199           if(controls != null) {
    200                 controls.destroy();
    201           }
    202           controls = null;
    203     }
    204     /** Method that attempts to parse an index related command from the given command. If such a command is parsed, it is immediately registered with this manager.
     198    public void invalidateControls() {
     199    if(controls != null) {
     200        controls.destroy();
     201    }
     202    controls = null;
     203    }
     204    /** Method that attempts to parse an index related command from the given command. If such a command is parsed, it is immediately registered with this manager.
    205205      * @param command The <strong>String</strong> to parse.
    206206      * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
     
    208208      * @see org.greenstone.gatherer.cdm.Index
    209209      */
    210     public boolean parse(String command) {
    211           String temp = command.toLowerCase();
    212           if(temp.startsWith("indexes")) {
    213                 CommandTokenizer ct = new CommandTokenizer(command);
    214                 ct.nextToken(); // Throw away indexes.
    215                 while(ct.hasMoreTokens()) {
    216                      String entry = ct.nextToken();
    217                      if(entry.indexOf(":") != -1) {
    218                           String level_str = entry.substring(0, entry.indexOf(":"));
    219                           String sources_raw = entry.substring(entry.indexOf(":") + 1);
    220                           Vector sources = new Vector();
    221                           StringTokenizer st = new StringTokenizer(sources_raw, ",");
    222                           while(st.hasMoreTokens()) {
    223                                 String token = st.nextToken();
    224                                 // We may have to replace old : with whatever namespace separator we are using.
    225                                 token = token.replace(':', MSMUtils.NS_SEP);
    226                                 sources.add(token);
    227                           }
    228                           for(int i = 0; i < Index.LEVEL.length; i++) {
    229                                 if(level_str.equals(Index.LEVEL[i])) {
    230                                     addIndex(new Index(i, sources, manager));
    231                                 }
    232                           }
    233                      }
    234                      else {
    235                           return false;
    236                      }
    237                 }
    238                 return true;
    239           }
    240           else if(temp.startsWith("defaultindex")) {
    241                 CommandTokenizer ct = new CommandTokenizer(command);
    242                 ct.nextToken();
    243                 String entry = ct.nextToken();
    244                 if(entry.indexOf(":") != -1) {
    245                      String level_str = entry.substring(0, entry.indexOf(":"));
    246                      String sources_raw = entry.substring(entry.indexOf(":") + 1);
    247                      Vector sources = new Vector();
    248                      StringTokenizer st = new StringTokenizer(sources_raw, ",");
    249                      while(st.hasMoreTokens()) {
    250                           sources.add(st.nextToken());
    251                      }
    252                      for(int i = 0; i < Index.LEVEL.length; i++) {
    253                           if(level_str.equals(Index.LEVEL[i])) {
    254                                 setDefault(new Index(i, sources, manager));
    255                           }
    256                      }
    257                 }
    258                 else {
    259                      return false;
    260                 }
    261                 return true;
    262           }
    263           return false;
    264     }
    265 
    266     public void removeAll() {
    267           removeAllElements();
    268           default_index = null;
    269           gatherer.c_man.configurationChanged();
    270     }
    271 
    272     /** Method to remove a certain index.
     210    public boolean parse(String command) {
     211    String temp = command.toLowerCase();
     212    if(temp.startsWith("indexes")) {
     213        CommandTokenizer ct = new CommandTokenizer(command);
     214        ct.nextToken(); // Throw away indexes.
     215        while(ct.hasMoreTokens()) {
     216        String entry = ct.nextToken();
     217        if(entry.indexOf(":") != -1) {
     218            String level_str = entry.substring(0, entry.indexOf(":"));
     219            String sources_raw = entry.substring(entry.indexOf(":") + 1);
     220            Vector sources = new Vector();
     221            StringTokenizer st = new StringTokenizer(sources_raw, ",");
     222            while(st.hasMoreTokens()) {
     223            String token = st.nextToken();
     224            // We may have to replace old : with whatever namespace separator we are using.
     225            token = token.replace(':', MSMUtils.NS_SEP);
     226            sources.add(token);
     227            }
     228            for(int i = 0; i < Index.LEVEL.length; i++) {
     229            if(level_str.equals(Index.LEVEL[i])) {
     230                addIndex(new Index(i, sources, manager));
     231            }
     232            }
     233        }
     234        else {
     235            return false;
     236        }
     237        }
     238        return true;
     239    }
     240    else if(temp.startsWith("defaultindex")) {
     241        CommandTokenizer ct = new CommandTokenizer(command);
     242        ct.nextToken();
     243        String entry = ct.nextToken();
     244        if(entry.indexOf(":") != -1) {
     245        String level_str = entry.substring(0, entry.indexOf(":"));
     246        String sources_raw = entry.substring(entry.indexOf(":") + 1);
     247        Vector sources = new Vector();
     248        StringTokenizer st = new StringTokenizer(sources_raw, ",");
     249        while(st.hasMoreTokens()) {
     250            sources.add(st.nextToken());
     251        }
     252        for(int i = 0; i < Index.LEVEL.length; i++) {
     253            if(level_str.equals(Index.LEVEL[i])) {
     254            setDefault(new Index(i, sources, manager));
     255            }
     256        }
     257        }
     258        else {
     259        return false;
     260        }
     261        return true;
     262    }
     263    return false;
     264    }
     265
     266    public void removeAll() {
     267    removeAllElements();
     268    default_index = null;
     269    gatherer.c_man.configurationChanged();
     270    }
     271
     272    /** Method to remove a certain index.
    273273      * @param index The <Strong>Index</strong> to remove.
    274274      * @see org.greenstone.gatherer.Gatherer
     
    277277      * @see org.greenstone.gatherer.collection.CollectionManager
    278278      */
    279     public void removeIndex(Index index) {
    280           if(index != null) {
    281                 String name = index.getName();
    282                 if(name != null) {
    283                      Language default_language = manager.languages.getDefaultLanguage();
    284                      CollectionMeta metadata = new CollectionMeta(manager, index, default_language, name);
    285                      manager.collectionmetadatum.removeMetadata(metadata);
    286                 }
    287                 removeElement(index);
    288                 if(default_index != null && default_index.equals(index)) {
    289                      default_index = null;
    290                 }
    291                 gatherer.c_man.configurationChanged();
    292           }
    293     }
    294     /** Method to set the default index.
     279    public void removeIndex(Index index) {
     280    if(index != null) {
     281        String name = index.getName();
     282        if(name != null) {
     283        Language default_language = manager.languages.getDefaultLanguage();
     284        CollectionMeta metadata = new CollectionMeta(manager, index, default_language, name);
     285        manager.collectionmetadatum.removeMetadata(metadata);
     286        }
     287        removeElement(index);
     288        if(default_index != null && default_index.equals(index)) {
     289        default_index = null;
     290        }
     291        gatherer.c_man.configurationChanged();
     292    }
     293    }
     294    /** Method to set the default index.
    295295      * @param index The new default <strong>Index</strong>.
    296296      * @see org.greenstone.gatherer.Gatherer
    297297      * @see org.greenstone.gatherer.collection.CollectionManager
    298298      */
    299     public void setDefault(Index index) {
    300           default_index = index;
    301           if(index != null && !contains(index)) {
    302                 addElement(index);
    303           }
    304           gatherer.c_man.configurationChanged();
    305     }
    306     /** Method to print out the contents of this class as a string.
     299    public void setDefault(Index index) {
     300    default_index = index;
     301    if(index != null && !contains(index)) {
     302        addElement(index);
     303    }
     304    gatherer.c_man.configurationChanged();
     305    }
     306    /** Method to print out the contents of this class as a string.
    307307      * @return A <strong>String</strong> just as it would appear in the colleciton configuration file.
    308308      */
    309     public String toString() {
    310           String text = "";
    311           // First the indexes.
    312           if(size() > 0) {
    313                 text = "indexes      ";
    314                 for(int i = 0; i < size(); i++) {
    315                      Index index = (Index) get(i);
    316                      text = text + index.toString(false);
    317                      if(i < size() - 1) {
    318                           text = text + " ";
    319                      }
    320                 }
     309    public String toString() {
     310    String text = "";
     311    // First the indexes.
     312    if(size() > 0) {
     313        text = "indexes      ";
     314        for(int i = 0; i < size(); i++) {
     315        Index index = (Index) get(i);
     316        text = text + index.toString(false);
     317        if(i < size() - 1) {
     318            text = text + " ";
     319        }
     320        }
    321321                // Now the default index if there is one, or just the first index
    322322                // if there isn't
    323                 if(default_index != null) {
    324                      text = text + "\ndefaultindex " + default_index.toString(false) + "\n";
    325                 }
    326                 text = text + "\n";
    327           }
    328           return text;
    329     }
    330     /** Overloaded to call get with both a key and an empty argument array.
     323        if(default_index != null) {
     324        text = text + "\ndefaultindex " + default_index.toString(false) + "\n";
     325        }
     326        text = text + "\n";
     327    }
     328    return text;
     329    }
     330    /** Overloaded to call get with both a key and an empty argument array.
    331331      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    332332      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
    333333      */
    334     private String get(String key) {
    335           return get(key, null);
    336     }
    337     /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
     334    private String get(String key) {
     335    return get(key, null);
     336    }
     337    /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
    338338      * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
    339339      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     
    343343      * @see org.greenstone.gatherer.Dictionary
    344344      */
    345     private String get(String key, String args[]) {
    346           if(key.indexOf('.') == -1) {
    347                 key = "CDM.IndexManager." + key;
    348           }
    349           return gatherer.dictionary.get(key, args);
    350     }
    351     /** This class creates a set of controls for editing the indexes. */
    352     private class Control
    353           extends JPanel {
    354             /** The default size of a label on this control. */
    355           private Dimension LABEL_SIZE = new Dimension(120,25);
    356           /** The button used to add a new index. */
    357           private JButton add = null;
    358           /** The button used to clear the default index. */
    359           private JButton clear_default = null;
    360           /** The button used to remove an index. */
    361           private JButton remove = null;
    362           /** The button used to set the default index. */
    363           private JButton set_default = null;
    364           /** The combobox used to adjust what level the new index will built on. */
    365           private JComboBox level = null;
    366           /** The label denoting the default index to be built for this collection. */
    367           private JLabel default_label = null;
    368           /** The label denoting the list of assigned indexes. */
    369           private JLabel index_label = null;
    370           /** The label denoting the control for choosing index level. */
    371           private JLabel level_label = null;
    372           /** The label denoting the name of the index. */
    373           private JLabel name_label = null;
    374           /** The label denoting the list of possible sources for the index. */
    375           private JLabel source_label = null;
    376           /** The title shown at the top of the index controls. */
    377           private JLabel title = null;
    378           /** The list of assigned indexes. */
    379           private JList index_list = null;
    380           /** The list of possible sources on which the index could be built. */
    381           private JList source_list = null;
    382           /** The panel used to display the list of assigned indexes. */
    383           private JPanel assigned_pane = null;
    384           /** The panel which contains the buttons used to edit indexes. */
    385           private JPanel button_pane = null;
    386           /** The panel on which all other panels are displayed. */
    387           private JPanel central_pane = null;
    388           /** The control pane showing the editable controls. */
    389           private JPanel control_pane = null;
    390           /** The edit pane contains the list of possible sources. */
    391           private JPanel edit_pane = null;
    392           /** A panel used to correctly lay out the default index label. */
    393           private JPanel default_pane = null;
    394           /** The panel containing the title label and instructions. */
    395           private JPanel header_pane = null;
    396           /** The lvel panel contains the control for adjusting index level. */
    397           private JPanel level_pane = null;
    398           /** The pane in which the name control is set. */
    399           private JPanel name_pane = null;
    400           /** The scrollpane containing the instructions text area. */
    401           private JScrollPane instructions_scroll = null;
    402           /** A text area containing inline instructions. */
    403           private JTextArea instructions = null;
    404           /** A text field naming the default index. Non-editable. */
    405           private JTextField default_value = null;
    406           /** A text field for controlling the name of the new index. */
    407           private JTextField name = null;
    408           /** A model containing all of the available index sources. */
    409           private Vector source_model = null;
    410           /** Constructor.
    411             * @see org.greenstone.gatherer.Configuration
    412             * @see org.greenstone.gatherer.Gatherer
    413             * @see org.greenstone.gatherer.cdm.IndexManager.Control.AddListener
    414             * @see org.greenstone.gatherer.cdm.IndexManager.Control.ClearDefaultListener
    415             * @see org.greenstone.gatherer.cdm.IndexManager.Control.NameListener
    416             * @see org.greenstone.gatherer.cdm.IndexManager.Control.RemoveListener
    417             * @see org.greenstone.gatherer.cdm.IndexManager.Control.SetDefaultListener
    418             * @see org.greenstone.gatherer.collection.CollectionManager
    419             * @see org.greenstone.gatherer.gui.Coloring
    420             * @see org.greenstone.gatherer.msm.MetadataSetManager
    421             * @see org.greenstone.gatherer.util.ExclusiveListSelectionListener
    422             */
    423           public Control() {
    424                 super();
    425                 source_model = new Vector();
    426                 source_model.add("text");
    427                 source_model.addAll(gatherer.c_man.msm.getAssignedElements());
     345    private String get(String key, String args[]) {
     346    if(key.indexOf('.') == -1) {
     347        key = "CDM.IndexManager." + key;
     348    }
     349    return gatherer.dictionary.get(key, args);
     350    }
     351    /** This class creates a set of controls for editing the indexes. */
     352    private class Control
     353    extends JPanel {
     354    /** The default size of a label on this control. */
     355    private Dimension LABEL_SIZE = new Dimension(120,25);
     356    /** The button used to add a new index. */
     357    private JButton add = null;
     358    /** The button used to clear the default index. */
     359    private JButton clear_default = null;
     360    /** The button used to remove an index. */
     361    private JButton remove = null;
     362    /** The button used to set the default index. */
     363    private JButton set_default = null;
     364    /** The combobox used to adjust what level the new index will built on. */
     365    private JComboBox level = null;
     366    /** The label denoting the default index to be built for this collection. */
     367    private JLabel default_label = null;
     368    /** The label denoting the list of assigned indexes. */
     369    private JLabel index_label = null;
     370    /** The label denoting the control for choosing index level. */
     371    private JLabel level_label = null;
     372    /** The label denoting the name of the index. */
     373    private JLabel name_label = null;
     374    /** The label denoting the list of possible sources for the index. */
     375    private JLabel source_label = null;
     376    /** The title shown at the top of the index controls. */
     377    private JLabel title = null;
     378    /** The list of assigned indexes. */
     379    private JList index_list = null;
     380    /** The list of possible sources on which the index could be built. */
     381    private JList source_list = null;
     382    /** The panel used to display the list of assigned indexes. */
     383    private JPanel assigned_pane = null;
     384    /** The panel which contains the buttons used to edit indexes. */
     385    private JPanel button_pane = null;
     386    /** The panel on which all other panels are displayed. */
     387    private JPanel central_pane = null;
     388    /** The control pane showing the editable controls. */
     389    private JPanel control_pane = null;
     390    /** The edit pane contains the list of possible sources. */
     391    private JPanel edit_pane = null;
     392    /** A panel used to correctly lay out the default index label. */
     393    private JPanel default_pane = null;
     394    /** The panel containing the title label and instructions. */
     395    private JPanel header_pane = null;
     396    /** The lvel panel contains the control for adjusting index level. */
     397    private JPanel level_pane = null;
     398    /** The pane in which the name control is set. */
     399    private JPanel name_pane = null;
     400    /** The scrollpane containing the instructions text area. */
     401    private JScrollPane instructions_scroll = null;
     402    /** A text area containing inline instructions. */
     403    private JTextArea instructions = null;
     404    /** A text field naming the default index. Non-editable. */
     405    private JTextField default_value = null;
     406    /** A text field for controlling the name of the new index. */
     407    private JTextField name = null;
     408    /** A model containing all of the available index sources. */
     409    private Vector source_model = null;
     410    /** Constructor.
     411     * @see org.greenstone.gatherer.Configuration
     412     * @see org.greenstone.gatherer.Gatherer
     413     * @see org.greenstone.gatherer.cdm.IndexManager.Control.AddListener
     414     * @see org.greenstone.gatherer.cdm.IndexManager.Control.ClearDefaultListener
     415     * @see org.greenstone.gatherer.cdm.IndexManager.Control.NameListener
     416     * @see org.greenstone.gatherer.cdm.IndexManager.Control.RemoveListener
     417     * @see org.greenstone.gatherer.cdm.IndexManager.Control.SetDefaultListener
     418     * @see org.greenstone.gatherer.collection.CollectionManager
     419     * @see org.greenstone.gatherer.gui.Coloring
     420     * @see org.greenstone.gatherer.msm.MetadataSetManager
     421     * @see org.greenstone.gatherer.util.ExclusiveListSelectionListener
     422     */
     423    public Control() {
     424        super();
     425        source_model = new Vector();
     426        source_model.add("text");
     427        source_model.addAll(gatherer.c_man.msm.getAssignedElements());
    428428                //source_model.addAll(gatherer.c_man.msm.getElements());
    429429                // Creation
    430                 add = new JButton(get("Add"));
    431                 add.setEnabled(false);
    432                 add.setMnemonic(KeyEvent.VK_A);
    433                 assigned_pane = new JPanel();
    434                 button_pane = new JPanel();
    435                 central_pane = new JPanel();
    436                 control_pane = new JPanel();
    437                 clear_default = new JButton(get("Clear_Default"));
    438                 clear_default.setMnemonic(KeyEvent.VK_C);
    439                 if(default_index == null) {
    440                      clear_default.setEnabled(false);
    441                 }
    442                 default_label = new JLabel(get("Default_Index"));
    443                 default_pane = new JPanel();
    444                 if(default_index != null) {
    445                      default_value = new JTextField(default_index.toString(true));
    446                      default_value.setCaretPosition(0);
    447                 }
    448                 else {
    449                      default_value = new JTextField();
    450                 }
    451                 edit_pane = new JPanel();
    452                 header_pane = new JPanel();
    453                 index_label = new JLabel(get("Indexes"));
    454                 index_list = new JList(model);
    455                 instructions = new JTextArea(get("Instructions"));
    456                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    457                 instructions.setEditable(false);
    458                 instructions.setLineWrap(true);
    459                 instructions.setRows(5);
    460                 instructions.setWrapStyleWord(true);
    461                 level = new JComboBox();
    462                 level.addItem(get("Document"));
    463                 level.addItem(get("Paragraph"));
    464                 level.addItem(get("Section"));
    465                 level.setEditable(false);
    466                 level_label = new JLabel(get("Level"));
    467                 level_label.setPreferredSize(LABEL_SIZE);
    468                 level_pane = new JPanel();
    469                 name = new JTextField();
    470                 name_label = new JLabel(get("Name"));
    471                 name_label.setPreferredSize(LABEL_SIZE);
    472                 name_pane = new JPanel();
    473                 remove = new JButton(get("Remove"));
    474                 remove.setEnabled(false);
    475                 remove.setMnemonic(KeyEvent.VK_R);
    476                 set_default = new JButton(get("Set_Default"));
    477                 set_default.setEnabled(false);
    478                 set_default.setMnemonic(KeyEvent.VK_S);
    479                 source_label = new JLabel(get("Source"));
    480                 source_list = new JList(source_model);
    481                 title = new JLabel(get("Title"));
    482                 title.setHorizontalAlignment(JLabel.CENTER);
     430        add = new JButton(get("Add"));
     431        add.setEnabled(false);
     432        add.setMnemonic(KeyEvent.VK_A);
     433        assigned_pane = new JPanel();
     434        button_pane = new JPanel();
     435        central_pane = new JPanel();
     436        control_pane = new JPanel();
     437        clear_default = new JButton(get("Clear_Default"));
     438        clear_default.setMnemonic(KeyEvent.VK_C);
     439        if(default_index == null) {
     440        clear_default.setEnabled(false);
     441        }
     442        default_label = new JLabel(get("Default_Index"));
     443        default_pane = new JPanel();
     444        if(default_index != null) {
     445        default_value = new JTextField(default_index.toString(true));
     446        default_value.setCaretPosition(0);
     447        }
     448        else {
     449        default_value = new JTextField();
     450        }
     451        edit_pane = new JPanel();
     452        header_pane = new JPanel();
     453        index_label = new JLabel(get("Indexes"));
     454        index_list = new JList(model);
     455        instructions = new JTextArea(get("Instructions"));
     456        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     457        instructions.setEditable(false);
     458        instructions.setLineWrap(true);
     459        instructions.setRows(5);
     460        instructions.setWrapStyleWord(true);
     461        level = new JComboBox();
     462        level.addItem(get("Document"));
     463        level.addItem(get("Paragraph"));
     464        level.addItem(get("Section"));
     465        level.setEditable(false);
     466        level_label = new JLabel(get("Level"));
     467        level_label.setPreferredSize(LABEL_SIZE);
     468        level_pane = new JPanel();
     469        name = new JTextField();
     470        name_label = new JLabel(get("Name"));
     471        name_label.setPreferredSize(LABEL_SIZE);
     472        name_pane = new JPanel();
     473        remove = new JButton(get("Remove"));
     474        remove.setEnabled(false);
     475        remove.setMnemonic(KeyEvent.VK_R);
     476        set_default = new JButton(get("Set_Default"));
     477        set_default.setEnabled(false);
     478        set_default.setMnemonic(KeyEvent.VK_S);
     479        source_label = new JLabel(get("Source"));
     480        source_list = new JList(source_model);
     481        title = new JLabel(get("Title"));
     482        title.setHorizontalAlignment(JLabel.CENTER);
    483483
    484484                // Listeners
    485                 add.addActionListener(new AddListener());
    486                 clear_default.addActionListener(new ClearDefaultListener());
    487                 remove.addActionListener(new RemoveListener());
    488                 set_default.addActionListener(new SetDefaultListener());
    489                 name.addKeyListener(new NameListener());
    490                 ListListener ll = new ListListener();
    491                 index_list.addListSelectionListener(ll);
    492                 source_list.addListSelectionListener(ll);
    493                 ExclusiveListSelectionListener elsl = new ExclusiveListSelectionListener();
    494                 elsl.add(index_list);
    495                 elsl.add(source_list);
     485        add.addActionListener(new AddListener());
     486        clear_default.addActionListener(new ClearDefaultListener());
     487        remove.addActionListener(new RemoveListener());
     488        set_default.addActionListener(new SetDefaultListener());
     489        name.addKeyListener(new NameListener());
     490        ListListener ll = new ListListener();
     491        index_list.addListSelectionListener(ll);
     492        source_list.addListSelectionListener(ll);
     493        ExclusiveListSelectionListener elsl = new ExclusiveListSelectionListener();
     494        elsl.add(index_list);
     495        elsl.add(source_list);
    496496
    497497                // Layout
    498                 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
    499 
    500                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    501 
    502                 header_pane.setLayout(new BorderLayout());
    503                 header_pane.add(title, BorderLayout.NORTH);
    504                 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    505 
    506                 name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    507 
    508                 name_pane.setBorder(BorderFactory.createEmptyBorder(4,2,4,2));
    509                 name_pane.setLayout(new BorderLayout());
    510                 name_pane.add(name_label, BorderLayout.WEST);
    511                 name_pane.add(name, BorderLayout.CENTER);
    512 
    513                 control_pane.setLayout(new BorderLayout());
    514                 control_pane.add(source_label, BorderLayout.NORTH);
    515                 control_pane.add(new JScrollPane(source_list), BorderLayout.CENTER);
    516 
    517                 level_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    518 
    519                 level_pane.setBorder(BorderFactory.createEmptyBorder(4,2,4,2));
    520                 level_pane.setLayout(new BorderLayout());
    521                 level_pane.add(level_label, BorderLayout.WEST);
    522                 level_pane.add(level, BorderLayout.CENTER);
    523 
    524                 edit_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    525                 edit_pane.setLayout(new BorderLayout());
    526                 edit_pane.add(name_pane, BorderLayout.NORTH);
    527                 edit_pane.add(control_pane, BorderLayout.CENTER);
    528                 edit_pane.add(level_pane, BorderLayout.SOUTH);
    529 
    530                 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    531 
    532                 default_pane.setBorder
    533                      (BorderFactory.createCompoundBorder
    534                       (BorderFactory.createCompoundBorder
    535                         (BorderFactory.createEmptyBorder(2,2,2,2),
    536                         BorderFactory.createRaisedBevelBorder()),
    537                         BorderFactory.createEmptyBorder(2,2,2,2)));
    538                 default_pane.setLayout(new BorderLayout());
    539                 default_pane.add(default_label, BorderLayout.WEST);
    540                 default_pane.add(default_value, BorderLayout.CENTER);
    541 
    542                 assigned_pane.setLayout(new BorderLayout());
    543                 assigned_pane.add(index_label, BorderLayout.NORTH);
    544                 assigned_pane.add(new JScrollPane(index_list), BorderLayout.CENTER);
    545                 assigned_pane.add(default_pane, BorderLayout.SOUTH);
    546 
    547                 central_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
    548                 central_pane.setLayout(new GridLayout(1,2));
    549                 central_pane.add(edit_pane);
    550                 central_pane.add(assigned_pane);
    551 
    552                 button_pane.setLayout(new GridLayout(2,2));
    553                 button_pane.add(add);
    554                 button_pane.add(remove);
    555                 button_pane.add(clear_default);
    556                 button_pane.add(set_default);
    557 
    558                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    559                 setLayout(new BorderLayout());
    560                 add(header_pane, BorderLayout.NORTH);
    561                 add(central_pane, BorderLayout.CENTER);
    562                 add(button_pane, BorderLayout.SOUTH);
    563           }
    564           /* Destructor, removes persistant listeners from the Dictionary.
     498        title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
     499
     500        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     501
     502        header_pane.setLayout(new BorderLayout());
     503        header_pane.add(title, BorderLayout.NORTH);
     504        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     505
     506        name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     507
     508        name_pane.setBorder(BorderFactory.createEmptyBorder(4,2,4,2));
     509        name_pane.setLayout(new BorderLayout());
     510        name_pane.add(name_label, BorderLayout.WEST);
     511        name_pane.add(name, BorderLayout.CENTER);
     512
     513        control_pane.setLayout(new BorderLayout());
     514        control_pane.add(source_label, BorderLayout.NORTH);
     515        control_pane.add(new JScrollPane(source_list), BorderLayout.CENTER);
     516
     517        level_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     518
     519        level_pane.setBorder(BorderFactory.createEmptyBorder(4,2,4,2));
     520        level_pane.setLayout(new BorderLayout());
     521        level_pane.add(level_label, BorderLayout.WEST);
     522        level_pane.add(level, BorderLayout.CENTER);
     523
     524        edit_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     525        edit_pane.setLayout(new BorderLayout());
     526        edit_pane.add(name_pane, BorderLayout.NORTH);
     527        edit_pane.add(control_pane, BorderLayout.CENTER);
     528        edit_pane.add(level_pane, BorderLayout.SOUTH);
     529
     530        default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     531
     532        default_pane.setBorder
     533        (BorderFactory.createCompoundBorder
     534        (BorderFactory.createCompoundBorder
     535          (BorderFactory.createEmptyBorder(2,2,2,2),
     536          BorderFactory.createRaisedBevelBorder()),
     537          BorderFactory.createEmptyBorder(2,2,2,2)));
     538        default_pane.setLayout(new BorderLayout());
     539        default_pane.add(default_label, BorderLayout.WEST);
     540        default_pane.add(default_value, BorderLayout.CENTER);
     541
     542        assigned_pane.setLayout(new BorderLayout());
     543        assigned_pane.add(index_label, BorderLayout.NORTH);
     544        assigned_pane.add(new JScrollPane(index_list), BorderLayout.CENTER);
     545        assigned_pane.add(default_pane, BorderLayout.SOUTH);
     546
     547        central_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
     548        central_pane.setLayout(new GridLayout(1,2));
     549        central_pane.add(edit_pane);
     550        central_pane.add(assigned_pane);
     551
     552        button_pane.setLayout(new GridLayout(2,2));
     553        button_pane.add(add);
     554        button_pane.add(remove);
     555        button_pane.add(clear_default);
     556        button_pane.add(set_default);
     557
     558        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     559        setLayout(new BorderLayout());
     560        add(header_pane, BorderLayout.NORTH);
     561        add(central_pane, BorderLayout.CENTER);
     562        add(button_pane, BorderLayout.SOUTH);
     563    }
     564    /* Destructor, removes persistant listeners from the Dictionary.
    565565            */
    566           public void destroy() {
    567           }
    568           /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
     566    public void destroy() {
     567    }
     568    /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
    569569          * @see org.greenstone.gatherer.Gatherer
    570570          * @see org.greenstone.gatherer.collection.CollectionManager
    571571          * @see org.greenstone.gatherer.msm.MetadataSetManager
    572572            */
    573           public void updateUI() {
    574                 if(instructions != null) {
    575                      instructions.setCaretPosition(0);
    576                 }
     573    public void updateUI() {
     574        if(instructions != null) {
     575        instructions.setCaretPosition(0);
     576        }
    577577                // Reload the assigned indexes list.
    578                 if(source_model != null) {
    579                      source_model.clear();
    580                      source_model.add("text");
    581                      source_model.addAll(gatherer.c_man.msm.getAssignedElements());
    582                 }
     578        if(source_model != null) {
     579        source_model.clear();
     580        source_model.add("text");
     581        source_model.addAll(gatherer.c_man.msm.getAssignedElements());
     582        }
    583583                // Faster than a NPE its the - 'Super class'.
    584                 super.updateUI();
    585           }
    586           /** Listens for actions apon the 'add' button in the IndexManager controls, and if detected calls the add method of the manager with a newly created index. */
    587           private class AddListener
    588                 implements ActionListener {
     584        super.updateUI();
     585    }
     586    /** Listens for actions apon the 'add' button in the IndexManager controls, and if detected calls the add method of the manager with a newly created index. */
     587    private class AddListener
     588        implements ActionListener {
    589589                /** Method called when an action is performed on a registered component, and when it does we check if we have enough data to create a new index, and if so we create one.
    590                 * @param event An <strong>ActionEvent</strong> providing extra information about the event.
    591                 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    592                 * @see org.greenstone.gatherer.cdm.CollectionMeta
    593                 * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    594                 * @see org.greenstone.gatherer.cdm.Index
    595                 * @see org.greenstone.gatherer.cdm.Language
    596                 * @see org.greenstone.gatherer.cdm.LanguageManager
     590                 * @param event An <strong>ActionEvent</strong> providing extra information about the event.
     591                 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     592                 * @see org.greenstone.gatherer.cdm.CollectionMeta
     593                 * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     594                 * @see org.greenstone.gatherer.cdm.Index
     595                 * @see org.greenstone.gatherer.cdm.Language
     596                 * @see org.greenstone.gatherer.cdm.LanguageManager
     597                 */
     598        public void actionPerformed(ActionEvent event) {
     599        if(!source_list.isSelectionEmpty() && name.getText().length() != 0) {
     600            Object object[] = source_list.getSelectedValues();
     601            Vector sources = new Vector();
     602            for(int i = 0; i < object.length; i++) {
     603            sources.add(object[i]);
     604            }
     605            Index index = new Index(level.getSelectedIndex(), sources, manager);
     606            // Before we add the index to the model, we have to add the collection metadata for this.
     607            Language language = manager.languages.getDefaultLanguage();
     608            CollectionMeta metadata = new CollectionMeta(manager, index, language, name.getText());
     609            manager.collectionmetadatum.addMetadata(metadata);
     610            // Finally add index.
     611            addIndex(index);
     612        }
     613        }
     614    }
     615    /** Listens for actions apon the 'clear default' button in the IndexManager controls, and if detected calls the setDefault method of the manager with <i>null</i>. */
     616    private class ClearDefaultListener
     617        implements ActionListener {
     618                /** If called when an action occurs on a registered component, we clear the default index.
     619                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
    597620                */
    598                 public void actionPerformed(ActionEvent event) {
    599                      if(!source_list.isSelectionEmpty() && name.getText().length() != 0) {
    600                           Object object[] = source_list.getSelectedValues();
    601                           Vector sources = new Vector();
    602                           for(int i = 0; i < object.length; i++) {
    603                                 sources.add(object[i]);
    604                           }
    605                           Index index = new Index(level.getSelectedIndex(), sources, manager);
    606                           // Before we add the index to the model, we have to add the collection metadata for this.
    607                           Language language = manager.languages.getDefaultLanguage();
    608                           CollectionMeta metadata = new CollectionMeta(manager, index, language, name.getText());
    609                           manager.collectionmetadatum.addMetadata(metadata);
    610                           // Finally add index.
    611                           addIndex(index);
    612                      }
    613                 }
    614           }
    615           /** Listens for actions apon the 'clear default' button in the IndexManager controls, and if detected calls the setDefault method of the manager with <i>null</i>. */
    616           private class ClearDefaultListener
    617                 implements ActionListener {
    618                 /** If called when an action occurs on a registered component, we clear the default index.
    619                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
     621        public void actionPerformed(ActionEvent event) {
     622        setDefault(null);
     623        clear_default.setEnabled(false);
     624        default_value.setText("");
     625        }
     626    }
     627    /** Listens for actions apon the 'remove' button in the IndexManager controls, and if detected calls the remove method of the manager with the index selected for removal. */
     628    private class RemoveListener
     629        implements ActionListener {
     630                /** If called when an action occurs on a registered component, we remove the currently selected index, if there is one.
     631                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
     632                 * @see org.greenstone.gatherer.cdm.Index
     633                 */
     634        public void actionPerformed(ActionEvent event) {
     635        if(!index_list.isSelectionEmpty()) {
     636            removeIndex((Index)index_list.getSelectedValue());
     637            if(default_index == null) {
     638            clear_default.setEnabled(false);
     639            default_value.setText("");
     640            }
     641        }
     642        }
     643    }
     644    /** Listens for actions apon the 'set default' button in the IndexManager controls, and if detected calls the setDefault method of the manager with the index selected for default. */
     645    private class SetDefaultListener
     646        implements ActionListener {
     647                /** If called when an action occurs on a registered component, we set the default index to the index currently selected.
     648                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
     649                 * @see org.greenstone.gatherer.cdm.Index
     650                 */
     651        public void actionPerformed(ActionEvent event) {
     652        setDefault((Index)index_list.getSelectedValue());
     653        if(default_index != null) {
     654            clear_default.setEnabled(true);
     655            default_value.setText(default_index.toString(true));
     656            default_value.setCaretPosition(0);
     657        }
     658        else {
     659            clear_default.setEnabled(false);
     660            default_value.setText("");
     661        }
     662        }
     663    }
     664    /** Listens for key presses within the name field, and enabled or disables controls as appropriate. */
     665    private class NameListener
     666        extends KeyAdapter {
     667                /** Called when a key is released, this is the perfect time to enable the add button if the fields are appropriately set.
     668                 * @param event A <strong>KeyEvent</strong> containing information about the key released.
    620669                */
    621                 public void actionPerformed(ActionEvent event) {
    622                      setDefault(null);
    623                      clear_default.setEnabled(false);
    624                      default_value.setText("");
    625                 }
    626           }
    627           /** Listens for actions apon the 'remove' button in the IndexManager controls, and if detected calls the remove method of the manager with the index selected for removal. */
    628           private class RemoveListener
    629                 implements ActionListener {
    630                 /** If called when an action occurs on a registered component, we remove the currently selected index, if there is one.
    631                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
    632                 * @see org.greenstone.gatherer.cdm.Index
     670        public void keyReleased(KeyEvent event) {
     671        if(source_list.isSelectionEmpty() || name.getText().length() == 0) {
     672            add.setEnabled(false);
     673        }
     674        else {
     675            add.setEnabled(true);
     676        }
     677        if(index_list.isSelectionEmpty()) {
     678            remove.setEnabled(false);
     679            set_default.setEnabled(false);
     680        }
     681        else {
     682            remove.setEnabled(true);
     683            set_default.setEnabled(true);
     684        }
     685        }
     686    }
     687    /** Listens for selections within the list on the IndexManager controls, and if a change is detected enables, or disables, controls appropriately. */
     688    private class ListListener
     689        implements ListSelectionListener {
     690                /** This method is called whenever the source list selection changes. When it does we need to check if the add button should now be enabled.
     691                 * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
    633692                */
    634                 public void actionPerformed(ActionEvent event) {
    635                      if(!index_list.isSelectionEmpty()) {
    636                           removeIndex((Index)index_list.getSelectedValue());
    637                           if(default_index == null) {
    638                                 clear_default.setEnabled(false);
    639                                 default_value.setText("");
    640                           }
    641                      }
    642                 }
    643           }
    644           /** Listens for actions apon the 'set default' button in the IndexManager controls, and if detected calls the setDefault method of the manager with the index selected for default. */
    645           private class SetDefaultListener
    646                 implements ActionListener {
    647                 /** If called when an action occurs on a registered component, we set the default index to the index currently selected.
    648                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
    649                 * @see org.greenstone.gatherer.cdm.Index
    650                 */
    651                 public void actionPerformed(ActionEvent event) {
    652                      setDefault((Index)index_list.getSelectedValue());
    653                      if(default_index != null) {
    654                           clear_default.setEnabled(true);
    655                           default_value.setText(default_index.toString(true));
    656                           default_value.setCaretPosition(0);
    657                      }
    658                      else {
    659                           clear_default.setEnabled(false);
    660                           default_value.setText("");
    661                      }
    662                 }
    663           }
    664           /** Listens for key presses within the name field, and enabled or disables controls as appropriate. */
    665           private class NameListener
    666                 extends KeyAdapter {
    667                 /** Called when a key is released, this is the perfect time to enable the add button if the fields are appropriately set.
    668                 * @param event A <strong>KeyEvent</strong> containing information about the key released.
    669                 */
    670                 public void keyReleased(KeyEvent event) {
    671                      if(source_list.isSelectionEmpty() || name.getText().length() == 0) {
    672                           add.setEnabled(false);
    673                      }
    674                      else {
    675                           add.setEnabled(true);
    676                      }
    677                      if(index_list.isSelectionEmpty()) {
    678                           remove.setEnabled(false);
    679                           set_default.setEnabled(false);
    680                      }
    681                      else {
    682                           remove.setEnabled(true);
    683                           set_default.setEnabled(true);
    684                      }
    685                 }
    686           }
    687           /** Listens for selections within the list on the IndexManager controls, and if a change is detected enables, or disables, controls appropriately. */
    688           private class ListListener
    689                 implements ListSelectionListener {
    690                 /** This method is called whenever the source list selection changes. When it does we need to check if the add button should now be enabled.
    691                 * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
    692                 */
    693                 public void valueChanged(ListSelectionEvent event) {
    694                      if(source_list.isSelectionEmpty() || name.getText().length() == 0) {
    695                           add.setEnabled(false);
    696                      }
    697                      else {
    698                           add.setEnabled(true);
    699                      }
    700                      if(index_list.isSelectionEmpty()) {
    701                           remove.setEnabled(false);
    702                           set_default.setEnabled(false);
    703                      }
    704                      else {
    705                           remove.setEnabled(true);
    706                           set_default.setEnabled(true);
    707                      }
    708                 }
    709           }
    710      }
     693        public void valueChanged(ListSelectionEvent event) {
     694        if(source_list.isSelectionEmpty() || name.getText().length() == 0) {
     695            add.setEnabled(false);
     696        }
     697        else {
     698            add.setEnabled(true);
     699        }
     700        if(index_list.isSelectionEmpty()) {
     701            remove.setEnabled(false);
     702            set_default.setEnabled(false);
     703        }
     704        else {
     705            remove.setEnabled(true);
     706            set_default.setEnabled(true);
     707        }
     708        }
     709    }
     710    }
    711711}
    712712
  • trunk/gli/src/org/greenstone/gatherer/cdm/Language.java

    r4293 r4366  
    5656*/
    5757public class Language
    58     implements Comparable {
    59     /** Is this language the default one. */
    60     private boolean default_language = false;
    61     /** The name of this language. */
    62     private String name = null;
    63     /** The two character code for this language. */
    64     private String value = null;
    65     /** Constructor.
    66       * @param value A <strong>String</strong> representing the code for this language.
    67       * @param name A <strong>String</strong> representing the name of this language.
    68       * @param default_language A <i>boolean</i> which is <i>true</i> if this language is the default one.
     58    implements Comparable {
     59    /** Is this language the default one. */
     60    private boolean default_language = false;
     61    /** The name of this language. */
     62    private String name = null;
     63    /** The two character code for this language. */
     64    private String value = null;
     65    /** Constructor.
     66     * @param value A <strong>String</strong> representing the code for this language.
     67     * @param name A <strong>String</strong> representing the name of this language.
     68     * @param default_language A <i>boolean</i> which is <i>true</i> if this language is the default one.
    6969      */
    70     public Language(String value, String name, boolean default_language) {
    71           this.default_language = default_language;
    72           this.name = name;
    73           this.value = value.substring(0, 2);
    74     }
    75     /** Copy constructor.
     70    public Language(String value, String name, boolean default_language) {
     71    this.default_language = default_language;
     72    this.name = name;
     73    this.value = value.substring(0, 2);
     74    }
     75    /** Copy constructor.
    7676      * @param language The <strong>Language</strong> we want to copy.
    7777      */
    78     public Language(Language language) {
    79           this.default_language = language.isDefault();
    80           this.name = language.toString();
    81           this.value = language.getCode();
    82     }
    83     /** Method to compare two languages for ordering purposes.
     78    public Language(Language language) {
     79    this.default_language = language.isDefault();
     80    this.name = language.toString();
     81    this.value = language.getCode();
     82    }
     83    /** Method to compare two languages for ordering purposes.
    8484      * @param object The other language as an <strong>Object</strong>.
    8585      * @return An <i>int</i> which indicates order using the same values as in String.compareTo().
    8686      * @see java.lang.String#compareTo
    8787      */
    88     public int compareTo(Object object) {
    89           return toString().compareTo(object.toString());
    90     }
    91     /** Method to test for the equality of two languages.
     88    public int compareTo(Object object) {
     89    return toString().compareTo(object.toString());
     90    }
     91    /** Method to test for the equality of two languages.
    9292      * @param object The other language as an <strong>Object</strong>.
    9393      * @return <i>true</i> if the languages are equal, <i>false</i> otherwise.
    9494      */
    95     public boolean equals(Object object) {
    96           if(compareTo(object) == 0) {
    97                 return true;
    98           }
    99           return false;
    100     }
    101     /** Method to retrieve the code of this language.
     95    public boolean equals(Object object) {
     96    if(compareTo(object) == 0) {
     97        return true;
     98    }
     99    return false;
     100    }
     101    /** Method to retrieve the code of this language.
    102102      * @return A <strong>String</strong> representing the two letter code.
    103103      */
    104     public String getCode() {
    105           return value;
    106     }
    107     /** Method to determine if this language is the default one.
     104    public String getCode() {
     105    return value;
     106    }
     107    /** Method to determine if this language is the default one.
    108108      * @return A <i>boolean</i> which is <i>true</i> if this language is the default one.
    109109      */
    110     public boolean isDefault() {
    111           return default_language;
    112     }
    113     /** Method to set the value of default.
     110    public boolean isDefault() {
     111    return default_language;
     112    }
     113    /** Method to set the value of default.
    114114      * @param value The new value of default as a <i>boolean</i>.
    115115      */
    116     public void setDefault(boolean value) {
    117           this.default_language = default_language;
    118     }
    119     /** Method to display the language code.
     116    public void setDefault(boolean value) {
     117    this.default_language = default_language;
     118    }
     119    /** Method to display the language code.
    120120      * @return A <strong>String</strong> representing the language code.
    121121      */
    122     public String toString() {
    123           return name;
    124     }
     122    public String toString() {
     123    return name;
     124    }
    125125}
    126126
  • trunk/gli/src/org/greenstone/gatherer/cdm/LanguageManager.java

    r4293 r4366  
    8585import org.greenstone.gatherer.cdm.Language;
    8686/** This class manages the language commands, remembering both a list of languages to build indexes in, plus the default language.
    87 * @author John Thompson, Greenstone Digital Library, University of Waikato
    88 * @version 2.3
    89 */
     87 * @author John Thompson, Greenstone Digital Library, University of Waikato
     88 * @version 2.3
     89 */
    9090public class LanguageManager
    91     extends DefaultListModel {
    92     /** A reference to the collection design manager. */
    93     private CollectionDesignManager manager = null;
    94     /** The visual controls for this manager. */
    95     private Control controls = null;
    96     /** A reference to the Gatherer. */
    97     private Gatherer gatherer = null;
    98     /** A reference to this class as a model, for the inner controls class. */
    99     private ListModel model = null;
    100     /** A hashtable of code->name mappings of known languages. */
    101     private LinkedHashMap known_languages = null;
    102     /** The default language object. */
    103     private Language default_language = null;
    104     /** Constructor.
    105       * @param gatherer A reference to the <strong>Gatherer</strong>.
    106       * @param manager A reference to the <strong>CollectionDesignManager</strong>.
    107       */
    108     public LanguageManager(Gatherer gatherer, CollectionDesignManager manager) {
    109           super();
    110           this.gatherer = gatherer;
    111           this.known_languages = new LinkedHashMap();
    112           this.manager = manager;
    113           this.model = this;
    114           loadLanguages();
    115     }
    116     /** Method to add a new language.
     91    extends DefaultListModel {
     92    /** A reference to the collection design manager. */
     93    private CollectionDesignManager manager = null;
     94    /** The visual controls for this manager. */
     95    private Control controls = null;
     96    /** A reference to the Gatherer. */
     97    private Gatherer gatherer = null;
     98    /** A reference to this class as a model, for the inner controls class. */
     99    private ListModel model = null;
     100    /** A hashtable of code->name mappings of known languages. */
     101    private LinkedHashMap known_languages = null;
     102    /** The default language object. */
     103    private Language default_language = null;
     104    /** Constructor.
     105     * @param gatherer A reference to the <strong>Gatherer</strong>.
     106     * @param manager A reference to the <strong>CollectionDesignManager</strong>.
     107     */
     108    public LanguageManager(Gatherer gatherer, CollectionDesignManager manager) {
     109    super();
     110    this.gatherer = gatherer;
     111    this.known_languages = new LinkedHashMap();
     112    this.manager = manager;
     113    this.model = this;
     114    loadLanguages();
     115    }
     116    /** Method to add a new language.
    117117      * @param language The <strong>Language</strong> to add.
    118118      * @see org.greenstone.gatherer.Gatherer
    119119      * @see org.greenstone.gatherer.collection.CollectionManager
    120120      */
    121     public void addLanguage(Language language) {
    122           if(!contains(language)) {
     121    public void addLanguage(Language language) {
     122    if(!contains(language)) {
    123123                // Add alphabetically.
    124                 for(int index = 0; index < size(); index++) {
    125                      Language sibling = (Language) get(index);
    126                      int position = language.compareTo(sibling);
    127                      // Sibling is before language.
    128                      if(position > 0) {
    129                           // Carry on.
    130                      }
    131                      // Language is equal to, or before sibling. Insert it.
    132                      else if(position == 0 || position < 0) {
    133                           add(index, language);
    134                           gatherer.c_man.configurationChanged();
    135                           return;
    136                      }
    137                 }
     124        for(int index = 0; index < size(); index++) {
     125        Language sibling = (Language) get(index);
     126        int position = language.compareTo(sibling);
     127        // Sibling is before language.
     128        if(position > 0) {
     129            // Carry on.
     130        }
     131        // Language is equal to, or before sibling. Insert it.
     132        else if(position == 0 || position < 0) {
     133            add(index, language);
     134            gatherer.c_man.configurationChanged();
     135            return;
     136        }
     137        }
    138138                // If we got this far, we haven't inserted language, and we are out of model so.
    139                 addElement(language);
    140                 gatherer.c_man.configurationChanged();
    141           }
    142     }
    143     /** Method to retrieve the control for this manager.
     139        addElement(language);
     140        gatherer.c_man.configurationChanged();
     141    }
     142    }
     143    /** Method to retrieve the control for this manager.
    144144      * @return A <strong>JPanel</strong> containing the controls.
    145145      */
    146     public JPanel getControls() {
    147           if(controls == null) {
    148                 controls = new Control();
    149           }
    150           return controls;
    151     }
    152     /** Method to retrieve the default language code.
     146    public JPanel getControls() {
     147    if(controls == null) {
     148        controls = new Control();
     149    }
     150    return controls;
     151    }
     152    /** Method to retrieve the default language code.
    153153      * @return A <strong>Language</strong> containing a two letter code.
    154154      */
    155     public Language getDefaultLanguage() {
    156           // If no default is set...
    157           if(default_language == null) {
     155    public Language getDefaultLanguage() {
     156    // If no default is set...
     157    if(default_language == null) {
    158158                // And we have other assigned languages, use the first one of them.
    159                 if(size() >= 1) {
    160                      default_language = (Language) get(0);
    161                 }
     159        if(size() >= 1) {
     160        default_language = (Language) get(0);
     161        }
    162162                // And we have nothing else, use English.
    163                 else {
    164                      default_language = getLanguage("en", false);
    165                      // Remember to add it.
    166                      addLanguage(default_language);
    167                 }
    168           }
    169           return default_language;
    170     }
    171     /** Method to retrieve a certain language object by its code.
     163        else {
     164        default_language = getLanguage("en", false);
     165        // Remember to add it.
     166        addLanguage(default_language);
     167        }
     168    }
     169    return default_language;
     170    }
     171    /** Method to retrieve a certain language object by its code.
    172172      * @param code The two letter code of a language, as a <strong>String</strong>.
    173173      * @param assigned_only If <i>true</i> only those languages currently having indexes built for them are checked, otherwise the known languages buffer is checked.
    174174      * @return The <strong>Language</strong> that matches the given code, or <i>null</i> if no such language exists.
    175175      */
    176     public Language getLanguage(String code, boolean assigned_only) {
    177           if(assigned_only) {
    178                 for(int i = 0; i < size(); i++) {
    179                      Language pos = (Language)get(i);
    180                      ///ystem.err.println("Comparing " + pos.getCode() + " and " + code);
    181                      if(pos.getCode().equals(code)) {
    182                           return pos;
    183                      }
    184                 }
    185           }
    186           else {
    187                 if(known_languages.containsKey(code)) {
    188                      return new Language((Language)known_languages.get(code));
    189                 }
    190           }
    191           return null;
    192     }
    193     /** Method to return a list of the known language codes.
     176    public Language getLanguage(String code, boolean assigned_only) {
     177    if(assigned_only) {
     178        for(int i = 0; i < size(); i++) {
     179        Language pos = (Language)get(i);
     180        ///ystem.err.println("Comparing " + pos.getCode() + " and " + code);
     181        if(pos.getCode().equals(code)) {
     182            return pos;
     183        }
     184        }
     185    }
     186    else {
     187        if(known_languages.containsKey(code)) {
     188        return new Language((Language)known_languages.get(code));
     189        }
     190    }
     191    return null;
     192    }
     193    /** Method to return a list of the known language codes.
    194194      * @return An <strong>ArrayList</strong> containing a series of alphabetically sorted two letter codes.
    195195      */
    196     public ArrayList getLanguageCodes() {
    197           ArrayList result = new ArrayList();
    198           Iterator key_iter = known_languages.keySet().iterator();
    199           while(key_iter.hasNext()) {
    200                 result.add(known_languages.get(key_iter.next()));
    201           }
    202           //for(Enumeration keys = known_languages.keys(); keys.hasMoreElements(); ) {
    203           //    result.add(known_languages.get(keys.nextElement()));
    204           //}
    205           //Collections.sort(result);
    206           return result;
    207     }
    208     /** Mark the current set of controls, if any, as obsolete and deallocate them. If further need of the controls will cause new controls to be created.
     196    public ArrayList getLanguageCodes() {
     197    ArrayList result = new ArrayList();
     198    Iterator key_iter = known_languages.keySet().iterator();
     199    while(key_iter.hasNext()) {
     200        result.add(known_languages.get(key_iter.next()));
     201    }
     202    //for(Enumeration keys = known_languages.keys(); keys.hasMoreElements(); ) {
     203    //  result.add(known_languages.get(keys.nextElement()));
     204    //}
     205    //Collections.sort(result);
     206    return result;
     207    }
     208    /** Mark the current set of controls, if any, as obsolete and deallocate them. If further need of the controls will cause new controls to be created.
    209209    * @see org.greenstone.gatherer.cdm.IndexManager.Control
    210210    */
    211     public void invalidateControls() {
    212           if(controls != null) {
    213                 controls.destroy();
    214           }
    215           controls = null;
    216     }
    217 
    218     /** Determine if the given language is the current default language.
     211    public void invalidateControls() {
     212    if(controls != null) {
     213        controls.destroy();
     214    }
     215    controls = null;
     216    }
     217
     218    /** Determine if the given language is the current default language.
    219219      * @param language The <strong>Language</strong> to test.
    220220      * @return <i>true</i> if the language is the default one, <i>false</i> otherwise.
    221221      */
    222     public boolean isDefaultLanguage(Language language) {
    223           return (language.equals(default_language));
    224     }
    225     /** This method attempts to parse a language command from the given string. If such a command is parsed, it is immediately added to the list of languages.
     222    public boolean isDefaultLanguage(Language language) {
     223    return (language.equals(default_language));
     224    }
     225    /** This method attempts to parse a language command from the given string. If such a command is parsed, it is immediately added to the list of languages.
    226226      * @param command The <strong>String</strong> containing a possible language command.
    227227      * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
    228228      * @see org.greenstone.gatherer.cdm.Language
    229229      */
    230     public boolean parse(String command) {
    231           String command_lc = command.toLowerCase();
    232           if(command_lc.startsWith("languages")) {
    233                 StringTokenizer tokenizer = new StringTokenizer(command);
    234                 tokenizer.nextToken();
    235                 while(tokenizer.hasMoreTokens()) {
    236                      String code = tokenizer.nextToken();
    237                      if(known_languages.containsKey(code)) {
    238                           Language language = (Language)known_languages.get(code);
    239                           addElement(new Language(language));
    240                      }
    241                      else {
    242                           addElement(new Language(code, code, false));
    243                      }
    244                 }
    245                 return true;
    246           }
    247           if(command_lc.startsWith("defaultlanguage")) {
    248                 StringTokenizer tokenizer = new StringTokenizer(command);
    249                 tokenizer.nextToken();
    250                 if(tokenizer.hasMoreTokens()) {
    251                      String code = tokenizer.nextToken();
    252                      Language language = getLanguage(code, true);
    253                      if(language == null) {
    254                           language = new Language(code, (String)known_languages.get(code), true);
    255                           addElement(language);
    256                      }
    257                      else {
    258                           language.setDefault(true);
    259                      }
    260                      setDefault(language);
    261                 }
    262                 return true;
    263           }
    264           return false;
    265     }
    266     /** Method to cause the list appearance to update if the selection changes. */
    267     public void refreshAppearance() {
    268           fireContentsChanged(this, 0, size());
    269     }
    270     /** Method to remove a certain language.
     230    public boolean parse(String command) {
     231    String command_lc = command.toLowerCase();
     232    if(command_lc.startsWith("languages")) {
     233        StringTokenizer tokenizer = new StringTokenizer(command);
     234        tokenizer.nextToken();
     235        while(tokenizer.hasMoreTokens()) {
     236        String code = tokenizer.nextToken();
     237        if(known_languages.containsKey(code)) {
     238            Language language = (Language)known_languages.get(code);
     239            addElement(new Language(language));
     240        }
     241        else {
     242            addElement(new Language(code, code, false));
     243        }
     244        }
     245        return true;
     246    }
     247    if(command_lc.startsWith("defaultlanguage")) {
     248        StringTokenizer tokenizer = new StringTokenizer(command);
     249        tokenizer.nextToken();
     250        if(tokenizer.hasMoreTokens()) {
     251        String code = tokenizer.nextToken();
     252        Language language = getLanguage(code, true);
     253        if(language == null) {
     254            language = new Language(code, (String)known_languages.get(code), true);
     255            addElement(language);
     256        }
     257        else {
     258            language.setDefault(true);
     259        }
     260        setDefault(language);
     261        }
     262        return true;
     263    }
     264    return false;
     265    }
     266    /** Method to cause the list appearance to update if the selection changes. */
     267    public void refreshAppearance() {
     268    fireContentsChanged(this, 0, size());
     269    }
     270    /** Method to remove a certain language.
    271271      * @param language The <strong>Language</strong> to remove.
    272272      * @see org.greenstone.gatherer.Gatherer
    273273      * @see org.greenstone.gatherer.collection.CollectionManager
    274274      */
    275     public void removeLanguage(Language language) {
    276           removeElement(language);
    277           if(default_language != null && default_language.equals(language)) {
    278                 default_language = null;
    279           }
    280           gatherer.c_man.configurationChanged();
    281     }
    282     /** Method to set the default language.
     275    public void removeLanguage(Language language) {
     276    removeElement(language);
     277    if(default_language != null && default_language.equals(language)) {
     278        default_language = null;
     279    }
     280    gatherer.c_man.configurationChanged();
     281    }
     282    /** Method to set the default language.
    283283      * @param language The <strong>Language</strong> to use as a default, or <i>null</i> for no default.
    284284      * @see org.greenstone.gatherer.Gatherer
    285285      * @see org.greenstone.gatherer.collection.CollectionManager
    286286      */
    287     public void setDefault(Language language) {
    288           // Unset existing.
    289           Language old = null;
    290           if(default_language != null) {
    291                 old = default_language;
    292                 default_language.setDefault(false);
    293                 default_language = null;
    294           }
    295           // Now set the new if its not null.
    296           if(language != null) {
    297                 default_language = language;
    298                 default_language.setDefault(true);
    299           }
    300           // Now cause the model to refresh any lists that are listening.
    301           int start = 0;
    302           int end = size() - 1;
    303           if(default_language != null && old != null) {
    304                 int index_default = indexOf(default_language);
    305                 int index_old = indexOf(old);
    306                 if(index_default < index_old) {
    307                      start = index_default;
    308                      end = index_old;
    309                 }
    310                 else {
    311                      start = index_old;
    312                      end = index_default;
    313                 }
    314           }
    315           else if(default_language != null) {
    316                 start = end = indexOf(default_language);
    317           }
    318           else {
    319                 start = end = indexOf(old);
    320           }
    321           fireContentsChanged(this, 0, size());
    322           gatherer.c_man.configurationChanged();
    323     }
    324     /** Method to translate this object into a block of commands as you you expect to find in the collection configuration file.
     287    public void setDefault(Language language) {
     288    // Unset existing.
     289    Language old = null;
     290    if(default_language != null) {
     291        old = default_language;
     292        default_language.setDefault(false);
     293        default_language = null;
     294    }
     295    // Now set the new if its not null.
     296    if(language != null) {
     297        default_language = language;
     298        default_language.setDefault(true);
     299    }
     300    // Now cause the model to refresh any lists that are listening.
     301    int start = 0;
     302    int end = size() - 1;
     303    if(default_language != null && old != null) {
     304        int index_default = indexOf(default_language);
     305        int index_old = indexOf(old);
     306        if(index_default < index_old) {
     307        start = index_default;
     308        end = index_old;
     309        }
     310        else {
     311        start = index_old;
     312        end = index_default;
     313        }
     314    }
     315    else if(default_language != null) {
     316        start = end = indexOf(default_language);
     317    }
     318    else {
     319        start = end = indexOf(old);
     320    }
     321    fireContentsChanged(this, 0, size());
     322    gatherer.c_man.configurationChanged();
     323    }
     324    /** Method to translate this object into a block of commands as you you expect to find in the collection configuration file.
    325325      * @return A <strong>String</string> containing a series of commands.
    326326      */
    327     public String toString() {
    328           StringBuffer text = new StringBuffer();
    329           if(size() > 1) {
    330                 text.append("languages ");
    331                 for(int i = 0; i < size(); i++) {
    332                      Language language = (Language) get(i);
    333                      text.append(language.getCode());
    334                      if(i < size() - 1) {
    335                           text.append(" ");
    336                      }
    337                      else {
    338                           text.append("\n");
    339                      }
    340                 }
     327    public String toString() {
     328    StringBuffer text = new StringBuffer();
     329    if(size() > 1) {
     330        text.append("languages ");
     331        for(int i = 0; i < size(); i++) {
     332        Language language = (Language) get(i);
     333        text.append(language.getCode());
     334        if(i < size() - 1) {
     335            text.append(" ");
     336        }
     337        else {
     338            text.append("\n");
     339        }
     340        }
    341341                // Only bother with default language if there is more than one language.
    342                 if(default_language != null) {
    343                      text.append("defaultlanguage ");
    344                      text.append(default_language.getCode());
    345                      text.append("\n");
    346                 }
    347                 text.append("\n");
    348           }
    349           return text.toString();
    350     }
    351     /** Overloaded to call get with both a key and an empty argument array.
     342        if(default_language != null) {
     343        text.append("defaultlanguage ");
     344        text.append(default_language.getCode());
     345        text.append("\n");
     346        }
     347        text.append("\n");
     348    }
     349    return text.toString();
     350    }
     351    /** Overloaded to call get with both a key and an empty argument array.
    352352      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    353353      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
    354354      */
    355     private String get(String key) {
    356           return get(key, null);
    357     }
    358     /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
     355    private String get(String key) {
     356    return get(key, null);
     357    }
     358    /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
    359359      * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
    360360      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     
    364364      * @see org.greenstone.gatherer.Dictionary
    365365      */
    366     private String get(String key, String args[]) {
    367           if(key.indexOf('.') == -1) {
    368                 key = "CDM.LanguageManager." + key;
    369           }
    370           return gatherer.dictionary.get(key, args);
    371     }
    372     /** This method loads a series of code->language mappings into known_languages, by reading from the 'languages.dat' file, which is essentially a verbatim copy of the ISO 639 Standard.
     366    private String get(String key, String args[]) {
     367    if(key.indexOf('.') == -1) {
     368        key = "CDM.LanguageManager." + key;
     369    }
     370    return gatherer.dictionary.get(key, args);
     371    }
     372    /** This method loads a series of code->language mappings into known_languages, by reading from the 'languages.dat' file, which is essentially a verbatim copy of the ISO 639 Standard.
    373373     * @see org.greenstone.gatherer.cdm.Language
    374374      */
    375      private void loadLanguages() {
    376           try {
    377                 File in_file = new File("languages.dat");
    378                 FileReader in_reader = new FileReader(in_file);
    379                 BufferedReader in = new BufferedReader(in_reader);
    380                 String entry = null;
    381                 while((entry = in.readLine()) != null) {
    382                      if(!entry.startsWith("#")) {
    383                           StringTokenizer tokenizer = new StringTokenizer(entry);
    384                           String name = tokenizer.nextToken();
    385                           String code = tokenizer.nextToken().toLowerCase();
    386                           Language language = new Language(code, name, false);
    387                           known_languages.put(code, language);
    388                      }
    389                 }
    390                 in.close();
    391           }
    392           catch (Exception error) {
    393                 error.printStackTrace();
    394           }
    395      }
    396 
    397      /** This class represents the visual component of the Language Manager. */
    398      private class Control
    399           extends JPanel {
    400           /** The button to add a new language support. */
    401           private JButton add = null;
    402           /** The button to clear the current default language. */
    403           private JButton clear_default = null;
    404           /** The button to remove a supported language. */
    405           private JButton remove = null;
    406           /** The button to set the current language as the default one. */
    407           private JButton set_default = null;
    408           /** A button to active the translation manager prompt. */
    409           private JButton translate = null;
    410           /** A combobox listing the available supported languages. */
    411           private JComboBox selector = null;
    412           /** The label denoting the default language. */
    413           private JLabel default_language_label = null;
    414           /** The label denoting the language selector. */
    415           private JLabel selector_label = null;
    416           /** The title label of this control view. */
    417           private JLabel title = null;
    418           /** A list of currently supported languages. */
    419           private JList list = null;
    420           /** The pane in which the control buttons are placed. */
    421           private JPanel button_pane = null;
    422           /** The pane onto which all other panes are placed. */
    423           private JPanel central_pane = null;
    424           /** The pane to the left containing editing controls. */
    425           private JPanel control_pane = null;
    426           /** A panel used to correctly layout the default language box. */
    427           private JPanel default_language_pane = null;
    428           /** The display pane contains the title and instruction controls. */
    429           private JPanel display_pane = null;
    430           /** The pane which holds everything the display pane doesn't! */
    431           private JPanel lower_pane = null;
    432           /** The pane containing the selector combobox. */
    433           private JPanel selector_pane = null;
    434           /** A text area displaying inline instructions. */
    435           private JTextArea instructions = null;
    436           /** A description of the language currently selected. */
    437           private JTextArea description = null;
    438           /** The text field showing the currently name of the default language. Non-editable. */
    439           private JTextField default_language_value = null;
    440           /** Constructor.
    441             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.AddListener
    442             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.ClearDefaultListener
    443             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.ListListener
    444             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.RemoveListener
    445             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.SelectorListener
    446             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.SetDefaultListener
    447             * @see org.greenstone.gatherer.cdm.LanguageManager.Control.TranslateListener
     375    private void loadLanguages() {
     376    try {
     377        File in_file = new File("languages.dat");
     378        FileReader in_reader = new FileReader(in_file);
     379        BufferedReader in = new BufferedReader(in_reader);
     380        String entry = null;
     381        while((entry = in.readLine()) != null) {
     382        if(!entry.startsWith("#")) {
     383            StringTokenizer tokenizer = new StringTokenizer(entry);
     384            String name = tokenizer.nextToken();
     385            String code = tokenizer.nextToken().toLowerCase();
     386            Language language = new Language(code, name, false);
     387            known_languages.put(code, language);
     388        }
     389        }
     390        in.close();
     391    }
     392    catch (Exception error) {
     393        error.printStackTrace();
     394    }
     395    }
     396
     397    /** This class represents the visual component of the Language Manager. */
     398    private class Control
     399    extends JPanel {
     400    /** The button to add a new language support. */
     401    private JButton add = null;
     402    /** The button to clear the current default language. */
     403    private JButton clear_default = null;
     404    /** The button to remove a supported language. */
     405    private JButton remove = null;
     406    /** The button to set the current language as the default one. */
     407    private JButton set_default = null;
     408    /** A button to active the translation manager prompt. */
     409    private JButton translate = null;
     410    /** A combobox listing the available supported languages. */
     411    private JComboBox selector = null;
     412    /** The label denoting the default language. */
     413    private JLabel default_language_label = null;
     414    /** The label denoting the language selector. */
     415    private JLabel selector_label = null;
     416    /** The title label of this control view. */
     417    private JLabel title = null;
     418    /** A list of currently supported languages. */
     419    private JList list = null;
     420    /** The pane in which the control buttons are placed. */
     421    private JPanel button_pane = null;
     422    /** The pane onto which all other panes are placed. */
     423    private JPanel central_pane = null;
     424    /** The pane to the left containing editing controls. */
     425    private JPanel control_pane = null;
     426    /** A panel used to correctly layout the default language box. */
     427    private JPanel default_language_pane = null;
     428    /** The display pane contains the title and instruction controls. */
     429    private JPanel display_pane = null;
     430    /** The pane which holds everything the display pane doesn't! */
     431    private JPanel lower_pane = null;
     432    /** The pane containing the selector combobox. */
     433    private JPanel selector_pane = null;
     434    /** A text area displaying inline instructions. */
     435    private JTextArea instructions = null;
     436    /** A description of the language currently selected. */
     437    private JTextArea description = null;
     438    /** The text field showing the currently name of the default language. Non-editable. */
     439    private JTextField default_language_value = null;
     440    /** Constructor.
     441     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.AddListener
     442     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.ClearDefaultListener
     443     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.ListListener
     444     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.RemoveListener
     445     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.SelectorListener
     446     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.SetDefaultListener
     447     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.TranslateListener
     448     */
     449    public Control() {
     450        super();
     451                // Creation.
     452        title = new JLabel(get("Title"));
     453        title.setHorizontalAlignment(JLabel.CENTER);
     454        title.setOpaque(true);
     455
     456        central_pane = new JPanel();
     457
     458        control_pane = new JPanel();
     459
     460        instructions = new JTextArea(get("Instructions"));
     461        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     462        instructions.setEditable(false);
     463        instructions.setLineWrap(true);
     464        instructions.setWrapStyleWord(true);
     465
     466        selector_pane = new JPanel();
     467
     468        selector_label = new JLabel(get("Selector"));
     469        selector = new JComboBox(getLanguageCodes().toArray());
     470
     471        display_pane = new JPanel();
     472
     473        list = new JList(model);
     474        list.setCellRenderer(new ListRenderer());
     475
     476        default_language_pane = new JPanel();
     477
     478        default_language_label = new JLabel(get("Default_Language"));
     479        default_language_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     480        if(default_language == null) {
     481        default_language_value = new JTextField();
     482        }
     483        else {
     484        default_language_value = new JTextField(default_language.toString());
     485        }
     486        default_language_value.setBackground(Color.white);
     487        default_language_value.setEditable(false);
     488
     489        button_pane = new JPanel();
     490
     491        add = new JButton(get("Add"));
     492        add.setMnemonic(KeyEvent.VK_A);
     493        if(selector.getSelectedItem() != null) {
     494        add.setEnabled(true);
     495        }
     496        else {
     497        add.setEnabled(false);
     498        }
     499
     500        remove = new JButton(get("Remove"));
     501        remove.setMnemonic(KeyEvent.VK_R);
     502        remove.setEnabled(false);
     503
     504        clear_default = new JButton(get("Clear_Default"));
     505        clear_default.setMnemonic(KeyEvent.VK_C);
     506        clear_default.setEnabled(false);
     507
     508        set_default = new JButton(get("Set_Default"));
     509        set_default.setMnemonic(KeyEvent.VK_S);
     510        set_default.setEnabled(false);
     511
     512        lower_pane = new JPanel();
     513        translate = new JButton(get("Translate"));
     514        translate.setMnemonic(KeyEvent.VK_T);
     515
     516                // Set up and connect listeners.
     517        add.addActionListener(new AddListener());
     518        clear_default.addActionListener(new ClearDefaultListener());
     519        remove.addActionListener(new RemoveListener());
     520        selector.addActionListener(new SelectorListener());
     521        set_default.addActionListener(new SetDefaultListener());
     522        translate.addActionListener(new TranslateListener());
     523        list.addListSelectionListener(new ListListener());
     524                // Layout components.
     525        selector_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
     526        selector_pane.setLayout(new BorderLayout());
     527        selector_pane.add(selector_label, BorderLayout.WEST);
     528        selector_pane.add(selector, BorderLayout.CENTER);
     529
     530        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     531
     532        control_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     533        control_pane.setLayout(new BorderLayout());
     534        control_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     535        control_pane.add(selector_pane, BorderLayout.SOUTH);
     536
     537        default_language_pane.setBorder
     538        (BorderFactory.createCompoundBorder
     539         (BorderFactory.createCompoundBorder
     540          (BorderFactory.createEmptyBorder(5,5,5,5),
     541           BorderFactory.createRaisedBevelBorder()),
     542          BorderFactory.createEmptyBorder(2,2,2,2)));
     543        default_language_pane.setLayout(new BorderLayout());
     544        default_language_pane.add(default_language_label, BorderLayout.WEST);
     545        default_language_pane.add(default_language_value, BorderLayout.CENTER);
     546
     547        display_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,5));
     548        display_pane.setLayout(new BorderLayout());
     549        display_pane.add(new JScrollPane(list), BorderLayout.CENTER);
     550        display_pane.add(default_language_pane, BorderLayout.SOUTH);
     551
     552        central_pane.setLayout(new GridLayout(1,2));
     553        central_pane.add(control_pane);
     554        central_pane.add(display_pane);
     555
     556        button_pane.setLayout(new GridLayout(2,2));
     557        button_pane.add(add);
     558        button_pane.add(remove);
     559        button_pane.add(clear_default);
     560        button_pane.add(set_default);
     561
     562        lower_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
     563        lower_pane = new JPanel(new BorderLayout());
     564        lower_pane.add(button_pane, BorderLayout.NORTH);
     565        lower_pane.add(translate, BorderLayout.CENTER);
     566
     567        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     568        setLayout(new BorderLayout());
     569        add(title, BorderLayout.NORTH);
     570        add(central_pane, BorderLayout.CENTER);
     571        add(lower_pane, BorderLayout.SOUTH);
     572    }
     573    /** Destructor.
    448574            */
    449           public Control() {
    450                 super();
    451                 // Creation.
    452                 title = new JLabel(get("Title"));
    453                 title.setHorizontalAlignment(JLabel.CENTER);
    454                 title.setOpaque(true);
    455 
    456                 central_pane = new JPanel();
    457 
    458                 control_pane = new JPanel();
    459 
    460                 instructions = new JTextArea(get("Instructions"));
    461                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    462                 instructions.setEditable(false);
    463                 instructions.setLineWrap(true);
    464                 instructions.setWrapStyleWord(true);
    465 
    466                 selector_pane = new JPanel();
    467 
    468                 selector_label = new JLabel(get("Selector"));
    469                 selector = new JComboBox(getLanguageCodes().toArray());
    470 
    471                 display_pane = new JPanel();
    472 
    473                 list = new JList(model);
    474                 list.setCellRenderer(new ListRenderer());
    475 
    476                 default_language_pane = new JPanel();
    477 
    478                 default_language_label = new JLabel(get("Default_Language"));
    479                 default_language_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    480                 if(default_language == null) {
    481                      default_language_value = new JTextField();
    482                 }
    483                 else {
    484                      default_language_value = new JTextField(default_language.toString());
    485                 }
    486                 default_language_value.setBackground(Color.white);
    487                 default_language_value.setEditable(false);
    488 
    489                 button_pane = new JPanel();
    490 
    491                 add = new JButton(get("Add"));
    492                 add.setMnemonic(KeyEvent.VK_A);
    493                 if(selector.getSelectedItem() != null) {
    494                      add.setEnabled(true);
    495                 }
    496                 else {
    497                      add.setEnabled(false);
    498                 }
    499 
    500                 remove = new JButton(get("Remove"));
    501                 remove.setMnemonic(KeyEvent.VK_R);
    502                 remove.setEnabled(false);
    503 
    504                 clear_default = new JButton(get("Clear_Default"));
    505                 clear_default.setMnemonic(KeyEvent.VK_C);
    506                 clear_default.setEnabled(false);
    507 
    508                 set_default = new JButton(get("Set_Default"));
    509                 set_default.setMnemonic(KeyEvent.VK_S);
    510                 set_default.setEnabled(false);
    511 
    512                 lower_pane = new JPanel();
    513                 translate = new JButton(get("Translate"));
    514                 translate.setMnemonic(KeyEvent.VK_T);
    515 
    516                 // Set up and connect listeners.
    517                 add.addActionListener(new AddListener());
    518                 clear_default.addActionListener(new ClearDefaultListener());
    519                 remove.addActionListener(new RemoveListener());
    520                 selector.addActionListener(new SelectorListener());
    521                 set_default.addActionListener(new SetDefaultListener());
    522                 translate.addActionListener(new TranslateListener());
    523                 list.addListSelectionListener(new ListListener());
    524                 // Layout components.
    525                 selector_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
    526                 selector_pane.setLayout(new BorderLayout());
    527                 selector_pane.add(selector_label, BorderLayout.WEST);
    528                 selector_pane.add(selector, BorderLayout.CENTER);
    529 
    530                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    531 
    532                 control_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    533                 control_pane.setLayout(new BorderLayout());
    534                 control_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    535                 control_pane.add(selector_pane, BorderLayout.SOUTH);
    536 
    537                 default_language_pane.setBorder
    538                      (BorderFactory.createCompoundBorder
    539                       (BorderFactory.createCompoundBorder
    540                         (BorderFactory.createEmptyBorder(5,5,5,5),
    541                          BorderFactory.createRaisedBevelBorder()),
    542                         BorderFactory.createEmptyBorder(2,2,2,2)));
    543                 default_language_pane.setLayout(new BorderLayout());
    544                 default_language_pane.add(default_language_label, BorderLayout.WEST);
    545                 default_language_pane.add(default_language_value, BorderLayout.CENTER);
    546 
    547                 display_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,5));
    548                 display_pane.setLayout(new BorderLayout());
    549                 display_pane.add(new JScrollPane(list), BorderLayout.CENTER);
    550                 display_pane.add(default_language_pane, BorderLayout.SOUTH);
    551 
    552                 central_pane.setLayout(new GridLayout(1,2));
    553                 central_pane.add(control_pane);
    554                 central_pane.add(display_pane);
    555 
    556                 button_pane.setLayout(new GridLayout(2,2));
    557                 button_pane.add(add);
    558                 button_pane.add(remove);
    559                 button_pane.add(clear_default);
    560                 button_pane.add(set_default);
    561 
    562                 lower_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    563                 lower_pane = new JPanel(new BorderLayout());
    564                 lower_pane.add(button_pane, BorderLayout.NORTH);
    565                 lower_pane.add(translate, BorderLayout.CENTER);
    566 
    567                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    568                 setLayout(new BorderLayout());
    569                 add(title, BorderLayout.NORTH);
    570                 add(central_pane, BorderLayout.CENTER);
    571                 add(lower_pane, BorderLayout.SOUTH);
    572           }
    573           /** Destructor.
     575    public void destroy() {
     576    }
     577    /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
    574578            */
    575           public void destroy() {
    576           }
    577           /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
    578             */
    579           public void updateUI() {
    580                 if(instructions != null) {
    581                      instructions.setCaretPosition(0);
    582                 }
    583                 super.updateUI();
    584           }
    585           /** Listens for actions apon the 'add' button in the LanguageManager controls, and if detected calls the add method of the manager with a newly created language. */
    586           private class AddListener
    587                 implements ActionListener {
     579    public void updateUI() {
     580        if(instructions != null) {
     581        instructions.setCaretPosition(0);
     582        }
     583        super.updateUI();
     584    }
     585    /** Listens for actions apon the 'add' button in the LanguageManager controls, and if detected calls the add method of the manager with a newly created language. */
     586    private class AddListener
     587        implements ActionListener {
    588588                /** Add a new language support.
    589                 * @param event An <strong>ActionEvent</strong>.
    590                 * @see org.greenstone.gatherer.cdm.Language
     589                 * @param event An <strong>ActionEvent</strong>.
     590                 * @see org.greenstone.gatherer.cdm.Language
     591                 */
     592        public void actionPerformed(ActionEvent event) {
     593        Language language = (Language)selector.getSelectedItem();
     594        if(language != null) {
     595            addLanguage(new Language(language));
     596        }
     597        }
     598    }
     599    /** Listens for actions apon the 'clear default' button in the LanguageManager controls, and if detected calls the setDefault method of the manager with <i>null</i>. */
     600    private class ClearDefaultListener
     601        implements ActionListener {
     602                /** Clear the default index.
     603                 * @param event An <strong>ActionEvent</strong>.
    591604                */
    592                 public void actionPerformed(ActionEvent event) {
    593                      Language language = (Language)selector.getSelectedItem();
    594                      if(language != null) {
    595                           addLanguage(new Language(language));
    596                      }
    597                 }
    598           }
    599           /** Listens for actions apon the 'clear default' button in the LanguageManager controls, and if detected calls the setDefault method of the manager with <i>null</i>. */
    600           private class ClearDefaultListener
    601                 implements ActionListener {
    602                 /** Clear the default index.
    603                 * @param event An <strong>ActionEvent</strong>.
     605        public void actionPerformed(ActionEvent event) {
     606        setDefault(null);
     607        clear_default.setEnabled(false);
     608        default_language_value.setText("");
     609        }
     610    }
     611    /** Listens for actions apon the 'remove' button in the LanguageManager controls, and if detected calls the remove method of the manager with the language selected for removal. */
     612    private class RemoveListener
     613        implements ActionListener {
     614                /** Remove the currently selected language, if any.
     615                 * @param event An <strong>ActionEvent</strong>.
     616                 * @see org.greenstone.gatherer.cdm.Language
     617                 */
     618        public void actionPerformed(ActionEvent event) {
     619        if(!list.isSelectionEmpty()) {
     620            removeLanguage((Language)list.getSelectedValue());
     621            if(default_language == null) {
     622            clear_default.setEnabled(false);
     623            default_language_value.setText("");
     624            }
     625        }
     626        }
     627    }
     628    /** Listens for selections wihtin the combobox on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
     629    private class SelectorListener
     630        implements ActionListener {
     631                /** Enable or disable controls depeding on selection.
     632                 * @param event An <strong>ActionEvent</strong>.
    604633                */
    605                 public void actionPerformed(ActionEvent event) {
    606                      setDefault(null);
    607                      clear_default.setEnabled(false);
    608                      default_language_value.setText("");
    609                 }
    610           }
    611           /** Listens for actions apon the 'remove' button in the LanguageManager controls, and if detected calls the remove method of the manager with the language selected for removal. */
    612           private class RemoveListener
    613                 implements ActionListener {
    614                 /** Remove the currently selected language, if any.
    615                 * @param event An <strong>ActionEvent</strong>.
    616                 * @see org.greenstone.gatherer.cdm.Language
     634        public void actionPerformed(ActionEvent event) {
     635        if(selector.getSelectedItem() != null) {
     636            add.setEnabled(true);
     637            //description.setText((String)known_languages.get(code));
     638        }
     639        else {
     640            add.setEnabled(false);
     641            //description.setText("");
     642        }
     643        }
     644    }
     645    /** Listens for actions apon the 'set default' button in the LanguageManager controls, and if detected calls the <i>setDefault()</i> method of the manager with the language selected for default. */
     646    private class SetDefaultListener
     647        implements ActionListener {
     648                /** Set the default index to the one currently selected, if any.
     649                 * @param event An <strong>ActionEvent</strong>.
     650                 * @see org.greenstone.gatherer.cdm.Language
     651                 */
     652        public void actionPerformed(ActionEvent event) {
     653        if(!list.isSelectionEmpty()) {
     654            setDefault((Language)list.getSelectedValue());
     655            clear_default.setEnabled(true);
     656            default_language_value.setText(default_language.toString());
     657        }
     658        }
     659    }
     660    /** Listens for actions apon the 'translate' button in the LanguageManager controls, and if detected creates a new <strong>TranslationManager</strong> to allow the user to tranlate. */
     661    private class TranslateListener
     662        implements ActionListener {
     663                /** Create a new translation manager, but remember to clean up after it disposes.
     664                 * @param event An <strong>ActionEvent</strong>.
     665                 * @see org.greenstone.gatherer.cdm.TranslationManager
     666                 */
     667        public void actionPerformed(ActionEvent event) {
     668        TranslationManager tm = new TranslationManager(gatherer, manager);
     669        tm.destroy();
     670        }
     671    }
     672    /** Listens for selections within the list on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
     673    private class ListListener
     674        implements ListSelectionListener {
     675                /** Enable or disable controls depending on the current list selection.
     676                 * @param event A <strong>ListSelectionEvent</strong>.
    617677                */
    618                 public void actionPerformed(ActionEvent event) {
    619                      if(!list.isSelectionEmpty()) {
    620                           removeLanguage((Language)list.getSelectedValue());
    621                           if(default_language == null) {
    622                                 clear_default.setEnabled(false);
    623                                 default_language_value.setText("");
    624                           }
    625                      }
    626                 }
    627           }
    628           /** Listens for selections wihtin the combobox on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
    629           private class SelectorListener
    630                 implements ActionListener {
    631                 /** Enable or disable controls depeding on selection.
    632                 * @param event An <strong>ActionEvent</strong>.
    633                 */
    634                 public void actionPerformed(ActionEvent event) {
    635                      if(selector.getSelectedItem() != null) {
    636                           add.setEnabled(true);
    637                           //description.setText((String)known_languages.get(code));
    638                      }
    639                      else {
    640                           add.setEnabled(false);
    641                           //description.setText("");
    642                      }
    643                 }
    644           }
    645           /** Listens for actions apon the 'set default' button in the LanguageManager controls, and if detected calls the <i>setDefault()</i> method of the manager with the language selected for default. */
    646           private class SetDefaultListener
    647                 implements ActionListener {
    648                 /** Set the default index to the one currently selected, if any.
    649                 * @param event An <strong>ActionEvent</strong>.
    650                 * @see org.greenstone.gatherer.cdm.Language
    651                 */
    652                 public void actionPerformed(ActionEvent event) {
    653                      if(!list.isSelectionEmpty()) {
    654                           setDefault((Language)list.getSelectedValue());
    655                           clear_default.setEnabled(true);
    656                           default_language_value.setText(default_language.toString());
    657                      }
    658                 }
    659           }
    660           /** Listens for actions apon the 'translate' button in the LanguageManager controls, and if detected creates a new <strong>TranslationManager</strong> to allow the user to tranlate. */
    661           private class TranslateListener
    662                 implements ActionListener {
    663                 /** Create a new translation manager, but remember to clean up after it disposes.
    664                 * @param event An <strong>ActionEvent</strong>.
    665                 * @see org.greenstone.gatherer.cdm.TranslationManager
    666                 */
    667                 public void actionPerformed(ActionEvent event) {
    668                      TranslationManager tm = new TranslationManager(gatherer, manager);
    669                      tm.destroy();
    670                 }
    671           }
    672           /** Listens for selections within the list on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
    673           private class ListListener
    674                 implements ListSelectionListener {
    675                 /** Enable or disable controls depending on the current list selection.
    676                 * @param event A <strong>ListSelectionEvent</strong>.
    677                 */
    678                 public void valueChanged(ListSelectionEvent event) {
    679                      if(list.isSelectionEmpty()) {
    680                           remove.setEnabled(false);
    681                           set_default.setEnabled(false);
    682                      }
    683                      else {
    684                           remove.setEnabled(true);
    685                           set_default.setEnabled(true);
    686                      }
    687                      refreshAppearance();
    688                 }
    689           }
    690           /** Our list cel renderer which renders the default cell just a little different. */
    691           private class ListRenderer
    692                 extends DefaultListCellRenderer {
     678        public void valueChanged(ListSelectionEvent event) {
     679        if(list.isSelectionEmpty()) {
     680            remove.setEnabled(false);
     681            set_default.setEnabled(false);
     682        }
     683        else {
     684            remove.setEnabled(true);
     685            set_default.setEnabled(true);
     686        }
     687        refreshAppearance();
     688        }
     689    }
     690    /** Our list cel renderer which renders the default cell just a little different. */
     691    private class ListRenderer
     692        extends DefaultListCellRenderer {
    693693                /** Method to produce the component used to display an entry in the list.
    694694                 * @param list The <strong>JList</strong> the component will be placed in.
     
    700700                 * @see org.greenstone.gatherer.cdm.Language
    701701                 */
    702                 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    703                      Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    704                      Language language = (Language) value;
    705                      if(language.isDefault() && !isSelected) {
    706                           component.setBackground(Gatherer.config.getColor("coloring.workspace_selection_background", false));
    707                      }
    708                      if(component instanceof JLabel) {
    709                           ((JLabel)component).setOpaque(true);
    710                      }
    711                      return component;
    712                 }
    713           }
    714     }
     702        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     703        Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     704        Language language = (Language) value;
     705        if(language.isDefault() && !isSelected) {
     706            component.setBackground(Gatherer.config.getColor("coloring.workspace_selection_background", false));
     707        }
     708        if(component instanceof JLabel) {
     709            ((JLabel)component).setOpaque(true);
     710        }
     711        return component;
     712        }
     713    }
     714    }
    715715}
    716716
  • trunk/gli/src/org/greenstone/gatherer/cdm/MetadataSetManager.java

    r4293 r4366  
    7878import org.w3c.dom.NodeList;
    7979/** Unlike its namesake in the msm package, this class really only knows how to produce a simple visual representation of the currently imported metadata sets. It is also read-only, so should be fairly straight forward.
    80 * @author John Thompson, Greenstone Digital Library, University of Waikato
    81 * @version 2.3
    82 * @see org.greenstone.gatherer.msm.MetadataSetManager
    83 */
     80 * @author John Thompson, Greenstone Digital Library, University of Waikato
     81 * @version 2.3
     82 * @see org.greenstone.gatherer.msm.MetadataSetManager
     83 */
    8484public class MetadataSetManager
    85     extends DynamicListModel
    86     implements MSMListener {
    87     /** The visual contols used to review the metadata sets. */
    88     private Control controls = null;
    89     /** A reference to the Gatherer. */
    90     private Gatherer gatherer = null;
    91     /** A reference to ourselves so our inner classes can refer to us. */
    92     private DynamicListModel model = null;
    93     /** Constructor.
    94       * @param gatherer A reference to the <strong>Gatherer</strong>.
    95       * @see org.greenstone.gatherer.collection.CollectionManager
    96       * @see org.greenstone.gatherer.msm.MetadataSetManager
    97       */
    98     public MetadataSetManager(Gatherer gatherer) {
    99           this.gatherer = gatherer;
    100           this.model = this;
    101           Gatherer.c_man.getCollection().msm.addMSMListener(this);
    102           loadMetadataSets();
    103     }
    104     /** Destructor. Remove any references of this class from persistant objects.
     85    extends DynamicListModel
     86    implements MSMListener {
     87    /** The visual contols used to review the metadata sets. */
     88    private Control controls = null;
     89    /** A reference to the Gatherer. */
     90    private Gatherer gatherer = null;
     91    /** A reference to ourselves so our inner classes can refer to us. */
     92    private DynamicListModel model = null;
     93    /** Constructor.
     94     * @param gatherer A reference to the <strong>Gatherer</strong>.
     95     * @see org.greenstone.gatherer.collection.CollectionManager
     96     * @see org.greenstone.gatherer.msm.MetadataSetManager
     97     */
     98    public MetadataSetManager(Gatherer gatherer) {
     99    this.gatherer = gatherer;
     100    this.model = this;
     101    Gatherer.c_man.getCollection().msm.addMSMListener(this);
     102    loadMetadataSets();
     103    }
     104    /** Destructor. Remove any references of this class from persistant objects.
    105105        * @see org.greenstone.gatherer.Gatherer
    106106      * @see org.greenstone.gatherer.collection.CollectionManager
    107107      * @see org.greenstone.gatherer.msm.MetadataSetManager
    108108      */
    109     public void destroy() {
    110           gatherer.c_man.msm.removeMSMListener(this);
    111     }
    112     /** Called when an element is changed within a set in the MSM, prompting us to refresh our list of elements being shown.
     109    public void destroy() {
     110    gatherer.c_man.msm.removeMSMListener(this);
     111    }
     112    /** Called when an element is changed within a set in the MSM, prompting us to refresh our list of elements being shown.
    113113      * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
    114114        * @see org.greenstone.gatherer.cdm.MetadataSetManager.Control
    115115      */
    116     public void elementChanged(MSMEvent event) {
    117           // Get the controls to refresh element list.
    118           if(controls != null) {
    119                 controls.refreshElementList();
    120           }
    121     }
    122     /** A method for retrieve the controls for this manager.
     116    public void elementChanged(MSMEvent event) {
     117    // Get the controls to refresh element list.
     118    if(controls != null) {
     119        controls.refreshElementList();
     120    }
     121    }
     122    /** A method for retrieve the controls for this manager.
    123123      * @see org.greenstone.gatherer.Dictionary
    124124      * @see org.greenstone.gatherer.gui.Coloring
    125125      * @see org.greenstone.gatherer.msm.MetadataSetManager
    126126      */
    127     public Control getControls() {
    128           if(controls == null) {
    129                 controls = new Control();
    130           }
    131           return controls;
    132     }
    133     /** A method to invalidate the current set of controls, as they become obselete.
     127    public Control getControls() {
     128    if(controls == null) {
     129        controls = new Control();
     130    }
     131    return controls;
     132    }
     133    /** A method to invalidate the current set of controls, as they become obselete.
    134134        * @see org.greenstone.gatherer.cdm.MetadataSetManager.Control
    135135      */
    136     public void invalidateControls() {
    137           if(controls != null) {
    138                 controls.destroy();
    139           }
    140           controls = null;
    141     }
    142     /** Called when a metadata value has undergone significant change.
     136    public void invalidateControls() {
     137    if(controls != null) {
     138        controls.destroy();
     139    }
     140    controls = null;
     141    }
     142    /** Called when a metadata value has undergone significant change.
    143143      * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
    144144      */
    145     public void metadataChanged(MSMEvent event) {
    146           // Couldn't care less.
    147     }
    148     /** Called when a set is added or removed from the MSM.
     145    public void metadataChanged(MSMEvent event) {
     146    // Couldn't care less.
     147    }
     148    /** Called when a set is added or removed from the MSM.
    149149      * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
    150150      */
    151     public void setChanged(MSMEvent event) {
    152           // Reload model.
    153           clear();
    154           loadMetadataSets();
    155     }
    156     /** Select the selected element, given its name, and return the bounds of the selection. Used during search and replace.
     151    public void setChanged(MSMEvent event) {
     152    // Reload model.
     153    clear();
     154    loadMetadataSets();
     155    }
     156    /** Select the selected element, given its name, and return the bounds of the selection. Used during search and replace.
    157157    * @param element The elements fully qualified name as a <strong>String</strong>.
    158158    * @return The bounds of the selection as a <strong>Rectangle</strong>.
    159159    * @see org.greenstone.gatherer.cdm.MetadataSetManager.Control
    160160    */
    161     public Rectangle setSelectedElement(String element) {
    162           if(controls != null) {
    163                 return controls.setSelectedElement(element);
    164           }
    165           return null;
    166     }
    167     /** Prints out the contents of this manager, as they would appear in the collection configuration file.
     161    public Rectangle setSelectedElement(String element) {
     162    if(controls != null) {
     163        return controls.setSelectedElement(element);
     164    }
     165    return null;
     166    }
     167    /** Prints out the contents of this manager, as they would appear in the collection configuration file.
    168168      * @return A <strong>String</strong> containing a block of commands.
    169169      * @see org.greenstone.gatherer.cdm.MetadataSetManager.SetWrapper
    170170      */
    171     public String toString() {
    172           String text = "";
    173           for(int i = 0; i < size(); i++) {
    174                 SetWrapper set = (SetWrapper)get(i);
    175                 text = text + set.toString() + "\n";
    176           }
    177           text = text + "\n";
    178           return text;
    179     }
    180     /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
     171    public String toString() {
     172    String text = "";
     173    for(int i = 0; i < size(); i++) {
     174        SetWrapper set = (SetWrapper)get(i);
     175        text = text + set.toString() + "\n";
     176    }
     177    text = text + "\n";
     178    return text;
     179    }
     180    /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
    181181      * @param event A <strong>MSMEvent</strong> containing information relevant to the event.
    182182      */
    183     public void valueChanged(MSMEvent event) {
    184     }
    185     /** Method to retrieve a phrase from the dictionary based on a key.
     183    public void valueChanged(MSMEvent event) {
     184    }
     185    /** Method to retrieve a phrase from the dictionary based on a key.
    186186      * @param key A <strong>String</strong> used to find the correct phrase.
    187187      * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
    188188      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    189189      */
    190     private String get(String key) {
    191           return get(key, null);
    192     }
    193     /** Method to retrieve a phrase from the dictionary based on a key.
     190    private String get(String key) {
     191    return get(key, null);
     192    }
     193    /** Method to retrieve a phrase from the dictionary based on a key.
    194194      * @param key A <strong>String</strong> used to find the correct phrase.
    195195      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
     
    197197      * @see org.greenstone.gatherer.Gatherer
    198198      */
    199     private String get(String key, String args[]) {
    200           if(key.indexOf(".") == -1) {
    201                 key = "CDM.MetadataSetManager." + key;
    202           }
    203           return gatherer.dictionary.get(key, args);
    204     }
    205     /** Retrieves the current list of loaded metadata sets, and builds a list model around them.
     199    private String get(String key, String args[]) {
     200    if(key.indexOf(".") == -1) {
     201        key = "CDM.MetadataSetManager." + key;
     202    }
     203    return gatherer.dictionary.get(key, args);
     204    }
     205    /** Retrieves the current list of loaded metadata sets, and builds a list model around them.
    206206        * @see org.greenstone.gatherer.Gatherer
    207207        * @see org.greenstone.gatherer.cdm.MetadataSetManager.SetWrapper
     
    210210        * @see org.greenstone.gatherer.msm.MetadataSetManager
    211211      */
    212      private void loadMetadataSets() {
    213           // We initialize the set_model with wrapped metadata sets. Note that when we call getSets() we also end up adding ourselves as a listener to the metadata set manager.
    214           Vector sets = gatherer.c_man.getCollection().msm.getSets();
    215           for(int i = 0; i < sets.size(); i++) {
    216                 addElement(new SetWrapper((MetadataSet)sets.get(i)));
    217           }
    218      }
    219      /** This class creates and lays-out the various controls for reviewing the metadata sets, and their commands as they would appear in the collection configuration file. */
    220      private class Control
    221           extends JPanel {
    222           /** The label denoting the element list. */
    223           private JLabel element_label = null;
    224           /** The label denoting the set list. */
    225           private JLabel set_label = null;
    226           /** The title of these controls. */
    227           private JLabel title = null;
    228           /** The list of elements for the choosen set. */
    229           private JList element_list = null;
    230           /** The list of sets in this collection. */
    231           private JList set_list = null;
    232           /** The panel onto which all other panels will be placed. */
    233           private JPanel central_pane = null;
    234           /** The panel onto which the element list will be placed. */
    235           private JPanel element_pane = null;
    236           /** The panel containing the title and instructions. */
    237           private JPanel header_pane = null;
    238           /** The panel containing the set list. */
    239           private JPanel set_pane = null;
    240           /** The text area of inline instructions. */
    241           private JTextArea instructions = null;
    242           /** The element model for the currently selected set. */
    243           private Vector element_model = null;
    244           /* Constructor.
    245           * @see org.greenstone.gatherer.Coloring;
    246           * @see org.greenstone.gatherer.Dictionary
    247           * @see org.greenstone.gatherer.cdm.MetadataSetManager.ListListener
    248           * @see org.greenstone.gatherer.msm.MetadataSetManager
     212    private void loadMetadataSets() {
     213    // We initialize the set_model with wrapped metadata sets. Note that when we call getSets() we also end up adding ourselves as a listener to the metadata set manager.
     214    Vector sets = gatherer.c_man.getCollection().msm.getSets();
     215    for(int i = 0; i < sets.size(); i++) {
     216        addElement(new SetWrapper((MetadataSet)sets.get(i)));
     217    }
     218    }
     219    /** This class creates and lays-out the various controls for reviewing the metadata sets, and their commands as they would appear in the collection configuration file. */
     220    private class Control
     221    extends JPanel {
     222    /** The label denoting the element list. */
     223    private JLabel element_label = null;
     224    /** The label denoting the set list. */
     225    private JLabel set_label = null;
     226    /** The title of these controls. */
     227    private JLabel title = null;
     228    /** The list of elements for the choosen set. */
     229    private JList element_list = null;
     230    /** The list of sets in this collection. */
     231    private JList set_list = null;
     232    /** The panel onto which all other panels will be placed. */
     233    private JPanel central_pane = null;
     234    /** The panel onto which the element list will be placed. */
     235    private JPanel element_pane = null;
     236    /** The panel containing the title and instructions. */
     237    private JPanel header_pane = null;
     238    /** The panel containing the set list. */
     239    private JPanel set_pane = null;
     240    /** The text area of inline instructions. */
     241    private JTextArea instructions = null;
     242    /** The element model for the currently selected set. */
     243    private Vector element_model = null;
     244    /* Constructor.
     245     * @see org.greenstone.gatherer.Coloring;
     246     * @see org.greenstone.gatherer.Dictionary
     247     * @see org.greenstone.gatherer.cdm.MetadataSetManager.ListListener
     248     * @see org.greenstone.gatherer.msm.MetadataSetManager
     249     */
     250    public Control() {
     251                // Create visual components
     252        central_pane = new JPanel();
     253        element_label = new JLabel(get("Elements"));
     254        element_label.setHorizontalAlignment(JLabel.CENTER);
     255        element_label.setOpaque(true);
     256        element_list = new JList();
     257        element_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     258        element_pane = new JPanel();
     259        header_pane = new JPanel();
     260        instructions = new JTextArea(get("Instructions"));
     261        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     262        instructions.setEditable(false);
     263        instructions.setLineWrap(true);
     264        instructions.setRows(5);
     265        instructions.setWrapStyleWord(true);
     266        set_label = new JLabel(get("Sets"));
     267        set_label.setHorizontalAlignment(JLabel.CENTER);
     268        set_label.setOpaque(true);
     269        set_list = new JList(model);
     270        set_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     271        set_pane = new JPanel();
     272        title = new JLabel(get("Title"));
     273        title.setHorizontalAlignment(JLabel.CENTER);
     274        title.setOpaque(true);
     275                // Add listeners
     276        set_list.addListSelectionListener(new ListListener());
     277                // Layout
     278        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     279
     280        header_pane.setLayout(new BorderLayout());
     281        header_pane.add(title, BorderLayout.NORTH);
     282        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     283
     284        set_pane.setLayout(new BorderLayout());
     285        set_pane.add(set_label, BorderLayout.NORTH);
     286        set_pane.add(new JScrollPane(set_list), BorderLayout.CENTER);
     287
     288        element_pane.setLayout(new BorderLayout());
     289        element_pane.add(element_label, BorderLayout.NORTH);
     290        element_pane.add(new JScrollPane(element_list), BorderLayout.CENTER);
     291
     292        central_pane.setLayout(new GridLayout(2,1));
     293        central_pane.add(set_pane);
     294        central_pane.add(element_pane);
     295
     296        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     297        setLayout(new BorderLayout());
     298        add(header_pane, BorderLayout.NORTH);
     299        add(central_pane, BorderLayout.CENTER);
     300    }
     301    /** Destructor.
    249302          */
    250           public Control() {
    251                 // Create visual components
    252                 central_pane = new JPanel();
    253                 element_label = new JLabel(get("Elements"));
    254                 element_label.setHorizontalAlignment(JLabel.CENTER);
    255                 element_label.setOpaque(true);
    256                 element_list = new JList();
    257                 element_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    258                 element_pane = new JPanel();
    259                 header_pane = new JPanel();
    260                 instructions = new JTextArea(get("Instructions"));
    261                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    262                 instructions.setEditable(false);
    263                 instructions.setLineWrap(true);
    264                 instructions.setRows(5);
    265                 instructions.setWrapStyleWord(true);
    266                 set_label = new JLabel(get("Sets"));
    267                 set_label.setHorizontalAlignment(JLabel.CENTER);
    268                 set_label.setOpaque(true);
    269                 set_list = new JList(model);
    270                 set_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    271                 set_pane = new JPanel();
    272                 title = new JLabel(get("Title"));
    273                 title.setHorizontalAlignment(JLabel.CENTER);
    274                 title.setOpaque(true);
    275                 // Add listeners
    276                 set_list.addListSelectionListener(new ListListener());
    277                 // Layout
    278                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    279 
    280                 header_pane.setLayout(new BorderLayout());
    281                 header_pane.add(title, BorderLayout.NORTH);
    282                 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    283 
    284                 set_pane.setLayout(new BorderLayout());
    285                 set_pane.add(set_label, BorderLayout.NORTH);
    286                 set_pane.add(new JScrollPane(set_list), BorderLayout.CENTER);
    287 
    288                 element_pane.setLayout(new BorderLayout());
    289                 element_pane.add(element_label, BorderLayout.NORTH);
    290                 element_pane.add(new JScrollPane(element_list), BorderLayout.CENTER);
    291 
    292                 central_pane.setLayout(new GridLayout(2,1));
    293                 central_pane.add(set_pane);
    294                 central_pane.add(element_pane);
    295 
    296                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    297                 setLayout(new BorderLayout());
    298                 add(header_pane, BorderLayout.NORTH);
    299                 add(central_pane, BorderLayout.CENTER);
    300           }
    301           /** Destructor.
    302           */
    303           public void destroy() {
    304           }
    305           /** Update the element list. */
    306           public void refreshElementList() {
    307                 element_list.updateUI();
    308           }
    309         /** Select the selected element, given its name, and return the bounds of the selection. Used during search and replace.
     303    public void destroy() {
     304    }
     305    /** Update the element list. */
     306    public void refreshElementList() {
     307        element_list.updateUI();
     308    }
     309    /** Select the selected element, given its name, and return the bounds of the selection. Used during search and replace.
    310310        * @param element The elements fully qualified name as a <strong>String</strong>.
    311311        * @return The bounds of the selection as a <strong>Rectangle</strong>.
     
    313313        * @see org.greenstone.gatherer.cdm.MetadataSetManager.Control.ElementWrapper
    314314        */
    315           public Rectangle setSelectedElement(String element) {
    316                 Rectangle bounds = null;
     315    public Rectangle setSelectedElement(String element) {
     316        Rectangle bounds = null;
    317317                // Parse off namespace
    318                 String namespace = element.substring(0, element.indexOf("."));
     318        String namespace = element.substring(0, element.indexOf("."));
    319319                // Force the set list to show the correct entry.
    320                 ListModel s_model = set_list.getModel();
    321                 for(int i = 0; i < s_model.getSize(); i++) {
    322                      SetWrapper sw = (SetWrapper) s_model.getElementAt(i);
    323                      if(sw.getSet().getNamespace().equals(namespace)) {
    324                           set_list.setSelectedValue(sw, true);
    325                      }
    326                 }
     320        ListModel s_model = set_list.getModel();
     321        for(int i = 0; i < s_model.getSize(); i++) {
     322        SetWrapper sw = (SetWrapper) s_model.getElementAt(i);
     323        if(sw.getSet().getNamespace().equals(namespace)) {
     324            set_list.setSelectedValue(sw, true);
     325        }
     326        }
    327327                // Force the element list to show that name.
    328                 ListModel e_model = element_list.getModel();
    329                 for(int i = 0; i < e_model.getSize(); i++) {
    330                      ElementWrapper ew = (ElementWrapper) e_model.getElementAt(i);
    331                      if(ew.name().equals(element)) {
    332                           element_list.setSelectedValue(ew, true);
    333                           bounds = element_list.getCellBounds(i, i);
    334                      }
    335                 }
     328        ListModel e_model = element_list.getModel();
     329        for(int i = 0; i < e_model.getSize(); i++) {
     330        ElementWrapper ew = (ElementWrapper) e_model.getElementAt(i);
     331        if(ew.name().equals(element)) {
     332            element_list.setSelectedValue(ew, true);
     333            bounds = element_list.getCellBounds(i, i);
     334        }
     335        }
    336336                // Return the bounds of the selected row.
    337                 return bounds;
    338           }
    339           /** Overriden to ensure the instruction area is scrolled to top.
     337        return bounds;
     338    }
     339    /** Overriden to ensure the instruction area is scrolled to top.
    340340          */
    341           public void updateUI() {
    342                 if(instructions != null) {
    343                      instructions.setCaretPosition(0);
    344                 }
    345                 super.updateUI();
    346           }
    347 
    348           private class ListListener
    349                 implements ListSelectionListener {
    350                 public void valueChanged(ListSelectionEvent event) {
    351                      if(!set_list.isSelectionEmpty()) {
    352                           MetadataSet set = ((SetWrapper)set_list.getSelectedValue()).getSet();
    353                           NodeList elements = set.getElements();
    354                           element_model = new Vector();
    355                           for(int i = 0; i < elements.getLength(); i++) {
    356                                 element_model.add(new ElementWrapper(elements.item(i)));
    357                           }
    358                           Collections.sort(element_model);
    359                           element_list.setListData(element_model);
    360                      }
    361                 }
    362           }
    363     }
    364     /** Provides a convience wrapper around a metadata set, that allows it to appear in the <strong>JList</strong> the same way it would in the collection configuration file. */
    365     private class SetWrapper {
    366           private MetadataSet set = null;
    367           public SetWrapper(MetadataSet set) {
    368                 this.set = set;
    369           }
    370           public MetadataSet getSet() {
    371                 return set;
    372           }
    373           public String toString() {
    374                 String namespace = set.getNamespace();
     341    public void updateUI() {
     342        if(instructions != null) {
     343        instructions.setCaretPosition(0);
     344        }
     345        super.updateUI();
     346    }
     347
     348    private class ListListener
     349        implements ListSelectionListener {
     350        public void valueChanged(ListSelectionEvent event) {
     351        if(!set_list.isSelectionEmpty()) {
     352            MetadataSet set = ((SetWrapper)set_list.getSelectedValue()).getSet();
     353            NodeList elements = set.getElements();
     354            element_model = new Vector();
     355            for(int i = 0; i < elements.getLength(); i++) {
     356            element_model.add(new ElementWrapper(elements.item(i)));
     357            }
     358            Collections.sort(element_model);
     359            element_list.setListData(element_model);
     360        }
     361        }
     362    }
     363    }
     364    /** Provides a convience wrapper around a metadata set, that allows it to appear in the <strong>JList</strong> the same way it would in the collection configuration file. */
     365    private class SetWrapper {
     366    private MetadataSet set = null;
     367    public SetWrapper(MetadataSet set) {
     368        this.set = set;
     369    }
     370    public MetadataSet getSet() {
     371        return set;
     372    }
     373    public String toString() {
     374        String namespace = set.getNamespace();
    375375                // Watch out for the greenstone set, with its namespace of ""
    376                 if(namespace == null || namespace.length() == 0) {
    377                      namespace = "greenstone";
    378                 }
    379                 return "metadataset " + namespace + " \"" + set.getFile().getName() + "\"";
    380           }
    381     }
     376        if(namespace == null || namespace.length() == 0) {
     377        namespace = "greenstone";
     378        }
     379        return "metadataset " + namespace + " \"" + set.getFile().getName() + "\"";
     380    }
     381    }
    382382}
  • trunk/gli/src/org/greenstone/gatherer/cdm/ParsingProgress.java

    r4293 r4366  
    6060import javax.swing.JProgressBar;
    6161/** This class provides a progress bar to be displayed whenever the module must reload the plugin and classifier information, either automatically or if the user indicates a reload is needed.
    62 * @author John Thompson, Greenstone Digital Library, University of Waikato
    63 * @version 2.3
    64 */
     62 * @author John Thompson, Greenstone Digital Library, University of Waikato
     63 * @version 2.3
     64 */
    6565public class ParsingProgress
    66     extends JDialog {
    67     /** The content pane within the dialog box. */
    68     private JPanel content_pane = null;
    69     /** The progress bar itself. */
    70     private JProgressBar progress = null;
    71     /** The default size of the progress dialog. */
    72     static final Dimension SIZE = new Dimension(400,75);
    73     /** Constructor.
    74       * @param title The title to show on the dialog, as a <strong>String</strong>.
    75       * @param message The message to show on the dialog, as a <strong>String</strong>.
    76       * @param max The total number of plugins/classifiers that have to be parsed before the progress bar can be disposed of, as an <i>int</i>.
     66    extends JDialog {
     67    /** The content pane within the dialog box. */
     68    private JPanel content_pane = null;
     69    /** The progress bar itself. */
     70    private JProgressBar progress = null;
     71    /** The default size of the progress dialog. */
     72    static final Dimension SIZE = new Dimension(400,75);
     73    /** Constructor.
     74     * @param title The title to show on the dialog, as a <strong>String</strong>.
     75     * @param message The message to show on the dialog, as a <strong>String</strong>.
     76     * @param max The total number of plugins/classifiers that have to be parsed before the progress bar can be disposed of, as an <i>int</i>.
    7777      */
    78     public ParsingProgress(String title, String message, int max) {
    79           super();
    80           this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    81           this.setSize(SIZE);
    82           this.setTitle(title);
    83           // Creation
    84           this.content_pane = (JPanel) getContentPane();
    85           this.progress = new JProgressBar();
    86           this.progress.setMaximum(max);
    87           // Layout
    88           this.content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    89           this.content_pane.setLayout(new BorderLayout());
    90           this.content_pane.add(new JLabel(message), BorderLayout.NORTH);
    91           this.content_pane.add(progress, BorderLayout.CENTER);
    92           // Center and display
    93           Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
    94           setLocation((screen_size.width - SIZE.width) / 2,
    95                           (screen_size.height - SIZE.height) / 2);
    96           show();
    97     }
    98     public void destroy() {
    99     }
    100     /** Method which increments the progress count by one, which should be called after every successful parsing of a classifier or plugin.
     78    public ParsingProgress(String title, String message, int max) {
     79    super();
     80    this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
     81    this.setSize(SIZE);
     82    this.setTitle(title);
     83    // Creation
     84    this.content_pane = (JPanel) getContentPane();
     85    this.progress = new JProgressBar();
     86    this.progress.setMaximum(max);
     87    // Layout
     88    this.content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     89    this.content_pane.setLayout(new BorderLayout());
     90    this.content_pane.add(new JLabel(message), BorderLayout.NORTH);
     91    this.content_pane.add(progress, BorderLayout.CENTER);
     92    // Center and display
     93    Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
     94    setLocation((screen_size.width - SIZE.width) / 2,
     95            (screen_size.height - SIZE.height) / 2);
     96    show();
     97    }
     98    public void destroy() {
     99    }
     100    /** Method which increments the progress count by one, which should be called after every successful parsing of a classifier or plugin.
    101101      */
    102     public void inc() {
    103           progress.setValue(progress.getValue() + 1);
    104     }
     102    public void inc() {
     103    progress.setValue(progress.getValue() + 1);
     104    }
    105105}
  • trunk/gli/src/org/greenstone/gatherer/cdm/PlugIn.java

    r4293 r4366  
    6363// ####################################################################################
    6464public class PlugIn
    65     extends ArrayList
    66     implements ArgumentContainer, Comparable, Serializable {
    67     /** A reference to the plugin that this one inherits from. */
    68     private PlugIn super_plugin = null;
    69     /** A string of custom arguments to pass to the plugin. */
    70     private String custom = null;
    71     /** A description of this plugin. */
    72     private String desc = null;
    73     /** The name of the plugin as it would appear in the collect.cfg file. */
    74     private String name = null;
    75     /** Default Constructor.
    76       */
    77     public PlugIn() {
    78           super();
    79     }
    80     /** Constructor.
     65    extends ArrayList
     66    implements ArgumentContainer, Comparable, Serializable {
     67    /** A reference to the plugin that this one inherits from. */
     68    private PlugIn super_plugin = null;
     69    /** A string of custom arguments to pass to the plugin. */
     70    private String custom = null;
     71    /** A description of this plugin. */
     72    private String desc = null;
     73    /** The name of the plugin as it would appear in the collect.cfg file. */
     74    private String name = null;
     75    /** Default Constructor.
     76     */
     77    public PlugIn() {
     78    super();
     79    }
     80    /** Constructor.
    8181      * @param name The name of this plugin as a <strong>String</strong>.
    8282      * @param desc A description of this plugin as a <strong>String</strong>.
    8383      * @param super_plugin The super class of this plugin, as a <strong>PlugIn</strong>.
    8484      */
    85     public PlugIn(String name, String desc, PlugIn super_plugin) {
    86           super();
    87           this.desc = desc;
    88           this.name = name;
    89           this.super_plugin = super_plugin;
    90     }
    91     /** Method to add an argument to this plugin. Only adds the argument if it isn't already present.
     85    public PlugIn(String name, String desc, PlugIn super_plugin) {
     86    super();
     87    this.desc = desc;
     88    this.name = name;
     89    this.super_plugin = super_plugin;
     90    }
     91    /** Method to add an argument to this plugin. Only adds the argument if it isn't already present.
    9292      * @param argument The <strong>Argument</strong> to add.
    9393      */
    94     public void addArgument(Argument argument) {
    95           if(!contains(argument)) {
    96                 add(argument);
    97                 argument.setOwner(name);
    98           }
    99     }
    100     /** Method to compare two plugins for ordering.
     94    public void addArgument(Argument argument) {
     95    if(!contains(argument)) {
     96        add(argument);
     97        argument.setOwner(name);
     98    }
     99    }
     100    /** Method to compare two plugins for ordering.
    101101      * @param object The plugin we are comparing to, as an <strong>Object</strong>.
    102102      * @return An <i>int</i> specifying the plugin order, using values as set out in <strong>String</strong>.
    103103      * @see java.lang.String#compareTo
    104104      */
    105     public int compareTo(Object object) {
    106           if(object != null && object instanceof PlugIn) {
    107                 PlugIn plugin = (PlugIn) object;
    108                 return name.compareTo(plugin.getName());
    109           }
    110           return -1;
    111     }
    112     /** This method produces a deep copy of this plugin. Note that this also creates a new copy of each of the super classes of plugins as well. This is the way it should be, as each assigned plugin may have different values for the higher plugins (such as BasPlug).
     105    public int compareTo(Object object) {
     106    if(object != null && object instanceof PlugIn) {
     107        PlugIn plugin = (PlugIn) object;
     108        return name.compareTo(plugin.getName());
     109    }
     110    return -1;
     111    }
     112    /** This method produces a deep copy of this plugin. Note that this also creates a new copy of each of the super classes of plugins as well. This is the way it should be, as each assigned plugin may have different values for the higher plugins (such as BasPlug).
    113113      * @return A newly created <strong>PlugIn</strong> with the same details and <strong>Argument</strong>s as this one.
    114114      */
    115     public PlugIn copy() {
    116           PlugIn copy = null;
    117           if(super_plugin == null) {
    118                 copy = new PlugIn(name, desc, null);
    119           }
    120           else {
    121                 copy = new PlugIn(name, desc, super_plugin.copy());
    122           }
    123           for(int i = 0; i < size(); i++) {
    124                 copy.addArgument(((Argument)get(i)).copy());
    125           }
    126           return copy;
    127     }
    128     /** Method to determine if two plugins are equal.
     115    public PlugIn copy() {
     116    PlugIn copy = null;
     117    if(super_plugin == null) {
     118        copy = new PlugIn(name, desc, null);
     119    }
     120    else {
     121        copy = new PlugIn(name, desc, super_plugin.copy());
     122    }
     123    for(int i = 0; i < size(); i++) {
     124        copy.addArgument(((Argument)get(i)).copy());
     125    }
     126    return copy;
     127    }
     128    /** Method to determine if two plugins are equal.
    129129      * @param object The plugin to test against, as an <strong>Object</strong>.
    130130      * @return <i>true</i> if the plugin names match, <i>false</i> otherwise.
    131131      */
    132     public boolean equals(Object object) {
    133           if(object != null && compareTo(object) == 0) {
    134                 return true;
    135           }
    136           return false;
    137     }
    138     /** Method to retrieve an argument by its name.
     132    public boolean equals(Object object) {
     133    if(object != null && compareTo(object) == 0) {
     134        return true;
     135    }
     136    return false;
     137    }
     138    /** Method to retrieve an argument by its name.
    139139      * @param name The name of the argument as a <strong>String</strong>.
    140140      * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
    141141      */
    142     public Argument getArgument(String name) {
    143           // The name given may still include the '-'
    144           if(name.startsWith("-")) {
    145                 name = name.substring(1);
    146           }
    147           ArrayList arguments = getArguments();
    148           for(int i = 0; i < arguments.size(); i++) {
    149                 Argument argument = (Argument)arguments.get(i);
    150                 if(argument.getName().equals(name)) {
    151                      return argument;
    152                 }
    153           }
    154           return null;
    155     }
    156     /** Method to retrieve all of the arguments available to a plugin, including both specific and general ones.
     142    public Argument getArgument(String name) {
     143    // The name given may still include the '-'
     144    if(name.startsWith("-")) {
     145        name = name.substring(1);
     146    }
     147    ArrayList arguments = getArguments();
     148    for(int i = 0; i < arguments.size(); i++) {
     149        Argument argument = (Argument)arguments.get(i);
     150        if(argument.getName().equals(name)) {
     151        return argument;
     152        }
     153    }
     154    return null;
     155    }
     156    /** Method to retrieve all of the arguments available to a plugin, including both specific and general ones.
    157157      * @return A <strong>Hashtable</strong> of arguments, with <name> -> <argument> entries.
    158158      */
    159     public ArrayList getArguments() {
    160           ArrayList all_arguments = new ArrayList(this);
    161           Collections.sort(all_arguments);
    162           if(super_plugin != null) {
    163                 ArrayList super_arguments = super_plugin.getArguments();
    164                 for(int i = 0; i < super_arguments.size(); i++) {
    165                      Object argument = super_arguments.get(i);
    166                      if(!all_arguments.contains(argument)) {
    167                           all_arguments.add(argument);
    168                      }
    169                 }
    170           }
    171           return all_arguments;
    172     }
    173     /** Method to retrieve a plugins custom argument information.
     159    public ArrayList getArguments() {
     160    ArrayList all_arguments = new ArrayList(this);
     161    Collections.sort(all_arguments);
     162    if(super_plugin != null) {
     163        ArrayList super_arguments = super_plugin.getArguments();
     164        for(int i = 0; i < super_arguments.size(); i++) {
     165        Object argument = super_arguments.get(i);
     166        if(!all_arguments.contains(argument)) {
     167            all_arguments.add(argument);
     168        }
     169        }
     170    }
     171    return all_arguments;
     172    }
     173    /** Method to retrieve a plugins custom argument information.
    174174      * @return The custom arguments as a <strong>String</strong>.
    175175      */
    176     public String getCustom() {
    177           return custom;
    178     }
    179     /** Method to retrieve a plugins name.
     176    public String getCustom() {
     177    return custom;
     178    }
     179    /** Method to retrieve a plugins name.
    180180      * @return A <strong>String</strong> containing the plugins name.
    181181      */
    182     public String getName() {
    183           return name;
    184     }
    185     public void setCustom(String custom) {
    186           this.custom = custom;
    187     }
    188     /** Method to set the value of desc.
     182    public String getName() {
     183    return name;
     184    }
     185    public void setCustom(String custom) {
     186    this.custom = custom;
     187    }
     188    /** Method to set the value of desc.
    189189      * @param desc The new value of desc as a <strong>String</strong>.
    190190      */
    191     public void setDesc(String desc) {
    192           this.desc = desc;
    193     }
    194     /** Method to set the value of name.
     191    public void setDesc(String desc) {
     192    this.desc = desc;
     193    }
     194    /** Method to set the value of name.
    195195      * @param name The new value of name as a <strong>String</strong>.
    196196      */
    197     public void setName(String name) {
    198           this.name = name;
    199     }
    200     /** Method to set the value of the super_plugin.
     197    public void setName(String name) {
     198    this.name = name;
     199    }
     200    /** Method to set the value of the super_plugin.
    201201      * @param super_plugin The new value of super_plugin as a <strong>PlugIn</strong>, or <i>null</i> if this class has no inheritance.
    202202      */
    203     public void setSuper(PlugIn super_plugin) {
    204           this.super_plugin = super_plugin;
    205     }
    206     /** Method to print out this plugin as it would appear as a command within the collection configuration file.
     203    public void setSuper(PlugIn super_plugin) {
     204    this.super_plugin = super_plugin;
     205    }
     206    /** Method to print out this plugin as it would appear as a command within the collection configuration file.
    207207      * @return A <strong>String</strong> containing a single plugin command.
    208208      */
    209     public String toString() {
    210           String text = "plugin " + name + " ";
    211           ArrayList arguments = getArguments();
    212           for(int i = 0; i < arguments.size(); i++) {
    213                 Argument argument = (Argument)arguments.get(i);
    214                 if(argument.isAssigned()) {
    215                      text = text + argument.toString();
    216                      if(i < arguments.size() - 1) {
    217                           text = text + " ";
    218                      }
    219                 }
    220           }
    221           // Now print custom arguments if any.
    222           if(custom != null) {
    223                 text = text + " " + custom;
    224           }
    225           return text;
    226     }       
     209    public String toString() {
     210    String text = "plugin " + name + " ";
     211    ArrayList arguments = getArguments();
     212    for(int i = 0; i < arguments.size(); i++) {
     213        Argument argument = (Argument)arguments.get(i);
     214        if(argument.isAssigned()) {
     215        text = text + argument.toString();
     216        if(i < arguments.size() - 1) {
     217            text = text + " ";
     218        }
     219        }
     220    }
     221    // Now print custom arguments if any.
     222    if(custom != null) {
     223        text = text + " " + custom;
     224    }
     225    return text;
     226    }         
    227227}
    228228
  • trunk/gli/src/org/greenstone/gatherer/cdm/PlugInManager.java

    r4293 r4366  
    103103/** This class is resposible for maintaining a list of known plug-ins, and importing new plugins using the parser. */
    104104public class PlugInManager {
    105     /** A reference to the main manager for this module. */
    106     private CollectionDesignManager manager = null;
    107     /** The controls for editing the contents of this manager. */
    108     private Control controls = null;
    109     /** A list of assigned plugins. */
    110     private DynamicListModel assigned = null;
    111     /** A list of those plugins that have not yet been assigned. Begins as a copy of reserve. */
    112     private DynamicListModel available = null;
    113     /** A list of known, but currently unassigned, plug-ins. */
    114     private DynamicListModel reserve = null;
    115     /** A reference to the Gatherer. */
    116     private Gatherer gatherer = null;
    117     /** The current index of the separator. */
    118     private JPanel separator = null;
    119     /** The default size for a label. */
    120     static final private Dimension LABEL_SIZE = new Dimension(140, 20);
    121     /** Constructor.
    122       */
    123     public PlugInManager(Gatherer gatherer, CollectionDesignManager manager) {
    124           this.assigned = new DynamicListModel();
    125           this.gatherer = gatherer;
    126           this.manager = manager;
    127           this.separator = getSeparator();
    128           // Add the movement separator
    129           assigned.addElement(separator);
    130           loadPlugIns();
    131           savePlugIns();
    132     }
    133     /** Method to add a new plugin to reserve.
     105    /** A reference to the main manager for this module. */
     106    private CollectionDesignManager manager = null;
     107    /** The controls for editing the contents of this manager. */
     108    private Control controls = null;
     109    /** A list of assigned plugins. */
     110    private DynamicListModel assigned = null;
     111    /** A list of those plugins that have not yet been assigned. Begins as a copy of reserve. */
     112    private DynamicListModel available = null;
     113    /** A list of known, but currently unassigned, plug-ins. */
     114    private DynamicListModel reserve = null;
     115    /** A reference to the Gatherer. */
     116    private Gatherer gatherer = null;
     117    /** The current index of the separator. */
     118    private JPanel separator = null;
     119    /** The default size for a label. */
     120    static final private Dimension LABEL_SIZE = new Dimension(140, 20);
     121    /** Constructor.
     122     */
     123    public PlugInManager(Gatherer gatherer, CollectionDesignManager manager) {
     124    this.assigned = new DynamicListModel();
     125    this.gatherer = gatherer;
     126    this.manager = manager;
     127    this.separator = getSeparator();
     128    // Add the movement separator
     129    assigned.addElement(separator);
     130    loadPlugIns();
     131    savePlugIns();
     132    }
     133    /** Method to add a new plugin to reserve.
    134134      * @param plugin The new <strong>PlugIn</strong>.
    135135      */
    136     public void addPlugIn(PlugIn plugin) {
    137           if(!reserve.contains(plugin)) {
    138                 reserve.addElement(plugin);
    139                 available.addElement(plugin);
    140           }
    141     }
    142     /** Method to assign a plugin.
     136    public void addPlugIn(PlugIn plugin) {
     137    if(!reserve.contains(plugin)) {
     138        reserve.addElement(plugin);
     139        available.addElement(plugin);
     140    }
     141    }
     142    /** Method to assign a plugin.
    143143      * @param plugin The reserve <strong>PlugIn</strong> to assign.
    144144      */
    145     public void assignPlugIn(PlugIn plugin) {
    146           if(!assigned.contains(plugin)) {
    147                 if(plugin.getName().equals("RecPlug") || plugin.getName().equals("ArcPlug")) {
    148                      assigned.addElement(plugin); // Adds after separator
    149                 }
    150                 else {
    151                      int index = assigned.indexOf(separator);
    152                      assigned.add(index, plugin);
    153                 }
     145    public void assignPlugIn(PlugIn plugin) {
     146    if(!assigned.contains(plugin)) {
     147        if(plugin.getName().equals("RecPlug") || plugin.getName().equals("ArcPlug")) {
     148        assigned.addElement(plugin); // Adds after separator
     149        }
     150        else {
     151        int index = assigned.indexOf(separator);
     152        assigned.add(index, plugin);
     153        }
    154154                // Remove from available
    155                 available.removeElement(plugin);
    156                 gatherer.c_man.configurationChanged();
    157           }
    158     }
    159     /** Method to retrieve the control for this manager.
     155        available.removeElement(plugin);
     156        gatherer.c_man.configurationChanged();
     157    }
     158    }
     159    /** Method to retrieve the control for this manager.
    160160      * @return A <strong>JPanel</strong> containing the controls.
    161161      */
    162     public JPanel getControls() {
    163           if(controls == null) {
    164                 controls = new Control();
    165           }
    166           return controls;
    167     }
    168     /** Method to retrieve the named plugin.
     162    public JPanel getControls() {
     163    if(controls == null) {
     164        controls = new Control();
     165    }
     166    return controls;
     167    }
     168    /** Method to retrieve the named plugin.
    169169      * @param name The name of the desired plugin as a <strong>String</strong>.
    170170      * @return The requested <strong>PlugIn</strong> or <i>null</i> if no such plugin exists.
    171171      */
    172     public PlugIn getPlugIn(String name) {
    173           for(int i = 0; i < reserve.size(); i++) {
    174                 Object object = reserve.get(i);
    175                 if(object instanceof PlugIn) {
    176                      PlugIn plugin = (PlugIn) object;
    177                      if(plugin.getName().equals(name)) {
    178                           return plugin;
    179                      }
    180                 }
    181           }
    182           // No success.
    183           return null;
    184     }
    185     /** Method to invalidate controls after a significant change in the system state.
    186       */
    187     public void invalidateControls() {
    188           if(controls != null) {
    189                 controls.destroy();
    190           }
    191           controls = null;
    192     }
    193     /** Method to load the details of a single plug-in.
     172    public PlugIn getPlugIn(String name) {
     173    for(int i = 0; i < reserve.size(); i++) {
     174        Object object = reserve.get(i);
     175        if(object instanceof PlugIn) {
     176        PlugIn plugin = (PlugIn) object;
     177        if(plugin.getName().equals(name)) {
     178            return plugin;
     179        }
     180        }
     181    }
     182    // No success.
     183    return null;
     184    }
     185    /** Method to invalidate controls after a significant change in the system state.
     186      */
     187    public void invalidateControls() {
     188    if(controls != null) {
     189        controls.destroy();
     190    }
     191    controls = null;
     192    }
     193    /** Method to load the details of a single plug-in.
    194194      * @param plugin The plugin <strong>File</strong> you wish to load.
    195195      */
    196     public void loadPlugIn(File plugin) {
    197           Document document = null;
    198           // Run pluginfo on this plugin, and then send the results for parsing.
    199           try {
    200                 String args[] = null;
    201                 if(Utility.isWindows()) {
    202                      args = new String[4];
    203                      if(gatherer.config.perl_path != null) {
    204                           args[0] = gatherer.config.perl_path + "Perl.exe";
    205                      }
    206                      else {
    207                           args[0] = "Perl.exe";
    208                      }
    209                      args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl";
    210                      args[2] = "-xml";
    211                      args[3] = getPlugInName(plugin);
    212                 }
    213                 else {
    214                      args = new String[3];
    215                      args[0] = "pluginfo.pl";
    216                      args[1] = "-xml";
    217                      args[2] = getPlugInName(plugin);
    218                 }
    219                 for(int i = 0; i < args.length; i++) {
    220                     ///ystem.out.print(args[i] + " ");
    221                 }
     196    public void loadPlugIn(File plugin) {
     197    Document document = null;
     198    // Run pluginfo on this plugin, and then send the results for parsing.
     199    try {
     200        String args[] = null;
     201        if(Utility.isWindows()) {
     202        args = new String[4];
     203        if(gatherer.config.perl_path != null) {
     204            args[0] = gatherer.config.perl_path + "Perl.exe";
     205        }
     206        else {
     207            args[0] = "Perl.exe";
     208        }
     209        args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl";
     210        args[2] = "-xml";
     211        args[3] = getPlugInName(plugin);
     212        }
     213        else {
     214        args = new String[3];
     215        args[0] = "pluginfo.pl";
     216        args[1] = "-xml";
     217        args[2] = getPlugInName(plugin);
     218        }
     219        for(int i = 0; i < args.length; i++) {
     220        ///ystem.out.print(args[i] + " ");
     221        }
    222222                ///ystem.out.print("\n");
    223223                // Create the process.
    224                 Runtime runtime = Runtime.getRuntime();
    225                 Process process = runtime.exec(args);
     224        Runtime runtime = Runtime.getRuntime();
     225        Process process = runtime.exec(args);
    226226                //InputStream input_stream = process.getErrorStream();
    227                 BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    228                 String line = "";
    229                 StringBuffer xml = new StringBuffer("");
    230                 while((line = error_in.readLine()) != null) {
    231                     xml.append(line);
    232                     xml.append("\n");
    233                 }
    234                 line = null;
    235                 error_in = null;
     227        BufferedReader error_in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
     228        String line = "";
     229        StringBuffer xml = new StringBuffer("");
     230        while((line = error_in.readLine()) != null) {
     231        xml.append(line);
     232        xml.append("\n");
     233        }
     234        line = null;
     235        error_in = null;
    236236                ///ystem.out.println("\n");
    237237                // Then read the xml from the piped input stream.
    238                 InputSource source = new InputSource(new StringReader(xml.toString()));
    239                 DOMParser parser = new DOMParser();
    240                 parser.parse(source);
    241                 document = parser.getDocument();
    242           }
    243           catch (Exception error) {
    244                 error.printStackTrace();
    245           }
    246           if(document != null) {
    247                 parse(document.getDocumentElement());
    248           }
    249     }
    250     /** Method to move a plugin higher in the list order.
     238        InputSource source = new InputSource(new StringReader(xml.toString()));
     239        DOMParser parser = new DOMParser();
     240        parser.parse(source);
     241        document = parser.getDocument();
     242    }
     243    catch (Exception error) {
     244        error.printStackTrace();
     245    }
     246    if(document != null) {
     247        parse(document.getDocumentElement());
     248    }
     249    }
     250    /** Method to move a plugin higher in the list order.
    251251      * @param plugin The <strong>PlugIn</strong> you want to move.
    252252      * @param direction <i>true</i> to move the plugin up, <i>false</i> to move it down.
    253253      * @param all <i>true</i> to move to move all the way, <i>false</i> for a single step.
    254254      */
    255      public void movePlugIn(PlugIn plugin, boolean direction, boolean all) {
    256           // Can't ever move RecPlug or ArcPlug.
    257           if(plugin.getName().equals("ArcPlug") || plugin.getName().equals("RecPlug")) {
    258                 JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Fixed"), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    259                 return;
    260           }
    261           if(all) {
    262                 if(direction) {
    263                      assigned.removeElement(plugin);
    264                      assigned.add(0, plugin);
    265                      gatherer.c_man.configurationChanged();
     255    public void movePlugIn(PlugIn plugin, boolean direction, boolean all) {
     256    // Can't ever move RecPlug or ArcPlug.
     257    if(plugin.getName().equals("ArcPlug") || plugin.getName().equals("RecPlug")) {
     258        JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Fixed"), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     259        return;
     260    }
     261    if(all) {
     262        if(direction) {
     263        assigned.removeElement(plugin);
     264        assigned.add(0, plugin);
     265        gatherer.c_man.configurationChanged();
     266        }
     267        else {
     268        assigned.removeElement(plugin);
     269        int index = assigned.size() - 1;
     270        boolean found = false;
     271        while(!found) {
     272            Object temp = assigned.get(index);
     273            if(temp instanceof PlugIn) {
     274            PlugIn current = (PlugIn) temp;
     275            if(current.getName().equals("ArcPlug") || current.getName().equals("RecPlug")) {
     276                index--;
     277            }
     278            else {
     279                found = true;
     280            }
     281            }
     282            else {
     283            found = true;
     284            }
     285        }
     286        assigned.add(index, plugin);
     287        gatherer.c_man.configurationChanged();
     288        }
     289    }
     290    else {
     291                // Try to move the plugin one step in the desired direction.
     292        int index = assigned.indexOf(plugin);
     293                ///ystem.err.println("Index of " + plugin + " = " + index);
     294        if(direction) {
     295        index--;
     296        if(index < 0) {
     297            String args[] = new String[1];
     298            args[0] = plugin.getName();
     299            JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     300            return;
     301        }
     302        assigned.removeElement(plugin);
     303        assigned.add(index, plugin);
     304        gatherer.c_man.configurationChanged();
     305        }
     306        else {
     307        index++;
     308        Object object = assigned.get(index);
     309        if(index == assigned.size()) {
     310            String args[] = new String[1];
     311            args[0] = plugin.getName();
     312            JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Bottom", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     313            // Still not going to move RecPlug or ArcPlug.
     314            return;
     315        }
     316        else if(!(object instanceof PlugIn) || ((PlugIn)object).getName().equals("ArcPlug") || ((PlugIn)object).getName().equals("RecPlug")) {
     317            String args[] = new String[1];
     318            args[0] = plugin.getName();
     319            JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Cannot", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     320            // Still not going to move RecPlug or ArcPlug.
     321            return;
     322        }
     323        assigned.removeElement(plugin);
     324        assigned.add(index, plugin);
     325        gatherer.c_man.configurationChanged();
     326        }
     327    }
     328    }
     329
     330    /** 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.
     331      * @param command The coomand <strong>String</strong> that may include plugin information.
     332      * @return <i>true</i> if a plugin command was parsed, <i>false</i> otherwise.
     333      */
     334    public boolean parse(String command) {
     335    String command_lc = command.toLowerCase();
     336    if(command_lc.startsWith("plugin")) {
     337        CommandTokenizer tokenizer = new CommandTokenizer(command);
     338        if(tokenizer.countTokens() >= 2) {
     339        tokenizer.nextToken(); // Throw away 'plugin'
     340        String name = tokenizer.nextToken();
     341        // Try to locate the plugin with this name.
     342        PlugIn plugin = getPlugIn(name);
     343        // And if successful start to parse the arguments.
     344        if(plugin != null) {
     345            // Take a copy.
     346            plugin = plugin.copy();
     347            String key = null;
     348            while(tokenizer.hasMoreTokens()) {
     349            if(key == null) {
     350                key = tokenizer.nextToken();
     351            }
     352            // Try to retrieve a matching argument.
     353            Argument argument = plugin.getArgument(key);
     354            if(argument != null) {
     355                // Set as assigned.
     356                argument.setAssigned(true);
     357                // And if the argument is of a parameter type, parse a parameter.
     358                if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
     359                argument.setValue(tokenizer.nextToken());
     360                }
     361                key = null;
     362            }
     363            // Argument cannot be matched.
     364            else {
     365                String cur_key = key;
     366                String value = tokenizer.nextToken();
     367                if(value.startsWith("-")) {
     368                key = value;
     369                value = null;
     370                }
     371                else {
     372                key = null;
     373                }
     374                String custom = plugin.getCustom();
     375                if(custom == null) {
     376                if(value == null) {
     377                    plugin.setCustom(cur_key);
    266378                }
    267379                else {
    268                      assigned.removeElement(plugin);
    269                      int index = assigned.size() - 1;
    270                      boolean found = false;
    271                      while(!found) {
    272                           Object temp = assigned.get(index);
    273                           if(temp instanceof PlugIn) {
    274                                 PlugIn current = (PlugIn) temp;
    275                                 if(current.getName().equals("ArcPlug") || current.getName().equals("RecPlug")) {
    276                                      index--;
    277                                 }
    278                                 else {
    279                                      found = true;
    280                                 }
    281                           }
    282                           else {
    283                                 found = true;
    284                           }
    285                      }
    286                      assigned.add(index, plugin);
    287                      gatherer.c_man.configurationChanged();
     380                    plugin.setCustom(cur_key + " " + value);
    288381                }
    289           }
    290           else {
    291                 // Try to move the plugin one step in the desired direction.
    292                 int index = assigned.indexOf(plugin);
    293                 ///ystem.err.println("Index of " + plugin + " = " + index);
    294                 if(direction) {
    295                      index--;
    296                      if(index < 0) {
    297                           String args[] = new String[1];
    298                           args[0] = plugin.getName();
    299                           JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    300                           return;
    301                      }
    302                      assigned.removeElement(plugin);
    303                      assigned.add(index, plugin);
    304                      gatherer.c_man.configurationChanged();
     382                }
     383                else {
     384                if(value == null) {
     385                    plugin.setCustom(custom + " " + cur_key);
    305386                }
    306387                else {
    307                      index++;
    308                      Object object = assigned.get(index);
    309                      if(index == assigned.size()) {
    310                           String args[] = new String[1];
    311                           args[0] = plugin.getName();
    312                           JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Bottom", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    313                           // Still not going to move RecPlug or ArcPlug.
    314                           return;
    315                      }
    316                      else if(!(object instanceof PlugIn) || ((PlugIn)object).getName().equals("ArcPlug") || ((PlugIn)object).getName().equals("RecPlug")) {
    317                           String args[] = new String[1];
    318                           args[0] = plugin.getName();
    319                           JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Cannot", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    320                           // Still not going to move RecPlug or ArcPlug.
    321                           return;
    322                      }
    323                      assigned.removeElement(plugin);
    324                      assigned.add(index, plugin);
    325                      gatherer.c_man.configurationChanged();
     388                    plugin.setCustom(custom + " " + cur_key + " " + value);
    326389                }
    327           }
    328      }
    329 
    330      /** 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.
    331       * @param command The coomand <strong>String</strong> that may include plugin information.
    332       * @return <i>true</i> if a plugin command was parsed, <i>false</i> otherwise.
    333       */
    334      public boolean parse(String command) {
    335           String command_lc = command.toLowerCase();
    336           if(command_lc.startsWith("plugin")) {
    337                 CommandTokenizer tokenizer = new CommandTokenizer(command);
    338                 if(tokenizer.countTokens() >= 2) {
    339                      tokenizer.nextToken(); // Throw away 'plugin'
    340                      String name = tokenizer.nextToken();
    341                      // Try to locate the plugin with this name.
    342                      PlugIn plugin = getPlugIn(name);
    343                      // And if successful start to parse the arguments.
    344                      if(plugin != null) {
    345                           // Take a copy.
    346                           plugin = plugin.copy();
    347                           String key = null;
    348                           while(tokenizer.hasMoreTokens()) {
    349                                 if(key == null) {
    350                                      key = tokenizer.nextToken();
    351                                 }
    352                                 // Try to retrieve a matching argument.
    353                                 Argument argument = plugin.getArgument(key);
    354                                 if(argument != null) {
    355                                      // Set as assigned.
    356                                      argument.setAssigned(true);
    357                                      // And if the argument is of a parameter type, parse a parameter.
    358                                      if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
    359                                           argument.setValue(tokenizer.nextToken());
    360                                      }
    361                                      key = null;
    362                                 }
    363                                 // Argument cannot be matched.
    364                                 else {
    365                                      String cur_key = key;
    366                                      String value = tokenizer.nextToken();
    367                                      if(value.startsWith("-")) {
    368                                           key = value;
    369                                           value = null;
    370                                      }
    371                                      else {
    372                                           key = null;
    373                                      }
    374                                      String custom = plugin.getCustom();
    375                                      if(custom == null) {
    376                                           if(value == null) {
    377                                                 plugin.setCustom(cur_key);
    378                                           }
    379                                           else {
    380                                                 plugin.setCustom(cur_key + " " + value);
    381                                           }
    382                                      }
    383                                      else {
    384                                           if(value == null) {
    385                                                 plugin.setCustom(custom + " " + cur_key);
    386                                           }
    387                                           else {
    388                                                 plugin.setCustom(custom + " " + cur_key + " " + value);
    389                                           }
    390                                      }
    391                                 }
    392                           }
    393                           // Slight tweak. If the plugin is the RecPlug we want to set use_metadata_files by default.
    394                           if(plugin.getName().equalsIgnoreCase("RecPlug")) {
    395                                 Argument argument = plugin.getArgument("-use_metadata_files");
    396                                 if(argument != null) {
    397                                      argument.setAssigned(true);
    398                                 }
    399                           }
    400                           // Second tweak. If the plugin is the HTMLPlug we want to modify the block expression so our backup files are ignored.
    401                           if(plugin.getName().equalsIgnoreCase("HTMLPlug")) {
    402                                 Argument argument = plugin.getArgument("-block_exp");
    403                                 if(argument != null) {
    404                                      argument.setValue(argument.getDefaultValue() + "|(~$)");
    405                                 }
    406                           }
    407                           // Add the plugin to our reserve
    408                           assignPlugIn(plugin);
    409                           return true;
    410                      }
    411                      else {
    412                           //ystem.err.println("Unknown plugin");
    413                      }
    414                 }
    415           }
    416           return false;
    417      }
    418      /** 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.
     390                }
     391            }
     392            }
     393            // Slight tweak. If the plugin is the RecPlug we want to set use_metadata_files by default.
     394            if(plugin.getName().equalsIgnoreCase("RecPlug")) {
     395            Argument argument = plugin.getArgument("-use_metadata_files");
     396            if(argument != null) {
     397                argument.setAssigned(true);
     398            }
     399            }
     400            // Second tweak. If the plugin is the HTMLPlug we want to modify the block expression so our backup files are ignored.
     401            if(plugin.getName().equalsIgnoreCase("HTMLPlug")) {
     402            Argument argument = plugin.getArgument("-block_exp");
     403            if(argument != null) {
     404                argument.setValue(argument.getDefaultValue() + "|(~$)");
     405            }
     406            }
     407            // Add the plugin to our reserve
     408            assignPlugIn(plugin);
     409            return true;
     410        }
     411        else {
     412            //ystem.err.println("Unknown plugin");
     413        }
     414        }
     415    }
     416    return false;
     417    }
     418    /** 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.
    419419      * @param plugin The <strong>PlugIn</strong> to remove.
    420420      */
    421     public void removePlugIn(PlugIn plugin) {
    422           assigned.removeElement(plugin);
    423           available.addElement(plugin);
    424           gatherer.c_man.configurationChanged();
    425     }
    426     /** Method to cache the current contents of reserve (known plugins) to file.
    427       */
    428     public void savePlugIns() {
    429           try {
    430                 FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "plugins.dat");
    431                 ObjectOutputStream out = new ObjectOutputStream(file);
    432                 out.writeObject(reserve);
    433                 out.close();
    434           }
    435           catch (Exception error) {
    436           }
    437     }
    438     /** Method used to determine the number of plugins that have been assigned.
     421    public void removePlugIn(PlugIn plugin) {
     422    assigned.removeElement(plugin);
     423    available.addElement(plugin);
     424    gatherer.c_man.configurationChanged();
     425    }
     426    /** Method to cache the current contents of reserve (known plugins) to file.
     427      */
     428    public void savePlugIns() {
     429    try {
     430        FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "plugins.dat");
     431        ObjectOutputStream out = new ObjectOutputStream(file);
     432        out.writeObject(reserve);
     433        out.close();
     434    }
     435    catch (Exception error) {
     436    }
     437    }
     438    /** Method used to determine the number of plugins that have been assigned.
    439439      * @return An <i>int</i> which is the number of plugins.
    440440      */
    441     public int size() {
    442           return assigned.size();
    443     }
    444     /** Method to print out a block of plugin commands, much like you'd find in a collection configuration file.
     441    public int size() {
     442    return assigned.size();
     443    }
     444    /** Method to print out a block of plugin commands, much like you'd find in a collection configuration file.
    445445      * @return A <strong>String</strong> containing a series of plugin commands separated by new lines.
    446446      */
    447     public String toString() {
    448           String text = "";
    449           for(int i = 0; i < assigned.size(); i++) {
    450                 Object object = assigned.get(i);
    451                 if(object instanceof PlugIn) {
    452                      PlugIn plugin = (PlugIn) object;
    453                      text = text + plugin.toString() + "\n";
    454                 }
    455           }
    456           text = text + "\n";
    457           return text;
    458     }
    459     /* Retrieve a phrase from the dictionary based on a certain key.
     447    public String toString() {
     448    String text = "";
     449    for(int i = 0; i < assigned.size(); i++) {
     450        Object object = assigned.get(i);
     451        if(object instanceof PlugIn) {
     452        PlugIn plugin = (PlugIn) object;
     453        text = text + plugin.toString() + "\n";
     454        }
     455    }
     456    text = text + "\n";
     457    return text;
     458    }
     459    /* Retrieve a phrase from the dictionary based on a certain key.
    460460      * @param key The search <strong>String</strong>.
    461461      * @return The matching phrase from the Dictionary.
    462462      */
    463     private String get(String key) {
    464           return get(key, null);
    465     }
    466     /* Retrieve a phrase from the dictionary based on a certain key and arguments.
     463    private String get(String key) {
     464    return get(key, null);
     465    }
     466    /* Retrieve a phrase from the dictionary based on a certain key and arguments.
    467467      * @param key The search <strong>String</strong>.
    468468      * @param args A <strong>String[]</strong> of arguments used to complete and format the choosen phrase.
    469469      * @return The matching phrase from the Dictionary.
    470470      */
    471     private String get(String key, String args[]) {
    472           if(key.indexOf(".") == -1) {
    473                 key = "CDM.PlugInManager." + key;
    474           }
    475           return gatherer.dictionary.get(key, args);
    476     }   
    477     /** Method to extract just the plugins name from a file object.
     471    private String get(String key, String args[]) {
     472    if(key.indexOf(".") == -1) {
     473        key = "CDM.PlugInManager." + key;
     474    }
     475    return gatherer.dictionary.get(key, args);
     476    }   
     477    /** Method to extract just the plugins name from a file object.
    478478      * @param plugin The <strong>File</strong> which references a certain plugin.
    479479      * @return A <strong>String</strong> containing just the plugins name, without extension.
    480480      */
    481     private String getPlugInName(File plugin) {
    482           String name = plugin.getName();
    483           if(name.indexOf(".") != -1) {
    484                 name = name.substring(0, name.indexOf("."));
    485           }
    486           return name;
    487     }
    488     /** Method to retrieve the CData value from a node. Requires a search for the #text node.
     481    private String getPlugInName(File plugin) {
     482    String name = plugin.getName();
     483    if(name.indexOf(".") != -1) {
     484        name = name.substring(0, name.indexOf("."));
     485    }
     486    return name;
     487    }
     488    /** Method to retrieve the CData value from a node. Requires a search for the #text node.
    489489      * @param node The <strong>Node</strong> whose value we wish to find.
    490490      * @return The value of node as a <strong>String</strong>, or <i>null</i> if no value exists.
    491491      */
    492     private String getValue(Node node) {
    493           if(node.hasChildNodes()) {
    494                 Node text = node.getFirstChild();
     492    private String getValue(Node node) {
     493    if(node.hasChildNodes()) {
     494        Node text = node.getFirstChild();
    495495                //ystem.err.println("Value of " + node.getNodeName() + " = " + text.getNodeValue());
    496                 return text.getNodeValue();
    497           }
    498           return node.getNodeValue();
    499     }
    500     /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
    501       */
    502     private void loadPlugIns() {
    503           // Attempt to restore the cached file.
    504           try {
    505                 FileInputStream file = new FileInputStream(Utility.BASE_DIR + "plugins.dat");
    506                 ObjectInputStream input = new ObjectInputStream(file);
    507                 reserve = (DynamicListModel) input.readObject();
    508                 available = reserve.shallowCopy();
    509           }
    510           catch (Exception error) {
    511           }
    512           if(reserve == null) {
    513                 available = new DynamicListModel();
    514                 reserve = new DynamicListModel();
    515                 reserve.setAutoOrder(true);
     496        return text.getNodeValue();
     497    }
     498    return node.getNodeValue();
     499    }
     500    /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
     501      */
     502    private void loadPlugIns() {
     503    // Attempt to restore the cached file.
     504    try {
     505        FileInputStream file = new FileInputStream(Utility.BASE_DIR + "plugins.dat");
     506        ObjectInputStream input = new ObjectInputStream(file);
     507        reserve = (DynamicListModel) input.readObject();
     508        available = reserve.shallowCopy();
     509    }
     510    catch (Exception error) {
     511    }
     512    if(reserve == null) {
     513        available = new DynamicListModel();
     514        reserve = new DynamicListModel();
     515        reserve.setAutoOrder(true);
    516516                // Retrieve the gsdl home directory...
    517                 String directory = gatherer.config.gsdl_path;
    518                 directory = directory + "perllib" + File.separator + "plugins" + File.separator;
    519                 loadPlugIns(new File(directory));
    520           }
    521     }
    522     /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
     517        String directory = gatherer.config.gsdl_path;
     518        directory = directory + "perllib" + File.separator + "plugins" + File.separator;
     519        loadPlugIns(new File(directory));
     520    }
     521    }
     522    /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
    523523      * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
    524524      */
    525     private void loadPlugIns(File directory) {
    526           File files[] = directory.listFiles();
    527           if(files != null) {
     525    private void loadPlugIns(File directory) {
     526    File files[] = directory.listFiles();
     527    if(files != null) {
    528528                // Create a progress indicator.
    529                 ParsingProgress progress = new ParsingProgress(get("CDM.PlugInManager.Parsing.Title"), get("CDM.PlugInManager.Parsing.Message"), files.length);
    530                 for(int i = 0; i < files.length; i++) {
    531                      // We only want to check Perl Modules.
    532                      if(files[i].getName().endsWith(".pm")) {
    533                           loadPlugIn(files[i]);
    534                      }
    535                      progress.inc();
     529        ParsingProgress progress = new ParsingProgress(get("CDM.PlugInManager.Parsing.Title"), get("CDM.PlugInManager.Parsing.Message"), files.length);
     530        for(int i = 0; i < files.length; i++) {
     531        // We only want to check Perl Modules.
     532        if(files[i].getName().endsWith(".pm")) {
     533            loadPlugIn(files[i]);
     534        }
     535        progress.inc();
     536        }
     537        progress.dispose();
     538    }
     539    }
     540
     541    private PlugIn parse(Node root) {
     542    PlugIn plugin = new PlugIn();
     543    String node_name = null;
     544    for(Node node = root.getFirstChild(); node != null;
     545        node = node.getNextSibling()) {
     546        node_name = node.getNodeName();
     547        if(node_name.equals("Name")) {
     548        String name = getValue(node);
     549        // 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.
     550        PlugIn existing = getPlugIn(name);
     551        if(existing != null) {
     552            return existing;
     553        }
     554        plugin.setName(name);
     555        }
     556        else if(node_name.equals("Desc")) {
     557        plugin.setDesc(getValue(node));
     558        }
     559                // Parse the multitude of arguments.
     560        else if(node_name.equals("Arguments")) {
     561        for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
     562            node_name = arg.getNodeName();
     563            // An option.
     564            if(node_name.equals("Option")) {
     565            Argument argument = new Argument();
     566            // If its an option we parse the multitude of details an options might have.
     567            for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
     568                node_name = det.getNodeName();
     569                if(node_name.equals("Name")) {
     570                argument.setName(getValue(det));
     571                }
     572                else if(node_name.equals("Desc")) {
     573                argument.setDesc(getValue(det));
     574                }
     575                else if(node_name.equals("Type")) {
     576                argument.setType(getValue(det));
     577                }
     578                else if(node_name.equals("Default")) {
     579                argument.setDefault(getValue(det));
     580                }
     581                else if(node_name.equals("List")) {
     582                // Two final loops are required to parse lists.
     583                for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
     584                    if(value.getNodeName().equals("Value")) {
     585                    String key = null;
     586                    String desc = "";
     587                    for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
     588                        node_name = subvalue.getNodeName();
     589                        if(node_name.equals("Name")) {
     590                        key = getValue(subvalue);
     591                        }
     592                        else if(node_name.equals("Desc")) {
     593                        desc = getValue(subvalue);
     594                        }
     595                    }
     596                    if(key != null) {
     597                        argument.addOption(key, desc);
     598                    }
     599                    }
    536600                }
    537                 progress.dispose();
    538           }
    539      }
    540 
    541      private PlugIn parse(Node root) {
    542           PlugIn plugin = new PlugIn();
    543           String node_name = null;
    544           for(Node node = root.getFirstChild(); node != null;
    545                 node = node.getNextSibling()) {
    546                 node_name = node.getNodeName();
    547                 if(node_name.equals("Name")) {
    548                      String name = getValue(node);
    549                      // 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.
    550                      PlugIn existing = getPlugIn(name);
    551                      if(existing != null) {
    552                           return existing;
    553                      }
    554                      plugin.setName(name);
     601                }
     602                else if(node_name.equals("Required")) {
     603                String v = getValue(det);
     604                if(v != null && v.equals("yes")) {
     605                    argument.setRequired(true);
    555606                }
    556                 else if(node_name.equals("Desc")) {
    557                      plugin.setDesc(getValue(node));
    558                 }
    559                 // Parse the multitude of arguments.
    560                 else if(node_name.equals("Arguments")) {
    561                      for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
    562                           node_name = arg.getNodeName();
    563                           // An option.
    564                           if(node_name.equals("Option")) {
    565                                 Argument argument = new Argument();
    566                                 // If its an option we parse the multitude of details an options might have.
    567                                 for(Node det = arg.getFirstChild(); det != null; det = det.getNextSibling()) {
    568                                      node_name = det.getNodeName();
    569                                      if(node_name.equals("Name")) {
    570                                           argument.setName(getValue(det));
    571                                      }
    572                                      else if(node_name.equals("Desc")) {
    573                                           argument.setDesc(getValue(det));
    574                                      }
    575                                      else if(node_name.equals("Type")) {
    576                                           argument.setType(getValue(det));
    577                                      }
    578                                      else if(node_name.equals("Default")) {
    579                                           argument.setDefault(getValue(det));
    580                                      }
    581                                      else if(node_name.equals("List")) {
    582                                           // Two final loops are required to parse lists.
    583                                           for(Node value = det.getFirstChild(); value != null; value = value.getNextSibling()) {
    584                                                 if(value.getNodeName().equals("Value")) {
    585                                                      String key = null;
    586                                                      String desc = "";
    587                                                      for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
    588                                                           node_name = subvalue.getNodeName();
    589                                                           if(node_name.equals("Name")) {
    590                                                                 key = getValue(subvalue);
    591                                                           }
    592                                                           else if(node_name.equals("Desc")) {
    593                                                                 desc = getValue(subvalue);
    594                                                           }
    595                                                      }
    596                                                      if(key != null) {
    597                                                           argument.addOption(key, desc);
    598                                                      }
    599                                                 }
    600                                           }
    601                                      }
    602                                      else if(node_name.equals("Required")) {
    603                                           String v = getValue(det);
    604                                           if(v != null && v.equals("yes")) {
    605                                                 argument.setRequired(true);
    606                                           }
    607                                      }
    608                                 }
    609                                 plugin.addArgument(argument);
    610                           }
    611                           // A super plugin class.
    612                           else if(node_name.equals("PlugInfo")) {
    613                                 PlugIn super_plugin = parse(arg);
    614                                 plugin.setSuper(super_plugin);
    615                           }
    616                      }
    617                 }
    618           }
    619           if(plugin.getName() != null) {
    620                 addPlugIn(plugin);
    621                 return plugin;
    622           }
    623           return null;
    624      }
    625 
    626      /** A class which provodes controls for assigned and editing plugins. */
    627      private class Control
    628           extends JPanel {
    629           /** Button for adding plugins. */
    630           private JButton add = null;
    631           /** Button for configuring the selected plugin. */
    632           private JButton configure = null;
    633           /** Buttom to move an assinged plugin as low in the order as possible. */
    634           private JButton move_bottom = null;
    635           /** Button to move an assigned plugin one position lower in the order. */
    636           private JButton move_down = null;
    637           /** Button to move an assigned plugin as high in the order as possible. */
    638           private JButton move_top = null;
    639           /** Button to move an assigned plugin one position higher in the order. */
    640           private JButton move_up = null;
    641           /** Button to remove the selected plugin. */
    642           private JButton remove = null;
    643           /** A combobox containing all of the known plugins, including those that may have already been assigned. */
    644           private JComboBox plugin = null;
    645           /** The label next to the plugin combobox. */
    646           private JLabel plugin_label = null;
    647           /** The label above the assigned plugin list. */
    648           private JLabel plugin_list_label = null;
    649           /** The title of this view. */
    650           private JLabel title = null;
    651           /** A list of assigned plugins. */
    652           private JList plugin_list = null;
    653           /** The area where the add, configure and remove buttons are placed. */
    654           private JPanel button_pane = null;
    655           /** The region which divides the central portion of the view into list and controls. */
    656           private JPanel central_pane = null;
    657           /** The area where title label and instructions sit. */
    658           private JPanel header_pane = null;
    659           /** The area where movement buttons are placed. */
    660           private JPanel movement_pane = null;
    661           /** The small region containing the plugin combobox and its label. */
    662           private JPanel plugin_pane = null;
    663           /** The pane containing the assigned plugin list and its label. */
    664           private JPanel plugin_list_pane = null;
    665           /** The text area containing instructions on the use of this control. */
    666           private JTextArea instructions = null;
    667           /** Constructor.
     607                }
     608            }
     609            plugin.addArgument(argument);
     610            }
     611            // A super plugin class.
     612            else if(node_name.equals("PlugInfo")) {
     613            PlugIn super_plugin = parse(arg);
     614            plugin.setSuper(super_plugin);
     615            }
     616        }
     617        }
     618    }
     619    if(plugin.getName() != null) {
     620        addPlugIn(plugin);
     621        return plugin;
     622    }
     623    return null;
     624    }
     625
     626    /** A class which provodes controls for assigned and editing plugins. */
     627    private class Control
     628    extends JPanel {
     629    /** Button for adding plugins. */
     630    private JButton add = null;
     631    /** Button for configuring the selected plugin. */
     632    private JButton configure = null;
     633    /** Buttom to move an assinged plugin as low in the order as possible. */
     634    private JButton move_bottom = null;
     635    /** Button to move an assigned plugin one position lower in the order. */
     636    private JButton move_down = null;
     637    /** Button to move an assigned plugin as high in the order as possible. */
     638    private JButton move_top = null;
     639    /** Button to move an assigned plugin one position higher in the order. */
     640    private JButton move_up = null;
     641    /** Button to remove the selected plugin. */
     642    private JButton remove = null;
     643    /** A combobox containing all of the known plugins, including those that may have already been assigned. */
     644    private JComboBox plugin = null;
     645    /** The label next to the plugin combobox. */
     646    private JLabel plugin_label = null;
     647    /** The label above the assigned plugin list. */
     648    private JLabel plugin_list_label = null;
     649    /** The title of this view. */
     650    private JLabel title = null;
     651    /** A list of assigned plugins. */
     652    private JList plugin_list = null;
     653    /** The area where the add, configure and remove buttons are placed. */
     654    private JPanel button_pane = null;
     655    /** The region which divides the central portion of the view into list and controls. */
     656    private JPanel central_pane = null;
     657    /** The area where title label and instructions sit. */
     658    private JPanel header_pane = null;
     659    /** The area where movement buttons are placed. */
     660    private JPanel movement_pane = null;
     661    /** The small region containing the plugin combobox and its label. */
     662    private JPanel plugin_pane = null;
     663    /** The pane containing the assigned plugin list and its label. */
     664    private JPanel plugin_list_pane = null;
     665    /** The text area containing instructions on the use of this control. */
     666    private JTextArea instructions = null;
     667    /** Constructor.
     668     */
     669    public Control() {
     670        Object plugins[] = reserve.toArray();
     671        Vector plugin_model = new Vector();
     672        for(int i = 0; i < plugins.length; i++) {
     673        plugin_model.add(((PlugIn)plugins[i]).getName());
     674        }
     675        Collections.sort(plugin_model);
     676                // Create
     677        add = new JButton(get("Add"));
     678        add.setMnemonic(KeyEvent.VK_A);
     679        button_pane = new JPanel();
     680        central_pane = new JPanel();
     681        configure = new JButton(get("Configure"));
     682        configure.setMnemonic(KeyEvent.VK_C);
     683        header_pane = new JPanel();
     684        instructions = new JTextArea(get("Instructions"));
     685        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     686        instructions.setEditable(false);
     687        instructions.setLineWrap(true);
     688        instructions.setRows(5);
     689        instructions.setWrapStyleWord(true);
     690        move_bottom = new JButton();
     691        JLabel move_bottom_label = new JLabel(get("Move_Bottom"));
     692        move_bottom_label.setHorizontalAlignment(JLabel.CENTER);
     693        move_bottom_label.setPreferredSize(LABEL_SIZE);
     694        move_bottom.setLayout(new BorderLayout());
     695        move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.WEST);
     696        move_bottom.add(move_bottom_label, BorderLayout.CENTER);
     697        move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.EAST);
     698        move_bottom.setMnemonic(KeyEvent.VK_B);
     699        move_down = new JButton();
     700        JLabel move_down_label = new JLabel(get("Move_Down"));
     701        move_down_label.setHorizontalAlignment(JLabel.CENTER);
     702        move_down_label.setPreferredSize(LABEL_SIZE);
     703        move_down.setLayout(new BorderLayout());
     704        move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.WEST);
     705        move_down.add(move_down_label, BorderLayout.CENTER);
     706        move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.EAST);
     707        move_down.setMnemonic(KeyEvent.VK_D);
     708        move_top = new JButton();
     709        JLabel move_top_label = new JLabel(get("Move_Top"));
     710        move_top_label.setHorizontalAlignment(JLabel.CENTER);
     711        move_top_label.setPreferredSize(LABEL_SIZE);
     712        move_top.setLayout(new BorderLayout());
     713        move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.WEST);
     714        move_top.add(move_top_label, BorderLayout.CENTER);
     715        move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.EAST);
     716        move_top.setMnemonic(KeyEvent.VK_T);
     717        move_up = new JButton();
     718        JLabel move_up_label = new JLabel(get("Move_Up"));
     719        move_up_label.setHorizontalAlignment(JLabel.CENTER);
     720        move_up_label.setPreferredSize(LABEL_SIZE);
     721        move_up.setLayout(new BorderLayout());
     722        move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.WEST);
     723        move_up.add(move_up_label, BorderLayout.CENTER);
     724        move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.EAST);
     725        move_up.setMnemonic(KeyEvent.VK_U);
     726        movement_pane = new JPanel();
     727        plugin = new JComboBox(available);
     728                //plugin.setEditable(true);
     729        plugin.setSelectedIndex(0);
     730        plugin_label = new JLabel(get("PlugIn"));
     731        plugin_list = new JList(assigned);
     732        plugin_list.setCellRenderer(new ListRenderer());
     733        plugin_list_label = new JLabel(get("Assigned"));
     734        plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
     735        plugin_list_label.setOpaque(true);
     736        plugin_list_pane = new JPanel();
     737        plugin_pane = new JPanel();
     738        remove = new JButton(get("Remove"));
     739        remove.setMnemonic(KeyEvent.VK_R);
     740        title = new JLabel(get("Title"));
     741        title.setHorizontalAlignment(JLabel.CENTER);
     742        title.setOpaque(true);
     743                // Listeners
     744        add.addActionListener(new AddListener());
     745        configure.addActionListener(new ConfigureListener());
     746        MoveListener ml = new MoveListener();
     747        move_bottom.addActionListener(ml);
     748        move_down.addActionListener(ml);
     749        move_top.addActionListener(ml);
     750        move_up.addActionListener(ml);
     751        remove.addActionListener(new RemoveListener());
     752        plugin_list.addMouseListener(new ClickListener());
     753                // Layout
     754        title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
     755
     756        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     757
     758        header_pane.setLayout(new BorderLayout());
     759        header_pane.add(title, BorderLayout.NORTH);
     760        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     761
     762        plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
     763
     764        movement_pane.setLayout(new GridLayout(4,1));
     765        movement_pane.add(move_top);
     766        movement_pane.add(move_up);
     767        movement_pane.add(move_down);
     768        movement_pane.add(move_bottom);
     769
     770        plugin_list_pane.setLayout(new BorderLayout());
     771        plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
     772        plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
     773        plugin_list_pane.add(movement_pane, BorderLayout.EAST);
     774
     775        plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     776
     777        plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     778        plugin_pane.setLayout(new GridLayout(1,2));
     779        plugin_pane.add(plugin_label);
     780        plugin_pane.add(plugin);
     781
     782                // Scope these mad bordering skillz.
     783        JPanel temp = new JPanel(new BorderLayout());
     784        temp.setBorder
     785        (BorderFactory.createCompoundBorder
     786         (BorderFactory.createEmptyBorder(5,0,5,0),
     787          BorderFactory.createCompoundBorder
     788          (BorderFactory.createTitledBorder(get("Controls")),
     789           BorderFactory.createEmptyBorder(2,2,2,2))));
     790                                                                     
     791        temp.add(plugin_pane, BorderLayout.NORTH);
     792        temp.add(button_pane, BorderLayout.SOUTH);
     793
     794        central_pane.setLayout(new BorderLayout());
     795        central_pane.add(plugin_list_pane, BorderLayout.CENTER);
     796        central_pane.add(temp, BorderLayout.SOUTH);
     797
     798        button_pane.setLayout(new GridLayout(3,1));
     799        button_pane.add(add);
     800        button_pane.add(configure);
     801        button_pane.add(remove);
     802
     803        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     804        setLayout(new BorderLayout());
     805        add(header_pane, BorderLayout.NORTH);
     806        add(central_pane, BorderLayout.CENTER);
     807                //add(button_pane, BorderLayout.SOUTH);
     808    }
     809    /** Method which acts like a destructor, tidying up references to persistant objects.
    668810            */
    669           public Control() {
    670                 Object plugins[] = reserve.toArray();
    671                 Vector plugin_model = new Vector();
    672                 for(int i = 0; i < plugins.length; i++) {
    673                      plugin_model.add(((PlugIn)plugins[i]).getName());
    674                 }
    675                 Collections.sort(plugin_model);
    676                 // Create
    677                 add = new JButton(get("Add"));
    678                 add.setMnemonic(KeyEvent.VK_A);
    679                 button_pane = new JPanel();
    680                 central_pane = new JPanel();
    681                 configure = new JButton(get("Configure"));
    682                 configure.setMnemonic(KeyEvent.VK_C);
    683                 header_pane = new JPanel();
    684                 instructions = new JTextArea(get("Instructions"));
    685                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    686                 instructions.setEditable(false);
    687                 instructions.setLineWrap(true);
    688                 instructions.setRows(5);
    689                 instructions.setWrapStyleWord(true);
    690                 move_bottom = new JButton();
    691                 JLabel move_bottom_label = new JLabel(get("Move_Bottom"));
    692                 move_bottom_label.setHorizontalAlignment(JLabel.CENTER);
    693                 move_bottom_label.setPreferredSize(LABEL_SIZE);
    694                 move_bottom.setLayout(new BorderLayout());
    695                 move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.WEST);
    696                 move_bottom.add(move_bottom_label, BorderLayout.CENTER);
    697                 move_bottom.add(new JLabel(Utility.getImage("arrow-bottom.gif")), BorderLayout.EAST);
    698                 move_bottom.setMnemonic(KeyEvent.VK_B);
    699                 move_down = new JButton();
    700                 JLabel move_down_label = new JLabel(get("Move_Down"));
    701                 move_down_label.setHorizontalAlignment(JLabel.CENTER);
    702                 move_down_label.setPreferredSize(LABEL_SIZE);
    703                 move_down.setLayout(new BorderLayout());
    704                 move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.WEST);
    705                 move_down.add(move_down_label, BorderLayout.CENTER);
    706                 move_down.add(new JLabel(Utility.getImage("arrow-down.gif")), BorderLayout.EAST);
    707                 move_down.setMnemonic(KeyEvent.VK_D);
    708                 move_top = new JButton();
    709                 JLabel move_top_label = new JLabel(get("Move_Top"));
    710                 move_top_label.setHorizontalAlignment(JLabel.CENTER);
    711                 move_top_label.setPreferredSize(LABEL_SIZE);
    712                 move_top.setLayout(new BorderLayout());
    713                 move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.WEST);
    714                 move_top.add(move_top_label, BorderLayout.CENTER);
    715                 move_top.add(new JLabel(Utility.getImage("arrow-top.gif")), BorderLayout.EAST);
    716                 move_top.setMnemonic(KeyEvent.VK_T);
    717                 move_up = new JButton();
    718                 JLabel move_up_label = new JLabel(get("Move_Up"));
    719                 move_up_label.setHorizontalAlignment(JLabel.CENTER);
    720                 move_up_label.setPreferredSize(LABEL_SIZE);
    721                 move_up.setLayout(new BorderLayout());
    722                 move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.WEST);
    723                 move_up.add(move_up_label, BorderLayout.CENTER);
    724                 move_up.add(new JLabel(Utility.getImage("arrow-up.gif")), BorderLayout.EAST);
    725                 move_up.setMnemonic(KeyEvent.VK_U);
    726                 movement_pane = new JPanel();
    727                 plugin = new JComboBox(available);
    728                 //plugin.setEditable(true);
    729                 plugin.setSelectedIndex(0);
    730                 plugin_label = new JLabel(get("PlugIn"));
    731                 plugin_list = new JList(assigned);
    732                 plugin_list.setCellRenderer(new ListRenderer());
    733                 plugin_list_label = new JLabel(get("Assigned"));
    734                 plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
    735                 plugin_list_label.setOpaque(true);
    736                 plugin_list_pane = new JPanel();
    737                 plugin_pane = new JPanel();
    738                 remove = new JButton(get("Remove"));
    739                 remove.setMnemonic(KeyEvent.VK_R);
    740                 title = new JLabel(get("Title"));
    741                 title.setHorizontalAlignment(JLabel.CENTER);
    742                 title.setOpaque(true);
    743                 // Listeners
    744                 add.addActionListener(new AddListener());
    745                 configure.addActionListener(new ConfigureListener());
    746                 MoveListener ml = new MoveListener();
    747                 move_bottom.addActionListener(ml);
    748                 move_down.addActionListener(ml);
    749                 move_top.addActionListener(ml);
    750                 move_up.addActionListener(ml);
    751                 remove.addActionListener(new RemoveListener());
    752                 plugin_list.addMouseListener(new ClickListener());
    753                 // Layout
    754                 title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
    755 
    756                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    757 
    758                 header_pane.setLayout(new BorderLayout());
    759                 header_pane.add(title, BorderLayout.NORTH);
    760                 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    761 
    762                 plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
    763 
    764                 movement_pane.setLayout(new GridLayout(4,1));
    765                 movement_pane.add(move_top);
    766                 movement_pane.add(move_up);
    767                 movement_pane.add(move_down);
    768                 movement_pane.add(move_bottom);
    769 
    770                 plugin_list_pane.setLayout(new BorderLayout());
    771                 plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
    772                 plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
    773                 plugin_list_pane.add(movement_pane, BorderLayout.EAST);
    774 
    775                 plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
    776 
    777                 plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    778                 plugin_pane.setLayout(new GridLayout(1,2));
    779                 plugin_pane.add(plugin_label);
    780                 plugin_pane.add(plugin);
    781 
    782                 // Scope these mad bordering skillz.
    783                 JPanel temp = new JPanel(new BorderLayout());
    784                 temp.setBorder
    785                      (BorderFactory.createCompoundBorder
    786                       (BorderFactory.createEmptyBorder(5,0,5,0),
    787                         BorderFactory.createCompoundBorder
    788                         (BorderFactory.createTitledBorder(get("Controls")),
    789                          BorderFactory.createEmptyBorder(2,2,2,2))));
    790                                                                      
    791                 temp.add(plugin_pane, BorderLayout.NORTH);
    792                 temp.add(button_pane, BorderLayout.SOUTH);
    793 
    794                 central_pane.setLayout(new BorderLayout());
    795                 central_pane.add(plugin_list_pane, BorderLayout.CENTER);
    796                 central_pane.add(temp, BorderLayout.SOUTH);
    797 
    798                 button_pane.setLayout(new GridLayout(3,1));
    799                 button_pane.add(add);
    800                 button_pane.add(configure);
    801                 button_pane.add(remove);
    802 
    803                 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    804                 setLayout(new BorderLayout());
    805                 add(header_pane, BorderLayout.NORTH);
    806                 add(central_pane, BorderLayout.CENTER);
    807                 //add(button_pane, BorderLayout.SOUTH);
    808           }
    809           /** Method which acts like a destructor, tidying up references to persistant objects.
    810             */
    811           public void destroy() {
    812           }
    813           /** 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.
     811    public void destroy() {
     812    }
     813    /** 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.
    814814            * @return <i>true</i> if this control has focus, <i>false</i> otherwise.
    815815            */
    816           public boolean hasFocus() {
    817                 return super.hasFocus();
    818           }
    819           /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
     816    public boolean hasFocus() {
     817        return super.hasFocus();
     818    }
     819    /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
    820820            */
    821           public void updateUI() {
    822                 if(instructions != null) {
    823                      instructions.setCaretPosition(0);
    824                 }
    825                 super.updateUI();
    826           }
    827           /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugIn()</i> method.
     821    public void updateUI() {
     822        if(instructions != null) {
     823        instructions.setCaretPosition(0);
     824        }
     825        super.updateUI();
     826    }
     827    /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugIn()</i> method.
    828828            */
    829           private class AddListener
    830                 implements ActionListener {
     829    private class AddListener
     830        implements ActionListener {
    831831                /** 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.
    832832                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
    833833                 */
    834                 public void actionPerformed(ActionEvent event) {
    835                      PlugIn new_plugin = null;
    836                      Object object = plugin.getSelectedItem();
    837                      if(object instanceof PlugIn) {
    838                           PlugIn target = (PlugIn)object;
    839                           new_plugin = target.copy();
    840                      }
    841                      else {
    842                           new_plugin = new PlugIn(object.toString(), "", null);
    843                      }
    844                      object = null;
    845                      // Automatically chain to configuration. This ensures required arguments are filled out.
    846                      ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, new_plugin);
    847                      if(ac.display()) {
    848                           assignPlugIn(new_plugin);
    849                           plugin_list.setSelectedValue(new_plugin, true);
    850                      }
    851                      ac = null;
    852                      new_plugin = null;
    853                      plugin.setSelectedIndex(0);
    854                 }
    855           }
    856           /** This class listens for actions upon the configure button in the controls, and if detected creates a new <strong>ArgumentConfiguration</strong> dialog box to allow for configuration.
     834        public void actionPerformed(ActionEvent event) {
     835        PlugIn new_plugin = null;
     836        Object object = plugin.getSelectedItem();
     837        if(object instanceof PlugIn) {
     838            PlugIn target = (PlugIn)object;
     839            new_plugin = target.copy();
     840        }
     841        else {
     842            new_plugin = new PlugIn(object.toString(), "", null);
     843        }
     844        object = null;
     845        // Automatically chain to configuration. This ensures required arguments are filled out.
     846        ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, new_plugin);
     847        if(ac.display()) {
     848            assignPlugIn(new_plugin);
     849            plugin_list.setSelectedValue(new_plugin, true);
     850        }
     851        ac = null;
     852        new_plugin = null;
     853        plugin.setSelectedIndex(0);
     854        }
     855    }
     856    /** This class listens for actions upon the configure button in the controls, and if detected creates a new <strong>ArgumentConfiguration</strong> dialog box to allow for configuration.
    857857            * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
    858858            */
    859           private class ConfigureListener
    860                 implements ActionListener {
     859    private class ConfigureListener
     860        implements ActionListener {
    861861                /** 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.
    862862                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
    863863                 */
    864                 public void actionPerformed(ActionEvent event) {
    865                      if(!plugin_list.isSelectionEmpty()) {
    866                           Object object = plugin_list.getSelectedValue();
    867                           if(object instanceof PlugIn) {
    868                                 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
    869                                 if(ac.display()) {
    870                                     assigned.refresh();
    871                                 }
    872                           }
    873                      }
    874                 }
    875           }
    876           /** A special list renderer which is able to render separating lines as well. */
    877           private class ListRenderer
    878                 extends DefaultListCellRenderer {
     864        public void actionPerformed(ActionEvent event) {
     865        if(!plugin_list.isSelectionEmpty()) {
     866            Object object = plugin_list.getSelectedValue();
     867            if(object instanceof PlugIn) {
     868            ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
     869            if(ac.display()) {
     870                assigned.refresh();
     871            }
     872            }
     873        }
     874        }
     875    }
     876    /** A special list renderer which is able to render separating lines as well. */
     877    private class ListRenderer
     878        extends DefaultListCellRenderer {
    879879                /** 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.
    880880                 * @param list - The <strong>JList</strong> we're painting.
     
    889889                 * @see javax.swing.ListSelectionModel
    890890                 */
    891                 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    892                      if(value instanceof JPanel) {
    893                           return (JPanel) value;
    894                      }
    895                      else {
    896                           return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    897                      }
    898                 }
    899           }
    900           /** Listens for double clicks apon the list and react as if the configure button was pushed. */
    901           private class ClickListener
    902                 extends MouseAdapter {
     891        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     892        if(value instanceof JPanel) {
     893            return (JPanel) value;
     894        }
     895        else {
     896            return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     897        }
     898        }
     899    }
     900    /** Listens for double clicks apon the list and react as if the configure button was pushed. */
     901    private class ClickListener
     902        extends MouseAdapter {
    903903                /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
    904904                 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
    905905                 */
    906                 public void mouseClicked(MouseEvent event) {
    907                      if(event.getClickCount() == 2 ) {
    908                           if(!plugin_list.isSelectionEmpty()) {
    909                                 Object object = plugin_list.getSelectedValue();
    910                                 if(object instanceof PlugIn) {
    911                                     ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
    912                                     if(ac.display()) {
    913                                           assigned.refresh();
    914                                     }
    915                                 }
    916                           }
    917                      }
    918                 }
    919           }
    920           /** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>movePlugIn()</i> method of the manager with the appropriate details. */
    921           private class MoveListener
    922                 implements ActionListener {
     906        public void mouseClicked(MouseEvent event) {
     907        if(event.getClickCount() == 2 ) {
     908            if(!plugin_list.isSelectionEmpty()) {
     909            Object object = plugin_list.getSelectedValue();
     910            if(object instanceof PlugIn) {
     911                ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
     912                if(ac.display()) {
     913                assigned.refresh();
     914                }
     915            }
     916            }
     917        }
     918        }
     919    }
     920    /** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>movePlugIn()</i> method of the manager with the appropriate details. */
     921    private class MoveListener
     922        implements ActionListener {
    923923                /** 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.
    924924                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
    925925                 */
    926                 public void actionPerformed(ActionEvent event) {
    927                      if(!plugin_list.isSelectionEmpty()) {
    928                           Object object = plugin_list.getSelectedValue();
    929                           if(object instanceof PlugIn) {
    930                                 PlugIn plugin = (PlugIn) object;
    931                                 if(event.getSource() == move_top) {
    932                                     movePlugIn(plugin, true, true);
    933                                 }
    934                                 else if(event.getSource() == move_up) {
    935                                     movePlugIn(plugin, true, false);
    936                                 }
    937                                 else if(event.getSource() == move_down) {
    938                                     movePlugIn(plugin, false, false);
    939                                 }
    940                                 else {
    941                                     movePlugIn(plugin, false, true);
    942                                 }
    943                                 plugin_list.setSelectedValue(plugin, true);
    944                           }
    945                      }
    946                 }
    947           }
    948           /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugIn()</i> method.
     926        public void actionPerformed(ActionEvent event) {
     927        if(!plugin_list.isSelectionEmpty()) {
     928            Object object = plugin_list.getSelectedValue();
     929            if(object instanceof PlugIn) {
     930            PlugIn plugin = (PlugIn) object;
     931            if(event.getSource() == move_top) {
     932                movePlugIn(plugin, true, true);
     933            }
     934            else if(event.getSource() == move_up) {
     935                movePlugIn(plugin, true, false);
     936            }
     937            else if(event.getSource() == move_down) {
     938                movePlugIn(plugin, false, false);
     939            }
     940            else {
     941                movePlugIn(plugin, false, true);
     942            }
     943            plugin_list.setSelectedValue(plugin, true);
     944            }
     945        }
     946        }
     947    }
     948    /** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugIn()</i> method.
    949949            */
    950           private class RemoveListener
    951                 implements ActionListener {
     950    private class RemoveListener
     951        implements ActionListener {
    952952                /** 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.
    953953                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
    954954                 */
    955                 public void actionPerformed(ActionEvent event) {
    956                      if(!plugin_list.isSelectionEmpty()) {
    957                           Object object = plugin_list.getSelectedValue();
    958                           if(object instanceof PlugIn) {
    959                                 removePlugIn((PlugIn)object);
    960                           }
    961                      }
    962                 }
    963           }
    964     }
    965     /** Creates a list separator.
     955        public void actionPerformed(ActionEvent event) {
     956        if(!plugin_list.isSelectionEmpty()) {
     957            Object object = plugin_list.getSelectedValue();
     958            if(object instanceof PlugIn) {
     959            removePlugIn((PlugIn)object);
     960            }
     961        }
     962        }
     963    }
     964    }
     965    /** Creates a list separator.
    966966      * Code courtesy of Farwell, Paul. Contact <a href="mailto:[email protected]">[email protected]</a>
    967967      */
    968     static private JPanel getSeparator() {
    969           // we put the separator inside a panel to control
    970           // its appearance
    971           JPanel _sepPanel = new JPanel();
    972           _sepPanel.setOpaque(false);
    973           _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
    974           _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
    975           _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
    976           _sepPanel.add(new JPopupMenu.Separator());
    977           _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
    978           return _sepPanel;
    979     }
     968    static private JPanel getSeparator() {
     969    // we put the separator inside a panel to control
     970    // its appearance
     971    JPanel _sepPanel = new JPanel();
     972    _sepPanel.setOpaque(false);
     973    _sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
     974    _sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
     975    _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
     976    _sepPanel.add(new JPopupMenu.Separator());
     977    _sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
     978    return _sepPanel;
     979    }
    980980}
    981981
  • trunk/gli/src/org/greenstone/gatherer/cdm/SubIndex.java

    r4293 r4366  
    6060*/
    6161public class SubIndex
    62     extends Vector
    63     implements Comparable {
    64     /** Default Constructor.
    65       */
    66     public SubIndex() {
    67           super();
    68     }
    69     /** Copy Constructor.
     62    extends Vector
     63    implements Comparable {
     64    /** Default Constructor.
     65     */
     66    public SubIndex() {
     67    super();
     68    }
     69    /** Copy Constructor.
    7070      * @param original The <strong>Vector</strong> used to initially fill the SubIndex.
    7171      */
    72     public SubIndex(Vector original) {
    73           super(original);
    74     }
    75     /** Parsed data Constructor.
     72    public SubIndex(Vector original) {
     73    super(original);
     74    }
     75    /** Parsed data Constructor.
    7676      * @param raw A <strong>String</strong> containing a comma separated list of subcollection names.
    7777      * @param manager A reference to the <strong>SubcollectionManager</strong> via which we retrieve the required Subcollections.
    7878      */
    79     public SubIndex(String raw, SubcollectionManager manager) {
    80           super();
    81           StringTokenizer tokenizer = new StringTokenizer(raw, ",");
    82           while(tokenizer.hasMoreTokens()) {
    83                 String name = tokenizer.nextToken();
    84                 Subcollection sub = manager.getSubcollection(name);
    85                 if(sub != null) {
    86                      add(sub);
    87                 }
    88           }
    89     }
    90     /** Method to compare two subindexes.
     79    public SubIndex(String raw, SubcollectionManager manager) {
     80    super();
     81    StringTokenizer tokenizer = new StringTokenizer(raw, ",");
     82    while(tokenizer.hasMoreTokens()) {
     83        String name = tokenizer.nextToken();
     84        Subcollection sub = manager.getSubcollection(name);
     85        if(sub != null) {
     86        add(sub);
     87        }
     88    }
     89    }
     90    /** Method to compare two subindexes.
    9191      * @param object The other subindex to compare to, as an <strong>Object</strong>.
    9292      * @return An <i>int</i> which is greater than, equal to or less than zero if the this object is before, equal to, or after the target object respectively.
    9393      */
    94     public int compareTo(Object object) {
    95           SubIndex index = (SubIndex) object;
    96           return toString().compareTo(index.toString());
    97     }
    98     /** Method to determine if this subindex contains a certain subcollection.
     94    public int compareTo(Object object) {
     95    SubIndex index = (SubIndex) object;
     96    return toString().compareTo(index.toString());
     97    }
     98    /** Method to determine if this subindex contains a certain subcollection.
    9999      * @param name The name, as a <strong>String</strong>, of the subcollection you are checking for.
    100100      * @return A <i>boolean</i> which is <i>true</i> if this index contains the named subcollection, <i>false</i> otherwise.
    101101      */
    102     public boolean containsSubcollection(String name) {
    103           for(int i = 0; i < size(); i++) {
    104                 Subcollection sub = (Subcollection) get(i);
    105                 if(sub.getName().equals(name)) {
    106                      return true;
    107                 }
    108           }
    109           return false;
    110     }
    111     /** Method to check two subindexes for equality.
     102    public boolean containsSubcollection(String name) {
     103    for(int i = 0; i < size(); i++) {
     104        Subcollection sub = (Subcollection) get(i);
     105        if(sub.getName().equals(name)) {
     106        return true;
     107        }
     108    }
     109    return false;
     110    }
     111    /** Method to check two subindexes for equality.
    112112      * @param object The other subindex to compare to, as an <strong>Object</strong>.
    113113      * @return A <i>boolean</i> which is <i>true</i> if the subindexes are equal, <i>false</i> otherwise.
    114114      */
    115     public boolean equals(Object object) {
    116           if(compareTo(object) == 0) {
    117                 return true;
    118           }
    119           return false;
    120     }
    121     /** Method to generate a comma separated list from a subindex vector.
     115    public boolean equals(Object object) {
     116    if(compareTo(object) == 0) {
     117        return true;
     118    }
     119    return false;
     120    }
     121    /** Method to generate a comma separated list from a subindex vector.
    122122      * @return A <strong>String</strong> representing this subindex.
    123123      */
    124     public String toString() {
    125           String text = "";
    126           for(int i = 0; i < size(); i++) {
    127                 Object object = get(i);
    128                 Subcollection sub = (Subcollection) get(i);
    129                 text = text + sub.getName();
    130                 if(i < size() - 1) {
    131                           text = text + ",";
    132                 }
    133           }
    134           return text;
    135     }
     124    public String toString() {
     125    String text = "";
     126    for(int i = 0; i < size(); i++) {
     127        Object object = get(i);
     128        Subcollection sub = (Subcollection) get(i);
     129        text = text + sub.getName();
     130        if(i < size() - 1) {
     131        text = text + ",";
     132        }
     133    }
     134    return text;
     135    }
    136136}
  • trunk/gli/src/org/greenstone/gatherer/cdm/SubIndexes.java

    r4293 r4366  
    5858*/
    5959public class SubIndexes
    60     extends DefaultListModel {
    61     public void changed() {
    62           fireContentsChanged(this, 0, getSize() - 1);
    63     }
    64     /** Method to display the contents of this class as an entry in the collection configuration file. The line contains the key word, then a space separated series of index entries.
    65       * @return A <strong>String</strong> representing this collection of indexes.
    66       */
    67     public String toString() {
    68           String text = "indexsubcollections  ";
    69           for(int i = 0; i < size(); i++) {
    70                 text = text + ((SubIndex)get(i)).toString();
    71                 if(i < size() - 1) {
    72                      text = text + " ";
    73                 }
    74           }
    75           text = text + "\n";
    76           return text;
    77     }
     60    extends DefaultListModel {
     61    public void changed() {
     62    fireContentsChanged(this, 0, getSize() - 1);
     63    }
     64    /** Method to display the contents of this class as an entry in the collection configuration file. The line contains the key word, then a space separated series of index entries.
     65     * @return A <strong>String</strong> representing this collection of indexes.
     66     */
     67    public String toString() {
     68    String text = "indexsubcollections  ";
     69    for(int i = 0; i < size(); i++) {
     70        text = text + ((SubIndex)get(i)).toString();
     71        if(i < size() - 1) {
     72        text = text + " ";
     73        }
     74    }
     75    text = text + "\n";
     76    return text;
     77    }
    7878}
  • trunk/gli/src/org/greenstone/gatherer/cdm/Subcollection.java

    r4293 r4366  
    5353import org.w3c.dom.Element;
    5454/** This class encapsulates one subcollection entry in the collection configuration file.
    55 * @author John Thompson, Greenstone Digital Library, University of Waikato
    56 * @version 2.3
    57 */
     55 * @author John Thompson, Greenstone Digital Library, University of Waikato
     56 * @version 2.3
     57 */
    5858public class Subcollection
    59     implements Comparable {
    60     /** A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise. */
    61     private boolean include = true;
    62     /** Either the fully qualified name of the metadata whose value should be matched against the given expression, or <i>null</i> if you wish to match against the file name. */
    63     private String element = null;
    64     /** A String containing a Perl expression which is used as the filter for this subcollection. */
    65     private String exp = null;
    66     /** A series of flags to be used when matching the expression. */
    67     private String flags = null;
    68     /** A String which is a unique identifier of a subcollection. */
    69     private String name = null;
    70     /** Constructor.
    71       * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    72       * @param pattern A <strong>String</strong> containing the inclusion, the element to filter, a Perl expression which is used as the filter for this subcollection, and a series of argument flags.
    73       */
    74     public Subcollection(String name, String pattern) {
    75           this.name = name;
    76           // Have to do some work on pattern.
    77           // Remove quote marks.
    78           if(pattern.startsWith("\"") || pattern.startsWith("'")) {
    79                 pattern = pattern.substring(1, pattern.length() - 1);
    80           }
    81           // Test for exclusion
    82           if(pattern.startsWith("!")) {
    83                 this.include = false;
    84                 pattern = pattern.substring(1, pattern.length());
    85           }
    86           else {
    87                 this.include = true;
    88           }
    89           if(pattern.indexOf("/") != -1) {
     59    implements Comparable {
     60    /** A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise. */
     61    private boolean include = true;
     62    /** Either the fully qualified name of the metadata whose value should be matched against the given expression, or <i>null</i> if you wish to match against the file name. */
     63    private String element = null;
     64    /** A String containing a Perl expression which is used as the filter for this subcollection. */
     65    private String exp = null;
     66    /** A series of flags to be used when matching the expression. */
     67    private String flags = null;
     68    /** A String which is a unique identifier of a subcollection. */
     69    private String name = null;
     70    /** Constructor.
     71     * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
     72     * @param pattern A <strong>String</strong> containing the inclusion, the element to filter, a Perl expression which is used as the filter for this subcollection, and a series of argument flags.
     73     */
     74    public Subcollection(String name, String pattern) {
     75    this.name = name;
     76    // Have to do some work on pattern.
     77    // Remove quote marks.
     78    if(pattern.startsWith("\"") || pattern.startsWith("'")) {
     79        pattern = pattern.substring(1, pattern.length() - 1);
     80    }
     81    // Test for exclusion
     82    if(pattern.startsWith("!")) {
     83        this.include = false;
     84        pattern = pattern.substring(1, pattern.length());
     85    }
     86    else {
     87        this.include = true;
     88    }
     89    if(pattern.indexOf("/") != -1) {
    9090                // Now element (which may be Filename)
    91                 this.element = pattern.substring(0, pattern.indexOf("/"));
    92                 if(this.element.toLowerCase().equals("filename")) {
    93                      this.element = null;
    94                 }
     91        this.element = pattern.substring(0, pattern.indexOf("/"));
     92        if(this.element.toLowerCase().equals("filename")) {
     93        this.element = null;
     94        }
    9595                // Extract Perl expression
    96                 if(pattern.indexOf("/") != pattern.lastIndexOf("/")) {
    97                      this.exp = pattern.substring(pattern.indexOf("/") + 1,
    98                                                             pattern.lastIndexOf("/"));
    99                      this.flags = pattern.substring(pattern.lastIndexOf("/") + 1);
    100                 }
    101                 else {
    102                      this.exp = pattern.substring(pattern.indexOf("/") + 1);
    103                 }
    104           }
    105           else {
     96        if(pattern.indexOf("/") != pattern.lastIndexOf("/")) {
     97        this.exp = pattern.substring(pattern.indexOf("/") + 1,
     98                         pattern.lastIndexOf("/"));
     99        this.flags = pattern.substring(pattern.lastIndexOf("/") + 1);
     100        }
     101        else {
     102        this.exp = pattern.substring(pattern.indexOf("/") + 1);
     103        }
     104    }
     105    else {
    106106                // Hmmm. Well I don't know what this is but it isn't a proper subcollection definition. Can't really 'return null' or something. So I'll just not set include, element, exp and flag expressions.
    107           }
    108     }
    109     /** Constructor.
     107    }
     108    }
     109    /** Constructor.
    110110      * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    111111      * @param include A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise.
    112112      * @param exp A <strong>String</strong> containing a Perl expression which is used as the filter for this subcollection.
    113113      */
    114     public Subcollection(String name, boolean include, String exp, String flags) {
    115           this.element = null;
    116           this.exp = exp;
    117           this.flags = flags;
    118           this.include = include;
    119           this.name = name;
    120     }
    121     /** Constructor.
     114    public Subcollection(String name, boolean include, String exp, String flags) {
     115    this.element = null;
     116    this.exp = exp;
     117    this.flags = flags;
     118    this.include = include;
     119    this.name = name;
     120    }
     121    /** Constructor.
    122122      * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    123123      * @param include A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise.
     
    126126      * @param flags A <strong>String</strong> of flags to be taken into account when matching the expression.
    127127      */
    128     public Subcollection(String name, boolean include, String element, String exp, String flags) {
    129           this.element = element;
    130           this.exp = exp;
    131           this.flags = flags;
    132           this.include = include;
    133           this.name = name;
    134     }
    135     /** Method to compare two subcollections.
     128    public Subcollection(String name, boolean include, String element, String exp, String flags) {
     129    this.element = element;
     130    this.exp = exp;
     131    this.flags = flags;
     132    this.include = include;
     133    this.name = name;
     134    }
     135    /** Method to compare two subcollections.
    136136      * @param object The other subcollection to compare to, as an <strong>Object</strong>.
    137137      * @return An <i>int</i> which is greater than, equal to or less than zero if the this object is before, equal to, or after the target object respectively.
    138138      */
    139     public int compareTo(Object object) {
    140           Subcollection sub = (Subcollection) object;
    141           return getName().compareTo(sub.getName());
    142     }
    143     /** Method to check two subcollections for equality.
     139    public int compareTo(Object object) {
     140    Subcollection sub = (Subcollection) object;
     141    return getName().compareTo(sub.getName());
     142    }
     143    /** Method to check two subcollections for equality.
    144144      * @param object The other subcollection to compare to, as an <strong>Object</strong>.
    145145      * @return A <i>boolean</i> which is <i>true</i> if the subcollections are equal, <i>false</i> otherwise.
    146146      */
    147     public boolean equals(Object object) {
    148           if(compareTo(object) == 0) {
    149                 return true;
    150           }
    151           return false;
    152     }
    153     /** Method to get the value of element.
     147    public boolean equals(Object object) {
     148    if(compareTo(object) == 0) {
     149        return true;
     150    }
     151    return false;
     152    }
     153    /** Method to get the value of element.
    154154      * @return The value of element as an <strong>String</strong>.
    155155      */
    156     public String getElement() {
    157           return element;
    158     }
    159     /** Method to get the value of expression.
     156    public String getElement() {
     157    return element;
     158    }
     159    /** Method to get the value of expression.
    160160      * @return The value of exp as a <strong>String</strong>.
    161161      */
    162     public String getExpression() {
    163           return exp;
    164     }
    165     /** Method to get the value of flags.
     162    public String getExpression() {
     163    return exp;
     164    }
     165    /** Method to get the value of flags.
    166166      * @return The value of flags as a <strong>String</strong>.
    167167      */
    168     public String getFlags() {
    169           return flags;
    170     }
    171     /** Method to get the value of include.
     168    public String getFlags() {
     169    return flags;
     170    }
     171    /** Method to get the value of include.
    172172      * @param boolean The value of include as a <i>boolean</i>.
    173173      */
    174     public boolean getInclude() {
    175           return include;
    176     }
    177     /** Method to get the value of name.
     174    public boolean getInclude() {
     175    return include;
     176    }
     177    /** Method to get the value of name.
    178178      * @param String The value of name as a <strong>String</string>.
    179179      */
    180     public String getName() {
    181           return name;
    182     }
    183     /** Method to get the name of the source of the strings used in pattern matching.
     180    public String getName() {
     181    return name;
     182    }
     183    /** Method to get the name of the source of the strings used in pattern matching.
    184184      * @return A <strong>String</strong> which is either the fully qualified name of a metadata element, or "Filename".
    185185      */
    186     public String getSource() {
    187           if(element != null) {
    188                 return element;
    189           }
    190           return "Filename";
    191     }
    192     /** Method to display the contents of this class as it would appear in the collection configuration file.
     186    public String getSource() {
     187    if(element != null) {
     188        return element;
     189    }
     190    return "Filename";
     191    }
     192    /** Method to display the contents of this class as it would appear in the collection configuration file.
    193193      * @return A <strong>String</strong> which could be used as a subcollection entry in collect.cfg.
    194194      */
    195     public String toString() {
    196           String text = "subcollection        ";
    197           text = text + name + " ";
    198           text = text + "\"";
    199           if(!include) {
    200                 text = text + "!";
    201           }
    202           if(element != null) {
    203                 text = text + element;
    204           }
    205           else {
    206                 text = text + "Filename";
    207           }
    208           text = text + "/";
    209           text = text + exp;
    210           text = text + "/";
    211           if(flags != null) {
    212                 text = text + flags;
    213           }
    214           text = text + "\"\n";
    215           return text;
    216     }
    217 
    218     /** Update certain fields of this subcollection.
     195    public String toString() {
     196    String text = "subcollection        ";
     197    text = text + name + " ";
     198    text = text + "\"";
     199    if(!include) {
     200        text = text + "!";
     201    }
     202    if(element != null) {
     203        text = text + element;
     204    }
     205    else {
     206        text = text + "Filename";
     207    }
     208    text = text + "/";
     209    text = text + exp;
     210    text = text + "/";
     211    if(flags != null) {
     212        text = text + flags;
     213    }
     214    text = text + "\"\n";
     215    return text;
     216    }
     217
     218    /** Update certain fields of this subcollection.
    219219      * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    220220      * @param source Either the fully qualified name of the metadata whose value should be matched against the given expression, or <i>null</i> if you wish to match against the file name.
     
    223223      * @param flags A <strong>String</strong> of flags to be taken into account when matching the expression.
    224224        */
    225     public void update(String name, String source, String exp, boolean include, String flags) {
    226           this.name = name;
    227           this.element = source;
    228           this.exp = exp;
    229           this.include = include;
    230           this.flags = flags;
    231     }
    232 
    233     /** Method to update the name of a metadata element, if it changes.
     225    public void update(String name, String source, String exp, boolean include, String flags) {
     226    this.name = name;
     227    this.element = source;
     228    this.exp = exp;
     229    this.include = include;
     230    this.flags = flags;
     231    }
     232
     233    /** Method to update the name of a metadata element, if it changes.
    234234      * @param old_name The current name of the element as a <strong>String</strong>.
    235235      * @param new_name The new name of the element as a <strong>String</strong>.
    236236      */
    237     public void updateElement(String old_name, String new_name) {
    238           if(element.equals(old_name)) {
    239                 element = new_name;
    240           }
    241     }
     237    public void updateElement(String old_name, String new_name) {
     238    if(element.equals(old_name)) {
     239        element = new_name;
     240    }
     241    }
    242242}
    243243
  • trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java

    r4293 r4366  
    8787import org.w3c.dom.Element;
    8888/** This class maintains a list of subcollections within our collection, and also records which of these subcollections we are building indexes for.
    89 * @author John Thompson, Greenstone Digital Library, University of Waikato
    90 * @version 2.1
    91 */
     89 * @author John Thompson, Greenstone Digital Library, University of Waikato
     90 * @version 2.1
     91 */
    9292public class SubcollectionManager
    93     extends DefaultListModel {
    94     /** The controls used to edit the settings of this manager. */
    95     private Control controls = null;
    96     /** A reference to this class so we can use it as a model in our inner classes. */
    97     private DefaultListModel model = null;
    98     /** The default index for the subcollections. */
    99     private DefaultSubIndex default_index = null;
    100     /** A reference to the Gatherer. */
    101     private Gatherer gatherer = null;
    102     /** A hashtable of subcollections, with mappings from name to subcollection. */
    103     private Hashtable subcollections = null;
    104     /** A vector-type structure of subcollection indexes. */
    105     private SubIndexes subindexes = null;
    106     /** A vector containing all of the subcollection commands that are unresolved, or in other words require that all 'subcollection <name> "<exp>"' to have been previously parsed before we can be certain their references will make sense. */
    107     private ArrayList unresolved = null;
    108     /** Constructor.
    109         * @param gatherer A reference to the <Strong>Gatherer</strong>.
    110         * @see org.greenstone.gatherer.cdm.SubIndexes
    111       */
    112     public SubcollectionManager(Gatherer gatherer) {
    113           super();
    114           this.gatherer = gatherer;
    115           this.model = this;
    116           this.subcollections = new Hashtable();
    117           this.subindexes = new SubIndexes();
    118           this.unresolved = new ArrayList();
    119     }
    120     /** Method to add a subindex.
     93    extends DefaultListModel {
     94    /** The controls used to edit the settings of this manager. */
     95    private Control controls = null;
     96    /** A reference to this class so we can use it as a model in our inner classes. */
     97    private DefaultListModel model = null;
     98    /** The default index for the subcollections. */
     99    private DefaultSubIndex default_index = null;
     100    /** A reference to the Gatherer. */
     101    private Gatherer gatherer = null;
     102    /** A hashtable of subcollections, with mappings from name to subcollection. */
     103    private Hashtable subcollections = null;
     104    /** A vector-type structure of subcollection indexes. */
     105    private SubIndexes subindexes = null;
     106    /** A vector containing all of the subcollection commands that are unresolved, or in other words require that all 'subcollection <name> "<exp>"' to have been previously parsed before we can be certain their references will make sense. */
     107    private ArrayList unresolved = null;
     108    /** Constructor.
     109     * @param gatherer A reference to the <Strong>Gatherer</strong>.
     110     * @see org.greenstone.gatherer.cdm.SubIndexes
     111     */
     112    public SubcollectionManager(Gatherer gatherer) {
     113    super();
     114    this.gatherer = gatherer;
     115    this.model = this;
     116    this.subcollections = new Hashtable();
     117    this.subindexes = new SubIndexes();
     118    this.unresolved = new ArrayList();
     119    }
     120    /** Method to add a subindex.
    121121      * @param subindex A <strong>SubIndex</strong>.
    122122        * @see org.greenstone.gatherer.Gatherer
    123123        * @see org.greenstone.gatherer.collection.CollectionManager
    124124      */
    125     public void addSubIndex(SubIndex subindex) {
    126           if(!subindexes.contains(subindex)) {
    127                 subindexes.addElement(subindex);
    128                 gatherer.c_man.configurationChanged();
    129           }
    130     }
    131     /** Method to add a new subcollection. Adds it to both the underlying list model and the hashtable mapping names to subcollections.
     125    public void addSubIndex(SubIndex subindex) {
     126    if(!subindexes.contains(subindex)) {
     127        subindexes.addElement(subindex);
     128        gatherer.c_man.configurationChanged();
     129    }
     130    }
     131    /** Method to add a new subcollection. Adds it to both the underlying list model and the hashtable mapping names to subcollections.
    132132      * @param sub The <strong>Subcollection</strong> to add.
    133133      * @return A <i>boolean</i> indicating if the addition was successful (<i>true</i>) or not (<i>false</i>).
     
    135135        * @see org.greenstone.gatherer.collection.CollectionManager
    136136      */
    137     public boolean addSubcollection(Subcollection sub) {
    138           if(!contains(sub)) {
    139                 addElement(sub);
    140                 subcollections.put(sub.getName(), sub);
    141                 gatherer.c_man.configurationChanged();
    142                 return true;
    143           }
    144           return false;
    145     }
    146     /** A method to add a new subcollection, by specifying its name, metadata element if applicable and Perl expression to filter pages into or out of this collection.
     137    public boolean addSubcollection(Subcollection sub) {
     138    if(!contains(sub)) {
     139        addElement(sub);
     140        subcollections.put(sub.getName(), sub);
     141        gatherer.c_man.configurationChanged();
     142        return true;
     143    }
     144    return false;
     145    }
     146    /** A method to add a new subcollection, by specifying its name, metadata element if applicable and Perl expression to filter pages into or out of this collection.
    147147      * @param name A <>>String</>> which is a unique identifier of a subcollection.
    148148      * @param include A <i>boolean</i> indicating whether this is an inclusion filter (<i>true</i>) or an exclusion one (<i>false</i>).
     
    153153        * @see org.greenstone.gatherer.cdm.Subcollection
    154154      */
    155     public boolean addSubcollection(String name, boolean include, String element, String exp, String flags) {
    156           Subcollection sub = null;
    157           if(element != null) {
    158                 sub = new Subcollection(name, include, element, exp, flags);
    159           }
    160           else {
    161                 sub = new Subcollection(name, include, exp, flags);
    162           }
    163           return addSubcollection(sub);
    164     }
    165     /** Refresh all derived components using this manager as a model.
     155    public boolean addSubcollection(String name, boolean include, String element, String exp, String flags) {
     156    Subcollection sub = null;
     157    if(element != null) {
     158        sub = new Subcollection(name, include, element, exp, flags);
     159    }
     160    else {
     161        sub = new Subcollection(name, include, exp, flags);
     162    }
     163    return addSubcollection(sub);
     164    }
     165    /** Refresh all derived components using this manager as a model.
    166166    */
    167     public void changed() {
    168           fireContentsChanged(this, 0, getSize() - 1);
    169     }
    170     /** Method to retrieve the controls for this manager.
     167    public void changed() {
     168    fireContentsChanged(this, 0, getSize() - 1);
     169    }
     170    /** Method to retrieve the controls for this manager.
    171171      * @return A <Strong>Control</strong> object which contains the controls used to edit the subcollection data.
    172172      */
    173     public Control getControls() {
    174           if(controls == null) {
    175                 controls = new Control();
    176           }
    177           return controls;
    178     }
    179     /** Method to retrieve the default index.
     173    public Control getControls() {
     174    if(controls == null) {
     175        controls = new Control();
     176    }
     177    return controls;
     178    }
     179    /** Method to retrieve the default index.
    180180      * @return A <strong>DefaultSubIndex</strong> object.
    181181      */
    182     public DefaultSubIndex getDefaultSubIndex() {
    183           return default_index;
    184     }
    185     /** Method to retrieve a certain subcollection by its name.
     182    public DefaultSubIndex getDefaultSubIndex() {
     183    return default_index;
     184    }
     185    /** Method to retrieve a certain subcollection by its name.
    186186      * @param name A <strong>String</strong> which is used as the key for finding the matching subcollection.
    187187      * @return The requested <strong>Subcollection</strong> or <i>null</i> if no such subcollection exists.
    188188      */
    189     public Subcollection getSubcollection(String name) {
    190           return (Subcollection) subcollections.get(name);
    191     }
    192     /** Method to get all of the subindexes set.
     189    public Subcollection getSubcollection(String name) {
     190    return (Subcollection) subcollections.get(name);
     191    }
     192    /** Method to get all of the subindexes set.
    193193      * @return A <strong>SubIndexes</strong> object containing all the defined indexes.
    194194      */
    195     public SubIndexes getSubIndexes() {
    196           return subindexes;
    197     }
    198     /** Method to get all of the subcollections defined.
     195    public SubIndexes getSubIndexes() {
     196    return subindexes;
     197    }
     198    /** Method to get all of the subcollections defined.
    199199      * @return A <strong>Vector</strong> of subcollections.
    200200      */
    201     public Vector getSubcollections() {
    202           Vector subcollections = new Vector();
    203           for(int i = 0; i < size(); i++) {
    204                 subcollections.add(get(i));
    205           }
    206           return subcollections;
    207     }
    208     /** Mark the current controls, if any, as invalid and deallocate them. Any further use of the controls will requires them being rebuilt.
     201    public Vector getSubcollections() {
     202    Vector subcollections = new Vector();
     203    for(int i = 0; i < size(); i++) {
     204        subcollections.add(get(i));
     205    }
     206    return subcollections;
     207    }
     208    /** Mark the current controls, if any, as invalid and deallocate them. Any further use of the controls will requires them being rebuilt.
    209209    * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control
    210210    */
    211     public void invalidateControls() {
    212           if(controls != null) {
    213                 controls.destroy();
    214                 controls = null;
    215           }
    216     }
    217     /** This method attempts to parse a subcollection related command from the given command string. If such a string is successfully parsed, it is immediately added to the data within this collection.
     211    public void invalidateControls() {
     212    if(controls != null) {
     213        controls.destroy();
     214        controls = null;
     215    }
     216    }
     217    /** This method attempts to parse a subcollection related command from the given command string. If such a string is successfully parsed, it is immediately added to the data within this collection.
    218218      * @param command The <strong>String</strong> to be parsed.
    219219      * @param finished This <i>boolean</i> is usually <i>false</i> when called, unless this parse call is being made -after- the entire collection configuration file has been read in in which case it is <i>true</i>.
     
    224224      * @see org.greenstone.gatherer.cdm.SubIndex
    225225      */
    226     public boolean parse(String command, boolean finished) {
    227           String temp = command.toLowerCase();
    228           CommandTokenizer tokenizer = new CommandTokenizer(command);
    229           tokenizer.nextToken(); // Throw away head.
    230           if(temp.startsWith("subcollection")) {
    231                 if(tokenizer.countTokens() >= 2) {
    232                      String name = tokenizer.nextToken();
    233                      String pattern = tokenizer.nextToken();
    234                      addSubcollection(new Subcollection(name, pattern));
    235                      return true;
    236                 }
    237           }
    238           else if(temp.startsWith("indexsubcollections")) {
     226    public boolean parse(String command, boolean finished) {
     227    String temp = command.toLowerCase();
     228    CommandTokenizer tokenizer = new CommandTokenizer(command);
     229    tokenizer.nextToken(); // Throw away head.
     230    if(temp.startsWith("subcollection")) {
     231        if(tokenizer.countTokens() >= 2) {
     232        String name = tokenizer.nextToken();
     233        String pattern = tokenizer.nextToken();
     234        addSubcollection(new Subcollection(name, pattern));
     235        return true;
     236        }
     237    }
     238    else if(temp.startsWith("indexsubcollections")) {
    239239                // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
    240                 if(!finished) {
    241                      unresolved.add(command);
    242                 }
    243                 else {
    244                      while(tokenizer.hasMoreTokens()) {
    245                           addSubIndex(new SubIndex(tokenizer.nextToken(), this));
    246                      }
    247                 }
    248                 return true;
    249           }
    250           else if(temp.startsWith("defaultsubcollection")) {
     240        if(!finished) {
     241        unresolved.add(command);
     242        }
     243        else {
     244        while(tokenizer.hasMoreTokens()) {
     245            addSubIndex(new SubIndex(tokenizer.nextToken(), this));
     246        }
     247        }
     248        return true;
     249    }
     250    else if(temp.startsWith("defaultsubcollection")) {
    251251                // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
    252                 if(!finished) {
    253                      unresolved.add(command);
    254                 }
    255                 else {
    256                      if(tokenizer.hasMoreTokens()) {
    257                           setDefaultSubIndex(new DefaultSubIndex(tokenizer.nextToken(), this));
    258                      }
    259                 }
    260                 return true;
    261           }
    262           return false;
    263     }
    264     /** Method to remove a certain subindex.
     252        if(!finished) {
     253        unresolved.add(command);
     254        }
     255        else {
     256        if(tokenizer.hasMoreTokens()) {
     257            setDefaultSubIndex(new DefaultSubIndex(tokenizer.nextToken(), this));
     258        }
     259        }
     260        return true;
     261    }
     262    return false;
     263    }
     264    /** Method to remove a certain subindex.
    265265      * @param subindex The <strong>SubIndex</strong> you wish to remove.
    266266      * @see org.greenstone.gatherer.Gatherer
    267267      * @see org.greenstone.gatherer.collection.CollectionManager
    268268      */
    269     public void removeSubIndex(SubIndex subindex) {
    270           subindexes.removeElement(subindex);
    271           gatherer.c_man.configurationChanged();
    272     }
    273     /** Method to remove all of the subindexes that contain a certain subcollection.
     269    public void removeSubIndex(SubIndex subindex) {
     270    subindexes.removeElement(subindex);
     271    gatherer.c_man.configurationChanged();
     272    }
     273    /** Method to remove all of the subindexes that contain a certain subcollection.
    274274      * @param sub The <strong>Subcollection</strong> that you wish to remove.
    275275      * @see org.greenstone.gatherer.Gatherer
     
    277277      * @see org.greenstone.gatherer.collection.CollectionManager
    278278      */
    279     public void removeSubIndexes(Subcollection sub) {
    280           for(int i = subindexes.size() - 1; i >= 0; i--) {
    281                 SubIndex subindex = (SubIndex)subindexes.get(i);
    282                 if(subindex.containsSubcollection(sub.getName())) {
    283                      subindexes.removeElement(subindex);
    284                 }
    285           }
    286           gatherer.c_man.configurationChanged();
    287     }
    288     /** Method to remove the given subcollection.
     279    public void removeSubIndexes(Subcollection sub) {
     280    for(int i = subindexes.size() - 1; i >= 0; i--) {
     281        SubIndex subindex = (SubIndex)subindexes.get(i);
     282        if(subindex.containsSubcollection(sub.getName())) {
     283        subindexes.removeElement(subindex);
     284        }
     285    }
     286    gatherer.c_man.configurationChanged();
     287    }
     288    /** Method to remove the given subcollection.
    289289      * @param sub The <strong>Subcollection</strong> you want to remove.
    290290      * @see org.greenstone.gatherer.Gatherer
    291291      * @see org.greenstone.gatherer.collection.CollectionManager
    292292      */
    293     public void removeSubcollection(Subcollection sub) {
    294           removeElement(sub);
    295           subcollections.remove(sub);
    296           gatherer.c_man.configurationChanged();
    297     }
    298     /** Method to retry the parsing of commands that were previously unable to be parsed as they referenced subcollections that may not have been instantiated.
    299       */
    300     public void reparseUnresolved() {
    301           for(int i = 0; i < unresolved.size(); i++) {
    302                 parse((String)unresolved.get(i), true);
    303           }
    304           unresolved.clear();
    305     }
    306     /** Method to set the default subcollection index.
     293    public void removeSubcollection(Subcollection sub) {
     294    removeElement(sub);
     295    subcollections.remove(sub);
     296    gatherer.c_man.configurationChanged();
     297    }
     298    /** Method to retry the parsing of commands that were previously unable to be parsed as they referenced subcollections that may not have been instantiated.
     299      */
     300    public void reparseUnresolved() {
     301    for(int i = 0; i < unresolved.size(); i++) {
     302        parse((String)unresolved.get(i), true);
     303    }
     304    unresolved.clear();
     305    }
     306    /** Method to set the default subcollection index.
    307307      * @param subcollection The <strong>Subcollection</strong> to use as the default index.
    308308      * @see org.greenstone.gatherer.Gatherer
    309309      * @see org.greenstone.gatherer.collection.CollectionManager
    310310      */
    311     public void setDefaultSubIndex(DefaultSubIndex subindex) {
    312           this.default_index = subindex;
    313           if(subindex != null) {
    314                 addSubIndex(subindex.getSubIndex());
    315           }
    316           gatherer.c_man.configurationChanged();
    317     }
    318     /** This method causes the contents of this manager to be converted to a string, which is accomplished by calling <i>toString()</i> on each subcollection, then printing out the contents of the index vector.
     311    public void setDefaultSubIndex(DefaultSubIndex subindex) {
     312    this.default_index = subindex;
     313    if(subindex != null) {
     314        addSubIndex(subindex.getSubIndex());
     315    }
     316    gatherer.c_man.configurationChanged();
     317    }
     318    /** This method causes the contents of this manager to be converted to a string, which is accomplished by calling <i>toString()</i> on each subcollection, then printing out the contents of the index vector.
    319319      * @return A <strong>String</strong> containing a block of configuration commands.
    320320        * @see org.greenstone.gatherer.cdm.SubIndex
    321321        * @see org.greenstone.gatherer.cdm.Subcollection
    322322      */
    323     public String toString() {
    324           String text = "";
    325           // Retrieve the subcollection names and sort them.
    326           if(subcollections.size() > 0) {
    327                 Vector names = new Vector(subcollections.keySet());
    328                 Collections.sort(names);
    329                 for(int i = 0; i < names.size(); i++) {
    330                      Subcollection sub =
    331                           (Subcollection) subcollections.get(names.get(i));
    332                      text = text + sub.toString();
    333                 }
     323    public String toString() {
     324    String text = "";
     325    // Retrieve the subcollection names and sort them.
     326    if(subcollections.size() > 0) {
     327        Vector names = new Vector(subcollections.keySet());
     328        Collections.sort(names);
     329        for(int i = 0; i < names.size(); i++) {
     330        Subcollection sub =
     331            (Subcollection) subcollections.get(names.get(i));
     332        text = text + sub.toString();
     333        }
    334334                // Now add a entry, separated by spaces for each subcollection
    335335                // index.
    336                 if(subindexes.size() > 0) {
    337                      text = text + subindexes.toString();
    338                 }
     336        if(subindexes.size() > 0) {
     337        text = text + subindexes.toString();
     338        }
    339339                // Finally add the default subcollection index if necessary.
    340                 if(default_index != null) {
    341                      text = text + default_index.toString();
    342                 }
    343                 text = text + "\n";
    344           }
    345           // Otherwise if there were no subcollections, there aren't going to be
    346           // subcollection indexes, nor a default subcollection index are there.
    347           return text;
    348     }
    349     /** Method to retrieve a phrase from the dictionary based on a key.
     340        if(default_index != null) {
     341        text = text + default_index.toString();
     342        }
     343        text = text + "\n";
     344    }
     345    // Otherwise if there were no subcollections, there aren't going to be
     346    // subcollection indexes, nor a default subcollection index are there.
     347    return text;
     348    }
     349    /** Method to retrieve a phrase from the dictionary based on a key.
    350350      * @param key A <strong>String</strong> used to find the correct phrase.
    351351      * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
    352352      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    353353      */
    354     private String get(String key) {
    355           return get(key, null);
    356     }
    357     /** Method to retrieve a phrase from the dictionary based on a key.
     354    private String get(String key) {
     355    return get(key, null);
     356    }
     357    /** Method to retrieve a phrase from the dictionary based on a key.
    358358      * @param key A <strong>String</strong> used to find the correct phrase.
    359359      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
     
    361361      * @see org.greenstone.gatherer.Gatherer
    362362      */
    363     private String get(String key, String args[]) {
    364           if(key.indexOf(".") == -1) {
    365                 key = "CDM.SubcollectionManager." + key;
    366           }
    367           return gatherer.dictionary.get(key, args);
    368     }
    369     /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
    370     private class Control
    371           extends JPanel {
    372             /** <i>true</i> if the current selection has changed. */
    373           private boolean changed = false;
    374           /** Button to add a subcollection. */
    375           private JButton add = null;
    376           /** Button to add a subindex. */
    377           private JButton add_index = null;
    378           /** Button to clear the default subindex. */
    379           private JButton clear_default = null;
    380           /** Button to remove a subcollection. */
    381           private JButton remove = null;
    382           /** Button to remove a subindex. */
    383           private JButton remove_index = null;
    384           /** Button to set the default subindex. */
    385           private JButton set_default = null;
    386           /** Button to cause an update of the subcollections. */
    387           private JButton update = null;
    388           /** A combobox allowing you to choose which field the data for matching should be taken from. Includes text body and filename, as well as all assigned metadata elements. */
    389           private JComboBox source = null;
    390           /** The list of assigned subcollections. */
    391           private JList subcollection_list = null;
    392           /** The list of subcollections available for the creation of subindexes. */
    393           private JList subcollection_list_2 = null;
    394           /** The list of assigned subindexes. */
    395           private JList subindexes_list = null;
    396           /** The label denoting the list of subindexes. */
    397           private JLabel subindexes_label = null;
    398           /** The panel containing the subcollection controls. */
    399           private JPanel subcollection_pane = null;
    400           /** The panel containing the subindex controls. */
    401           private JPanel subindex_pane = null;
    402           /** The tabbed pane used to store the subcollection and subindex controls. */
    403           private JTabbedPane tabbed_pane = null;
    404           /** The area used to display inline instructions. */
    405           private JTextArea instructions = null;
    406           /** The field displaying the name of the default subindex. */
    407           private JTextField default_value = null;
    408           /** A field used for specifying flags for the PERL expression matching, such as 'i' for case insensitive. */
    409           private JTextField flags = null;
    410           /** The pattern the source text must match. */
    411           private JTextField match = null;
    412           /** The name of this subcollection. */
    413           private JTextField name = null;
    414           /** When this button is selected the filter matching files are excluded. */
    415           private JToggleButton exclude = null;
    416           /** When this button is selected the filter matching files are included. */
    417           private JToggleButton include = null;
    418           /** The existing subcollection whose details you are reviewing, if any. */
    419           private Subcollection current = null;
    420             /** Constructor, creates the outer parts of the view, then calls two methods in turn to create the subcollection controls and subindex controls.
    421             */
    422           public Control() {
     363    private String get(String key, String args[]) {
     364    if(key.indexOf(".") == -1) {
     365        key = "CDM.SubcollectionManager." + key;
     366    }
     367    return gatherer.dictionary.get(key, args);
     368    }
     369    /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
     370    private class Control
     371    extends JPanel {
     372    /** <i>true</i> if the current selection has changed. */
     373    private boolean changed = false;
     374    /** Button to add a subcollection. */
     375    private JButton add = null;
     376    /** Button to add a subindex. */
     377    private JButton add_index = null;
     378    /** Button to clear the default subindex. */
     379    private JButton clear_default = null;
     380    /** Button to remove a subcollection. */
     381    private JButton remove = null;
     382    /** Button to remove a subindex. */
     383    private JButton remove_index = null;
     384    /** Button to set the default subindex. */
     385    private JButton set_default = null;
     386    /** Button to cause an update of the subcollections. */
     387    private JButton update = null;
     388    /** A combobox allowing you to choose which field the data for matching should be taken from. Includes text body and filename, as well as all assigned metadata elements. */
     389    private JComboBox source = null;
     390    /** The list of assigned subcollections. */
     391    private JList subcollection_list = null;
     392    /** The list of subcollections available for the creation of subindexes. */
     393    private JList subcollection_list_2 = null;
     394    /** The list of assigned subindexes. */
     395    private JList subindexes_list = null;
     396    /** The label denoting the list of subindexes. */
     397    private JLabel subindexes_label = null;
     398    /** The panel containing the subcollection controls. */
     399    private JPanel subcollection_pane = null;
     400    /** The panel containing the subindex controls. */
     401    private JPanel subindex_pane = null;
     402    /** The tabbed pane used to store the subcollection and subindex controls. */
     403    private JTabbedPane tabbed_pane = null;
     404    /** The area used to display inline instructions. */
     405    private JTextArea instructions = null;
     406    /** The field displaying the name of the default subindex. */
     407    private JTextField default_value = null;
     408    /** A field used for specifying flags for the PERL expression matching, such as 'i' for case insensitive. */
     409    private JTextField flags = null;
     410    /** The pattern the source text must match. */
     411    private JTextField match = null;
     412    /** The name of this subcollection. */
     413    private JTextField name = null;
     414    /** When this button is selected the filter matching files are excluded. */
     415    private JToggleButton exclude = null;
     416    /** When this button is selected the filter matching files are included. */
     417    private JToggleButton include = null;
     418    /** The existing subcollection whose details you are reviewing, if any. */
     419    private Subcollection current = null;
     420    /** Constructor, creates the outer parts of the view, then calls two methods in turn to create the subcollection controls and subindex controls.
     421     */
     422    public Control() {
    423423                // Create
    424                 JPanel border_pane = new JPanel();
    425                 JPanel header_pane = new JPanel();
    426                 instructions = new JTextArea(get("Instructions"));
    427                 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    428                 instructions.setEditable(false);
    429                 instructions.setLineWrap(true);
    430                 instructions.setRows(5);
    431                 instructions.setWrapStyleWord(true);
    432                 tabbed_pane = new JTabbedPane();
    433                 JLabel title = new JLabel(get("Title"));
    434                 title.setHorizontalAlignment(JLabel.CENTER);
    435                 createSubcollection();
    436                 createSubindex();
     424        JPanel border_pane = new JPanel();
     425        JPanel header_pane = new JPanel();
     426        instructions = new JTextArea(get("Instructions"));
     427        instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     428        instructions.setEditable(false);
     429        instructions.setLineWrap(true);
     430        instructions.setRows(5);
     431        instructions.setWrapStyleWord(true);
     432        tabbed_pane = new JTabbedPane();
     433        JLabel title = new JLabel(get("Title"));
     434        title.setHorizontalAlignment(JLabel.CENTER);
     435        createSubcollection();
     436        createSubindex();
    437437                // Add listeners
    438438                // Layout
    439                 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    440                 header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    441                 header_pane.setLayout(new BorderLayout());
    442                 header_pane.add(title, BorderLayout.NORTH);
    443                 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    444                 tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
    445                 tabbed_pane.addTab(get("Subindex_Controls"), subindex_pane);
    446                 border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    447                 border_pane.setLayout(new BorderLayout());
    448                 border_pane.add(tabbed_pane, BorderLayout.CENTER);
    449                 setLayout(new BorderLayout());
    450                 add(header_pane, BorderLayout.NORTH);
    451                 add(border_pane, BorderLayout.CENTER);
    452           }
    453             /** Create the subcollection controls.
     439        instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     440        header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     441        header_pane.setLayout(new BorderLayout());
     442        header_pane.add(title, BorderLayout.NORTH);
     443        header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
     444        tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
     445        tabbed_pane.addTab(get("Subindex_Controls"), subindex_pane);
     446        border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
     447        border_pane.setLayout(new BorderLayout());
     448        border_pane.add(tabbed_pane, BorderLayout.CENTER);
     449        setLayout(new BorderLayout());
     450        add(header_pane, BorderLayout.NORTH);
     451        add(border_pane, BorderLayout.CENTER);
     452    }
     453    /** Create the subcollection controls.
    454454            * @see org.greenstone.gatherer.Gatherer
    455455            * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddListener
     
    459459            * @see org.greenstone.gatherer.msm.MetadataSetManager
    460460            */
    461           public void createSubcollection() {
     461    public void createSubcollection() {
    462462                // Create
    463                 add = new JButton(get("Add"));
    464                 add.setMnemonic(KeyEvent.VK_A);
    465                 JPanel button_pane = new JPanel();
    466                 JPanel button_pane_1 = new JPanel();
    467                 JPanel button_pane_3 = new JPanel();
    468                 exclude = new JToggleButton(get("Exclude"));
    469                 exclude.setMnemonic(KeyEvent.VK_X);
    470                 flags = new JTextField();
    471                 JLabel flags_label = new JLabel(get("Flags"));
    472                 include = new JToggleButton(get("Include"));
    473                 include.setMnemonic(KeyEvent.VK_I);
    474                 JLabel inclusive_label = new JLabel(get("Inclusive"));
    475                 JPanel inclusive_pane = new JPanel();
    476                 match = new JTextField();
    477                 JLabel match_label = new JLabel(get("Match"));
    478                 name = new JTextField();
    479                 JLabel name_label = new JLabel(get("Name"));
    480                 remove = new JButton(get("Remove"));
    481                 remove.setMnemonic(KeyEvent.VK_R);
    482                 Vector source_model = gatherer.c_man.msm.getAssignedElements();
    483                 source_model.add(0, "Filename");
    484                 source = new JComboBox(source_model);
    485                 JLabel source_label = new JLabel(get("Source"));
    486                 subcollection_list = new JList(model);
    487                 subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    488                 subcollection_pane = new JPanel();
    489                 ButtonGroup bg = new ButtonGroup();
    490                 bg.add(include);
    491                 bg.add(exclude);
    492                 include.setSelected(true);
    493                 JPanel subcollection_list_pane = new JPanel();
    494                 JLabel subcollection_list_label = new JLabel(get("Assigned"));
     463        add = new JButton(get("Add"));
     464        add.setMnemonic(KeyEvent.VK_A);
     465        JPanel button_pane = new JPanel();
     466        JPanel button_pane_1 = new JPanel();
     467        JPanel button_pane_3 = new JPanel();
     468        exclude = new JToggleButton(get("Exclude"));
     469        exclude.setMnemonic(KeyEvent.VK_X);
     470        flags = new JTextField();
     471        JLabel flags_label = new JLabel(get("Flags"));
     472        include = new JToggleButton(get("Include"));
     473        include.setMnemonic(KeyEvent.VK_I);
     474        JLabel inclusive_label = new JLabel(get("Inclusive"));
     475        JPanel inclusive_pane = new JPanel();
     476        match = new JTextField();
     477        JLabel match_label = new JLabel(get("Match"));
     478        name = new JTextField();
     479        JLabel name_label = new JLabel(get("Name"));
     480        remove = new JButton(get("Remove"));
     481        remove.setMnemonic(KeyEvent.VK_R);
     482        Vector source_model = gatherer.c_man.msm.getAssignedElements();
     483        source_model.add(0, "Filename");
     484        source = new JComboBox(source_model);
     485        JLabel source_label = new JLabel(get("Source"));
     486        subcollection_list = new JList(model);
     487        subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     488        subcollection_pane = new JPanel();
     489        ButtonGroup bg = new ButtonGroup();
     490        bg.add(include);
     491        bg.add(exclude);
     492        include.setSelected(true);
     493        JPanel subcollection_list_pane = new JPanel();
     494        JLabel subcollection_list_label = new JLabel(get("Assigned"));
    495495
    496496                // Add listeners
    497                 add.addActionListener(new AddListener());
    498                 remove.addActionListener(new RemoveListener());
    499                 subcollection_list.addListSelectionListener(new ListListener());
     497        add.addActionListener(new AddListener());
     498        remove.addActionListener(new RemoveListener());
     499        subcollection_list.addListSelectionListener(new ListListener());
    500500
    501501                // Layout
    502                 inclusive_pane.setLayout(new GridLayout());
    503                inclusive_pane.add(include);
    504                 inclusive_pane.add(exclude);
    505                 button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    506                 button_pane_1.setLayout(new GridLayout(5, 2));
    507                 button_pane_1.add(name_label);
    508                 button_pane_1.add(name);
    509                 button_pane_1.add(source_label);
    510                 button_pane_1.add(source);
    511                 button_pane_1.add(match_label);
    512                 button_pane_1.add(match);
    513                 button_pane_1.add(inclusive_label);
    514                 button_pane_1.add(inclusive_pane);
    515                 button_pane_1.add(flags_label);
    516                 button_pane_1.add(flags);
    517                 button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    518                 button_pane_3.setLayout(new GridLayout(1,2));
    519                 button_pane_3.add(add);
    520                 button_pane_3.add(remove);
    521                 button_pane.setLayout(new BorderLayout());
    522                 button_pane.add(button_pane_1, BorderLayout.CENTER);
    523                 button_pane.add(button_pane_3, BorderLayout.SOUTH);
    524                 subcollection_list_pane.setLayout(new BorderLayout());
    525                 subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
    526                 subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
    527                 subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    528                 subcollection_pane.setLayout(new BorderLayout());
    529                 subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
    530                 subcollection_pane.add(button_pane, BorderLayout.SOUTH);
    531           }
    532             /** Create the subindex controls.
     502        inclusive_pane.setLayout(new GridLayout());
     503        inclusive_pane.add(include);
     504        inclusive_pane.add(exclude);
     505        button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
     506        button_pane_1.setLayout(new GridLayout(5, 2));
     507        button_pane_1.add(name_label);
     508        button_pane_1.add(name);
     509        button_pane_1.add(source_label);
     510        button_pane_1.add(source);
     511        button_pane_1.add(match_label);
     512        button_pane_1.add(match);
     513        button_pane_1.add(inclusive_label);
     514        button_pane_1.add(inclusive_pane);
     515        button_pane_1.add(flags_label);
     516        button_pane_1.add(flags);
     517        button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
     518        button_pane_3.setLayout(new GridLayout(1,2));
     519        button_pane_3.add(add);
     520        button_pane_3.add(remove);
     521        button_pane.setLayout(new BorderLayout());
     522        button_pane.add(button_pane_1, BorderLayout.CENTER);
     523        button_pane.add(button_pane_3, BorderLayout.SOUTH);
     524        subcollection_list_pane.setLayout(new BorderLayout());
     525        subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
     526        subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
     527        subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     528        subcollection_pane.setLayout(new BorderLayout());
     529        subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
     530        subcollection_pane.add(button_pane, BorderLayout.SOUTH);
     531    }
     532    /** Create the subindex controls.
    533533             * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddSubIndexListener
    534534             * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ClearDefaultListener
     
    538538             * @see org.greenstone.gatherer.util.ExclusiveListListener
    539539             */
    540           public void createSubindex() {
     540    public void createSubindex() {
    541541                // Creation
    542                 add_index = new JButton(get("Add_Subindex"));
    543                 add_index.setMnemonic(KeyEvent.VK_A);
    544                 JPanel button_pane_2 = new JPanel();
    545                 clear_default = new JButton(get("Clear_Default_Subindex"));
    546                 clear_default.setMnemonic(KeyEvent.VK_C);
    547                 if(default_index == null) {
    548                      clear_default.setEnabled(false);
    549                 }
    550                 JLabel default_label = new JLabel(get("Default_Subindex"));
    551                 JPanel default_pane = new JPanel();
    552                 if(default_index == null) {
    553                      default_value = new JTextField();
    554                 }
    555                 else {
    556                      default_value = new JTextField(default_index.getSubIndex().toString());
    557                 }
    558                 JPanel subindex_inner_pane_1 = new JPanel();
    559                 JPanel subindex_inner_pane_2 = new JPanel();
    560                 remove_index = new JButton(get("Remove_Subindex"));
    561                 remove_index.setMnemonic(KeyEvent.VK_R);
    562                 set_default = new JButton(get("Set_Default_Subindex"));
    563                 set_default.setMnemonic(KeyEvent.VK_S);
    564                 JLabel subcollection_label = new JLabel(get("Subcollection"));
    565                 subcollection_list_2 = new JList(model);
    566                 JPanel list_2_pane = new JPanel();
    567                 subindex_pane = new JPanel();
    568                 JLabel subindexes_label = new JLabel(get("Subindexes"));
    569                 subindexes_list = new JList(subindexes);
    570                 subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    571                 JPanel subindexes_pane = new JPanel();
     542        add_index = new JButton(get("Add_Subindex"));
     543        add_index.setMnemonic(KeyEvent.VK_A);
     544        JPanel button_pane_2 = new JPanel();
     545        clear_default = new JButton(get("Clear_Default_Subindex"));
     546        clear_default.setMnemonic(KeyEvent.VK_C);
     547        if(default_index == null) {
     548        clear_default.setEnabled(false);
     549        }
     550        JLabel default_label = new JLabel(get("Default_Subindex"));
     551        JPanel default_pane = new JPanel();
     552        if(default_index == null) {
     553        default_value = new JTextField();
     554        }
     555        else {
     556        default_value = new JTextField(default_index.getSubIndex().toString());
     557        }
     558        JPanel subindex_inner_pane_1 = new JPanel();
     559        JPanel subindex_inner_pane_2 = new JPanel();
     560        remove_index = new JButton(get("Remove_Subindex"));
     561        remove_index.setMnemonic(KeyEvent.VK_R);
     562        set_default = new JButton(get("Set_Default_Subindex"));
     563        set_default.setMnemonic(KeyEvent.VK_S);
     564        JLabel subcollection_label = new JLabel(get("Subcollection"));
     565        subcollection_list_2 = new JList(model);
     566        JPanel list_2_pane = new JPanel();
     567        subindex_pane = new JPanel();
     568        JLabel subindexes_label = new JLabel(get("Subindexes"));
     569        subindexes_list = new JList(subindexes);
     570        subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     571        JPanel subindexes_pane = new JPanel();
    572572
    573573                // Add listeners
    574                 ChangeListener cl = new ChangeListener();
    575                 ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
    576                 ell.add(subcollection_list_2);
    577                 ell.add(subindexes_list);
    578                 add_index.addActionListener(new AddSubIndexListener());
    579                 clear_default.addActionListener(new ClearDefaultListener());
    580                 exclude.addActionListener(cl);
    581                 include.addActionListener(cl);
    582                 remove_index.addActionListener(new RemoveSubIndexListener());
    583                 set_default.addActionListener(new SetDefaultListener());
    584                 source.addActionListener(cl);
    585                 flags.addKeyListener(cl);
    586                 match.addKeyListener(cl);
    587                 name.addKeyListener(cl);
     574        ChangeListener cl = new ChangeListener();
     575        ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
     576        ell.add(subcollection_list_2);
     577        ell.add(subindexes_list);
     578        add_index.addActionListener(new AddSubIndexListener());
     579        clear_default.addActionListener(new ClearDefaultListener());
     580        exclude.addActionListener(cl);
     581        include.addActionListener(cl);
     582        remove_index.addActionListener(new RemoveSubIndexListener());
     583        set_default.addActionListener(new SetDefaultListener());
     584        source.addActionListener(cl);
     585        flags.addKeyListener(cl);
     586        match.addKeyListener(cl);
     587        name.addKeyListener(cl);
    588588
    589589                // Layout
    590                 list_2_pane.setLayout(new BorderLayout());
    591                 list_2_pane.add(subcollection_label, BorderLayout.NORTH);
    592                 list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
    593                 subindexes_pane.setLayout(new BorderLayout());
    594                 subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
    595                 subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
    596                 subindex_inner_pane_2.setLayout(new GridLayout(2,1));
    597                 subindex_inner_pane_2.add(list_2_pane);
    598                 subindex_inner_pane_2.add(subindexes_pane);
    599                 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    600                 default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
    601                 default_pane.setLayout(new BorderLayout());
    602                 default_pane.add(default_label, BorderLayout.WEST);
    603                 default_pane.add(default_value, BorderLayout.CENTER);
    604                 subindex_inner_pane_1.setLayout(new BorderLayout());
    605                 subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
    606                 subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
    607                 button_pane_2.setLayout(new GridLayout(2,2));
    608                 button_pane_2.add(add_index);
    609                 button_pane_2.add(remove_index);
    610                 button_pane_2.add(clear_default);
    611                 button_pane_2.add(set_default);
    612                 subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    613                 subindex_pane.setLayout(new BorderLayout());
    614                 subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
    615                 subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
    616           }
    617           /** Method to unregister any listeners to avoid memory leaks.
     590        list_2_pane.setLayout(new BorderLayout());
     591        list_2_pane.add(subcollection_label, BorderLayout.NORTH);
     592        list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
     593        subindexes_pane.setLayout(new BorderLayout());
     594        subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
     595        subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
     596        subindex_inner_pane_2.setLayout(new GridLayout(2,1));
     597        subindex_inner_pane_2.add(list_2_pane);
     598        subindex_inner_pane_2.add(subindexes_pane);
     599        default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     600        default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
     601        default_pane.setLayout(new BorderLayout());
     602        default_pane.add(default_label, BorderLayout.WEST);
     603        default_pane.add(default_value, BorderLayout.CENTER);
     604        subindex_inner_pane_1.setLayout(new BorderLayout());
     605        subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
     606        subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
     607        button_pane_2.setLayout(new GridLayout(2,2));
     608        button_pane_2.add(add_index);
     609        button_pane_2.add(remove_index);
     610        button_pane_2.add(clear_default);
     611        button_pane_2.add(set_default);
     612        subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     613        subindex_pane.setLayout(new BorderLayout());
     614        subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
     615        subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
     616    }
     617    /** Method to unregister any listeners to avoid memory leaks.
    618618            */
    619           public void destroy() {
    620           }
    621           /** We have overriden this method to provide completely different functionality, given that our JPanel will never actually have focus. We call this method in GUI on the view we are about to replace, and this method checks if a change has occured and if so updates the current object.
     619    public void destroy() {
     620    }
     621    /** We have overriden this method to provide completely different functionality, given that our JPanel will never actually have focus. We call this method in GUI on the view we are about to replace, and this method checks if a change has occured and if so updates the current object.
    622622            * @return A <i>boolean</i> which is always <i>false</i>.
    623623            * @see org.greenstone.gatherer.msm.ElementWrapper
    624624            */
    625           public boolean hasFocus() {
     625    public boolean hasFocus() {
    626626                // If we have a current metadata open, and something has changed then save the change.
    627                 if(changed && current != null) {
    628                      String n = name.getText();
    629                      String s = null;
    630                      Object o = source.getSelectedItem();
    631                      if(o instanceof ElementWrapper) {
    632                           ElementWrapper e = (ElementWrapper)o;
    633                           s = e.toString();
    634                      }
    635                      String e = match.getText();
    636                      String f = flags.getText();
    637                      if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
    638                           current.update(n, s, e, include.isSelected(), f);
    639                           int index = model.indexOf(current);
    640                           changed();
    641                           subindexes.changed();
    642                           if(default_index != null) {
    643                                 default_value.setText(default_index.getSubIndex().toString());
    644                           }
    645                      }
    646                      changed = false;
    647                 }
    648                 return false;
    649           }
    650           /** Overriden to ensure the instructions are scrolled to top.
     627        if(changed && current != null) {
     628        String n = name.getText();
     629        String s = null;
     630        Object o = source.getSelectedItem();
     631        if(o instanceof ElementWrapper) {
     632            ElementWrapper e = (ElementWrapper)o;
     633            s = e.toString();
     634        }
     635        String e = match.getText();
     636        String f = flags.getText();
     637        if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
     638            current.update(n, s, e, include.isSelected(), f);
     639            int index = model.indexOf(current);
     640            changed();
     641            subindexes.changed();
     642            if(default_index != null) {
     643            default_value.setText(default_index.getSubIndex().toString());
     644            }
     645        }
     646        changed = false;
     647        }
     648        return false;
     649    }
     650    /** Overriden to ensure the instructions are scrolled to top.
    651651          */
    652           public void updateUI() {
    653                 if(instructions != null) {
    654                      instructions.setCaretPosition(0);
    655                 }
    656                 super.updateUI();
    657           }
    658           /** Listens for actions apon the 'add' button in the SubcollectionManager controls, and if detected calls the addSubcollection method of the manager with a newly created subcollection. */
    659           private class AddListener
    660                 implements ActionListener {
     652    public void updateUI() {
     653        if(instructions != null) {
     654        instructions.setCaretPosition(0);
     655        }
     656        super.updateUI();
     657    }
     658    /** Listens for actions apon the 'add' button in the SubcollectionManager controls, and if detected calls the addSubcollection method of the manager with a newly created subcollection. */
     659    private class AddListener
     660        implements ActionListener {
    661661                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we wish to retrieve information from the various edit controls, and if we have sufficient data to build a new subcollection do so.
    662662                 * @param event An <strong>ActionEvent</strong> containing information about the event.
     
    664664                 * @see org.greenstone.gatherer.msm.ElementWrapper
    665665                 */
    666                 public void actionPerformed(ActionEvent event) {
    667                      String n = name.getText();
    668                      String s = null;
    669                      Object o = source.getSelectedItem();
    670                      if(o instanceof ElementWrapper) {
    671                           ElementWrapper e = (ElementWrapper)o;
    672                           s = e.toString();
    673                      }
    674                      String e = match.getText();
    675                      String f = flags.getText();
    676                      if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
    677                           Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
    678                           addSubcollection(sub);
    679                      }
    680                      changed = false;
    681                 }
    682           }
    683           /** Listens for actions apon the 'add subindex' button in the SubcollectionManager controls, and if detected calls the addSubindex method of the manager with a newly created subindex. */
    684           private class AddSubIndexListener
    685                 implements ActionListener {
     666        public void actionPerformed(ActionEvent event) {
     667        String n = name.getText();
     668        String s = null;
     669        Object o = source.getSelectedItem();
     670        if(o instanceof ElementWrapper) {
     671            ElementWrapper e = (ElementWrapper)o;
     672            s = e.toString();
     673        }
     674        String e = match.getText();
     675        String f = flags.getText();
     676        if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
     677            Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
     678            addSubcollection(sub);
     679        }
     680        changed = false;
     681        }
     682    }
     683    /** Listens for actions apon the 'add subindex' button in the SubcollectionManager controls, and if detected calls the addSubindex method of the manager with a newly created subindex. */
     684    private class AddSubIndexListener
     685        implements ActionListener {
    686686                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a series of subcollections selected, and if so build an new subindex based apon them.
    687687                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    688688                 * @see org.greenstone.gatherer.cdm.SubIndex
    689689                 */
    690                 public void actionPerformed(ActionEvent event) {
    691                      if(!subcollection_list_2.isSelectionEmpty()) {
    692                           Vector selected = new Vector();
    693                           Object raw[] = subcollection_list_2.getSelectedValues();
    694                           for(int i = 0; i < raw.length; i++) {
    695                                 selected.add(raw[i]);
    696                           }
    697                           addSubIndex(new SubIndex(selected));
    698                      }
    699                 }
    700           }
    701           /** This class listens for any key entry in a text field, selection change in a combobox or button click, and when detected sets the changed flag to true. Its also convenient to use this class to test if the add button should be active yet. */
    702           public class ChangeListener
    703                 extends KeyAdapter
    704                 implements ActionListener {
     690        public void actionPerformed(ActionEvent event) {
     691        if(!subcollection_list_2.isSelectionEmpty()) {
     692            Vector selected = new Vector();
     693            Object raw[] = subcollection_list_2.getSelectedValues();
     694            for(int i = 0; i < raw.length; i++) {
     695            selected.add(raw[i]);
     696            }
     697            addSubIndex(new SubIndex(selected));
     698        }
     699        }
     700    }
     701    /** This class listens for any key entry in a text field, selection change in a combobox or button click, and when detected sets the changed flag to true. Its also convenient to use this class to test if the add button should be active yet. */
     702    public class ChangeListener
     703        extends KeyAdapter
     704        implements ActionListener {
    705705                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to record that somethings changed, then validate the controls.
    706706                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    707707                 */
    708                 public void actionPerformed(ActionEvent event) {
    709                      changed = true;
    710                      validate();
    711                 }
     708        public void actionPerformed(ActionEvent event) {
     709        changed = true;
     710        validate();
     711        }
    712712                /** Any inheritor of KeyAdapter can override this method so we can be informed when an key has been type in one of our target controls. In this case we want to record that somethings changed, then validate the controls.
    713713                 * @param event An <strong>KeyEvent</strong> containing information about the event.
    714714                 */
    715                 public void keyPressed(KeyEvent event) {
    716                      changed = true;
    717                      validate();
    718                 }
     715        public void keyPressed(KeyEvent event) {
     716        changed = true;
     717        validate();
     718        }
    719719                /** Method to validate the current editor values, and enable or disable controls based on said values. */
    720                 private void validate() {
    721                      if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
    722                           add.setEnabled(true);
    723                      }
    724                      else {
    725                           add.setEnabled(false);
    726                      }
    727                 }
    728           }
    729           /** Listens for actions apon the 'clear default subindex' button in the SubcollectionManager controls, and if detected calls the setDefaultSubIndex() method of the manager with <i>null</i>. */
    730           private class ClearDefaultListener
    731                 implements ActionListener {
     720        private void validate() {
     721        if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
     722            add.setEnabled(true);
     723        }
     724        else {
     725            add.setEnabled(false);
     726        }
     727        }
     728    }
     729    /** Listens for actions apon the 'clear default subindex' button in the SubcollectionManager controls, and if detected calls the setDefaultSubIndex() method of the manager with <i>null</i>. */
     730    private class ClearDefaultListener
     731        implements ActionListener {
    732732                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to clear the default subindex.
    733733                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    734734                 */
    735                 public void actionPerformed(ActionEvent event) {
    736                      setDefaultSubIndex(null);
    737                      clear_default.setEnabled(false);
    738                      default_value.setText("");
    739                 }
    740           }
    741           /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
    742           private class ListListener
    743                 implements ListSelectionListener {
     735        public void actionPerformed(ActionEvent event) {
     736        setDefaultSubIndex(null);
     737        clear_default.setEnabled(false);
     738        default_value.setText("");
     739        }
     740    }
     741    /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
     742    private class ListListener
     743        implements ListSelectionListener {
    744744                /** Any implementation of ListSelectionListener must include this method so we can be informed when the selection changes. In this case we want to execute any changes the users made to the entry, then update the controls with details of the new selection.
    745745                 * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
     
    747747                 * @see org.greenstone.gatherer.msm.ElementWrapper
    748748                 */
    749                 public void valueChanged(ListSelectionEvent event) {
    750                      // If we have a previous collection and the users changed something, but not added, then update subcollection.
    751                      if(changed && current != null) {
    752                           String n = name.getText();
    753                           String s = null;
    754                           Object o = source.getSelectedItem();
    755                           if(o instanceof ElementWrapper) {
    756                                 ElementWrapper e = (ElementWrapper)o;
    757                                 s = e.toString();
    758                           }
    759                           String e = match.getText();
    760                           String f = flags.getText();
    761                           if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
    762                                 current.update(n, s, e, include.isSelected(), f);
    763                                 int index = model.indexOf(current);
    764                                 changed();
    765                                 subindexes.changed();
    766                                 if(default_index != null) {
    767                                     default_value.setText(default_index.getSubIndex().toString());
    768                                 }
    769                           }
    770                      }
    771                      // Now load the new entry.
    772                      if(!subcollection_list.isSelectionEmpty()) {
    773                           current = (Subcollection) subcollection_list.getSelectedValue();
    774                           flags.setText(current.getFlags());
    775                           include.setSelected(current.getInclude());
    776                           exclude.setSelected(!current.getInclude());
    777                           match.setText(current.getExpression());
    778                           name.setText(current.getName());
    779                           String s = current.getSource();
    780                           int pos = 0;
    781                           Object value = source.getItemAt(pos);
    782                           while(value != null) {
    783                                 if(value instanceof ElementWrapper) {
    784                                     ElementWrapper e = (ElementWrapper) value;
    785                                     if(e.toString().equals(s)) {
    786                                           source.setSelectedIndex(pos);
    787                                           value = null;
    788                                     }
    789                                     else {
    790                                           pos++;
    791                                           value = source.getItemAt(pos);
    792                                     }
    793                                 }
    794                                 else if(value.toString().equals(s)) {
    795                                     source.setSelectedIndex(pos);
    796                                     value = null;
    797                                 }
    798                                 else {
    799                                     pos++;
    800                                     value = source.getItemAt(pos);
    801                                 }
    802                           }
    803                           // Can't add one thats already there.
    804                           add.setEnabled(false);
    805                           // You can remove it though...
    806                           remove.setEnabled(true);
    807                      }
    808                      else {
    809                           flags.setText("");
    810                           include.setSelected(true);
    811                           match.setText("");
    812                           name.setText("");
    813                           source.setSelectedIndex(0);
    814                           remove.setEnabled(false);
    815                      }
    816                      // Have to do this after so we don't get called when nothings actually changed.
    817                      changed = false;
    818                 }
    819           }
    820           /** Listens for actions apon the 'remove' button in the SubcollectionManager controls, and if detected calls the remove method of the manager with the SubIndex selected for removal. */
    821           private class RemoveListener
    822                 implements ActionListener {
     749        public void valueChanged(ListSelectionEvent event) {
     750        // If we have a previous collection and the users changed something, but not added, then update subcollection.
     751        if(changed && current != null) {
     752            String n = name.getText();
     753            String s = null;
     754            Object o = source.getSelectedItem();
     755            if(o instanceof ElementWrapper) {
     756            ElementWrapper e = (ElementWrapper)o;
     757            s = e.toString();
     758            }
     759            String e = match.getText();
     760            String f = flags.getText();
     761            if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
     762            current.update(n, s, e, include.isSelected(), f);
     763            int index = model.indexOf(current);
     764            changed();
     765            subindexes.changed();
     766            if(default_index != null) {
     767                default_value.setText(default_index.getSubIndex().toString());
     768            }
     769            }
     770        }
     771        // Now load the new entry.
     772        if(!subcollection_list.isSelectionEmpty()) {
     773            current = (Subcollection) subcollection_list.getSelectedValue();
     774            flags.setText(current.getFlags());
     775            include.setSelected(current.getInclude());
     776            exclude.setSelected(!current.getInclude());
     777            match.setText(current.getExpression());
     778            name.setText(current.getName());
     779            String s = current.getSource();
     780            int pos = 0;
     781            Object value = source.getItemAt(pos);
     782            while(value != null) {
     783            if(value instanceof ElementWrapper) {
     784                ElementWrapper e = (ElementWrapper) value;
     785                if(e.toString().equals(s)) {
     786                source.setSelectedIndex(pos);
     787                value = null;
     788                }
     789                else {
     790                pos++;
     791                value = source.getItemAt(pos);
     792                }
     793            }
     794            else if(value.toString().equals(s)) {
     795                source.setSelectedIndex(pos);
     796                value = null;
     797            }
     798            else {
     799                pos++;
     800                value = source.getItemAt(pos);
     801            }
     802            }
     803            // Can't add one thats already there.
     804            add.setEnabled(false);
     805            // You can remove it though...
     806            remove.setEnabled(true);
     807        }
     808        else {
     809            flags.setText("");
     810            include.setSelected(true);
     811            match.setText("");
     812            name.setText("");
     813            source.setSelectedIndex(0);
     814            remove.setEnabled(false);
     815        }
     816        // Have to do this after so we don't get called when nothings actually changed.
     817        changed = false;
     818        }
     819    }
     820    /** Listens for actions apon the 'remove' button in the SubcollectionManager controls, and if detected calls the remove method of the manager with the SubIndex selected for removal. */
     821    private class RemoveListener
     822        implements ActionListener {
    823823                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subcolleciton selected, and if so remove both it and any subindexes based on it.
    824824                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    825825                 * @see org.greenstone.gatherer.cdm.Subcollection
    826826                 */
    827                 public void actionPerformed(ActionEvent event) {
    828                      if(!subcollection_list.isSelectionEmpty()) {
    829                           Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
    830                           removeSubIndexes(sub_col);
    831                           removeSubcollection(sub_col);
    832                      }
    833                 }
    834           }
    835           /** Listens for actions apon the 'remove subindex' button in the SubcollectionManager controls, and if detected calls the removeSubIndex method of the manager with the SubIndex selected for removal. */
    836           private class RemoveSubIndexListener
    837                 implements ActionListener {
     827        public void actionPerformed(ActionEvent event) {
     828        if(!subcollection_list.isSelectionEmpty()) {
     829            Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
     830            removeSubIndexes(sub_col);
     831            removeSubcollection(sub_col);
     832        }
     833        }
     834    }
     835    /** Listens for actions apon the 'remove subindex' button in the SubcollectionManager controls, and if detected calls the removeSubIndex method of the manager with the SubIndex selected for removal. */
     836    private class RemoveSubIndexListener
     837        implements ActionListener {
    838838                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subindex selected, and if so remove it.
    839839                 * @param event An <strong>ActionEvent</strong> containing information about the event.
    840840                 * @see org.greenstone.gatherer.cdm.SubIndex
    841841                 */
    842                 public void actionPerformed(ActionEvent event) {
    843                      if(!subindexes_list.isSelectionEmpty()) {
    844                           removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
    845                      }
    846                 }
    847           }
    848           /** Listens for actions apon the 'set default subindex' button in the SubcollectionManager controls, and if detected calls the setDefaultSubIndex method of the manager with the SubIndex selected for default. */
    849           private class SetDefaultListener
    850                 implements ActionListener {
     842        public void actionPerformed(ActionEvent event) {
     843        if(!subindexes_list.isSelectionEmpty()) {
     844            removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
     845        }
     846        }
     847    }
     848    /** Listens for actions apon the 'set default subindex' button in the SubcollectionManager controls, and if detected calls the setDefaultSubIndex method of the manager with the SubIndex selected for default. */
     849    private class SetDefaultListener
     850        implements ActionListener {
    851851                /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subindex selected, and if so set it as default.
    852852                 * @param event An <strong>ActionEvent</strong> containing information about the event.
     
    854854                 * @see org.greenstone.gatherer.cdm.SubIndex
    855855                 */
    856                 public void actionPerformed(ActionEvent event) {
    857                      if(!subindexes_list.isSelectionEmpty()) {
    858                           setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
    859                           clear_default.setEnabled(true);
    860                           default_value.setText(default_index.getSubIndex().toString());
    861                      }
    862                 }
    863           }
    864     }
     856        public void actionPerformed(ActionEvent event) {
     857        if(!subindexes_list.isSelectionEmpty()) {
     858            setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
     859            clear_default.setEnabled(true);
     860            default_value.setText(default_index.getSubIndex().toString());
     861        }
     862        }
     863    }
     864    }
    865865}
    866866
  • trunk/gli/src/org/greenstone/gatherer/cdm/TranslationManager.java

    r4293 r4366  
    8787import org.greenstone.gatherer.cdm.LanguageManager;
    8888/** This class provides a graphical interface to allow a user to quickly and conviently (ie all in one place) translate the text fragments associated with general metadata and indexes into each of the assigned languages in the collection. It should provide clear controls for the editing of these text fragments, plus clear indicate what languages still need further translation, which it will do through a combination of coloring and other visual indicators.
    89 * @author John Thompson, Greenstone Digital Library, University of Waikato
    90 * @version 2.3
    91 */
     89 * @author John Thompson, Greenstone Digital Library, University of Waikato
     90 * @version 2.3
     91 */
    9292public class TranslationManager
    93     extends JDialog {
    94     /** A reference to our creator, the CollectionDesignManager. */
    95     private CollectionDesignManager manager = null;
    96     /** The currently selected collection metadata. */
    97     private CollectionMeta current = null;
    98     /** A listener for selection changes in the feature list. */
    99     private FeatureListener features_listener = null;
    100     /** A reference to the Gatherer, for access to the Dictionary and messaging purposes. */
    101     private Gatherer gatherer = null;
    102     /** The button used to close the translation dialog. */
    103     private JButton close_button = null;
    104     /** A reference to the dialog so that our inner classes can interact with it. */
    105     private JDialog dialog = null;
    106     /** The label denoting the features list. */
    107     private JLabel features_label = null;
    108     /** The label denoting the language table. */
    109     private JLabel languages_label = null;
    110     /** The label denoting the original text area. */
    111     private JLabel original_label = null;
    112     /** The label denoting the original language field */
    113     private JLabel original_language_label = null;
    114     /** The label denoting the translated text area. */
    115     private JLabel translation_label = null;
    116     /** The label denoting the translated language field. */
    117     private JLabel translation_language_label = null;
    118     /** A list of the various features that have collection metadata associated with them. */
    119     private JList features_list = null;
    120     /** The base panel. */
    121     private JPanel content_pane = null;
    122     /** The right panel. */
    123     private JPanel control_pane = null;
    124     /** The panel the features list is shown in. */
    125     private JPanel features_pane = null;
    126     /** The panel the languages table is shown in. */
    127     private JPanel languages_pane = null;
    128     /** The panel the original text is shown in. */
    129     private JPanel original_pane = null;
    130     /** The panel the original language field is shown in. */
    131     private JPanel original_header_pane = null;
    132     /** The panel the translation text is shown in. */
    133     private JPanel translation_pane = null;
    134     /** The panel the translation language field is shown in. */
    135     private JPanel translation_header_pane = null;
    136     /** The table used to show the languages supported by the collection. */
    137     private JTable languages_table = null;
    138     /** The text area displaying the original text (in the default language). */
    139     private JTextArea original = null;
    140     /** The text area displaying the translated text (in the selected language). */
    141     private JTextArea translation = null;
    142     /** The language currently selected. */
    143     private Language current_language = null;
    144     /** The proxy model to the language manager which serves as the basis for the table. */
    145     private TableProxy languages_model = null;
    146     /** The default size of the features list. */
    147     static final private Dimension FEATURE_SIZE = new Dimension(200, 400);
    148     /** The default size of the translation dialog. */
    149     static final private Dimension SIZE = new Dimension(800, 450);
    150     /** Constructor.
    151     * @param gatherer A reference to the <strong>Gatherer</strong>.
    152     * @param manager A reference to the <strong>CollectionDesignManager</strong>.
    153     * @see org.greenstone.gatherer.Configuration
    154     * @see org.greenstone.gatherer.cdm.CollectionMeta
    155     * @see org.greenstone.gatherer.cdm.TranslationManager.TableProxy
    156     */
    157     public TranslationManager(Gatherer gatherer, CollectionDesignManager manager) {
    158           super();
    159           this.dialog = this;
    160           this.gatherer = gatherer;
    161           this.manager = manager;
    162           this.languages_model = new TableProxy();
    163           // Create the features model. Basically we want one string entry for each unique name in the metadata.
    164           ArrayList features_model = new ArrayList();
    165           for(int i = 0; i < manager.collectionmetadatum.size(); i++) {
    166                 CollectionMeta metadata = (CollectionMeta) manager.collectionmetadatum.get(i);
    167                 Object object = metadata.getName();
    168                 String name = null;
    169                 if(object instanceof Index) {
    170                      name = ((Index)object).toString(false);
    171                 }
    172                 else {
    173                      name = object.toString();
    174                 }
    175                 if(!features_model.contains(name)) {
    176                      features_model.add(name);
    177                 }
    178           }
    179           Collections.sort(features_model);
    180           // Create components...
    181           setModal(true);
    182           setSize(SIZE);
    183           close_button = new JButton(get("General.Close"));
    184           content_pane = (JPanel) getContentPane();
    185           control_pane = new JPanel();
    186           features_label = new JLabel(get("Affected_Features"));
    187           features_label.setHorizontalAlignment(JLabel.CENTER);
    188           features_list = new JList(features_model.toArray());
    189           features_listener = new FeatureListener();
    190           features_pane = new JPanel();
    191           features_pane.setPreferredSize(FEATURE_SIZE);
    192           languages_table = new JTable(languages_model);
    193           languages_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    194           languages_label = new JLabel(get("Assigned_Languages"));
    195           languages_label.setHorizontalAlignment(JLabel.CENTER);
    196           languages_pane = new JPanel();
    197           original = new JTextArea();
    198           original.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    199           original.setEditable(false);
    200           original.setFont(new Font("Arial Unicode MS", Font.PLAIN, 10));
    201           original_header_pane = new JPanel();
    202           original_label = new JLabel(get("Default_Text"));
    203           original_label.setHorizontalAlignment(JLabel.CENTER);
    204           original_language_label = new JLabel("");
    205           original_pane = new JPanel();
    206           translation = new JTextArea();
    207           translation.setEnabled(false);
    208           translation.setFont(new Font("Arial Unicode MS", Font.PLAIN, 10));
    209           translation_header_pane = new JPanel();
    210           translation_label = new JLabel(get("Translation"));
    211           translation_label.setHorizontalAlignment(JLabel.CENTER);
    212           translation_language_label = new JLabel("");
    213           translation_pane = new JPanel();
    214           // Add listeners...
    215           close_button.addActionListener(new CloseListener());
    216           translation.addKeyListener(new TranslationListener());
    217           features_list.addListSelectionListener(features_listener);
    218           features_list.addListSelectionListener(languages_model);
    219           ListSelectionModel languages_selection_model = languages_table.getSelectionModel();
    220           languages_selection_model.addListSelectionListener(new TableListener());
    221           // Layout...
    222           features_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    223           features_pane.setLayout(new BorderLayout());
    224           features_pane.add(features_label, BorderLayout.NORTH);
    225           features_pane.add(new JScrollPane(features_list), BorderLayout.CENTER);
    226           languages_label.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    227           languages_pane.setLayout(new BorderLayout());
    228           languages_pane.add(languages_label, BorderLayout.NORTH);
    229           languages_pane.add(new JScrollPane(languages_table), BorderLayout.CENTER);
    230           original_header_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    231           original_header_pane.setLayout(new BorderLayout());
    232           original_header_pane.add(original_label, BorderLayout.WEST);
    233           original_header_pane.add(original_language_label, BorderLayout.EAST);
    234           original_pane.setLayout(new BorderLayout());
    235           original_pane.add(original_header_pane, BorderLayout.NORTH);
    236           original_pane.add(new JScrollPane(original), BorderLayout.CENTER);
    237           translation_header_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
    238           translation_header_pane.setLayout(new BorderLayout());
    239           translation_header_pane.add(translation_label, BorderLayout.WEST);
    240           translation_header_pane.add(translation_language_label, BorderLayout.EAST);
    241           translation_pane.setLayout(new BorderLayout());
    242           translation_pane.add(translation_header_pane, BorderLayout.NORTH);
    243           translation_pane.add(new JScrollPane(translation), BorderLayout.CENTER);
    244           control_pane.setLayout(new GridLayout(3,1));
    245           control_pane.add(languages_pane);
    246           control_pane.add(original_pane);
    247           control_pane.add(translation_pane);
    248           content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    249           content_pane.setLayout(new BorderLayout());
    250           content_pane.add(features_pane, BorderLayout.WEST);
    251           content_pane.add(control_pane, BorderLayout.CENTER);
    252           content_pane.add(close_button, BorderLayout.SOUTH);
    253           // Display...
    254           Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
    255           for (int i = 0; i < languages_model.getColumnCount() - 1; i++) {
    256                 TableColumn column = languages_table.getColumnModel().getColumn(i);
    257                 column.setMinWidth(0);
    258                 column.setMaxWidth(screen_size.width);
    259                 column.setPreferredWidth((SIZE.width - FEATURE_SIZE.width) / 6);
    260           }
    261           setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
    262           show();
    263     }
    264     /** Destructor
     93    extends JDialog {
     94    /** A reference to our creator, the CollectionDesignManager. */
     95    private CollectionDesignManager manager = null;
     96    /** The currently selected collection metadata. */
     97    private CollectionMeta current = null;
     98    /** A listener for selection changes in the feature list. */
     99    private FeatureListener features_listener = null;
     100    /** A reference to the Gatherer, for access to the Dictionary and messaging purposes. */
     101    private Gatherer gatherer = null;
     102    /** The button used to close the translation dialog. */
     103    private JButton close_button = null;
     104    /** A reference to the dialog so that our inner classes can interact with it. */
     105    private JDialog dialog = null;
     106    /** The label denoting the features list. */
     107    private JLabel features_label = null;
     108    /** The label denoting the language table. */
     109    private JLabel languages_label = null;
     110    /** The label denoting the original text area. */
     111    private JLabel original_label = null;
     112    /** The label denoting the original language field */
     113    private JLabel original_language_label = null;
     114    /** The label denoting the translated text area. */
     115    private JLabel translation_label = null;
     116    /** The label denoting the translated language field. */
     117    private JLabel translation_language_label = null;
     118    /** A list of the various features that have collection metadata associated with them. */
     119    private JList features_list = null;
     120    /** The base panel. */
     121    private JPanel content_pane = null;
     122    /** The right panel. */
     123    private JPanel control_pane = null;
     124    /** The panel the features list is shown in. */
     125    private JPanel features_pane = null;
     126    /** The panel the languages table is shown in. */
     127    private JPanel languages_pane = null;
     128    /** The panel the original text is shown in. */
     129    private JPanel original_pane = null;
     130    /** The panel the original language field is shown in. */
     131    private JPanel original_header_pane = null;
     132    /** The panel the translation text is shown in. */
     133    private JPanel translation_pane = null;
     134    /** The panel the translation language field is shown in. */
     135    private JPanel translation_header_pane = null;
     136    /** The table used to show the languages supported by the collection. */
     137    private JTable languages_table = null;
     138    /** The text area displaying the original text (in the default language). */
     139    private JTextArea original = null;
     140    /** The text area displaying the translated text (in the selected language). */
     141    private JTextArea translation = null;
     142    /** The language currently selected. */
     143    private Language current_language = null;
     144    /** The proxy model to the language manager which serves as the basis for the table. */
     145    private TableProxy languages_model = null;
     146    /** The default size of the features list. */
     147    static final private Dimension FEATURE_SIZE = new Dimension(200, 400);
     148    /** The default size of the translation dialog. */
     149    static final private Dimension SIZE = new Dimension(800, 450);
     150    /** Constructor.
     151     * @param gatherer A reference to the <strong>Gatherer</strong>.
     152     * @param manager A reference to the <strong>CollectionDesignManager</strong>.
     153     * @see org.greenstone.gatherer.Configuration
     154     * @see org.greenstone.gatherer.cdm.CollectionMeta
     155     * @see org.greenstone.gatherer.cdm.TranslationManager.TableProxy
     156     */
     157    public TranslationManager(Gatherer gatherer, CollectionDesignManager manager) {
     158    super();
     159    this.dialog = this;
     160    this.gatherer = gatherer;
     161    this.manager = manager;
     162    this.languages_model = new TableProxy();
     163    // Create the features model. Basically we want one string entry for each unique name in the metadata.
     164    ArrayList features_model = new ArrayList();
     165    for(int i = 0; i < manager.collectionmetadatum.size(); i++) {
     166        CollectionMeta metadata = (CollectionMeta) manager.collectionmetadatum.get(i);
     167        Object object = metadata.getName();
     168        String name = null;
     169        if(object instanceof Index) {
     170        name = ((Index)object).toString(false);
     171        }
     172        else {
     173        name = object.toString();
     174        }
     175        if(!features_model.contains(name)) {
     176        features_model.add(name);
     177        }
     178    }
     179    Collections.sort(features_model);
     180    // Create components...
     181    setModal(true);
     182    setSize(SIZE);
     183    close_button = new JButton(get("General.Close"));
     184    content_pane = (JPanel) getContentPane();
     185    control_pane = new JPanel();
     186    features_label = new JLabel(get("Affected_Features"));
     187    features_label.setHorizontalAlignment(JLabel.CENTER);
     188    features_list = new JList(features_model.toArray());
     189    features_listener = new FeatureListener();
     190    features_pane = new JPanel();
     191    features_pane.setPreferredSize(FEATURE_SIZE);
     192    languages_table = new JTable(languages_model);
     193    languages_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     194    languages_label = new JLabel(get("Assigned_Languages"));
     195    languages_label.setHorizontalAlignment(JLabel.CENTER);
     196    languages_pane = new JPanel();
     197    original = new JTextArea();
     198    original.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     199    original.setEditable(false);
     200    original.setFont(new Font("Arial Unicode MS", Font.PLAIN, 10));
     201    original_header_pane = new JPanel();
     202    original_label = new JLabel(get("Default_Text"));
     203    original_label.setHorizontalAlignment(JLabel.CENTER);
     204    original_language_label = new JLabel("");
     205    original_pane = new JPanel();
     206    translation = new JTextArea();
     207    translation.setEnabled(false);
     208    translation.setFont(new Font("Arial Unicode MS", Font.PLAIN, 10));
     209    translation_header_pane = new JPanel();
     210    translation_label = new JLabel(get("Translation"));
     211    translation_label.setHorizontalAlignment(JLabel.CENTER);
     212    translation_language_label = new JLabel("");
     213    translation_pane = new JPanel();
     214    // Add listeners...
     215    close_button.addActionListener(new CloseListener());
     216    translation.addKeyListener(new TranslationListener());
     217    features_list.addListSelectionListener(features_listener);
     218    features_list.addListSelectionListener(languages_model);
     219    ListSelectionModel languages_selection_model = languages_table.getSelectionModel();
     220    languages_selection_model.addListSelectionListener(new TableListener());
     221    // Layout...
     222    features_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     223    features_pane.setLayout(new BorderLayout());
     224    features_pane.add(features_label, BorderLayout.NORTH);
     225    features_pane.add(new JScrollPane(features_list), BorderLayout.CENTER);
     226    languages_label.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     227    languages_pane.setLayout(new BorderLayout());
     228    languages_pane.add(languages_label, BorderLayout.NORTH);
     229    languages_pane.add(new JScrollPane(languages_table), BorderLayout.CENTER);
     230    original_header_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     231    original_header_pane.setLayout(new BorderLayout());
     232    original_header_pane.add(original_label, BorderLayout.WEST);
     233    original_header_pane.add(original_language_label, BorderLayout.EAST);
     234    original_pane.setLayout(new BorderLayout());
     235    original_pane.add(original_header_pane, BorderLayout.NORTH);
     236    original_pane.add(new JScrollPane(original), BorderLayout.CENTER);
     237    translation_header_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     238    translation_header_pane.setLayout(new BorderLayout());
     239    translation_header_pane.add(translation_label, BorderLayout.WEST);
     240    translation_header_pane.add(translation_language_label, BorderLayout.EAST);
     241    translation_pane.setLayout(new BorderLayout());
     242    translation_pane.add(translation_header_pane, BorderLayout.NORTH);
     243    translation_pane.add(new JScrollPane(translation), BorderLayout.CENTER);
     244    control_pane.setLayout(new GridLayout(3,1));
     245    control_pane.add(languages_pane);
     246    control_pane.add(original_pane);
     247    control_pane.add(translation_pane);
     248    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     249    content_pane.setLayout(new BorderLayout());
     250    content_pane.add(features_pane, BorderLayout.WEST);
     251    content_pane.add(control_pane, BorderLayout.CENTER);
     252    content_pane.add(close_button, BorderLayout.SOUTH);
     253    // Display...
     254    Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
     255    for (int i = 0; i < languages_model.getColumnCount() - 1; i++) {
     256        TableColumn column = languages_table.getColumnModel().getColumn(i);
     257        column.setMinWidth(0);
     258        column.setMaxWidth(screen_size.width);
     259        column.setPreferredWidth((SIZE.width - FEATURE_SIZE.width) / 6);
     260    }
     261    setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
     262    show();
     263    }
     264    /** Destructor
    265265      */
    266     public void destroy() {
    267           dialog = null;
    268     }
    269     /** Retrieve a phrase from the dictionary based on a certain key.
     266    public void destroy() {
     267    dialog = null;
     268    }
     269    /** Retrieve a phrase from the dictionary based on a certain key.
    270270      * @param key The search <strong>String</strong>.
    271271      * @return The matching phrase from the Dictionary as a <strong>String</strong>.
    272272      */
    273     private String get(String key) {
    274           return get(key, null);
    275     }
    276     /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
     273    private String get(String key) {
     274    return get(key, null);
     275    }
     276    /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
    277277      * @param key The search <strong>String</strong>.
    278278      * @param args A <strong>String[]</strong> used to complete and format the returned phrase.
     
    281281      * @see org.greenstone.gatherer.Gatherer
    282282      */
    283     private String get(String key, String args[]) {
    284           if(key.indexOf(".") == -1) {
    285                 key = "CDM.TranslationManager." + key;
    286           }
    287           return gatherer.dictionary.get(key, args);
    288     }
    289     /** Listens for actions apon the close button. */
    290     private class CloseListener
    291           implements ActionListener {
    292           /** Closes the dialog. Any implementation of an ActionListener must include this method so we can be informed when an action has occured.
    293             * @param event An <Strong>ActionEvent</strong> containing details about the action.
    294             */
    295           public void actionPerformed(ActionEvent event) {
    296                 dialog.dispose();
    297           }
    298     }
    299     /** Listens to selections within the feature list. */
    300     private class FeatureListener
    301           implements ListSelectionListener {
    302         /** Called whenever the selection changes in the registered list, which requires us to create a new TableProxy.
    303         * @param event A <strong>ListSelectionEvent</strong> containing more information about the list selection change.
    304         * @see org.greenstone.gatherer.cdm.CollectionMeta
    305         * @see org.greenstone.gatherer.cdm.Language
    306         */
    307           public void valueChanged(ListSelectionEvent event) {
     283    private String get(String key, String args[]) {
     284    if(key.indexOf(".") == -1) {
     285        key = "CDM.TranslationManager." + key;
     286    }
     287    return gatherer.dictionary.get(key, args);
     288    }
     289    /** Listens for actions apon the close button. */
     290    private class CloseListener
     291    implements ActionListener {
     292    /** Closes the dialog. Any implementation of an ActionListener must include this method so we can be informed when an action has occured.
     293     * @param event An <Strong>ActionEvent</strong> containing details about the action.
     294            */
     295    public void actionPerformed(ActionEvent event) {
     296        dialog.dispose();
     297    }
     298    }
     299    /** Listens to selections within the feature list. */
     300    private class FeatureListener
     301    implements ListSelectionListener {
     302    /** Called whenever the selection changes in the registered list, which requires us to create a new TableProxy.
     303     * @param event A <strong>ListSelectionEvent</strong> containing more information about the list selection change.
     304     * @see org.greenstone.gatherer.cdm.CollectionMeta
     305     * @see org.greenstone.gatherer.cdm.Language
     306     */
     307    public void valueChanged(ListSelectionEvent event) {
    308308                // Try to find the default language value for this feature.
    309                 String name = (String) features_list.getSelectedValue();
    310                 Language language = manager.languages.getDefaultLanguage();
    311                 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(name, language, true);
    312                 if(metadata != null && metadata.getValue() != null && metadata.getValue().length() != 0) {
    313                      if(!metadata.getLanguage().equals(language)) {
    314                           original_label.setText(get("Existing_Text"));
    315                      }
    316                      else {
    317                           original_label.setText(get("Default_Text"));
    318                      }
    319                      original.setText(metadata.getValue());
    320                      original_language_label.setText(metadata.getLanguage().toString());
    321                 }
    322                 else {
    323                      original_label.setText(get("No_Text"));
    324                      original.setText("");
    325                 }
    326           }
    327     }
    328     /** Listens for selections within the languages table. */
    329     private class TableListener
    330           implements ListSelectionListener {
    331         /** Called whenever the selection changes in the registered list, which requires us to update several parts of the dialog.
    332         * @param event A <strong>ListSelectionEvent</strong> containing more information about the list selection change.
    333         * @see org.greenstone.gatherer.cdm.CollectionMeta
    334         * @see org.greenstone.gatherer.cdm.Language
    335         */
    336           public void valueChanged(ListSelectionEvent event) {
    337                 if (event.getValueIsAdjusting()) return;
    338                 ListSelectionModel lsm = (ListSelectionModel)event.getSource();
    339                 if (!lsm.isSelectionEmpty()) {
    340                      int row = lsm.getMinSelectionIndex();
    341                      current = languages_model.getMetadata(row);
    342                      if(current != null) {
    343                           if (current.getValue() != null) {
    344                                 translation.setText(current.getValue());
    345                           }
    346                           else {
    347                                 translation.setText("");
    348                           }
    349                           current_language = current.getLanguage();
    350                      }
    351                      else {
    352                           current_language = (Language) languages_model.getValueAt(row, 1);
    353                           translation.setText("");
    354                      }
    355                      features_listener.valueChanged(null);
    356                      translation_language_label.setText(current_language.toString());
    357                      translation.setEnabled(true);
    358                 }
    359           }
    360     }
    361     /** A AbstractTableModel extension based upon a vector of CollectionMeta, which can also listen to a list for selection changes. */
    362     private class TableProxy
    363           extends AbstractTableModel
    364           implements ListSelectionListener {
    365             /** Called when the contents of a cell changes.
    366             */
    367           public void cellChanged() {
    368                 fireTableDataChanged();
    369           }
    370           /** Returns the most specific superclass for all the cell values in the column.
     309        String name = (String) features_list.getSelectedValue();
     310        Language language = manager.languages.getDefaultLanguage();
     311        CollectionMeta metadata = manager.collectionmetadatum.getMetadata(name, language, true);
     312        if(metadata != null && metadata.getValue() != null && metadata.getValue().length() != 0) {
     313        if(!metadata.getLanguage().equals(language)) {
     314            original_label.setText(get("Existing_Text"));
     315        }
     316        else {
     317            original_label.setText(get("Default_Text"));
     318        }
     319        original.setText(metadata.getValue());
     320        original_language_label.setText(metadata.getLanguage().toString());
     321        }
     322        else {
     323        original_label.setText(get("No_Text"));
     324        original.setText("");
     325        }
     326    }
     327    }
     328    /** Listens for selections within the languages table. */
     329    private class TableListener
     330    implements ListSelectionListener {
     331    /** Called whenever the selection changes in the registered list, which requires us to update several parts of the dialog.
     332     * @param event A <strong>ListSelectionEvent</strong> containing more information about the list selection change.
     333     * @see org.greenstone.gatherer.cdm.CollectionMeta
     334     * @see org.greenstone.gatherer.cdm.Language
     335     */
     336    public void valueChanged(ListSelectionEvent event) {
     337        if (event.getValueIsAdjusting()) return;
     338        ListSelectionModel lsm = (ListSelectionModel)event.getSource();
     339        if (!lsm.isSelectionEmpty()) {
     340        int row = lsm.getMinSelectionIndex();
     341        current = languages_model.getMetadata(row);
     342        if(current != null) {
     343            if (current.getValue() != null) {
     344            translation.setText(current.getValue());
     345            }
     346            else {
     347            translation.setText("");
     348            }
     349            current_language = current.getLanguage();
     350        }
     351        else {
     352            current_language = (Language) languages_model.getValueAt(row, 1);
     353            translation.setText("");
     354        }
     355        features_listener.valueChanged(null);
     356        translation_language_label.setText(current_language.toString());
     357        translation.setEnabled(true);
     358        }
     359    }
     360    }
     361    /** A AbstractTableModel extension based upon a vector of CollectionMeta, which can also listen to a list for selection changes. */
     362    private class TableProxy
     363    extends AbstractTableModel
     364    implements ListSelectionListener {
     365    /** Called when the contents of a cell changes.
     366     */
     367    public void cellChanged() {
     368        fireTableDataChanged();
     369    }
     370    /** Returns the most specific superclass for all the cell values in the column.
    371371            * @param column An <i>int</i> specifying which columns class to be determined.
    372372            * @return The columns <strong>Class</strong>.
    373373            */
    374374        public Class getColumnClass(int column) {
    375                 return String.class;
    376           }
    377           /** Returns the number of columns in the model.
     375        return String.class;
     376    }
     377    /** Returns the number of columns in the model.
    378378            * @return An <i>int</i> specifying the number of columns.
    379379            */
    380           public int getColumnCount() {
    381                 if(!features_list.isSelectionEmpty()) {
    382                      return 2;
    383                 }
    384                 return 0;
    385           }
     380    public int getColumnCount() {
     381        if(!features_list.isSelectionEmpty()) {
     382        return 2;
     383        }
     384        return 0;
     385    }
    386386        /** Returns the name of the column at columnIndex.
    387387            * @param column An <i>int</i> specifying the column whose name you are interesting in.
    388388            * @return The name of the column as a <strong>String</strong>.
    389389            */
    390           public String getColumnName(int column) {
    391                 String name = null;
    392                 switch(column) {
    393                 case 0:
    394                      name = get("Language");
    395                      break;
    396                 case 1:
    397                      name = get("Text");
    398                      break;
    399                 }
    400                 return name;
    401           }
    402           /** Retrieve the collection metadata from the specified row.
     390    public String getColumnName(int column) {
     391        String name = null;
     392        switch(column) {
     393        case 0:
     394        name = get("Language");
     395        break;
     396        case 1:
     397        name = get("Text");
     398        break;
     399        }
     400        return name;
     401    }
     402    /** Retrieve the collection metadata from the specified row.
    403403          * @param row An <i>int</i> indicating the row in question.
    404404          * @see org.greenstone.gatherer.cdm.Language
    405405          * @see org.greenstone.gatherer.cdm.LanguageManager
    406406          */
    407           public CollectionMeta getMetadata(int row) {
    408                 String name = (String) features_list.getSelectedValue();
    409                 Language language = (Language) getValueAt(row, 0);
    410                 return manager.collectionmetadatum.getMetadata(name, language, false);
    411           }
     407    public CollectionMeta getMetadata(int row) {
     408        String name = (String) features_list.getSelectedValue();
     409        Language language = (Language) getValueAt(row, 0);
     410        return manager.collectionmetadatum.getMetadata(name, language, false);
     411    }
    412412        /** Returns the number of rows in the model.
    413413            * @return An <i>int</i> specifying the number of rows in the table, which is exactly the number of languages assigned to this collection.
    414414            * @see org.greenstone.gatherer.cdm.LanguageManager
    415415            */
    416           public int getRowCount() {
    417                 return manager.languages.size();
    418           }
    419           /** Returns the value for the cell at column and row.
     416    public int getRowCount() {
     417        return manager.languages.size();
     418    }
     419    /** Returns the value for the cell at column and row.
    420420            * @param row The desired row as an <i>int</i>.
    421421            * @param column The desired column as an <i>int</i>.
     
    425425            * @see org.greenstone.gatherer.cdm.LanguageManager
    426426            */
    427           public Object getValueAt(int row, int column) {
    428                 if(!features_list.isSelectionEmpty()) {
    429                      // First of all find the Language that matches the row and the current feature name, because in any case you'll need them.
    430                      Language language = (Language)manager.languages.get(row);
    431                      String feature_name = (String)features_list.getSelectedValue();
    432                      // Also try to locate the collection level metadata that matches.
    433                      CollectionMeta metadata = manager.collectionmetadatum.getMetadata(feature_name, language, false);
    434                      // Now we do subtly different things depending on the column.
    435                      switch(column) {
    436                      case 0: // The Language. Easiest case.
    437                           return language;
    438                      case 1: // The value of the metadata. Needs us to retrieve the value for a certain feature and language.
    439                           if(metadata != null) {
    440                                 return metadata.getValue();
    441                           }
    442                      }
    443                      // If all else fails, return an empty string and hope the class caster doesn't explode.
    444                 }
    445                 return "";
    446           }
     427    public Object getValueAt(int row, int column) {
     428        if(!features_list.isSelectionEmpty()) {
     429        // First of all find the Language that matches the row and the current feature name, because in any case you'll need them.
     430        Language language = (Language)manager.languages.get(row);
     431        String feature_name = (String)features_list.getSelectedValue();
     432        // Also try to locate the collection level metadata that matches.
     433        CollectionMeta metadata = manager.collectionmetadatum.getMetadata(feature_name, language, false);
     434        // Now we do subtly different things depending on the column.
     435        switch(column) {
     436        case 0: // The Language. Easiest case.
     437            return language;
     438        case 1: // The value of the metadata. Needs us to retrieve the value for a certain feature and language.
     439            if(metadata != null) {
     440            return metadata.getValue();
     441            }
     442        }
     443        // If all else fails, return an empty string and hope the class caster doesn't explode.
     444        }
     445        return "";
     446    }
    447447        /** Returns true if the cell at row and column is editable.
    448448            * @param row The row of the cell as an <i>int</i>.
    449449            * @param column The column of the cell also as an <i>int</i>.
    450450            */
    451           public boolean isCellEditable(int rowIndex, int columnIndex) {
    452                 return false;
    453           }
     451    public boolean isCellEditable(int rowIndex, int columnIndex) {
     452        return false;
     453    }
    454454        /** Sets the value in the cell at columnIndex and rowIndex to aValue.
    455455            */
    456           public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    457           }
    458           /** Any implementation of <i>ListSelectionListener</i> must include this method so we can be informed when the list selection has changed.
     456    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
     457    }
     458    /** Any implementation of <i>ListSelectionListener</i> must include this method so we can be informed when the list selection has changed.
    459459            * @param event A <strong>ListSelectionEvent</strong> containing information about the selection change.
    460460            */
    461           public void valueChanged(ListSelectionEvent event) {
    462                 fireTableStructureChanged();
    463           }
    464     }
    465     /** This provides a custom renderer that colours the background of the default language cell green, and the foreground of currently unready metadata rows red. */
    466     private class TableRenderer
    467           extends DefaultTableCellRenderer {
    468           /** Retrieve the component used to rubberstamp the table based on the given parameters.
    469           * @param table The <strong>JTable</strong> to rendered.
    470           * @param value The <strong>Object</strong> whose representation will be shown in the table row.
    471           * @param isSelected <i>true</i> iff the column/row is selected.
    472           * @param hasFocus <i>true</i> iff the column/row is in focus.
    473           * @param row An <i>int</i> specifying the target row.
    474           * @param column An <i>int</i> specifying the target column.
    475           * @see org.greenstone.gatherer.cdm.Language
    476           */
    477           public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    478                 Component component = null;
     461    public void valueChanged(ListSelectionEvent event) {
     462        fireTableStructureChanged();
     463    }
     464    }
     465    /** This provides a custom renderer that colours the background of the default language cell green, and the foreground of currently unready metadata rows red. */
     466    private class TableRenderer
     467    extends DefaultTableCellRenderer {
     468    /** Retrieve the component used to rubberstamp the table based on the given parameters.
     469    * @param table The <strong>JTable</strong> to rendered.
     470    * @param value The <strong>Object</strong> whose representation will be shown in the table row.
     471    * @param isSelected <i>true</i> iff the column/row is selected.
     472    * @param hasFocus <i>true</i> iff the column/row is in focus.
     473    * @param row An <i>int</i> specifying the target row.
     474    * @param column An <i>int</i> specifying the target column.
     475    * @see org.greenstone.gatherer.cdm.Language
     476    */
     477    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     478        Component component = null;
    479479                // Create the component.
    480                 if(value instanceof String || value instanceof Language) {
    481                      JLabel label = new JLabel(value.toString());
    482                      label.setOpaque(true);
    483                      component = label;
    484                 }
    485                 else {
    486                      JCheckBox check = new JCheckBox("", ((Boolean)value).booleanValue());
    487                      JPanel pane = new JPanel(new BorderLayout());
    488                      pane.add(check, BorderLayout.CENTER);
    489                      component = pane;
    490                 }
     480        if(value instanceof String || value instanceof Language) {
     481        JLabel label = new JLabel(value.toString());
     482        label.setOpaque(true);
     483        component = label;
     484        }
     485        else {
     486        JCheckBox check = new JCheckBox("", ((Boolean)value).booleanValue());
     487        JPanel pane = new JPanel(new BorderLayout());
     488        pane.add(check, BorderLayout.CENTER);
     489        component = pane;
     490        }
    491491                // Check for default property
    492                 Language language = (Language)languages_model.getValueAt(row, 1);
    493                 if(language.isDefault()) {
    494                      if(isSelected) {
    495                           component.setBackground(Gatherer.config.getColor("coloring.collection_selection_background", false));
    496                      }
    497                      else {
    498                           component.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    499                      }
    500                 }
    501                 else {
    502                      if(isSelected) {
    503                           component.setBackground(table.getSelectionBackground());
    504                      }
    505                      else {
    506                           component.setForeground(Color.white);
    507                      }
    508                 }
     492        Language language = (Language)languages_model.getValueAt(row, 1);
     493        if(language.isDefault()) {
     494        if(isSelected) {
     495            component.setBackground(Gatherer.config.getColor("coloring.collection_selection_background", false));
     496        }
     497        else {
     498            component.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     499        }
     500        }
     501        else {
     502        if(isSelected) {
     503            component.setBackground(table.getSelectionBackground());
     504        }
     505        else {
     506            component.setForeground(Color.white);
     507        }
     508        }
    509509                // Check for readiness
    510                 Boolean ready = (Boolean)languages_model.getValueAt(row, 0);
    511                 if(!ready.booleanValue()) {
    512                      component.setForeground(Color.red);
    513                 }
    514                 else {
    515                      component.setForeground(Color.black);
    516                 }
    517                 return component;
    518           }
    519     }
    520     /** Listens for actions within the translation text field and immediately updates the collection metadata as necessary. */
    521     private class TranslationListener
    522           extends KeyAdapter {
    523          /** This method is called when a key has been released, and is perfect for us to synchronize the contents of the translation field with the collection metadata associated with the selected feature and language.
    524         * @param event A <strong>KeyEvent</strong> containing more detail about the key released.
    525         * @see org.greenstone.gatherer.cdm.CollectionMeta
    526         * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    527         * @see org.greenstone.gatherer.cdm.Index
    528         */
    529           public void keyReleased(KeyEvent event) {
    530                 if(current == null) {
    531                      String name = (String)features_list.getSelectedValue();
    532                      Index index = manager.indexes.getIndex(name);
    533                      if(index == null) {
    534                           current = new CollectionMeta(manager, name, current_language, translation.getText());
    535                      }
    536                      else {
    537                           current = new CollectionMeta(manager, index, current_language, translation.getText());
    538                      }
    539                      manager.collectionmetadatum.addMetadata(current);
    540                 }
    541                 else {
    542                      current.update(current.getName(), current.getLanguage(), translation.getText());
    543                 }
    544                 languages_model.cellChanged();
    545           }
    546     }
     510        Boolean ready = (Boolean)languages_model.getValueAt(row, 0);
     511        if(!ready.booleanValue()) {
     512        component.setForeground(Color.red);
     513        }
     514        else {
     515        component.setForeground(Color.black);
     516        }
     517        return component;
     518    }
     519    }
     520    /** Listens for actions within the translation text field and immediately updates the collection metadata as necessary. */
     521    private class TranslationListener
     522    extends KeyAdapter {
     523    /** This method is called when a key has been released, and is perfect for us to synchronize the contents of the translation field with the collection metadata associated with the selected feature and language.
     524    * @param event A <strong>KeyEvent</strong> containing more detail about the key released.
     525    * @see org.greenstone.gatherer.cdm.CollectionMeta
     526    * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     527    * @see org.greenstone.gatherer.cdm.Index
     528    */
     529    public void keyReleased(KeyEvent event) {
     530        if(current == null) {
     531        String name = (String)features_list.getSelectedValue();
     532        Index index = manager.indexes.getIndex(name);
     533        if(index == null) {
     534            current = new CollectionMeta(manager, name, current_language, translation.getText());
     535        }
     536        else {
     537            current = new CollectionMeta(manager, index, current_language, translation.getText());
     538        }
     539        manager.collectionmetadatum.addMetadata(current);
     540        }
     541        else {
     542        current.update(current.getName(), current.getLanguage(), translation.getText());
     543        }
     544        languages_model.cellChanged();
     545    }
     546    }
    547547}
Note: See TracChangeset for help on using the changeset viewer.