Changeset 4932


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

Major CDM rewrite so it uses DOM.

Location:
trunk/gli/src/org/greenstone/gatherer
Files:
11 added
21 edited

Legend:

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

    r4838 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    45 /**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    49  * Written:      01/05/02
    50  * Revised:      16/08/02 Optimized and Commented.
    51  **************************************************************************************/
    52 import java.io.Serializable;
    53 import java.util.ArrayList;
    54 import java.util.Iterator;
    55 import java.util.HashMap;
     28
     29import java.io.*;
     30import java.util.*;
     31import org.greenstone.gatherer.Gatherer;
     32import org.greenstone.gatherer.cdm.CollectionConfiguration;
     33import org.greenstone.gatherer.collection.Collection;
     34import org.greenstone.gatherer.collection.CollectionManager;
    5635import org.greenstone.gatherer.msm.ElementWrapper;
     36import org.greenstone.gatherer.msm.MetadataSetManager;
    5737import org.greenstone.gatherer.msm.MSMUtils;
     38import org.greenstone.gatherer.util.StaticStrings;
    5839import org.greenstone.gatherer.util.Utility;
     40import org.w3c.dom.*;
     41
    5942/** This class contains all the details about a single argument that can be passed to this plugin, including option lists if the parameters are restricted.
    6043 * @author John Thompson, Greenstone Digital Library, University of Waikato
    6144 * @version 2.3
    6245 */
    63 
    64 // ####################################################################################
    65 // Optimization                          Saving
    66 // ####################################################################################
    67 // Vector -> ArrayList                   + Memory, + Processor (pos. - Processor)
    68 // Hashtable -> HashMap                  + Processor
    69 // int -> byte (x7)                      + Memory (168b)
    70 // External method calls                 + Memory, Processor
    71 // ####################################################################################
    72 
    7346public class Argument
    7447    implements Comparable, Serializable {
    75     /** 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. */
    76     private ArrayList values = null;
     48    /** An element of the argument type enumeration. */
     49    static final public byte ENUM = 0;
     50    /** An element of the argument type enumeration. */
     51    static final public byte FLAG = 1;
     52    /** An element of the argument type enumeration. */
     53    static final public byte HIERARCHY = 2;
     54    /** An element of the argument type enumeration. */
     55    static final public byte INTEGER = 3;
     56    /** An element of the argument type enumeration. */
     57    static final public byte LANGUAGE = 4;
     58    /** An element of the argument type enumeration. */
     59    static final public byte METADATA = 5;
     60    /** An element of the argument type enumeration. */
     61    static final public byte METADATUM = 6;
     62    /** An element of the argument type enumeration. */
     63    static final public byte STRING = 7;
    7764    /** <i>true</i> if this argument is required for the applicable script to work properly, <i>false</i> otherwise. */
    7865    private boolean required = false;
    7966    /** The type of this argument. Initially an int, but bytes are cheaper. */
    80     private byte type = FLAG;
    81 
    82     private ElementWrapper element = null;
     67    private byte type = STRING;
     68    private Element element;
    8369    /** 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. */
    8470    private HashMap list = null;
     
    8672    private String default_value = null;
    8773    /** The text description of this argument parsed from the pluginfo output. */
    88     private String desc = null;
     74    private String description = null;
    8975    /** The argument flag as it appears in the command. Also used as the unique identifier of an argument. */
    9076    private String name = null;
    9177    /** The plugin that owns this argument, for the purposes of visualising inheritance. */
    9278    private String owner = null;
    93     /** If this argument has been assigned, what is its value. Must be non-null for the argument to be printed. */
    94     private String value = null;
    95     /** An element of the argument type enumeration. */
    96     static final public byte ENUM = 0;
    97     /** An element of the argument type enumeration. */
    98     static final public byte FLAG = 1;
    99     /** An element of the argument type enumeration. */
    100     static final public byte HIERARCHY = 2;
    101     /** An element of the argument type enumeration. */
    102     static final public byte INTEGER = 3;
    103     /** An element of the argument type enumeration. */
    104     static final public byte LANGUAGE = 4;
    105     /** An element of the argument type enumeration. */
    106     static final public byte METADATA = 5;
    107     /** An element of the argument type enumeration. */
    108     static final public byte METADATUM = 6;
    109     /** An element of the argument type enumeration. */
    110     static final public byte STRING = 7;
     79
    11180    /** Default Constructor. */
    11281    public Argument() {
    11382    }
    114     /** Normal Constructor, based on data parsed from an information script.
    115       * @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.
    116       * @param desc The text description of this argument parsed from the output as a <strong>String</strong>.
    117       * @param type The type of this argument as a <i>byte</i>.
    118       * @param default_value The default value for a parameter type argument, which may include a Perl type regular expression, as a <strong>String</strong>.
    119       */
    120     public Argument(String name, String desc, byte type, String default_value) {
    121     this.default_value = default_value;
    122     this.desc = desc;
    123     this.name = name;
    124     this.type = type;
    125     if(type == ENUM) {
    126         this.list = new HashMap();
    127     }
    128     if(type == METADATUM) {
    129         values = new ArrayList();
    130     }
    131     }
     83
     84    public Argument(Element element) {
     85    this.element = element;
     86    }
     87
    13288    /** Method to add an element to the option list.
    133       * @param name The name value of the option as a <strong>String</strong>.
    134       * @param desc The description of this options as a <strong>String</strong>.
    135       */
     89     * @param name The name value of the option as a <strong>String</strong>.
     90     * @param desc The description of this options as a <strong>String</strong>.
     91     */
    13692    public void addOption(String name, String desc) {
    13793    if(type == ENUM && name != null) {
     
    13995        desc = "";
    14096        }
    141         if(!list.containsKey(name)) {
    142         list.put(name, desc);
    143         }
    144     }
    145     }
     97        if(list == null) {
     98        list = new HashMap();
     99        }
     100        list.put(name, desc);
     101    }
     102    }
     103
    146104    /** Method to compare two arguments for ordering.
    147       * @param object The argument we are comparing to, as an <strong>Object</strong>.
    148       * @return An <i>int</i> specifying the argument order, using values as set out in String.
    149       * @see java.lang.String#compareTo
    150       * @see org.greenstone.gatherer.cdm.Argument
    151       */
     105     * @param object The argument we are comparing to, as an <strong>Object</strong>.
     106     * @return An <i>int</i> specifying the argument order, using values as set out in String.
     107     * @see java.lang.String#compareTo
     108     * @see org.greenstone.gatherer.cdm.Argument
     109     */
    152110    public int compareTo(Object object) {
    153     Argument argument = (Argument)object;
    154     return getName().compareTo(argument.getName());
    155     }
    156     /** Method to deep copy this argument.
    157       * @return A newly created <strong>Argument</strong> which has the same details as this one.
    158       */
     111    if(object instanceof Argument) {
     112        return getName().compareTo(((Argument)object).getName());
     113    }
     114    else {
     115        return toString().compareTo(object.toString());
     116    }
     117    }
     118
    159119    public Argument copy() {
    160     Argument copy = new Argument(name, desc, type, default_value);
     120    Argument copy = new Argument();
     121    copy.setDefaultValue(default_value);
     122    copy.setDescription(description);
     123    copy.setOptions(list);
     124    copy.setOwner(owner);
     125    copy.setName(name);
    161126    copy.setRequired(required);
    162     if(values != null) {
    163         copy.setValues(values);
    164     }
    165     if(list != null) {
    166         HashMap list_deep_copy = new HashMap();
    167         Iterator it = list.keySet().iterator();
    168         while(it.hasNext()) {
    169         String key = (String) it.next();
    170         String desc = (String) list.get(key);
    171         list_deep_copy.put(new String(key), new String(desc));
    172         }
    173         copy.setOptions(list_deep_copy);
    174     }
     127    copy.setType(type);
    175128    return copy;
    176129    }
     130
    177131    /** Method to determine if two arguments are equal.
    178       * @param object The argument to test against, as an <strong>Object</strong>.
    179       * @return <i>true</i> if the arguments names match, <i>false</i> otherwise.
    180       */
     132     * @param object The argument to test against, as an <strong>Object</strong>.
     133     * @return <i>true</i> if the arguments names match, <i>false</i> otherwise.
     134     */
    181135    public boolean equals(Object object) {
    182136    return (compareTo(object) == 0);
    183137    }
     138
    184139    /** Method to retrieve the value of default_value.
    185       * @return A <strong>String</strong> containing the default value.
    186       */
     140     * @return A <strong>String</strong> containing the default value.
     141     */
    187142    public String getDefaultValue() {
    188143    return default_value;
    189144    }
     145
    190146    /** Method to retrieve this arguments description.
    191       * @return A <strong>String</strong> containing the description.
    192       */
    193     public String getDesc() {
    194     return desc;
    195     }
     147     * @return A <strong>String</strong> containing the description.
     148     */
     149    public String getDescription() {
     150    return description;
     151    }
     152
    196153    /** Method to retrieve the description of a certain list option value.
    197       * @param key The <strong>String</strong> whose description we are searching for.
    198       * @return The description of the desired key as a <strong>String</strong> which may be empty if no such key exists.
    199       */
    200     public String getDesc(String key) {
     154     * @param key The <strong>String</strong> whose description we are searching for.
     155     * @return The description of the desired key as a <strong>String</strong> which may be empty if no such key exists.
     156     */
     157    public String getDescription(String key) {
    201158    if(list.containsKey(key)) {
    202159        return (String)list.get(key);
     
    204161    return "";
    205162    }
     163
    206164    /** Method to retrieve the option list for this argument.
    207       * @return A <strong>HashMap</strong> containing &lt;option value&gt; -&gt; &lt;description&gt; entries.
    208       */
    209     public HashMap getList() {
     165     * @return A <strong>HashMap</strong> containing &lt;option value&gt; -&gt; &lt;description&gt; entries.
     166     */
     167    public HashMap getOptions() {
    210168    return list;
    211169    }
     170
    212171    /** Method to retrieve the value of name.
    213       * @return A <strong>String</strong> containing the argument name.
    214       */
     172     * @return A <strong>String</strong> containing the argument name.
     173     */
    215174    public String getName() {
     175    if(name == null && element != null) {
     176        name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
     177    }
    216178    return name;
    217179    }
     180
    218181    /** Retrieve the name of the owner of this argument.
    219       * @return The owners name as a <strong>String</strong>.
    220       */
     182     * @return The owners name as a <strong>String</strong>.
     183     */
    221184    public String getOwner() {
    222185    return owner;
    223186    }
     187   
    224188    /** Method to determine the type of this argument.
    225       * @return An <i>byte</i> specifying the type.
    226       */
     189     * @return An <i>byte</i> specifying the type.
     190     */
    227191    public byte getType() {
    228192    return type;
    229193    }
     194
    230195    /** Method to retrieve the value of value.
    231       * @return The value of value as a <strong>String</strong>.
    232       */
     196     * @return The value of value as a <strong>String</strong>.
     197     */
    233198    public String getValue() {
    234     if(element != null) {
    235         return element.toString();
     199    String value = null;
     200    // Only assigned arguments have values.
     201    if(element != null) {
     202        value = MSMUtils.getValue(element);
     203        // We may have to retrieve the language dependant string for a MSM Element
     204        if(type == METADATUM) {
     205        ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(value);
     206        if(element_wrapper != null) {
     207            value = element_wrapper.toString();
     208        }
     209        }
    236210    }
    237211    return value;
    238212    }
     213
    239214    /** Retrieve the vector of values.
    240       * @return An <strong>ArrayList</strong> of values.
    241       */
     215     * @return An <strong>ArrayList</strong> of values.
     216     */
    242217    public ArrayList getValues() {
     218    ArrayList values = new ArrayList();
     219    // Only assigned arguments have values.
     220    if(element != null) {
     221        String value = MSMUtils.getValue(element);
     222        StringTokenizer tokenizer = new StringTokenizer(value, ",");
     223        while(tokenizer.hasMoreTokens()) {
     224        String token = tokenizer.nextToken();
     225        if(type == METADATA) {
     226            ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(token);
     227            if(element_wrapper != null) {
     228            token = element_wrapper.toString();
     229            }
     230        }
     231        values.add(token);
     232        }
     233    }
    243234    return values;
    244235    }
     236
    245237    /** Method to determine if this argument has been assigned.
    246       * @return <i>true</i> if it has, <i>false</i> otherwise.
    247       */
     238     * @return <i>true</i> if it has, <i>false</i> otherwise.
     239     */
    248240    public boolean isAssigned() {
    249     return (required || value != null || (values != null && values.size() > 0));
    250     }
     241    return (element != null && element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
     242    }
     243
     244    public boolean isCustomArgument() {
     245    return (element != null && element.getAttribute(StaticStrings.CUSTOM_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
     246    }
     247
    251248    /** Method to determine of this argument is required for the associated script to work.
    252       * @return <i>true</i> if this argument is required, <i>false</i> otherwise.
    253       */
     249     * @return <i>true</i> if this argument is required, <i>false</i> otherwise.
     250     */
    254251    public boolean isRequired() {
    255252    return required;
    256253    }
     254
    257255    /** Method to allow for the activation of arguments that might never have their setValue() method called.
    258       * @param new_state The required state as a <i>boolean</i>.
    259       */
    260     public void setAssigned(boolean new_state) {
    261     if(new_state && (value == null || values == null)) {
    262         value = "";
    263     }
    264     else {
    265         value = null;
    266     }
    267     }
     256     * @param assigned the desired state as a boolean
     257     */
     258    public void setAssigned(boolean assigned) {
     259    if(element != null) {
     260        element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, (assigned ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
     261    }
     262    }
     263
     264    public void setCustomArgument(boolean custom) {
     265    if(element != null) {
     266        element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, (custom ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
     267    }
     268    }
     269
    268270    /** Sets the value of default_value.
    269       * @param new_default_value The new value for default_value as a <strong>String</strong>.
    270       */
    271     public void setDefault(String new_default_value) {
    272     default_value = new_default_value;
    273     }
     271     * @param default_value The new value for default_value as a <strong>String</strong>.
     272     */
     273    public void setDefaultValue(String default_value) {
     274    this.default_value = default_value;
     275    }
     276
    274277    /** Set the value of desc.
    275       * @param new_desc The new value of desc as a <strong>String</strong>.
    276       */
    277     public void setDesc(String new_desc) {
    278     desc = new_desc;
    279     }
    280 
    281     public void setElementValue(ElementWrapper element) {
     278     * @param description The new value of desc as a <strong>String</strong>.
     279     */
     280    public void setDescription(String description) {
     281    this.description = description;
     282    }
     283
     284    public void setElement(Element element) {
    282285    this.element = element;
    283286    }
    284287
    285288    /** Set the value of name.
    286       * @param new_name The new value of name as a <strong>String</strong>.
    287       */
    288     public void setName(String new_name) {
    289     name = new_name;
    290     }
     289     * @param name The new value of name as a <strong>String</strong>.
     290     */
     291    public void setName(String name) {
     292    this.name = name;
     293    }
     294
    291295    /** Sets the value of the options list.
    292       * @param new_list The new options list as a <strong>HashMap</strong>.
    293       */
    294     public void setOptions(HashMap new_list) {
    295     list = new_list;
    296     }
     296     * @param list The new options list as a <strong>HashMap</strong>.
     297     */
     298    public void setOptions(HashMap list) {
     299    this.list = list;
     300    }
     301
    297302    /** Set the owner of this argument.
    298       * @param owner The name of the owner of this argument as a <strong>String</strong>.
    299       */
     303     * @param owner The name of the owner of this argument as a <strong>String</strong>.
     304     */
    300305    public void setOwner(String owner) {
    301306    this.owner = owner;
    302307    }
     308
    303309    /** Set the value of required.
    304       * @param new_required The new value of required as a <i>boolean</i>.
    305       */
    306     public void setRequired(boolean new_required) {
    307     required = new_required;
    308     }
     310     * @param required The new value of required as a <i>boolean</i>.
     311     */
     312    public void setRequired(boolean required) {
     313    this.required = required;
     314    }
     315
    309316    /** Set the value of type.
    310       * @param new_type The new value of type as an <i>byte</i>.
    311       */
    312     public void setType(byte new_type) {
    313     type = new_type;
    314     if(type == ENUM) {
    315         list = new HashMap();
    316     }
    317     if(type == METADATUM && values == null) {
    318         values = new ArrayList();
    319     }
    320     }
     317     * @param type The new value of type as an <i>byte</i>.
     318     */
     319    public void setType(byte type) {
     320    this.type = type;
     321    }
     322
    321323    /** Set the value of type, by matching a type to the given string.
    322       * @param new_type A <strong>String</strong> which contains the name of a certain argument type.
    323       */
     324     * @param new_type A <strong>String</strong> which contains the name of a certain argument type.
     325     */
    324326    public void setType(String new_type) {
    325     if(new_type.equalsIgnoreCase("enum")) {
     327    if(new_type.equalsIgnoreCase(StaticStrings.ENUM_STR)) {
    326328        this.type = ENUM;
    327329        list = new HashMap();
    328330    }
    329     else if(new_type.equalsIgnoreCase("flag")) {
     331    else if(new_type.equalsIgnoreCase(StaticStrings.FLAG_STR)) {
    330332        this.type = FLAG;
    331333    }
    332     else if(new_type.equalsIgnoreCase("hierarchy")) {
     334    else if(new_type.equalsIgnoreCase(StaticStrings.HIERARCHY_STR)) {
    333335        this.type = HIERARCHY;
    334336    }
    335     else if(new_type.equalsIgnoreCase("int")) {
     337    else if(new_type.equalsIgnoreCase(StaticStrings.INT_STR)) {
    336338        this.type = INTEGER;
    337339    }
    338     else if(new_type.equalsIgnoreCase("language")) {
     340    else if(new_type.equalsIgnoreCase(StaticStrings.LANGUAGE_STR)) {
    339341        this.type = LANGUAGE;
    340342    }
    341     else if(new_type.equalsIgnoreCase("metadata")) {
     343    else if(new_type.equalsIgnoreCase(StaticStrings.METADATA_TYPE_STR)) {
    342344        this.type = METADATA;
    343345    }
    344     else if(new_type.equalsIgnoreCase("metadatum")) {
     346    else if(new_type.equalsIgnoreCase(StaticStrings.METADATUM_TYPE_STR)) {
    345347        this.type = METADATUM;
    346         if(values == null) {
    347         values = new ArrayList();
    348         }
    349     }
    350     else if(new_type.equalsIgnoreCase("string")) {
     348    }
     349    else {
    351350        this.type = STRING;
    352351    }
    353     }
    354 
    355     /** Method to set the value of value.
    356       * @param new_value The new value of value as a <strong>String</strong>.
    357       */
    358     public void setValue(String new_value) {
    359     this.value = new_value;
    360     }
     352   
     353    }
     354    /** Method to set the value of this argument.
     355     * @param value
     356     * @see org.greenstone.gatherer.Gatherer
     357     * @see org.greenstone.gatherer.msm.MSMUtils
     358     */
     359    public void setValue(String value) {
     360    if(element != null) {
     361        MSMUtils.setValue(element, value);
     362    }
     363    else {
     364        Gatherer.println("Argument.setValue(" + value + ") called on a base Argument.");
     365    }
     366    }
     367
    361368    /** 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.
    362       * @param new_values An <strong>ArrayList</strong> of values.
    363       */
    364     public void setValues(ArrayList new_values) {
    365     values = new_values;
    366     }
     369     * @param values an ArrayList of values
     370     * @see org.greenstone.gatherer.Gatherer
     371     * @see org.greenstone.gatherer.msm.MSMUtils   
     372     */
     373    public void setValues(ArrayList values) {
     374    if(element != null) {
     375        StringBuffer value = new StringBuffer();
     376        int value_length = values.size();
     377        for(int i = 0; i < value_length; i++) {
     378        value.append(values.get(i));
     379        value.append(StaticStrings.COMMA_CHARACTER);
     380        }
     381        value.deleteCharAt(value.length() - 1); // Remove last ','
     382        MSMUtils.setValue(element, value.toString());
     383    }
     384    else {
     385        Gatherer.println("Argument.setValues([" + values.size() + " items]) called on a base Argument.");
     386    }
     387    }
     388
    367389    /** Method for translating the data of this class into a string.
    368       * @return A <strong>String</strong> containing a fragment of the total arguments string.
    369       */
     390     * @return a String containing a fragment of the total arguments string
     391     * @see org.greenstone.gatherer.Gatherer
     392     * @see org.greenstone.gatherer.collection.Collection
     393     * @see org.greenstone.gatherer.collection.CollectionManager
     394     * @see org.greenstone.gatherer.msm.MetadataSetManager
     395     * @see org.greenstone.gatherer.msm.MSMUtils
     396     * @see org.greenstone.gatherer.util.StaticStrings
     397     */
    370398    public String toString() {
    371     switch(type) {
    372     case FLAG:
    373         return "-" + name;
    374     case METADATA:
    375         StringBuffer metadata_text = new StringBuffer("-");
    376         metadata_text.append(name);
    377         metadata_text.append(" ");
    378         if(element != null) {
    379         String element_name = element.toString();
    380         if(element_name.indexOf(" ") != -1) {
    381             metadata_text.append("\"");
    382             metadata_text.append(element_name);
    383             metadata_text.append("\"");
     399    StringBuffer text = new StringBuffer("-");
     400    if(element != null) {
     401        if(name == null) {
     402        name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
     403        }
     404        text.append(name);
     405        String value = MSMUtils.getValue(element);
     406        if(value.length() > 0) {
     407        text.append(StaticStrings.SPACE_CHARACTER);
     408        // Tokenize the string
     409        StringTokenizer tokenizer = new StringTokenizer(value, ",");
     410        while(tokenizer.hasMoreTokens()) {
     411            String token = tokenizer.nextToken();
     412            if(type == METADATA || type == METADATUM) {
     413            ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(token);
     414            if(element_wrapper != null) {
     415                text.append(element_wrapper.toString());
     416                element_wrapper = null;
     417            }
     418            else {
     419                text.append(token);
     420            }
     421            }
     422            else {
     423            text.append(token);
     424            }
     425            token = null;
     426            text.append(StaticStrings.COMMA_CHARACTER);
    384427        }
    385         else {
    386             metadata_text.append(element_name);
    387         }
    388         element_name = null;
    389         }
    390         else {
    391         metadata_text.append(value);
    392         }
    393         return metadata_text.toString();
    394     case METADATUM:
    395         StringBuffer metadatum_text = new StringBuffer("-");
    396         metadatum_text.append(name);
    397         metadatum_text.append(" ");
    398         for(int i = 0; i < values.size(); i++) {
    399         metadatum_text.append(values.get(i).toString());
    400         if(i < values.size() - 1) {
    401             metadatum_text.append(",");
    402         }
    403         }
    404         return metadatum_text.toString();
    405     case STRING:
    406         // we need to put quotes if they are not there
    407         if (value != null && value.indexOf(' ') != -1 && value.indexOf('"')==-1) {
    408         // if there is a space and we haven't got any quotes
    409         return "-" + name + " \"" + value + "\"";
    410         } // otherwise it will stuff up but I cant be bothered doing this properly
    411     default:
    412         return "-" + name + " " + value;
    413     }
    414     }
    415 
    416     public String toStringConfig() {
    417     switch(type) {
    418     case METADATA:
    419         StringBuffer metadata_text = new StringBuffer("-");
    420         metadata_text.append(name);
    421         if(element != null) {
    422         metadata_text.append(" ");
    423         String element_name = element.getName();
    424         if (element_name.startsWith(Utility.EXTRACTED_METADATA_NAMESPACE+MSMUtils.NS_SEP)) {
    425            
    426             element_name = element_name.substring(element_name.indexOf(MSMUtils.NS_SEP)+1);
    427         }
    428         metadata_text.append(element_name);
    429         element_name = null;
    430         }
    431         else if(value != null) {
    432         metadata_text.append(" ");
    433         metadata_text.append(value);
    434         }
    435         return metadata_text.toString();
    436     case METADATUM:
    437         StringBuffer metadatum_text = new StringBuffer("-");
    438         metadatum_text.append(name);
    439         metadatum_text.append(" ");
    440         for(int i = 0; i < values.size(); i++) {
    441         String temp_value = values.get(i).toString();
    442         if (temp_value.startsWith(Utility.EXTRACTED_METADATA_NAMESPACE+MSMUtils.NS_SEP)) {
    443            
    444             temp_value = temp_value.substring(temp_value.indexOf(MSMUtils.NS_SEP)+1);
    445         }
    446         metadatum_text.append(temp_value);
    447         if(i < values.size() - 1) {
    448             metadatum_text.append(",");
    449         }
    450         }
    451         return metadatum_text.toString();
    452     default:
    453         return toString();
    454     }
    455     }
    456    
     428        tokenizer = null;
     429        text.deleteCharAt(text.length() - 1);
     430        }
     431        value = null;
     432    }
     433    return text.toString();
     434    }   
    457435}
    458 
    459 
  • trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java

    r4838 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    45 /**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    49  * Written:      01/05/02
    50  * Revised:      16/08/02 Optimized and Commented. Added destructor.
    51  **************************************************************************************/
    52 import java.awt.BorderLayout;
    53 import java.awt.Color;
    54 import java.awt.Component;
    55 import java.awt.Dimension;
    56 import java.awt.GridLayout;
    57 import java.awt.Toolkit;
    58 import java.awt.event.ActionEvent;
    59 import java.awt.event.ActionListener;
    60 import java.awt.event.ItemEvent;
    61 import java.awt.event.ItemListener;
    62 import java.awt.event.KeyEvent;
    63 import java.util.ArrayList;
    64 import java.util.Collections;
    65 import java.util.HashMap;
    66 import java.util.Iterator;
    67 import javax.swing.BorderFactory;
    68 import javax.swing.BoxLayout;
    69 import javax.swing.DefaultListModel;
    70 import javax.swing.JButton;
    71 import javax.swing.JCheckBox;
    72 import javax.swing.JComboBox;
    73 import javax.swing.JComponent;
    74 import javax.swing.JDialog;
    75 import javax.swing.JLabel;
    76 import javax.swing.JList;
    77 import javax.swing.JOptionPane;
    78 import javax.swing.JPanel;
    79 import javax.swing.JScrollPane;
    80 import javax.swing.JTextField;
     28
     29import java.awt.*;
     30import java.awt.event.*;
     31import java.util.*;
     32import javax.swing.*;
    8133import org.greenstone.gatherer.Gatherer;
    8234import org.greenstone.gatherer.cdm.Argument;
     
    9749 * @see org.greenstone.gatherer.cdm.PlugIn
    9850 */
    99 // ####################################################################################
    100 // Optimization                          Saving
    101 // ####################################################################################
    102 // Vector -> ArrayList                   + Processor
    103 // Hashtable -> HashMap                  + Processor
    104 // Remove several global references      + Memory (1Kb+)
    105 // ####################################################################################
    106 
    10751public class ArgumentConfiguration
    10852    extends ModalDialog
     
    11458    /** 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). */
    11559    private boolean success = false;
    116     /** A reference to the main CollectionDesignManager class for access to other managers. */
    117     private CollectionDesignManager manager = null;
    118     /** A reference to the Gatherer. */
    119     private Gatherer gatherer = null;
    12060    /** A button to cancel this dialog. */
    12161    private JButton cancel = null;
     
    13777    static final private Dimension SIZE = new Dimension(800, 425);
    13878    /** Constructor.
    139      * @param gatherer A reference to the <strong>Gatherer</strong>.
    140      * @param manager The <strong>CollectionDesignManager</strong> for access to other configuration managers.
    14179     * @param data The plugin or classifier whose arguments we are configuring, in the form of its supported <strong>ArgumentContainer</strong> interface.
    14280     * @see org.greenstone.gatherer.Configuration
    14381     */
    144     public ArgumentConfiguration(Gatherer gatherer, CollectionDesignManager manager, ArgumentContainer data) {
    145     super(gatherer.g_man);
     82    public ArgumentConfiguration(ArgumentContainer data) {
     83    super(Gatherer.g_man);
    14684    this.data = data;
    147     this.gatherer = gatherer;
    148     this.manager = manager;
    14985    this.self = this;
    15086    String custom_str = data.getCustom();
     
    210146
    211147    // Display on screen.
    212     Dimension screen_size = gatherer.config.screen_size;
     148    Dimension screen_size = Gatherer.config.screen_size;
    213149    setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
    214150    screen_size = null;
     
    223159    if(event.getSource() == ok) {
    224160        // Update the details stored in the data objects arguments.
    225         if(custom.getText().length() > 0) {
    226         data.setCustom(custom.getText());
    227         }
     161        data.setCustom(custom.getText());
    228162        // Loop through each of the controls in the central pane, updating the matching argument as necessary.
    229163        for(int i = 0; i < central_pane.getComponentCount(); i++) {
     
    248182    custom = null;
    249183    data = null;
    250     gatherer = null;
    251     manager = null;
    252184    ok = null;
    253185    self = null;
     
    285217      */
    286218    private void generateControls() {
    287     ArrayList arguments = data.getArguments();
     219    ArrayList arguments = data.getArguments(true, false);
    288220    int total_height = 250;
    289221    int size = arguments.size();
     
    317249        key = "CDM.ArgumentConfiguration." + key;
    318250    }
    319     return gatherer.dictionary.get(key, args);
     251    return Gatherer.dictionary.get(key, args);
    320252    }
    321253    /** This class encapsulates all the technical difficulty of creating a specific control based on an Argument. */
     
    324256    /** The Argument this control will be based on. */
    325257    private Argument argument = null;
     258
     259    private Color colour_one = Gatherer.config.getColor("coloring.collection_heading_background", false);
     260    private Color colour_two = Gatherer.config.getColor("coloring.collection_tree_background", false);
    326261    /** One of a possible two buttons available for adding to this control. */
    327262    private JButton one = null;
     
    345280    public ArgumentControl(Argument argument) {
    346281        this.argument = argument;
    347         String tip = "<html>" + argument.getDesc() + "</html>";
     282        String tip = "<html>" + argument.getDescription() + "</html>";
    348283        tip = Utility.formatHTMLWidth(tip, 60);
    349284        // If this is the first control, there is no history.
    350285        if(previous_owner == null) {
    351286        previous_owner = argument.getOwner();
    352         addHeader(previous_owner, Color.white);
     287        addHeader(previous_owner, colour_one);
    353288        }
    354289        // Otherwise if the owner of the control has changed since the last argument, toggle the colouring of the control.
     
    356291        coloured = !coloured;
    357292        previous_owner = argument.getOwner();
    358         addHeader(previous_owner, (coloured ? Gatherer.config.getColor("coloring.collection_tree_background", false) : Color.white));
     293        addHeader(previous_owner, (coloured ? colour_two : colour_one));
    359294        }
    360295        // Create
    361296        if(coloured) {
    362         setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     297        setBackground(colour_one);
    363298        }
    364299        else {
    365         setBackground(Color.white);
     300        setBackground(colour_two);
    366301        }
    367302        JLabel owner_label = new JLabel(argument.getOwner());
     
    382317        case Argument.ENUM:
    383318        // Build an option model, wrapping each entry of the list table.
    384         HashMap arg_list = argument.getList();
     319        HashMap arg_list = argument.getOptions();
    385320        ArrayList options_model = new ArrayList();
    386321        Iterator it = arg_list.keySet().iterator();
     
    405340        break;
    406341        case Argument.HIERARCHY:
    407         value = new JComboBox(gatherer.c_man.msm.getAssignedElements(true));
     342        value = new JComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements(true));
    408343        /** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
    409344        ((JComboBox)value).setEditable(true);
     
    450385        break;
    451386        case Argument.LANGUAGE:
    452         value = new JComboBox(manager.languages.getLanguageCodes().toArray());
     387        value = new JComboBox(CollectionDesignManager.language_manager.getLanguageCodes().toArray());
    453388        // Now ensure we have the existing value or default value selected if either exist.
    454389        Language selected = null;
    455390        if(existing_value != null) {
    456             selected = manager.languages.getLanguage(existing_value, false);
     391            selected = CollectionDesignManager.language_manager.getLanguage(existing_value);
    457392        }
    458393        else if(default_value != null) {
    459             selected = manager.languages.getLanguage(default_value, false);
     394            selected = CollectionDesignManager.language_manager.getLanguage(default_value);
    460395        }
    461396        if(selected != null) {
    462             ((JComboBox)value).setSelectedItem(selected);
     397            ((JComboBox)value).setSelectedItem(selected.getCode());
    463398        }
    464399        break;
    465         case Argument.METADATA:
    466         value = new JComboBox(gatherer.c_man.msm.getAssignedElements());
     400        case Argument.METADATUM:
     401        value = new JComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements());
    467402        /** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
    468403        ((JComboBox)value).setEditable(true);
     
    475410        }
    476411        break;
    477         case Argument.METADATUM:
     412        case Argument.METADATA:
    478413        // Comma separated metadata values.
    479414        ArrayList values = argument.getValues();
    480         value = new JComboBox(gatherer.c_man.msm.getAssignedElements());
     415        value = new JComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements());
    481416        DefaultListModel model = new DefaultListModel();
    482417        list = new JList(model);
     
    566501        add(inner_pane, BorderLayout.CENTER);
    567502    }
     503
    568504    public Object getValue() {
    569505        if(value instanceof JComboBox) {
     
    650586            // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
    651587            return true;
    652         case Argument.METADATA:
    653             // I feel like a cast-away
    654             argument.setElementValue((ElementWrapper)((JComboBox)value).getSelectedItem());
    655             return true;
     588        case Argument.METADATUM:
    656589        case Argument.HIERARCHY:
    657590            argument.setValue(((JComboBox)value).getSelectedItem().toString());
    658591            // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
    659592            return true;
    660         case Argument.METADATUM:
     593        case Argument.METADATA:
    661594            DefaultListModel model = (DefaultListModel)list.getModel();
    662595            ArrayList values = new ArrayList();
     
    743676        this.target = target;
    744677        }
    745         /** When the add button is clicked, we attempt to add the selected metadata from the source into the target.
    746         * @param event An <strong>ActionEvent</strong> containing information about the event.
    747         * @see org.greenstone.gatherer.msm.ElementWrapper
    748         */
     678                /** When the add button is clicked, we attempt to add the selected metadata from the source into the target.
     679                * @param event An <strong>ActionEvent</strong> containing information about the event.
     680                * @see org.greenstone.gatherer.msm.ElementWrapper
     681                */
    749682        public void actionPerformed(ActionEvent event) {
    750683        ElementWrapper element = (ElementWrapper) source.getSelectedItem();
    751         String name = element.getName();
     684        String name = element.toString();
    752685        if(!model.contains(name)) {
    753686            boolean found = false;
  • trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentContainer.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    4528/**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    4929 * Written:      20/05/02
    50  * Revised:
     30 * Revised:      03/07/03
    5131 **************************************************************************************/
    5232import java.util.ArrayList;
     
    5737public interface ArgumentContainer {
    5838    /** 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>.
     39     * @param include_normal true to filter so normal arguments are returned
     40     * @param include_custom true to filter so custom arguments are returned
     41     * @return the arguments within a ArrayList
    6042     */
    61     public ArrayList getArguments();
     43    public ArrayList getArguments(boolean include_normal, boolean include_custom);
    6244    /** Method to retrieve this containers custom argument string.
    63      * @return The custom arguments as a <strong>String</strong>.
     45     * @return the custom arguments as a String
    6446     */
    6547    public String getCustom();
    6648    /** Method to retrieve the name associated with this argument container.
    67      * @return The name as a <strong>String</strong>.
     49     * @return the name as a String
    6850     */
    6951    public String getName();
    7052    /** Method to set the custom arguments string.
    71      * @param custom The new custom argument <strong>String</strong>.
     53     * @param custom the new custom argument String
    7254     */
    7355    public void setCustom(String custom);
  • trunk/gli/src/org/greenstone/gatherer/cdm/Classifier.java

    r4838 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    4528/**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    4929 * Written:      01/05/02
    5030 * Revised:      16/08/02 Optimized and Commented.
     31 *               11/07/03 DOM support
    5132 **************************************************************************************/
    52 import java.io.Serializable;
    53 import java.util.ArrayList;
     33import java.io.*;
     34import java.util.*;
    5435import org.greenstone.gatherer.cdm.Argument;
    5536import org.greenstone.gatherer.cdm.ArgumentContainer;
    56 import org.greenstone.gatherer.cdm.CustomClassifier;
    57 import org.greenstone.gatherer.cdm.Format;
     37import org.greenstone.gatherer.cdm.CollectionConfiguration;
     38import org.greenstone.gatherer.cdm.CollectionDesignManager;
     39import org.greenstone.gatherer.cdm.DOMProxyListEntry;
     40import org.greenstone.gatherer.util.StaticStrings;
     41import org.greenstone.gatherer.util.Utility;
     42import org.w3c.dom.*;
    5843/** This class is responsible for storing information from a parsed classinfo.pl call in such a way that it allows easy access to parsed details for the purposes of user design and specification of classifiers.
    5944 * @author John Thompson, Greenstone Digital Library, University of Waikato
    6045 * @version 2.3
    6146 */
    62 // ####################################################################################
    63 // Optimization                          Saving
    64 // ####################################################################################
    65 // Vector -> ArrayList (x8)              + Processor
    66 // ####################################################################################
    6747public class Classifier
    6848    extends ArrayList
    69     implements ArgumentContainer, Comparable, Serializable {
     49    implements ArgumentContainer, Comparable, DOMProxyListEntry, Serializable {
     50
     51    static final public String CLASSIFIER_PREFIX = "CL";
     52
    7053    /** A reference to the classifier that this one inherits from. */
    7154    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;
     55    /** The element this classifier is based upon. */
     56    private Element element;
    7657    /** A description of this classifier. */
    77     private String desc = null;
     58    private String description = null;
    7859    /** The name of the classifier as it would appear in the collect.cfg file. */
    7960    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.
     61    /** This string is filled out the first time this classifier is created, and remains unchanged there-after. It is used to match up with Format commands that may not yet have been instantiated (and thus only have offline references along the lines of 'CL1' to figure out what Classifier they want.) */
     62    private String old_position_string = null;
     63
     64    /** Constructor used only in DOMProxyListModel initializations.
    8365     */
    8466    public Classifier() {
     67    }
     68
     69    public Classifier(Element element, Classifier base_classifier) {
    8570    super();
    86     dependant_formats = new ArrayList();
    87     }
     71    this.element = element;
     72    this.name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     73    ///atherer.println("Establishing Classifier: " + name);
     74    // Parse in any argument options for this classifier, keeping a list of the ones found
     75    HashMap known_arguments = new HashMap();
     76    NodeList option_elements = element.getElementsByTagName(StaticStrings.OPTION_ELEMENT);
     77    int option_elements_length = option_elements.getLength();
     78    for(int i = 0; i < option_elements_length; i++) {
     79        Element option_element = (Element) option_elements.item(i);
     80        Argument argument = new Argument(option_element);
     81        ///atherer.println("Rebuilding existing argument: " + argument.getName());
     82        argument.setOwner(name);
     83        add(argument);
     84        known_arguments.put(argument.getName(), argument);
     85    }
     86    // If a base classifier was given
     87    if(base_classifier != null) {
     88        // Copy the details, and add a reference to whatever base_classifiers super classifier is.
     89        description = base_classifier.getDescription();
     90        // Now search through the 'dummy' arguments belonging to the base classifier. For each found, if it is already assigned, fill out further details such as type. If any are found that are not already assigned for this classifier, copy them and add them, but without a value.
     91        ArrayList all_arguments = base_classifier.getArguments(true, true);
     92        int argument_count = all_arguments.size();
     93        for(int j = 0; j < argument_count; j++) {
     94        Argument base_argument = (Argument) all_arguments.get(j);
     95        String base_argument_name = base_argument.getName();
     96        ///atherer.println("Library indicates this classifier should have an argument: " + base_argument_name);
     97        Argument existing_argument = (Argument) known_arguments.get(base_argument_name);
     98        // Found an existing argument. Complete its details
     99        if(existing_argument != null) {
     100            ///atherer.println("Found existing argument. Filling out details.");
     101            existing_argument.setCustomArgument(false);
     102            existing_argument.setDefaultValue(base_argument.getDefaultValue());
     103            existing_argument.setDescription(base_argument.getDescription());
     104            existing_argument.setOptions(base_argument.getOptions());
     105            existing_argument.setRequired(base_argument.isRequired());
     106            existing_argument.setType(base_argument.getType());
     107        }
     108        // No existing argument. Copy base_argument and add it, but do not set its assigned flag. That should be set the first time its changed by the user.
     109        else {
     110            ///atherer.println("No such argument. Adding new, unassigned, argument.");
     111            // The trick thing is that we have to create a new element in the DOM as well.
     112            Argument new_argument = base_argument.copy();
     113            Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
     114            argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, base_argument_name);
     115            argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     116            argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.FALSE_STR);
     117            new_argument.setElement(argument_element);
     118            // All done. Add it.
     119            element.appendChild(argument_element);
     120            add(new_argument);
     121        }
     122        }
     123    }
     124    old_position_string = getPositionString();
     125    }
     126
    88127    /** Constructor.
    89128      * @param name The name of this classifier as a <strong>String</strong>.
     
    91130      * @param super_classifier The super class of this classifier, as a <strong>Classifier</strong>.
    92131      */
    93     public Classifier(String name, String desc, Classifier super_classifier) {
    94     this();
    95     this.desc = desc;
     132    public Classifier(String name, String description, Classifier super_classifier) {
     133    super();
     134    this.description = description;
    96135    this.name = name;
    97136    this.super_classifier = super_classifier;
    98137    }
     138
    99139    /** Method to add an argument to this classifier. Only adds the argument if it isn't already present.
    100140      * @param argument The <strong>Argument</strong> to add.
    101141      */
    102142    public void addArgument(Argument argument) {
    103     if(!contains(argument)) {
     143    if(element == null && !contains(argument)) {
    104144        add(argument);
    105145        argument.setOwner(name);
    106146    }
    107147    }
    108     /** Method to register a dependant format with this classifier. If the classifier changes, this format also needs to be updated.
    109       * @param format A <strong>Format</strong> which is dependant on this classifier.
    110       */
    111     public void addDependantFormat(Format format) {
    112     dependant_formats.add(format);
    113     }
     148
    114149    /** Method to compare two classifiers for ordering.
    115150      * @param object The classifier we are comparing to, as an <strong>Object</strong>.
     
    118153      */
    119154    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).
    127       * @return A newly created <strong>Classifier</strong> with the same details and Arguments as this one.
    128       * @see org.greenstone.gatherer.cdm.Argument
    129       */
    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     }
     155    if(object == null) {
     156        return -1;
     157    }
     158    return toString().compareTo(object.toString());
     159    }
     160
     161    /** The assigned classifier constructor.
     162     * @param element the DOM Element this classifier is based upon
     163     * @param base_classifier the Classifier from the stored library showing details about this classifier, may be null
     164     */
     165    public DOMProxyListEntry create(Element element) {
     166    String classifier_name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     167    // Determine the base classifier from the classifier name
     168    Classifier base_classifier = CollectionDesignManager.classifier_manager.getBaseClassifier(classifier_name);
     169    Classifier classifier = new Classifier(element, base_classifier);
     170    base_classifier = null;
     171    classifier_name = null;
     172    return classifier;
     173    }
     174
    143175    /** Method to determine if two classifiers are equal.
    144       * @param object The classifier to test against, as an <strong>Object</strong>.
    145       * @return <i>true</i> if the classifier names match, <i>false</i> otherwise.
    146       * @see org.greenstone.gatherer.cdm.CustomClassifier
    147       */
     176     * @param object The classifier to test against, as an <strong>Object</strong>.
     177     * @return <i>true</i> if the classifier names match, <i>false</i> otherwise.
     178     * @see org.greenstone.gatherer.cdm.CustomClassifier
     179     */
    148180    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     }
     181    return (compareTo(object) == 0);
     182    }
     183
    157184    /** Method to retrieve an argument by its name.
    158       * @param name The name of the argument as a <strong>String</strong>.
    159       * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
    160       */
     185     * @param name The name of the argument as a <strong>String</strong>.
     186     * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
     187     */
    161188    public Argument getArgument(String name) {
    162189    // The name given may still include the '-'
     
    164191        name = name.substring(1);
    165192    }
    166     ArrayList arguments = getArguments();
     193    ArrayList arguments = getArguments(true, true);
    167194    for(int i = 0; i < arguments.size(); i++) {
    168195        Argument argument = (Argument)arguments.get(i);
     
    173200    return null;
    174201    }
    175     /** Method to retrieve all of the arguments available to a classifier, including both specific and general ones.
    176       * @return A <strong>Hashtable</strong> of arguments, with &lt;name&gt; -&gt; &lt;argument&gt; entries.
    177       */
    178     public ArrayList getArguments() {
    179     ArrayList all_arguments = new ArrayList(this);
     202
     203     /** Retrieve all of the arguments available to this base classifier, including its super classifiers arguments. Some complexity is added by allowing the caller to choose whether they want normal arguments, custom arguments, or both.
     204     * @return an ArrayList of all of the arguments, starting with those for this classifier and ending with the arguments for basplug or similiar root classifier
     205     */
     206    public ArrayList getArguments(boolean include_normal, boolean include_custom) {
     207    ArrayList arguments = new ArrayList();
     208    if(include_normal && include_custom) {
     209        arguments.addAll(this);
     210    }
     211    else {
     212        int size = size();
     213        for(int i = 0; i < size; i++) {
     214        Argument argument = (Argument) get(i);
     215        if(argument.isCustomArgument()) {
     216            if(include_custom && !arguments.contains(argument)) {
     217            arguments.add(argument);
     218            }
     219        }
     220        else {
     221            if(include_normal && !arguments.contains(argument)) {
     222            arguments.add(argument);
     223            }
     224        }
     225        argument = null;
     226        }
     227    }
    180228    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.
    192       * @return The custom arguments as a <strong>String</strong>.
    193       */
     229        ArrayList remainder = super_classifier.getArguments(include_normal, include_custom);
     230        remainder.removeAll(arguments);
     231        arguments.addAll(remainder);
     232    }
     233    return arguments;
     234    }
     235
     236    /** Method to retrieve a classifiers custom argument information. Custom arguments are defined to be those that have not got matching arguments in the base reference classifier from the library. Of course if there is no base classifier then all arguments are considered to be custom.
     237     * @return the custom arguments as a String
     238     */
    194239    public String getCustom() {
    195     return custom;
    196     }
     240    StringBuffer custom_text = new StringBuffer();
     241    // Retrieve all of the arguments, and append any that are custom into one long string
     242    ArrayList arguments = getArguments(false, true);
     243    int arguments_size = arguments.size();
     244    boolean first = true;
     245    for(int i = 0; i < arguments_size; i++) {
     246        Argument argument = (Argument) arguments.get(i);
     247        if(argument.isAssigned()) {
     248        if(!first) {
     249            custom_text.append(" ");
     250        }
     251        custom_text.append(argument.toString());
     252        first = false;
     253        }
     254    }
     255    return custom_text.toString();
     256    }
     257
     258    public String getDescription() {
     259    return description;
     260    }
     261
     262    public Element getElement() {
     263    return element;
     264    }
     265
    197266    /** Method to retrieve a classifiers name.
    198       * @return A <strong>String</strong> containing the classifiers name.
    199       */
     267     * @return A <strong>String</strong> containing the classifiers name.
     268     */
    200269    public String getName() {
     270    if(name == null && element != null) {
     271        name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     272    }
    201273    return name;
    202274    }
    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.
    204       * @return A <strong>String</strong> containing the special position keyword.
    205       * @see org.greenstone.gatherer.cdm.ClassifierManager
    206       */
     275
     276    public String getOldPositionString() {
     277    return old_position_string;
     278    }
     279
     280    /** Generate the string showing this classifiers position. */
    207281    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.
    214       * @param custom The new value of custom as a <strong>String</strong>.
    215       */
    216     public void setCustom(String custom) {
    217     this.custom = custom;
    218     }
    219     /** Method to set the value of desc.
    220       * @param desc The new value of desc as a <strong>String</strong>.
    221       */
    222     public void setDesc(String desc) {
    223     this.desc = desc;
    224     }
    225     /** Method to set the value of manager.
    226       * @param manager The new manager as a <strong>ClassifierManager</strong>.
    227       */
    228     public void setManager(ClassifierManager manager) {
    229     this.manager = manager;
    230     }
    231     /** Method to set the value of name.
    232       * @param name The new value of name as a <strong>String</strong>.
    233       */
     282    String position_string = CLASSIFIER_PREFIX;
     283    if(element != null) {
     284        // Determine our place in the collect.cfg file
     285        int position_int = CollectionDesignManager.classifier_manager.indexOf(this) + 1;
     286        if(position_int != -1) {
     287        position_string = position_string + position_int;
     288        }
     289    }
     290    return position_string;
     291    }
     292
     293    public boolean isAssigned() {
     294    return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
     295    }
     296
     297    public void setAssigned(boolean assigned) {
     298    if(element != null) {
     299        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     300    }
     301    }
     302
     303    /** Set the custom arguments. This turns out to be quite tricky. We must parse in the string, searching for arguments (for that we use a handy method in CollectionConfiguration). Next, for each argument, we check if we already know about it. If so we update its value, otherwise we create a new argument and assign it (must assign!).
     304     * @param custom_str the custom arguments all splodged together in one String
     305     */
     306    public void setCustom(String custom_str) {
     307    HashMap raw_arguments = CollectionConfiguration.parseArguments(new CommandTokenizer(custom_str));
     308    ArrayList custom_arguments = getArguments(false, true);
     309    int size = custom_arguments.size();
     310    for(int i = 0; i < size; i++) {
     311        Argument argument = (Argument) custom_arguments.get(i);
     312        String original_argument_name = StaticStrings.MINUS_CHARACTER + argument.getName();
     313        if(raw_arguments.containsKey(original_argument_name)) {
     314        // Set as assigned
     315        argument.setAssigned(true);
     316        String argument_value = (String)raw_arguments.remove(original_argument_name);
     317        if(argument_value != null) {
     318            argument.setValue(argument_value);
     319            argument_value = null;
     320        }
     321        }
     322        // We've removed it from our custom statement, so unassign
     323        else {
     324        argument.setAssigned(false);
     325        }
     326        argument = null;
     327    }
     328    // Any left over, add to the classifier
     329    Iterator argument_names = raw_arguments.keySet().iterator();
     330    while(argument_names.hasNext()) {
     331        String argument_name = (String) argument_names.next();
     332        String argument_value = (String) raw_arguments.get(argument_name);
     333        // The tricky thing is that we have to create a new element in the DOM as well.
     334        Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
     335        argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, argument_name.substring(1));
     336        argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     337        argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.TRUE_STR);
     338        Argument argument = new Argument(argument_element);
     339        argument_name = null;
     340        if(argument_value != null) {
     341        argument.setValue(argument_value);
     342        argument_value = null;
     343        }
     344        // All done. Add it.
     345        element.appendChild(argument_element);
     346        add(argument);
     347        argument_element = null;
     348    }
     349    raw_arguments = null;
     350    }
     351
     352    /** Method to set the value of desc.
     353     * @param desc The new value of desc as a <strong>String</strong>.
     354     */
     355    public void setDescription(String desc) {
     356    this.description = description;
     357    }
     358
     359    public void setElement(Element element) {
     360    this.element = element;
     361    }
     362
     363    /** Method to set the value of name.
     364     * @param name The new value of name as a <strong>String</strong>.
     365     */
    234366    public void setName(String name) {
    235367    this.name = name;
    236368    }
     369
    237370    /** Method to set the value of the super_classifier.
    238       * @param super_classifier The new value of super_classifier as a <strong>Classifier</strong>, or <i>null</i> if this class has no inheritance.
    239       */
     371     * @param super_classifier The new value of super_classifier as a <strong>Classifier</strong>, or <i>null</i> if this class has no inheritance.
     372     */
    240373    public void setSuper(Classifier super_classifier) {
    241374    this.super_classifier = super_classifier;
    242375    }
     376
    243377    /** Method to print out this classifier as it would appear to the user in the interface
    244378      * @return A <strong>String</strong> containing a single classifier command.
    245379      */
    246380    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     }
    263     /** Method to print out this classifier as it would appear as a command within the collection configuration file.
    264       * @return A <strong>String</strong> containing a single classifier command.
    265       */
    266     public String toStringConfig() {
    267     StringBuffer text = new StringBuffer("classify ");
    268     text.append(name);
    269     text.append(" ");
    270     ArrayList arguments = getArguments();
    271     for(int i = 0; i < arguments.size(); i++) {
    272         Argument argument = (Argument)arguments.get(i);
    273         if(argument.isAssigned()) {
    274         text.append(argument.toStringConfig());
    275         text.append(" ");
    276         }
    277     }
    278     if(custom != null) {
    279         text.append(custom);
    280     }
    281     return text.toString();
     381    if(element != null) {
     382        if(name == null) {
     383        name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     384        }
     385        StringBuffer text = new StringBuffer(StaticStrings.CLASSIFY_STR);
     386        text.append(" ");
     387        text.append(name);
     388        text.append(" ");
     389        ArrayList arguments = getArguments(true, true);
     390        int arguments_size = arguments.size();
     391        for(int i = 0; i < arguments_size; i++) {
     392        Argument argument = (Argument)arguments.get(i);
     393        if(argument.isAssigned()) {
     394            text.append(argument.toString());
     395            text.append(" ");
     396        }
     397        }
     398        return text.substring(0, text.length() - 1);
     399    }
     400    else {
     401        return name;
     402    }
    282403    }
    283404}
    284 
    285 
  • trunk/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java

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

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    45 /**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    49  * Written:      02/05/02
    50  * Revised:      16/08/02 Optimized and added Destructor.
    51  **************************************************************************************/
    52 import java.awt.BorderLayout;
    53 import java.awt.Rectangle;
    54 import java.io.BufferedReader;
    55 import java.io.File;
    56 import java.io.FileReader;
    57 import java.io.FileOutputStream;
    58 import java.lang.Exception;
    59 import java.lang.String;
    60 import java.lang.StringBuffer;
    61 import java.util.ArrayList;
    62 import java.util.StringTokenizer;
    63 import javax.swing.JPanel;
     28import java.awt.*;
     29import java.awt.event.*;
     30import java.io.*;
     31import javax.swing.*;
     32import javax.swing.event.*;
    6433import org.greenstone.gatherer.Gatherer;
    6534import org.greenstone.gatherer.cdm.ClassifierManager;
     35import org.greenstone.gatherer.cdm.CollectionConfiguration;
    6636import org.greenstone.gatherer.cdm.CollectionMetaManager;
    6737import org.greenstone.gatherer.cdm.FormatManager;
    68 import org.greenstone.gatherer.cdm.GUI;
    69 import org.greenstone.gatherer.cdm.Index;
     38import org.greenstone.gatherer.cdm.GeneralManager;
    7039import org.greenstone.gatherer.cdm.IndexManager;
    71 import org.greenstone.gatherer.cdm.MetadataSetManager;
     40import org.greenstone.gatherer.cdm.MetadataSetView;
    7241import org.greenstone.gatherer.cdm.PlugInManager;
    7342import org.greenstone.gatherer.cdm.SubcollectionManager;
    74 import org.greenstone.gatherer.util.EmailAddress;
     43import org.greenstone.gatherer.cdm.TranslationView;
    7544/** This manager provides access to submanagers, which in turn provide tools for the designing of Greenstone collections via the information stored in etc/collect.cfg. This class acts as a hub for the managers that handle specific parts of the configuration such as classifiers, format strings and language settings.
    7645 * @author John Thompson, Greenstone Digital Library, University of Waikato
    77  * @version 2.3
     46 * @version 2.3d
    7847 */
    79 // ####################################################################################
    80 // Optimization                          Saving
    81 // ####################################################################################
    82 // Vector -> ArrayList                   + Processor
    83 // String -> StringBuffer                + Memory, + Processor
    84 // ####################################################################################
    8548public 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;
     49    /** This listener listens for any event on any of the components in any of the sub-views, and marks the collection as needing saving if any change occurs. */
     50    static public CDMChangeListener change_listener;
    9051    /** A list of classifiers to use at build time. */
    91     public ClassifierManager classifiers = null;
     52    static public ClassifierManager classifier_manager;
     53    /** The CollectionConfiguration object on which this CDM will be based. */
     54    static public CollectionConfiguration collect_config;
    9255    /** 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;
     56    static public CollectionMetaManager collectionmeta_manager;
    10057    /** A list of formating strings to use at build time. */
    101     public FormatManager formats = null;
     58    static public FormatManager format_manager;
    10259    /** The manager in charge of displaying this manager and the controls for other managers. */
    103     public GUI gui = null;
     60    static public GeneralManager general_manager;
    10461    /** List of indexes to be built, and the default index. */
    105     public IndexManager indexes = null;
     62    static public IndexManager index_manager;
    10663    /** Contains instructions dealing with the collection language. */
    107     public LanguageManager languages = null;
     64    static public LanguageManager language_manager;
    10865    /** A simple manager for the visual review of metadata sets. */
    109     public MetadataSetManager metadatasets = null;
     66    static public MetadataSetView metadataset_view;
    11067    /** A list of plugins to use at build time. */
    111     public PlugInManager plugins = null;
     68    static public PlugInManager plugin_manager;
    11269    /** 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;
     70    static public SubcollectionManager subcollection_manager;
     71
     72    static public SubcollectionIndexManager subcollectionindex_manager;
    11473    /** A supercollection command allows a single search to be conducted across several collections. It is a very basic command and so avoids all the crazy model stuff that exists in most of the design managers. */
    115     public SuperCollectionManager superman; // Just cause I could ;p
     74    static public SuperCollectionManager supercollection_manager; // Just cause I could ;p
    11675    /** The text translation manager. */
    117     public TranslationManager transman;
    118     /** A list of whatever commands could not be parsed at all. */
    119     private ArrayList rest = null;
    120     /** A reference to the Gatherer. */
    121     private Gatherer gatherer = null;
    122     /** Constructor.
    123      * @param gatherer The <strong>Gatherer</strong> that created this class.
    124      * @see org.greenstone.gatherer.cdm.ClassifierManager
    125      * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    126      * @see org.greenstone.gatherer.cdm.FormatManager
    127      * @see org.greenstone.gatherer.cdm.IndexManager
    128      * @see org.greenstone.gatherer.cdm.LanguageManager
    129      * @see org.greenstone.gatherer.cdm.MetadataSetManager
    130      * @see org.greenstone.gatherer.cdm.PlugInManager
    131      * @see org.greenstone.gatherer.cdm.SubcollectionManager
    132      */
    133     public CollectionDesignManager() {
    134     this.gatherer = Gatherer.self;
    135     this.classifiers = new ClassifierManager(gatherer, this);
    136     this.collectionmetadatum = new CollectionMetaManager(gatherer, this);
    137     this.formats = new FormatManager(gatherer, this);
    138     this.indexes = new IndexManager(gatherer, this);
    139     this.languages = new LanguageManager(gatherer, this);
    140     this.metadatasets = new MetadataSetManager(gatherer);
    141     this.plugins = new PlugInManager(gatherer, this);
    142     this.rest = new ArrayList();
    143     this.subcollections = new SubcollectionManager(gatherer, this);
    144     this.superman = new SuperCollectionManager();
    145     this.transman = new TranslationManager(this);
    146     }
    147     /** 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.
    148      * @see org.greenstone.gatherer.cdm.ClassifierManager
    149      * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    150      * @see org.greenstone.gatherer.cdm.FormatManager
    151      * @see org.greenstone.gatherer.cdm.IndexManager
    152      * @see org.greenstone.gatherer.cdm.LanguageManager
    153      * @see org.greenstone.gatherer.cdm.MetadataSetManager
    154      * @see org.greenstone.gatherer.cdm.PlugInManager
    155      * @see org.greenstone.gatherer.cdm.SubcollectionManager
     76    static public TranslationView translation_view;
     77    /** Constructor. Loads a certain collection configuration file, which is parsed into a DOM. This model is then registered with the command information managers, each of whom knows how to, and provides controls to, alter certain commands.
     78     * @param collect_config_file the File representing a collection configuration file either in its text (G2) or xml (G3) form
     79     */
     80    public CollectionDesignManager(File collect_config_file) {
     81    Gatherer.println("Initializaing CollectionDesignModule.");
     82    change_listener = new CDMChangeListener();
     83    // Parse the collection configuration
     84    collect_config = new CollectionConfiguration(collect_config_file);
     85    if(Gatherer.debug != null) {
     86        collect_config.display();
     87    }
     88    // Create the command information managers, registering the config file with each as necessary
     89    language_manager = new LanguageManager(collect_config.getLanguages());
     90    collectionmeta_manager = new CollectionMetaManager();
     91    classifier_manager = new ClassifierManager();
     92    general_manager = new GeneralManager();
     93    index_manager = new IndexManager(collect_config.getIndexes());
     94    metadataset_view = new MetadataSetView();
     95    plugin_manager = new PlugInManager();
     96    plugin_manager.placeSeparator();
     97    subcollection_manager = new SubcollectionManager();
     98    subcollectionindex_manager = new SubcollectionIndexManager(collect_config.getSubIndexes());
     99    supercollection_manager = new SuperCollectionManager(collect_config.getSuperCollection());
     100    translation_view = new TranslationView();
     101    format_manager = new FormatManager(); // Parse formats at the very end, given that they depend upon several other managers to appear properly.
     102    Gatherer.println("CollectionDesignModule loaded.");
     103    }
     104    /** This method deconstructs each of the managers, causing them to dispose of their controls.
    156105     */
    157106    public void destroy() {
    158107    // Remove visual the component from its parent.
    159     if(gui.getParent() != null) {
    160         gui.getParent().remove(gui);
     108    if(general_manager.getParent() != null) {
     109        general_manager.getParent().remove(general_manager);
    161110    }
    162111    // Remove references from persistant listeners.
    163     if(classifiers != null && formats != null && gui != null && indexes != null && languages != null && metadatasets != null && plugins != null && subcollections != null) {
    164         classifiers.invalidateControls();
    165         formats.invalidateControls();
    166         gui.invalidateControls();
    167         indexes.invalidateControls();
    168         languages.invalidateControls();
    169         metadatasets.invalidateControls();
    170         plugins.invalidateControls();
    171         subcollections.invalidateControls();
    172         superman.invalidateControls();
    173     }
    174     // Null globals.
    175     classifiers = null;
    176     collectionmetadatum = null;
    177     creator = null;
    178     maintainer = null;
    179     in_file = null;
    180     formats = null;
    181     gui = null;
    182     indexes = null;
    183     languages = null;
    184     metadatasets = null;
    185     plugins = null;
    186     subcollections = null;
    187     superman = null;
    188     rest = null;
    189     gatherer = null;
     112    classifier_manager.destroy();
     113    classifier_manager = null;
     114    format_manager.destroy();
     115    format_manager = null;
     116    general_manager.destroy();
     117    general_manager = null;
     118    index_manager.destroy();
     119    index_manager = null;
     120    language_manager.destroy();
     121    language_manager = null;
     122    metadataset_view.destroy();
     123    metadataset_view = null;
     124    plugin_manager.destroy();
     125    plugin_manager = null;
     126    subcollection_manager.destroy();
     127    subcollection_manager = null;
     128    supercollection_manager.destroy();
     129    supercollection_manager = null;
     130    translation_view.destroy();
     131    translation_view = null;
    190132    }
    191133
    192134    /** Display the GUI interface for the CollectionDesignManager in the centre of the indicated panel.
    193      * @param target The <strong>JPanel</strong> you wish to display the GUI on.
    194      * @see org.greenstone.gatherer.cdm.GUI
     135     * @param target the JPanel you wish to display the gui on
    195136     */
    196137    public void display(JPanel target) {
    197     this.gui = new GUI(gatherer, this);
    198     target.add(gui, BorderLayout.CENTER);
     138    target.add(general_manager, BorderLayout.CENTER);
    199139    }
    200140    /** 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.
    201      * @see org.greenstone.gatherer.cdm.GUI
    202141     */
    203142    public void gainFocus() {
    204     gui.updateUI();
    205     }
    206     /** Retrieve the current set of indexes as defined by the user configuration.
    207      * @return An <strong>ArrayList</strong> of indexes.
    208      * @see org.greenstone.gatherer.cdm.Index
    209      * @see org.greenstone.gatherer.cdm.IndexManager
    210      */
    211     public ArrayList getIndexes() {
    212     ArrayList result = new ArrayList();
    213     int size = indexes.size();
    214     for(int i = 0; i < size; i++) {
    215         result.add(indexes.getIndex(i));
    216     }
    217     return result;
     143    general_manager.gainFocus();
    218144    }
    219145    /** Retrieve the name of the collection configuration file which is being used as the source of the information in this object.
     
    221147     */
    222148    public String getFilename() {
    223     return in_file.getAbsolutePath();
    224     }
    225     /** 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.
    226      * @param filename The name of the file you wish to attempt to pass as a <strong>String</strong>.
     149    return collect_config.getFile().getAbsolutePath();
     150    }
     151
     152    /** Cause the current collection configuration to be written out to disk.
    227153     * @see org.greenstone.gatherer.cdm.ClassifierManager
    228154     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     
    235161     * @see org.greenstone.gatherer.util.EmailAddress
    236162     */
    237     private BufferedReader in;
    238     /** If one of the submanagers detects that it hasn't been provided enough arguments (such as format which always requires at least three) it can call this method to request another line of text from the collect.cfg. If the collect.cfg was not well formed this will cause some problems, but that can't be helped.
    239      * @param prefix the String we have so far
    240      * @return a String with a further line form the collect.cfg appended
    241      */
    242     public String parseMore(String prefix) {
    243     ///ystem.err.println("Command incomplete: " + prefix);
    244     try {
    245         String suffix = in.readLine();
    246         ///ystem.err.println("Adding: " + suffix);
    247         if(suffix != null) {
    248         prefix = prefix + " " + suffix;
    249         }
    250         suffix = null;
    251     }
    252     catch(Exception error) {
    253         error.printStackTrace();
    254     }
    255     return prefix;
    256     }
    257 
    258     public void parse(String filename) {
    259     try {
    260         in_file = new File(filename);
    261         FileReader in_reader = new FileReader(in_file);
    262         in = new BufferedReader(in_reader);
    263         String command = null;
    264         while((command = in.readLine()) != null) {
    265         if(command.length() > 0) {
    266             // Now we've finished parsing a command line, see what manager wants a piece of it.
    267             // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
    268             while(command.trim().endsWith("\\")) {
    269             String next_line = (in.readLine()).trim();
    270             if(next_line != null && next_line.length() > 0) {
    271                 command = command.substring(0, command.lastIndexOf("\\"));
    272                 command = command + next_line;
    273             }
    274             }
    275             // Now we've finished parsing a command line, see what manager wants a piece of it.
    276             boolean found = false;
    277             String command_lc = command.toLowerCase();
    278             if(command_lc.startsWith("creator")) {
    279             creator = new EmailAddress(gatherer, command);
    280             found = true;
    281             }
    282             if(command_lc.startsWith("maintainer")) {
    283             maintainer = new EmailAddress(gatherer, command);
    284             found = true;
    285             }
    286             if(command_lc.startsWith("public")) {
    287             if(command_lc.endsWith("true")) {
    288                 public_col = true;
    289             }
    290             else {
    291                 public_col = false;
    292             }
    293             found = true;
    294             }
    295             if(command_lc.startsWith("beta")) {
    296             if(command_lc.endsWith("false")) {
    297                 beta = false;
    298             }
    299             else {
    300                 beta = true;
    301             }
    302             found = true;
    303             }
    304             if(!found) {
    305             found = indexes.parse(command);
    306             }
    307             if(!found) {
    308             found = subcollections.parse(command, false);
    309             }
    310             if(!found) {
    311             found = languages.parse(command);
    312             }
    313             if(!found) {
    314             found = plugins.parse(command);
    315             }
    316             if(!found) {
    317             found = classifiers.parse(command);
    318             }
    319             if(!found) {
    320             found = formats.parse(command, false);
    321             }
    322             if(!found) {
    323             found = collectionmetadatum.parse(command, false);
    324             }
    325             if(!found) {
    326             found = superman.parse(command);
    327             }
    328             // Metadataset commands
    329             if(command_lc.startsWith("metadataset")) {
    330             // Nothing yet. Eventually used to import metadata.
    331             found = true;
    332             }
    333             // Comments we ignore.
    334             if(command_lc.startsWith("# these instructions are not recognized by the gatherer.")) {
    335             // Ignore
    336             found = true;
    337             }
    338             // We have been unable to parse this command, add it to rest.
    339             if(!found) {
    340             rest.add(command);
    341             }
    342         }
    343         }
    344         in.close();
    345         // Now attempt to finalize any commands that were not immediately parsed as they were waiting for unresolved references.
    346         subcollections.reparseUnresolved();
    347         classifiers.reparseUnresolved();
    348         formats.reparseUnresolved();
    349         collectionmetadatum.reparseUnresolved();
    350     }
    351     catch(Exception error) {
    352         error.printStackTrace();
    353     }
    354     }
    355     /** 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.
    356      * @see org.greenstone.gatherer.cdm.ClassifierManager
    357      * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    358      * @see org.greenstone.gatherer.cdm.FormatManager
    359      * @see org.greenstone.gatherer.cdm.IndexManager
    360      * @see org.greenstone.gatherer.cdm.LanguageManager
    361      * @see org.greenstone.gatherer.cdm.MetadataSetManager
    362      * @see org.greenstone.gatherer.cdm.PlugInManager
    363      * @see org.greenstone.gatherer.cdm.SubcollectionManager
    364      * @see org.greenstone.gatherer.util.EmailAddress
    365      */
    366163    public void save() {
    367     try {
    368         // If the file already exists (it should) rename it.
    369         if(in_file.exists()) {
    370         String filename = in_file.getAbsolutePath();
    371         File backup = new File(filename + "~");
    372         backup.deleteOnExit();
    373         if(!in_file.renameTo(backup)) {
    374             Gatherer.println("Error in CollectionDesignManager.parse(): FileRenamedException");
    375         }
    376         in_file = new File(filename); // Just in case we moved it.
    377         }
    378         FileOutputStream out = new FileOutputStream(in_file);
    379 
    380         StringBuffer text = new StringBuffer("");
    381         if(creator != null) {
    382         text.append(creator.toString());
    383         text.append("\n");
    384         }
    385         if(maintainer != null) {
    386         text.append(maintainer.toString());
    387         text.append("\n");
    388         }
    389         if(public_col) {
    390         text.append("public true\n");
    391         }
    392         else {
    393         text.append("public false\n");
    394         }
    395         if(beta) {
    396         text.append("beta true\n");
    397         }
    398         else {
    399         text.append("beta false\n");
    400         }
    401         if(text.length() > 0) {
    402         text.append("\n");
    403         }
    404         if(plugins.size() > 0) {
    405         text.append(plugins.toString());
    406         }
    407         if(indexes.size() > 0) {
    408         text.append(indexes.toString());
    409         }
    410         if(languages.size() > 0) {
    411         text.append(languages.toString());
    412         }
    413         if(subcollections.size() > 0) {
    414         text.append(subcollections.toString());
    415         }
    416         String super_collections_command = superman.toString();
    417         if(super_collections_command != null) {
    418         text.append(super_collections_command);
    419         }
    420         if(classifiers.size() > 0) {
    421         text.append(classifiers.toString());
    422         }
    423         if(formats.size() > 0) {
    424         text.append(formats.toString());
    425         }
    426         if(collectionmetadatum.size() > 0) {
    427         text.append(collectionmetadatum.toString());
    428         }
    429         text.append(metadatasets.toString());
    430         if(rest.size() > 0) {
    431         // Write out rest at the bottom.
    432         text.append("# These instructions are not recognized by the Gatherer.\n");
    433         for(int i = 0; i < rest.size(); i++) {
    434             text.append(rest.get(i));
    435             text.append("\n");
    436         }
    437         }
    438         out.write(text.toString().getBytes());
    439         out.close();
    440         out = null;
    441     }
    442     catch(Exception error) {
    443         error.printStackTrace();
    444     }
     164    general_manager.loseFocus();
     165    collect_config.save();
    445166    }
    446167    /** 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).
     
    451172    public Rectangle setSelectedElement(String element) {
    452173    // First ensure that the metadata set controls are visible.
    453     gui.setSelectedView("CDM.GUI.MetadataSets");
     174    general_manager.setSelectedView("CDM.GUI.MetadataSets");
    454175    // Then tell them to select the given element.
    455     return metadatasets.setSelectedElement(element);
     176    return metadataset_view.setSelectedElement(element);
     177    }
     178
     179    private class CDMChangeListener
     180    implements ActionListener, DocumentListener {
     181   
     182    public void actionPerformed(ActionEvent event) {
     183        Gatherer.c_man.getCollection().setSaved(false);
     184    }
     185
     186    /** Gives notification that an attribute or set of attributes changed. */
     187    public void changedUpdate(DocumentEvent e) {
     188        Gatherer.c_man.getCollection().setSaved(false);
     189    }
     190         
     191    /** Gives notification that there was an insert into the document. */
     192    public void insertUpdate(DocumentEvent e) {
     193        Gatherer.c_man.getCollection().setSaved(false);
     194    }
     195         
     196    /** Gives notification that a portion of the document has been removed. */
     197    public void removeUpdate(DocumentEvent e) {
     198        Gatherer.c_man.getCollection().setSaved(false);
     199    }
    456200    }
    457201}
  • trunk/gli/src/org/greenstone/gatherer/cdm/CollectionMeta.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    4528/**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Copyright:    Copyright (c) 2001
    49  * Company:      The University of Waikato
    50  * Written:        /05/02
    51  * Revised:      22/08/02 Revamped, Optimized and Commented.
     29 * Written:     
     30 * Revised:     28/06/03 - DOM support
    5231 **************************************************************************************/
     32import org.greenstone.gatherer.Configuration;
     33import org.greenstone.gatherer.Gatherer;
     34import org.greenstone.gatherer.cdm.CollectionConfiguration;
     35import org.greenstone.gatherer.cdm.CollectionDesignManager;
     36import org.greenstone.gatherer.cdm.DOMProxyListEntry;
    5337import org.greenstone.gatherer.cdm.Index;
    54 import org.greenstone.gatherer.cdm.Language;
     38import org.greenstone.gatherer.msm.MSMUtils;
     39import org.greenstone.gatherer.util.StaticStrings;
    5540import org.greenstone.gatherer.util.Utility;
     41import org.w3c.dom.*;
    5642/** This class encapsulates a single collection level metadata assignment, which constitutes a name, language and value.
    5743 * @author John Thompson, Greenstone Digital Library, University of Waikato
    58  * @version 2.3
     44 * @version 2.4
    5945 */
    6046public 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 also refer to an Index or a Partition. */
    67     private Object name = null;
    68     /** The value of this metadata. */
    69     private String value = null;
     47    implements DOMProxyListEntry {
     48    private Element element;
     49    private String text;
     50
    7051    /** 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>.
    74       */
    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;
     52     * @param element the Element from which we will determine metadata details
     53     */
     54    public CollectionMeta(Element element) {
     55    this.element = element;
    8056    }
     57
     58    /** Constructor to create a new piece of metadata given its name. */
     59    public CollectionMeta(String name) {
     60    element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.COLLECTIONMETADATA_ELEMENT);
     61    element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
     62    element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, Gatherer.config.interface_language);
     63    }
     64
     65    /** Constructor to create a new piece of metadata given its name. */
     66    public CollectionMeta(String name, String language) {
     67    element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.COLLECTIONMETADATA_ELEMENT);
     68    element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
     69    element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, language);
     70    }
     71
    8172    /** Method to compare two collection metadata objects to calculate their respective ordering.
    82       * @param object The other metadata to compare to, as an <strong>Object</strong>.
    83       * @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.
    84       * @see org.greenstone.gatherer.cdm.Language
    85       */
     73     * @param object the other metadata to compare to, as an Object
     74     * @return an int which is less than 0 if this object proceeds the given object, 0 if they are equal and greater than 0 otherwise.
     75     * @see org.greenstone.gatherer.cdm.Language
     76     */
    8677    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     }
    10778    return toString().compareTo(object.toString());
    10879    }
     80
     81    /** Factory constructor. */
     82    public DOMProxyListEntry create(Element element) {
     83    return new CollectionMeta(element);
     84    }
     85
    10986    /** Method to compare two collection metadata objects for equality.
    110       * @param object The other metadata to compare to, as an <strong>Object</strong>.
    111       * @return A <i>boolean</i> value of <i>true</i> if the object are equal, <i>false</i> otherwise.
    112       */
     87     * @param object The other metadata to compare to, as an <strong>Object</strong>.
     88     * @return A <i>boolean</i> value of <i>true</i> if the object are equal, <i>false</i> otherwise.
     89     */
    11390    public boolean equals(Object object) {
    114     if(compareTo(object) == 0) {
    115         return true;
    116     }
    117     return false;
     91    return (compareTo(object) == 0);
    11892    }
     93
     94    public Element getElement() {
     95    return element;
     96    }
     97
    11998    /** Method to retrieve the value of language.
    120      * @return The value of language as a <strong>Language</strong>.
     99     * @return The value of language as a <strong>String</strong>.
    121100     */
    122     public Language getLanguage() {
    123     return language;
     101    public String getLanguage() {
     102    // Retrieve the language string
     103    return element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE);
    124104    }
     105
    125106    /** Method to retrieve the value of name.
    126      * @return The value of name as an <strong>Object</strong>.
     107     * @return
    127108     */
    128     public Object getName() {
    129     return name;
     109    public String getName() {
     110    return element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
    130111    }
    131112    /** Method to retrieve the value of value (well great choice of name there).
    132       * @return The value of value as a <strong>String</strong>.
    133       */
     113     * @return The value of value as a <strong>String</strong>.
     114     */
    134115    public String getValue() {
    135     return value;
     116    // We have to replace the string made of '\' 'n' with the '\n' character! Also watch for other greenstone magic
     117    return Utility.decodeGreenstone(MSMUtils.getValue(element));
    136118    }
    137     /** Method to print out this class as it would appear within the collection configuration file.
    138       * @return A <strong>String</strong> containing the text value of this class.
    139       */
    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.toStringConfig() + " ";
     119
     120    public boolean isAssigned() {
     121    return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
     122    }
     123
     124    /** Determine if this metadata is one of the four special pieces of metadata.
     125     * @return true if this metadata is special, false otherwise.
     126     */
     127    public boolean isSpecial() {
     128    return (element != null && element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
     129    }
     130
     131    public void setAssigned(boolean assigned) {
     132    if(element != null) {
     133        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
    146134    }
    147     else if(name instanceof SubIndex) {
    148         text = text + ".";
    149         SubIndex index = (SubIndex)name;
    150         text = text + index.toString() + " ";
    151     }
    152     else {
    153         text = text + name.toString() + " ";
    154     }
    155     if(language != null && manager.languages.size() > 0 && !manager.languages.isDefaultLanguage(language)) {
    156         text = text + "[l=" + language.getCode() + "] ";
    157     }
    158     text = text + "\"" + Utility.encodeGreenstone(value) + "\"\n";
    159     return text;
    160135    }
    161     /** Used to update the contents of this collection level metadata to the given 'new' values.
    162       * @param name The new name of the metadata, as a <strong>Object</strong>.
    163       * @param language The new <strong>Language</strong> of the metadata.
    164       * @param value And the value the metadata is assigned, as a <strong>String</strong>.
    165       */
    166     public void update(Object name, Language language, String value) {
    167     this.name = name;
    168     this.language = language;
    169     this.value = value;
     136
     137    public void setElement(Element element) {
     138    this.element = element;
     139    text = null;
    170140    }
    171141
     
    174144     */
    175145    public void setValue(String value) {
    176     this.value = value;
     146    MSMUtils.setValue(element, Utility.encodeGreenstone(value));
     147    text = null; // Reset text
    177148    }
    178149
    179     /** Ensure this is a valid metadata entry by checking that the value is non-null and non-zero length (after having removed whitespace).
    180      * @return <i>true</i> if this metadata has a valid value and should be added to the config, <i>false</i> otherwise.
    181      */
    182     public boolean valid() {
    183     return(value != null && value.trim().length() > 0);
     150    /** Method to print out this class as it would appear within the collection configuration file.
     151      * @return A <strong>String</strong> containing the text value of this class.
     152      */
     153    public String toString() {
     154    if(text == null) {
     155        text = CollectionConfiguration.toString(element, true);
     156    }
     157    return text;
    184158    }
    185159}
  • trunk/gli/src/org/greenstone/gatherer/cdm/CollectionMetaManager.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    45 /**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Copyright:    Copyright (c) 2001
    49  * Company:      The University of Waikato
    50  * Written:        /05/02
    51  * Revised:      22/08/02 Revamped, Optimized and Commented.
    52  **************************************************************************************/
    5328import java.awt.*;
    5429import java.awt.event.*;
     
    5934import org.greenstone.gatherer.cdm.CollectionDesignManager;
    6035import org.greenstone.gatherer.cdm.CollectionMeta;
     36import org.greenstone.gatherer.cdm.DOMProxyListModel;
    6137import org.greenstone.gatherer.cdm.Index;
    62 import org.greenstone.gatherer.cdm.Language;
    6338import org.greenstone.gatherer.gui.EditorDialog;
     39import org.greenstone.gatherer.util.StaticStrings;
    6440import org.greenstone.gatherer.util.Utility;
     41import org.w3c.dom.*;
    6542/** This class is responsible for maintaining a list of assigned collection level metadata, and for allows manipulations on the aforementioned data.
    6643 * @author John Thompson, Greenstone Digital Library, University of Waikato
    67  * @version 2.3
     44 * @version 2.3d
    6845 */
    69 // ####################################################################################
    70 // Optimization                               Saving
    71 // ####################################################################################
    72 // Removed Vector and Hashtable               + Memory, + Processor
    73 // ####################################################################################
    74 public class CollectionMetaManager
    75     extends DefaultListModel {
    76     /** A reference to the cdm manager so we can access indexes and languages. */
    77     private CollectionDesignManager manager = null;
    78     /** A reference to ourself so that inner classes can use us as a model. */
    79     private DefaultListModel model = null;
    80     /** A reference to the Gatherer. */
    81     private Gatherer gatherer = null;
    82     /** The language the most recent metadata returned was in. */
    83     private Language current_language = null;
    84     /** We can't safely parse metadata commands until after all the other commands have been parsed, so we store commands here for now. */
    85     private ArrayList unresolved_commands = null;
    86     /** Constructor.
    87      * @param gatherer A reference to the <strong>Gatherer</strong>.
    88      * @param manager A reference to the <strong>CollectionDesignManager</strong> for access to other configuration managers.
    89      */
    90     public CollectionMetaManager(Gatherer gatherer, CollectionDesignManager manager) {
    91     super();
    92     this.gatherer = gatherer;
    93     this.manager = manager;
    94     this.model = this;
    95     this.unresolved_commands = new ArrayList();
     46public class CollectionMetaManager
     47    extends DOMProxyListModel {
     48   
     49    /** Constructor. */
     50    public CollectionMetaManager() {
     51    super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.COLLECTIONMETADATA_ELEMENT, new CollectionMeta(""));
     52    Gatherer.println("CollectionMetaManager: " + getSize() + " metadata parsed.");
    9653    }
    9754    /** Method to add a new piece of metadata.
    98       * @param metadata The new <strong>CollectionMeta</strong>.
    99       */
    100     public void addMetadata(CollectionMeta metadata) {
    101     CollectionMeta existing = getMetadata(metadata.getName().toString(), metadata.getLanguage(), false);
    102     if(existing != null) {
    103         removeElement(existing);
     55     * @param metadata the new CollectionMeta
     56     */
     57    public void addMetadatum(CollectionMeta metadata) {
     58    if(!contains(metadata)) {
     59        Element element = metadata.getElement();
     60        // Locate where we should insert this new subcollection.
     61        Node target_node = CollectionConfiguration.findInsertionPoint(element);
     62        // Failing that we insert immediately after a language string
     63        add(root, metadata, target_node);
     64        Gatherer.c_man.configurationChanged();
    10465    }
    105     addElement(metadata);
    106     gatherer.c_man.configurationChanged();
     66    Gatherer.c_man.configurationChanged();
    10767    }
    108     /** Retrieve the collectionextra metadata in the default language, if present.
    109       * @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>.
    110       * @see org.greenstone.gatherer.cdm.Language
    111       */
    112     public CollectionMeta getCollectionExtra() {
    113     CollectionMeta result = getMetadata("collectionextra", Gatherer.config.interface_language, true);
    114     if(result == null) {
    115         result = new CollectionMeta(manager, "collectionextra", Gatherer.config.interface_language, "");
    116         addMetadata(result);
     68
     69    public CollectionMeta get(int i) {
     70    return (CollectionMeta) getElementAt(i);
     71    }
     72
     73    /** Retrieve all of the general metadata. */
     74    public ArrayList getMetadata() {
     75    ArrayList result = new ArrayList();
     76    int size = getSize();
     77    for(int i = 0; i < size; i++) {
     78        CollectionMeta metadata = (CollectionMeta) getElementAt(i);
     79        if(!metadata.getName().startsWith(StaticStrings.STOP_CHARACTER)) {
     80        result.add(metadata);
     81        }
    11782    }
    11883    return result;
    11984    }
    120     /** Retrieve the collectionname metadata in the default language, if present.
    121       * @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>.
    122       * @see org.greenstone.gatherer.cdm.Language
    123       */
    124     public CollectionMeta getCollectionName() {
    125     return getMetadata("collectionname", Gatherer.config.interface_language, true);
    126     }
    127     /** Retrieve the iconcollection metadata in the default language, if present.
    128       * @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>.
    129       * @see org.greenstone.gatherer.cdm.Language
    130       */
    131     public CollectionMeta getIconCollection() {
    132     CollectionMeta result = getMetadata("iconcollection", Gatherer.config.interface_language, true);
    133     if(result == null) {
    134         result = new CollectionMeta(manager, "iconcollection", Gatherer.config.interface_language, "");
    135         addMetadata(result);
    136     }
    137     return result;
    138     }
    139     /** Retrieve the iconcollection metadata in the default language, if present.
    140       * @return A <strong>CollectionMeta</strong> containing the iconcollectionsmall in the default language if present, or else the first iconcollectionsmall of any language, otherwise <i>null</i>.
    141       * @see org.greenstone.gatherer.cdm.Language
    142       */
    143     public CollectionMeta getIconCollectionSmall() {
    144     CollectionMeta result = getMetadata("iconcollectionsmall", Gatherer.config.interface_language, true);
    145     if(result == null) {
    146         result = new CollectionMeta(manager, "iconcollectionsmall", Gatherer.config.interface_language, "");
    147         addMetadata(result);
    148     }
    149     return result;
    150     }
    151     /** Method to retrieve the list of metadata.
    152       * @return An <strong>ArrayList</strong> containing the metadata.
    153       */
    154     public ArrayList getMetadata() {
    155     ArrayList metadata = new ArrayList();
    156     for(int i = 0; i < size(); i++) {
    157         metadata.add(get(i));
    158     }
    159     Collections.sort(metadata);
    160     return metadata;
    161     }
    16285     
    16386    /** Retrieve all of the metadata for the given feature, regardless of language. */
    164     public ArrayList getMetadata(Object name) {
     87    public ArrayList getMetadata(String name) {
    16588    ArrayList result = new ArrayList();
    166     for(int i = 0; i < size(); i++) {
    167         CollectionMeta metadata = (CollectionMeta) get(i);
     89    int size = getSize(); // Refresh DOM Model
     90    for(int i = 0; i < size; i++) {
     91        CollectionMeta metadata = (CollectionMeta) getElementAt(i);
    16892        if(metadata.getName().equals(name)) {
    16993        result.add(metadata);
     
    17296    return result;
    17397    }
     98
     99    /** Retrieve the named piece of metadata, in the default language, if available. If no such metadata is available then it is created.
     100     * @param name the name of the metadatum to retrieve as a String
     101     * @return the dom Element containing the specified metadatum
     102     */
     103    public CollectionMeta getMetadatum(String name) {
     104    return getMetadatum(name, true);
     105    }
     106
     107    public CollectionMeta getMetadatum(String name, boolean add_if_not_found) {
     108    ///atherer.println("Get the metadata for " + name + " in the default language.");
     109    int size = getSize();
     110    for(int i = 0; i < size; i++) {
     111        CollectionMeta metadatum = (CollectionMeta) getElementAt(i);
     112        if(metadatum.getName().equals(name) && metadatum.getLanguage().equals(Gatherer.config.interface_language)) {
     113        ///atherer.println("Found '" + metadatum + "'");
     114        return metadatum;
     115        }
     116        else {
     117        ///atherer.println("No match with: " + metadatum.getName() + " [l=" + metadatum.getLanguage() + "] \"" + metadatum.getValue() + "\"");
     118        }
     119        metadatum = null;
     120    }
     121    if(add_if_not_found) {
     122        CollectionMeta result = new CollectionMeta(name);
     123        addMetadatum(result);
     124        ///atherer.println("Added new metadata.");
     125        return result;
     126    }
     127    else {
     128        return null;
     129    }
     130    }
     131
    174132    /** Method to retrieve a certain piece of metadata based on its name and language.
    175       * @param name the name of the metadata as an Object (as it may actually be a refernce to an Index or SubIndex)
    176       * @param language The <strong>Language</strong> of the metadata.
    177       * @param partial <i>true</i> to return the first partial match (ie matches name but not language).
    178       * @return The <strong>CollectionMeta</strong> requested, or <i>null</i> if no such metadata.
    179       */
    180     public CollectionMeta getMetadata(Object name, Language language, boolean partial) {
     133     * @param name the name of the metadata as an Object (as it may actually be a refernce to an Index or SubIndex)
     134     * @param language the language of the metadata.
     135     * @param partial <i>true</i> to return the first partial match (ie matches name but not language).
     136     * @return The <strong>CollectionMeta</strong> requested, or <i>null</i> if no such metadata.
     137     */
     138    public CollectionMeta getMetadata(String name, String language, boolean partial) {
    181139    CollectionMeta partial_match = null;
    182     for(int i = 0; i < size(); i++) {
    183         CollectionMeta metadata = (CollectionMeta) get(i);
     140    for(int i = 0; i < getSize(); i++) {
     141        CollectionMeta metadata = (CollectionMeta) getElementAt(i);
    184142        Object metadata_name = metadata.getName();
    185143        // We test the case of an object match (ie Index to Index)...
    186144        if(metadata_name.equals(name)) {
    187         if (metadata.getLanguage().equals(language)) {
    188             return metadata;
    189         }
    190         partial_match = metadata;
    191         }
    192         // But if that fails we also try a string match such that "section:dls.Title" == Index
    193         if(metadata_name.toString().equals(name.toString())) {
    194145        if (metadata.getLanguage().equals(language)) {
    195146            return metadata;
     
    203154    return null;
    204155    }
    205     /** 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.
    206      * @param command The command text we wish to parse, as a <strong>String</strong>.
    207      * @return A <i>boolean</i> which is <i>true</i> if a collection metadata command was successfully parsed, <i>false</i> otherwise.
    208      * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    209      * @see org.greenstone.gatherer.cdm.CommandTokenizer
    210      * @see org.greenstone.gatherer.cdm.Language
    211      * @see org.greenstone.gatherer.cdm.LanguageManager
    212      * @see org.greenstone.gatherer.util.Utility
    213      */
    214     public boolean parse(String command, boolean finished) {
    215     String temp = command.toLowerCase();
    216     if(temp.startsWith("collectionmeta")) {
    217         if(finished) {
    218         CommandTokenizer ct = new CommandTokenizer(command);
    219         if(ct.countTokens() >= 3) {
    220             ct.nextToken(); // Throw away collectionmeta
    221             Object key = ct.nextToken();
    222             Language language = null;
    223             String language_code = null;
    224             String value = ct.nextToken();
    225             // Arg. Remember a language token will be '[l=<code>]'
    226             if(value.startsWith("[") && value.endsWith("]")) {
    227             language_code = value.substring(3, value.length() - 1);
    228             ///ystem.err.println("Language code = " + language_code);
    229             value = ct.nextToken();
    230             }
    231             // Check if the key is an index, and if so retrieve it.
    232             if(((String)key).startsWith(".")) {
    233             ///ystem.err.println("Detected '.' prefix.");
    234             String key_str = (String)key;
    235             key = null;
    236             key_str = key_str.substring(1);
    237             Index ind = Index.parseIndexConfig(key_str, manager);
    238             if (ind != null) {
    239                
    240                 key = manager.indexes.getIndex(ind.toString(false));
    241             }
    242            
    243             // If that didn't work, then it might be a subindex so have a bash at retrieving that instead.
    244             if(key == null) {
    245                 key = manager.subcollections.getSubIndex(key_str);
    246                 //if(key != null) {
    247                 ///ystem.err.println("Its a subindex.");
    248                 //}
    249                 //else {
    250                 ///ystem.err.println("Error Will Robinson.");
    251                 //}
    252             }
    253             //else {
    254                 ///ystem.err.println("Its an index.");
    255             //}
    256             }
    257             // An if we have a language code, retrieve its object too.
    258             if(language_code != null) {
    259             language = manager.languages.getLanguage(language_code, false);
    260             }
    261             // Otherwise set language to the default language.
    262             else {
    263             language = Gatherer.config.interface_language;
    264             }
    265             if(key != null) {
    266             // Trim any "
    267             if(value.equals("\"\"")) {
    268                 value = "";
    269             }
    270             else {
    271                 if(value.startsWith("\"")) {
    272                 value = value.substring(1);
    273                 }
    274                 if(value.endsWith("\"")) {
    275                 value = value.substring(0, value.length() - 1);
    276                 }
    277             }
    278             CollectionMeta meta = new CollectionMeta(manager, key, language, Utility.decodeGreenstone(value));
    279             addMetadata(meta);
    280             }
    281             return true;
     156
     157    /** Method to remove a piece of metadata.
     158     * @param metadata metadata
     159     */
     160    public void removeMetadata(CollectionMeta metadata) {
     161    if(metadata != null) {
     162        String name = metadata.getName();
     163        String language = metadata.getLanguage();
     164        for(int i = 0; i < getSize(); i++) {
     165        CollectionMeta other = (CollectionMeta) getElementAt(i);
     166        if(name.equals(other.getName()) && language.equals(other.getLanguage())) {
     167            remove(i);
     168            Gatherer.c_man.configurationChanged();
     169            return;
    282170        }
    283         }
    284         else {
    285         unresolved_commands.add(command);
    286         return true;
    287         }
     171        other = null;
     172        }   
     173        language = null;
     174        name = null;
    288175    }
    289     return false;
    290     }
    291     /** Ensure that the values being showed are the most up to date. */
    292     public void refresh() {
    293     fireContentsChanged(this, 0, size());
    294176    }
    295177
    296     /** Method to remove a piece of metadata.
    297       * @param metadata The <strong>CollectionMeta</strong> you wish to remove.
    298       */
    299     public void removeMetadata(CollectionMeta metadata) {
    300     removeElement(metadata);
    301     gatherer.c_man.configurationChanged();
    302     }
    303     /** Method which attempts to reparse obvious metadata commands which used unresovable references.
    304       */
    305     public void reparseUnresolved() {
    306     for(int i = 0; i < unresolved_commands.size(); i++) {
    307         parse((String)unresolved_commands.get(i), true);
     178    /** Removes all of the metadata with a certain name, regardless of language or value. */
     179    public void removeMetadata(String name) {
     180    boolean removed_entry = false;
     181    for(int i = getSize(); i != 0; i--) {
     182        CollectionMeta other = (CollectionMeta) getElementAt(i - 1);
     183        if(name.equals(other.getName())) {
     184        remove(i - 1);
     185        removed_entry = true;
     186        }
     187        other = null;
     188    }   
     189    if(removed_entry) {
     190        Gatherer.c_man.configurationChanged();
    308191    }
    309     // Regardless of if they work, clear the commands.
    310     unresolved_commands.clear();
    311     }
    312     /** Sets the value of a certain metadata.
    313       * @param name The name of the metadata as a <strong>String</strong>.
    314       * @param language The <strong>Language</strong> to use.
    315       * @param value The value of the metadata also as a <strong>String</strong>.
    316       */
    317     public void setMetadata(String name, Language language, String value) {
    318     addMetadata(new CollectionMeta(manager, name, language, value));
    319     }
    320     /** Method to produce the list of metadata in a string such as you would find in the collection configuration file.
    321       * @return A <strong>String</strong> containing the list of collection metadata.
    322       */
    323     public String toString() {
    324     // We sort the metadata first.
    325     ArrayList metadatum = new ArrayList();
    326     for(int i = 0; i < size(); i++) {
    327         metadatum.add(get(i));
    328     }
    329     Collections.sort(metadatum, new CollectionMetaComparator());
    330     // Now we print them
    331     StringBuffer text = new StringBuffer("");
    332     for(int i = 0; i < metadatum.size(); i++) {
    333         CollectionMeta data = (CollectionMeta) metadatum.get(i);
    334         if(data.valid()) {
    335         text.append(data.toString());
    336         }
    337     }
    338     metadatum = null;
    339     text.append("\n");
    340     return text.toString();
    341     }
    342     /** Overloaded to call get with both a key and an empty argument array.
    343       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    344       * @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.
    345       */
    346     private String get(String key) {
    347     return get(key, null);
    348     }
    349     /** 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>
    350       * 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>.
    351       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    352       * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
    353       * @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.
    354       * @see org.greenstone.gatherer.Gatherer
    355       * @see org.greenstone.gatherer.Dictionary
    356       */
    357     private String get(String key, String args[]) {
    358     if(key.indexOf('.') == -1) {
    359         key = "CDM.CollectionMetaManager." + key;
    360     }
    361     return gatherer.dictionary.get(key, args);
    362192    }
    363193
    364     private class CollectionMetaComparator
    365     implements Comparator {
    366     public int compare(Object o1, Object o2) {
    367         String s1 = o1.toString();
    368         String s2 = o2.toString();
    369         if(s1.startsWith(".")) {
    370         return 1;
    371         }
    372         else if(s2.startsWith(".")) {
    373         return -1;
    374         }
    375         return o1.toString().compareTo(o2.toString());
    376     }
    377     public boolean equals(Object o2) {
    378         return (compare(this, o2) == 0);
    379     }
     194    public int size() {
     195    return getSize();
    380196    }
    381197}
  • trunk/gli/src/org/greenstone/gatherer/cdm/Format.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    4528/**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    4929 * Written:      06/05/02
    5030 * Revised:      04/10/02 - Commented
     31 *               14/07/03 - DOM Support
    5132 **************************************************************************************/
     33import org.greenstone.gatherer.cdm.CollectionConfiguration;
     34import org.greenstone.gatherer.cdm.CollectionDesignManager;
    5235import org.greenstone.gatherer.cdm.Classifier;
    53 /** This class encapsulates all the information about a format command from the collection configuration. This includes both the 'general' formatting commands, and the commands targetted at specific classifiers or classification component types.
     36import org.greenstone.gatherer.cdm.DOMProxyListEntry;
     37import org.greenstone.gatherer.msm.MSMUtils;
     38import org.w3c.dom.*;
     39/** This class encapsulates all the information about a format command from the collection configuration. This includes both the 'general' formatting commands, and the commands targetted at specific classifiers or classification component types. This class is, unfortunately, the most complex in terms of DOM model support, since we have to maintain a live reference to any classifier this format applies to. We temporarily use the feature name as the format name attribute but since the order of classifiers can change, this of course gets horribly out of date. Before the CollectionDesignManager saves the CollectionConfiguration it calls a method in the FormatManager to force all of the Formats to update their name attributes.
    5440 * @author John Thompson, Greenstone Digital Library, University of Waikato
    5541 * @version 2.3
    5642 */
    57 public 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;
     43public class Format
     44    implements DOMProxyListEntry {
     45
    7246    /** The default features as specified by the Greenstone Developers manual. */
    7347    static final public String DEFAULT_FEATURES[] = {"", "DocumentArrowsBottom","DocumentButtons","DocumentContents","DocumentHeading","DocumentImages","DocumentText","DocumentUseHTML","Search"};
    7448    /** The list of known feature parts. */
    7549    static final public String DEFAULT_PARTS[] = {"","DateList","HList","Invisible","VList"};
     50
     51    /** Not all features have an associated part, such as those in the default features list (apart from Search which does have parts!) */
     52    static public boolean canHavePart(String name) {
     53    return !(name.equalsIgnoreCase(DEFAULT_FEATURES[1]) || name.equalsIgnoreCase(DEFAULT_FEATURES[2]) || name.equalsIgnoreCase(DEFAULT_FEATURES[3]) || name.equalsIgnoreCase(DEFAULT_FEATURES[4]) || name.equalsIgnoreCase(DEFAULT_FEATURES[5]) || name.equalsIgnoreCase(DEFAULT_FEATURES[6]) || name.equalsIgnoreCase(DEFAULT_FEATURES[7]));
     54    }
     55
     56    static public boolean isParamType(String name) {
     57    return (name.equalsIgnoreCase(DEFAULT_FEATURES[1]) || name.equalsIgnoreCase(DEFAULT_FEATURES[3]) || name.equalsIgnoreCase(DEFAULT_FEATURES[5]) || name.equalsIgnoreCase(DEFAULT_FEATURES[7]));
     58    }
     59
     60    /** If this format is altering a Classifier then this is the classifier in question. */
     61    private Classifier classifier = null;
     62    /** The element this format is based on. */
     63    private Element element = null;
     64    /** We keep a copy of the part because its slightly more computationally tricky to calculate. */
     65    private String part = null;
     66    /** Cached result of toString. */
     67    private String text = null;
     68
     69    /** Constructor only to be used during DOMProxyListModel initialization. */
     70    public Format() {
     71    }
     72
     73    public Format(Element element) {
     74    this.element = element;
     75    // Immediately check if we are dealing with a classifier, by retrieving the feature name. If it is a classifier, then restore the live reference immediately before anything changes it.
     76    Object object = getFeature();
     77    if(object instanceof Classifier) {
     78        classifier = (Classifier) object;
     79    }
     80    else {
     81        String feature = (String) object;
     82        if(feature.toUpperCase().startsWith(Classifier.CLASSIFIER_PREFIX)) {
     83        // Extract the integer index
     84        int index = Integer.parseInt(feature.substring(Classifier.CLASSIFIER_PREFIX.length()));
     85        // Subtract one (as java is 0-2 where G2 is 1-3)
     86        index = index - 1;
     87        // Retrieve the appropriate classifier
     88        classifier = CollectionDesignManager.classifier_manager.getClassifier(index);
     89        }
     90    }
     91    }
     92
    7693    /** Constructor for a flag format command.
    7794     * @param feature The <Strong>Object</strong> this format affects.
     
    8097     */
    8198    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     }
     99    element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.FORMAT_ELEMENT);
     100    setName(feature, part);
     101    setState(state);
     102    }
     103
    87104    /** Constructor for a format-string format command.
    88105     * @param feature The <Strong>Object</strong> this format affects.
     
    91108     */
    92109    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     }
     110    element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.FORMAT_ELEMENT);
     111    setName(feature, part);
     112    setValue(value);
     113    }
     114
     115    public boolean canHavePart() {
     116    return canHavePart(getName());
     117    }
     118
     119    public int compareTo(Object object) {
     120    if(object == null) { // It seems that occasionally compareTo is called and somehow null ends up in comparison.
     121        return -1;
     122    }
     123    if(object instanceof Format && element != null) {
     124        return element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE).compareTo(((Format)object).getName());
     125    }
     126    return toString().compareTo(object.toString());
     127    }
     128
     129    public DOMProxyListEntry create(Element element) {
     130    return new Format(element);
     131    }
     132
     133    public boolean equals(Object object) {
     134    return (compareTo(object) == 0);
     135    }
     136
     137    public Element getElement() {
     138    return element;
     139    }
     140
    98141    /** Method to retrieve the value of feature, which may either be a String or a Classifier.
    99142     * @return The value of feature as an <strong>Object</strong>.
    100143     */
    101144    public Object getFeature() {
    102     return feature;
    103     }
    104     /** Method to retrieve the value of part.
     145    if(classifier != null) {
     146        return classifier;
     147    }
     148    else if(element != null) {
     149        String name = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
     150        // Remove part
     151        String part = getPart();
     152        String feature;
     153        if(part != null) {
     154        feature = name.substring(0, name.length() - part.length());
     155        }
     156        else {
     157        feature = name;
     158        }
     159        part = null;
     160        name = null;
     161        // If the feature now refers to a classifier, retrieve it.
     162        if(feature.toUpperCase().startsWith(Classifier.CLASSIFIER_PREFIX)) {
     163        // Extract the integer index
     164        int index = Integer.parseInt(feature.substring(Classifier.CLASSIFIER_PREFIX.length()));
     165        // Subtract one (as java is 0-2 where G2 is 1-3)
     166        index = index - 1;
     167        // Retrieve the appropriate classifier
     168        classifier = CollectionDesignManager.classifier_manager.getClassifier(index);
     169        return classifier;
     170        }
     171        else {
     172        return feature;
     173        }
     174    }
     175    else {
     176        return "Error";
     177    }
     178    }
     179
     180    public String getName() {
     181    if(element != null) {
     182        return element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
     183    }
     184    return "Error";
     185    }
     186
     187    /** Method to retrieve the value of part. Of course there may not be one, in which case return ""
    105188     * @return The value of part as a <Strong>String</strong>.
    106189     */
    107190    public String getPart() {
     191    if(part == null && element != null) {
     192        // To determine a part, we retrieve the Format name, then look for one of our recognized parts
     193        String name = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
     194        // DEFAULT_PARTS[0] is an empty string to correctly enable comboboxes.
     195        name = name.toLowerCase();
     196        for(int i = 1; part == null && i < DEFAULT_PARTS.length; i++) {
     197        if(name.endsWith(DEFAULT_PARTS[i].toLowerCase())) {
     198            part = DEFAULT_PARTS[i];
     199        }
     200        }
     201        if(part == null) {
     202        part = DEFAULT_PARTS[0];
     203        }
     204    }
    108205    return part;
    109206    }
    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     }
     207
    126208    /** Method to retrieve the value of state.
    127      * @param The value of state as a <i>boolean</i>.
     209     * @return value of state as a <i>boolean</i>.
    128210     */
    129211    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     }
     212    return (element != null && element.getAttribute(CollectionConfiguration.VALUE_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR));
     213    }
     214
    138215    /** Retrieve the value of value.
    139216     * @return A <strong>String</strong> which is the value of value.
    140217     */
    141218    public String getValue() {
     219    String value = "Error";
     220    if(element != null) {
     221        value = MSMUtils.getValue(element);
     222    }
    142223    return value;
    143224    }
     225
     226    public boolean isAssigned() {
     227    return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
     228    }
     229
     230    public boolean isParamType() {
     231    return (element != null && element.getAttribute(CollectionConfiguration.VALUE_ATTRIBUTE).length() > 0);
     232    }
     233
     234    public void setAssigned(boolean assigned) {
     235    if(element != null) {
     236        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     237    }
     238    }
     239
     240    public void setElement(Element element) {
     241    this.element = element;
     242    part = null;
     243    text = null;
     244    // Establish the classifier reference, if necessary
     245    getFeature();
     246    }
     247
     248    public void setName(Object feature, String part) {
     249    // Can't do anything unless an element exists.
     250    if(element != null) {
     251        this.part = part; // Easier for later on.
     252        if(feature instanceof Classifier) {
     253        classifier = (Classifier) feature;
     254        element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, classifier.getPositionString() + part);
     255        }
     256        else {
     257        element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, feature.toString() + part);
     258        }
     259        text = null;
     260    }
     261    }
     262
    144263    /** Set the value of state.
    145264     * @param state The new value for state as a <i>boolean</i>.
    146265     */
    147266    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     }
     267    if(element != null) {
     268        element.setAttribute(CollectionConfiguration.VALUE_ATTRIBUTE, (state ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     269        text = null;
     270    }
     271    }
     272
    156273    /** Set the value of value. Hmmm.
    157274     * @param value The new value from value as a <strong>String</strong>.
    158275     */
    159276    public void setValue(String value) {
    160     this.value = value;
    161     }
     277    if(element != null) {
     278        MSMUtils.setValue(element, value);
     279        text = null;
     280    }
     281    }
     282
    162283    /** Method to translate this classes information into a line of text as you would expect in the collection configuration file.
    163284     * @return A <strong>String</strong> containing the format command.
    164285     */
    165286    public String toString() {
    166     String text = "format ";
    167     text = text + getPosition() + " ";
    168     switch(type) {
    169     case FLAG:
    170         if(state) {
    171         text = text + "true";
     287    if(text == null && element != null) {
     288        StringBuffer temp = new StringBuffer(CollectionConfiguration.FORMAT_STR);
     289        temp.append(" ");
     290        temp.append(element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE));
     291        temp.append(" ");
     292        String value = element.getAttribute(CollectionConfiguration.VALUE_ATTRIBUTE);
     293        if(value.length() > 0) {
     294        temp.append(value);
    172295        }
    173296        else {
    174         text = text + "false";
    175         }
    176         break;
    177     default:
    178         text = text + "\"" + value + "\"";
     297        temp.append("\"");
     298        temp.append(MSMUtils.getValue(element));
     299        temp.append("\"");
     300        }
     301        text = temp.toString();
     302        temp = null;
    179303    }
    180304    return text;
    181305    }
    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;
     306
     307    public void update() {
     308    if(classifier != null) {
     309        element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, classifier.getPositionString() + getPart());
     310        text = null;
     311    }
    197312    }
    198313}
  • trunk/gli/src/org/greenstone/gatherer/cdm/FormatManager.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    4528/**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    49  * Written:        /05/02
    50  * Revised:      04/10/02 - Commented
     29 * Written:     06/05/02
     30 * Revised:     04/10/02 - Commented
     31 *              14/07/03 - DOM support
    5132 **************************************************************************************/
    52 import java.awt.BorderLayout;
    53 import java.awt.CardLayout;
    54 import java.awt.Color;
    55 import java.awt.Dimension;
    56 import java.awt.GridLayout;
    57 import java.awt.event.ActionEvent;
    58 import java.awt.event.ActionListener;
    59 import java.awt.event.KeyAdapter;
    60 import java.awt.event.KeyEvent;
    61 import java.util.ArrayList;
    62 import java.util.Collections;
    63 import java.util.Vector;
    64 import javax.swing.BorderFactory;
    65 import javax.swing.BoxLayout;
    66 import javax.swing.ButtonGroup;
    67 import javax.swing.DefaultComboBoxModel;
    68 import javax.swing.JButton;
    69 import javax.swing.JCheckBox;
    70 import javax.swing.JComboBox;
    71 import javax.swing.JLabel;
    72 import javax.swing.JList;
    73 import javax.swing.JPanel;
    74 import javax.swing.JScrollPane;
    75 import javax.swing.JTabbedPane;
    76 import javax.swing.JTextArea;
    77 import javax.swing.JTextField;
    78 import javax.swing.JToggleButton;
    79 import javax.swing.ListSelectionModel;
    80 import javax.swing.event.ListSelectionEvent;
    81 import javax.swing.event.ListSelectionListener;
     33import java.awt.*;
     34import java.awt.event.*;
     35import java.util.*;
     36import javax.swing.*;
     37import javax.swing.event.*;
    8238import org.greenstone.gatherer.Gatherer;
    8339import org.greenstone.gatherer.cdm.Classifier;
    8440import org.greenstone.gatherer.cdm.ClassifierManager;
     41import org.greenstone.gatherer.cdm.CollectionConfiguration;
    8542import org.greenstone.gatherer.cdm.CollectionDesignManager;
    8643import org.greenstone.gatherer.cdm.CommandTokenizer;
    87 import org.greenstone.gatherer.cdm.DynamicListModel;
     44import org.greenstone.gatherer.cdm.Control;
     45import org.greenstone.gatherer.cdm.DOMProxyListModel;
    8846import org.greenstone.gatherer.cdm.Format;
    8947import org.greenstone.gatherer.msm.ElementWrapper;
    9048import org.greenstone.gatherer.util.Utility;
     49import org.w3c.dom.*;
    9150/** This class maintains a list of format statements, and allows the addition and removal of these statements.
    9251 * @author John Thompson, Greenstone Digital Library, University of Waikato
     
    9453 */
    9554public 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;
     55    extends DOMProxyListModel {
     56
    9957    /** The controls used to edit the format commands. */
    10058    private Control controls = null;
    10159    /** 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;
     60    private DOMProxyListModel model = null;
     61
     62    /** Constructor. */
     63    public FormatManager() {
     64    super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.FORMAT_ELEMENT, new Format());
    11565    this.model = this;
    116     this.unresolved_commands = new Vector();
     66    Gatherer.println("FormatManager: parsed " + getSize() + " format statements.");
     67    // Establish all of the format objects, so that classifier indexes are initially correct (subsequent refreshes of the model will be sufficient to keep these up to date, as long as we start with a live reference to a classifier.
     68    int size = getSize();
     69    for(int i = 0; i < size; i++) {
     70        getElementAt(i);
     71    }
    11772    }
    11873    /** Method to add a new format to this manager.
     
    12075      */
    12176    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.
    128       * @param format The <strong>Format</strong> whose uniqueness we want to check.
    129       * @return The <strong>Format</strong> that matches the one given, or <i>null</i> if no such format exists.
    130       */
    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     }
     77    if(!contains(format)) {
     78        Element element = format.getElement();
     79        // Locate where we should insert this new classifier.
     80        Node target_node = CollectionConfiguration.findInsertionPoint(element);
     81        add(root, format, target_node);
     82        Gatherer.c_man.configurationChanged();
     83    }
     84    }
     85
     86    public void destroy() {
     87    if(controls != null) {
     88        controls.destroy();
     89        controls = null;
     90    }
     91    }
     92
    14093    /** Gets the format indicated by the index.
    141       * @param index The location of the desired format, as an <i>int</i>.
    142       */
     94     * @param index The location of the desired format, as an <i>int</i>.
     95     */
    14396    public Format getFormat(int index) {
    144     return (Format)get(index);
    145     }
     97    Format result = null;
     98    if(0 < index && index < getSize()) {
     99        result = (Format) getElementAt(index);
     100    }
     101    return result;
     102    }
     103   
    146104    /** Method to retrieve this managers controls.
    147       * @return The <strong>Control</strong> for this collection.
    148       */
     105     * @return the Control for this collection.
     106     */
    149107    public Control getControls() {
    150108    if(controls == null) {
    151         controls = new Control();
     109        controls = new FormatControl();
    152110    }
    153111    return controls;
    154112    }
    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.
    163       * @param command The <strong>String</strong> we are trying to parse a command from.
    164       * @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.
    165       * @return A <i>boolean</i> which is <i>true</i> if we managed to parse a command, <i>false</i> otherwise.
    166       * @see org.greenstone.gatherer.cdm.Classifier
    167       * @see org.greenstone.gatherer.cdm.CommandTokenizer
    168       * @see org.greenstone.gatherer.cdm.Format
    169       */
    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;
    287         }
    288         else {
    289         // Ensure we have enough tokens for a format command
    290         CommandTokenizer ct = new CommandTokenizer(command);
    291         while(ct.countTokens() < 3) {
    292             command = manager.parseMore(command);
    293             ct = new CommandTokenizer(command);
    294         }
    295         unresolved_commands.add(command);
    296         }
    297         return true;
    298     }
    299     return false;
    300     }
     113
    301114    /** Method to remove a format.
    302       * @param format The <strong>Format</strong> to remove.
    303       */
     115     * @param format The <strong>Format</strong> to remove.
     116     */
    304117    public void removeFormat(Format format) {
    305     removeElement(format);
    306     gatherer.c_man.configurationChanged();
    307     }
    308     /** Method which attempts to reparse obvious format commands which previously referenced unresovable Classifiers.
    309     */
    310     public void reparseUnresolved() {
    311     for(int i = 0; i < unresolved_commands.size(); i++) {
    312         if(!parse((String)unresolved_commands.get(i), true)) {
    313         ///ystem.err.println("*** Error: Command " + unresolved_commands.get(i));
    314         }
    315     }
    316     // Regardless of if they work, clear the commands.
    317     unresolved_commands.clear();
    318     }
    319     /** Method to produce a block of text representing the format commands in this manager, ready to be used in the collection configuration file.
    320     * @return A <strong>String</strong> containing a series of format commands.
    321     */
    322     public String toString() {
    323     StringBuffer text = new StringBuffer("");
    324     for(int i = 0; i < size(); i++) {
    325         Format format = (Format) get(i);
    326         text.append(format.toString());
    327         text.append("\n");
    328     }
    329     text.append("\n");
    330     return text.toString();
    331     }
     118    remove(format);
     119    Gatherer.c_man.configurationChanged();
     120    }
     121
    332122    /** Overloaded to call get with both a key and an empty argument array.
    333       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    334       * @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.
    335       */
     123     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     124     * @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.
     125     */
    336126    private String get(String key) {
    337127    return get(key, null);
    338128    }
     129
    339130    /** 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>
    340       * 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>.
    341       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    342       * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
    343       * @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.
    344       * @see org.greenstone.gatherer.Gatherer
    345       * @see org.greenstone.gatherer.Dictionary
    346       */
     131     * 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>.
     132     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     133     * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
     134     * @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.
     135     * @see org.greenstone.gatherer.Gatherer
     136     * @see org.greenstone.gatherer.Dictionary
     137     */
    347138    private String get(String key, String args[]) {
    348139    if(key.indexOf('.') == -1) {
    349140        key = "CDM.FormatManager." + key;
    350141    }
    351     return gatherer.dictionary.get(key, args);
    352     }
    353     private class Control
    354     extends JPanel {
     142    return Gatherer.dictionary.get(key, args);
     143    }
     144
     145    private class FormatControl
     146    extends JPanel
     147    implements Control {
    355148    /** Do we ignore selection changing events (mainly because we're generating them!) */
    356149    private boolean ignore = false;
     
    404197    private Vector part_model = null;
    405198    private Vector special_model = null;
    406     public Control() {
    407         ArrayList feature_model = new ArrayList();
    408                 // Add the set options
    409         for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
    410         feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
    411         }
    412                 // Now the classifiers.
    413         for(int j = 0; j < manager.classifiers.size(); j++) {
    414         feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
    415         }
    416         Collections.sort(feature_model);
     199    public FormatControl() {
     200        ArrayList feature_model = buildFeatureModel();
    417201        part_model = new Vector();
    418202        part_model.add("");//get("Custom"));
     
    430214        special_model.add("[parent(Top):_]");
    431215        special_model.add("[parent(All'_'):_]");
    432         Vector elements = gatherer.c_man.msm.getAssignedElements();
     216        Vector elements = Gatherer.c_man.getCollection().msm.getAssignedElements();
    433217        for(int i = 0; i < elements.size(); i++) {
    434218        special_model.add("[" + ((ElementWrapper)elements.get(i)).toString() + "]");
    435219        }
    436220        Collections.sort(special_model);
    437                 // Create
     221        // Create
    438222        add = new JButton(get("Add"));
    439223        add.setEnabled(false);
     
    443227        control_pane = new JPanel();
    444228        editor = new JTextArea();
    445         editor.setBackground(Color.white);
     229        editor.setBackground(Gatherer.config.getColor("coloring.editable", false));
    446230        editor.setCaretPosition(0);
    447231        editor.setLineWrap(true);
    448         editor.setWrapStyleWord(true);
     232        editor.setWrapStyleWord(false);
    449233        editor_label = new JLabel(get("Editor"));
    450234        editor_label.setHorizontalAlignment(JLabel.CENTER);
     
    496280        value_pane = new JPanel();
    497281        view_pane = new JPanel();
    498                 // Connect
     282        // Connect
    499283        add.addActionListener(new AddListener());
    500284        button_group.add(on);
    501285        button_group.add(off);
    502         editor.addKeyListener(new EditorListener());
     286        editor.getDocument().addDocumentListener(new EditorListener());
    503287        feature.addActionListener(new FeatureListener());
    504288        format_list.addListSelectionListener(new FormatListListener());
     
    596380        ready = true;
    597381    }
     382
    598383    public void destroy() {
    599384    }
     385
    600386    /** Overriden to ensure that the instructions pane is scrolled to the top.
    601             */
    602     public void updateUI() {
     387     */
     388    public void gainFocus() {
     389        // This is only necessary if the components have been realized
    603390        if(ready) {
    604         // Rebuild feature model.
    605         ArrayList feature_model = new ArrayList();
    606         // Add the set options
    607         for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
    608             feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
    609         }
    610         // Now the classifiers.
    611         for(int j = 0; j < manager.classifiers.size(); j++) {
    612             feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
    613         }
     391        model.refresh();
     392        ArrayList feature_model = buildFeatureModel();
     393        // Remember the current selection
     394        Object selected_object = feature.getSelectedItem();
    614395        feature.setModel(new DefaultComboBoxModel(feature_model.toArray()));
     396        // Now resotre the selected object as best as possible
     397        feature.setSelectedItem(selected_object);
    615398        if(instructions != null) {
    616399            instructions.setCaretPosition(0);
    617400        }
    618         }
    619         super.updateUI();
    620     }
    621 
    622 
     401        }   
     402    }
     403
     404    public void loseFocus() {
     405        // Force all of the Formats to update their names with the correct values.
     406        int size = model.getSize();
     407        for(int i = 0; i < size; i++) {
     408        Format format = (Format) model.getElementAt(i);
     409        format.update();
     410        }
     411    }
     412
     413    private ArrayList buildFeatureModel() {
     414        // Rebuild feature model.
     415        ArrayList feature_model = new ArrayList();
     416        // Add the set options
     417        for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
     418        feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
     419        }
     420        // Now the classifiers.
     421        for(int j = 0; j < CollectionDesignManager.classifier_manager.getSize(); j++) {
     422        feature_model.add(new Entry(CollectionDesignManager.classifier_manager.getClassifier(j)));
     423        }
     424        Collections.sort(feature_model);
     425        return feature_model;
     426    }
    623427
    624428    /** Formats the formatting string so that it contains safe characters and isn't enclosed in speech marks etc. (Ironic eh?)
    625             * @see java.lang.StringBuffer
    626             */
     429     * @see java.lang.StringBuffer
     430     */
    627431    private String format(String raw) {
    628432        String safe = null;
     
    665469        return raw;
    666470    }
     471
    667472    /** Listens for clicks on the add button, and if the relevant details are provided adds a new format. */
    668473    private class AddListener
    669474        implements ActionListener {
    670475        public void actionPerformed(ActionEvent event) {
    671         ignore = true;
     476        //ignore = true;
    672477        Entry entry = (Entry)feature.getSelectedItem();
    673478        Object f = entry.getFeature();
     
    685490        format_list.setSelectedValue(current_format, true);
    686491        new_entry = false;
    687         ignore = false;
    688         }
    689     }
     492        //ignore = false;
     493        }
     494    }
     495
    690496    private class EditorListener
    691         extends KeyAdapter {
    692         public void keyReleased(KeyEvent event) {
     497        implements DocumentListener {
     498 
     499        public void changedUpdate(DocumentEvent e) {
     500        update();
     501        }
     502         
     503        public void insertUpdate(DocumentEvent e) {
     504        update();
     505        }
     506         
     507        public void removeUpdate(DocumentEvent e) {
     508        update();
     509        }
     510
     511        public void update() {
    693512        String safe = format(editor.getText());
    694513        if(!ignore && current_format != null) {
     
    700519            current_format.setValue("");
    701520            }
    702             gatherer.c_man.configurationChanged();
    703             model.refresh();
     521            Gatherer.c_man.configurationChanged();
     522            model.refresh(current_format);
    704523        }
    705524        Entry entry = (Entry) feature.getSelectedItem();
     
    713532        }
    714533    }
     534
    715535    /** 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. */
    716536    private class Entry
     
    781601        }
    782602    }
     603
    783604    private class FeatureListener
    784605        implements ActionListener {
     
    788609            Entry entry = (Entry) feature.getSelectedItem();
    789610            String name = entry.toString();
    790             int type = Format.getType(name);
    791             switch(type) {
    792             case Format.FLAG:
     611            if(Format.isParamType(name)) {
    793612            // Flags first.
    794613            part.setEnabled(false);
     
    797616            view_type = FLAG;
    798617            add.setEnabled(true); // One of the options must be selected.
    799             break;
    800             default:
     618            }
     619            else {
    801620            part.setEnabled(true);
    802621            part_pane.add(part, BorderLayout.CENTER);
     
    815634        }
    816635    }
     636
    817637    private class FormatListListener
    818638        implements ListSelectionListener {
     
    825645            Entry an_entry = new Entry(current_format.getFeature());
    826646            feature.setSelectedItem(an_entry);
    827             // Try to match the part.
    828             part.setSelectedItem(current_format.getPart());
     647            // If we didn't match anything, add it and select it again
     648            Entry result_entry = (Entry) feature.getSelectedItem();
     649            if(!an_entry.equals(result_entry)) {
     650                feature.insertItemAt(an_entry, feature.getItemCount());
     651                feature.setSelectedItem(an_entry);
     652            }
     653           
     654            if(current_format.canHavePart()) {
     655                part.setEnabled(true);
     656                // Try to match the part.
     657                String part_entry = current_format.getPart();
     658                part.setSelectedItem(part_entry);
     659                // If we didn't match anything, add it and select it again
     660                String selected_part = (String)part.getSelectedItem();
     661                if(!part_entry.equals(selected_part)) {
     662                part.insertItemAt(part_entry, part.getItemCount());
     663                feature.setSelectedItem(part_entry);
     664                }
     665            }
     666            else {
     667                part.setEnabled(false);
     668            }
    829669            // Now use type to determine what controls are visible, and what have initial values.
    830             switch(current_format.getType()) {
    831             case Format.FLAG:
     670            if(current_format.isParamType()) {
    832671                // Flags first.
    833672                part.setEnabled(false);
     
    839678                off.setSelected(!current_format.getState());
    840679                add.setEnabled(false); // Can only update
    841                 break;
    842             default:
     680            }
     681            else {
    843682                part.setEnabled(true);
    844683                part_pane.add(part, BorderLayout.CENTER);
     
    907746            // We have just performed an edit. Immediately update the format and model.
    908747            current_format.setState(on.isSelected());
    909             model.refresh();
     748            model.refresh(current_format);
    910749        }
    911750        }
     
    917756            // We have just performed an edit. Immediately update the format and model.
    918757            current_format.setValue(value.getText());
    919             model.refresh();
     758            model.refresh(current_format);
    920759        }
    921760        }
  • trunk/gli/src/org/greenstone/gatherer/cdm/Index.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    44 /**************************************************************************************
    45  * Title:        Gatherer
    46  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    47  * Copyright:    Copyright (c) 2001
    48  * Company:      The University of Waikato
    49  * Written:      03/05/02
    50  * Revised:      17/11/02
    51  **************************************************************************************/
    52 import java.util.Collections;
    53 import java.util.Comparator;
    54 import java.util.StringTokenizer;
    55 import java.util.Vector;
     28
     29import java.util.*;
     30import org.greenstone.gatherer.Gatherer;
     31import org.greenstone.gatherer.cdm.CollectionConfiguration;
     32import org.greenstone.gatherer.cdm.CollectionDesignManager;
    5633import org.greenstone.gatherer.cdm.CollectionMeta;
     34import org.greenstone.gatherer.cdm.DOMProxyListEntry;
     35import org.greenstone.gatherer.msm.ElementWrapper;
    5736import org.greenstone.gatherer.msm.MSMUtils;
     37import org.greenstone.gatherer.util.StaticStrings;
    5838import org.greenstone.gatherer.util.Utility;
    59 import org.w3c.dom.Element;
     39import org.w3c.dom.*;
    6040/** This class encapsulates a single indexing pair.
    6141 * @author John Thompson, Greenstone Digital Library, University of Waikato
    62  * @version 2.2
     42 * @version 2.3d
    6343 */
    6444public class Index
    65     implements Comparable {
    66     /** A refernce to the main manager for access to other sub-managers. */
    67     private CollectionDesignManager manager = null;
    68     /** The level of this index. */
    69     private int level = 0;
    70     /** The sources for data this index is built apon, which are either fully qualified metadata element names or 'text'. */
    71     private Vector sources = null;
    72     /** An element in the index level enumeration. */
    73     static public final int DOCUMENT = 0;
    74     /** An element in the index level enumeration. */
    75     static public final int PARAGRAPH = 1;
    76     /** An element in the index level enumeration. */
    77     static public final int SECTION = 2;
     45    implements Comparable, DOMProxyListEntry {
    7846    /** An values of items in the index level enumeration. */
    7947    static public final String LEVEL[] = {"document","paragraph","section"};
    8048
    81     /** Constructor.
    82      * @param level The level of this index as a <strong>String</string>.
    83      * @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".
    84      */
    85     public Index(int level, Vector sources, CollectionDesignManager manager) {
     49    private ArrayList sources = null;
     50    /** The level of this index (if old sckool MG). */
     51    private int level = -1;
     52    /** The element this index is based upon. */
     53    private Element element = null;
     54    /** The unique, if cryptic, identifier of an index. */
     55    private String id = null;
     56
     57    /** Default constructor, which should only be used during DOMProxyListModel creation. */
     58    public Index() {
     59    }
     60
     61    /** Constructor. */
     62    public Index(Element element) {
     63    this.element = element;
     64    }
     65
     66    /** Constructor for a newly assigned index. */
     67    public Index(ArrayList sources) {
     68    this.sources = sources;
     69    // Create a new element
     70    Document document = CollectionDesignManager.collect_config.document;
     71    element = document.createElement(CollectionConfiguration.INDEX_ELEMENT);
     72    // For each source add a content element
     73    int size = sources.size();
     74    for(int i = 0; i < size; i++) {
     75        Element content_element = document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
     76        Object source_object = sources.get(i);
     77        if(source_object instanceof ElementWrapper) {
     78        content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, ((ElementWrapper)source_object).getName());
     79        }
     80        else {
     81        content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, source_object.toString());
     82        }
     83        element.appendChild(content_element);
     84        content_element = null;
     85    }
     86    document = null;
     87    }
     88
     89    /** Constructor for a newly assigned index with specified level (old skool). */
     90    public Index(int level, ArrayList sources) {
     91    this(sources);
    8692    this.level = level;
    87     this.manager = manager;
    88     this.sources = sources;
    89     if(this.sources == null) {
    90         this.sources = new Vector();
    91         this.sources.add("text");
    92     }
    93     }
     93    element.setAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE, LEVEL[level]);
     94    }
     95
    9496    /** Method to compare two indexes.
    95       * @param object The other index as an <strong>Object</strong>.
    96       * @return An <i>int</i> which indicates how the indexes compare.
    97       * @see java.lang.String
    98       */
     97     * @param object The other index as an <strong>Object</strong>.
     98     * @return An <i>int</i> which indicates how the indexes compare.
     99     * @see java.lang.String
     100     */
    99101    public int compareTo(Object object) {
    100     return toString(false).compareTo(object.toString());
    101     }
     102    return id.compareTo(((Index)object).getID());
     103    }
     104   
     105    public DOMProxyListEntry create(Element element) {
     106    return new Index(element);
     107    }
     108
    102109    /** Method to test for the equality of two indexes.
    103       * @param object The other index as an <strong>Object</strong>.
    104       * @return A <i>boolean</i> which is <i>true</i> if the two indexes are equal, <i>false</i> otherwise.
    105       */
     110     * @param object The other index as an <strong>Object</strong>.
     111     * @return A <i>boolean</i> which is <i>true</i> if the two indexes are equal, <i>false</i> otherwise.
     112     */
    106113    public boolean equals(Object object) {
    107     if(compareTo(object) == 0) {
    108         return true;
    109     }
    110     return false;
    111     }
    112     /** Method to get the data source of this index.
    113       * @return A <strong>String</string> which is a comma separated list of either fully qualified names of an assigned metadata elements, or "text".
    114       */
    115     public String getData() {
    116     String result = "";
    117     Collections.sort(sources, new IndexComparator());
    118     for(int i = 0; i < sources.size(); i++) {
    119         result = result + sources.get(i).toString();
    120         if(i < sources.size() - 1) {
    121         result = result + ",";
    122         }
    123     }
    124     return result;
    125     }
    126     /** Method to get the data source of this index.
    127      * @return A <strong>String</string> which is a comma separated list of either fully qualified names of an assigned metadata elements, or "text".
    128      * Note, greenstone extracted metadata do not have the ex.
    129      */
    130     public String getDataConfig() {
    131     String result = "";
    132     Collections.sort(sources, new IndexComparator());
    133     for(int i = 0; i < sources.size(); i++) {
    134         String source = sources.get(i).toString();
    135         if (source.startsWith(Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP)) {
    136         // remove the ex. bit
    137         source = source.substring(source.indexOf(MSMUtils.NS_SEP)+1);
    138         }
    139         result = result + source;
    140         if(i < sources.size() - 1) {
    141         result = result + ",";
    142         }
    143     }
    144     return result;
    145     }
    146    
     114    return (compareTo(object) == 0);
     115    }
     116   
     117    public Element getElement() {
     118    return element;
     119    }
     120   
    147121    /** Method to get the value of level.
    148       * @return The value of level as a <strong>String</strong>.
    149       */
     122     * @return the level as a int
     123     */
    150124    public int getLevel() {
     125    if(level == -1) {
     126        String level_str = element.getAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE);
     127        for(int i = 0; level == -1 && i < LEVEL.length; i++) {
     128        if(level_str.equals(LEVEL[i])) {
     129            level = i;
     130        }
     131        }
     132        level_str = null;
     133    }
    151134    return level;
    152135    }
    153     /** Method to get the value of metadata.
    154       * @return The value of metadata as an <strong>Vector</strong>.
    155       */
    156     public Vector getMetadata() {
     136
     137    public String getID() {
     138    if(id == null) {
     139        StringBuffer id_buffer = new StringBuffer();
     140        // Write level information, if any.
     141        int level = getLevel();
     142        if(0 <= level && level < 3) {
     143        id_buffer.append(LEVEL[level]);
     144        id_buffer.append(StaticStrings.COLON_CHARACTER);
     145        }
     146        // Write data information. Retrieve each of the content sources and add them in a comma separated list.
     147        ArrayList sources = getSources();
     148        int sources_size = sources.size();
     149        for(int i = 0; i < sources_size; i++) {
     150        Object source_object = sources.get(i);
     151        if(source_object instanceof ElementWrapper) {
     152            id_buffer.append(((ElementWrapper)source_object).getName());
     153        }
     154        else {
     155            id_buffer.append(source_object.toString());
     156        }
     157        id_buffer.append(StaticStrings.COMMA_CHARACTER);
     158        }
     159        sources = null;
     160        id = id_buffer.substring(0, id_buffer.length() - 1);
     161    }
     162    return id;
     163    }
     164
     165    /** Retrieve the sources of this index.
     166     * @return the sources as an ArrayList
     167     */
     168    public ArrayList getSources() {
     169    if(sources == null) {
     170        sources = new ArrayList();
     171        NodeList content_elements = element.getElementsByTagName(CollectionConfiguration.CONTENT_ELEMENT);
     172        int content_elements_length = content_elements.getLength();
     173        for(int i = 0; i < content_elements_length; i++) {
     174        Element content_element = (Element) content_elements.item(i);
     175        sources.add(content_element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE));
     176        }
     177        content_elements = null;
     178        Collections.sort(sources);
     179    }
    157180    return sources;
    158181    }
    159     /** Method to retrieve this indexes name.
    160       * @return A <strong>String</strong>.
    161       */
    162     public String getName() {
    163     if(manager != null) {
    164         String name = LEVEL[level] + ":" + getData();
    165         Language language = manager.languages.getDefaultLanguage();
    166         CollectionMeta metadata = manager.collectionmetadatum.getMetadata(name, language, true);
    167         if(metadata != null) {
    168         return metadata.getValue();
    169         }
    170     }
    171     return "";
    172    
    173     }
     182
     183    public boolean isAssigned() {
     184    return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
     185    }
     186
     187    public void setAssigned(boolean assigned) {
     188    if(element != null) {
     189        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     190    }
     191    }
     192
     193    public void setElement(Element element) {
     194    this.element = element;
     195    this.level = -1;
     196    this.id = null;
     197    this.sources = null;
     198    }
     199
     200    /** Method to set the level of this index which can only be used for the default index.
     201     * @param level the new level as an int
     202     */
     203    public void setLevel(int new_level) {
     204    if(element != null && element.getNodeName().equals(CollectionConfiguration.INDEX_DEFAULT_ELEMENT)) {
     205        element.setAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE, LEVEL[new_level]);
     206        this.id = null; // Regenerate ID.
     207        this.level = new_level;
     208    }
     209    else {
     210        Gatherer.println("Error! Called setLevel() of index other than the default.");
     211    }
     212    }
     213
     214    /** Method to set the sources for this index which can only be used for the default index.
     215     * @param sources an ArrayList of source names
     216     */
     217    public void setSources(ArrayList sources) {
     218    if(element != null && element.getNodeName().equals(CollectionConfiguration.INDEX_DEFAULT_ELEMENT)) {
     219        // Erase old sources
     220        MSMUtils.clear(element);
     221        // For each entry in the sources array add a new content element.
     222        int size = sources.size();
     223        for(int i = 0; i < size; i++) {
     224        Element content_element = element.getOwnerDocument().createElement(CollectionConfiguration.CONTENT_ELEMENT);
     225        content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, (String) sources.get(i));
     226        element.appendChild(content_element);
     227        content_element = null;
     228        }
     229        this.id = null; // Regenerate ID.
     230        this.sources = sources;
     231    }
     232    else {
     233        Gatherer.println("Error! Called setSource() of index other than the default.");
     234    }
     235    }
     236
    174237    /** Method to turn this object into a string representation ready to be placed in the collection configuration file.
    175       * @return A <strong>String</strong> containing the information of this class.
    176       */
     238     * @return A <strong>String</strong> containing the information of this class.
     239     */
    177240    public String toString() {
    178     return LEVEL[level] + ":" + getData();
    179     }
    180     /** Retrieve a textual representation of this index.
    181     * @param show_name <i>true</i> if you want the name of this index, <i>false</i> for the gsdl index reference.
    182     */
    183     public String toString(boolean show_name) {
    184     if(show_name) {
    185         return getName();
    186     }
    187     return LEVEL[level] + ":" + getData();
    188     }
    189    
    190     /** Retrieve a textual representation of this index, specifically for the configuration files. Extracted metadata is shown to teh user and stored as ex.MD, however in the config file it should have no namespace */
    191     public String toStringConfig() {
    192 
    193     return LEVEL[level] + ":" + getDataConfig();
    194     }
    195 
    196     /** Method to parse a configuration file index specification into an Index
    197      * object. returns null if invalid syntax */
    198     public static Index parseIndexConfig(String entry, CollectionDesignManager manager) {
    199     // all (mg) indexes must start with level:
    200     if(entry.indexOf(":") == -1) {
    201         return null;
    202     }
    203    
    204     String level_str = entry.substring(0, entry.indexOf(":"));
    205     String sources_raw = entry.substring(entry.indexOf(":") + 1);
    206     Vector sources = new Vector();
    207     StringTokenizer st = new StringTokenizer(sources_raw, ",");
    208     while(st.hasMoreTokens()) {
    209         String token = st.nextToken();
    210         // We may have to replace old : with whatever namespace separator we are using.
    211         token = token.replace(':', MSMUtils.NS_SEP);
    212         // if there is no namespace, we need to add one, except for text
    213         if (token.indexOf(MSMUtils.NS_SEP)==-1) {
    214         if (!token.equals("text")) {
    215             token = Utility.EXTRACTED_METADATA_NAMESPACE+MSMUtils.NS_SEP+token;
    216         }
    217         }
    218        
    219         sources.add(token);
    220     }
    221     Index index = null;
    222     for(int i = 0; i < Index.LEVEL.length; i++) {
    223         if(level_str.equals(Index.LEVEL[i])) {
    224         return new Index(i, sources, manager);
    225        
    226         }
    227     }
    228     // somethings gone wrong
    229     return null;
    230    
    231     }
    232    
    233     /** A custom comparator for comparing Indexes. */
    234     private class IndexComparator
    235     implements Comparator {
    236     /** Method to compare two objects, which may be either indexes or strings.
    237      * @param object1 One object as an <strong>Object</strong>.
    238      * @param object2 Another object as an <strong>Object</strong>.
    239      * @return An <i>int</i> which indicates how they compare.
    240      * @see java.lang.String
    241      */
    242     public int compare(Object object1, Object object2) {
    243         if(object1 instanceof Index && object2 instanceof Index) {
    244         Index index1 = (Index)object1;
    245         Index index2 = (Index)object2;
    246         return index1.toString(false).compareTo(index2.toString(false));
    247         }
    248         else if(object1 instanceof Index) {
    249         Index index = (Index) object1;
    250         return index.toString(false).compareTo(object2.toString());
    251         }
    252         else if(object2 instanceof Index) {
    253         Index index = (Index) object2;
    254         return object1.toString().compareTo(index.toString(false));
    255         }
    256         return object1.toString().compareTo(object2.toString());
    257     }
    258     /** Method to test for the equality of two objects, which may be indexes or strings.
    259             * @param object Another object as an <strong>Object</strong>.
    260             * @return A <i>boolean</i> which is <i>true</i> if the two objects are equal, <i>false</i> otherwise.
    261             */
    262     public boolean equals(Object object) {
    263         if(compareTo(object) == 0) {
    264         return true;
    265         }
    266         return false;
    267     }
     241    String id = getID();
     242    StringBuffer text = new StringBuffer(id);
     243    CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(StaticStrings.STOP_CHARACTER + id, false);
     244    if(metadatum != null) {
     245        text.append(" \"");
     246        text.append(metadatum.getValue());
     247        text.append("\"");
     248    }
     249    return text.toString();
    268250    }
    269251}
  • trunk/gli/src/org/greenstone/gatherer/cdm/IndexManager.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    44 /**************************************************************************************
    45  * Title:        Gatherer
    46  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    47  * Copyright:    Copyright (c) 2001
    48  * Company:      The University of Waikato
    49  * Written:      03/05/02
    50  * Revised:      17/11/02 - Commented
    51  **************************************************************************************/
    52 import java.awt.BorderLayout;
    53 import java.awt.Color;
    54 import java.awt.Component;
    55 import java.awt.Dimension;
    56 import java.awt.GridLayout;
    57 import java.awt.event.ActionEvent;
    58 import java.awt.event.ActionListener;
    59 import java.awt.event.KeyAdapter;
    60 import java.awt.event.KeyEvent;
    61 import java.util.Collections;
    62 import java.util.StringTokenizer;
    63 import java.util.Vector;
    64 import javax.swing.BorderFactory;
    65 import javax.swing.DefaultListCellRenderer;
    66 import javax.swing.DefaultListModel;
    67 import javax.swing.JButton;
    68 import javax.swing.JComboBox;
    69 import javax.swing.JLabel;
    70 import javax.swing.JList;
    71 import javax.swing.JOptionPane;
    72 import javax.swing.JPanel;
    73 import javax.swing.JScrollPane;
    74 import javax.swing.JTextArea;
    75 import javax.swing.JTextField;
    76 import javax.swing.event.ListDataEvent;
    77 import javax.swing.event.ListDataListener;
    78 import javax.swing.event.ListSelectionEvent;
    79 import javax.swing.event.ListSelectionListener;
     28import java.awt.*;
     29import java.awt.event.*;
     30import java.util.*;
     31import javax.swing.*;
     32import javax.swing.event.*;
    8033import org.greenstone.gatherer.Gatherer;
     34import org.greenstone.gatherer.cdm.CollectionMeta;
    8135import org.greenstone.gatherer.cdm.CommandTokenizer;
     36import org.greenstone.gatherer.cdm.Control;
     37import org.greenstone.gatherer.cdm.DOMProxyListModel;
    8238import org.greenstone.gatherer.cdm.Index;
    8339import org.greenstone.gatherer.msm.ElementWrapper;
    8440import org.greenstone.gatherer.msm.MSMUtils;
    8541import org.greenstone.gatherer.util.ExclusiveListSelectionListener;
    86 import org.w3c.dom.Element;
     42import org.greenstone.gatherer.util.StaticStrings;
     43import org.w3c.dom.*;
    8744/** 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.
    8845 * @author John Thompson, Greenstone Digital Library, University of Waikato
     
    9047 */
    9148public class IndexManager
    92     extends DefaultListModel {
    93     /** A reference to our creator, the collection design manager. */
    94     private CollectionDesignManager manager = null;
     49    extends DOMProxyListModel {
    9550    /** The controls for editing the indexes. */
    9651    private Control controls = null;
    9752    /** A reference to ourselves so our inner methods have access. */
    98     private DefaultListModel model = null;
    99     /** A reference to the Gatherer, for access to the Dictionary and messaging purposes. */
    100     private Gatherer gatherer = null;
     53    private DOMProxyListModel model = null;
    10154    /** The default index. */
    10255    private Index default_index = null;
    103     /** Constructor.
    104      * @param gatherer A reference to the <strong>Gatherer</strong>.
    105      * @param manager A reference to the <strong>CollectionDesignManager</strong>.
    106      */
    107     public IndexManager(Gatherer gatherer, CollectionDesignManager manager) {
    108     super();
    109     this.gatherer = gatherer;
    110     this.manager = manager;
    111     this.model = this;
     56    /** Constructor. */
     57    public IndexManager(Element indexes) {
     58    super(indexes, CollectionConfiguration.INDEX_ELEMENT, new Index());
     59    Gatherer.println("IndexManager: " + getSize() + " indexes parsed.");
     60    model = this;
     61    // Parse and retrieve the default index
     62    NodeList default_index_elements = CollectionDesignManager.collect_config.getDocumentElement().getElementsByTagName(CollectionConfiguration.INDEX_DEFAULT_ELEMENT);
     63    if(default_index_elements.getLength() > 0) {
     64        default_index = new Index((Element)default_index_elements.item(0));
     65    }
    11266    }
    11367    /** Method to add a new index.
    114       * @param index The <strong>Index</strong> to add.
    115       * @see org.greenstone.gatherer.Gatherer
    116       * @see org.greenstone.gatherer.collection.CollectionManager
    117       */
    118     public void addIndex(Index index) {
     68     * @param index The <strong>Index</strong> to add.
     69     * @see org.greenstone.gatherer.Gatherer
     70     * @see org.greenstone.gatherer.collection.CollectionManager
     71     */
     72    public void addIndex(Index index, CollectionMeta metadatum) {
     73    ///ystem.err.println("Adding an index: " + index.toString());
    11974    if(!contains(index)) {
    120         String index_str = index.toString(false).toLowerCase();
    121                 // Add alphabetically.
    122         for(int i = 0; i < size(); i++) {
    123         Index sibling = (Index) get(i);
    124         String sibling_str = sibling.toString(false).toLowerCase();
    125         int position = index_str.compareTo(sibling_str);
    126         // Sibling is before index.
    127         if(position > 0) {
    128             // Carry on.
    129         }
    130         // Index is equal to, or before sibling. Insert it.
    131         else if(position == 0 || position < 0) {
    132             add(i, index);
    133             gatherer.c_man.configurationChanged();
    134             return;
    135         }
    136         }
    137                 // If we got this far, we haven't inserted index, and we are out of model so.
    138         addElement(index);
    139         gatherer.c_man.configurationChanged();
     75        CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
     76        // Retrieve the currently last index
     77        Index last_index = (Index)getElementAt(getSize() - 1);
     78        addAfter(index, last_index);
     79        Gatherer.c_man.configurationChanged();
    14080    }
    14181    else {
    142         JOptionPane.showMessageDialog(manager.gui, get("CDM.IndexManager.Index_Exists"), get("General.Warning"), JOptionPane.WARNING_MESSAGE);
    143     }
    144     }
    145     /** Method to acquire the controls for editing the indexes.
    146       * @return A <strong>JPanel</strong> containing the controls.
    147       * @see org.greenstone.gatherer.cdm.IndexManager.Control
    148       */
    149     public JPanel getControls() {
    150     if(controls == null) {
    151         controls = new Control();
    152     }
    153     return controls;
    154     }
    155     /** Method to get the default index.
    156       * @return The default <strong>Index</strong>.
    157       */
    158     public Index getDefault() {
    159     return default_index;
    160     }
    161     /** Method to retrieve a certain index, as referenced by an index number.
    162       * @param index An <i>int</i> which indicates the position of the desired index.
    163       * @return The <strong>Index</strong> at the given index, or <i>null</i> if no such index exists.
    164       */
    165     public Index getIndex(int index) {
    166     if(0 <= index && index < size()) {
    167         return (Index)get(index);
    168     }
    169     return null;
    170     }
    171     /** Method to retrieve a certain index, given its name.
    172       * @param name The name of the index as a <Strong>String</strong>.
    173       * @return The <strong>Index</strong> that matches name, or <i>null</i> if no such index exists.
    174       */
    175     public Index getIndex(String name) {
    176     ///ystem.err.println("Searching for index " + name);
    177     for(int i = 0; i < size(); i++) {
    178         Index index = (Index) get(i);
    179         if(index.toString(false).equals(name)) {
    180         ///ystem.err.println("Found.");
    181         return (Index)get(i);
    182         }
    183     }
    184     ///ystem.err.println("No such index.");
    185     return null;
    186     }
    187     /** A method to retrieve all of the indexes associated with this manager.
    188       * @return A <strong>Vector</strong> of <strong>Index</strong>es.
    189       */
    190     public Vector getIndexes() {
    191     Vector indexes = new Vector();
    192     for(int i = 0; i < size(); i++) {
    193         indexes.add(get(i));
    194     }
    195     Collections.sort(indexes);
    196     return indexes;
    197     }
    198     /** 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.
    199     * @see org.greenstone.gatherer.cdm.IndexManager.Control
    200     */
    201     public void invalidateControls() {
     82        JOptionPane.showMessageDialog(Gatherer.g_man, get("CDM.IndexManager.Index_Exists"), get("General.Warning"), JOptionPane.WARNING_MESSAGE);
     83    }
     84    }
     85
     86    public void destroy() {
    20287    if(controls != null) {
    20388        controls.destroy();
    204     }
    205     controls = null;
    206     }
    207     /** 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.
    208       * @param command The <strong>String</strong> to parse.
    209       * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
    210       * @see org.greenstone.gatherer.cdm.CommandTokenizer
    211       * @see org.greenstone.gatherer.cdm.Index
    212       */
    213     public boolean parse(String command) {
    214     String temp = command.toLowerCase();
    215     if(temp.startsWith("indexes")) {
    216         CommandTokenizer ct = new CommandTokenizer(command);
    217         ct.nextToken(); // Throw away indexes.
    218         while(ct.hasMoreTokens()) {
    219         String entry = ct.nextToken();
    220         Index index = Index.parseIndexConfig(entry, manager);
    221         if (index != null) {
    222             addIndex(index);
    223            
    224         } else { // return false if there is one error??
    225             return false;
    226         }
    227         }
    228        
    229         return true;
    230     }
    231     else if(temp.startsWith("defaultindex")) {
    232         CommandTokenizer ct = new CommandTokenizer(command);
    233         ct.nextToken();
    234         String entry = ct.nextToken();
    235         Index index = Index.parseIndexConfig(entry, manager);
    236         if (index != null) {
    237         setDefault(index);
    238         return true;
    239         }
    240         return false;
    241     }
    242    
    243     return false;
    244     }
    245 
    246     public void removeAll() {
    247     removeAllElements();
     89        controls = null;
     90    }
    24891    default_index = null;
    249     gatherer.c_man.configurationChanged();
     92    model = null;
     93    }
     94
     95    /** Method to acquire the controls for editing the indexes.
     96     * @return the Control
     97     */
     98    public Control getControls() {
     99    if(controls == null) {
     100        // Build controls
     101        controls = new IndexControl();
     102    }
     103    return controls;
     104    }
     105
     106    /** Method to get the default index.
     107     * @return The default <strong>Index</strong>.
     108     */
     109    public Index getDefault() {
     110    if(default_index != null && default_index.isAssigned()) {
     111        return default_index;
     112    }
     113    else {
     114        return null;
     115    }
     116    }
     117
     118    /** Method to retrieve a certain index, as referenced by an index number.
     119     * @param index An <i>int</i> which indicates the position of the desired index.
     120     * @return The <strong>Index</strong> at the given index, or <i>null</i> if no such index exists.
     121     */
     122    public Index getIndex(int index) {
     123    if(0 <= index && index < getSize()) {
     124        return (Index)getElementAt(index);
     125    }
     126    return null;
     127    }
     128
     129    /** Method to retrieve a certain index, given its id.
     130     * @param id the id of the index as a String
     131     * @return the Index that matches id, or null if no such index exists
     132     */
     133    public Index getIndex(String id) {
     134    int size = getSize();
     135    for(int i = 0; i < size; i++) {
     136        Index index = (Index) getElementAt(i);
     137        if(index.getID().equals(id)) {
     138        return index;
     139        }
     140    }
     141    return null;
     142    }
     143
     144    public ArrayList getIndexes() {
     145    return children();
    250146    }
    251147
    252148    /** Method to remove a certain index.
    253       * @param index The <Strong>Index</strong> to remove.
    254       * @see org.greenstone.gatherer.Gatherer
    255       * @see org.greenstone.gatherer.cdm.CollectionDesignManager
    256       * @see org.greenstone.gatherer.cdm.CollectionMetaManager
    257       * @see org.greenstone.gatherer.collection.CollectionManager
    258       */
     149     * @param index the Index to remove.
     150     * @see org.greenstone.gatherer.Gatherer
     151     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     152     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
     153     * @see org.greenstone.gatherer.collection.CollectionManager
     154     */
    259155    public void removeIndex(Index index) {
    260156    if(index != null) {
    261         String name = index.getName();
    262         if(name != null) {
    263         Language default_language = manager.languages.getDefaultLanguage();
    264         CollectionMeta metadata = new CollectionMeta(manager, index, default_language, name);
    265         manager.collectionmetadatum.removeMetadata(metadata);
    266         }
    267         removeElement(index);
     157        // Remove any current metadata from this index
     158        CollectionDesignManager.collectionmeta_manager.removeMetadata(StaticStrings.STOP_CHARACTER + index.getID());
     159        // Check if the index removed happens to be the default index
    268160        if(default_index != null && default_index.equals(index)) {
    269         default_index = null;
    270         }
    271         gatherer.c_man.configurationChanged();
    272     }
    273     }
     161        default_index.setAssigned(false);
     162        }
     163        // Remove the index
     164        remove(index);
     165        Gatherer.c_man.configurationChanged();
     166    }
     167    }
     168
    274169    /** Method to set the default index.
    275       * @param index The new default <strong>Index</strong>.
    276       * @see org.greenstone.gatherer.Gatherer
    277       * @see org.greenstone.gatherer.collection.CollectionManager
    278       */
     170     * @param index the new default Index
     171     * @see org.greenstone.gatherer.Gatherer
     172     * @see org.greenstone.gatherer.collection.CollectionManager
     173     */
    279174    public void setDefault(Index index) {
    280     default_index = index;
    281     if(index != null && !contains(index)) {
    282         addElement(index);
    283     }
    284     gatherer.c_man.configurationChanged();
    285     }
    286     /** Method to print out the contents of this class as a string.
    287       * @return A <strong>String</strong> just as it would appear in the colleciton configuration file.
    288       */
    289     public String toString() {
    290     String text = "";
    291     // First the indexes.
    292     if(size() > 0) {
    293         text = "indexes      ";
    294         for(int i = 0; i < size(); i++) {
    295         Index index = (Index) get(i);
    296         text = text + index.toStringConfig();
    297         if(i < size() - 1) {
    298             text = text + " ";
    299         }
    300         }
    301         // Now the default index if there is one, or just the first index
    302         // if there isn't
     175    if(index != null) {
     176        if(default_index == null) {
     177        // Create the default index element, and place immediately after indexes element.
     178        Element default_index_element = root.getOwnerDocument().createElement(CollectionConfiguration.INDEX_DEFAULT_ELEMENT);
     179        default_index = new Index(default_index_element);
     180        Node target_node = CollectionConfiguration.findInsertionPoint(default_index_element);
     181        if(target_node != null) {
     182            root.getOwnerDocument().getDocumentElement().insertBefore(default_index_element, target_node);
     183        }
     184        else {
     185            root.getOwnerDocument().getDocumentElement().appendChild(default_index_element);
     186        }
     187        }
     188        default_index.setAssigned(true);
     189        default_index.setLevel(index.getLevel());
     190        default_index.setSources(index.getSources());
     191    }
     192    else {
    303193        if(default_index != null) {
    304         text = text + "\ndefaultindex " + default_index.toStringConfig() + "\n";
    305         }
    306         text = text + "\n";
    307     }
    308     return text;
    309     }
    310 
    311 
    312 
    313 
     194        default_index.setAssigned(false);
     195        }
     196    }
     197    Gatherer.c_man.configurationChanged();
     198    }
    314199   
    315200    /** Overloaded to call get with both a key and an empty argument array.
    316       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    317       * @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.
    318       */
     201     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     202     * @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.
     203     */
    319204    private String get(String key) {
    320205    return get(key, null);
    321206    }
     207
    322208    /** 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>
    323       * 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>.
    324       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    325       * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
    326       * @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.
    327       * @see org.greenstone.gatherer.Gatherer
    328       * @see org.greenstone.gatherer.Dictionary
    329       */
     209     * 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>.
     210     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     211     * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
     212     * @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 automatically populated with formatting Strings of with argument String provided in the get call.
     213     * @see org.greenstone.gatherer.Gatherer
     214     * @see org.greenstone.gatherer.Dictionary
     215     */
    330216    private String get(String key, String args[]) {
    331217    if(key.indexOf('.') == -1) {
    332218        key = "CDM.IndexManager." + key;
    333219    }
    334     return gatherer.dictionary.get(key, args);
    335     }
     220    return Gatherer.dictionary.get(key, args);
     221    }
     222
    336223    /** This class creates a set of controls for editing the indexes. */
    337     private class Control
    338     extends JPanel {
     224    private class IndexControl
     225    extends JPanel
     226    implements Control {
    339227    /** The default size of a label on this control. */
    340228    private Dimension LABEL_SIZE = new Dimension(120,25);
     
    406294     * @see org.greenstone.gatherer.util.ExclusiveListSelectionListener
    407295     */
    408     public Control() {
     296    public IndexControl() {
    409297        super();
    410298        source_model = new Vector();
    411299        source_model.add("text");
    412         source_model.addAll(gatherer.c_man.msm.getAssignedElements());
    413         //source_model.addAll(gatherer.c_man.msm.getElements());
     300        source_model.addAll(Gatherer.c_man.getCollection().msm.getAssignedElements());
    414301        // Creation
    415302        add = new JButton(get("Add"));
     
    428315        default_pane = new JPanel();
    429316        if(default_index != null) {
    430         default_value = new JTextField(default_index.toString(true));
     317        default_value = new JTextField(default_index.toString());
    431318        default_value.setCaretPosition(0);
    432319        }
     
    440327        index_label = new JLabel(get("Indexes"));
    441328        index_list = new JList(model);
    442         index_list.setCellRenderer(new IndexListCellRenderer());
    443329        instructions = new JTextArea(get("Instructions"));
    444330        instructions.setEditable(false);
     
    550436    }
    551437    /* Destructor, removes persistant listeners from the Dictionary.
    552             */
     438     */
    553439    public void destroy() {
    554440    }
    555     /** We override the updateUI method so that we can ensure we are scrolled to the top of the instructions box first.
    556           * @see org.greenstone.gatherer.Gatherer
    557           * @see org.greenstone.gatherer.collection.CollectionManager
    558           * @see org.greenstone.gatherer.msm.MetadataSetManager
    559             */
    560     public void updateUI() {
     441
     442    public void gainFocus() {
    561443        if(instructions != null) {
    562444        instructions.setCaretPosition(0);
     
    566448        source_model.clear();
    567449        source_model.add("text");
    568         source_model.addAll(gatherer.c_man.msm.getAssignedElements());
     450        source_model.addAll(Gatherer.c_man.getCollection().msm.getAssignedElements());
    569451        // reset the model in the list - needed if the model is larger than when it was first created, the list doesn't display
    570452        source_list.setListData(source_model);
    571453       
    572454        }
    573         // Faster than a NPE its the - 'Super class'.
    574         super.updateUI();
    575     }
     455    }
     456
     457    public void loseFocus() {
     458    }
     459
    576460    /** 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. */
    577461    private class AddListener
     
    589473        if(!source_list.isSelectionEmpty() && name.getText().length() != 0) {
    590474            Object object[] = source_list.getSelectedValues();
    591             Vector sources = new Vector();
     475            ArrayList sources = new ArrayList();
    592476            for(int i = 0; i < object.length; i++) {
    593477            sources.add(object[i]);
    594478            }
    595             Index index = new Index(level.getSelectedIndex(), sources, manager);
     479            object = null;
     480            Index index = new Index(level.getSelectedIndex(), sources);
     481            sources = null;
    596482            // Before we add the index to the model, we have to add the collection metadata for this.
    597             Language language = manager.languages.getDefaultLanguage();
    598             CollectionMeta metadata = new CollectionMeta(manager, index, language, name.getText());
    599             manager.collectionmetadatum.addMetadata(metadata);
     483            CollectionMeta metadatum = new CollectionMeta(StaticStrings.STOP_CHARACTER + index.getID());
     484            metadatum.setValue(name.getText());
    600485            // Finally add index.
    601             addIndex(index);
     486            addIndex(index, metadatum);
     487            metadatum = null;
     488            index = null;
    602489        }
    603490        }
     
    606493    private class ClearDefaultListener
    607494        implements ActionListener {
    608                 /** If called when an action occurs on a registered component, we clear the default index.
    609                 * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
    610                 */
     495        /** If called when an action occurs on a registered component, we clear the default index.
     496        * @param event An <strong>ActionEvent</strong> containing extra information about the action that occured.
     497         */
    611498        public void actionPerformed(ActionEvent event) {
    612499        setDefault(null);
     
    643530        if(default_index != null) {
    644531            clear_default.setEnabled(true);
    645             default_value.setText(default_index.toString(true));
     532            default_value.setText(default_index.toString());
    646533            default_value.setCaretPosition(0);
    647534        }
     
    698585        }
    699586    }
    700 
    701 
    702     private class IndexListCellRenderer
    703         extends DefaultListCellRenderer {
    704        
    705         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    706         StringBuffer text = new StringBuffer(value.toString());
    707         // Retrieve the indexes name if any.
    708         CollectionMeta metadata = manager.collectionmetadatum.getMetadata(value, manager.languages.getDefaultLanguage(), true);
    709         if(metadata != null) {
    710             text.append(" \"");
    711             text.append(metadata.getValue());
    712             text.append("\"");
    713         }
    714         return super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
    715         }
    716 
    717     }
    718 
    719587    }
    720588}
  • trunk/gli/src/org/greenstone/gatherer/cdm/Language.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    4428/**************************************************************************************
    45  * Title:        Gatherer
    46  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    47  * Copyright:    Copyright (c) 2001
    48  * Company:      The University of Waikato
    4929 * Written:      08/05/02
    5030 * Revised:      17/11/02 - Commented
     31 *               07/07/03 - DOM support
    5132 **************************************************************************************/
    52 
     33import org.greenstone.gatherer.cdm.CollectionConfiguration;
     34import org.greenstone.gatherer.cdm.CollectionDesignManager;
     35import org.greenstone.gatherer.cdm.DOMProxyListEntry;
     36import org.greenstone.gatherer.msm.MSMUtils;
     37import org.w3c.dom.*;
    5338/** A pretty unexciting extension of a two character string, in that it has a field which details if its the default language.
    5439* @author John Thompson, Greenstone Digital Library, University of Waikato
     
    5641*/
    5742public class Language
    58     implements Comparable {
    59     /** Is this language the default one. */
    60     private boolean default_language = false;
     43    implements Comparable, DOMProxyListEntry {
     44    /** The Element this language entry is based upon. */
     45    private Element element = null;
     46    /** The two character code for this language. */
     47    private String code = null;
    6148    /** The name of this language. */
    6249    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.
    69       */
    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);
     50 
     51    public Language() {
    7452    }
    75     /** Copy constructor.
    76       * @param language The <strong>Language</strong> we want to copy.
    77       */
    78     public Language(Language language) {
    79     this.default_language = language.isDefault();
    80     this.name = language.toString();
    81     this.value = language.getCode();
     53
     54    public Language(Element element) {
     55    this.element = element;
    8256    }
     57
     58    /** Constructor for a brand new language. */
     59    public Language(String code) {
     60    this.code = code;
     61    // Create the new element
     62    element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.LANGUAGE_ELEMENT);
     63    element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, code);
     64    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
     65    }
     66
    8367    /** Method to compare two languages for ordering purposes.
    84       * @param object The other language as an <strong>Object</strong>.
    85       * @return An <i>int</i> which indicates order using the same values as in String.compareTo().
    86       * @see java.lang.String#compareTo
    87       */
     68     * @param object the other language as an Object
     69     * @return an int which indicates the order between this language and the given one: < 0, 0 or > 0 for before, equal to or after respectively
     70     */
    8871    public int compareTo(Object object) {
    8972    return toString().compareTo(object.toString());
    9073    }
     74
     75    public DOMProxyListEntry create(Element element) {
     76    return new Language(element);
     77    }
     78
    9179    /** Method to test for the equality of two languages.
    92       * @param object The other language as an <strong>Object</strong>.
    93       * @return <i>true</i> if the languages are equal, <i>false</i> otherwise.
    94       */
     80     * @param object The other language as an <strong>Object</strong>.
     81     * @return <i>true</i> if the languages are equal, <i>false</i> otherwise.
     82     */
    9583    public boolean equals(Object object) {
    96     if(compareTo(object) == 0) {
    97         return true;
     84    return (compareTo(object) == 0);
     85    }
     86
     87    /** Method to retrieve the code of this language.
     88     * @return A <strong>String</strong> representing the two letter code.
     89     */
     90    public String getCode() {
     91    if(code == null && element != null) {
     92        code = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
    9893    }
    99     return false;
     94    return code;
    10095    }
    101     /** Method to retrieve the code of this language.
    102       * @return A <strong>String</strong> representing the two letter code.
    103       */
    104     public String getCode() {
    105     return value;
     96
     97    public Element getElement() {
     98    return element;
    10699    }
    107     /** Method to determine if this language is the default one.
    108       * @return A <i>boolean</i> which is <i>true</i> if this language is the default one.
    109       */
    110     public boolean isDefault() {
    111     return default_language;
     100
     101    public String getName() {
     102    if(name == null) {
     103        String code = getCode();
     104        name = CollectionDesignManager.language_manager.getLanguageName(code);
     105    }
     106    return name;
    112107    }
    113     /** Method to set the value of default.
    114       * @param value The new value of default as a <i>boolean</i>.
    115       */
    116     public void setDefault(boolean value) {
    117     this.default_language = default_language;
     108
     109    public boolean isAssigned() {
     110    return (element != null && element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR));
    118111    }
     112
     113    public void setAssigned(boolean value) {
     114    if(element != null) {
     115        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (value ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     116    }
     117    }
     118
     119    public void setCode(String new_code) {
     120    code = new_code;
     121    // Set element
     122    if(element != null) {
     123        element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, new_code);
     124    }
     125    // Reset name
     126    name = null;
     127    }
     128
     129    public void setElement(Element new_element) {
     130    element = new_element;
     131    code = null;
     132    name = null;
     133    }
     134
    119135    /** Method to display the language code.
    120       * @return A <strong>String</strong> representing the language code.
    121       */
     136     * @return A <strong>String</strong> representing the language code.
     137     */
    122138    public String toString() {
    123     return name;
     139    return getName();
    124140    }
    125141}
  • trunk/gli/src/org/greenstone/gatherer/cdm/LanguageManager.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    4428/**************************************************************************************
    45  * Title:        Gatherer
    46  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    47  * Copyright:    Copyright (c) 2001
    48  * Company:      The University of Waikato
    4929 * Written:      08/05/02
    5030 * Revised:      17/11/02 - Commented
     31 *               07/07/03 - DOM support
    5132 **************************************************************************************/
    52 import java.awt.BorderLayout;
    53 import java.awt.Color;
    54 import java.awt.Component;
    55 import java.awt.Dimension;
    56 import java.awt.GridLayout;
    57 import java.awt.event.ActionEvent;
    58 import java.awt.event.ActionListener;
    59 import java.awt.event.KeyEvent;
    60 import java.io.BufferedReader;
    61 import java.io.File;
    62 import java.io.FileReader;
    63 import java.util.ArrayList;
    64 import java.util.Collections;
    65 import java.util.Enumeration;
    66 import java.util.Iterator;
    67 import java.util.LinkedHashMap;
    68 import java.util.StringTokenizer;
    69 import java.util.Vector;
    70 import javax.swing.BorderFactory;
    71 import javax.swing.DefaultListCellRenderer;
    72 import javax.swing.DefaultListModel;
    73 import javax.swing.ListModel;
    74 import javax.swing.JButton;
    75 import javax.swing.JComboBox;
    76 import javax.swing.JLabel;
    77 import javax.swing.JList;
    78 import javax.swing.JPanel;
    79 import javax.swing.JScrollPane;
    80 import javax.swing.JTextArea;
    81 import javax.swing.JTextField;
    82 import javax.swing.event.ListSelectionEvent;
    83 import javax.swing.event.ListSelectionListener;
     33import java.awt.*;
     34import java.awt.event.*;
     35import java.io.*;
     36import java.util.*;
     37import javax.swing.*;
     38import javax.swing.event.*;
    8439import org.greenstone.gatherer.Gatherer;
     40import org.greenstone.gatherer.cdm.CollectionConfiguration;
     41import org.greenstone.gatherer.cdm.CollectionDesignManager;
     42import org.greenstone.gatherer.cdm.Control;
     43import org.greenstone.gatherer.cdm.DOMProxyListModel;
    8544import org.greenstone.gatherer.cdm.Language;
     45import org.greenstone.gatherer.cdm.LanguageListCellRenderer;
     46import org.w3c.dom.*;
    8647/** This class manages the language commands, remembering both a list of languages to build indexes in, plus the default language.
    8748 * @author John Thompson, Greenstone Digital Library, University of Waikato
     
    8950 */
    9051public class LanguageManager
    91     extends DefaultListModel {
    92     /** A reference to the collection design manager. */
    93     private CollectionDesignManager manager = null;
     52    extends DOMProxyListModel {
     53
     54    static final private Dimension LABEL_SIZE = new Dimension(125,25);
     55
    9456    /** The visual controls for this manager. */
    9557    private Control controls = null;
    96     /** A reference to the Gatherer. */
    97     private Gatherer gatherer = null;
    9858    /** A reference to this class as a model, for the inner controls class. */
    99     private ListModel model = null;
     59    private DOMProxyListModel model = null;
    10060    /** A hashtable of code->name mappings of known languages. */
    10161    private LinkedHashMap known_languages = null;
    10262    /** The default language object. */
    10363    private Language default_language = null;
    104 
    105     static final private Dimension LABEL_SIZE = new Dimension(125,25);
    106     /** Constructor.
    107      * @param gatherer A reference to the <strong>Gatherer</strong>.
    108      * @param manager A reference to the <strong>CollectionDesignManager</strong>.
    109      */
    110     public LanguageManager(Gatherer gatherer, CollectionDesignManager manager) {
    111     super();
    112     this.gatherer = gatherer;
    113     this.known_languages = new LinkedHashMap();
    114     this.manager = manager;
     64 
     65   /** Constructor. */
     66    public LanguageManager(Element languages_element) {
     67    super(languages_element, CollectionConfiguration.LANGUAGE_ELEMENT, new Language());
     68   
     69    Gatherer.println("LanguageManager: " + getSize() + " languages parsed.");
     70
    11571    this.model = this;
    116     loadLanguages();
    117     }
    118     /** Method to add a new language.
    119       * @param language The <strong>Language</strong> to add.
    120       * @see org.greenstone.gatherer.Gatherer
    121       * @see org.greenstone.gatherer.collection.CollectionManager
    122       */
    123     public void addLanguage(Language language) {
    124     if(!contains(language)) {
    125                 // Add alphabetically.
    126         for(int index = 0; index < size(); index++) {
    127         Language sibling = (Language) get(index);
    128         int position = language.compareTo(sibling);
    129         // Sibling is before language.
    130         if(position > 0) {
    131             // Carry on.
    132         }
    133         // Language is equal to, or before sibling. Insert it.
    134         else if(position == 0 || position < 0) {
    135             add(index, language);
    136             gatherer.c_man.configurationChanged();
    137             return;
    138         }
    139         }
    140                 // If we got this far, we haven't inserted language, and we are out of model so.
    141         addElement(language);
    142         gatherer.c_man.configurationChanged();
    143     }
    144     }
    145     /** Method to retrieve the control for this manager.
    146       * @return A <strong>JPanel</strong> containing the controls.
    147       */
    148     public JPanel getControls() {
    149     if(controls == null) {
    150         controls = new Control();
    151     }
    152     return controls;
    153     }
    154     /** Method to retrieve the default language code.
    155       * @return A <strong>Language</strong> containing a two letter code.
    156       */
    157     public Language getDefaultLanguage() {
    158     // If no default is set...
    159     if(default_language == null) {
    160                 // And we have other assigned languages, use the first one of them.
    161         if(size() >= 1) {
    162         default_language = (Language) get(0);
    163         }
    164                 // And we have nothing else, use English.
    165         else {
    166         default_language = getLanguage("en", false);
    167         // Remember to add it.
    168         addLanguage(default_language);
    169         }
    170     }
    171     return default_language;
    172     }
    173     /** Method to retrieve a certain language object by its code.
    174      * @param code The two letter code of a language, as a <strong>String</strong>.
    175      * @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.
    176      * @return The <strong>Language</strong> that matches the given code, or <i>null</i> if no such language exists.
    177      */
    178     public Language getLanguage(String code, boolean assigned_only) {
    179     if(assigned_only) {
    180         for(int i = 0; i < size(); i++) {
    181         Language pos = (Language)get(i);
    182         ///ystem.err.println("Comparing " + pos.getCode() + " and " + code);
    183         if(pos.getCode().equals(code)) {
    184             return pos;
    185         }
    186         }
    187     }
    188     else {
    189         if(known_languages.containsKey(code)) {
    190         return new Language((Language)known_languages.get(code));
    191         }
    192     }
    193     return null;
    194     }
    195     /** Method to return a list of the known language codes.
    196      * @return An <strong>ArrayList</strong> containing a series of alphabetically sorted two letter codes.
    197      */
    198     public ArrayList getLanguageCodes() {
    199     ArrayList result = new ArrayList();
    200     Iterator key_iter = known_languages.keySet().iterator();
    201     while(key_iter.hasNext()) {
    202         result.add(known_languages.get(key_iter.next()));
    203     }
    204     //for(Enumeration keys = known_languages.keys(); keys.hasMoreElements(); ) {
    205     //  result.add(known_languages.get(keys.nextElement()));
    206     //}
    207     //Collections.sort(result);
    208     return result;
    209     }
    210     /** 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.
    211     * @see org.greenstone.gatherer.cdm.IndexManager.Control
    212     */
    213     public void invalidateControls() {
    214     if(controls != null) {
    215         controls.destroy();
    216     }
    217     controls = null;
    218     }
    219 
    220     /** Determine if the given language is the current default language.
    221       * @param language The <strong>Language</strong> to test.
    222       * @return <i>true</i> if the language is the default one, <i>false</i> otherwise.
    223       */
    224     public boolean isDefaultLanguage(Language language) {
    225     return (language.equals(default_language));
    226     }
    227     /** 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.
    228       * @param command The <strong>String</strong> containing a possible language command.
    229       * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
    230       * @see org.greenstone.gatherer.cdm.Language
    231       */
    232     public boolean parse(String command) {
    233     String command_lc = command.toLowerCase();
    234     if(command_lc.startsWith("languages")) {
    235         StringTokenizer tokenizer = new StringTokenizer(command);
    236         tokenizer.nextToken();
    237         while(tokenizer.hasMoreTokens()) {
    238         String code = tokenizer.nextToken();
    239         if(known_languages.containsKey(code)) {
    240             Language language = (Language)known_languages.get(code);
    241             addElement(new Language(language));
    242         }
    243         else {
    244             addElement(new Language(code, code, false));
    245         }
    246         }
    247         return true;
    248     }
    249     if(command_lc.startsWith("defaultlanguage")) {
    250         StringTokenizer tokenizer = new StringTokenizer(command);
    251         tokenizer.nextToken();
    252         if(tokenizer.hasMoreTokens()) {
    253         String code = tokenizer.nextToken();
    254         Language language = getLanguage(code, true);
    255         if(language == null) {
    256             language = new Language(code, (String)known_languages.get(code), true);
    257             addElement(language);
    258         }
    259         else {
    260             language.setDefault(true);
    261         }
    262         setDefault(language);
    263         }
    264         return true;
    265     }
    266     return false;
    267     }
    268     /** Method to cause the list appearance to update if the selection changes. */
    269     public void refreshAppearance() {
    270     fireContentsChanged(this, 0, size());
    271     }
    272     /** Method to remove a certain language.
    273       * @param language The <strong>Language</strong> to remove.
    274       * @see org.greenstone.gatherer.Gatherer
    275       * @see org.greenstone.gatherer.collection.CollectionManager
    276       */
    277     public void removeLanguage(Language language) {
    278     removeElement(language);
    279     if(default_language != null && default_language.equals(language)) {
    280         default_language = null;
    281     }
    282     gatherer.c_man.configurationChanged();
    283     }
    284     /** Method to set the default language.
    285       * @param language The <strong>Language</strong> to use as a default, or <i>null</i> for no default.
    286       * @see org.greenstone.gatherer.Gatherer
    287       * @see org.greenstone.gatherer.collection.CollectionManager
    288       */
    289     public void setDefault(Language language) {
    290     // Unset existing.
    291     Language old = null;
    292     if(default_language != null) {
    293         old = default_language;
    294         default_language.setDefault(false);
    295         default_language = null;
    296     }
    297     // Now set the new if its not null.
    298     if(language != null) {
    299         default_language = language;
    300         default_language.setDefault(true);
    301     }
    302     // Now cause the model to refresh any lists that are listening.
    303     int start = 0;
    304     int end = size() - 1;
    305     if(default_language != null && old != null) {
    306         int index_default = indexOf(default_language);
    307         int index_old = indexOf(old);
    308         if(index_default < index_old) {
    309         start = index_default;
    310         end = index_old;
    311         }
    312         else {
    313         start = index_old;
    314         end = index_default;
    315         }
    316     }
    317     else if(default_language != null) {
    318         start = end = indexOf(default_language);
    319     }
    320     else {
    321         start = end = indexOf(old);
    322     }
    323     fireContentsChanged(this, 0, size());
    324     gatherer.c_man.configurationChanged();
    325     }
    326     /** Method to translate this object into a block of commands as you you expect to find in the collection configuration file.
    327      * @return A <strong>String</string> containing a series of commands.
    328      */
    329     public String toString() {
    330     StringBuffer text = new StringBuffer();
    331     if(size() > 1) {
    332         text.append("languages ");
    333         for(int i = 0; i < size(); i++) {
    334         Language language = (Language) get(i);
    335         text.append(language.getCode());
    336         if(i < size() - 1) {
    337             text.append(" ");
    338         }
    339         else {
    340             text.append("\n");
    341         }
    342         }
    343                 // Only bother with default language if there is more than one language.
    344         if(default_language != null) {
    345         text.append("defaultlanguage ");
    346         text.append(default_language.getCode());
    347         text.append("\n");
    348         }
    349         text.append("\n");
    350     }
    351     return text.toString();
    352     }
    353     /** Overloaded to call get with both a key and an empty argument array.
    354       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    355       * @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.
    356       */
    357     private String get(String key) {
    358     return get(key, null);
    359     }
    360     /** 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>
    361       * 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>.
    362       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    363       * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
    364       * @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.
    365       * @see org.greenstone.gatherer.Gatherer
    366       * @see org.greenstone.gatherer.Dictionary
    367       */
    368     private String get(String key, String args[]) {
    369     if(key.indexOf('.') == -1) {
    370         key = "CDM.LanguageManager." + key;
    371     }
    372     return gatherer.dictionary.get(key, args);
    373     }
    374     /** 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.
    375      * @see org.greenstone.gatherer.cdm.Language
    376       */
    377     private void loadLanguages() {
     72    // Retrieve the default language
     73    NodeList default_language_elements = CollectionDesignManager.collect_config.getDocumentElement().getElementsByTagName(CollectionConfiguration.LANGUAGE_DEFAULT_ELEMENT);
     74    if(default_language_elements.getLength() > 0) {
     75        default_language = new Language((Element)default_language_elements.item(0));
     76    }
     77    // Load a series of code->language mappings into known_languages, by reading from the 'languages.dat' file, which is essentially a subset of the ISO 639 Standard.
     78    known_languages = new LinkedHashMap();
    37879    try {
    37980        File in_file = new File("languages.dat");
     
    38485        if(!entry.startsWith("#")) {
    38586            StringTokenizer tokenizer = new StringTokenizer(entry);
    386             String name = tokenizer.nextToken();
    387             String code = tokenizer.nextToken().toLowerCase();
    388             Language language = new Language(code, name, false);
    389             known_languages.put(code, language);
     87            if(tokenizer.countTokens() >= 2) {
     88            String name = tokenizer.nextToken();
     89            String code = tokenizer.nextToken().toLowerCase();
     90            known_languages.put(code, name);
     91            }
    39092        }
    39193        }
    39294        in.close();
     95        in_reader.close();
     96        in = null;
     97        in_reader = null;
     98        in_file = null;
    39399    }
    394100    catch (Exception error) {
     
    397103    }
    398104
     105    /** Method to add a new language.
     106     * @param language The <strong>Language</strong> to add.
     107     * @see org.greenstone.gatherer.Gatherer
     108     * @see org.greenstone.gatherer.collection.CollectionManager
     109     */
     110    public void addLanguage(Language language) {
     111    if(!contains(language)) {
     112        Element element = language.getElement();
     113        // Locate where we should insert this new subcollection.
     114        Node target_node = CollectionConfiguration.findInsertionPoint(element);
     115        // Failing that we insert immediately after a language string
     116        add(root, language, target_node);
     117        Gatherer.c_man.configurationChanged();
     118    }
     119    }
     120
     121    public void destroy() {
     122    if(controls != null) {
     123        controls.destroy();
     124        controls = null;
     125    }
     126    known_languages.clear();
     127    known_languages = null;
     128    }
     129
     130    /** Method to retrieve the control for this manager.
     131     * @return the Control for editing the language partitions
     132     */
     133    public Control getControls() {
     134    if(controls == null) {
     135        // Build controls
     136        controls = new LanguageControl();
     137    }
     138    return controls;
     139    }
     140
     141    /** Method to retrieve the default language code.
     142     * @return A <strong>Language</strong> containing a two letter code.
     143     */
     144    public Language getDefaultLanguage() {
     145    // If no default is set...
     146    if(default_language != null && default_language.isAssigned()) {
     147        return default_language;
     148    }
     149    return null;
     150    }
     151
     152    /** Method to retrieve a certain language object by its code.
     153     * @param code The two letter code of a language, as a <strong>String</strong>.
     154     * @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.
     155     * @return The <strong>Language</strong> that matches the given code, or <i>null</i> if no such language exists.
     156     */
     157    public Language getLanguage(String code) {
     158    int size = getSize();
     159    for(int i = 0; i < size; i++) {
     160        Language language = (Language) getElementAt(i);
     161        if(language.getCode().equals(code)) {
     162        return language;
     163        }
     164    }
     165    return null;
     166    }
     167
     168    public ArrayList getLanguages() {
     169    return children();
     170    }
     171
     172    /** Method to return a list of the known language codes.
     173     * @return an ArrayList containing the series of known language codes as per the languages.dat file
     174     */
     175    public ArrayList getLanguageCodes() {
     176    return new ArrayList(known_languages.keySet());
     177    }
     178
     179    public String getLanguageName(String code) {
     180    return (String) known_languages.get(code);
     181    }
     182
     183    /** Method to remove a certain language.
     184     * @param language The <strong>Language</strong> to remove.
     185     * @see org.greenstone.gatherer.Gatherer
     186     * @see org.greenstone.gatherer.collection.CollectionManager
     187     */
     188    public void removeLanguage(Language language) {
     189    remove(language);
     190    if(default_language != null && default_language.equals(language)) {
     191        default_language = null;
     192    }
     193    Gatherer.c_man.configurationChanged();
     194    }
     195
     196    /** Method to set the default language.
     197     * @param language The <strong>Language</strong> to use as a default, or <i>null</i> for no default.
     198     * @see org.greenstone.gatherer.Gatherer
     199     * @see org.greenstone.gatherer.collection.CollectionManager
     200     */
     201    public void setDefault(Language language) {
     202    if(language != null) {
     203        if(default_language == null) {
     204        // Create the default index element, and place immediately after indexes element.
     205        Element default_language_element = root.getOwnerDocument().createElement(CollectionConfiguration.LANGUAGE_DEFAULT_ELEMENT);
     206        default_language = new Language(default_language_element);
     207        Node target_node = CollectionConfiguration.findInsertionPoint(default_language_element);
     208        if(target_node != null) {
     209            root.getOwnerDocument().getDocumentElement().insertBefore(default_language_element, target_node);
     210        }
     211        else {
     212            root.getOwnerDocument().getDocumentElement().appendChild(default_language_element);
     213        }
     214        }
     215        default_language.setAssigned(true);
     216        default_language.setCode(language.getCode());
     217    }
     218    else {
     219        if(default_language != null) {
     220        default_language.setAssigned(false);
     221        }
     222    }
     223    Gatherer.c_man.configurationChanged();
     224    }
     225
     226    /** Overloaded to call get with both a key and an empty argument array.
     227      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     228      * @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.
     229      */
     230    private String get(String key) {
     231    if(key.indexOf('.') == -1) {
     232        key = "CDM.LanguageManager." + key;
     233    }
     234    return Gatherer.dictionary.get(key, (String[])null);
     235    }
     236
    399237    /** This class represents the visual component of the Language Manager. */
    400     private class Control
    401     extends JPanel {
     238    private class LanguageControl
     239    extends JPanel
     240    implements Control {
    402241    /** The button to add a new language support. */
    403     private JButton add = null;
     242    private JButton add_button = null;
    404243    /** The button to clear the current default language. */
    405     private JButton clear_default = null;
     244    private JButton clear_button = null;
    406245    /** The button to remove a supported language. */
    407     private JButton remove = null;
     246    private JButton remove_button = null;
    408247    /** The button to set the current language as the default one. */
    409     private JButton set_default = null;
     248    private JButton set_button = null;
    410249    /** A combobox listing the available supported languages. */
    411     private JComboBox selector = null;
     250    private JComboBox selector_combobox = null;
    412251    /** A list of currently supported languages. */
    413     private JList list = null;
     252    private JList language_list = null;
    414253    /** A description of the language currently selected. */
    415     private JTextArea description = null;
     254    private JTextArea description_textarea = null;
    416255    /** The text field showing the currently name of the default language. Non-editable. */
    417     private JTextField default_language_value = null;
     256    private JTextField default_language_field = null;
    418257    /** Constructor.
    419258     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.AddListener
     
    425264     * @see org.greenstone.gatherer.cdm.LanguageManager.Control.TranslateListener
    426265     */
    427     public Control() {
     266    public LanguageControl() {
    428267        super();
    429268        // Creation.
     
    434273        title_label.setOpaque(true);
    435274
    436         list = new JList(model);
    437         list.setCellRenderer(new ListRenderer());
     275        language_list = new JList(model);
    438276
    439277        JPanel details_panel = new JPanel();
     
    446284
    447285        if(default_language == null) {
    448         default_language_value = new JTextField();
     286        default_language_field = new JTextField();
    449287        }
    450288        else {
    451         default_language_value = new JTextField(default_language.toString());
    452         }
    453         default_language_value.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    454         default_language_value.setEditable(false);
     289        default_language_field = new JTextField(default_language.toString());
     290        }
     291        default_language_field.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     292        default_language_field.setEditable(false);
    455293
    456294        JPanel control_panel = new JPanel();
     
    459297        selector_label.setPreferredSize(LABEL_SIZE);
    460298
    461         selector = new JComboBox(getLanguageCodes().toArray());
    462         selector.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     299        selector_combobox = new JComboBox(getLanguageCodes().toArray());
     300        selector_combobox.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     301        selector_combobox.setRenderer(new LanguageListCellRenderer());
    463302
    464303        JPanel button_panel = new JPanel();
    465304
    466         add = new JButton(get("Add"));
    467         add.setMnemonic(KeyEvent.VK_A);
    468         if(selector.getSelectedItem() != null) {
    469         add.setEnabled(true);
    470         }
    471         else {
    472         add.setEnabled(false);
    473         }
    474 
    475         remove = new JButton(get("Remove"));
    476         remove.setMnemonic(KeyEvent.VK_R);
    477         remove.setEnabled(false);
    478 
    479         clear_default = new JButton(get("Clear_Default"));
    480         clear_default.setMnemonic(KeyEvent.VK_C);
    481         clear_default.setEnabled(false);
    482 
    483         set_default = new JButton(get("Set_Default"));
    484         set_default.setMnemonic(KeyEvent.VK_S);
    485         set_default.setEnabled(false);
     305        add_button = new JButton(get("Add"));
     306        add_button.setMnemonic(KeyEvent.VK_A);
     307
     308        remove_button = new JButton(get("Remove"));
     309        remove_button.setMnemonic(KeyEvent.VK_R);
     310        remove_button.setEnabled(false);
     311
     312        clear_button = new JButton(get("Clear_Default"));
     313        clear_button.setMnemonic(KeyEvent.VK_C);
     314        clear_button.setEnabled(false);
     315
     316        set_button = new JButton(get("Set_Default"));
     317        set_button.setMnemonic(KeyEvent.VK_S);
     318        set_button.setEnabled(false);
    486319
    487320        // Set up and connect listeners.
    488         add.addActionListener(new AddListener());
    489         clear_default.addActionListener(new ClearDefaultListener());
    490         remove.addActionListener(new RemoveListener());
    491         selector.addActionListener(new SelectorListener());
    492         set_default.addActionListener(new SetDefaultListener());
    493         list.addListSelectionListener(new ListListener());
     321        add_button.addActionListener(new AddListener());
     322        clear_button.addActionListener(new ClearDefaultListener());
     323        remove_button.addActionListener(new RemoveListener());
     324        selector_combobox.addActionListener(new SelectorListener());
     325        set_button.addActionListener(new SetDefaultListener());
     326        language_list.addListSelectionListener(new ListListener());
    494327        // Layout components.
    495328        default_panel.setBorder(BorderFactory.createRaisedBevelBorder());
    496329        default_panel.setLayout(new BorderLayout());
    497330        default_panel.add(default_label, BorderLayout.WEST);
    498         default_panel.add(default_language_value, BorderLayout.CENTER);
     331        default_panel.add(default_language_field, BorderLayout.CENTER);
    499332
    500333        control_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    501334        control_panel.setLayout(new BorderLayout());
    502335        control_panel.add(selector_label, BorderLayout.WEST);
    503         control_panel.add(selector, BorderLayout.CENTER);
     336        control_panel.add(selector_combobox, BorderLayout.CENTER);
    504337
    505338        details_panel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
     
    510343        center_panel.setLayout(new BorderLayout());
    511344        center_panel.add(title_label, BorderLayout.NORTH);
    512         center_panel.add(new JScrollPane(list), BorderLayout.CENTER);
     345        center_panel.add(new JScrollPane(language_list), BorderLayout.CENTER);
    513346        center_panel.add(details_panel, BorderLayout.SOUTH);
    514347
    515348        button_panel.setLayout(new GridLayout(2,2,5,5));
    516         button_panel.add(add);
    517         button_panel.add(remove);
    518         button_panel.add(clear_default);
    519         button_panel.add(set_default);
     349        button_panel.add(add_button);
     350        button_panel.add(remove_button);
     351        button_panel.add(clear_button);
     352        button_panel.add(set_button);
    520353
    521354        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     
    524357        add(button_panel, BorderLayout.SOUTH);
    525358    }
    526     /** Destructor.
    527             */
     359    /** Destructor. */
    528360    public void destroy() {
    529361    }
     362
     363    public void gainFocus() {
     364    }
     365
     366    public void loseFocus() {
     367    }
     368
    530369    /** 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. */
    531370    private class AddListener
     
    536375         */
    537376        public void actionPerformed(ActionEvent event) {
    538         Language language = (Language)selector.getSelectedItem();
    539         if(language != null) {
    540             addLanguage(new Language(language));
    541         }
    542         }
    543     }
     377        String language_code = (String) selector_combobox.getSelectedItem();
     378        if(language_code != null) {
     379            addLanguage(new Language(language_code));
     380        }
     381        add_button.setEnabled(false);
     382        }
     383    }
     384
    544385    /** 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>. */
    545386    private class ClearDefaultListener
     
    550391        public void actionPerformed(ActionEvent event) {
    551392        setDefault(null);
    552         clear_default.setEnabled(false);
    553         default_language_value.setText("");
    554         }
    555     }
     393        clear_button.setEnabled(false);
     394        default_language_field.setText("");
     395        }
     396    }
     397
    556398    /** 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. */
    557399    private class RemoveListener
     
    562404         */
    563405        public void actionPerformed(ActionEvent event) {
    564         if(!list.isSelectionEmpty()) {
    565             removeLanguage((Language)list.getSelectedValue());
    566             if(default_language == null) {
    567             clear_default.setEnabled(false);
    568             default_language_value.setText("");
     406        Language delete_me = (Language)language_list.getSelectedValue();
     407        if(delete_me != null) {
     408            removeLanguage(delete_me);
     409            if(default_language != null && default_language.equals(delete_me)) {
     410            setDefault(null);
     411            clear_button.setEnabled(false);
     412            default_language_field.setText("");
    569413            }
    570414        }
    571         }
    572     }
    573     /** Listens for selections wihtin the combobox on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
     415        remove_button.setEnabled(false);
     416        }
     417    }
     418
     419    /** Listens for selections within the combobox on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
    574420    private class SelectorListener
    575421        implements ActionListener {
     
    578424         */
    579425        public void actionPerformed(ActionEvent event) {
    580         if(selector.getSelectedItem() != null) {
    581             add.setEnabled(true);
    582             //description.setText((String)known_languages.get(code));
     426        if(selector_combobox.getSelectedItem() != null) {
     427            add_button.setEnabled(true);
    583428        }
    584429        else {
    585             add.setEnabled(false);
    586             //description.setText("");
    587         }
    588         }
    589     }
     430            add_button.setEnabled(false);
     431        }
     432        }
     433    }
     434
    590435    /** 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. */
    591436    private class SetDefaultListener
    592437        implements ActionListener {
    593                 /** Set the default index to the one currently selected, if any.
    594                 * @param event An <strong>ActionEvent</strong>.
    595                 * @see org.greenstone.gatherer.cdm.Language
    596                 */
     438        /** Set the default index to the one currently selected, if any.
     439        * @param event An <strong>ActionEvent</strong>.
     440        * @see org.greenstone.gatherer.cdm.Language
     441        */
    597442        public void actionPerformed(ActionEvent event) {
    598         if(!list.isSelectionEmpty()) {
    599             setDefault((Language)list.getSelectedValue());
    600             clear_default.setEnabled(true);
    601             default_language_value.setText(default_language.toString());
    602         }
    603         }
    604     }
     443        if(!language_list.isSelectionEmpty()) {
     444            setDefault((Language)language_list.getSelectedValue());
     445            clear_button.setEnabled(true);
     446            default_language_field.setText(default_language.toString());
     447        }
     448        }
     449    }
     450
    605451    /** Listens for selections within the list on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
    606452    private class ListListener
     
    610456         */
    611457        public void valueChanged(ListSelectionEvent event) {
    612         if(list.isSelectionEmpty()) {
    613             remove.setEnabled(false);
    614             set_default.setEnabled(false);
     458        if(language_list.isSelectionEmpty()) {
     459            remove_button.setEnabled(false);
     460            set_button.setEnabled(false);
    615461        }
    616462        else {
    617             remove.setEnabled(true);
    618             set_default.setEnabled(true);
    619         }
    620         refreshAppearance();
    621         }
    622     }
    623     /** Our list cel renderer which renders the default cell just a little different. */
    624     private class ListRenderer
    625         extends DefaultListCellRenderer {
    626         /** Method to produce the component used to display an entry in the list.
    627          * @param list The <strong>JList</strong> the component will be placed in.
    628          * @param value A value to be displayed for this component, as a <strong>Object</strong>.
    629          * @param index The position in the list it will occupy as an <i>int</i>.
    630          * @param isSelected Whether the user has currently selected this component, as a <i>boolean</i>.
    631          * @param cellHasFocus Whether the component currently has focus, again as a <i>boolean</i>.
    632          * @return A <strong>Component</strong> to be used as the entry in the list.
    633          * @see org.greenstone.gatherer.cdm.Language
    634          */
    635         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    636         Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    637         Language language = (Language) value;
    638         if(language.isDefault() && !isSelected) {
    639             component.setBackground(Gatherer.config.getColor("coloring.workspace_selection_background", false));
    640         }
    641         if(component instanceof JLabel) {
    642             ((JLabel)component).setOpaque(true);
    643         }
    644         return component;
     463            remove_button.setEnabled(true);
     464            set_button.setEnabled(true);
     465        }
    645466        }
    646467    }
  • trunk/gli/src/org/greenstone/gatherer/cdm/PlugIn.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    44 /**
    45  * Title:        The Gatherer<br>
    46  * Description:  The Gatherer: a tool for gathering and enriching digital collections.<br>
    47  * Copyright:    Copyright (c) 2001<br>
    48  * Company:      The University of Waikato<br>
    49  * First Coded:  01/05/02
    50  * @author John Thompson, Greenstone Digital Libraries
    51  * @version 2.1
    52  */
    53 import java.io.Serializable;
    54 import java.util.ArrayList;
    55 import java.util.Collections;
     28
     29import java.io.*;
     30import java.util.*;
     31import org.greenstone.gatherer.Gatherer;
    5632import org.greenstone.gatherer.cdm.Argument;
    5733import org.greenstone.gatherer.cdm.ArgumentContainer;
     34import org.greenstone.gatherer.cdm.DOMProxyListEntry;
     35import org.greenstone.gatherer.util.StaticStrings;
     36import org.w3c.dom.*;
    5837/** This class is responsible for storing information from a parsed pluginfo call in such a way that it allows easy access to parsed details for the purposes of user design and specification of plugins. */
    59 // ####################################################################################
    60 // Optimization                          Saving
    61 // ####################################################################################
    62 // Vector -> ArrayList                   + Memory, + Processor (pos. - Processor)
    63 // ####################################################################################
    6438public 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.
     39    extends ArrayList
     40    implements ArgumentContainer, Comparable, DOMProxyListEntry, Serializable {
     41    /** The DOM Element this assigned PlugIn is modelled on. */
     42    private Element element;
     43    /** The parent PlugIn this one inherits from, if any. */
     44    private PlugIn super_plugin;
     45    private String description;
     46    private String name;
     47
     48    /** Constructor used only in DOMProxyListModel initializations.
    7649     */
    7750    public PlugIn() {
     51    }
     52
     53    public PlugIn(Element element, PlugIn base_plugin) {
    7854    super();
    79     }
    80     /** Constructor.
    81       * @param name The name of this plugin as a <strong>String</strong>.
    82       * @param desc A description of this plugin as a <strong>String</strong>.
    83       * @param super_plugin The super class of this plugin, as a <strong>PlugIn</strong>.
    84       */
    85     public PlugIn(String name, String desc, PlugIn super_plugin) {
     55    this.element = element;
     56    this.name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     57    ///atherer.println("Establishing Plugin: " + name);
     58    // Parse in any argument options for this plugin, keeping a list of the ones found
     59    HashMap known_arguments = new HashMap();
     60    NodeList option_elements = element.getElementsByTagName(StaticStrings.OPTION_ELEMENT);
     61    int option_elements_length = option_elements.getLength();
     62    for(int i = 0; i < option_elements_length; i++) {
     63        Element option_element = (Element) option_elements.item(i);
     64        Argument argument = new Argument(option_element);
     65        ///atherer.println("Rebuilding existing argument: " + argument.getName());
     66        argument.setOwner(name);
     67        add(argument);
     68        known_arguments.put(argument.getName(), argument);
     69    }
     70    // If a base plugin was given
     71    if(base_plugin != null) {
     72        // Copy the details, and add a reference to whatever base_plugins super plugin is.
     73        description = base_plugin.getDescription();
     74        // Now search through the 'dummy' arguments belonging to the base plugin. For each found, if it is already assigned, fill out further details such as type. If any are found that are not already assigned for this plugin, copy them and add them, but without a value.
     75        ArrayList all_arguments = base_plugin.getArguments(true, true);
     76        int argument_count = all_arguments.size();
     77        for(int j = 0; j < argument_count; j++) {
     78        Argument base_argument = (Argument) all_arguments.get(j);
     79        String base_argument_name = base_argument.getName();
     80        ///atherer.println("Library indicates this plugin should have an argument: " + base_argument_name);
     81        Argument existing_argument = (Argument) known_arguments.get(base_argument_name);
     82        // Found an existing argument. Complete its details
     83        if(existing_argument != null) {
     84            ///atherer.println("Found existing argument. Filling out details.");
     85            existing_argument.setCustomArgument(false);
     86            existing_argument.setDefaultValue(base_argument.getDefaultValue());
     87            existing_argument.setDescription(base_argument.getDescription());
     88            existing_argument.setOptions(base_argument.getOptions());
     89            existing_argument.setRequired(base_argument.isRequired());
     90            existing_argument.setType(base_argument.getType());
     91        }
     92        // No existing argument. Copy base_argument and add it, but do not set its assigned flag. That should be set the first time its changed by the user.
     93        else {
     94            ///atherer.println("No such argument. Adding new, unassigned, argument.");
     95            // The trick thing is that we have to create a new element in the DOM as well.
     96            Argument new_argument = base_argument.copy();
     97            Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
     98            argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, base_argument_name);
     99            argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
     100            argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.FALSE_STR);
     101            new_argument.setElement(argument_element);
     102            // All done. Add it.
     103            element.appendChild(argument_element);
     104            add(new_argument);
     105        }
     106        }
     107    }
     108    }
     109
     110    /** This constructor is only used for library level Plugins.
     111     * @param name
     112     * @param description
     113     * @param super_plugin
     114     */
     115    public PlugIn(String name, String description, PlugIn super_plugin) {
    86116    super();
    87     this.desc = desc;
     117    this.description = description;
    88118    this.name = name;
    89119    this.super_plugin = super_plugin;
    90120    }
    91     /** Method to add an argument to this plugin. Only adds the argument if it isn't already present.
    92       * @param argument The <strong>Argument</strong> to add.
    93       */
     121
     122    /** Method to add an argument to this base plugin. Only adds the argument if it isn't already present, and only if this is a base plugin (ie not based on DOM).
     123     * @param argument the Argument to add
     124     */
    94125    public void addArgument(Argument argument) {
    95     if(!contains(argument)) {
     126    if(element == null && !contains(argument)) {
    96127        add(argument);
    97128        argument.setOwner(name);
    98129    }
    99130    }
     131
    100132    /** Method to compare two plugins for ordering.
    101       * @param object The plugin we are comparing to, as an <strong>Object</strong>.
    102       * @return An <i>int</i> specifying the plugin order, using values as set out in <strong>String</strong>.
    103       * @see java.lang.String#compareTo
    104       */
     133     * @param object The plugin we are comparing to, as an <strong>Object</strong>.
     134     * @return An <i>int</i> specifying the plugin order, using values as set out in <strong>String</strong>.
     135     * @see java.lang.String#compareTo
     136     */
    105137    public int compareTo(Object object) {
    106     if(object != null && object instanceof PlugIn) {
    107         PlugIn plugin = (PlugIn) object;
    108         return name.compareTo(plugin.getName());
     138    if(object instanceof PlugIn) {
     139        return name.compareTo(((PlugIn)object).getName());
    109140    }
    110141    return -1;
    111142    }
    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).
    113       * @return A newly created <strong>PlugIn</strong> with the same details and <strong>Argument</strong>s as this one.
    114       */
    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     }
     143
     144    /** The assigned plugin constructor.
     145     * @param element the DOM Element this plugin is based upon
     146     * @param base_plugin the PlugIn from the stored library showing details about this plugin, may be null
     147     */
     148    public DOMProxyListEntry create(Element element) {
     149    String plugin_name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     150    // Determine the base plugin from the plugin name
     151    PlugIn base_plugin = CollectionDesignManager.plugin_manager.getBasePlugIn(plugin_name);
     152    PlugIn plugin = new PlugIn(element, base_plugin);
     153    base_plugin = null;
     154    plugin_name = null;
     155    return plugin;
     156    }
     157
    128158    /** Method to determine if two plugins are equal.
    129       * @param object The plugin to test against, as an <strong>Object</strong>.
    130       * @return <i>true</i> if the plugin names match, <i>false</i> otherwise.
    131       */
     159     * @param object The plugin to test against, as an <strong>Object</strong>.
     160     * @return <i>true</i> if the plugin names match, <i>false</i> otherwise.
     161     */
    132162    public boolean equals(Object object) {
    133     if(object != null && compareTo(object) == 0) {
    134         return true;
    135     }
    136     return false;
    137     }
     163    return (compareTo(object) == 0);
     164    }
     165
    138166    /** Method to retrieve an argument by its name.
    139       * @param name The name of the argument as a <strong>String</strong>.
    140       * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
    141       */
     167     * @param name The name of the argument as a <strong>String</strong>.
     168     * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
     169     */
    142170    public Argument getArgument(String name) {
    143171    // The name given may still include the '-'
     
    145173        name = name.substring(1);
    146174    }
    147     ArrayList arguments = getArguments();
     175    ArrayList arguments = getArguments(true, true);
    148176    for(int i = 0; i < arguments.size(); i++) {
    149177        Argument argument = (Argument)arguments.get(i);
     
    154182    return null;
    155183    }
    156     /** Method to retrieve all of the arguments available to a plugin, including both specific and general ones.
    157       * @return A <strong>Hashtable</strong> of arguments, with <name> -> <argument> entries.
    158       */
    159     public ArrayList getArguments() {
    160     ArrayList all_arguments = new ArrayList(this);
    161     Collections.sort(all_arguments);
     184
     185    /** Retrieve all of the arguments available to this base plugin, including its super plugins arguments. Some complexity is added by allowing the caller to choose whether they want normal arguments, custom arguments, or both.
     186     * @return an ArrayList of all of the arguments, starting with those for this plugin and ending with the arguments for basplug or similiar root plugin
     187     */
     188    public ArrayList getArguments(boolean include_normal, boolean include_custom) {
     189    ArrayList arguments = new ArrayList();
     190    if(include_normal && include_custom) {
     191        arguments.addAll(this);
     192    }
     193    else {
     194        int size = size();
     195        for(int i = 0; i < size; i++) {
     196        Argument argument = (Argument) get(i);
     197        if(argument.isCustomArgument()) {
     198            if(include_custom && !arguments.contains(argument)) {
     199            arguments.add(argument);
     200            }
     201        }
     202        else {
     203            if(include_normal && !arguments.contains(argument)) {
     204            arguments.add(argument);
     205            }
     206        }
     207        argument = null;
     208        }
     209    }
    162210    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.
    174       * @return The custom arguments as a <strong>String</strong>.
    175       */
     211        ArrayList remainder = super_plugin.getArguments(include_normal, include_custom);
     212        remainder.removeAll(arguments);
     213        arguments.addAll(remainder);
     214    }
     215    return arguments;
     216    }
     217
     218    /** Method to retrieve a plugins custom argument information. Custom arguments are defined to be those that have not got matching arguments in the base reference plugin from the library. Of course if there is no base plugin then all arguments are considered to be custom.
     219     * @return the custom arguments as a String
     220     */
    176221    public String getCustom() {
    177     return custom;
    178     }
     222    StringBuffer custom_text = new StringBuffer();
     223    // Retrieve all of the arguments, and append any that are custom into one long string
     224    ArrayList arguments = getArguments(false, true);
     225    int arguments_size = arguments.size();
     226    boolean first = true;
     227    for(int i = 0; i < arguments_size; i++) {
     228        Argument argument = (Argument) arguments.get(i);
     229        if(argument.isAssigned()) {
     230        if(!first) {
     231            custom_text.append(" ");
     232        }
     233        custom_text.append(argument.toString());
     234        first = false;
     235        }
     236    }
     237    return custom_text.toString();
     238    }
     239
     240    public String getDescription() {
     241    return description;
     242    }
     243
     244    public Element getElement() {
     245    return element;
     246    }
     247
    179248    /** Method to retrieve a plugins name.
    180       * @return A <strong>String</strong> containing the plugins name.
    181       */
     249     * @return A <strong>String</strong> containing the plugins name.
     250     */
    182251    public String getName() {
     252    if(name == null && element != null) {
     253        name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     254    }
    183255    return name;
    184256    }
    185     public void setCustom(String custom) {
    186     this.custom = custom;
    187     }
     257
     258    public boolean isAssigned() {
     259    return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
     260    }
     261
     262    public boolean isSeparator() {
     263    return (element != null && element.getAttribute(StaticStrings.SEPARATOR_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
     264    }
     265
     266    public void setAssigned(boolean assigned) {
     267    if(element != null) {
     268        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     269    }
     270    }
     271
     272    /** Set the custom arguments. This turns out to be quite tricky. We must parse in the string, searching for arguments (for that we use a handy method in CollectionConfiguration). Next, for each argument, we check if we already know about it. If so we update its value, otherwise we create a new argument and assign it (must assign!).
     273     * @param custom_str the custom arguments all splodged together in one String
     274     */
     275    public void setCustom(String custom_str) {
     276    HashMap raw_arguments = CollectionConfiguration.parseArguments(new CommandTokenizer(custom_str));
     277    ArrayList custom_arguments = getArguments(false, true);
     278    int size = custom_arguments.size();
     279    for(int i = 0; i < size; i++) {
     280        Argument argument = (Argument) custom_arguments.get(i);
     281        String original_argument_name = StaticStrings.MINUS_CHARACTER + argument.getName();
     282        if(raw_arguments.containsKey(original_argument_name)) {
     283        // Set as assigned
     284        argument.setAssigned(true);
     285        String argument_value = (String)raw_arguments.remove(original_argument_name);
     286        if(argument_value != null) {
     287            argument.setValue(argument_value);
     288            argument_value = null;
     289        }
     290        }
     291        // We've removed it from our custom statement, so unassign
     292        else {
     293        argument.setAssigned(false);
     294        }
     295        argument = null;
     296    }
     297    // Any left over, add to the plugin
     298    Iterator argument_names = raw_arguments.keySet().iterator();
     299    while(argument_names.hasNext()) {
     300        String argument_name = (String) argument_names.next();
     301        String argument_value = (String) raw_arguments.get(argument_name);
     302        // The tricky thing is that we have to create a new element in the DOM as well.
     303        Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
     304        argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, argument_name.substring(1));
     305        argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
     306        argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.TRUE_STR);
     307        Argument argument = new Argument(argument_element);
     308        argument_name = null;
     309        if(argument_value != null) {
     310        argument.setValue(argument_value);
     311        argument_value = null;
     312        }
     313        // All done. Add it.
     314        element.appendChild(argument_element);
     315        add(argument);
     316        argument_element = null;
     317    }
     318    raw_arguments = null;
     319    }
     320
    188321    /** Method to set the value of desc.
    189       * @param desc The new value of desc as a <strong>String</strong>.
    190       */
    191     public void setDesc(String desc) {
    192     this.desc = desc;
    193     }
     322     * @param desc The new value of desc as a <strong>String</strong>.
     323     */
     324    public void setDescription(String desc) {
     325    this.description = description;
     326    }
     327
     328    public void setElement(Element element) {
     329    this.element = element;
     330    }
     331
    194332    /** Method to set the value of name.
    195       * @param name The new value of name as a <strong>String</strong>.
    196       */
     333     * @param name The new value of name as a <strong>String</strong>.
     334     */
    197335    public void setName(String name) {
    198336    this.name = name;
    199337    }
     338
    200339    /** Method to set the value of the super_plugin.
    201       * @param super_plugin The new value of super_plugin as a <strong>PlugIn</strong>, or <i>null</i> if this class has no inheritance.
    202       */
     340     * @param super_plugin The new value of super_plugin as a <strong>PlugIn</strong>, or <i>null</i> if this class has no inheritance.
     341     */
    203342    public void setSuper(PlugIn super_plugin) {
    204343    this.super_plugin = super_plugin;
    205344    }
     345
    206346    /** Method to print out this plugin as it would appear as a command within the collection configuration file.
    207       * @return A <strong>String</strong> containing a single plugin command.
    208       */
     347     * @return A <strong>String</strong> containing a single plugin command.
     348     */
    209349    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;
     350    if(element != null) {
     351        if(name == null) {
     352        name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
     353        }
     354        StringBuffer text = new StringBuffer(StaticStrings.PLUGIN_STR);
     355        text.append(" ");
     356        text.append(name);
     357        text.append(" ");
     358        ArrayList arguments = getArguments(true, true);
     359        int arguments_size = arguments.size();
     360        for(int i = 0; i < arguments_size; i++) {
     361        Argument argument = (Argument)arguments.get(i);
     362        if(argument.isAssigned()) {
     363            text.append(argument.toString());
     364            text.append(" ");
     365        }
     366        argument = null;
     367        }
     368        return text.substring(0, text.length() - 1);
     369    }
     370    // Basic Plugin
     371    else {
     372        return name;
     373    }
    226374    }         
    227375}
  • trunk/gli/src/org/greenstone/gatherer/cdm/PlugInManager.java

    r4838 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    44 /**
    45  * Title:        The Gatherer<br>
    46  * Description:  The Gatherer: a tool for gathering and enriching digital collections.<br>
    47  * Copyright:    Copyright (c) 2001<br>
    48  * Company:      The University of Waikato<br>
    49  * First Coded:  01/05/02
    50  * @author John Thompson, Greenstone Digital Libraries
    51  * @version 2.1
    52  */
     28
    5329import java.awt.*;
    5430import java.awt.event.*;
     
    5733import javax.swing.*;
    5834import javax.swing.event.*;
    59 import javax.swing.plaf.basic.BasicArrowButton;
    60 import org.apache.xerces.parsers.DOMParser;
     35import javax.swing.plaf.basic.*;
     36import org.apache.xerces.parsers.*;
    6137import org.greenstone.gatherer.Gatherer;
    6238import org.greenstone.gatherer.cdm.Argument;
    6339import org.greenstone.gatherer.cdm.ArgumentConfiguration;
     40import org.greenstone.gatherer.cdm.CollectionDesignManager;
    6441import org.greenstone.gatherer.cdm.CommandTokenizer;
     42import org.greenstone.gatherer.cdm.Control;
    6543import org.greenstone.gatherer.cdm.DynamicListModel;
    6644import org.greenstone.gatherer.cdm.PlugIn;
    67 import org.greenstone.gatherer.msm.ElementWrapper;
     45import org.greenstone.gatherer.gui.GComboBox;
    6846import org.greenstone.gatherer.msm.MSMUtils;
     47import org.greenstone.gatherer.util.StaticStrings;
    6948import org.greenstone.gatherer.util.Utility;
    7049import org.w3c.dom.*;
    71 import org.xml.sax.InputSource;
     50import org.xml.sax.*;
    7251/** This class is resposible for maintaining a list of known plug-ins, and importing new plugins using the parser. */
    73 public class PlugInManager {
    74     /** A reference to the main manager for this module. */
    75     private CollectionDesignManager manager = null;
     52public class PlugInManager
     53    extends DOMProxyListModel {
     54    /** The library 'reserve' of base plugins. */
     55    private ArrayList library = null;
    7656    /** The controls for editing the contents of this manager. */
    7757    private Control controls = null;
    78     /** A list of assigned plugins. */
    79     private DynamicListModel assigned = null;
    80     /** A list of those plugins that have not yet been assigned. Begins as a copy of reserve. */
    81     private DynamicListModel available = null;
    82     /** A list of known, but currently unassigned, plug-ins. */
    83     private DynamicListModel reserve = null;
    84     /** A reference to the Gatherer. */
    85     private Gatherer gatherer = null;
    86     /** The current index of the separator. */
    87     private JPanel separator = null;
     58    private DOMProxyListModel model;
     59    private JPanel separator;
     60    private PlugIn separator_plugin;
    8861    /** The default size for a label. */
    8962    static final private Dimension LABEL_SIZE = new Dimension(140, 20);
    9063    /** Constructor.
    9164     */
    92     public PlugInManager(Gatherer gatherer, CollectionDesignManager manager) {
    93     this.assigned = new DynamicListModel();
    94     this.gatherer = gatherer;
    95     this.manager = manager;
    96     this.separator = getSeparator();
    97     // Add the movement separator
    98     assigned.addElement(separator);
     65    public PlugInManager() {
     66    super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.PLUGIN_ELEMENT, new PlugIn());
     67    Gatherer.println("PlugInManager: " + getSize() + " plugins parsed.");
     68    model = this;
     69    // Reload/Create the library
    9970    loadPlugIns();
    10071    savePlugIns();
    101     }
    102     /** Method to add a new plugin to reserve.
    103       * @param plugin The new <strong>PlugIn</strong>.
    104       */
     72    // Create the separator, cause we can reuse it.
     73    separator = getSeparator();
     74    }
     75    /** Method to add a new plugin to the library
     76     * @param plugin the new base PlugIn
     77     */
    10578    public void addPlugIn(PlugIn plugin) {
    106     if(!reserve.contains(plugin)) {
    107         reserve.addElement(plugin);
    108         available.addElement(plugin);
    109     }
    110     }
    111     /** Method to assign a plugin.
    112       * @param plugin The reserve <strong>PlugIn</strong> to assign.
    113       */
     79    if(!library.contains(plugin)) {
     80        library.add(plugin);
     81    }
     82    }
     83
     84    /** Method to assign a plugin
     85     * @param plugin the PlugIn to assign
     86     */
    11487    public void assignPlugIn(PlugIn plugin) {
    115     if(!assigned.contains(plugin)) {
    116         if(plugin.getName().equals("RecPlug") || plugin.getName().equals("ArcPlug")) {
    117         assigned.addElement(plugin); // Adds after separator
    118         }
    119         else {
    120         int index = assigned.indexOf(separator);
    121         assigned.add(index, plugin);
    122         }
    123                 // Remove from available
    124         available.removeElement(plugin);
    125         gatherer.c_man.configurationChanged();
    126     }
    127     }
     88    if(plugin.getName().equals(StaticStrings.RECPLUG_STR) || plugin.getName().equals(StaticStrings.ARCPLUG_STR)) {
     89        addAfter(plugin, separator_plugin); // Adds after separator
     90    }
     91    else {
     92        addBefore(plugin, separator_plugin);
     93    }
     94    Gatherer.c_man.configurationChanged();
     95    }
     96
     97    /** Destructor. */
     98    public void destroy() {
     99    if(controls != null) {
     100        controls.destroy();
     101        controls = null;
     102    }
     103    library.clear();
     104    library = null;
     105    }
     106
    128107    /** Method to retrieve the control for this manager.
    129       * @return A <strong>JPanel</strong> containing the controls.
    130       */
    131     public JPanel getControls() {
     108     * @return the Control
     109     */
     110    public Control getControls() {
    132111    if(controls == null) {
    133         controls = new Control();
     112        // Build controls
     113        controls = new PlugInControl();
    134114    }
    135115    return controls;
    136116    }
    137     /** Method to retrieve the named plugin.
    138       * @param name The name of the desired plugin as a <strong>String</strong>.
    139       * @return The requested <strong>PlugIn</strong> or <i>null</i> if no such plugin exists.
    140       */
    141     public PlugIn getPlugIn(String name) {
    142     for(int i = 0; i < reserve.size(); i++) {
    143         Object object = reserve.get(i);
    144         if(object instanceof PlugIn) {
    145         PlugIn plugin = (PlugIn) object;
    146         if(plugin.getName().equals(name)) {
    147             return plugin;
    148         }
     117
     118    /** Retrieve the base pluging of the given name, or null if no such plugin.
     119     * @param name the name of the base plugin to retrieve as a String
     120     * @return the PlugIn requested or null if no such plugin
     121     */
     122    public PlugIn getBasePlugIn(String name) {
     123    int library_size = library.size();
     124    for(int i = 0; i < library_size; i++) {
     125        PlugIn plugin = (PlugIn) library.get(i);
     126        if(plugin.getName().equals(name)) {
     127        return plugin;
    149128        }
    150129    }
     
    152131    return null;
    153132    }
    154     /** Method to invalidate controls after a significant change in the system state.
    155       */
    156     public void invalidateControls() {
    157     if(controls != null) {
    158         controls.destroy();
    159     }
    160     controls = null;
    161     }
     133
     134    /** Method to move a plugin in the list order.
     135     * @param plugin the PlugIn you want to move.
     136     * @param direction true to move the plugin up, false to move it down.
     137     * @param all true to move to move all the way, false for a single step.
     138     */
     139    public void movePlugIn(PlugIn plugin, boolean direction, boolean all) {
     140    // Can't ever move RecPlug or ArcPlug.
     141    if(getSize() < 3) {
     142        Gatherer.println("Not enough plugins to allow moving.");
     143        return;
     144    }
     145    if(plugin.getName().equals(StaticStrings.ARCPLUG_STR) || plugin.getName().equals(StaticStrings.RECPLUG_STR)) {
     146        JOptionPane.showMessageDialog(Gatherer.g_man, get("CDM.Move.Fixed"), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     147        return;
     148    }
     149    if(all) {
     150        // Move to top
     151        if(direction) {
     152        // Remove the moving plugin
     153        remove(plugin);
     154        // Retrieve the first plugin
     155        PlugIn first_plugin = (PlugIn) getElementAt(0);
     156        // Add the moving plugin before the first plugin
     157        addBefore(plugin, first_plugin);
     158        first_plugin = null;
     159        Gatherer.c_man.configurationChanged();
     160        }
     161        else {
     162        // Remove the moving plugin
     163        remove(plugin);
     164        // Locate the plugin immediately before the separator. We have to ensure the separator index is up to date, given we've just removed a plugin.
     165        int separator_index = -1;
     166        if((separator_index = findSeparatorIndex()) != -1) {
     167            PlugIn separator_plugin = (PlugIn) getElementAt(separator_index);
     168            // Add the moving plugin before the separator
     169            addBefore(plugin, separator_plugin);
     170            Gatherer.c_man.configurationChanged();     
     171        }
     172        // Otherwise we aren't moving anywhere!
     173        }
     174    }
     175    else {
     176        // Try to move the plugin one step in the desired direction.
     177        int index = indexOf(plugin);
     178        ///ystem.err.println("Index of " + plugin + " = " + index);
     179        if(direction) {
     180        index--;
     181        if(index < 0) {
     182            String args[] = new String[2];
     183            args[0] = get("CDM.PlugInManager.PlugIn_Str");
     184            args[1] = plugin.getName();
     185            JOptionPane.showMessageDialog(Gatherer.g_man, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     186            return;
     187        }
     188        remove(plugin);
     189        add(index, plugin);
     190        Gatherer.c_man.configurationChanged();
     191        }
     192        else {
     193        index++;
     194        PlugIn next_plugin = (PlugIn) getElementAt(index);
     195        if(next_plugin.isSeparator()) {
     196            String args[] = new String[1];
     197            args[0] = plugin.getName();
     198            JOptionPane.showMessageDialog(Gatherer.g_man, get("CDM.Move.Cannot", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
     199            // Still not going to move RecPlug or ArcPlug.
     200            return;
     201        }
     202        remove(plugin);
     203        add(index, plugin);
     204        Gatherer.c_man.configurationChanged();
     205        }
     206    }
     207    }
     208
     209    /** We attempt to place the separator between the unfixed and the fixed plugins. Since we only know of two fixed plugins, we search for either of them, and place the separator before them.
     210     */
     211    public void placeSeparator() {
     212    ///ystem.err.println("Placing separator.");
     213    int separator_index = getSize();
     214    if(separator_index > 0) {
     215        boolean found_fixed = false;
     216        int index = separator_index - 1;
     217        while(index > 0) {
     218        PlugIn plugin = (PlugIn) getElementAt(index);
     219        String name = plugin.getName();
     220        if(name.equals(StaticStrings.RECPLUG_STR) || name.equals(StaticStrings.ARCPLUG_STR)) {
     221            found_fixed = true;
     222            index--;
     223        }
     224        else {
     225            if(found_fixed) {
     226            separator_index = index + 1;
     227            index = -1;
     228            }
     229            else {
     230            index--;
     231            }
     232        }
     233        name = null;
     234        plugin = null;
     235        }
     236    }
     237    Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
     238    element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, CollectionConfiguration.SEPARATOR_ATTRIBUTE);
     239    element.setAttribute(CollectionConfiguration.SEPARATOR_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
     240    separator_plugin = new PlugIn(element, null);
     241    ///atherer.println("Adding plugin separator at: " + separator_index);
     242    add(separator_index, separator_plugin);
     243    }
     244
     245    /** This method removes an assigned plugin. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a plugin from the library.
     246     * @param plugin The <strong>PlugIn</strong> to remove.
     247     */
     248    public void removePlugIn(PlugIn plugin) {
     249    remove(plugin);
     250    Gatherer.c_man.configurationChanged();
     251    }
     252
     253    /** Method to cache the current contents of library (known plugins) to file.
     254     */
     255    public void savePlugIns() {
     256    try {
     257        FileOutputStream file = new FileOutputStream(Utility.BASE_DIR + "plugins.dat");
     258        ObjectOutputStream out = new ObjectOutputStream(file);
     259        out.writeObject(library);
     260        out.close();
     261    }
     262    catch (Exception error) {
     263        Gatherer.printStackTrace(error);
     264    }
     265    }
     266
     267    /** Determine the current separator index. */
     268    private int findSeparatorIndex() {
     269    int separator_index = getSize() - 1;
     270    while(separator_index >= 0) {
     271        PlugIn search = (PlugIn) getElementAt(separator_index);
     272        if(search.isSeparator()) {
     273        return separator_index;
     274        }
     275        separator_index--;
     276    }
     277    return separator_index;
     278    }
     279
     280    /* Retrieve a phrase from the dictionary based on a certain key.
     281     * @param key The search <strong>String</strong>.
     282     * @return The matching phrase from the Dictionary.
     283     */
     284    private String get(String key) {
     285    return get(key, (String[])null);
     286    }
     287   
     288    private String get(String key, String arg) {
     289    String args[] = new String[1];
     290    args[0] = arg;
     291    return get(key, args);
     292    }
     293
     294    /* Retrieve a phrase from the dictionary based on a certain key and arguments.
     295     * @param key The search <strong>String</strong>.
     296     * @param args A <strong>String[]</strong> of arguments used to complete and format the choosen phrase.
     297     * @return The matching phrase from the Dictionary.
     298     */
     299    private String get(String key, String args[]) {
     300    if(key.indexOf(".") == -1) {
     301        key = "CDM.PlugInManager." + key;
     302    }
     303    return Gatherer.dictionary.get(key, args);
     304    }   
     305
     306    /** Retrieve a list of those plugins that are in library but not in the assigned plugins. */
     307    private Object[] getAvailable() {
     308    ArrayList available = new ArrayList();
     309    available.addAll(library);
     310    // Now go through the assigned plugins, and remove any that match.
     311    available.removeAll(children());
     312    return available.toArray();
     313    }
     314
     315    /** Method to extract just the plugins name from a file object.
     316     * @param plugin The <strong>File</strong> which references a certain plugin.
     317     * @return A <strong>String</strong> containing just the plugins name, without extension.
     318     */
     319    private String getPlugInName(File plugin) {
     320    String name = plugin.getName();
     321    if(name.indexOf(".") != -1) {
     322        name = name.substring(0, name.indexOf("."));
     323    }
     324    return name;
     325    }
     326
    162327    /** Method to load the details of a single plug-in.
    163       * @param plugin The plugin <strong>File</strong> you wish to load.
    164       */
    165     public void loadPlugIn(File plugin) {
     328     * @param plugin The plugin <strong>File</strong> you wish to load.
     329     */
     330    private void loadPlugIn(File plugin) {
    166331    Document document = null;
    167332    // Run pluginfo on this plugin, and then send the results for parsing.
     
    170335        if(Utility.isWindows()) {
    171336        args = new String[4];
    172         if(gatherer.config.perl_path != null) {
    173             args[0] = gatherer.config.perl_path;
     337        if(Gatherer.config.perl_path != null) {
     338            args[0] = Gatherer.config.perl_path;
    174339        }
    175340        else {
    176341            args[0] = "Perl.exe";
    177342        }
    178         args[1] = gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl";
     343        args[1] = Gatherer.config.gsdl_path + "bin" + File.separator + "script" + File.separator + "pluginfo.pl";
    179344        args[2] = "-xml";
    180345        args[3] = getPlugInName(plugin);
     
    229394    }
    230395    if(document != null) {
    231         parse(document.getDocumentElement());
    232     }
    233     }
    234     /** Method to move a plugin higher in the list order.
    235       * @param plugin The <strong>PlugIn</strong> you want to move.
    236       * @param direction <i>true</i> to move the plugin up, <i>false</i> to move it down.
    237       * @param all <i>true</i> to move to move all the way, <i>false</i> for a single step.
    238       */
    239     public void movePlugIn(PlugIn plugin, boolean direction, boolean all) {
    240     // Can't ever move RecPlug or ArcPlug.
    241     if(plugin.getName().equals("ArcPlug") || plugin.getName().equals("RecPlug")) {
    242         JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Fixed"), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    243         return;
    244     }
    245     if(all) {
    246         if(direction) {
    247         assigned.removeElement(plugin);
    248         assigned.add(0, plugin);
    249         gatherer.c_man.configurationChanged();
    250         }
    251         else {
    252         assigned.removeElement(plugin);
    253         int index = assigned.size() - 1;
    254         boolean found = false;
    255         while(!found) {
    256             Object temp = assigned.get(index);
    257             if(temp instanceof PlugIn) {
    258             PlugIn current = (PlugIn) temp;
    259             if(current.getName().equals("ArcPlug") || current.getName().equals("RecPlug")) {
    260                 index--;
    261             }
    262             else {
    263                 found = true;
    264             }
    265             }
    266             else {
    267             found = true;
    268             }
    269         }
    270         assigned.add(index, plugin);
    271         gatherer.c_man.configurationChanged();
    272         }
    273     }
    274     else {
    275                 // Try to move the plugin one step in the desired direction.
    276         int index = assigned.indexOf(plugin);
    277                 ///ystem.err.println("Index of " + plugin + " = " + index);
    278         if(direction) {
    279         index--;
    280         if(index < 0) {
    281             String args[] = new String[1];
    282             args[0] = plugin.getName();
    283             JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Top", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    284             return;
    285         }
    286         assigned.removeElement(plugin);
    287         assigned.add(index, plugin);
    288         gatherer.c_man.configurationChanged();
    289         }
    290         else {
    291         index++;
    292         Object object = assigned.get(index);
    293         if(index == assigned.size()) {
    294             String args[] = new String[1];
    295             args[0] = plugin.getName();
    296             JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.At_Bottom", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    297             // Still not going to move RecPlug or ArcPlug.
    298             return;
    299         }
    300         else if(!(object instanceof PlugIn) || ((PlugIn)object).getName().equals("ArcPlug") || ((PlugIn)object).getName().equals("RecPlug")) {
    301             String args[] = new String[1];
    302             args[0] = plugin.getName();
    303             JOptionPane.showMessageDialog(manager.gui, get("CDM.Move.Cannot", args), get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
    304             // Still not going to move RecPlug or ArcPlug.
    305             return;
    306         }
    307         assigned.removeElement(plugin);
    308         assigned.add(index, plugin);
    309         gatherer.c_man.configurationChanged();
    310         }
    311     }
    312     }
    313 
    314     /** 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.
    315       * @param command The coomand <strong>String</strong> that may include plugin information.
    316       * @return <i>true</i> if a plugin command was parsed, <i>false</i> otherwise.
    317       */
    318     public boolean parse(String command) {
    319     String command_lc = command.toLowerCase();
    320     if(command_lc.startsWith("plugin")) {
    321         CommandTokenizer tokenizer = new CommandTokenizer(command);
    322         if(tokenizer.countTokens() >= 2) {
    323         tokenizer.nextToken(); // Throw away 'plugin'
    324         String name = tokenizer.nextToken();
    325         // Try to locate the plugin with this name.
    326         PlugIn plugin = getPlugIn(name);
    327         // And if successful start to parse the arguments.
    328         if(plugin != null) {
    329             // Take a copy.
    330             plugin = plugin.copy();
    331             String key = null;
    332             while(tokenizer.hasMoreTokens()) {
    333             if(key == null) {
    334                 key = tokenizer.nextToken();
    335             }
    336             // Try to retrieve a matching argument.
    337             Argument argument = plugin.getArgument(key);
    338             if(argument != null) {
    339                 // Set as assigned.
    340                 argument.setAssigned(true);
    341                 // And if the argument is of a parameter type, parse a parameter.
    342                 if(argument.getType() != Argument.FLAG && tokenizer.hasMoreTokens()) {
    343                 String value = tokenizer.nextToken();
    344                 ElementWrapper element = null;
    345                 if(argument.getType() == Argument.METADATA) {
    346                     value = value.replace(':', MSMUtils.NS_SEP);
    347                     if (value.indexOf(MSMUtils.NS_SEP)==-1){
    348                     value = Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP + value;
    349                     }
    350                     // Now retrieve the element this refers to, if available.
    351                     element = Gatherer.c_man.getCollection().msm.getElement(value);
    352                 }
    353                 if(element != null) {
    354                     argument.setElementValue(element);
    355                     element = null;
    356                 }
    357                 else {
    358                     argument.setValue(value);
    359                 }
    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.
    419       * @param plugin The <strong>PlugIn</strong> to remove.
    420       */
    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.
    439       * @return An <i>int</i> which is the number of plugins.
    440       */
    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.
    445       * @return A <strong>String</strong> containing a series of plugin commands separated by new lines.
    446       */
    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.
    460       * @param key The search <strong>String</strong>.
    461       * @return The matching phrase from the Dictionary.
    462       */
    463     private String get(String key) {
    464     return get(key, (String[])null);
    465     }
    466 
    467     private String get(String key, String arg) {
    468     String args[] = new String[1];
    469     args[0] = arg;
    470     return get(key, args);
    471     }
    472 
    473     /* Retrieve a phrase from the dictionary based on a certain key and arguments.
    474       * @param key The search <strong>String</strong>.
    475       * @param args A <strong>String[]</strong> of arguments used to complete and format the choosen phrase.
    476       * @return The matching phrase from the Dictionary.
    477       */
    478     private String get(String key, String args[]) {
    479     if(key.indexOf(".") == -1) {
    480         key = "CDM.PlugInManager." + key;
    481     }
    482     return gatherer.dictionary.get(key, args);
    483     }   
    484     /** Method to extract just the plugins name from a file object.
    485       * @param plugin The <strong>File</strong> which references a certain plugin.
    486       * @return A <strong>String</strong> containing just the plugins name, without extension.
    487       */
    488     private String getPlugInName(File plugin) {
    489     String name = plugin.getName();
    490     if(name.indexOf(".") != -1) {
    491         name = name.substring(0, name.indexOf("."));
    492     }
    493     return name;
    494     }
    495     /** Method to retrieve the CData value from a node. Requires a search for the #text node.
    496       * @param node The <strong>Node</strong> whose value we wish to find.
    497       * @return The value of node as a <strong>String</strong>, or <i>null</i> if no value exists.
    498       */
    499     private String getValue(Node node) {
    500     if(node.hasChildNodes()) {
    501         Node text = node.getFirstChild();
    502                 //ystem.err.println("Value of " + node.getNodeName() + " = " + text.getNodeValue());
    503         return text.getNodeValue();
    504     }
    505     return node.getNodeValue();
    506     }
     396        parseXML(document.getDocumentElement());
     397    }
     398    }
     399
    507400    /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
    508401      */
     
    512405        FileInputStream file = new FileInputStream(Utility.BASE_DIR + "plugins.dat");
    513406        ObjectInputStream input = new ObjectInputStream(file);
    514         reserve = (DynamicListModel) input.readObject();
    515         available = reserve.shallowCopy();
     407        library = (ArrayList) input.readObject();
    516408    }
    517409    catch (Exception error) {
    518410    }
    519     if(reserve == null) {
    520         available = new DynamicListModel();
    521         reserve = new DynamicListModel();
    522         reserve.setAutoOrder(true);
    523                 // Retrieve the gsdl home directory...
    524         String directory = gatherer.config.gsdl_path;
     411    if(library == null) {
     412        library = new ArrayList();
     413        // Retrieve the gsdl home directory...
     414        String directory = Gatherer.config.gsdl_path;
    525415        directory = directory + "perllib" + File.separator + "plugins" + File.separator;
    526416        loadPlugIns(new File(directory));
     
    533423    File files[] = directory.listFiles();
    534424    if(files != null) {
    535                 // Create a progress indicator.
     425        // Create a progress indicator.
    536426        ParsingProgress progress = new ParsingProgress(get("CDM.PlugInManager.Parsing.Title"), get("CDM.PlugInManager.Parsing.Message"), files.length);
    537427        for(int i = 0; i < files.length; i++) {
     
    546436    }
    547437
    548     private PlugIn parse(Node root) {
     438    private PlugIn parseXML(Node root) {
    549439    PlugIn plugin = new PlugIn();
    550440    String node_name = null;
     
    553443        node_name = node.getNodeName();
    554444        if(node_name.equals("Name")) {
    555         String name = getValue(node);
     445        String name = MSMUtils.getValue(node);
    556446        // 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.
    557         PlugIn existing = getPlugIn(name);
     447        PlugIn existing = getBasePlugIn(name);
    558448        if(existing != null) {
    559449            return existing;
     
    562452        }
    563453        else if(node_name.equals("Desc")) {
    564         plugin.setDesc(getValue(node));
     454        plugin.setDescription(MSMUtils.getValue(node));
    565455        }
    566456                // Parse the multitude of arguments.
     
    575465                node_name = det.getNodeName();
    576466                if(node_name.equals("Name")) {
    577                 argument.setName(getValue(det));
     467                argument.setName(MSMUtils.getValue(det));
    578468                }
    579469                else if(node_name.equals("Desc")) {
    580                 argument.setDesc(getValue(det));
     470                argument.setDescription(MSMUtils.getValue(det));
    581471                }
    582472                else if(node_name.equals("Type")) {
    583                 argument.setType(getValue(det));
     473                argument.setType(MSMUtils.getValue(det));
    584474                }
    585475                else if(node_name.equals("Default")) {
    586                 argument.setDefault(getValue(det));
     476                argument.setDefaultValue(MSMUtils.getValue(det));
    587477                }
    588478                else if(node_name.equals("List")) {
     
    595485                        node_name = subvalue.getNodeName();
    596486                        if(node_name.equals("Name")) {
    597                         key = getValue(subvalue);
     487                        key = MSMUtils.getValue(subvalue);
    598488                        }
    599489                        else if(node_name.equals("Desc")) {
    600                         desc = getValue(subvalue);
     490                        desc = MSMUtils.getValue(subvalue);
    601491                        }
    602492                    }
     
    608498                }
    609499                else if(node_name.equals("Required")) {
    610                 String v = getValue(det);
     500                String v = MSMUtils.getValue(det);
    611501                if(v != null && v.equals("yes")) {
    612502                    argument.setRequired(true);
     
    618508            // A super plugin class.
    619509            else if(node_name.equals("PlugInfo")) {
    620             PlugIn super_plugin = parse(arg);
     510            PlugIn super_plugin = parseXML(arg);
    621511            plugin.setSuper(super_plugin);
    622512            }
     
    632522
    633523    /** A class which provodes controls for assigned and editing plugins. */
    634     private class Control
    635     extends JPanel {
     524    private class PlugInControl
     525    extends JPanel
     526    implements Control {
    636527    /** Button for adding plugins. */
    637528    private JButton add = null;
     
    649540    private JButton remove = null;
    650541    /** A combobox containing all of the known plugins, including those that may have already been assigned. */
    651     private JComboBox plugin = null;
     542    private GComboBox plugin = null;
    652543    /** The label next to the plugin combobox. */
    653544    private JLabel plugin_label = null;
     
    674565    /** Constructor.
    675566     */
    676     public Control() {
    677         Object plugins[] = reserve.toArray();
     567    public PlugInControl() {
     568        Object plugins[] = library.toArray();
    678569        Vector plugin_model = new Vector();
    679570        for(int i = 0; i < plugins.length; i++) {
     
    681572        }
    682573        Collections.sort(plugin_model);
    683                 // Create
     574        // Create
    684575        add = new JButton(get("Add"));
    685576        add.setMnemonic(KeyEvent.VK_A);
     
    697588        instructions.setWrapStyleWord(true);
    698589        move_bottom = new JButton();
    699         JLabel move_bottom_label = new JLabel(get("Move_Bottom"));
     590        JLabel move_bottom_label = new JLabel(get("CDM.Move.Move_Bottom"));
    700591        move_bottom_label.setHorizontalAlignment(JLabel.CENTER);
    701592        move_bottom_label.setPreferredSize(LABEL_SIZE);
     
    706597        move_bottom.setMnemonic(KeyEvent.VK_B);
    707598        move_down = new JButton();
    708         JLabel move_down_label = new JLabel(get("Move_Down"));
     599        JLabel move_down_label = new JLabel(get("CDM.Move.Move_Down"));
    709600        move_down_label.setHorizontalAlignment(JLabel.CENTER);
    710601        move_down_label.setPreferredSize(LABEL_SIZE);
     
    715606        move_down.setMnemonic(KeyEvent.VK_D);
    716607        move_top = new JButton();
    717         JLabel move_top_label = new JLabel(get("Move_Top"));
     608        JLabel move_top_label = new JLabel(get("CDM.Move.Move_Top"));
    718609        move_top_label.setHorizontalAlignment(JLabel.CENTER);
    719610        move_top_label.setPreferredSize(LABEL_SIZE);
     
    724615        move_top.setMnemonic(KeyEvent.VK_T);
    725616        move_up = new JButton();
    726         JLabel move_up_label = new JLabel(get("Move_Up"));
     617        JLabel move_up_label = new JLabel(get("CDM.Move.Move_Up"));
    727618        move_up_label.setHorizontalAlignment(JLabel.CENTER);
    728619        move_up_label.setPreferredSize(LABEL_SIZE);
     
    733624        move_up.setMnemonic(KeyEvent.VK_U);
    734625        movement_pane = new JPanel();
    735         plugin = new JComboBox(available);
    736         //plugin.setEditable(true);
     626
     627        plugin = new GComboBox(getAvailable());
     628        plugin.setBackgroundNonSelectionColor(Gatherer.config.getColor("coloring.editable", false));
     629        plugin.setBackgroundSelectionColor(Gatherer.config.getColor("coloring.collection_selection_background", false));
     630        plugin.setEditable(true);
    737631        plugin.setSelectedIndex(0);
     632        plugin.setTextNonSelectionColor(Gatherer.config.getColor("coloring.workspace_tree_foreground", false));
     633        plugin.setTextSelectionColor(Gatherer.config.getColor("coloring.collection_selection_foreground", false));
     634
    738635        plugin_label = new JLabel(get("PlugIn"));
    739         plugin_list = new JList(assigned);
     636        plugin_list = new JList(model);
    740637        plugin_list.setCellRenderer(new ListRenderer());
    741638        plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     
    822719    public void destroy() {
    823720    }
    824     /** 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.
    825             * @return <i>true</i> if this control has focus, <i>false</i> otherwise.
    826             */
    827     public boolean hasFocus() {
    828         return super.hasFocus();
    829     }
     721
    830722    /** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
    831             */
    832     public void updateUI() {
     723     */
     724    public void gainFocus() {
    833725        if(instructions != null) {
    834726        instructions.setCaretPosition(0);
     
    836728        super.updateUI();
    837729    }
    838     /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugIn()</i> method.
    839             */
     730
     731    public void loseFocus() {
     732
     733    }
     734
     735    /** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugIn()</i> method. */
    840736    private class AddListener
    841737        implements ActionListener {
    842                 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
    843                 * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
    844                 */
     738        /** 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.
     739        * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
     740        */
    845741        public void actionPerformed(ActionEvent event) {
    846         PlugIn new_plugin = null;
    847         Object object = plugin.getSelectedItem();
    848         if(object instanceof PlugIn) {
    849             PlugIn target = (PlugIn)object;
    850             new_plugin = target.copy();
    851         }
    852         else {
    853             new_plugin = new PlugIn(object.toString(), "", null);
    854         }
    855         object = null;
    856         // Automatically chain to configuration. This ensures required arguments are filled out.
    857         ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, new_plugin);
    858         if(ac.display()) {
    859             assignPlugIn(new_plugin);
    860             plugin_list.setSelectedValue(new_plugin, true);
    861         }
    862         ac = null;
    863         new_plugin = null;
    864         plugin.setSelectedIndex(0);
    865         }
    866     }
    867     /** 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.
    868             * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
    869             */
    870     private class ConfigureListener
    871         implements ActionListener {
    872                 /** 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.
    873                  * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
    874                  */
    875         public void actionPerformed(ActionEvent event) {
    876         if(!plugin_list.isSelectionEmpty()) {
    877             Object object = plugin_list.getSelectedValue();
    878             if(object instanceof PlugIn) {
    879             ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
     742        Object selected_object = plugin.getSelectedItem();
     743        // If there is something in the combobox, but we haven't registered a selection, then add the object and select it!
     744        if(selected_object != null && plugin.getSelectedIndex() == -1) {
     745            plugin.insertItemAt(selected_object, plugin.getItemCount());
     746        }
     747        if(selected_object != null) {
     748            // Create a new element in the DOM
     749            Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
     750            // Remember that the plugin supplied might be a custom string rather than a base plugin
     751            PlugIn new_plugin = null;
     752            if(selected_object instanceof PlugIn) {
     753            PlugIn base_plugin = (PlugIn) selected_object;
     754            element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
     755            new_plugin = new PlugIn(element, base_plugin);
     756            base_plugin = null;
     757            }
     758            else {
     759            element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
     760            new_plugin = new PlugIn(element, null);
     761            }
     762            if(!model.contains(new_plugin)) {
     763            // Automatically chain to configuration. This ensures required arguments are filled out.
     764            ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
    880765            if(ac.display()) {
    881                 assigned.refresh();
     766                assignPlugIn(new_plugin);
     767                plugin_list.setSelectedValue(new_plugin, true);
    882768            }
    883             }
    884         }
    885         }
    886     }
    887     /** A special list renderer which is able to render separating lines as well. */
    888     private class ListRenderer
    889         extends DefaultListCellRenderer {
    890                 /** 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.
    891                  * @param list - The <strong>JList</strong> we're painting.
    892                  * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
    893                  * @param index - The cells index as an <i>int</i>.
    894                  * @param isSelected - <i>true</i> if the specified cell was selected.
    895                  * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
    896                  * @return A <strong>Component</strong> whose paint() method will render the specified value.
    897                  * @see javax.swing.JList
    898                  * @see javax.swing.JSeparator
    899                  * @see javax.swing.ListModel
    900                  * @see javax.swing.ListSelectionModel
    901                  */
    902         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    903         if(value instanceof JPanel) {
    904             return (JPanel) value;
    905         }
    906         else {
    907             return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    908         }
    909         }
    910     }
     769            ac = null;
     770            new_plugin = null;
     771            plugin.setSelectedIndex(0);
     772            }
     773            else {
     774            JOptionPane.showMessageDialog(Gatherer.g_man, get("PlugIn_Exists"), get("General.Error"), JOptionPane.ERROR_MESSAGE);
     775            }
     776        }
     777        }
     778    }
     779
    911780    /** Listens for double clicks apon the list and react as if the configure button was pushed. */
    912781    private class ClickListener
    913782        extends MouseAdapter {
    914                 /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
    915                 * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
    916                 */
     783        /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
     784        * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
     785        */
    917786        public void mouseClicked(MouseEvent event) {
    918787        if(event.getClickCount() == 2 ) {
    919788            if(!plugin_list.isSelectionEmpty()) {
    920             Object object = plugin_list.getSelectedValue();
    921             if(object instanceof PlugIn) {
    922                 ArgumentConfiguration ac = new ArgumentConfiguration(gatherer, manager, (PlugIn)object);
     789            PlugIn plugin = (PlugIn) plugin_list.getSelectedValue();
     790            if(!plugin.isSeparator()) {
     791                ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
    923792                if(ac.display()) {
    924                 assigned.refresh();
     793                refresh(plugin);
    925794                }
     795                ac.destroy();
     796                ac = null;
    926797            }
     798            }
     799        }
     800        }
     801    }
     802
     803    /** 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.
     804     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
     805     */
     806    private class ConfigureListener
     807        implements ActionListener {
     808        /** 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.
     809         * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
     810         */
     811        public void actionPerformed(ActionEvent event) {
     812        if(!plugin_list.isSelectionEmpty()) {
     813            PlugIn plugin = (PlugIn) plugin_list.getSelectedValue();
     814            if(!plugin.isSeparator()) {
     815            ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
     816            if(ac.display()) {
     817                refresh(plugin);
     818            }
     819            ac.destroy();
     820            ac = null;
    927821            }
    928822        }
     
    946840        }
    947841    }
     842
     843    /** A special list renderer which is able to render separating lines as well. */
     844    private class ListRenderer
     845        extends DefaultListCellRenderer {
     846        /** 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.
     847         * @param list - The <strong>JList</strong> we're painting.
     848         * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
     849         * @param index - The cells index as an <i>int</i>.
     850         * @param isSelected - <i>true</i> if the specified cell was selected.
     851         * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
     852         * @return A <strong>Component</strong> whose paint() method will render the specified value.
     853         * @see javax.swing.JList
     854         * @see javax.swing.JSeparator
     855         * @see javax.swing.ListModel
     856         * @see javax.swing.ListSelectionModel
     857         */
     858        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     859        PlugIn plugin = (PlugIn) value;
     860        if(plugin.isSeparator()) {
     861            return separator;
     862        }
     863        else {
     864            return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     865        }
     866        }
     867    }
     868
    948869
    949870    /** 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. */
     
    999920    }
    1000921    /** Creates a list separator.
    1001       * Code courtesy of Farwell, Paul. Contact <a href="mailto:[email protected]">[email protected]</a>
    1002       */
     922     * Code courtesy of Farwell, Paul. Contact <a href="mailto:[email protected]">[email protected]</a>
     923     */
    1003924    static private JPanel getSeparator() {
    1004925    // we put the separator inside a panel to control
     
    1014935    }
    1015936}
    1016 
    1017 
    1018 
    1019 
  • trunk/gli/src/org/greenstone/gatherer/cdm/Subcollection.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    4428/**************************************************************************************
    45  * Title:        Gatherer
    46  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    47  * Copyright:    Copyright (c) 2001
    48  * Company:      The University of Waikato
    4929 * Written:      03/05/02
    5030 * Revised:      17/11/02 - Commenting
     31 *               04/07/03 - Completely rewritten to support DOM
    5132 **************************************************************************************/
     33import org.greenstone.gatherer.Gatherer;
     34import org.greenstone.gatherer.cdm.CollectionConfiguration;
     35import org.greenstone.gatherer.cdm.CollectionDesignManager;
     36import org.greenstone.gatherer.cdm.DOMProxyListEntry;
     37import org.greenstone.gatherer.msm.ElementWrapper;
    5238import org.greenstone.gatherer.msm.MSMUtils;
    53 import org.w3c.dom.Element;
     39import org.greenstone.gatherer.util.StaticStrings;
     40import org.greenstone.gatherer.util.Troolean;
     41import org.w3c.dom.*;
    5442/** This class encapsulates one subcollection entry in the collection configuration file.
    5543 * @author John Thompson, Greenstone Digital Library, University of Waikato
    56  * @version 2.3
     44 * @version 2.4
    5745 */
    5846public class Subcollection
    59     implements Comparable {
     47    implements Comparable, DOMProxyListEntry {
    6048    /** 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;
     49    private Troolean include = new Troolean();
     50    /** The DOM Element this Subcollection is based upon. */
     51    private Element element = null;
     52    /** A String containing a Perl expression which is used as the pattern by which to filter this subcollection. */
     53    private String pattern = null;
    6654    /** A series of flags to be used when matching the expression. */
    6755    private String flags = null;
    6856    /** A String which is a unique identifier of a subcollection. */
    6957    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) {
     58    /** 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. */
     59    private String source = null;
     60    private String text = null;
     61
     62    /** Default constructor which should only be used during DOMProxyListModel initialization. */
     63    public Subcollection() {
     64    }
     65
     66    /** Constructor for representing an existing assigned Subcollection.
     67     * @param element the Element this subcollection is based upon
     68     */
     69    public Subcollection(Element element) {
     70    this.element = element;
     71    }
     72
     73    /** Constructor for assigning a brand new Subcollection.
     74     * @param name a unique identifier for this collection as a String
     75     * @param include true if this the pattern should be an inclusion filter, false for exclusion
     76     * @param source either the fully qualified name of an element as a String, or null to filter filenames
     77     * @param pattern the matching pattern as a String
     78     * @param flags any flags to use while matching, as a String
     79     */
     80    public Subcollection(String name, boolean include, String source, String pattern, String flags) {
     81    // Cache the details
     82    this.flags = flags;
     83    this.include.set(include);
    7584    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    this.pattern = pattern;
     86    if(source != null) {
     87        this.source = source;
    8588    }
    8689    else {
    87         this.include = true;
    88     }
    89     if(pattern.indexOf("/") != -1) {
    90                 // 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;
     90        this.source = StaticStrings.FILENAME_STR;
     91    }
     92    // Create a new DOM Element with the appropriate attributes and text value
     93    element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.SUBCOLLECTION_ELEMENT);
     94    element.setAttribute(StaticStrings.CONTENT_ATTRIBUTE, source);
     95    element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
     96    element.setAttribute(StaticStrings.OPTIONS_ATTRIBUTE, flags);
     97    element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, (include ? StaticStrings.INCLUDE_STR : StaticStrings.EXCLUDE_STR));
     98    MSMUtils.setValue(element, pattern);
     99    }
     100
     101    /** Method to compare two subcollections.
     102     * @param object he other subcollection to compare to, as an Object
     103     * @return an int which is &gt;0, 0, or &lt;0 if this subcollection is before, equal to, or after the target object respectively.
     104     */
     105    public int compareTo(Object object) {
     106    return getName().compareTo(((Subcollection)object).getName());
     107    }
     108
     109    public DOMProxyListEntry create(Element element) {
     110    return new Subcollection(element);
     111    }
     112
     113    /** Method to check two subcollections for equality.
     114     * @param object the other subcollection to compare to, as an Object
     115     * @return true if the subcollections are equal, false otherwise.
     116     */
     117    public boolean equals(Object object) {
     118    return (compareTo(object) == 0);
     119    }
     120
     121    /** Retrieve the DOM Element this Subcollection is based upon.
     122     * @return an Element
     123     */
     124    public Element getElement() {
     125    return element;
     126    }
     127
     128    /** Method to get the value of flags.
     129     * @return the value of flags as a String
     130     */
     131    public String getFlags() {
     132    if(flags == null && element != null) {
     133        flags = element.getAttribute(StaticStrings.OPTIONS_ATTRIBUTE);
     134    }
     135    return flags;
     136    }
     137
     138    /** Method to get the value of name.
     139     * @param String The value of name as a <strong>String</string>.
     140     */
     141    public String getName() {
     142    if(name == null && element != null) {
     143        name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
     144    }
     145    return name;
     146    }
     147
     148    public String getPattern() {
     149    if(pattern == null && element != null) {
     150        pattern = MSMUtils.getValue(element);
     151    }
     152    return pattern;
     153    }
     154
     155    /** Method to get the name of the source of the strings used in pattern matching.
     156     * @return a String which is either the fully qualified name of a metadata element, or filename
     157     */
     158    public String getSource() {
     159    if(source == null &&element != null) {
     160        source = element.getAttribute(StaticStrings.CONTENT_ATTRIBUTE);
     161        // If this is a MSM Element then retrieve the appropriate ElementWrapper and use the language specific name
     162        if(!source.equals(StaticStrings.FILENAME_STR)) {
     163        ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(source);
     164        if(element_wrapper != null) {
     165            source = element_wrapper.toString();
     166        }
    94167        }
    95                 // 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 {
    106                 // 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.
    110       * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    111       * @param include A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise.
    112       * @param exp A <strong>String</strong> containing a Perl expression which is used as the filter for this subcollection.
    113       */
    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.
    122       * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    123       * @param include A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise.
    124       * @param element 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.
    125       * @param exp A <strong>String</strong> containing a Perl expression which is used as the filter for this subcollection.
    126       * @param flags A <strong>String</strong> of flags to be taken into account when matching the expression.
    127       */
    128     public Subcollection(String name, boolean include, String element, String exp, String flags) {
     168    }
     169    return source;
     170    }
     171
     172    public boolean isAssigned() {
     173    return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
     174    }
     175
     176    /** Method to get the value of include.
     177     * @param boolean true if this is an inclusion filter, false otherwise
     178     */
     179    public boolean isInclusive() {
     180    if(!include.isDecided() && element != null) {
     181        include.set(element.getAttribute(StaticStrings.TYPE_ATTRIBUTE).equals(StaticStrings.INCLUDE_STR));
     182    }
     183    return include.isTrue();
     184    }
     185
     186    public void setAssigned(boolean assigned) {
     187    if(element != null) {
     188        element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
     189    }
     190    }
     191
     192    public void setElement(Element element) {
    129193    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.
    136       * @param object The other subcollection to compare to, as an <strong>Object</strong>.
    137       * @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.
    138       */
    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.
    144       * @param object The other subcollection to compare to, as an <strong>Object</strong>.
    145       * @return A <i>boolean</i> which is <i>true</i> if the subcollections are equal, <i>false</i> otherwise.
    146       */
    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.
    154       * @return The value of element as an <strong>String</strong>.
    155       */
    156     public String getElement() {
    157     return element;
    158     }
    159     /** Method to get the value of expression.
    160       * @return The value of exp as a <strong>String</strong>.
    161       */
    162     public String getExpression() {
    163     return exp;
    164     }
    165     /** Method to get the value of flags.
    166       * @return The value of flags as a <strong>String</strong>.
    167       */
    168     public String getFlags() {
    169     return flags;
    170     }
    171     /** Method to get the value of include.
    172       * @param boolean The value of include as a <i>boolean</i>.
    173       */
    174     public boolean getInclude() {
    175     return include;
    176     }
    177     /** Method to get the value of name.
    178       * @param String The value of name as a <strong>String</string>.
    179       */
    180     public String getName() {
    181     return name;
    182     }
    183     /** Method to get the name of the source of the strings used in pattern matching.
    184       * @return A <strong>String</strong> which is either the fully qualified name of a metadata element, or "Filename".
    185       */
    186     public String getSource() {
    187     if(element != null) {
    188         return element;
    189     }
    190     return "Filename";
    191     }
     194    include.reset();
     195    flags = null;
     196    name = null;
     197    pattern = null;
     198    source = null;
     199    text = null;
     200    }
     201
     202    public void setFlags(String new_flags) {
     203    if(element != null) {
     204        // Change element
     205        element.setAttribute(StaticStrings.OPTIONS_ATTRIBUTE, new_flags);
     206        flags = new_flags;
     207        text = null;
     208    }
     209    }
     210
     211    public void setInclusive(boolean new_include) {
     212    if(element != null) {
     213        // Change element
     214        element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, (new_include ? StaticStrings.INCLUDE_STR : StaticStrings.EXCLUDE_STR));
     215        include.set(new_include);
     216        text = null;
     217    }
     218    }
     219
     220    public void setName(String new_name) {
     221    if(element != null) {
     222        // Change element
     223        element.setAttribute(StaticStrings.NAME_ATTRIBUTE, new_name);
     224        name = new_name;
     225        text = null;
     226    }
     227    }
     228
     229    public void setPattern(String new_pattern) {
     230    if(element != null) {
     231        // Change element
     232        MSMUtils.setValue(element, new_pattern);
     233        pattern = new_pattern;
     234        text = null;
     235    }
     236    }
     237
     238    public void setSource(String new_source) {
     239    if(element != null) {
     240        // Change element
     241        element.setAttribute(StaticStrings.CONTENT_ATTRIBUTE, new_source);
     242        source = new_source;
     243        text = null;
     244    }
     245    }
     246
    192247    /** Method to display the contents of this class as it would appear in the collection configuration file.
    193       * @return A <strong>String</strong> which could be used as a subcollection entry in collect.cfg.
    194       */
     248     * @return a String representing this subcollection
     249     */
    195250    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";
     251    if(text == null && element != null) {
     252        text = CollectionConfiguration.toString(element, true);
     253    }
    215254    return text;
    216255    }
    217 
    218     /** Update certain fields of this subcollection.
    219       * @param name A <strong>String</strong> which is a unique identifier of a subcollection.
    220       * @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.
    221       * @param exp A <strong>String</strong> containing a Perl expression which is used as the filter for this subcollection.
    222       * @param include A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise.
    223       * @param flags A <strong>String</strong> of flags to be taken into account when matching the expression.
    224         */
    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.
    234       * @param old_name The current name of the element as a <strong>String</strong>.
    235       * @param new_name The new name of the element as a <strong>String</strong>.
    236       */
    237     public void updateElement(String old_name, String new_name) {
    238     if(element.equals(old_name)) {
    239         element = new_name;
    240     }
    241     }
    242256}
    243257
  • trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    4327package org.greenstone.gatherer.cdm;
    4428/**************************************************************************************
    45  * Title:        Gatherer
    46  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    47  * Copyright:    Copyright (c) 2001
    48  * Company:      The University of Waikato
    49  * Written:      02/05/02
    50  * Revised:      17/11/02 - Commented
     29 * Written:      ??/??/02
     30 * Revised:      04/07/03 - DOM support
    5131 **************************************************************************************/
    5232import java.awt.*;
     
    5636import javax.swing.event.*;
    5737import org.greenstone.gatherer.Gatherer;
     38import org.greenstone.gatherer.cdm.CollectionConfiguration;
     39import org.greenstone.gatherer.cdm.CollectionDesignManager;
     40import org.greenstone.gatherer.cdm.Control;
     41import org.greenstone.gatherer.cdm.DOMProxyListModel;
    5842import org.greenstone.gatherer.cdm.Subcollection;
    59 import org.greenstone.gatherer.cdm.SubIndex;
    60 import org.greenstone.gatherer.cdm.SubIndexes;
     43import org.greenstone.gatherer.gui.NonWhitespaceField;
    6144import org.greenstone.gatherer.msm.ElementWrapper;
     45import org.greenstone.gatherer.msm.MSMUtils;
    6246import org.greenstone.gatherer.util.ExclusiveListSelectionListener;
    63 import org.w3c.dom.Element;
    64 /** This class maintains a list of subcollections within our collection, and also records which of these subcollections we are building indexes for.
     47import org.greenstone.gatherer.util.StaticStrings;
     48import org.greenstone.gatherer.util.Utility;
     49import org.w3c.dom.*;
     50/** This class maintains a list of subcollections within our collection.
    6551 * @author John Thompson, Greenstone Digital Library, University of Waikato
    66  * @version 2.1
     52 * @version 2.4
    6753 */
    6854public class SubcollectionManager
    69     extends DefaultListModel {
    70     /** A reference to the manager so we can get access to languages. */
    71     private CollectionDesignManager manager;
     55    extends DOMProxyListModel {
     56
     57    static final private String CLASS_DICTIONARY_NAME = "CDM.SubcollectionManager.";
     58
    7259    /** The controls used to edit the settings of this manager. */
    7360    private Control controls = null;
    74     /** A reference to this class so we can use it as a model in our inner classes. */
    75     private DefaultListModel model = null;
    76     /** The default index for the subcollections. */
    77     private DefaultSubIndex default_index = null;
    78     /** A reference to the Gatherer. */
    79     private Gatherer gatherer = null;
    80     /** A hashtable of subcollections, with mappings from name to subcollection. */
    81     private Hashtable subcollections = null;
    82     /** A vector-type structure of subcollection indexes. */
    83     private SubIndexes subindexes = null;
    84     /** 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. */
    85     private ArrayList unresolved = null;
    86     /** Constructor.
    87      * @param gatherer A reference to the <Strong>Gatherer</strong>.
    88      * @see org.greenstone.gatherer.cdm.SubIndexes
    89      */
    90     public SubcollectionManager(Gatherer gatherer, CollectionDesignManager manager) {
    91     super();
    92     this.gatherer = gatherer;
    93     this.manager = manager;
     61
     62    private DOMProxyListModel model;
     63
     64    /** Constructor.
     65     * @see org.greenstone.gatherer.Gatherer
     66     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
     67     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
     68     * @see org.greenstone.gatherer.cdm.DOMProxyListModel
     69     * @see org.greenstone.gatherer.cdm.Subcollection
     70     */
     71    public SubcollectionManager() {
     72    super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.SUBCOLLECTION_ELEMENT, new Subcollection());
     73    Gatherer.println("SubcollectionManager: " + getSize() + " subcollections parsed.");
    9474    this.model = this;
    95     this.subcollections = new Hashtable();
    96     this.subindexes = new SubIndexes();
    97     this.unresolved = new ArrayList();
    98     }
    99     /** Method to add a subindex.
    100      * @param subindex A <strong>SubIndex</strong>.
     75    }
     76
     77    /** Method to add a new subcollection.
     78     * @param subcollection the Subcollection to add
    10179     * @see org.greenstone.gatherer.Gatherer
     80     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
     81     * @see org.greenstone.gatherer.cdm.DOMProxyListModel
    10282     * @see org.greenstone.gatherer.collection.CollectionManager
    10383     */
    104     public void addSubIndex(SubIndex subindex) {
    105     if(!subindexes.contains(subindex)) {
    106         subindexes.addElement(subindex);
    107         gatherer.c_man.configurationChanged();
    108     }
    109     }
    110     /** Method to add a new subcollection. Adds it to both the underlying list model and the hashtable mapping names to subcollections.
    111       * @param sub The <strong>Subcollection</strong> to add.
    112       * @return A <i>boolean</i> indicating if the addition was successful (<i>true</i>) or not (<i>false</i>).
    113         * @see org.greenstone.gatherer.Gatherer
    114         * @see org.greenstone.gatherer.collection.CollectionManager
    115       */
    116     public boolean addSubcollection(Subcollection sub) {
    117     if(!contains(sub)) {
    118         addElement(sub);
    119         subcollections.put(sub.getName(), sub);
    120         gatherer.c_man.configurationChanged();
    121         return true;
    122     }
    123     return false;
    124     }
    125     /** 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.
    126      * @param name A <>>String</>> which is a unique identifier of a subcollection.
    127      * @param include A <i>boolean</i> indicating whether this is an inclusion filter (<i>true</i>) or an exclusion one (<i>false</i>).
    128      * @param element An <>>Element</>> which is either the metadata whose value should be matched against the given expression, or <i>null</i> if you wish to match against the file name.
    129      * @param exp A <>>String</>> containing a Perl expression which is used as the filter for this subcollection.
    130      * @param flags A <strong>String<strong> listing any special flags to be applied when matching the expression.
    131      * @return A <i>boolean</i> with a value of <i>true</i> if the addition was successful.
    132      * @see org.greenstone.gatherer.cdm.Subcollection
    133      */
    134     public boolean addSubcollection(String name, boolean include, String element, String exp, String flags) {
    135     Subcollection sub = null;
    136     if(element != null) {
    137         sub = new Subcollection(name, include, element, exp, flags);
    138     }
    139     else {
    140         sub = new Subcollection(name, include, exp, flags);
    141     }
    142     return addSubcollection(sub);
    143     }
    144     /** Refresh all derived components using this manager as a model.
    145      */
    146     public void changed() {
    147     fireContentsChanged(this, 0, getSize() - 1);
    148     }
    149     /** Method to retrieve the controls for this manager.
    150      * @return A <Strong>Control</strong> object which contains the controls used to edit the subcollection data.
    151      */
    152     public Control getControls() {
    153     if(controls == null) {
    154         controls = new Control();
    155     }
    156     return controls;
    157     }
    158     /** Method to retrieve the default index.
    159       * @return A <strong>DefaultSubIndex</strong> object.
    160       */
    161     public DefaultSubIndex getDefaultSubIndex() {
    162     return default_index;
    163     }
    164     /** Method to retrieve a certain subcollection by its name.
    165      * @param name A <strong>String</strong> which is used as the key for finding the matching subcollection.
    166      * @return The requested <strong>Subcollection</strong> or <i>null</i> if no such subcollection exists.
    167      */
    168     public Subcollection getSubcollection(String name) {
    169     return (Subcollection) subcollections.get(name);
    170     }
    171 
    172     /** Retrieve a certain subindex given its name.
    173      * @param name the String representation of a subindex.
    174      * @return the SubIndex requested or null if no such subindex.
    175      */
    176     public SubIndex getSubIndex(String name) {
    177     for(int i = 0; i < subindexes.size(); i++) {
    178         SubIndex subindex = (SubIndex) subindexes.get(i);
    179         if(subindex.toString().equals(name)) {
    180         return subindex;
    181         }
    182     }
    183     return null;
    184     }
    185 
    186     /** Method to get all of the subindexes set.
    187      * @return A <strong>SubIndexes</strong> object containing all the defined indexes.
    188      */
    189     public SubIndexes getSubIndexes() {
    190     return subindexes;
    191     }
    192     /** Method to get all of the subcollections defined.
    193      * @return A <strong>Vector</strong> of subcollections.
    194      */
    195     public Vector getSubcollections() {
    196     Vector subcollections = new Vector();
    197     for(int i = 0; i < size(); i++) {
    198         subcollections.add(get(i));
    199     }
    200     return subcollections;
    201     }
    202     /** Mark the current controls, if any, as invalid and deallocate them. Any further use of the controls will requires them being rebuilt.
    203      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control
    204      */
    205     public void invalidateControls() {
     84    public void addSubcollection(Subcollection subcollection) {
     85    if(!contains(subcollection)) {
     86        Element element = subcollection.getElement();
     87        // Locate where we should insert this new subcollection.
     88        Node target_node = CollectionConfiguration.findInsertionPoint(element);
     89        // Failing that we insert immediately after a language string
     90        add(root, subcollection, target_node);
     91        Gatherer.c_man.configurationChanged();
     92    }
     93    }
     94
     95    public void destroy() {
    20696    if(controls != null) {
    20797        controls.destroy();
     
    20999    }
    210100    }
    211     /** 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.
    212      * @param command The <strong>String</strong> to be parsed.
    213      * @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>.
    214      * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
    215      * @see org.greenstone.gatherer.cdm.CommandTokenizer
    216      * @see org.greenstone.gatherer.cdm.DefaultSubIndex
    217      * @see org.greenstone.gatherer.cdm.Subcollection
    218      * @see org.greenstone.gatherer.cdm.SubIndex
    219      */
    220     public boolean parse(String command, boolean finished) {
    221     String temp = command.toLowerCase();
    222     CommandTokenizer tokenizer = new CommandTokenizer(command);
    223     tokenizer.nextToken(); // Throw away head.
    224     if(temp.startsWith("subcollection")) {
    225         if(tokenizer.countTokens() >= 2) {
    226         String name = tokenizer.nextToken();
    227         String pattern = tokenizer.nextToken();
    228         addSubcollection(new Subcollection(name, pattern));
    229         return true;
    230         }
    231     }
    232     else if(temp.startsWith("indexsubcollections")) {
    233                 // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
    234         if(!finished) {
    235         unresolved.add(command);
    236         }
    237         else {
    238         while(tokenizer.hasMoreTokens()) {
    239             addSubIndex(new SubIndex(tokenizer.nextToken(), this));
    240         }
    241         }
    242         return true;
    243     }
    244     else if(temp.startsWith("defaultsubcollection")) {
    245                 // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
    246         if(!finished) {
    247         unresolved.add(command);
    248         }
    249         else {
    250         if(tokenizer.hasMoreTokens()) {
    251             setDefaultSubIndex(new DefaultSubIndex(tokenizer.nextToken(), this));
    252         }
    253         }
    254         return true;
    255     }
    256     return false;
    257     }
    258     /** Method to remove a certain subindex.
    259       * @param subindex The <strong>SubIndex</strong> you wish to remove.
    260       * @see org.greenstone.gatherer.Gatherer
    261       * @see org.greenstone.gatherer.collection.CollectionManager
    262       */
    263     public void removeSubIndex(SubIndex subindex) {
    264     subindexes.removeElement(subindex);
    265     gatherer.c_man.configurationChanged();
    266     }
    267     /** Method to remove all of the subindexes that contain a certain subcollection.
    268       * @param sub The <strong>Subcollection</strong> that you wish to remove.
    269       * @see org.greenstone.gatherer.Gatherer
    270       * @see org.greenstone.gatherer.cdm.SubIndex
    271       * @see org.greenstone.gatherer.collection.CollectionManager
    272       */
    273     public void removeSubIndexes(Subcollection sub) {
    274     for(int i = subindexes.size() - 1; i >= 0; i--) {
    275         SubIndex subindex = (SubIndex)subindexes.get(i);
    276         if(subindex.containsSubcollection(sub.getName())) {
    277         subindexes.removeElement(subindex);
    278         }
    279     }
    280     gatherer.c_man.configurationChanged();
    281     }
     101
     102    /** Method to retrieve the controls for this manager.
     103     * @return the Control used to edit the subcollection data
     104     */
     105    public Control getControls() {
     106    if(controls == null) {
     107        controls = new SubcollectionControl();
     108    }
     109    return controls;
     110    }
     111
     112    /** Method to retrieve a certain subcollection by its name.
     113     * @param name a String which is used as the key for finding the matching subcollection
     114     * @return the requested Subcollection or null if no such subcollection exists.
     115     */
     116    public Subcollection getSubcollection(String name) {
     117    Subcollection result = null;
     118    int size = getSize();
     119    for(int i = 0; i < size; i++) {
     120        Subcollection subcollection = (Subcollection) getElementAt(i);
     121        if(subcollection.getName().equals(name)) {
     122        result = subcollection;
     123        }
     124    }
     125    return result;
     126    }
     127
     128    /** Method to get all of the subcollections defined.
     129     * @return an ArrayList of subcollections
     130     */
     131    public ArrayList getSubcollections() {
     132    return children();
     133    }
     134
    282135    /** Method to remove the given subcollection.
    283       * @param sub The <strong>Subcollection</strong> you want to remove.
    284       * @see org.greenstone.gatherer.Gatherer
    285       * @see org.greenstone.gatherer.collection.CollectionManager
    286       */
    287     public void removeSubcollection(Subcollection sub) {
    288     removeElement(sub);
    289     subcollections.remove(sub);
    290     gatherer.c_man.configurationChanged();
    291     }
    292     /** Method to retry the parsing of commands that were previously unable to be parsed as they referenced subcollections that may not have been instantiated.
    293       */
    294     public void reparseUnresolved() {
    295     for(int i = 0; i < unresolved.size(); i++) {
    296         parse((String)unresolved.get(i), true);
    297     }
    298     unresolved.clear();
    299     }
    300     /** Method to set the default subcollection index.
    301       * @param subcollection The <strong>Subcollection</strong> to use as the default index.
    302       * @see org.greenstone.gatherer.Gatherer
    303       * @see org.greenstone.gatherer.collection.CollectionManager
    304       */
    305     public void setDefaultSubIndex(DefaultSubIndex subindex) {
    306     this.default_index = subindex;
    307     if(subindex != null) {
    308         addSubIndex(subindex.getSubIndex());
    309     }
    310     gatherer.c_man.configurationChanged();
    311     }
    312     /** 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.
    313       * @return A <strong>String</strong> containing a block of configuration commands.
    314         * @see org.greenstone.gatherer.cdm.SubIndex
    315         * @see org.greenstone.gatherer.cdm.Subcollection
    316       */
    317     public String toString() {
    318     String text = "";
    319     // Retrieve the subcollection names and sort them.
    320     if(subcollections.size() > 0) {
    321         Vector names = new Vector(subcollections.keySet());
    322         Collections.sort(names);
    323         for(int i = 0; i < names.size(); i++) {
    324         Subcollection sub =
    325             (Subcollection) subcollections.get(names.get(i));
    326         text = text + sub.toString();
    327         }
    328                 // Now add a entry, separated by spaces for each subcollection
    329                 // index.
    330         if(subindexes.size() > 0) {
    331         text = text + subindexes.toString();
    332         }
    333                 // Finally add the default subcollection index if necessary.
    334         if(default_index != null) {
    335         text = text + default_index.toString();
    336         }
    337         text = text + "\n";
    338     }
    339     // Otherwise if there were no subcollections, there aren't going to be
    340     // subcollection indexes, nor a default subcollection index are there.
    341     return text;
    342     }
     136     * @param subcollection the Subcollection you want to remove
     137     * @see org.greenstone.gatherer.Gatherer
     138     * @see org.greenstone.gatherer.collection.CollectionManager
     139     */
     140    public void removeSubcollection(Subcollection subcollection) {
     141    remove(subcollection);
     142    Gatherer.c_man.configurationChanged();
     143    }
     144
     145    public void updateSubcollection(Subcollection subcollection, String name, boolean include, String source, String pattern, String flags) {
     146    subcollection.setFlags(flags);
     147    subcollection.setInclusive(include);
     148    subcollection.setName(name);
     149    subcollection.setPattern(pattern);
     150    subcollection.setSource(source);
     151    refresh(subcollection);
     152    Gatherer.c_man.configurationChanged();
     153    }
     154
    343155    /** Method to retrieve a phrase from the dictionary based on a key.
    344       * @param key A <strong>String</strong> used to find the correct phrase.
    345       * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
    346       * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    347       */
     156     * @param key A <strong>String</strong> used to find the correct phrase.
     157     * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
     158     * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
     159     */
    348160    private String get(String key) {
    349     return get(key, null);
    350     }
    351     /** Method to retrieve a phrase from the dictionary based on a key.
    352       * @param key A <strong>String</strong> used to find the correct phrase.
    353       * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    354       * @see org.greenstone.gatherer.Dictionary
    355       * @see org.greenstone.gatherer.Gatherer
    356       */
    357     private String get(String key, String args[]) {
    358161    if(key.indexOf(".") == -1) {
    359         key = "CDM.SubcollectionManager." + key;
    360     }
    361     return gatherer.dictionary.get(key, args);
    362     }
     162        key = CLASS_DICTIONARY_NAME + key;
     163    }
     164    return Gatherer.dictionary.get(key);
     165    }
     166
    363167    /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
    364     private class Control
    365     extends JPanel {
    366     /** <i>true</i> if the current selection has changed. */
    367     private boolean changed = false;
    368     /** Button to add a subcollection. */
    369     private JButton add = null;
    370     /** Button to add a subindex. */
    371     private JButton add_index = null;
    372     /** Button to clear the default subindex. */
    373     private JButton clear_default = null;
    374     /** Button to remove a subcollection. */
    375     private JButton remove = null;
    376     /** Button to remove a subindex. */
    377     private JButton remove_index = null;
    378     /** Button to set the default subindex. */
    379     private JButton set_default = null;
    380     /** Button to cause an update of the subcollections. */
    381     private JButton update = null;
    382     /** 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. */
    383     private JComboBox source = null;
    384     /** The list of assigned subcollections. */
    385     private JList subcollection_list = null;
    386     /** The list of subcollections available for the creation of subindexes. */
    387     private JList subcollection_list_2 = null;
    388     /** The list of assigned subindexes. */
    389     private JList subindexes_list = null;
    390     /** The label denoting the list of subindexes. */
    391     private JLabel subindexes_label = null;
    392     /** The panel containing the subcollection controls. */
    393     private JPanel subcollection_pane = null;
    394     /** The panel containing the subindex controls. */
    395     private JPanel subindex_pane = null;
    396     /** The tabbed pane used to store the subcollection and subindex controls. */
    397     private JTabbedPane tabbed_pane = null;
    398     /** The area used to display inline instructions. */
    399     private JTextArea instructions = null;
    400     /** The field displaying the name of the default subindex. */
    401     private JTextField default_value = null;
    402     /** A field used for specifying flags for the PERL expression matching, such as 'i' for case insensitive. */
    403     private JTextField flags = null;
    404     /** The pattern the source text must match. */
    405     private JTextField match = null;
    406     /** The name of this subcollection. */
    407     private JTextField name = null;
    408     /** The name of this subindex. */
    409     private JTextField subindex_name;
    410     /** When this button is selected the filter matching files are excluded. */
    411     private JToggleButton exclude = null;
    412     /** When this button is selected the filter matching files are included. */
    413     private JToggleButton include = null;
    414     /** The existing subcollection whose details you are reviewing, if any. */
    415     private Subcollection current = null;
    416     /** Constructor, creates the outer parts of the view, then calls two methods in turn to create the subcollection controls and subindex controls.
    417      */
    418     public Control() {
     168    private class SubcollectionControl
     169    extends JPanel
     170    implements Control {
     171
     172    private JButton add_button;
     173    private JButton remove_button;
     174    private JButton update_button;
     175    private JComboBox source_combobox;
     176    private JList subcollection_list;
     177    private JTabbedPane tabbed_pane;
     178    private JTextArea instructions_area;
     179    private JTextField flags_field;
     180    private JTextField match_field;
     181    private JTextField name_field;
     182    private JToggleButton exclude_button;
     183    private JToggleButton include_button;
     184
     185    /** Constructor */
     186    public SubcollectionControl() {
    419187        // Create
    420188        JPanel border_pane = new JPanel();
    421189        JPanel header_pane = new JPanel();
    422         instructions = new JTextArea(get("Instructions"));
    423         instructions.setEditable(false);
    424         instructions.setLineWrap(true);
    425         instructions.setRows(5);
    426         instructions.setWrapStyleWord(true);
     190        instructions_area = new JTextArea(get("Instructions"));
     191        instructions_area.setEditable(false);
     192        instructions_area.setLineWrap(true);
     193        instructions_area.setRows(5);
     194        instructions_area.setWrapStyleWord(true);
    427195        tabbed_pane = new JTabbedPane();
    428196        JLabel title = new JLabel(get("Title"));
    429197        title.setHorizontalAlignment(JLabel.CENTER);
    430         createSubCollection();
    431         createSubIndex();
     198       
     199        JPanel button_pane_3 = new JPanel();
     200        add_button = new JButton(get("Add"));
     201        add_button.setMnemonic(KeyEvent.VK_A);
     202        add_button.setEnabled(false);
     203        remove_button = new JButton(get("Remove"));
     204        remove_button.setMnemonic(KeyEvent.VK_R);
     205        remove_button.setEnabled(false);
     206        update_button = new JButton(get("Update"));
     207        update_button.setMnemonic(KeyEvent.VK_C);
     208        update_button.setEnabled(false);
     209
     210        JPanel button_pane = new JPanel();
     211        JPanel button_pane_1 = new JPanel();
     212        exclude_button = new JToggleButton(get("Exclude"));
     213        exclude_button.setMnemonic(KeyEvent.VK_X);
     214        flags_field = new NonWhitespaceField();
     215        JLabel flags_label = new JLabel(get("Flags"));
     216        include_button = new JToggleButton(get("Include"));
     217        include_button.setMnemonic(KeyEvent.VK_I);
     218        JLabel inclusive_label = new JLabel(get("Inclusive"));
     219        JPanel inclusive_pane = new JPanel();
     220        match_field = new JTextField();
     221        JLabel match_label = new JLabel(get("Match"));
     222        name_field = new NonWhitespaceField();
     223        JLabel name_label = new JLabel(get("Name"));
     224        Vector source_model = Gatherer.c_man.getCollection().msm.getAssignedElements();
     225        source_model.add(0, StaticStrings.FILENAME_STR);
     226        source_combobox = new JComboBox(source_model);
     227        JLabel source_label = new JLabel(get("Source"));
     228        subcollection_list = new JList(model);
     229        subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     230        JPanel subcollection_pane = new JPanel();
     231        ButtonGroup bg = new ButtonGroup();
     232        bg.add(include_button);
     233        bg.add(exclude_button);
     234        include_button.setSelected(true);
     235        JPanel subcollection_list_pane = new JPanel();
     236        JLabel subcollection_list_label = new JLabel(get("Assigned"));
     237
    432238        // Add listeners
     239        SubCollectionChangeListener cl = new SubCollectionChangeListener();
     240        add_button.addActionListener(new AddSubCollectionListener());
     241        remove_button.addActionListener(new RemoveSubCollectionListener());
     242        update_button.addActionListener(new UpdateSubCollectionListener());
     243        exclude_button.addActionListener(cl);
     244        include_button.addActionListener(cl);
     245        source_combobox.addActionListener(cl);
     246        flags_field.getDocument().addDocumentListener(cl);
     247        match_field.getDocument().addDocumentListener(cl);
     248        name_field.getDocument().addDocumentListener(cl);
     249        subcollection_list.addListSelectionListener(new SubCollectionListListener());
     250
    433251        // Layout
    434         instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     252        instructions_area.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
     253
    435254        header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    436255        header_pane.setLayout(new BorderLayout());
    437256        header_pane.add(title, BorderLayout.NORTH);
    438         header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
    439         tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
    440         tabbed_pane.addTab(get("Subindex_Controls"), subindex_pane);
    441         tabbed_pane.addTab(get("Language_Controls"), manager.languages.getControls());
    442         border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
    443         border_pane.setLayout(new BorderLayout());
    444         border_pane.add(tabbed_pane, BorderLayout.CENTER);
    445         setLayout(new BorderLayout());
    446         add(header_pane, BorderLayout.NORTH);
    447         add(border_pane, BorderLayout.CENTER);
    448     }
    449     /** Create the subcollection controls.
    450      * @see org.greenstone.gatherer.Gatherer
    451      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddListener
    452      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ListListener
    453      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveListener
    454      * @see org.greenstone.gatherer.collection.CollectionManager
    455      * @see org.greenstone.gatherer.msm.MetadataSetManager
    456      */
    457     public void createSubCollection() {
    458         // Create
    459         add = new JButton(get("Add"));
    460         add.setMnemonic(KeyEvent.VK_A);
    461         add.setEnabled(false);
    462         JPanel button_pane = new JPanel();
    463         JPanel button_pane_1 = new JPanel();
    464         JPanel button_pane_3 = new JPanel();
    465         exclude = new JToggleButton(get("Exclude"));
    466         exclude.setMnemonic(KeyEvent.VK_X);
    467         flags = new JTextField();
    468         JLabel flags_label = new JLabel(get("Flags"));
    469         include = new JToggleButton(get("Include"));
    470         include.setMnemonic(KeyEvent.VK_I);
    471         JLabel inclusive_label = new JLabel(get("Inclusive"));
    472         JPanel inclusive_pane = new JPanel();
    473         match = new JTextField();
    474         JLabel match_label = new JLabel(get("Match"));
    475         name = new JTextField();
    476         JLabel name_label = new JLabel(get("Name"));
    477         remove = new JButton(get("Remove"));
    478         remove.setMnemonic(KeyEvent.VK_R);
    479         remove.setEnabled(false);
    480         Vector source_model = gatherer.c_man.msm.getAssignedElements();
    481         source_model.add(0, "Filename");
    482         source = new JComboBox(source_model);
    483         JLabel source_label = new JLabel(get("Source"));
    484         subcollection_list = new JList(model);
    485         subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    486         subcollection_pane = new JPanel();
    487         ButtonGroup bg = new ButtonGroup();
    488         bg.add(include);
    489         bg.add(exclude);
    490         include.setSelected(true);
    491         JPanel subcollection_list_pane = new JPanel();
    492         JLabel subcollection_list_label = new JLabel(get("Assigned"));
    493 
    494         // Add listeners
    495         SubCollectionChangeListener cl = new SubCollectionChangeListener();
    496         add.addActionListener(new AddSubCollectionListener());
    497         remove.addActionListener(new RemoveSubCollectionListener());
    498         subcollection_list.addListSelectionListener(new SubCollectionListListener());
    499         //exclude.addActionListener(cl);
    500         //include.addActionListener(cl);
    501         //source.addActionListener(cl);
    502         //flags.addDocumentListener(cl);
    503         match.getDocument().addDocumentListener(cl);
    504         name.getDocument().addDocumentListener(cl);
    505 
    506         // Layout
     257        header_pane.add(new JScrollPane(instructions_area), BorderLayout.CENTER);
     258
    507259        inclusive_pane.setLayout(new GridLayout());
    508         inclusive_pane.add(include);
    509         inclusive_pane.add(exclude);
     260        inclusive_pane.add(include_button);
     261        inclusive_pane.add(exclude_button);
     262
    510263        button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    511264        button_pane_1.setLayout(new GridLayout(5, 2));
    512265        button_pane_1.add(name_label);
    513         button_pane_1.add(name);
     266        button_pane_1.add(name_field);
    514267        button_pane_1.add(source_label);
    515         button_pane_1.add(source);
     268        button_pane_1.add(source_combobox);
    516269        button_pane_1.add(match_label);
    517         button_pane_1.add(match);
     270        button_pane_1.add(match_field);
    518271        button_pane_1.add(inclusive_label);
    519272        button_pane_1.add(inclusive_pane);
    520273        button_pane_1.add(flags_label);
    521         button_pane_1.add(flags);
     274        button_pane_1.add(flags_field);
     275
    522276        button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    523         button_pane_3.setLayout(new GridLayout(1,2));
    524         button_pane_3.add(add);
    525         button_pane_3.add(remove);
     277        button_pane_3.setLayout(new GridLayout(1,3));
     278        button_pane_3.add(add_button);
     279        button_pane_3.add(update_button);
     280        button_pane_3.add(remove_button);
     281
    526282        button_pane.setLayout(new BorderLayout());
    527283        button_pane.add(button_pane_1, BorderLayout.CENTER);
    528284        button_pane.add(button_pane_3, BorderLayout.SOUTH);
     285
    529286        subcollection_list_pane.setLayout(new BorderLayout());
    530287        subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
     
    534291        subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
    535292        subcollection_pane.add(button_pane, BorderLayout.SOUTH);
    536     }
    537     /** Create the subindex controls.
    538      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddSubIndexListener
    539      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ClearDefaultListener
    540      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ChangeListener
    541      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveSubIndexListener
    542      * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.SetDefaultListener
    543      * @see org.greenstone.gatherer.util.ExclusiveListListener
    544      */
    545     public void createSubIndex() {
    546         // Creation
    547         JPanel subindex_name_panel = new JPanel();
    548         JLabel subindex_name_label = new JLabel(get("PartitionName"));
    549         subindex_name = new JTextField();
    550 
    551         add_index = new JButton(get("Add_Subindex"));
    552         add_index.setMnemonic(KeyEvent.VK_A);
    553         add_index.setEnabled(false);
    554         JPanel button_pane_2 = new JPanel();
    555         clear_default = new JButton(get("Clear_Default_Subindex"));
    556         clear_default.setMnemonic(KeyEvent.VK_C);
    557         if(default_index == null) {
    558         clear_default.setEnabled(false);
    559         }
    560         JLabel default_label = new JLabel(get("Default_Subindex"));
    561         JPanel default_pane = new JPanel();
    562         if(default_index == null) {
    563         default_value = new JTextField();
    564         }
    565         else {
    566         default_value = new JTextField(default_index.getSubIndex().toString());
    567         }
    568         default_value.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    569         default_value.setEditable(false);
    570         JPanel subindex_inner_pane_1 = new JPanel();
    571         JPanel subindex_inner_pane_2 = new JPanel();
    572         remove_index = new JButton(get("Remove_Subindex"));
    573         remove_index.setMnemonic(KeyEvent.VK_R);
    574         set_default = new JButton(get("Set_Default_Subindex"));
    575         set_default.setMnemonic(KeyEvent.VK_S);
    576         JLabel subcollection_label = new JLabel(get("Subcollection"));
    577         subcollection_list_2 = new JList(model);
    578         JPanel list_2_pane = new JPanel();
    579         subindex_pane = new JPanel();
    580         JLabel subindexes_label = new JLabel(get("Subindexes"));
    581         subindexes_list = new JList(subindexes);
    582         subindexes_list.setCellRenderer(new SubIndexListCellRenderer());
    583         subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    584         JPanel subindexes_pane = new JPanel();
    585 
    586         // Add listeners
    587         ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
    588         ell.add(subcollection_list_2);
    589         ell.add(subindexes_list);
    590         add_index.addActionListener(new AddSubIndexListener());
    591         clear_default.addActionListener(new ClearDefaultSubIndexListener());
    592         remove_index.addActionListener(new RemoveSubIndexListener());
    593         set_default.addActionListener(new SetDefaultSubIndexListener());
    594 
    595         subindex_name.getDocument().addDocumentListener(new SubIndexNameDocumentListener());
    596         subcollection_list_2.addListSelectionListener(new SubCollectionList2Listener());
    597 
    598         // Layout
    599         subindex_name_panel.setLayout(new BorderLayout());
    600         subindex_name_panel.add(subindex_name_label, BorderLayout.WEST);
    601         subindex_name_panel.add(subindex_name, BorderLayout.CENTER);
    602 
    603         list_2_pane.setLayout(new BorderLayout());
    604         list_2_pane.add(subcollection_label, BorderLayout.NORTH);
    605         list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
    606        
    607         subindexes_pane.setLayout(new BorderLayout());
    608         subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
    609         subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
    610        
    611         subindex_inner_pane_2.setLayout(new GridLayout(1,2,0,5));
    612         subindex_inner_pane_2.add(list_2_pane);
    613         subindex_inner_pane_2.add(subindexes_pane);
    614        
    615         default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    616         default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
    617         default_pane.setLayout(new BorderLayout());
    618         default_pane.add(default_label, BorderLayout.WEST);
    619         default_pane.add(default_value, BorderLayout.CENTER);
    620        
    621         subindex_inner_pane_1.setLayout(new BorderLayout());
    622         subindex_inner_pane_1.add(subindex_name_panel, BorderLayout.NORTH);
    623         subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
    624         subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
    625        
    626         button_pane_2.setLayout(new GridLayout(2,2));
    627         button_pane_2.add(add_index);
    628         button_pane_2.add(remove_index);
    629         button_pane_2.add(clear_default);
    630         button_pane_2.add(set_default);
    631        
    632         subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    633         subindex_pane.setLayout(new BorderLayout());
    634         subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
    635         subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
    636     }
    637    
    638    
     293
     294        tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
     295        tabbed_pane.addTab(get("Subindex_Controls"), (JPanel) CollectionDesignManager.subcollectionindex_manager.getControls());
     296        tabbed_pane.addTab(get("Language_Controls"), (JPanel) CollectionDesignManager.language_manager.getControls());
     297
     298        border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
     299        border_pane.setLayout(new BorderLayout());
     300        border_pane.add(tabbed_pane, BorderLayout.CENTER);
     301
     302        setLayout(new BorderLayout());
     303        add(header_pane, BorderLayout.NORTH);
     304        add(border_pane, BorderLayout.CENTER);
     305    }
     306       
    639307    /** Method to unregister any listeners to avoid memory leaks.
    640308     */
    641309    public void destroy() {
    642310    }
    643     /** 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.
    644      * @return A <i>boolean</i> which is always <i>false</i>.
    645      * @see org.greenstone.gatherer.msm.ElementWrapper
    646      */
    647     public boolean hasFocus() {
    648         // If we have a current metadata open, and something has changed then save the change.
    649         if(changed && current != null) {
    650         String n = name.getText();
    651         String s = null;
    652         Object o = source.getSelectedItem();
    653         if(o instanceof ElementWrapper) {
    654             ElementWrapper e = (ElementWrapper)o;
    655             s = e.toString();
    656         }
    657         String e = match.getText();
    658         String f = flags.getText();
    659         if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
    660             current.update(n, s, e, include.isSelected(), f);
    661             int index = model.indexOf(current);
    662             changed();
    663             subindexes.changed();
    664             if(default_index != null) {
    665             default_value.setText(default_index.getSubIndex().toString());
    666             }
    667         }
    668         changed = false;
    669         }
    670         return false;
    671     }
    672     /** Overriden to ensure the instructions are scrolled to top.
    673      */
    674     public void updateUI() {
    675         if(instructions != null) {
    676         instructions.setCaretPosition(0);
    677         }
    678         super.updateUI();
    679     }
    680 
    681     /** Method to validate the current subcollection editor values, and enable or disable controls (add button) based on said values.
    682      * we want to disable add until a new name is present
    683      */
    684     protected void validateAdd() {
    685         if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
    686         if (subcollections.containsKey(name.getText())) {
    687             add.setEnabled(false);
    688         } else {
    689             add.setEnabled(true);
    690         }
    691         }
    692         else {
    693         add.setEnabled(false);
    694         }
    695     }
     311
     312    public void gainFocus() {
     313        // Rebuild the sources combobox
     314        Vector source_model = Gatherer.c_man.getCollection().msm.getAssignedElements();
     315        source_model.add(0, "Filename"); // Add filename as a possible source.
     316        source_combobox.setModel(new DefaultComboBoxModel(source_model));
     317    }
     318
     319    public void loseFocus() {
     320    }
     321
    696322    /** 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. */
    697323    private class AddSubCollectionListener
     
    703329         */
    704330        public void actionPerformed(ActionEvent event) {
    705         String n = name.getText(); // not allowed spaces!
    706         if (n.indexOf(' ')!=-1) {
    707             n = n.substring(0, n.indexOf(' '));
    708             name.setText(n);
    709         }
    710         String s = null;
    711         Object o = source.getSelectedItem();
    712         if(o instanceof ElementWrapper) {
    713             ElementWrapper e = (ElementWrapper)o;
    714             s = e.toString();
    715         }
    716         String e = match.getText();
    717         String f = flags.getText();
    718         if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
    719             Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
    720             addSubcollection(sub);
    721         }
    722         changed = false;
    723         validateAdd();
    724         }
    725     }
    726     /** 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. */
    727     private class AddSubIndexListener
    728         implements ActionListener {
    729         /** 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.
    730          * @param event An <strong>ActionEvent</strong> containing information about the event.
    731          * @see org.greenstone.gatherer.cdm.SubIndex
    732          */
    733         public void actionPerformed(ActionEvent event) {
    734         if(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0) {
    735             Vector selected = new Vector();
    736             Object raw[] = subcollection_list_2.getSelectedValues();
    737             for(int i = 0; i < raw.length; i++) {
    738             selected.add(raw[i]);
     331        String name = name_field.getText();
     332        String source = null;
     333        Object object = source_combobox.getSelectedItem();
     334        if(object instanceof ElementWrapper) {
     335            ElementWrapper element_wrapper = (ElementWrapper)object;
     336            source = element_wrapper.getName();
     337            if(source.indexOf(MSMUtils.NS_SEP) == -1) {
     338            source = Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP + source;
    739339            }
    740             SubIndex subindex = new SubIndex(selected);
    741             addSubIndex(subindex);
    742             // Add the subindexes name.
    743             CollectionMeta metadata = new CollectionMeta(manager, subindex, manager.languages.getDefaultLanguage(), subindex_name.getText());
    744             manager.collectionmetadatum.addMetadata(metadata);
    745         }
    746         }
    747     }
    748     /** 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. */
     340        }
     341        else {
     342            source = object.toString();
     343        }
     344        String pattern = match_field.getText();
     345        String flags = flags_field.getText();
     346        if(name.length() > 0 && (source == null || source.length() > 0) && pattern.length() > 0) {
     347            Subcollection subcollection = new Subcollection(name, include_button.isSelected(), source, pattern, flags);
     348            addSubcollection(subcollection);
     349            // Change the selection to the new subcollection
     350            subcollection_list.setSelectedValue(subcollection, true);
     351        }
     352        add_button.setEnabled(false);
     353        }
     354    }
     355
     356    /** This class listens for any key entry in a text field, selection change in a combobox or button click, and updates a subcollection as appropriate. Its also convenient to use this class to test if the add button should be active yet. */
    749357    private class SubCollectionChangeListener
    750358        implements DocumentListener, ActionListener {
     
    753361         */
    754362        public void actionPerformed(ActionEvent event) {
    755         changed = true;
    756363        validateAdd();
    757364        }
    758365
    759366        public void changedUpdate(DocumentEvent event) {
    760         changed = true;
    761367        validateAdd();
    762368        }
     369
    763370        public void insertUpdate(DocumentEvent event) {
    764         changed = true;
    765371        validateAdd();
    766372
     
    768374
    769375        public void removeUpdate(DocumentEvent event) {
    770         changed = true;
    771376        validateAdd();
    772377        }
    773     }
    774     /** 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>. */
    775     private class ClearDefaultSubIndexListener
    776         implements ActionListener {
    777         /** 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.
    778          * @param event An <strong>ActionEvent</strong> containing information about the event.
    779          */
    780         public void actionPerformed(ActionEvent event) {
    781         setDefaultSubIndex(null);
    782         clear_default.setEnabled(false);
    783         default_value.setText("");
    784         }
    785     }
     378
     379        /** Method to validate the current subcollection editor values, and enable or disable controls (add button) based on said values. */
     380        private void validateAdd() {
     381        if(name_field.getText().length() > 0 && match_field.getText().length() > 0) {
     382            if (getSubcollection(name_field.getText()) == null) {
     383            add_button.setEnabled(true);
     384            } else {
     385            add_button.setEnabled(false);
     386            }
     387        }
     388        else {
     389            add_button.setEnabled(false);
     390        }
     391        }
     392    }
     393
    786394    /** 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. */
    787395    private class RemoveSubCollectionListener
     
    793401        public void actionPerformed(ActionEvent event) {
    794402        if(!subcollection_list.isSelectionEmpty()) {
    795             Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
    796             removeSubIndexes(sub_col);
    797             removeSubcollection(sub_col);
    798         }
    799         }
    800     }
    801     /** 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. */
    802     private class RemoveSubIndexListener
     403            Subcollection subcollection = (Subcollection)subcollection_list.getSelectedValue();
     404            removeSubcollection(subcollection);
     405            // And remove subcollection indexes dependant on this subcollection
     406            CollectionDesignManager.subcollectionindex_manager.removeSubcollectionIndexes(subcollection);
     407        }
     408        remove_button.setEnabled(false);
     409        }
     410    }
     411
     412    private class UpdateSubCollectionListener
    803413        implements ActionListener {
    804         /** 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.
    805          * @param event An <strong>ActionEvent</strong> containing information about the event.
    806          * @see org.greenstone.gatherer.cdm.SubIndex
    807          */
    808414        public void actionPerformed(ActionEvent event) {
    809         if(!subindexes_list.isSelectionEmpty()) {
    810             removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
    811         }
    812         }
    813     }
    814     /** 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. */
    815     private class SetDefaultSubIndexListener
    816         implements ActionListener {
    817         /** 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.
    818          * @param event An <strong>ActionEvent</strong> containing information about the event.
    819          * @see org.greenstone.gatherer.cdm.DefaultSubIndex
    820          * @see org.greenstone.gatherer.cdm.SubIndex
    821          */
    822         public void actionPerformed(ActionEvent event) {
    823         if(!subindexes_list.isSelectionEmpty()) {
    824             setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
    825             clear_default.setEnabled(true);
    826             default_value.setText(default_index.getSubIndex().toString());
    827         }
    828         }
    829     }
    830 
     415        if(!subcollection_list.isSelectionEmpty()) {
     416            Subcollection subcollection = (Subcollection)subcollection_list.getSelectedValue();
     417            String name = name_field.getText();
     418            String source = null;
     419            Object object = source_combobox.getSelectedItem();
     420            if(object instanceof ElementWrapper) {
     421            ElementWrapper element_wrapper = (ElementWrapper)object;
     422            source = element_wrapper.getName();
     423            if(source.indexOf(MSMUtils.NS_SEP) == -1) {
     424                source = Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP + source;
     425            }
     426            }
     427            else {
     428            source = object.toString();
     429            }
     430            String pattern = match_field.getText();
     431            String flags = flags_field.getText();
     432            if(name.length() > 0 && (source == null || source.length() > 0) && pattern.length() > 0) {
     433            updateSubcollection(subcollection, name, include_button.isSelected(), source, pattern, flags);
     434            }
     435        }
     436        }
     437    }
    831438
    832439    /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
     
    839446         */
    840447        public void valueChanged(ListSelectionEvent event) {
    841         // If we have a previous collection and the users changed something, but not added, then update subcollection.
    842         if(changed && current != null) {
    843             String n = name.getText();
    844             String s = null;
    845             Object o = source.getSelectedItem();
    846             if(o instanceof ElementWrapper) {
    847             ElementWrapper e = (ElementWrapper)o;
    848             s = e.toString();
    849             }
    850             String e = match.getText();
    851             String f = flags.getText();
    852             if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
    853             current.update(n, s, e, include.isSelected(), f);
    854             int index = model.indexOf(current);
    855             changed();
    856             subindexes.changed();
    857             if(default_index != null) {
    858                 default_value.setText(default_index.getSubIndex().toString());
    859             }
    860             }
    861         }
    862         // Now load the new entry.
     448        // Now the entry
    863449        if(!subcollection_list.isSelectionEmpty()) {
    864             current = (Subcollection) subcollection_list.getSelectedValue();
    865             flags.setText(current.getFlags());
    866             include.setSelected(current.getInclude());
    867             exclude.setSelected(!current.getInclude());
    868             match.setText(current.getExpression());
    869             name.setText(current.getName());
    870             String s = current.getSource();
     450            Subcollection subcollection = (Subcollection) subcollection_list.getSelectedValue();
     451            flags_field.setText(subcollection.getFlags());
     452            include_button.setSelected(subcollection.isInclusive());
     453            exclude_button.setSelected(!subcollection.isInclusive());
     454            match_field.setText(subcollection.getPattern());
     455            name_field.setText(subcollection.getName());
     456            String s = subcollection.getSource();
    871457            int pos = 0;
    872             Object value = source.getItemAt(pos);
     458            Object value = source_combobox.getItemAt(pos);
     459            //ystem.err.println("Search for: " + s);
    873460            while(value != null) {
    874461            if(value instanceof ElementWrapper) {
    875462                ElementWrapper e = (ElementWrapper) value;
    876                 if(e.toString().equals(s)) {
    877                 source.setSelectedIndex(pos);
     463                String e_name = e.getName();
     464                if(e_name.indexOf(MSMUtils.NS_SEP) == -1) {
     465                e_name = Utility.EXTRACTED_METADATA_NAMESPACE + MSMUtils.NS_SEP + e_name;
     466                }
     467                //ystem.err.print("Compare to: " + e_name);
     468                if(e_name.equals(s)) {
     469                source_combobox.setSelectedIndex(pos);
    878470                value = null;
     471                //ystem.err.println(" - Match");
    879472                }
    880473                else {
    881474                pos++;
    882                 value = source.getItemAt(pos);
     475                value = source_combobox.getItemAt(pos);
     476                //ystem.err.println(" - Fail");
    883477                }
    884478            }
    885479            else if(value.toString().equals(s)) {
    886                 source.setSelectedIndex(pos);
     480                source_combobox.setSelectedIndex(pos);
    887481                value = null;
    888482            }
    889483            else {
    890484                pos++;
    891                 value = source.getItemAt(pos);
     485                value = source_combobox.getItemAt(pos);
    892486            }
    893487            }
    894488            // Can't add one thats already there.
    895             add.setEnabled(false);
    896             // You can remove it though...
    897             remove.setEnabled(true);
     489            add_button.setEnabled(false);
     490            // You can update or remove it though...
     491            remove_button.setEnabled(true);
     492            update_button.setEnabled(true);
    898493        }
    899494        else {
    900             flags.setText("");
    901             include.setSelected(true);
    902             match.setText("");
    903             name.setText("");
    904             source.setSelectedIndex(0);
    905             remove.setEnabled(false);
    906         }
    907         // Have to do this after so we don't get called when nothings actually changed.
    908         changed = false;
    909        
    910         }
    911     }
    912 
    913     private class SubCollectionList2Listener
    914         implements ListSelectionListener {
    915 
    916         public void valueChanged(ListSelectionEvent event) {
    917         if(!event.getValueIsAdjusting()) {
    918             add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
    919         }
    920         }
    921     }
    922    
    923     private class SubIndexListCellRenderer
    924         extends DefaultListCellRenderer {
    925        
    926         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
    927         StringBuffer text = new StringBuffer(value.toString());
    928         // Retrieve the indexes name if any.
    929         CollectionMeta metadata = manager.collectionmetadatum.getMetadata(value, manager.languages.getDefaultLanguage(), true);
    930         if(metadata != null) {
    931             text.append(" \"");
    932             text.append(metadata.getValue());
    933             text.append("\"");
    934         }
    935         return super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
    936         }
    937 
    938     }
    939    
    940     private class SubIndexNameDocumentListener
    941         implements DocumentListener {
    942         /** Gives notification that an attribute or set of attributes changed. */
    943         public void changedUpdate(DocumentEvent e) {
    944         update();
    945         }
    946         /** Gives notification that there was an insert into the document. */
    947         public void insertUpdate(DocumentEvent e) {
    948         update();
    949         }
    950         /** Gives notification that a portion of the document has been removed. */
    951         public void removeUpdate(DocumentEvent e) {
    952         update();
    953         }
    954         /** The text area has changed in some way. Given that this can only happed when we are editing or adding a text fragment we better respond appropriately. */
    955         private void update() {
    956         add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
    957         }
    958     }
    959 
     495            flags_field.setText("");
     496            include_button.setSelected(true);
     497            match_field.setText("");
     498            name_field.setText("");
     499            source_combobox.setSelectedIndex(0);
     500            remove_button.setEnabled(false);
     501            update_button.setEnabled(false);
     502        }
     503        }
     504    }
    960505    }
    961506}
  • trunk/gli/src/org/greenstone/gatherer/cdm/SuperCollectionManager.java

    r4675 r4932  
    2828
    2929import java.awt.*;
    30 import java.awt.event.*;
    3130import java.io.*;
    3231import java.util.*;
    3332import javax.swing.*;
     33import javax.swing.event.*;
    3434import org.greenstone.gatherer.Configuration;
    3535import org.greenstone.gatherer.Dictionary;
    3636import org.greenstone.gatherer.Gatherer;
     37import org.greenstone.gatherer.cdm.DOMProxyListModel;
    3738import org.greenstone.gatherer.checklist.CheckList;
    3839import org.greenstone.gatherer.checklist.Entry;
    3940import org.greenstone.gatherer.collection.CollectionConfiguration;
     41import org.greenstone.gatherer.util.StaticStrings;
    4042import org.greenstone.gatherer.util.Utility;
    41 
    42 public class SuperCollectionManager {
     43import org.w3c.dom.*;
     44/** This class contains the information about what supercollection has been specified (if any) and methods for changing this information. Note that there is a major difference between this manager and the others in that its DOM model is never used directly in any list component. It is only used to decide whether a certain entry in the actual checklist is checked. */
     45public class SuperCollectionManager
     46    extends DOMProxyListModel {
    4347
    4448    static final public String SUPERCOLLECTION_COMMAND = "supercollection";
     
    4650
    4751    private String current_coll_name = null;
    48     private Control controls;
    49     private ArrayList collection_checklist_model;
    50 
    51     SuperCollectionManager() {
    52     // We start by building a model of the installed collections.
    53     collection_checklist_model = new ArrayList();
    54     File gsdl_collection_directory = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
    55     current_coll_name = Gatherer.c_man.getCollection().getName();
    56     File[] possible_collections = gsdl_collection_directory.listFiles();
    57     for(int i = 0; possible_collections != null && i < possible_collections.length; i++) {
    58         // The simpliest case is if the directory etc/collect.cfg file and a metadata/ in it. Thus it can easily be built upon.
    59         File collect_cfg_file = new File(possible_collections[i], Utility.CONFIG_DIR);
    60         if(collect_cfg_file.exists()) {
    61         CollectionConfiguration collect_cfg = new CollectionConfiguration(collect_cfg_file);
    62         String collection_title = collect_cfg.getName();
    63         String collection_name = possible_collections[i].getName();
    64         // We do have to block the model collection.
    65         if(!collection_title.equals("**title**")) {
    66             Entry entry = new Entry(collection_title);
    67             entry.setProperty(collection_name);
    68             if (collection_name.equals(current_coll_name)) {
    69             // the current collection is always selected
    70             entry.setFixed(true);
    71             entry.setSelected(true);
    72             }
    73             collection_checklist_model.add(entry);
    74             entry = null;
    75 
    76         }
    77         collection_name = null;
    78         collection_title = null;
    79         collect_cfg = null;
     52    private Control controls = null;
     53    private ArrayList collection_checklist_model = null; // Model used to actually populate list
     54
     55    public SuperCollectionManager(Element supercollections_element) {
     56    super(supercollections_element, StaticStrings.COLLECTION_ELEMENT, new SuperCollection());
     57    Gatherer.println("SuperCollectionManager: " + getSize() + " supercollection members parsed.");
     58    }
     59
     60    public void destroy() {
     61    if(controls != null) {
     62        controls.destroy();
     63        controls = null;
     64    }
     65    if(collection_checklist_model != null) {
     66        collection_checklist_model.clear();
     67        collection_checklist_model = null;
     68    }
     69    }
     70
     71    public void addSuperCollection(SuperCollection supercollection) {
     72    if(!contains(supercollection)) {
     73        add(getSize(), supercollection);
     74    }
     75    }
     76
     77    /** Method to retrieve the control for this manager.
     78     * @return the Control for editing supercollection settings
     79     */
     80    public Control getControls() {
     81    if(controls == null) {
     82        // Build controls
     83        this.controls = new SuperCollectionControl();
     84    }
     85    return controls;
     86    }
     87
     88    public SuperCollection getSuperCollection(String collection_name) {
     89    SuperCollection result = null;
     90    int size = getSize();
     91    for(int i = 0; result == null && i < size; i++) {
     92        SuperCollection supercollection = (SuperCollection) getElementAt(i);
     93        if(supercollection.getName().equals(collection_name)) {
     94        result = supercollection;
    8095        }
    81         collect_cfg_file = null;
    82     }
    83     possible_collections = null;
    84     gsdl_collection_directory = null;
    85     // Sort the result.
    86     Collections.sort(collection_checklist_model);
    87     }
    88 
    89     public boolean parse(String command) {
    90     String command_lc = command.toLowerCase();
    91     if(command_lc.startsWith(SUPERCOLLECTION_COMMAND) || command_lc.startsWith(CCS_COMMAND)) {
    92         StringTokenizer tokenizer = new StringTokenizer(command);
    93         tokenizer.nextToken();
    94         // Read in each of the collection names.
    95         ArrayList collection_names = new ArrayList();
    96         while(tokenizer.hasMoreTokens()) {
    97         collection_names.add(tokenizer.nextToken());
    98         }
    99         // Now that we have the collection names, select any entries in the checklist that match.
    100         for(int i = 0; i < collection_checklist_model.size(); i++) {
    101         Entry entry = (Entry) collection_checklist_model.get(i);
    102         String collection_name = entry.getProperty();
    103         if(collection_names.contains(collection_name)) {
    104             entry.setSelected(true);
    105             collection_names.remove(collection_name); // Makes successive runs faster.
    106         }
    107         collection_name = null;
    108         entry = null;
    109         }
    110         // Done.
    111         return true;
    112     }
    113     return false;
    114     }
    115 
    116     /** Method to retrieve the control for this manager.
    117      * @return A JPanel containing the controls.
    118      */
    119     public JPanel getControls() {
    120     if(controls == null) {
    121         controls = new Control();
    122     }
    123     return controls;
    124     }
    125 
    126     public void invalidateControls() {
    127     controls = null;
    128     }
    129 
    130     /** Return the contents of this manager as a command or block of commands ready to be written to the collection configuration file.
    131      * @return A String containing a configuration command or block of commands, terminated with a new line. This value will be null if there was no supercollection command set. */
    132     public String toString() {
    133     StringBuffer command = new StringBuffer(SUPERCOLLECTION_COMMAND);
    134     // Now for each entry selected output its collection name (property setting)
    135     boolean found_entry = false;
    136     for(int i = 0; i < collection_checklist_model.size(); i++) {
    137         Entry entry = (Entry) collection_checklist_model.get(i);
    138         if(entry.isSelected()) {
    139         if (!entry.getProperty().equals(current_coll_name)){
    140             found_entry = true;
    141         }
    142         command.append(" ");
    143         command.append(entry.getProperty());
    144         }
    145         entry = null;
    146     }
    147     command.append("\n");
    148     command.append("\n");
    149    
    150     // It is possible that there was only one entry - the current collection -  in which case we return null.
    151     if(found_entry) {
    152         return command.toString();
    153     }
    154     else {
    155         return null;
    156     }
     96        supercollection = null;
     97    }
     98    return result;
     99    }
     100
     101    public void removeSuperCollection(SuperCollection supercollection) {
     102    remove(supercollection);
    157103    }
    158104
     
    169115
    170116    /** Provides controls for altering the SuperCollection settings. */
    171     private class Control
    172     extends JPanel {
     117    private class SuperCollectionControl
     118    extends JPanel
     119    implements Control {
    173120
    174121    private boolean init = true;
     122    private CheckList collection_checklist = null;
    175123    //private JSplitPane center_pane;
    176124
    177     Control() {
     125    SuperCollectionControl() {
    178126        super();
     127
     128        buildModel();
    179129        // Creation
    180130        JPanel header_panel = new JPanel();
     
    194144        instructions.setWrapStyleWord(true);
    195145
    196         CheckList collection_checklist = new CheckList(collection_checklist_model);
     146        collection_checklist = new CheckList(collection_checklist_model);
     147
    197148        // Layout
    198149        //center_pane.setTopComponent(new JScrollPane(instructions));
     
    209160    }
    210161
    211     public void paint(Graphics g) {
    212         super.paint(g);
    213         // If this is the first time we've painted this control, then set the divider 1/3:2/3
    214         //if(init) {
    215         //  init = false;
    216         //  center_pane.setDividerLocation(0.3);
    217         //  super.paint(g);
    218         //}
     162    public void destroy() {
     163    }
     164
     165    public void gainFocus() {
     166    }
     167
     168    public void loseFocus() {
     169        // Retrieve the current supercollections
     170        ArrayList supercollections = children();
     171        // Now iterate through the checklist, and for each checked box found ensure the Supercollection exists, and ensure its assigned. Remove any supercollections altered in this way from the temporary array list
     172        int size = collection_checklist_model.size();
     173        for(int i = 0; i < size; i++) {
     174        Entry entry = (Entry) collection_checklist_model.get(i);
     175        if(entry.isSelected()) {
     176            String collection_name = (String) entry.getProperty();
     177            SuperCollection supercollection = getSuperCollection(collection_name);
     178            // Create the supercollection element if necessary
     179            if(supercollection == null) {
     180            Element supercollection_element = root.getOwnerDocument().createElement(StaticStrings.COLLECTION_ELEMENT);
     181            supercollection = new SuperCollection(supercollection_element);
     182            supercollection.setName(collection_name);
     183            addSuperCollection(supercollection);
     184            }
     185            else {
     186            supercollections.remove(supercollection);
     187            }
     188            supercollection.setAssigned(true);
     189        }
     190        }
     191        // Any collections left in the temporary list have been unselected, so delete them
     192        for(int j = supercollections.size(); j > 0; j--) {
     193        SuperCollection supercollection = (SuperCollection) supercollections.get(j - 1);
     194        removeSuperCollection(supercollection);
     195        }
     196    }
     197
     198    private void buildModel() {
     199        // We start by building a model of the installed collections.
     200        collection_checklist_model = new ArrayList();
     201        File gsdl_collection_directory = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
     202        current_coll_name = Gatherer.c_man.getCollection().getName();
     203        File[] possible_collections = gsdl_collection_directory.listFiles();
     204        for(int i = 0; possible_collections != null && i < possible_collections.length; i++) {
     205        // The simpliest case is if the directory etc/collect.cfg file and a metadata/ in it. Thus it can easily be built upon.
     206        File collect_cfg_file = new File(possible_collections[i], Utility.CONFIG_DIR);
     207        if(collect_cfg_file.exists()) {
     208            CollectionConfiguration collect_cfg = new CollectionConfiguration(collect_cfg_file);
     209            String collection_title = collect_cfg.getName();
     210            String collection_name = possible_collections[i].getName();
     211            // We do have to block the model collection.
     212            if(!collection_title.equals("**title**")) {
     213            Entry entry = new Entry(collection_title);
     214            entry.setProperty(collection_name);
     215            // Check if a collection with this name exists. The current collection is always selected.
     216            entry.setSelected(getSuperCollection(collection_name) != null || collection_name.equals(current_coll_name));
     217            entry.setFixed(collection_name.equals(current_coll_name));
     218            collection_checklist_model.add(entry);
     219            entry = null;
     220           
     221            }
     222            collection_name = null;
     223            collection_title = null;
     224            collect_cfg = null;
     225        }
     226        collect_cfg_file = null;
     227        }
     228        possible_collections = null;
     229        gsdl_collection_directory = null;
     230        // Sort the result.
     231        Collections.sort(collection_checklist_model);
    219232    }
    220233    }
  • trunk/gli/src/org/greenstone/gatherer/cdm/custom/CustomAZList.java

    r4656 r4932  
    4545import org.greenstone.gatherer.cdm.ClassifierManager;
    4646import org.greenstone.gatherer.cdm.CustomClassifier;
    47 import org.greenstone.gatherer.cdm.Language;
    4847import org.greenstone.gatherer.file.FileNode;
    4948import org.greenstone.gatherer.msm.ElementWrapper;
     
    629628    }
    630629    else {
    631         String language_code = Gatherer.config.interface_language.getCode();
     630        String language_code = Gatherer.config.interface_language;
    632631        hidden_mde = hidden_mds.addElement(element.toString().replace('.','_'), language_code);
    633632        found = false;
  • trunk/gli/src/org/greenstone/gatherer/checklist/CheckList.java

    r4572 r4932  
    219219    private class CheckListListener
    220220    extends MouseAdapter {
     221
    221222    //private Entry previous_checkbox = null;
    222223    /** Called whenever the mouse is clicked over our list. We find the nearest checkbox and change its state.
     
    227228        int index = list.locationToIndex(e.getPoint());
    228229        Entry checkbox = (Entry)list.getModel().getElementAt(index);
    229         // If this is the same checkbox as was recently selected, change the tick.
    230         if (list.isSelectedIndex(index)) {
    231         if(!checkbox.isFixed()) {
    232             checkbox.setSelected(!checkbox.isSelected());
    233         }
    234         checkbox.grabFocus();
    235         }
    236         /*
    237           if(list.isSelectedIndex(index) && checkbox == previous_checkbox) {
    238           if(!checkbox.isFixed()) {
    239           checkbox.setSelected(!checkbox.isSelected());
    240           }
    241           checkbox.grabFocus();
    242           }
    243           // Otherwise the selection has just changed, so select the new checkbox
    244           else if(list.isSelectedIndex(index)) {
    245           previous_checkbox = checkbox;
    246           }
    247           else {
    248           previous_checkbox = null;
    249           }
    250         */
     230        if(!checkbox.isFixed()) {
     231        checkbox.setSelected(!checkbox.isSelected());
     232        }
     233        checkbox.grabFocus();
    251234    }
    252235    }
Note: See TracChangeset for help on using the changeset viewer.