Changeset 4366


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

re-tabbed the code for java

Location:
trunk/gli/src/org/greenstone/gatherer
Files:
76 edited

Legend:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    r4293 r4366  
    6666// ####################################################################################
    6767public class CheckList
    68     extends JList {
    69     /** The border used when a list row is not in focus. */
    70     protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
    71     /** Constructor. */
    72     public CheckList() {
    73           super();
    74           setCellRenderer(new CellRenderer());
    75           setModel(new DefaultListModel());
    76           setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    77           addMouseListener(new CheckListListener());
    78     }
    79     /** Constructor.
     68    extends JList {
     69    /** The border used when a list row is not in focus. */
     70    protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
     71    /** Constructor. */
     72    public CheckList() {
     73    super();
     74    setCellRenderer(new CellRenderer());
     75    setModel(new DefaultListModel());
     76    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     77    addMouseListener(new CheckListListener());
     78    }
     79    /** Constructor.
    8080      * @param list_data An <strong>ArrayList</strong> of entries for this checklist.
    8181      * @see org.greenstone.gatherer.checklist.CheckList.Entry
    8282      */
    83     public CheckList(ArrayList list_data) {
    84           super();
    85           // Create a new model.
    86           DefaultListModel model = new DefaultListModel();
    87           for(int i = 0; i < list_data.size(); i++) {
    88                 Entry entry = new Entry(list_data.get(i));
    89                 String name = entry.toString();
    90                 int index = 0;
    91                 boolean found = false;
    92                 while(index < model.size() && !found) {
    93                      Object sibling = model.getElementAt(index);
    94                      if(name.compareTo(sibling.toString()) <= 0) {
    95                           model.add(index, entry);
    96                           found = true;
    97                      }
    98                      index++;
    99                 }
    100                 if(!found) {
    101                      model.addElement(entry);
    102                 }
    103           }
    104           setModel(model);
    105           setCellRenderer(new CellRenderer());
    106           addMouseListener(new CheckListListener());
    107           setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    108     }
    109 
    110     /** Constructor. */
    111     public CheckList(ListModel data_model) {
    112           super(data_model);
    113           setCellRenderer(new CellRenderer());
    114           addMouseListener(new CheckListListener());
    115           setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    116     }
    117 
    118     public void addEntry(Entry entry) {
    119           DefaultListModel model = (DefaultListModel) getModel();
    120           String name = entry.toString();
    121           int index = 0;
    122           boolean found = false;
    123           while(index < model.size() && !found) {
    124                 Object sibling = model.getElementAt(index);
    125                 if(name.compareTo(sibling.toString()) <= 0) {
    126                      model.add(index, entry);
    127                      found = true;
    128                 }
    129                 index++;
    130                 sibling = null;
    131           }
    132           if(!found) {
    133                 model.addElement(entry);
    134           }       
    135           name = null;
    136           model = null;
    137     }
    138 
    139     public Entry get(int index) {
    140           DefaultListModel model = (DefaultListModel) getModel();
    141           return (Entry) model.get(index);
    142     }
    143 
    144     /** Retrieve the currently ticked entries from this list.
     83    public CheckList(ArrayList list_data) {
     84    super();
     85    // Create a new model.
     86    DefaultListModel model = new DefaultListModel();
     87    for(int i = 0; i < list_data.size(); i++) {
     88        Entry entry = new Entry(list_data.get(i));
     89        String name = entry.toString();
     90        int index = 0;
     91        boolean found = false;
     92        while(index < model.size() && !found) {
     93        Object sibling = model.getElementAt(index);
     94        if(name.compareTo(sibling.toString()) <= 0) {
     95            model.add(index, entry);
     96            found = true;
     97        }
     98        index++;
     99        }
     100        if(!found) {
     101        model.addElement(entry);
     102        }
     103    }
     104    setModel(model);
     105    setCellRenderer(new CellRenderer());
     106    addMouseListener(new CheckListListener());
     107    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     108    }
     109
     110    /** Constructor. */
     111    public CheckList(ListModel data_model) {
     112    super(data_model);
     113    setCellRenderer(new CellRenderer());
     114    addMouseListener(new CheckListListener());
     115    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     116    }
     117
     118    public void addEntry(Entry entry) {
     119    DefaultListModel model = (DefaultListModel) getModel();
     120    String name = entry.toString();
     121    int index = 0;
     122    boolean found = false;
     123    while(index < model.size() && !found) {
     124        Object sibling = model.getElementAt(index);
     125        if(name.compareTo(sibling.toString()) <= 0) {
     126        model.add(index, entry);
     127        found = true;
     128        }
     129        index++;
     130        sibling = null;
     131    }
     132    if(!found) {
     133        model.addElement(entry);
     134    }         
     135    name = null;
     136    model = null;
     137    }
     138
     139    public Entry get(int index) {
     140    DefaultListModel model = (DefaultListModel) getModel();
     141    return (Entry) model.get(index);
     142    }
     143
     144    /** Retrieve the currently ticked entries from this list.
    145145      * @return An <strong>ArrayList</strong> containing only those entries from the initial list that are checked.
    146146      * @see org.greenstone.gatherer.checklist.CheckList.Entry
    147147      */
    148     public ArrayList getSelected() {
    149           ArrayList result = new ArrayList();
    150           DefaultListModel model = (DefaultListModel) getModel();
    151           int size = model.size();
    152           for(int i = 0; i < size; i++) {
    153                 Entry entry = (Entry) model.get(i);
    154                 if(entry.isSelected()) {
    155                      result.add(entry.getObject());
    156                 }
    157           }
    158           return result;
    159     }
    160 
    161     public boolean isSelected(int index) {
    162           DefaultListModel model = (DefaultListModel) getModel();
    163           Entry entry = (Entry) model.get(index);
    164           return entry.isSelected();
    165     }
    166 
    167     public int getEntryCount() {
    168           return getModel().getSize();
    169     }
    170 
    171     /** Checks the entries in the list whose name appear in the given array.
     148    public ArrayList getSelected() {
     149    ArrayList result = new ArrayList();
     150    DefaultListModel model = (DefaultListModel) getModel();
     151    int size = model.size();
     152    for(int i = 0; i < size; i++) {
     153        Entry entry = (Entry) model.get(i);
     154        if(entry.isSelected()) {
     155        result.add(entry.getObject());
     156        }
     157    }
     158    return result;
     159    }
     160
     161    public boolean isSelected(int index) {
     162    DefaultListModel model = (DefaultListModel) getModel();
     163    Entry entry = (Entry) model.get(index);
     164    return entry.isSelected();
     165    }
     166
     167    public int getEntryCount() {
     168    return getModel().getSize();
     169    }
     170
     171    /** Checks the entries in the list whose name appear in the given array.
    172172      * @param names The name of entries to be checked as a <strong>String[]</strong>.
    173173      * @see org.greenstone.gatherer.checklist.CheckList.Entry
    174174      */
    175     public void setSelected(String names[]) {
    176           DefaultListModel model = (DefaultListModel) getModel();
    177           int size = model.size();
    178           for(int i = 0; i < size; i++) {
    179                 Entry entry = (Entry) model.get(i);
    180                 for(int j = 0; names != null && j < names.length; j++) {
    181                      if(entry.toString().equals(names[j])) {
    182                           entry.setSelected(true);
    183                      }
    184                 }
    185           }       
    186     }
    187     /** A custom list cell renderer for producing rows which contain clickable check boxes. */
    188     protected class CellRenderer
    189           implements ListCellRenderer {
    190           /** 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.
    191             * @param list The </strong>JList</strong> we're painting.
    192             * @param value The value returned by list.getModel().getElementAt(index), as an <strong>Object</strong>.
    193             * @param index The cells index as an <i>int</i>.
    194             * @param is_selected <i>true</i> if the specified cell was selected, <i>false</i> otherwise.
    195             * @param cell_has_focus <i>true</i> if and only if the specified cell has the focus.
    196             * @return A <strong>Component</strong> whose paint() method will render the specified value.
     175    public void setSelected(String names[]) {
     176    DefaultListModel model = (DefaultListModel) getModel();
     177    int size = model.size();
     178    for(int i = 0; i < size; i++) {
     179        Entry entry = (Entry) model.get(i);
     180        for(int j = 0; names != null && j < names.length; j++) {
     181        if(entry.toString().equals(names[j])) {
     182            entry.setSelected(true);
     183        }
     184        }
     185    }         
     186    }
     187    /** A custom list cell renderer for producing rows which contain clickable check boxes. */
     188    protected class CellRenderer
     189    implements ListCellRenderer {
     190    /** 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.
     191     * @param list The </strong>JList</strong> we're painting.
     192     * @param value The value returned by list.getModel().getElementAt(index), as an <strong>Object</strong>.
     193     * @param index The cells index as an <i>int</i>.
     194     * @param is_selected <i>true</i> if the specified cell was selected, <i>false</i> otherwise.
     195     * @param cell_has_focus <i>true</i> if and only if the specified cell has the focus.
     196     * @return A <strong>Component</strong> whose paint() method will render the specified value.
    197197            */
    198           public Component getListCellRendererComponent(JList list, Object value, int index, boolean is_selected, boolean cell_has_focus) {
    199                 JCheckBox checkbox = (JCheckBox) value;
    200                 checkbox.setBackground(is_selected ? list.getSelectionBackground() : list.getBackground());
    201                 checkbox.setForeground(is_selected ? list.getSelectionForeground() : list.getForeground());
    202                 checkbox.setEnabled(list.isEnabled());
    203                 checkbox.setFont(list.getFont());
    204                 checkbox.setFocusPainted(false);
    205                 checkbox.setBorderPainted(true);
    206                 checkbox.setBorder((is_selected) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
    207                 return checkbox;
    208           }
    209     }
    210     /** Listens for clicks apon the checks within the list, and updates as necessary. */
    211     private class CheckListListener
    212           extends MouseAdapter {
    213           private Entry previous_checkbox = null;
    214           /** Called whenever the mouse is clicked over our list. We find the nearest checkbox and change its state.
    215             * @param e A <strong>MouseEvent</strong> containing everything you ever wanted to know about the mouse event but were afraid to ask.
    216             */
    217           public void mousePressed(MouseEvent e) {
    218                 JList list = (JList) e.getSource();
    219                 int index = list.locationToIndex(e.getPoint());
    220                 Entry checkbox = (Entry)list.getModel().getElementAt(index);
     198    public Component getListCellRendererComponent(JList list, Object value, int index, boolean is_selected, boolean cell_has_focus) {
     199        JCheckBox checkbox = (JCheckBox) value;
     200        checkbox.setBackground(is_selected ? list.getSelectionBackground() : list.getBackground());
     201        checkbox.setForeground(is_selected ? list.getSelectionForeground() : list.getForeground());
     202        checkbox.setEnabled(list.isEnabled());
     203        checkbox.setFont(list.getFont());
     204        checkbox.setFocusPainted(false);
     205        checkbox.setBorderPainted(true);
     206        checkbox.setBorder((is_selected) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
     207        return checkbox;
     208    }
     209    }
     210    /** Listens for clicks apon the checks within the list, and updates as necessary. */
     211    private class CheckListListener
     212    extends MouseAdapter {
     213    private Entry previous_checkbox = null;
     214    /** Called whenever the mouse is clicked over our list. We find the nearest checkbox and change its state.
     215     * @param e A <strong>MouseEvent</strong> containing everything you ever wanted to know about the mouse event but were afraid to ask.
     216     */
     217    public void mousePressed(MouseEvent e) {
     218        JList list = (JList) e.getSource();
     219        int index = list.locationToIndex(e.getPoint());
     220        Entry checkbox = (Entry)list.getModel().getElementAt(index);
    221221                // If this is the same checkbox as was recently selected, change the tick.
    222                 if(list.isSelectedIndex(index) && checkbox == previous_checkbox) {
    223                      if(!checkbox.isFixed()) {
    224                           checkbox.setSelected(!checkbox.isSelected());
    225                      }
    226                      checkbox.grabFocus();
    227                 }
     222        if(list.isSelectedIndex(index) && checkbox == previous_checkbox) {
     223        if(!checkbox.isFixed()) {
     224            checkbox.setSelected(!checkbox.isSelected());
     225        }
     226        checkbox.grabFocus();
     227        }
    228228                // Otherwise the selection has just changed, so select the new checkbox
    229                 else if(list.isSelectedIndex(index)) {
    230                      previous_checkbox = checkbox;
    231                 }
    232                 else {
    233                      previous_checkbox = null;
    234                 }
    235           }
    236     }
     229        else if(list.isSelectedIndex(index)) {
     230        previous_checkbox = checkbox;
     231        }
     232        else {
     233        previous_checkbox = null;
     234        }
     235    }
     236    }
    237237}
    238238
  • trunk/gli/src/org/greenstone/gatherer/checklist/Entry.java

    r4293 r4366  
    99/** An Entry encapsulates a single row of the list, both its check box and the object the row represents. */
    1010public class Entry
    11     extends JCheckBox {
    12     /** Is this checkboxes state fixed. */
    13     private boolean fixed = false;
    14     /** The original object this row is based on, and whose toString() is used to generate the check box label. */
    15     private Object object = null;
    16     /** A sundry string for storing original values (rather than strings retrieved from dictionary). */
    17     private String property;
    18     /** Constructor. */
    19     public Entry(Object object) {
    20           super(object.toString());
    21           this.object = object;
    22           // We also build a special tool tip for metadata sets.
    23           if(object instanceof MetadataSet) {
    24                 MetadataSet set = (MetadataSet) object;
     11    extends JCheckBox {
     12    /** Is this checkboxes state fixed. */
     13    private boolean fixed = false;
     14    /** The original object this row is based on, and whose toString() is used to generate the check box label. */
     15    private Object object = null;
     16    /** A sundry string for storing original values (rather than strings retrieved from dictionary). */
     17    private String property;
     18    /** Constructor. */
     19    public Entry(Object object) {
     20    super(object.toString());
     21    this.object = object;
     22    // We also build a special tool tip for metadata sets.
     23    if(object instanceof MetadataSet) {
     24        MetadataSet set = (MetadataSet) object;
    2525                // Build tooltip
    26                 StringBuffer tip = new StringBuffer(Gatherer.dictionary.get("NewCollectionPrompt.Set_Contains"));
    27                 tip.append(":\n");
    28                 for(int i = 0; i < set.size(); i++) {
    29                      Element element = set.getElement(i);
    30                      tip.append(MSMUtils.getIdentifier(element));
    31                      if(i < set.size() - 1) {
    32                           tip.append(", ");
    33                      }
    34                 }
    35                 setToolTipText(Utility.formatHTMLWidth(tip.toString(), 60));
    36           }
    37     }
     26        StringBuffer tip = new StringBuffer(Gatherer.dictionary.get("NewCollectionPrompt.Set_Contains"));
     27        tip.append(":\n");
     28        for(int i = 0; i < set.size(); i++) {
     29        Element element = set.getElement(i);
     30        tip.append(MSMUtils.getIdentifier(element));
     31        if(i < set.size() - 1) {
     32            tip.append(", ");
     33        }
     34        }
     35        setToolTipText(Utility.formatHTMLWidth(tip.toString(), 60));
     36    }
     37    }
    3838
    39     /** Constructor. */
    40     public Entry(String text, boolean is_selected) {
    41           super(text);
    42           setSelected(is_selected);
    43     }
     39    /** Constructor. */
     40    public Entry(String text, boolean is_selected) {
     41    super(text);
     42    setSelected(is_selected);
     43    }
    4444
    45     /** Retrieve the object associated with this entry.
     45    /** Retrieve the object associated with this entry.
    4646      * @return An <strong>Object</strong>.
    4747      */
    48     public Object getObject() {
    49           if(object == null) {
    50                 return getText();
    51           }
    52           return object;
    53     }
     48    public Object getObject() {
     49    if(object == null) {
     50        return getText();
     51    }
     52    return object;
     53    }
    5454
    55     public String getProperty() {
    56           return property;
    57     }
     55    public String getProperty() {
     56    return property;
     57    }
    5858
    59     public boolean isFixed() {
    60           return fixed;
    61     }
     59    public boolean isFixed() {
     60    return fixed;
     61    }
    6262
    63     public void setFixed(boolean fixed) {
    64           this.fixed = fixed;
    65     }
     63    public void setFixed(boolean fixed) {
     64    this.fixed = fixed;
     65    }
    6666
    67     public void setProperty(String property) {
    68           this.property = property;
    69     }
     67    public void setProperty(String property) {
     68    this.property = property;
     69    }
    7070
    71     public String toString() {
    72           if(object == null) {
    73                 return getText();
    74           }
    75           return object.toString();
    76     }
     71    public String toString() {
     72    if(object == null) {
     73        return getText();
     74    }
     75    return object.toString();
     76    }
    7777}
  • trunk/gli/src/org/greenstone/gatherer/collection/BuildOptions.java

    r4293 r4366  
    1515/** Build options uses the argument list found in config.xml and the current settings from the loaded collection configuration to represent the options the user wants to use during import and build. If there are no arguments stored in config.xml, or if the user indicates the argument are out of date, this class tries to parse new ones. */
    1616public class BuildOptions {
    17     /** The root element of the build argument tree. */
    18     private Element build_arguments_element;
    19     /** The root element of the build values tree. */
    20     private Element build_values_element;
    21     /** The root element of the import argument tree. */
    22     private Element import_arguments_element;
    23     /** The root element of the import values tree. */
    24     private Element import_values_element;
    25     /** A cache of previously created build arguments. */
    26     private Hashtable build_arguments_cache = new Hashtable();
    27     /** A cache of previously created import arguments. */
    28     private Hashtable import_arguments_cache = new Hashtable();
    29     /** The name of an argument element. */
    30     static final private String ARGUMENT = "Argument";
    31     /** The name of the enabled attribute. */
    32     static final private String ENABLED = "enabled";
    33     /** The name of the 'false' value. */
    34     static final private String FALSE = "false";
    35     /** The name of a name attribute. */
    36     static final private String NAME = "name";
    37     /** The name of an option element. */
    38     static final private String OPTION = "Option";
    39     /** The name of the 'true' value. */
    40     static final private String TRUE = "true";
    41     /** When constructing a BuildOptions object we first try to retrieve the valid arguments from config.xml. If that fails we then try to parse the arguments noticed when calling import.pl -xml and buildcol.pl -xml. If that also fails, we load the default arguments from the xml template library. */
    42     public BuildOptions(Element build_values_element, Element import_values_element) {
    43           // Try to retrieve the arguments for import and build.
    44           build_arguments_element = Gatherer.config.getArguments("buildcol.pl");
    45           import_arguments_element = Gatherer.config.getArguments("import.pl");
    46           // If that fails try to reconstruct the arguments
    47           if(build_arguments_element == null || import_arguments_element == null) {
    48                 build_arguments_element = loadArguments("buildcol.pl");
    49                 import_arguments_element = loadArguments("import.pl");
     17    /** The root element of the build argument tree. */
     18    private Element build_arguments_element;
     19    /** The root element of the build values tree. */
     20    private Element build_values_element;
     21    /** The root element of the import argument tree. */
     22    private Element import_arguments_element;
     23    /** The root element of the import values tree. */
     24    private Element import_values_element;
     25    /** A cache of previously created build arguments. */
     26    private Hashtable build_arguments_cache = new Hashtable();
     27    /** A cache of previously created import arguments. */
     28    private Hashtable import_arguments_cache = new Hashtable();
     29    /** The name of an argument element. */
     30    static final private String ARGUMENT = "Argument";
     31    /** The name of the enabled attribute. */
     32    static final private String ENABLED = "enabled";
     33    /** The name of the 'false' value. */
     34    static final private String FALSE = "false";
     35    /** The name of a name attribute. */
     36    static final private String NAME = "name";
     37    /** The name of an option element. */
     38    static final private String OPTION = "Option";
     39    /** The name of the 'true' value. */
     40    static final private String TRUE = "true";
     41    /** When constructing a BuildOptions object we first try to retrieve the valid arguments from config.xml. If that fails we then try to parse the arguments noticed when calling import.pl -xml and buildcol.pl -xml. If that also fails, we load the default arguments from the xml template library. */
     42    public BuildOptions(Element build_values_element, Element import_values_element) {
     43    // Try to retrieve the arguments for import and build.
     44    build_arguments_element = Gatherer.config.getArguments("buildcol.pl");
     45    import_arguments_element = Gatherer.config.getArguments("import.pl");
     46    // If that fails try to reconstruct the arguments
     47    if(build_arguments_element == null || import_arguments_element == null) {
     48        build_arguments_element = loadArguments("buildcol.pl");
     49        import_arguments_element = loadArguments("import.pl");
    5050                // And if that too fails, load the default argument templates
    51                 if(build_arguments_element == null || import_arguments_element == null) {
    52                      Document build_document = Utility.parse("xml" + File.separator + "buildcol.xml", true);
    53                      build_arguments_element = build_document.getDocumentElement();
    54                      build_document = null;
    55                      Document import_document = Utility.parse("xml" + File.separator + "import.xml", true);
    56                      import_arguments_element = import_document.getDocumentElement();
    57                      import_document = null;
    58                      ///atherer.println("Loaded default BO arguments from templates.");
     51        if(build_arguments_element == null || import_arguments_element == null) {
     52        Document build_document = Utility.parse("xml" + File.separator + "buildcol.xml", true);
     53        build_arguments_element = build_document.getDocumentElement();
     54        build_document = null;
     55        Document import_document = Utility.parse("xml" + File.separator + "import.xml", true);
     56        import_arguments_element = import_document.getDocumentElement();
     57        import_document = null;
     58        ///atherer.println("Loaded default BO arguments from templates.");
     59        }
     60        else {
     61        ///atherer.println("Loaded BO arguments from scripts.");
     62        }
     63                // By now we should definately have the arguments. However the reason we are here is because they are not stored in the config.xml file, to make sure they are stored now.
     64        Gatherer.config.setArguments(build_arguments_element);
     65        Gatherer.config.setArguments(import_arguments_element);
     66    }
     67    else {
     68        Gatherer.println("Loaded BO arguments from config.xml");
     69    }
     70    // Now take a note of the values too.
     71    this.build_values_element = build_values_element;
     72    this.import_values_element = import_values_element;
     73    }
     74
     75    /** Retrieve the arguments associated with a certain type of action, ie import or build. */
     76    public String[] getArguments(boolean build) {
     77    String arguments[] = null;
     78    NodeList argument_list = null;
     79    if(build) {
     80        argument_list = build_values_element.getElementsByTagName(ARGUMENT);
     81    }
     82    else {
     83        argument_list = import_values_element.getElementsByTagName(ARGUMENT);
     84    }
     85    for(int i = 0; i < argument_list.getLength(); i++) {
     86        String[] temp = new String[2];
     87        Element argument = (Element) argument_list.item(i);
     88        ArrayTools.add(arguments, argument.getAttribute(NAME));
     89        String value = MSMUtils.getValue(argument);
     90        if(value != null && value.length() > 0) {
     91        ArrayTools.add(arguments, value);
     92        }
     93    }
     94    return arguments;
     95    }
     96
     97    /** Retrieve the indexth argument belonging to build. */
     98    public Argument getBuildArgument(int index) {
     99    Argument argument = null;
     100    // Try to find the argument in the cache.
     101    SoftReference reference = (SoftReference) build_arguments_cache.get(new Integer(index));
     102    if(reference != null) {
     103        argument = (Argument) reference.get();
     104    }
     105    // Otherwise generate a new argument.
     106    if(argument == null) {
     107        argument = getArgument(build_arguments_element, index);
     108    }
     109    return argument;
     110    }
     111
     112    /** Retrieve the number of arguments involved in building. */
     113    public int getBuildArgumentCount() {
     114    NodeList build_options = build_arguments_element.getElementsByTagName(OPTION);
     115    return build_options.getLength();
     116    }
     117
     118    /** Retrieve the value of a certain build argument. */
     119    public String getBuildValue(String name) {
     120    return getValue(build_values_element, name, false);
     121    }
     122
     123    /** Determine if the named argument value is enabled or disabled. */
     124    public boolean getBuildValueEnabled(String name) {
     125    boolean result = false;
     126    String value = getValue(build_values_element, name, true);
     127    if(value != null && value.length() > 0) {
     128        result = (value.equalsIgnoreCase(TRUE));
     129    }
     130    return result;
     131    }
     132
     133    /** Retrieve all of the build values as a String array ready to added to the buildcol.pl call. */
     134    public String[] getBuildValues() {
     135    return getValues(build_values_element);
     136    }
     137
     138    /** Retrieve the indexth argument belonging to import. */
     139    public Argument getImportArgument(int index) {
     140    Argument argument = null;
     141    // Try to find the argument in the cache.
     142    SoftReference reference = (SoftReference) import_arguments_cache.get(new Integer(index));
     143    if(reference != null) {
     144        argument = (Argument) reference.get();
     145    }
     146    // Otherwise generate a new argument.
     147    if(argument == null) {
     148        argument = getArgument(import_arguments_element, index);
     149    }
     150    return argument;
     151    }
     152
     153    /** Retrieve the number of arguments involved in importing. */
     154    public int getImportArgumentCount() {
     155    NodeList import_options = import_arguments_element.getElementsByTagName(OPTION);
     156    return import_options.getLength();
     157    }
     158
     159    /** Retrieve the value of a certain build argument. */
     160    public String getImportValue(String name) {
     161    return getValue(import_values_element, name, false);
     162    }
     163
     164    /** Determine if the named argument value is enabled or disabled. */
     165    public boolean getImportValueEnabled(String name) {
     166    boolean result = false;
     167    String value = getValue(import_values_element, name, true);
     168    if(value != null && value.length() > 0) {
     169        result = (value.equalsIgnoreCase(TRUE));
     170    }
     171    return result;
     172    }
     173
     174    /** Retrieve all of the import arguments in a form ready to be sent out to a shell process. */
     175    public String[] getImportValues() {
     176    return getValues(import_values_element);
     177    }
     178
     179    /** Set the value of a build argument. */
     180    public void setBuildValue(String name, boolean enable, String value) {
     181    setValue(build_values_element, name, enable, value);
     182    }
     183
     184    /** Set the value of a build argument. */
     185    public void setImportValue(String name, boolean enable, String value) {
     186    setValue(import_values_element, name, enable, value);
     187    }   
     188
     189    /** Remove the given build value. */
     190    public void removeBuildValue(String name) {
     191    removeValue(build_values_element, name);
     192    }
     193
     194    /** Remove the given import value. */
     195    public void removeImportValue(String name) {
     196    removeValue(import_values_element, name);
     197    }
     198
     199    /** Retrieve the indexth element from the given set of arguments. */
     200    private Argument getArgument(Element arguments_element, int index) {
     201    Argument argument = null;
     202    try {
     203        NodeList option_list = arguments_element.getElementsByTagName(OPTION);
     204        if(0 <= index && index < option_list.getLength()) {
     205        // Retrieve the appropriate argument
     206        Element option = (Element) option_list.item(index);
     207        // Iterate through this option elements children, making note of any details we find.
     208        argument = new Argument();
     209        for(Node node = option.getFirstChild(); node != null; node = node.getNextSibling()) {
     210            String node_name = node.getNodeName();
     211            if(node_name.equals("Name")) {
     212            argument.setName(MSMUtils.getValue(node));
     213            }
     214            else if(node_name.equals("Desc")) {
     215            argument.setDesc(MSMUtils.getValue(node));
     216            }
     217            else if(node_name.equals("Type")) {
     218            argument.setType(MSMUtils.getValue(node));
     219            }
     220            else if(node_name.equals("Default")) {
     221            argument.setDefault(MSMUtils.getValue(node));
     222            }
     223            else if(node_name.equals("List")) {
     224            // Two final loops are required to parse lists.
     225            for(Node value = node.getFirstChild(); value != null; value = value.getNextSibling()) {
     226                if(value.getNodeName().equals("Value")) {
     227                String key = null;
     228                String desc = "";
     229                for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
     230                    node_name = subvalue.getNodeName();
     231                    if(node_name.equals("Name")) {
     232                    key = MSMUtils.getValue(subvalue);
     233                    }
     234                    else if(node_name.equals("Desc")) {
     235                    desc = MSMUtils.getValue(subvalue);
     236                    }
    59237                }
    60                 else {
    61                      ///atherer.println("Loaded BO arguments from scripts.");
     238                if(key != null) {
     239                    argument.addOption(key, desc);
    62240                }
    63                 // By now we should definately have the arguments. However the reason we are here is because they are not stored in the config.xml file, to make sure they are stored now.
    64                 Gatherer.config.setArguments(build_arguments_element);
    65                 Gatherer.config.setArguments(import_arguments_element);
    66           }
    67           else {
    68                 Gatherer.println("Loaded BO arguments from config.xml");
    69           }
    70           // Now take a note of the values too.
    71           this.build_values_element = build_values_element;
    72           this.import_values_element = import_values_element;
    73      }
    74 
    75      /** Retrieve the arguments associated with a certain type of action, ie import or build. */
    76      public String[] getArguments(boolean build) {
    77           String arguments[] = null;
    78           NodeList argument_list = null;
    79           if(build) {
    80                 argument_list = build_values_element.getElementsByTagName(ARGUMENT);
    81           }
    82           else {
    83                 argument_list = import_values_element.getElementsByTagName(ARGUMENT);
    84           }
    85           for(int i = 0; i < argument_list.getLength(); i++) {
    86                 String[] temp = new String[2];
    87                 Element argument = (Element) argument_list.item(i);
    88                 ArrayTools.add(arguments, argument.getAttribute(NAME));
    89                 String value = MSMUtils.getValue(argument);
    90                 if(value != null && value.length() > 0) {
    91                      ArrayTools.add(arguments, value);
    92                 }
    93           }
    94           return arguments;
    95      }
    96 
    97      /** Retrieve the indexth argument belonging to build. */
    98      public Argument getBuildArgument(int index) {
    99           Argument argument = null;
    100           // Try to find the argument in the cache.
    101           SoftReference reference = (SoftReference) build_arguments_cache.get(new Integer(index));
    102           if(reference != null) {
    103                 argument = (Argument) reference.get();
    104           }
    105           // Otherwise generate a new argument.
    106           if(argument == null) {
    107                 argument = getArgument(build_arguments_element, index);
    108           }
    109           return argument;
    110      }
    111 
    112      /** Retrieve the number of arguments involved in building. */
    113      public int getBuildArgumentCount() {
    114           NodeList build_options = build_arguments_element.getElementsByTagName(OPTION);
    115           return build_options.getLength();
    116      }
    117 
    118      /** Retrieve the value of a certain build argument. */
    119      public String getBuildValue(String name) {
    120           return getValue(build_values_element, name, false);
    121      }
    122 
    123      /** Determine if the named argument value is enabled or disabled. */
    124      public boolean getBuildValueEnabled(String name) {
    125           boolean result = false;
    126           String value = getValue(build_values_element, name, true);
    127           if(value != null && value.length() > 0) {
    128                 result = (value.equalsIgnoreCase(TRUE));
    129           }
    130           return result;
    131      }
    132 
    133      /** Retrieve all of the build values as a String array ready to added to the buildcol.pl call. */
    134      public String[] getBuildValues() {
    135           return getValues(build_values_element);
    136      }
    137 
    138      /** Retrieve the indexth argument belonging to import. */
    139      public Argument getImportArgument(int index) {
    140           Argument argument = null;
    141           // Try to find the argument in the cache.
    142           SoftReference reference = (SoftReference) import_arguments_cache.get(new Integer(index));
    143           if(reference != null) {
    144                 argument = (Argument) reference.get();
    145           }
    146           // Otherwise generate a new argument.
    147           if(argument == null) {
    148                 argument = getArgument(import_arguments_element, index);
    149           }
    150           return argument;
    151      }
    152 
    153      /** Retrieve the number of arguments involved in importing. */
    154      public int getImportArgumentCount() {
    155           NodeList import_options = import_arguments_element.getElementsByTagName(OPTION);
    156           return import_options.getLength();
    157      }
    158 
    159      /** Retrieve the value of a certain build argument. */
    160      public String getImportValue(String name) {
    161           return getValue(import_values_element, name, false);
    162      }
    163 
    164      /** Determine if the named argument value is enabled or disabled. */
    165      public boolean getImportValueEnabled(String name) {
    166           boolean result = false;
    167           String value = getValue(import_values_element, name, true);
    168           if(value != null && value.length() > 0) {
    169                 result = (value.equalsIgnoreCase(TRUE));
    170           }
    171           return result;
    172      }
    173 
    174      /** Retrieve all of the import arguments in a form ready to be sent out to a shell process. */
    175      public String[] getImportValues() {
    176           return getValues(import_values_element);
    177      }
    178 
    179      /** Set the value of a build argument. */
    180      public void setBuildValue(String name, boolean enable, String value) {
    181           setValue(build_values_element, name, enable, value);
    182      }
    183 
    184      /** Set the value of a build argument. */
    185      public void setImportValue(String name, boolean enable, String value) {
    186           setValue(import_values_element, name, enable, value);
    187      }   
    188 
    189      /** Remove the given build value. */
    190      public void removeBuildValue(String name) {
    191           removeValue(build_values_element, name);
    192      }
    193 
    194      /** Remove the given import value. */
    195      public void removeImportValue(String name) {
    196           removeValue(import_values_element, name);
    197      }
    198 
    199      /** Retrieve the indexth element from the given set of arguments. */
    200      private Argument getArgument(Element arguments_element, int index) {
    201           Argument argument = null;
    202           try {
    203                 NodeList option_list = arguments_element.getElementsByTagName(OPTION);
    204                 if(0 <= index && index < option_list.getLength()) {
    205                      // Retrieve the appropriate argument
    206                      Element option = (Element) option_list.item(index);
    207                      // Iterate through this option elements children, making note of any details we find.
    208                      argument = new Argument();
    209                      for(Node node = option.getFirstChild(); node != null; node = node.getNextSibling()) {
    210                           String node_name = node.getNodeName();
    211                           if(node_name.equals("Name")) {
    212                                 argument.setName(MSMUtils.getValue(node));
    213                           }
    214                           else if(node_name.equals("Desc")) {
    215                                 argument.setDesc(MSMUtils.getValue(node));
    216                           }
    217                           else if(node_name.equals("Type")) {
    218                                 argument.setType(MSMUtils.getValue(node));
    219                           }
    220                           else if(node_name.equals("Default")) {
    221                                 argument.setDefault(MSMUtils.getValue(node));
    222                           }
    223                           else if(node_name.equals("List")) {
    224                                 // Two final loops are required to parse lists.
    225                                 for(Node value = node.getFirstChild(); value != null; value = value.getNextSibling()) {
    226                                      if(value.getNodeName().equals("Value")) {
    227                                           String key = null;
    228                                           String desc = "";
    229                                           for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
    230                                                 node_name = subvalue.getNodeName();
    231                                                 if(node_name.equals("Name")) {
    232                                                      key = MSMUtils.getValue(subvalue);
    233                                                 }
    234                                                 else if(node_name.equals("Desc")) {
    235                                                      desc = MSMUtils.getValue(subvalue);
    236                                                 }
    237                                           }
    238                                           if(key != null) {
    239                                                 argument.addOption(key, desc);
    240                                           }
    241                                      }
    242                                 }
    243                           }
    244                           else if(node_name.equals("Required")) {
    245                                 String v = MSMUtils.getValue(node);
    246                                 if(v != null && v.equals("yes")) {
    247                                      argument.setRequired(true);
    248                                 }
    249                           }
    250                      }
    251                 }
    252           }
    253           catch (Exception error) {
    254                 Gatherer.println("Error in BuildOptions.getArgument(): " + error);
    255                 Gatherer.printStackTrace(error);
    256           }
    257           return argument;
    258      }
    259 
    260      private String getValue(Element arguments_element, String name, boolean is_enabled) {
    261           String result = null;
    262           try {
    263                 NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
    264                 for(int i = 0; result == null && i < arguments.getLength(); i++) {
    265                      Element argument_element = (Element) arguments.item(i);
    266                      // Is this the argument we want.
    267                      if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
    268                           // Are we simply determining if this argument is enabled
    269                           if(is_enabled) {
    270                                 result = argument_element.getAttribute(ENABLED);
    271                           }
    272                           else {
    273                                 String argument_value = MSMUtils.getValue(argument_element);
    274                                 if(argument_value != null) {
    275                                      result = argument_value;
    276                                 }
    277                                 argument_value = null;
    278                           }
    279                      }
    280                      argument_element = null;
    281                 }
    282                 arguments = null;
    283           }
    284           catch (Exception error) {
    285                 Gatherer.printStackTrace(error);
    286           }
    287           return result;
    288      }
    289 
    290      private String[] getValues(Element arguments_element) {
    291           ArrayList values = new ArrayList();
    292           try {
    293                 NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
    294                 for(int i = 0; i < arguments.getLength(); i++) {
    295                      Element argument_element = (Element) arguments.item(i);
    296                      // Determine if this argument is enabled.
    297                      if(argument_element.getAttribute(ENABLED).equalsIgnoreCase(TRUE)) {
    298                           // First store the name of the argument prefixed with a '-'
    299                           values.add("-" + argument_element.getAttribute(NAME));
    300                           // Now retrieve the value.
    301                           String argument_value = MSMUtils.getValue(argument_element);
    302                           // If there is a value, tokenize it by commas only.
    303                           if(argument_value != null && argument_value.length() > 0) {
    304                                 values.add(argument_value);
    305                           }
    306                           argument_value = null;
    307                      }
    308                      argument_element = null;
    309                 }
    310                 arguments = null;
    311           }
    312           catch (Exception error) {
    313                 Gatherer.printStackTrace(error);
    314           }
    315           return ArrayTools.arrayListToStringArray(values);
    316      }
    317 
    318      private Element loadArguments(String filename) {
    319           Element arguments_element = null;
    320           // Run the required program.
    321           /** @todo - I never finished implementing this. Have to test that the perl script handles being loaded in this way.
    322           try {
    323                 String args[] = new String[3];
    324                 args[0] = Gatherer.config.perl_path;
    325                 args[1] = filename;
    326                 args[2] = "-xml";
     241                }
     242            }
     243            }
     244            else if(node_name.equals("Required")) {
     245            String v = MSMUtils.getValue(node);
     246            if(v != null && v.equals("yes")) {
     247                argument.setRequired(true);
     248            }
     249            }
     250        }
     251        }
     252    }
     253    catch (Exception error) {
     254        Gatherer.println("Error in BuildOptions.getArgument(): " + error);
     255        Gatherer.printStackTrace(error);
     256    }
     257    return argument;
     258    }
     259
     260    private String getValue(Element arguments_element, String name, boolean is_enabled) {
     261    String result = null;
     262    try {
     263        NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
     264        for(int i = 0; result == null && i < arguments.getLength(); i++) {
     265        Element argument_element = (Element) arguments.item(i);
     266        // Is this the argument we want.
     267        if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
     268            // Are we simply determining if this argument is enabled
     269            if(is_enabled) {
     270            result = argument_element.getAttribute(ENABLED);
     271            }
     272            else {
     273            String argument_value = MSMUtils.getValue(argument_element);
     274            if(argument_value != null) {
     275                result = argument_value;
     276            }
     277            argument_value = null;
     278            }
     279        }
     280        argument_element = null;
     281        }
     282        arguments = null;
     283    }
     284    catch (Exception error) {
     285        Gatherer.printStackTrace(error);
     286    }
     287    return result;
     288    }
     289
     290    private String[] getValues(Element arguments_element) {
     291    ArrayList values = new ArrayList();
     292    try {
     293        NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
     294        for(int i = 0; i < arguments.getLength(); i++) {
     295        Element argument_element = (Element) arguments.item(i);
     296        // Determine if this argument is enabled.
     297        if(argument_element.getAttribute(ENABLED).equalsIgnoreCase(TRUE)) {
     298            // First store the name of the argument prefixed with a '-'
     299            values.add("-" + argument_element.getAttribute(NAME));
     300            // Now retrieve the value.
     301            String argument_value = MSMUtils.getValue(argument_element);
     302            // If there is a value, tokenize it by commas only.
     303            if(argument_value != null && argument_value.length() > 0) {
     304            values.add(argument_value);
     305            }
     306            argument_value = null;
     307        }
     308        argument_element = null;
     309        }
     310        arguments = null;
     311    }
     312    catch (Exception error) {
     313        Gatherer.printStackTrace(error);
     314    }
     315    return ArrayTools.arrayListToStringArray(values);
     316    }
     317
     318    private Element loadArguments(String filename) {
     319    Element arguments_element = null;
     320    // Run the required program.
     321    /** @todo - I never finished implementing this. Have to test that the perl script handles being loaded in this way.
     322        try {
     323        String args[] = new String[3];
     324        args[0] = Gatherer.config.perl_path;
     325        args[1] = filename;
     326        args[2] = "-xml";
    327327                // Create the process.
    328328                Runtime runtime = Runtime.getRuntime();
     
    334334                Document document = parser.getDocument();
    335335                arguments_element = document.getDocumentElement();
    336           }
    337           catch (Exception error) {
     336                }
     337                catch (Exception error) {
    338338                Gatherer.println("Error in BuildOptions.loadArguments(): " + error);
    339339                Gatherer.printStackTrace(error);
    340           }
    341           */
    342           return arguments_element;
    343      }
    344 
    345      /** Set the state of some build or import argument. Note that value may be either a single String, and ArrayList of Strings or null. If enable is false then any existing argument for the named argument is disabled. */
    346      public void setValue(Element arguments_element, String name, boolean enable, String value) {
    347           ///ystem.err.println("Set value: " + (arguments_element == build_values_element ? "Build" : "Import") + ", " + name + ", " + enable + ", " + value);
    348           try {
    349                 Document document = arguments_element.getOwnerDocument();
    350                 NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
    351                 boolean found = false;
    352                 for(int i = 0; i < arguments.getLength(); i++) {
    353                      Element argument_element = (Element) arguments.item(i);
    354                      // If this the argument named.
    355                      if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
    356                           found = true;
    357                           // Set whether this argument is enabled
    358                           argument_element.setAttribute(ENABLED, (enable ? TRUE : FALSE));
    359                           // Now we set the value, depending or what it is.
    360                           if(value == null) {
    361                                 // Nothing to do.
    362                           }
    363                           else {
    364                                 // Remove existing text nodes.
    365                                 while(argument_element.hasChildNodes()) {
    366                                      argument_element.removeChild(argument_element.getFirstChild());
    367                                 }
    368                                 argument_element.appendChild(document.createTextNode((String)value));
    369                           }
    370                      }
    371                      argument_element = null;
    372340                }
     341    */
     342    return arguments_element;
     343    }
     344
     345    /** Set the state of some build or import argument. Note that value may be either a single String, and ArrayList of Strings or null. If enable is false then any existing argument for the named argument is disabled. */
     346    public void setValue(Element arguments_element, String name, boolean enable, String value) {
     347    ///ystem.err.println("Set value: " + (arguments_element == build_values_element ? "Build" : "Import") + ", " + name + ", " + enable + ", " + value);
     348    try {
     349        Document document = arguments_element.getOwnerDocument();
     350        NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
     351        boolean found = false;
     352        for(int i = 0; i < arguments.getLength(); i++) {
     353        Element argument_element = (Element) arguments.item(i);
     354        // If this the argument named.
     355        if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
     356            found = true;
     357            // Set whether this argument is enabled
     358            argument_element.setAttribute(ENABLED, (enable ? TRUE : FALSE));
     359            // Now we set the value, depending or what it is.
     360            if(value == null) {
     361            // Nothing to do.
     362            }
     363            else {
     364            // Remove existing text nodes.
     365            while(argument_element.hasChildNodes()) {
     366                argument_element.removeChild(argument_element.getFirstChild());
     367            }
     368            argument_element.appendChild(document.createTextNode((String)value));
     369            }
     370        }
     371        argument_element = null;
     372        }
    373373                // If we haven't found an instance of this argument, but should have, then add it.
    374                 if(!found && (enable || value != null)) {
    375                      Element argument_element = document.createElement(ARGUMENT);
    376                      argument_element.setAttribute(NAME, name);
    377                      argument_element.setAttribute(ENABLED, (enable ? TRUE : FALSE));
    378                      // Now we set the value, depending or what it is.
    379                      if(value == null) {
    380                           // Nothing to do.
    381                      }
    382                      else {
    383                           argument_element.appendChild(document.createTextNode((String)value));
    384                      }
    385                      arguments_element.appendChild(argument_element);
    386                 }
    387                 arguments = null;
    388                 document = null;
     374        if(!found && (enable || value != null)) {
     375        Element argument_element = document.createElement(ARGUMENT);
     376        argument_element.setAttribute(NAME, name);
     377        argument_element.setAttribute(ENABLED, (enable ? TRUE : FALSE));
     378        // Now we set the value, depending or what it is.
     379        if(value == null) {
     380            // Nothing to do.
     381        }
     382        else {
     383            argument_element.appendChild(document.createTextNode((String)value));
     384        }
     385        arguments_element.appendChild(argument_element);
     386        }
     387        arguments = null;
     388        document = null;
    389389                // Make sure the collection knows to save.
    390                 Gatherer.c_man.getCollection().setSaved(false);
    391           }
    392           catch (Exception error) {
    393                 Gatherer.printStackTrace(error);
    394           }
    395     }
    396 
    397     /** Remove the named value from the given arguments element. */
    398     private void removeValue(Element arguments_element, String name) {
    399           try {
    400                 NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
    401                 boolean found = false;
    402                 for(int i = 0; !found && i < arguments.getLength(); i++) {
    403                      Element argument_element = (Element) arguments.item(i);
    404                      // Is this the argument we want.
    405                      if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
    406                           arguments_element.removeChild(argument_element);
    407                           found = true;
    408                      }
    409                      argument_element = null;
    410                 }
    411                 arguments = null;
    412           }
    413           catch (Exception error) {
    414                 Gatherer.printStackTrace(error);
    415           }
    416     }
     390        Gatherer.c_man.getCollection().setSaved(false);
     391    }
     392    catch (Exception error) {
     393        Gatherer.printStackTrace(error);
     394    }
     395    }
     396
     397    /** Remove the named value from the given arguments element. */
     398    private void removeValue(Element arguments_element, String name) {
     399    try {
     400        NodeList arguments = arguments_element.getElementsByTagName(ARGUMENT);
     401        boolean found = false;
     402        for(int i = 0; !found && i < arguments.getLength(); i++) {
     403        Element argument_element = (Element) arguments.item(i);
     404        // Is this the argument we want.
     405        if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
     406            arguments_element.removeChild(argument_element);
     407            found = true;
     408        }
     409        argument_element = null;
     410        }
     411        arguments = null;
     412    }
     413    catch (Exception error) {
     414        Gatherer.printStackTrace(error);
     415    }
     416    }
    417417}
  • trunk/gli/src/org/greenstone/gatherer/collection/Collection.java

    r4293 r4366  
    5656 */
    5757public class Collection {
    58     /** A reference to the BuildOptions. */
    59     public BuildOptions build_options;
    60     /** A reference to the Collection Design Manager. */
    61     public CollectionDesignManager cdm;
    62     /** A reference to the Greenstone Directory Metadata Manager. */
    63     public GDMManager gdm;
    64     /** A reference to the Metadata Set Manager. */
    65     public MetadataSetManager msm;
    66     /** <i>true</i> if the currently loaded collection has been saved since the last significant change, <i>false</i> otherwise. */
    67     private boolean saved = false;
    68     /** The collectio configuration file for this collection. */
    69     private CollectionConfiguration collect_cfg;
    70     /** The document around which this collection class is based. */
    71     private Document document;
    72     /** The file the collection is in (the file may not actually exist, such in the case of a legacy collection)! */
    73     private File file;
    74     /** The name of the argument element. */
    75     static final private String ARGUMENT = "Argument";
    76     /** The name of the build element. */
    77     static final private String BUILD = "Build";
    78     /** The name of the built attribute. */
    79     static final private String BUILT = "built";
    80     /** The name of the build config element. */
    81     static final private String BUILD_CONFIG = "BuildConfig";
    82     /** The name of the collection xml template. */
    83     static final private String COLLECTION_XML_TEMPLATE = "xml" + File.separator + "template.col";
    84     /** The name of the directory mappings element. */
    85     static final private String DIRECTORY_MAPPINGS = "DirectoryMappings";
    86     /** The name of the file attribute. */
    87     static final private String FILE = "file";
    88     /** The name of the import element. */
    89     static final private String IMPORT = "Import";
    90     /** The name of the imported attribute. */
    91     static final private String IMPORTED = "imported";
    92     /** The name of the mapping element. */
    93     static final private String MAPPING = "Mapping";
    94     /** The name of the name attribute. */
    95     static final private String NAME = "name";
    96     /** The name of the true value. */
    97     static final private String TRUE = "true";
    98     /** Constructor. */
    99     public Collection(File collection_xml) {
    100           this.file = collection_xml;
    101           // Try to load this collections details.
    102           document = Utility.parse(collection_xml, false);
    103           // If that fails load the default settings for a collection.
    104           if(document == null) {
    105                 document = Utility.parse(COLLECTION_XML_TEMPLATE, true);
    106           }
    107           // Point the Configuration class at our gatherer config arguments.
    108           Gatherer.config.setCollectionConfiguration(document);
    109           // We also attempt to parse the collection configuration file.
    110           collect_cfg = new CollectionConfiguration(new File(collection_xml.getParentFile(), Utility.CONFIG_DIR));
    111           // Finally create all of the child managers that are directly dependant on a collection
    112           build_options = new BuildOptions(getBuildValues(), getImportValues());         
    113     }
    114     /** Add a special directory mapping. */
    115     public boolean addDirectoryMapping(String name, File file) {
    116           boolean result = false;
    117           try {
    118                 Element document_element = document.getDocumentElement();
    119                 Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
     58    /** A reference to the BuildOptions. */
     59    public BuildOptions build_options;
     60    /** A reference to the Collection Design Manager. */
     61    public CollectionDesignManager cdm;
     62    /** A reference to the Greenstone Directory Metadata Manager. */
     63    public GDMManager gdm;
     64    /** A reference to the Metadata Set Manager. */
     65    public MetadataSetManager msm;
     66    /** <i>true</i> if the currently loaded collection has been saved since the last significant change, <i>false</i> otherwise. */
     67    private boolean saved = false;
     68    /** The collectio configuration file for this collection. */
     69    private CollectionConfiguration collect_cfg;
     70    /** The document around which this collection class is based. */
     71    private Document document;
     72    /** The file the collection is in (the file may not actually exist, such in the case of a legacy collection)! */
     73    private File file;
     74    /** The name of the argument element. */
     75    static final private String ARGUMENT = "Argument";
     76    /** The name of the build element. */
     77    static final private String BUILD = "Build";
     78    /** The name of the built attribute. */
     79    static final private String BUILT = "built";
     80    /** The name of the build config element. */
     81    static final private String BUILD_CONFIG = "BuildConfig";
     82    /** The name of the collection xml template. */
     83    static final private String COLLECTION_XML_TEMPLATE = "xml" + File.separator + "template.col";
     84    /** The name of the directory mappings element. */
     85    static final private String DIRECTORY_MAPPINGS = "DirectoryMappings";
     86    /** The name of the file attribute. */
     87    static final private String FILE = "file";
     88    /** The name of the import element. */
     89    static final private String IMPORT = "Import";
     90    /** The name of the imported attribute. */
     91    static final private String IMPORTED = "imported";
     92    /** The name of the mapping element. */
     93    static final private String MAPPING = "Mapping";
     94    /** The name of the name attribute. */
     95    static final private String NAME = "name";
     96    /** The name of the true value. */
     97    static final private String TRUE = "true";
     98    /** Constructor. */
     99    public Collection(File collection_xml) {
     100    this.file = collection_xml;
     101    // Try to load this collections details.
     102    document = Utility.parse(collection_xml, false);
     103    // If that fails load the default settings for a collection.
     104    if(document == null) {
     105        document = Utility.parse(COLLECTION_XML_TEMPLATE, true);
     106    }
     107    // Point the Configuration class at our gatherer config arguments.
     108    Gatherer.config.setCollectionConfiguration(document);
     109    // We also attempt to parse the collection configuration file.
     110    collect_cfg = new CollectionConfiguration(new File(collection_xml.getParentFile(), Utility.CONFIG_DIR));
     111    // Finally create all of the child managers that are directly dependant on a collection
     112    build_options = new BuildOptions(getBuildValues(), getImportValues());       
     113    }
     114    /** Add a special directory mapping. */
     115    public boolean addDirectoryMapping(String name, File file) {
     116    boolean result = false;
     117    try {
     118        Element document_element = document.getDocumentElement();
     119        Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
    120120                // Ensure the name isn't already in use.
    121                 boolean found = false;
    122                 NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
    123                 for(int i = 0; !found && i < mappings.getLength(); i++) {
    124                      Element mapping_element = (Element) mappings.item(i);
    125                      if(mapping_element.getAttribute(NAME).equalsIgnoreCase(name)) {
    126                           found = true;
    127                      }
    128                      mapping_element = null;
    129                 }
     121        boolean found = false;
     122        NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
     123        for(int i = 0; !found && i < mappings.getLength(); i++) {
     124        Element mapping_element = (Element) mappings.item(i);
     125        if(mapping_element.getAttribute(NAME).equalsIgnoreCase(name)) {
     126            found = true;
     127        }
     128        mapping_element = null;
     129        }
    130130                // Otherwise add the mapping.
    131                 if(!found) {
    132                      Element mapping_element = document.createElement(MAPPING);
    133                      mapping_element.setAttribute(NAME, name);
    134                      mapping_element.setAttribute(FILE, file.toString());
    135                      directory_mappings_element.appendChild(mapping_element);
    136                      result = true;
    137                      mapping_element = null;
    138                 }
    139                 mappings = null;
    140                 directory_mappings_element = null;
    141                 document_element = null;
    142                 saved = false;
    143           }
    144           catch (Exception error) {
    145                 Gatherer.printStackTrace(error);
    146           }
    147           return result;
    148     }
     131        if(!found) {
     132        Element mapping_element = document.createElement(MAPPING);
     133        mapping_element.setAttribute(NAME, name);
     134        mapping_element.setAttribute(FILE, file.toString());
     135        directory_mappings_element.appendChild(mapping_element);
     136        result = true;
     137        mapping_element = null;
     138        }
     139        mappings = null;
     140        directory_mappings_element = null;
     141        document_element = null;
     142        saved = false;
     143    }
     144    catch (Exception error) {
     145        Gatherer.printStackTrace(error);
     146    }
     147    return result;
     148    }
    149149
    150     /** Destructor.
    151       * @see org.greenstone.gatherer.collection.CollectionModel */
    152     public void destroy() {
    153           cdm.destroy();
    154           gdm.destroy();
    155           msm.destroy();
    156           Gatherer.config.setCollectionConfiguration(null);
    157           cdm = null;
    158           document = null;
    159           gdm = null;
    160           msm = null;
    161     }
    162     /** Determine whether this collection has been successfully built in the past.
    163       * @return <i>true</i> if the collection has been built, <i>false</i> otherwise.
    164       */
    165     public boolean getBuilt() {
    166           return get(BUILT);
    167     }
    168     /** Calculates the number of documents in this collection. */
    169     public int getDocumentCount() {
    170           return getCount((TreeNode)Gatherer.c_man.getRecordSet().getRoot(), false);
    171     }
    172     /** Retrieve the description of this collection.
    173       * @return The description as a <strong>String</strong>.
    174       */
    175     public String getDescription() {
    176           return collect_cfg.getDescription();
    177     }
    178     /** Retrieve a specific directory mapping associated with this collection.
    179       * @param name The name of the mapping to retrieve as a <strong>String</strong>.
    180       * @return The <strong>File</strong> this name maps to, or <i>null</i> if no such mapping.
    181       */
    182     public File getDirectoryMapping(String name) {
    183           File result = null;
    184           try {
    185                 Element document_element = document.getDocumentElement();
    186                 Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
     150    /** Destructor.
     151     * @see org.greenstone.gatherer.collection.CollectionModel */
     152    public void destroy() {
     153    cdm.destroy();
     154    gdm.destroy();
     155    msm.destroy();
     156    Gatherer.config.setCollectionConfiguration(null);
     157    cdm = null;
     158    document = null;
     159    gdm = null;
     160    msm = null;
     161    }
     162    /** Determine whether this collection has been successfully built in the past.
     163     * @return <i>true</i> if the collection has been built, <i>false</i> otherwise.
     164     */
     165    public boolean getBuilt() {
     166    return get(BUILT);
     167    }
     168    /** Calculates the number of documents in this collection. */
     169    public int getDocumentCount() {
     170    return getCount((TreeNode)Gatherer.c_man.getRecordSet().getRoot(), false);
     171    }
     172    /** Retrieve the description of this collection.
     173     * @return The description as a <strong>String</strong>.
     174     */
     175    public String getDescription() {
     176    return collect_cfg.getDescription();
     177    }
     178    /** Retrieve a specific directory mapping associated with this collection.
     179     * @param name The name of the mapping to retrieve as a <strong>String</strong>.
     180     * @return The <strong>File</strong> this name maps to, or <i>null</i> if no such mapping.
     181     */
     182    public File getDirectoryMapping(String name) {
     183    File result = null;
     184    try {
     185        Element document_element = document.getDocumentElement();
     186        Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
    187187                // Ensure the name isn't already in use.
    188                 boolean found = false;
    189                 NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
    190                 for(int i = 0; !found && i < mappings.getLength(); i++) {
    191                      Element mapping_element = (Element) mappings.item(i);
    192                      if(mapping_element.getAttribute(NAME).equalsIgnoreCase(name)) {
    193                           result = new File(MSMUtils.getValue(mapping_element));
    194                           found = true;
    195                      }
    196                      mapping_element = null;
    197                 }
    198                 mappings = null;
    199                 directory_mappings_element = null;
    200                 document_element = null;
    201           }
    202           catch(Exception error) {
    203                 Gatherer.printStackTrace(error);
    204           }
    205           return result;
    206     }
    207     /** Retrieve the special directory mappings associated with this collection.
    208       * @return A <strong>HashMap</strong> containing mappings from names to directories.
    209       */
    210     public HashMap getDirectoryMappings() {
    211           HashMap special_directories = new HashMap();
    212           try {
    213                 Element document_element = document.getDocumentElement();
    214                 Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
     188        boolean found = false;
     189        NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
     190        for(int i = 0; !found && i < mappings.getLength(); i++) {
     191        Element mapping_element = (Element) mappings.item(i);
     192        if(mapping_element.getAttribute(NAME).equalsIgnoreCase(name)) {
     193            result = new File(MSMUtils.getValue(mapping_element));
     194            found = true;
     195        }
     196        mapping_element = null;
     197        }
     198        mappings = null;
     199        directory_mappings_element = null;
     200        document_element = null;
     201    }
     202    catch(Exception error) {
     203        Gatherer.printStackTrace(error);
     204    }
     205    return result;
     206    }
     207    /** Retrieve the special directory mappings associated with this collection.
     208     * @return A <strong>HashMap</strong> containing mappings from names to directories.
     209     */
     210    public HashMap getDirectoryMappings() {
     211    HashMap special_directories = new HashMap();
     212    try {
     213        Element document_element = document.getDocumentElement();
     214        Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
    215215                // Ensure the name isn't already in use.
    216                 boolean found = false;
    217                 NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
    218                 for(int i = 0; !found && i < mappings.getLength(); i++) {
    219                      Element mapping_element = (Element) mappings.item(i);
    220                      String name = mapping_element.getAttribute(NAME);
    221                      File file = new File(mapping_element.getAttribute(FILE));
    222                      special_directories.put(name, file);
    223                      file = null;
    224                      name = null;
    225                      mapping_element = null;
    226                 }
    227                 mappings = null;
    228                 directory_mappings_element = null;
    229                 document_element = null;
    230           }
    231           catch(Exception error) {
    232                 Gatherer.printStackTrace(error);
    233           }       
    234           return special_directories;
    235     }
    236     /** Retrieve the authors email for this collection.
    237       * @return The email as a <strong>String</strong>.
    238       */
    239     public String getEmail() {
    240           return collect_cfg.getCreator();
    241     }
    242     /** Counts the number of folders used in the current record set. */
    243     public int getFolderCount() {
    244           return getCount((TreeNode)Gatherer.c_man.getRecordSet().getRoot(), true);
    245     }
    246     /** Determine if this collection has had an import action run upon it since the last major change.
    247       * @return <i>true</i> if an import has occured, <i>false</i> otherwise.
    248       */
    249     public boolean getImported() {
    250           return get(IMPORTED);
    251     }
    252     /** Retrieve the short name for this collection.
    253       * @return The name as a <strong>String</strong>.
    254       */
    255     public String getName() {
    256           return file.getParentFile().getName();
    257     }
    258     /** Determine if this collection has been saved since the last major change.
    259       * @return <i>true</i> if it has been saved recently, <i>false</i> otherwise.
    260       */
    261     public boolean getSaved() {
    262           return saved;
    263     }
    264     /** Retrieve the title of this collection.
    265       * @return The title as a <strong>String</strong>.
    266       */
    267     public String getTitle() {
    268           return collect_cfg.getName();
    269     }
    270     /** Remove a previously defined special directory mapping.
    271       * @param name The name of the mapping to remove as a <strong>String</strong>.
    272       * @return The <strong>File</strong> of the mapping removed.
    273       */
    274     public File removeDirectoryMapping(String name) {
    275           File file = null;
    276           try {
    277                 Element document_element = document.getDocumentElement();
    278                 Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
     216        boolean found = false;
     217        NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
     218        for(int i = 0; !found && i < mappings.getLength(); i++) {
     219        Element mapping_element = (Element) mappings.item(i);
     220        String name = mapping_element.getAttribute(NAME);
     221        File file = new File(mapping_element.getAttribute(FILE));
     222        special_directories.put(name, file);
     223        file = null;
     224        name = null;
     225        mapping_element = null;
     226        }
     227        mappings = null;
     228        directory_mappings_element = null;
     229        document_element = null;
     230    }
     231    catch(Exception error) {
     232        Gatherer.printStackTrace(error);
     233    }         
     234    return special_directories;
     235    }
     236    /** Retrieve the authors email for this collection.
     237     * @return The email as a <strong>String</strong>.
     238     */
     239    public String getEmail() {
     240    return collect_cfg.getCreator();
     241    }
     242    /** Counts the number of folders used in the current record set. */
     243    public int getFolderCount() {
     244    return getCount((TreeNode)Gatherer.c_man.getRecordSet().getRoot(), true);
     245    }
     246    /** Determine if this collection has had an import action run upon it since the last major change.
     247     * @return <i>true</i> if an import has occured, <i>false</i> otherwise.
     248     */
     249    public boolean getImported() {
     250    return get(IMPORTED);
     251    }
     252    /** Retrieve the short name for this collection.
     253     * @return The name as a <strong>String</strong>.
     254     */
     255    public String getName() {
     256    return file.getParentFile().getName();
     257    }
     258    /** Determine if this collection has been saved since the last major change.
     259     * @return <i>true</i> if it has been saved recently, <i>false</i> otherwise.
     260     */
     261    public boolean getSaved() {
     262    return saved;
     263    }
     264    /** Retrieve the title of this collection.
     265     * @return The title as a <strong>String</strong>.
     266     */
     267    public String getTitle() {
     268    return collect_cfg.getName();
     269    }
     270    /** Remove a previously defined special directory mapping.
     271     * @param name The name of the mapping to remove as a <strong>String</strong>.
     272     * @return The <strong>File</strong> of the mapping removed.
     273     */
     274    public File removeDirectoryMapping(String name) {
     275    File file = null;
     276    try {
     277        Element document_element = document.getDocumentElement();
     278        Element directory_mappings_element = (Element) MSMUtils.getNodeFromNamed(document_element, DIRECTORY_MAPPINGS);
    279279                // Ensure the name isn't already in use.
    280                 boolean found = false;
    281                 NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
    282                 for(int i = 0; !found && i < mappings.getLength(); i++) {
    283                      Element mapping_element = (Element) mappings.item(i);
    284                      if(mapping_element.getAttribute(NAME).equalsIgnoreCase(name)) {
    285                           file = new File(MSMUtils.getValue(mapping_element));
    286                           directory_mappings_element.removeChild(mapping_element);
    287                           found = true;
    288                      }
    289                      mapping_element = null;
    290                 }
    291                 mappings = null;
    292                 directory_mappings_element = null;
    293                 document_element = null;
    294                 saved = false;
    295           }
    296           catch(Exception error) {
    297                 Gatherer.printStackTrace(error);
    298           }
    299           return file;
    300     }
    301     /** Save this xml document to the given file. */
    302     public void save() {
    303           Utility.export(document, file);
    304     }
    305     /** Set the value of built to the given value.
    306       * @param value The new value for built, <i>true</i> if the collection has been built successfully, <i>false</i> otherwise.
    307       */
    308     public void setBuilt(boolean value) {
    309           set(BUILT, value);
    310           saved = false;
    311     }
    312     /** Set the value of imported to the given value.
    313       * @param value The new value for imported, <i>true</i> if the collection has been imported successfully, <i>false</i> otherwise.
    314       */
    315     public void setImported(boolean value) {
    316           set(IMPORTED, value);
    317           saved = false;
    318     }
    319     /** Set the value of saved to the given value.
    320       * @param value The new value for saved, <i>true</i> if the collection has been saved recently, <i>false</i> otherwise.
    321       */
    322     public void setSaved(boolean value) {
    323           saved = value;
    324     }
    325     /** Set the value of title to the given value.
    326       * @param title The new <strong>String</strong> title.
    327       */
    328     public void setTitle(String title) {
    329           collect_cfg.setName(title);
    330     }
    331     /** Method called to return a textual representation of a class, which in this case is the collections title.
    332       * @return A <strong>String</strong> containing the collections title.
    333       */
    334     public String toString() {
    335           return collect_cfg.getName();
    336     }
    337     /** Get the value of a collection argument. */
    338     private boolean get(String name) {
    339           boolean result = false;
    340           try {
    341                 Element document_element = document.getDocumentElement();
    342                 NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
    343                 boolean found = false;
    344                 for(int i = 0; !found && i < arguments.getLength(); i++) {
    345                      Element argument_element = (Element) arguments.item(i);
    346                      if(argument_element.getParentNode() == document_element) {
    347                           if(argument_element.getAttribute(NAME).equalsIgnoreCase(BUILT)) {
    348                                 String value = MSMUtils.getValue(argument_element);
    349                                 if(value.equalsIgnoreCase(TRUE)) {
    350                                     result = true;
    351                                 }
    352                                 found = true;
    353                                 value = null;
    354                           }
    355                      }
    356                      argument_element = null;
    357                 }
    358                 arguments = null;
    359                 document_element = null;
    360           }
    361           catch (Exception error) {
    362                 Gatherer.printStackTrace(error);
    363           }
    364           return result;
    365     }
     280        boolean found = false;
     281        NodeList mappings = directory_mappings_element.getElementsByTagName(MAPPING);
     282        for(int i = 0; !found && i < mappings.getLength(); i++) {
     283        Element mapping_element = (Element) mappings.item(i);
     284        if(mapping_element.getAttribute(NAME).equalsIgnoreCase(name)) {
     285            file = new File(MSMUtils.getValue(mapping_element));
     286            directory_mappings_element.removeChild(mapping_element);
     287            found = true;
     288        }
     289        mapping_element = null;
     290        }
     291        mappings = null;
     292        directory_mappings_element = null;
     293        document_element = null;
     294        saved = false;
     295    }
     296    catch(Exception error) {
     297        Gatherer.printStackTrace(error);
     298    }   
     299    return file;
     300    }
     301    /** Save this xml document to the given file. */
     302    public void save() {
     303    Utility.export(document, file);
     304    }
     305    /** Set the value of built to the given value.
     306     * @param value The new value for built, <i>true</i> if the collection has been built successfully, <i>false</i> otherwise.
     307     */
     308    public void setBuilt(boolean value) {
     309    set(BUILT, value);
     310    saved = false;
     311    }
     312    /** Set the value of imported to the given value.
     313     * @param value The new value for imported, <i>true</i> if the collection has been imported successfully, <i>false</i> otherwise.
     314     */
     315    public void setImported(boolean value) {
     316    set(IMPORTED, value);
     317    saved = false;
     318    }
     319    /** Set the value of saved to the given value.
     320     * @param value The new value for saved, <i>true</i> if the collection has been saved recently, <i>false</i> otherwise.
     321     */
     322    public void setSaved(boolean value) {
     323    saved = value;
     324    }
     325    /** Set the value of title to the given value.
     326     * @param title The new <strong>String</strong> title.
     327     */
     328    public void setTitle(String title) {
     329    collect_cfg.setName(title);
     330    }
     331    /** Method called to return a textual representation of a class, which in this case is the collections title.
     332     * @return A <strong>String</strong> containing the collections title.
     333     */
     334    public String toString() {
     335    return collect_cfg.getName();
     336    }
     337    /** Get the value of a collection argument. */
     338    private boolean get(String name) {
     339    boolean result = false;
     340    try {
     341        Element document_element = document.getDocumentElement();
     342        NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
     343        boolean found = false;
     344        for(int i = 0; !found && i < arguments.getLength(); i++) {
     345        Element argument_element = (Element) arguments.item(i);
     346        if(argument_element.getParentNode() == document_element) {
     347            if(argument_element.getAttribute(NAME).equalsIgnoreCase(BUILT)) {
     348            String value = MSMUtils.getValue(argument_element);
     349            if(value.equalsIgnoreCase(TRUE)) {
     350                result = true;
     351            }
     352            found = true;
     353            value = null;
     354            }
     355        }
     356        argument_element = null;
     357        }
     358        arguments = null;
     359        document_element = null;
     360    }
     361    catch (Exception error) {
     362        Gatherer.printStackTrace(error);
     363    }
     364    return result;
     365    }
    366366
    367     /** Method to retrieve the current build options associated with this Collection. */
    368     private Element getBuildValues() {
    369           Element build_values_element = null;
    370           try {
    371                 Element document_element = document.getDocumentElement();
    372                 Element build_config_element = (Element) MSMUtils.getNodeFromNamed(document_element, BUILD_CONFIG);
    373                 build_values_element = (Element) MSMUtils.getNodeFromNamed(build_config_element, BUILD);
    374                 build_config_element = null;
    375                 document_element = null;
    376           }
    377           catch (Exception error) {
    378                 Gatherer.printStackTrace(error);
    379           }
    380           return build_values_element;
    381     }
     367    /** Method to retrieve the current build options associated with this Collection. */
     368    private Element getBuildValues() {
     369    Element build_values_element = null;
     370    try {
     371        Element document_element = document.getDocumentElement();
     372        Element build_config_element = (Element) MSMUtils.getNodeFromNamed(document_element, BUILD_CONFIG);
     373        build_values_element = (Element) MSMUtils.getNodeFromNamed(build_config_element, BUILD);
     374        build_config_element = null;
     375        document_element = null;
     376    }
     377    catch (Exception error) {
     378        Gatherer.printStackTrace(error);
     379    }
     380    return build_values_element;
     381    }
    382382
    383     /** Count either documents or folders, depending on the state of the given boolean. */
    384     private int getCount(TreeNode node, boolean folders) {
    385           int count = 0;
    386           File file = ((FileNode)node).getFile();
    387           if(file.isFile() && !folders) {
    388                 count++;
    389           }
    390           else if(file.isDirectory() && folders) {
    391                 count++;
    392           }
    393           for(int i = 0; i < node.getChildCount(); i++) {
    394                 count = count + getCount(node.getChildAt(i), folders);
    395           }
    396           return count;
    397     }
     383    /** Count either documents or folders, depending on the state of the given boolean. */
     384    private int getCount(TreeNode node, boolean folders) {
     385    int count = 0;
     386    File file = ((FileNode)node).getFile();
     387    if(file.isFile() && !folders) {
     388        count++;
     389    }
     390    else if(file.isDirectory() && folders) {
     391        count++;
     392    }
     393    for(int i = 0; i < node.getChildCount(); i++) {
     394        count = count + getCount(node.getChildAt(i), folders);
     395    }
     396    return count;
     397    }
    398398
    399     /** Method to retrieve the current import options associated with this Collection. */
    400     public Element getImportValues() {
    401           Element import_values_element = null;
    402           try {
    403                 Element document_element = document.getDocumentElement();
    404                 Element build_config_element = (Element) MSMUtils.getNodeFromNamed(document_element, BUILD_CONFIG);
    405                 import_values_element = (Element) MSMUtils.getNodeFromNamed(build_config_element, IMPORT);
    406                 build_config_element = null;
    407                 document_element = null;
    408           }
    409           catch (Exception error) {
    410                 Gatherer.printStackTrace(error);
    411           }
    412           return import_values_element;
    413     }
     399    /** Method to retrieve the current import options associated with this Collection. */
     400    public Element getImportValues() {
     401    Element import_values_element = null;
     402    try {
     403        Element document_element = document.getDocumentElement();
     404        Element build_config_element = (Element) MSMUtils.getNodeFromNamed(document_element, BUILD_CONFIG);
     405        import_values_element = (Element) MSMUtils.getNodeFromNamed(build_config_element, IMPORT);
     406        build_config_element = null;
     407        document_element = null;
     408    }
     409    catch (Exception error) {
     410        Gatherer.printStackTrace(error);
     411    }
     412    return import_values_element;
     413    }
    414414
    415     /** Set the value of a collection argument. */
    416     private void set(String name, boolean value) {
    417           try {
    418                 Element document_element = document.getDocumentElement();
    419                 NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
    420                 boolean found = false;
    421                 for(int i = 0; !found && i < arguments.getLength(); i++) {
    422                      Element argument_element = (Element) arguments.item(i);
    423                      if(argument_element.getParentNode() == document_element) {
    424                           if(argument_element.getAttribute(NAME).equalsIgnoreCase(BUILT)) {
    425                                 // Strip any current value nodes.
    426                                 while(argument_element.hasChildNodes()) {
    427                                     argument_element.removeChild(argument_element.getFirstChild());
    428                                 }
    429                                 // Append new value
    430                                 argument_element.appendChild(document.createTextNode(value ? "true" : "false"));
    431                           }
    432                      }
    433                      argument_element = null;
    434                 }
    435                 arguments = null;
    436                 document_element = null;
    437           }
    438           catch (Exception error) {
    439                 Gatherer.printStackTrace(error);
    440           }
    441     }
     415    /** Set the value of a collection argument. */
     416    private void set(String name, boolean value) {
     417    try {
     418        Element document_element = document.getDocumentElement();
     419        NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
     420        boolean found = false;
     421        for(int i = 0; !found && i < arguments.getLength(); i++) {
     422        Element argument_element = (Element) arguments.item(i);
     423        if(argument_element.getParentNode() == document_element) {
     424            if(argument_element.getAttribute(NAME).equalsIgnoreCase(BUILT)) {
     425            // Strip any current value nodes.
     426            while(argument_element.hasChildNodes()) {
     427                argument_element.removeChild(argument_element.getFirstChild());
     428            }
     429            // Append new value
     430            argument_element.appendChild(document.createTextNode(value ? "true" : "false"));
     431            }
     432        }
     433        argument_element = null;
     434        }
     435        arguments = null;
     436        document_element = null;
     437    }
     438    catch (Exception error) {
     439        Gatherer.printStackTrace(error);
     440    }
     441    }
    442442}
  • trunk/gli/src/org/greenstone/gatherer/collection/CollectionConfiguration.java

    r4293 r4366  
    1010public class CollectionConfiguration {
    1111
    12     private Element creator_element;
    13     private Element description_element;
    14     private Element maintainer_element;
    15     private Element name_element;
    16     private String creator;
    17     private String description;
    18     private String maintainer;
    19     private String name;
     12    private Element creator_element;
     13    private Element description_element;
     14    private Element maintainer_element;
     15    private Element name_element;
     16    private String creator;
     17    private String description;
     18    private String maintainer;
     19    private String name;
    2020
    21     public CollectionConfiguration(File file) {
    22           try {
    23                 String filename = file.getName().toLowerCase();
    24                 if(filename.endsWith(".xml")) {
     21    public CollectionConfiguration(File file) {
     22    try {
     23        String filename = file.getName().toLowerCase();
     24        if(filename.endsWith(".xml")) {
    2525                     
     26        }
     27        else if(filename.endsWith(".cfg")) {
     28        FileReader fr = new FileReader(file);
     29        BufferedReader br = new BufferedReader(fr);
     30        String command = null;
     31        while((command = br.readLine()) != null) {
     32            if(command.length() > 0) {
     33            // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
     34            while(command.trim().endsWith("\\")) {
     35                command = command.substring(0, command.lastIndexOf("\\"));
     36                String next_line = br.readLine();
     37                if(next_line != null) {
     38                command = command + next_line;
     39                }
     40                next_line = null;
     41            }
     42            CommandTokenizer tokenizer = new CommandTokenizer(command);
     43            if(tokenizer.countTokens() >= 2) {
     44                String temp = tokenizer.nextToken();
     45                if(temp.equalsIgnoreCase("creator")) {
     46                creator = tokenizer.nextToken();
     47                }
     48                else if(temp.equalsIgnoreCase("maintainer")) {
     49                maintainer = tokenizer.nextToken();
     50                }
     51                else if(temp.equalsIgnoreCase("collectionmeta")) {
     52                temp = tokenizer.nextToken();
     53                if(temp.equalsIgnoreCase("collectionname")) {
     54                    temp = tokenizer.nextToken();
     55                    if(temp.startsWith("[") && temp.endsWith("]")) {
     56                    String language = temp.substring(temp.indexOf("=") + 1, temp.length() - 1);
     57                    if(name == null || language.equalsIgnoreCase(Gatherer.dictionary.getLanguage())) {
     58                        name = Utility.decodeGreenstone(tokenizer.nextToken());
     59                    }
     60                    }
     61                    else if(name == null) {
     62                    name = Utility.decodeGreenstone(temp);
     63                    }
     64                    if(name != null && name.startsWith("\"") && name.endsWith("\"")) {
     65                    name = name.substring(1, name.length() - 1);
     66                    }
    2667                }
    27                 else if(filename.endsWith(".cfg")) {
    28                      FileReader fr = new FileReader(file);
    29                      BufferedReader br = new BufferedReader(fr);
    30                      String command = null;
    31                      while((command = br.readLine()) != null) {
    32                           if(command.length() > 0) {
    33                                 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
    34                                 while(command.trim().endsWith("\\")) {
    35                                      command = command.substring(0, command.lastIndexOf("\\"));
    36                                      String next_line = br.readLine();
    37                                      if(next_line != null) {
    38                                           command = command + next_line;
    39                                      }
    40                                      next_line = null;
    41                                 }
    42                                 CommandTokenizer tokenizer = new CommandTokenizer(command);
    43                                 if(tokenizer.countTokens() >= 2) {
    44                                      String temp = tokenizer.nextToken();
    45                                      if(temp.equalsIgnoreCase("creator")) {
    46                                           creator = tokenizer.nextToken();
    47                                      }
    48                                      else if(temp.equalsIgnoreCase("maintainer")) {
    49                                           maintainer = tokenizer.nextToken();
    50                                      }
    51                                      else if(temp.equalsIgnoreCase("collectionmeta")) {
    52                                           temp = tokenizer.nextToken();
    53                                           if(temp.equalsIgnoreCase("collectionname")) {
    54                                                 temp = tokenizer.nextToken();
    55                                                 if(temp.startsWith("[") && temp.endsWith("]")) {
    56                                                      String language = temp.substring(temp.indexOf("=") + 1, temp.length() - 1);
    57                                                      if(name == null || language.equalsIgnoreCase(Gatherer.dictionary.getLanguage())) {
    58                                                           name = Utility.decodeGreenstone(tokenizer.nextToken());
    59                                                      }
    60                                                 }
    61                                                 else if(name == null) {
    62                                                      name = Utility.decodeGreenstone(temp);
    63                                                 }
    64                                                 if(name != null && name.startsWith("\"") && name.endsWith("\"")) {
    65                                                      name = name.substring(1, name.length() - 1);
    66                                                 }
    67                                           }
    68                                           else if(temp.equalsIgnoreCase("collectionextra")) {
    69                                                 temp = tokenizer.nextToken();
    70                                                 ///ystem.err.println("Read: " + temp);
    71                                                 if(temp.startsWith("[") && temp.endsWith("]")) {
    72                                                      String language = temp.substring(temp.indexOf("=") + 1, temp.length() - 1);
    73                                                      ///ystem.err.println("Try to match " + language + " to " + Gatherer.dictionary.getLanguage());
    74                                                      if(description == null || language.equalsIgnoreCase(Gatherer.dictionary.getLanguage())) {
    75                                                           description = Utility.decodeGreenstone(tokenizer.nextToken());
    76                                                           ///ystem.err.println("Found language match, or first match: " + description);
    77                                                      }
    78                                                 }
    79                                                 else if(description == null) {
    80                                                      description = Utility.decodeGreenstone(temp);
    81                                                      ///ystem.err.println("Found first match: " + description);
    82                                                 }
    83                                                 if(description != null && description.startsWith("\"") && description.endsWith("\"")) {
    84                                                      description = description.substring(1, description.length() - 1);
    85                                                 }
    86                                           }
    87                                      }
    88                                      temp = null;
    89                                 }
    90                                 tokenizer = null;
    91                           }
    92                      }
    93                      command = null;
    94                      br.close();
    95                      br = null;
    96                      fr.close();
    97                      fr = null;
     68                else if(temp.equalsIgnoreCase("collectionextra")) {
     69                    temp = tokenizer.nextToken();
     70                    ///ystem.err.println("Read: " + temp);
     71                    if(temp.startsWith("[") && temp.endsWith("]")) {
     72                    String language = temp.substring(temp.indexOf("=") + 1, temp.length() - 1);
     73                    ///ystem.err.println("Try to match " + language + " to " + Gatherer.dictionary.getLanguage());
     74                    if(description == null || language.equalsIgnoreCase(Gatherer.dictionary.getLanguage())) {
     75                        description = Utility.decodeGreenstone(tokenizer.nextToken());
     76                        ///ystem.err.println("Found language match, or first match: " + description);
     77                    }
     78                    }
     79                    else if(description == null) {
     80                    description = Utility.decodeGreenstone(temp);
     81                    ///ystem.err.println("Found first match: " + description);
     82                    }
     83                    if(description != null && description.startsWith("\"") && description.endsWith("\"")) {
     84                    description = description.substring(1, description.length() - 1);
     85                    }
    9886                }
     87                }
     88                temp = null;
     89            }
     90            tokenizer = null;
     91            }
     92        }
     93        command = null;
     94        br.close();
     95        br = null;
     96        fr.close();
     97        fr = null;
     98        }
    9999                ///ystem.err.println("Parsed collect.cfg");
    100100                ///ystem.err.println("name        = " + name);
     
    102102                ///ystem.err.println("maintainer  = " + maintainer);
    103103                ///ystem.err.println("description = " + description);
    104           }
    105           catch(Exception error) {
    106                 Gatherer.println("Error in CollectionConfiguration.<init>(): " + error);
    107                 Gatherer.printStackTrace(error);
    108           }
    109     }
     104    }
     105    catch(Exception error) {
     106        Gatherer.println("Error in CollectionConfiguration.<init>(): " + error);
     107        Gatherer.printStackTrace(error);
     108    }
     109    }
    110110
    111     public String getCreator() {
    112           String result = "";
    113           if(creator_element != null) {
    114                 result = MSMUtils.getValue(creator_element);
    115           }
    116           else if(creator != null) {
    117                 result = creator;
    118           }
    119           return result;
    120     }
     111    public String getCreator() {
     112    String result = "";
     113    if(creator_element != null) {
     114        result = MSMUtils.getValue(creator_element);
     115    }
     116    else if(creator != null) {
     117        result = creator;
     118    }
     119    return result;
     120    }
    121121
    122     public String getDescription() {
    123           String result = "";
    124           if(description_element != null) {
    125                 result = MSMUtils.getValue(description_element);
    126           }
    127           else if(description != null) {
    128                 result = description;
    129           }
    130           return result;
    131     }
     122    public String getDescription() {
     123    String result = "";
     124    if(description_element != null) {
     125        result = MSMUtils.getValue(description_element);
     126    }
     127    else if(description != null) {
     128        result = description;
     129    }
     130    return result;
     131    }
    132132
    133     public String getMaintainer() {
    134           String result = "";
    135           if(maintainer_element != null) {
    136                 result = MSMUtils.getValue(maintainer_element);
    137           }
    138           else if(maintainer != null) {
    139                 result = maintainer;
    140           }
    141           return result;
    142     }
     133    public String getMaintainer() {
     134    String result = "";
     135    if(maintainer_element != null) {
     136        result = MSMUtils.getValue(maintainer_element);
     137    }
     138    else if(maintainer != null) {
     139        result = maintainer;
     140    }
     141    return result;
     142    }
    143143
    144     public String getName() {
    145           String result = "Error";
    146           if(name_element != null) {
    147                 result = MSMUtils.getValue(name_element);
    148           }
    149           else if(name != null) {
    150                 result = name;
    151           }
    152           return result;
    153     }
     144    public String getName() {
     145    String result = "Error";
     146    if(name_element != null) {
     147        result = MSMUtils.getValue(name_element);
     148    }
     149    else if(name != null) {
     150        result = name;
     151    }
     152    return result;
     153    }
    154154
    155     public void setName(String name) {
    156           /** @todo */
    157     }
     155    public void setName(String name) {
     156    /** @todo */
     157    }
    158158}
  • trunk/gli/src/org/greenstone/gatherer/collection/CollectionManager.java

    r4351 r4366  
    7676 */
    7777public class CollectionManager
    78     implements GShellListener, MSMListener {
    79     /** A reference to the metadata set manager.
    80       * @deprecated
    81       */
    82     public MetadataSetManager msm;
    83     /** A reference to the undo manager. Although only one instance is shared between all collections, the undo queues are emptied between each. */
    84     public UndoManager undo;
    85     /** Are we currently in the process of building? */
    86     private boolean building = false;
    87     /** Are we currently in the process of importing? */
    88     private boolean importing = false;
    89     /** The collection this manager is managing! */
    90     private Collection collection = null;
    91     /** The collection_model. */
    92     private FileSystemModel collection_model = null;
    93     /** The workspace model. This becomes invalid on a collection change. */
    94     private FileSystemModel workspace_model = null;
    95     /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
    96     private FMTreeModelListener fm_tree_model_listener = null;
    97     /** The monitor resposible for parsing the build process. */
    98     private GShellProgressMonitor build_monitor = null;
    99     /** The monitor resposible for parsing the copy process. */
    100     private GShellProgressMonitor copy_monitor = null;
    101     /** The monitor resposible for parsing the import process. */
    102     private GShellProgressMonitor import_monitor = null;
    103 
    104     private int special_case = -1;
    105     /** The name of the standard lock file. */
    106     static final public String LOCK_FILE = "gatherer.lck";
    107     static final public int NO_SPECIAL_CASE = -1;
    108     static final public int SPECIAL_DLS = 0;
    109     /** Constructor. */
    110     public CollectionManager() {
    111           // Initialisation.
    112           this.building = false;
    113           this.importing = false;
    114           this.collection = null;
    115           this.undo = new UndoManager();
    116     }
    117     /** Add a special directory mapping.
     78    implements GShellListener, MSMListener {
     79    /** A reference to the metadata set manager.
     80     * @deprecated
     81     */
     82    public MetadataSetManager msm;
     83    /** A reference to the undo manager. Although only one instance is shared between all collections, the undo queues are emptied between each. */
     84    public UndoManager undo;
     85    /** Are we currently in the process of building? */
     86    private boolean building = false;
     87    /** Are we currently in the process of importing? */
     88    private boolean importing = false;
     89    /** The collection this manager is managing! */
     90    private Collection collection = null;
     91    /** The collection_model. */
     92    private FileSystemModel collection_model = null;
     93    /** The workspace model. This becomes invalid on a collection change. */
     94    private FileSystemModel workspace_model = null;
     95    /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
     96    private FMTreeModelListener fm_tree_model_listener = null;
     97    /** The monitor resposible for parsing the build process. */
     98    private GShellProgressMonitor build_monitor = null;
     99    /** The monitor resposible for parsing the copy process. */
     100    private GShellProgressMonitor copy_monitor = null;
     101    /** The monitor resposible for parsing the import process. */
     102    private GShellProgressMonitor import_monitor = null;
     103
     104    private int special_case = -1;
     105    /** The name of the standard lock file. */
     106    static final public String LOCK_FILE = "gatherer.lck";
     107    static final public int NO_SPECIAL_CASE = -1;
     108    static final public int SPECIAL_DLS = 0;
     109    /** Constructor. */
     110    public CollectionManager() {
     111    // Initialisation.
     112    this.building = false;
     113    this.importing = false;
     114    this.collection = null;
     115    this.undo = new UndoManager();
     116    }
     117    /** Add a special directory mapping.
    118118      * @param name The name for this directory mapping as a <strong>String</strong>.
    119119      * @param file The directory this mapping maps to as a <strong>File</strong>.
    120120      */
    121     public void addDirectoryMapping(String name, File file) {
    122           if(ready()) {
     121    public void addDirectoryMapping(String name, File file) {
     122    if(ready()) {
    123123                // Update the information stored in the collection
    124                 collection.addDirectoryMapping(name, file);
     124        collection.addDirectoryMapping(name, file);
    125125                // Now update the tree
    126                 FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
    127                 FileNode parent = (FileNode) model.getRoot();
    128                 FileNode target = new FileNode(file, name);
    129                 SynchronizedTreeModelTools.insertNodeInto(model, parent, target);
    130           }
    131     }
    132     /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
     126        FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
     127        FileNode parent = (FileNode) model.getRoot();
     128        FileNode target = new FileNode(file, name);
     129        SynchronizedTreeModelTools.insertNodeInto(model, parent, target);
     130    }
     131    }
     132    /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
    133133      * @see org.greenstone.gatherer.Configuration
    134134      * @see org.greenstone.gatherer.Gatherer
     
    141141      * @see org.greenstone.gatherer.util.Utility
    142142      */
    143     public void buildCollection() {
    144           Gatherer.println("Building collection");
    145           building = true;
    146 
    147           String args[];
    148           if(Utility.isWindows()) {
    149               args = new String[4];
    150                 args[0] = Gatherer.config.perl_path;
    151               args[1] = "-S";
    152               args[2] = Gatherer.config.getScriptPath() + "buildcol.pl";
    153               args[3] = collection.getName();
    154           }
    155           else {
    156               args = new String[2];
    157               args[0] = Gatherer.config.getScriptPath() + "buildcol.pl";
    158               args[1] = collection.getName();
    159           }
    160           args = ArrayTools.add(args, collection.build_options.getBuildValues());
    161           GShell shell = new GShell(args, GShell.BUILD, Message.BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
    162           shell.addGShellListener(Gatherer.g_man.create_pane);
    163           shell.start();
    164     }
    165     /** Used to determine whether the currently active collection has been built.
     143    public void buildCollection() {
     144    Gatherer.println("Building collection");
     145    building = true;
     146
     147    String args[];
     148    if(Utility.isWindows()) {
     149        args = new String[4];
     150        args[0] = Gatherer.config.perl_path;
     151        args[1] = "-S";
     152        args[2] = Gatherer.config.getScriptPath() + "buildcol.pl";
     153        args[3] = collection.getName();
     154    }
     155    else {
     156        args = new String[2];
     157        args[0] = Gatherer.config.getScriptPath() + "buildcol.pl";
     158        args[1] = collection.getName();
     159    }
     160    args = ArrayTools.add(args, collection.build_options.getBuildValues());
     161    GShell shell = new GShell(args, GShell.BUILD, Message.BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
     162    shell.addGShellListener(Gatherer.g_man.create_pane);
     163    shell.start();
     164    }
     165    /** Used to determine whether the currently active collection has been built.
    166166      * @return A boolean indicating the built status of the collection.
    167167      */
    168     public boolean built() {
    169           if(collection != null) {
    170                 return collection.getBuilt();
    171           }
    172           return false;
    173     }
    174     /** Called to close the current collection and remove its lock file.
    175       * @see org.greenstone.gatherer.Gatherer
    176       * @see org.greenstone.gatherer.collection.Collection
    177       * @see org.greenstone.gatherer.util.Utility
    178       */
    179     public void closeCollection() {
    180           // Remove the lock on this file, then remove the collection.
    181           File lock_file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + LOCK_FILE);
    182           lock_file.delete();
    183           collection.msm.destroy();
    184           collection = null;
    185           collection_model = null;
    186           workspace_model = null;
    187           undo.clear();
    188           Gatherer.config.setCollectionConfiguration(null);
    189           Gatherer.g_man.collectionChanged(false);
    190     }
    191 
    192     /** Method that is called whenever something has changed in the configuration of this collection. */
    193     public void configurationChanged() {
    194           if(collection != null) {
    195                 collection.setSaved(false);
    196           }
    197     }
    198 
    199     /** Used to set the current collection to the given collection. Note that this call should -always- be proceeded by a ready call, and if the colection is ready and the saved flag is unset then the user should be prompted to save. Also note that this method creates yet another GShell to run buildcol.pl. */
    200     public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets) {
    201           special_case = NO_SPECIAL_CASE;
    202           try {
     168    public boolean built() {
     169    if(collection != null) {
     170        return collection.getBuilt();
     171    }
     172    return false;
     173    }
     174    /** Called to close the current collection and remove its lock file.
     175      * @see org.greenstone.gatherer.Gatherer
     176      * @see org.greenstone.gatherer.collection.Collection
     177      * @see org.greenstone.gatherer.util.Utility
     178      */
     179    public void closeCollection() {
     180    // Remove the lock on this file, then remove the collection.
     181    File lock_file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + LOCK_FILE);
     182    lock_file.delete();
     183    collection.msm.destroy();
     184    collection = null;
     185    collection_model = null;
     186    workspace_model = null;
     187    undo.clear();
     188    Gatherer.config.setCollectionConfiguration(null);
     189    Gatherer.g_man.collectionChanged(false);
     190    }
     191
     192    /** Method that is called whenever something has changed in the configuration of this collection. */
     193    public void configurationChanged() {
     194    if(collection != null) {
     195        collection.setSaved(false);
     196    }
     197    }
     198
     199    /** Used to set the current collection to the given collection. Note that this call should -always- be proceeded by a ready call, and if the colection is ready and the saved flag is unset then the user should be prompted to save. Also note that this method creates yet another GShell to run buildcol.pl. */
     200    public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets) {
     201    special_case = NO_SPECIAL_CASE;
     202    try {
    203203                // Create a progress monitor.
    204                 ProgressMonitor progress = new ProgressMonitor(Gatherer.g_man, get("Creating_New"), "mkcol.pl", 0, 7);
     204        ProgressMonitor progress = new ProgressMonitor(Gatherer.g_man, get("Creating_New"), "mkcol.pl", 0, 7);
    205205                // Create the new collection.
    206                 makeCollection(description, email, name, title);
    207                 progress.setProgress(1);
     206        makeCollection(description, email, name, title);
     207        progress.setProgress(1);
    208208
    209209                // ACTIVE_DIR/gimport/
    210                 String a_dir = Utility.getCollectionDir(Gatherer.config.gsdl_path) + name + File.separator;
     210        String a_dir = Utility.getCollectionDir(Gatherer.config.gsdl_path) + name + File.separator;
    211211
    212212                // Has to be done before creating greenstone directory metadata manager.
    213                 File gimport_dir_temp = new File(Utility.getImportDir(a_dir)+"temp.dat");
    214                 File gimport_dir = gimport_dir_temp.getParentFile();
    215                 gimport_dir.mkdirs();
    216                 if(progress != null) {
    217                      progress.setNote(get("Gimport_Created"));
    218                 }
     213        File gimport_dir_temp = new File(Utility.getImportDir(a_dir)+"temp.dat");
     214        File gimport_dir = gimport_dir_temp.getParentFile();
     215        gimport_dir.mkdirs();
     216        if(progress != null) {
     217        progress.setNote(get("Gimport_Created"));
     218        }
    219219
    220220                // ACTIVE_DIR/gcache/
    221                 File gcache_dir_temp = new File(Utility.getCacheDir(a_dir)+"temp.dat");
    222                 File gcache_dir = gcache_dir_temp.getParentFile();
    223                 gcache_dir.mkdirs();
    224                 if(progress != null) {
    225                      progress.setNote(get("Gcache_Created"));
    226                 }
     221        File gcache_dir_temp = new File(Utility.getCacheDir(a_dir)+"temp.dat");
     222        File gcache_dir = gcache_dir_temp.getParentFile();
     223        gcache_dir.mkdirs();
     224        if(progress != null) {
     225        progress.setNote(get("Gcache_Created"));
     226        }
    227227
    228228                // ACTIVE_DIR/log/
    229                 File log_dir_temp = new File(Utility.getLogDir(a_dir)+"temp.dat");
    230                 File log_dir = log_dir_temp.getParentFile();
    231                 log_dir.mkdirs();
    232                 if(progress != null) {
    233                     progress.setNote(get("Log_Created"));
    234                 }
     229        File log_dir_temp = new File(Utility.getLogDir(a_dir)+"temp.dat");
     230        File log_dir = log_dir_temp.getParentFile();
     231        log_dir.mkdirs();
     232        if(progress != null) {
     233        progress.setNote(get("Log_Created"));
     234        }
    235235               
    236                 progress.setProgress(2);
     236        progress.setProgress(2);
    237237
    238238                // Now create the collection object around the directory.
    239                 collection = new Collection(new File(a_dir, name + ".col"));
    240                 collection.msm = new MetadataSetManager();
    241                 msm = collection.msm; // Legacy
    242                 collection.msm.load();
     239        collection = new Collection(new File(a_dir, name + ".col"));
     240        collection.msm = new MetadataSetManager();
     241        msm = collection.msm; // Legacy
     242        collection.msm.load();
    243243                // Import default metadata sets if any.
    244                 for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
    245                      MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
    246                      collection.msm.importMDS(metadata_set.getFile(), false);
    247                 }
     244        for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
     245        MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
     246        collection.msm.importMDS(metadata_set.getFile(), false);
     247        }
    248248
    249249                // Before we create the CollectionDesignManager we have to check if we are basing it upon some other collection.
    250                 if(base_collection_directory != null) {
    251                      // If so our first step is to correctly generate an import profile for our collection from this base collection.
    252                      // Try to import any existing metadata sets for this collection. Look in base_collection_directory/metadata and import any metadata sets found.
    253                      File base_metadata = new File(base_collection_directory, Utility.METADATA_DIR);
    254                      if(base_metadata.exists()) {
    255                           File[] possible_metadata_sets = base_metadata.listFiles();
    256                           for(int i = 0; possible_metadata_sets != null && i < possible_metadata_sets.length; i++) {
    257                                 String filename = possible_metadata_sets[i].getName();
    258                                 if(filename.endsWith(".mds")) {
    259                                     ///ystem.err.println("Found a metadata set. Importing: " + possible_metadata_sets[i].getAbsolutePath());
    260                                     collection.msm.importMDS(possible_metadata_sets[i], false);
    261                                 }
    262                           }
    263                      }
    264                      // If no sets were imported, then create a new metadata with this new collections name. Note that if this is one of the 'big five' collections then I already know the importing mappings as well.
    265                      boolean skip_import_phase = false;
    266                      if(collection.msm.getSets().size() == 0) {
    267                           CollectionConfiguration col_con = new CollectionConfiguration(new File(base_collection_directory, Utility.CONFIG_DIR));
    268                           // If the source collection is one of the 'big five' then we know what the metadata set is.
    269                           String collection_name = col_con.getName();
    270                           // Demo collection - part of the DLS
    271                           if(collection_name.equals(Utility.COLLECTION_DEMO) || collection_name.equals(Utility.COLLECTION_DLS)) {
    272                                 special_case = SPECIAL_DLS;
    273                                 String demo_directory = (new File(base_collection_directory.getParentFile(), Utility.COLLECTION_DEMO_DIRECTORY)).getAbsolutePath();
    274                                 String dls_directory = (new File(base_collection_directory.getParentFile(), Utility.COLLECTION_DLS_DIRECTORY)).getAbsolutePath();
    275                                 // Add the dls.mds
    276                                 collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.DLS_MDS), false);
    277                                 // Add the mappings for the dls (even if its not present).
    278                                 collection.msm.profiler.addAction(dls_directory, "AZList", "dls.AZList");
    279                                 collection.msm.profiler.addAction(dls_directory, "Keyword", "dls.Keyword");
    280                                 collection.msm.profiler.addAction(dls_directory, "Language", "dls.Language");
    281                                 collection.msm.profiler.addAction(dls_directory, "Organization", "dls.Organization");
    282                                 collection.msm.profiler.addAction(dls_directory, "Subject", "dls.Subject");
    283                                 collection.msm.profiler.addAction(dls_directory, "Title", "dls.Title");
    284                                 // Add the mappings for the demo dls (even if its not present).
    285                                 collection.msm.profiler.addAction(demo_directory, "AZList", "dls.AZList");
    286                                 collection.msm.profiler.addAction(demo_directory, "Keyword", "dls.Keyword");
    287                                 collection.msm.profiler.addAction(demo_directory, "Language", "dls.Language");
    288                                 collection.msm.profiler.addAction(demo_directory, "Organization", "dls.Organization");
    289                                 collection.msm.profiler.addAction(demo_directory, "Subject", "dls.Subject");
    290                                 collection.msm.profiler.addAction(demo_directory, "Title", "dls.Title");
    291                                 // Skip the import phase
    292                                 skip_import_phase = true;
    293                           }
    294                           // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
    295                           else {
    296                                 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
    297                                 // If cancelled then they really do mean to start a collection with no metadata sets.
    298                                 if(!ncm_prompt.isCancelled()) {
    299                                     ArrayList initial_sets = ncm_prompt.getSets();
    300                                     for(int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
    301                                           MetadataSet metadata_set = (MetadataSet) initial_sets.get(i);
    302                                           collection.msm.importMDS(metadata_set.getFile(), false);
    303                                           metadata_set = null;
    304                                     }
    305                                     initial_sets = null;
    306                                 }
    307                                 ncm_prompt.dispose();
    308                                 ncm_prompt = null;
    309                           }
    310                      }
    311                      // Do a dry metadata import run over the entire base collection, recording profile mappings. We do this by finding the archive files, and then iterating over them using the GreenstoneArchiveParser to retrieve metadata from them. We then process the importing of new metadata elements using the selectElement prompt used in a file action metadata import. However the big change is that we don't actually import any metadata, just create importing profiles.
    312                      File base_archives = new File(base_collection_directory, Utility.ARCHIVE_DIR);
    313                      if(!skip_import_phase && base_archives.exists()) {
    314                           ///ystem.err.println("Found archives directory.");
    315                      }
    316                      // Failing that we do a dummy run over the files in the collection.
    317                      else if(!skip_import_phase) {
    318                           ///ystem.err.println("No archives directory. Searching files for metadata.xml information.");
    319                           // Find the import directory
    320                           File base_import = new File(base_collection_directory, Utility.IMPORT_DIR);
    321                           if(!base_import.exists()) {
    322                                 base_import = new File(base_collection_directory, Utility.OLD_IMPORT_DIR);
    323                           }
    324                           if(base_import.exists()) {
    325                                 searchForMetadata(base_import);
    326                           }
    327                           // And if that fails then we must have been asked by Satan himself to build the very digital collections of hell, because they don't match any goodly greenstone collection I have ever seen, so you can't blame me if I can't import them.
    328                      }
    329                      // Now we update our collect.cfg
    330                      updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_DIR), new File(a_dir, Utility.CONFIG_DIR), description, email, title);
    331                 }
    332 
    333                 collection.cdm = new CollectionDesignManager();
    334                 collection.gdm = new GDMManager();
    335 
    336                 progress.setProgress(3);
     250        if(base_collection_directory != null) {
     251        // If so our first step is to correctly generate an import profile for our collection from this base collection.
     252        // Try to import any existing metadata sets for this collection. Look in base_collection_directory/metadata and import any metadata sets found.
     253        File base_metadata = new File(base_collection_directory, Utility.METADATA_DIR);
     254        if(base_metadata.exists()) {
     255            File[] possible_metadata_sets = base_metadata.listFiles();
     256            for(int i = 0; possible_metadata_sets != null && i < possible_metadata_sets.length; i++) {
     257            String filename = possible_metadata_sets[i].getName();
     258            if(filename.endsWith(".mds")) {
     259                ///ystem.err.println("Found a metadata set. Importing: " + possible_metadata_sets[i].getAbsolutePath());
     260                collection.msm.importMDS(possible_metadata_sets[i], false);
     261            }
     262            }
     263        }
     264        // If no sets were imported, then create a new metadata with this new collections name. Note that if this is one of the 'big five' collections then I already know the importing mappings as well.
     265        boolean skip_import_phase = false;
     266        if(collection.msm.getSets().size() == 0) {
     267            CollectionConfiguration col_con = new CollectionConfiguration(new File(base_collection_directory, Utility.CONFIG_DIR));
     268            // If the source collection is one of the 'big five' then we know what the metadata set is.
     269            String collection_name = col_con.getName();
     270            // Demo collection - part of the DLS
     271            if(collection_name.equals(Utility.COLLECTION_DEMO) || collection_name.equals(Utility.COLLECTION_DLS)) {
     272            special_case = SPECIAL_DLS;
     273            String demo_directory = (new File(base_collection_directory.getParentFile(), Utility.COLLECTION_DEMO_DIRECTORY)).getAbsolutePath();
     274            String dls_directory = (new File(base_collection_directory.getParentFile(), Utility.COLLECTION_DLS_DIRECTORY)).getAbsolutePath();
     275            // Add the dls.mds
     276            collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.DLS_MDS), false);
     277            // Add the mappings for the dls (even if its not present).
     278            collection.msm.profiler.addAction(dls_directory, "AZList", "dls.AZList");
     279            collection.msm.profiler.addAction(dls_directory, "Keyword", "dls.Keyword");
     280            collection.msm.profiler.addAction(dls_directory, "Language", "dls.Language");
     281            collection.msm.profiler.addAction(dls_directory, "Organization", "dls.Organization");
     282            collection.msm.profiler.addAction(dls_directory, "Subject", "dls.Subject");
     283            collection.msm.profiler.addAction(dls_directory, "Title", "dls.Title");
     284            // Add the mappings for the demo dls (even if its not present).
     285            collection.msm.profiler.addAction(demo_directory, "AZList", "dls.AZList");
     286            collection.msm.profiler.addAction(demo_directory, "Keyword", "dls.Keyword");
     287            collection.msm.profiler.addAction(demo_directory, "Language", "dls.Language");
     288            collection.msm.profiler.addAction(demo_directory, "Organization", "dls.Organization");
     289            collection.msm.profiler.addAction(demo_directory, "Subject", "dls.Subject");
     290            collection.msm.profiler.addAction(demo_directory, "Title", "dls.Title");
     291            // Skip the import phase
     292            skip_import_phase = true;
     293            }
     294            // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
     295            else {
     296            NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
     297            // If cancelled then they really do mean to start a collection with no metadata sets.
     298            if(!ncm_prompt.isCancelled()) {
     299                ArrayList initial_sets = ncm_prompt.getSets();
     300                for(int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
     301                MetadataSet metadata_set = (MetadataSet) initial_sets.get(i);
     302                collection.msm.importMDS(metadata_set.getFile(), false);
     303                metadata_set = null;
     304                }
     305                initial_sets = null;
     306            }
     307            ncm_prompt.dispose();
     308            ncm_prompt = null;
     309            }
     310        }
     311        // Do a dry metadata import run over the entire base collection, recording profile mappings. We do this by finding the archive files, and then iterating over them using the GreenstoneArchiveParser to retrieve metadata from them. We then process the importing of new metadata elements using the selectElement prompt used in a file action metadata import. However the big change is that we don't actually import any metadata, just create importing profiles.
     312        File base_archives = new File(base_collection_directory, Utility.ARCHIVE_DIR);
     313        if(!skip_import_phase && base_archives.exists()) {
     314            ///ystem.err.println("Found archives directory.");
     315        }
     316        // Failing that we do a dummy run over the files in the collection.
     317        else if(!skip_import_phase) {
     318            ///ystem.err.println("No archives directory. Searching files for metadata.xml information.");
     319            // Find the import directory
     320            File base_import = new File(base_collection_directory, Utility.IMPORT_DIR);
     321            if(!base_import.exists()) {
     322            base_import = new File(base_collection_directory, Utility.OLD_IMPORT_DIR);
     323            }
     324            if(base_import.exists()) {
     325            searchForMetadata(base_import);
     326            }
     327            // And if that fails then we must have been asked by Satan himself to build the very digital collections of hell, because they don't match any goodly greenstone collection I have ever seen, so you can't blame me if I can't import them.
     328        }
     329        // Now we update our collect.cfg
     330        updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_DIR), new File(a_dir, Utility.CONFIG_DIR), description, email, title);
     331        }
     332
     333        collection.cdm = new CollectionDesignManager();
     334        collection.gdm = new GDMManager();
     335
     336        progress.setProgress(3);
    337337
    338338                // Has to be done after creating metadata set manager.
    339                 File gmeta_dir_temp = new File(getCollectionMetadata()+"temp.dat");
    340                 File gmeta_dir = gmeta_dir_temp.getParentFile();
    341                 gmeta_dir.mkdirs();
    342                 if(progress != null) {
    343                      progress.setNote("GMeta created");
    344                 }
    345                 progress.setProgress(4);
    346 
    347                 progress.setProgress(6);
     339        File gmeta_dir_temp = new File(getCollectionMetadata()+"temp.dat");
     340        File gmeta_dir = gmeta_dir_temp.getParentFile();
     341        gmeta_dir.mkdirs();
     342        if(progress != null) {
     343        progress.setNote("GMeta created");
     344        }
     345        progress.setProgress(4);
     346
     347        progress.setProgress(6);
    348348                // Register ourselves as being interested in what the msm has to say.
    349                 collection.msm.addMSMListener(this);
     349        collection.msm.addMSMListener(this);
    350350                // Create a lock file.
    351                 File lock_file = new File(a_dir, LOCK_FILE);
    352                 FileOutputStream out = new FileOutputStream(lock_file);
    353                 out.write(LOCK_FILE.getBytes());
    354                 out.close();
    355                 out = null;
    356                 progress.setProgress(7);
    357                 String args[] = new String[1];
    358                 args[0] = name;
    359                 progress.setNote(get("Session_Ready", args));
    360                 progress.close();
    361           }
    362           catch (Exception error) {
    363                 Gatherer.printStackTrace(error);
    364           }
    365           // Done.
    366           if(Gatherer.g_man != null) {
    367                 workspace_model = null;
    368                 Gatherer.g_man.collectionChanged(ready());
    369           }
    370     }
    371 
    372     public void createLockFile(File destination) {
    373           try {
    374                 Document default_lockfile = Utility.parse("xml" + File.separator + LOCK_FILE, true);
    375                 String user_name = System.getProperty("user.name");
    376                 Element person_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
    377                 person_element.appendChild(default_lockfile.createTextNode(user_name));
    378                 person_element = null;
    379                 user_name = null;
    380                 String machine_name = Utility.getMachineName();
    381                 Element machine_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
    382                 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
    383                 machine_element = null;
    384                 machine_name = null;
    385                 String date_time = Utility.getDateString();
    386                 Element date_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
    387                 date_element.appendChild(default_lockfile.createTextNode(date_time));
    388                 date_element = null;
    389                 date_time = null;
    390                 Utility.export(default_lockfile, destination);
    391           }
    392           catch (Exception error) {
    393                 Gatherer.printStackTrace(error);
    394           }
    395     }
    396 
    397     /** Method that is called whenever an element within a set is changed or modified. We want to mark the collection so that it needs saving again.
     351        File lock_file = new File(a_dir, LOCK_FILE);
     352        FileOutputStream out = new FileOutputStream(lock_file);
     353        out.write(LOCK_FILE.getBytes());
     354        out.close();
     355        out = null;
     356        progress.setProgress(7);
     357        String args[] = new String[1];
     358        args[0] = name;
     359        progress.setNote(get("Session_Ready", args));
     360        progress.close();
     361    }
     362    catch (Exception error) {
     363        Gatherer.printStackTrace(error);
     364    }
     365    // Done.
     366    if(Gatherer.g_man != null) {
     367        workspace_model = null;
     368        Gatherer.g_man.collectionChanged(ready());
     369    }
     370    }
     371
     372    public void createLockFile(File destination) {
     373    try {
     374        Document default_lockfile = Utility.parse("xml" + File.separator + LOCK_FILE, true);
     375        String user_name = System.getProperty("user.name");
     376        Element person_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
     377        person_element.appendChild(default_lockfile.createTextNode(user_name));
     378        person_element = null;
     379        user_name = null;
     380        String machine_name = Utility.getMachineName();
     381        Element machine_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
     382        machine_element.appendChild(default_lockfile.createTextNode(machine_name));
     383        machine_element = null;
     384        machine_name = null;
     385        String date_time = Utility.getDateString();
     386        Element date_element = (Element) MSMUtils.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
     387        date_element.appendChild(default_lockfile.createTextNode(date_time));
     388        date_element = null;
     389        date_time = null;
     390        Utility.export(default_lockfile, destination);
     391    }
     392    catch (Exception error) {
     393        Gatherer.printStackTrace(error);
     394    }
     395    }
     396
     397    /** Method that is called whenever an element within a set is changed or modified. We want to mark the collection so that it needs saving again.
    398398      * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
    399399      * @see org.greenstone.gatherer.collection.Collection
    400400      */
    401     public void elementChanged(MSMEvent event) {
    402           // This means the state of the collections has changed, so we should set saved to false.
    403           collection.setSaved(false);
    404     }
    405     /** Used to retrieve the build options associated with the currently loaded collection. If none yet exist, default ones are created.
     401    public void elementChanged(MSMEvent event) {
     402    // This means the state of the collections has changed, so we should set saved to false.
     403    collection.setSaved(false);
     404    }
     405    /** Used to retrieve the build options associated with the currently loaded collection. If none yet exist, default ones are created.
    406406      * @return A <strong>BuildOptions</strong> object containing the build options for the current collection.
    407407      * @see org.greenstone.gatherer.collection.Collection
    408408      */
    409     public BuildOptions getBuildOptions() {
    410           return collection.build_options;
    411     }
    412 
    413     /** Retrieve the current collection.
     409    public BuildOptions getBuildOptions() {
     410    return collection.build_options;
     411    }
     412
     413    /** Retrieve the current collection.
    414414      * @return The <strong>Collection</strong> itself.
    415415      */
    416     public Collection getCollection() {
    417           return collection;
    418     }
    419     /** Constructs the absolute filename of the collection archive directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archive/"
     416    public Collection getCollection() {
     417    return collection;
     418    }
     419    /** Constructs the absolute filename of the collection archive directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archive/"
    420420      * @return A <strong>String</strong> containing the filename.
    421421      * @see org.greenstone.gatherer.Configuration
     
    424424      * @see org.greenstone.gatherer.util.Utility
    425425      */
    426     public String getCollectionArchive() {
    427           return Utility.getArchiveDir(Gatherer.config.gsdl_path, collection.getName());
    428     }
    429     /** Constructs the absolute filename of the collection building directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/building/"
     426    public String getCollectionArchive() {
     427    return Utility.getArchiveDir(Gatherer.config.gsdl_path, collection.getName());
     428    }
     429    /** Constructs the absolute filename of the collection building directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/building/"
    430430      * @return A <strong>String</strong> containing the filename.
    431431      * @see org.greenstone.gatherer.Configuration
     
    434434      * @see org.greenstone.gatherer.util.Utility
    435435      */
    436     public String getCollectionBuild() {
    437           return Utility.getBuildDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    438     }
    439     /** Constructs the absolute filename of the collection cache directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/gcache/"
     436    public String getCollectionBuild() {
     437    return Utility.getBuildDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     438    }
     439    /** Constructs the absolute filename of the collection cache directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/gcache/"
    440440      * @return A <strong>String</strong> containing the filename.
    441441      * @see org.greenstone.gatherer.Configuration
     
    444444      * @see org.greenstone.gatherer.util.Utility
    445445      */
    446     public String getCollectionCache() {
    447           return Utility.getCacheDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    448     }
    449     /** Constructs the absolute filename of the collection config file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/collect.cfg"
     446    public String getCollectionCache() {
     447    return Utility.getCacheDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     448    }
     449    /** Constructs the absolute filename of the collection config file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/collect.cfg"
    450450      * @return A <strong>String</strong> containing the filename.
    451451      * @see org.greenstone.gatherer.Configuration
     
    454454      * @see org.greenstone.gatherer.util.Utility
    455455      */
    456     public String getCollectionConfig() {
    457           return Utility.getConfigDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    458     }
    459 
    460     /** Constructs the absolute filename of the collection directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;"
     456    public String getCollectionConfig() {
     457    return Utility.getConfigDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     458    }
     459
     460    /** Constructs the absolute filename of the collection directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;"
    461461      * @return A <strong>String</strong> containing the directory name.
    462462      * @see org.greenstone.gatherer.Configuration
     
    465465      * @see org.greenstone.gatherer.util.Utility
    466466      */
    467     public String getCollectionDirectory() {
    468           return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator;
    469     }
    470 
    471     /** Constructs the absolute filename of the collection etc directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/"
     467    public String getCollectionDirectory() {
     468    return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator;
     469    }
     470
     471    /** Constructs the absolute filename of the collection etc directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/"
    472472      * @return A <strong>String</strong> containing the filename.
    473473      * @see org.greenstone.gatherer.Configuration
     
    476476      * @see org.greenstone.gatherer.util.Utility
    477477      */
    478     public String getCollectionEtc() {
    479           return Utility.getEtcDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    480     }
    481     /** Constructs the absolute filename of the collection file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/&lt;col_name&gt;.col"
     478    public String getCollectionEtc() {
     479    return Utility.getEtcDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     480    }
     481    /** Constructs the absolute filename of the collection file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/&lt;col_name&gt;.col"
    482482      * @return A <strong>String</strong> containing the filename.
    483483      * @see org.greenstone.gatherer.Configuration
     
    486486      * @see org.greenstone.gatherer.util.Utility
    487487      */
    488     public String getCollectionFilename() {
    489           return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + collection.getName() + ".col";
    490     }
    491     /** Constructs the absolute filename of the collection import directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/gimport/"
     488    public String getCollectionFilename() {
     489    return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + collection.getName() + ".col";
     490    }
     491    /** Constructs the absolute filename of the collection import directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/gimport/"
    492492      * @return A <strong>String</strong> containing the filename.
    493493      * @see org.greenstone.gatherer.Configuration
     
    496496      * @see org.greenstone.gatherer.util.Utility
    497497      */
    498     public String getCollectionImport() {
    499           return Utility.getImportDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    500     }
    501     /** Constructs the absolute filename of the collection index directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/index/"
     498    public String getCollectionImport() {
     499    return Utility.getImportDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     500    }
     501    /** Constructs the absolute filename of the collection index directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/index/"
    502502      * @return A <strong>String</strong> containing the filename.
    503503      * @see org.greenstone.gatherer.Configuration
     
    506506      * @see org.greenstone.gatherer.util.Utility
    507507      */
    508     public String getCollectionIndex() {
    509           return Utility.getIndexDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    510     }
    511     /** Constructs the absolute filename of the collection log directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/log/"
     508    public String getCollectionIndex() {
     509    return Utility.getIndexDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     510    }
     511    /** Constructs the absolute filename of the collection log directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/log/"
    512512      * @return A <strong>String</strong> containing the filename.
    513513      * @see org.greenstone.gatherer.Configuration
     
    516516      * @see org.greenstone.gatherer.util.Utility
    517517      */
    518     public String getCollectionLog() {
    519          return Utility.getLogDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    520     }
    521     /** Constructs the absolute filename of the collection metadata directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/metadata/"
     518    public String getCollectionLog() {
     519    return Utility.getLogDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     520    }
     521    /** Constructs the absolute filename of the collection metadata directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/metadata/"
    522522      * @return A <strong>String</strong> containing the filename.
    523523      * @see org.greenstone.gatherer.Configuration
     
    526526      * @see org.greenstone.gatherer.util.Utility
    527527      */
    528     public String getCollectionMetadata() {
    529           return Utility.getMetadataDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    530     }
    531 
    532     public String getCollectionOldImport() {
    533           return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + Utility.OLD_IMPORT_DIR;
    534     }
    535 
    536     /** This method either returns the title of the current collection, or a placeholder string of 'No Collection'.
     528    public String getCollectionMetadata() {
     529    return Utility.getMetadataDir(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     530    }
     531
     532    public String getCollectionOldImport() {
     533    return Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator + Utility.OLD_IMPORT_DIR;
     534    }
     535
     536    /** This method either returns the title of the current collection, or a placeholder string of 'No Collection'.
    537537      * @return A <strong>String</strong> which represents what we wish to display for a collection title.
    538538      * @see org.greenstone.gatherer.collection.Collection
    539539      */
    540     public String getCollectionTitle() {
    541           if(collection != null) {
    542                 return collection.getTitle();
    543           }
    544           return get("Collection.No_Collection");
    545     }
    546 
    547     /** Retrieve the record set (tree model) associated with the current collection. */
    548     public TreeModel getRecordSet() {
    549           if(collection_model == null && collection != null) {
     540    public String getCollectionTitle() {
     541    if(collection != null) {
     542        return collection.getTitle();
     543    }
     544    return get("Collection.No_Collection");
     545    }
     546
     547    /** Retrieve the record set (tree model) associated with the current collection. */
     548    public TreeModel getRecordSet() {
     549    if(collection_model == null && collection != null) {
    550550                // Check if the gimport directory exists, and if so use it.
    551                 File gimport_directory = new File(getCollectionImport());
    552                 if(gimport_directory.exists()) {
    553                      // Generate a new FileSystemModel based on the collection gimport directory.
    554                      collection_model = new FileSystemModel(new FileNode(gimport_directory, false));
    555                 }
    556                 else {
    557                      ///ystem.err.println("No gimport directory exists.");
    558                      // Otherwise default to the import directory. If it doesn't exist, there aint much more I can do.
    559                      // Generate a new FileSystemModel based on the collection import directory.
    560                      collection_model = new FileSystemModel(new FileNode(new File(getCollectionOldImport()), false));
    561                 }
     551        File gimport_directory = new File(getCollectionImport());
     552        if(gimport_directory.exists()) {
     553        // Generate a new FileSystemModel based on the collection gimport directory.
     554        collection_model = new FileSystemModel(new FileNode(gimport_directory, false));
     555        }
     556        else {
     557        ///ystem.err.println("No gimport directory exists.");
     558        // Otherwise default to the import directory. If it doesn't exist, there aint much more I can do.
     559        // Generate a new FileSystemModel based on the collection import directory.
     560        collection_model = new FileSystemModel(new FileNode(new File(getCollectionOldImport()), false));
     561        }
    562562                // Ensure that the manager is a change listener for the tree.
    563                 if(fm_tree_model_listener == null) {
    564                      fm_tree_model_listener = new FMTreeModelListener();
    565                 }
    566                 collection_model.addTreeModelListener(fm_tree_model_listener);
    567           }
    568           return collection_model;
    569     }
    570     /** Create and return the model behind the workspace tree. Quite an extensive method, as it must first map known greenstone collections, then the local file system and finally any public or private download workspaces. */
    571     public TreeModel getWorkspace() {
    572           if(workspace_model != null) {
    573                 return workspace_model;
    574           }
    575           // Create the workspace tree.
    576           FileNode workspace_root = new FileNode("ABS_ROOT");
    577           workspace_model = new FileSystemModel(workspace_root);
    578           // Create and add Greenstone collections node.
    579           // Starting at the collection directory of gsdl...
    580           File start = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
    581           FileNode world_root = new FileNode(get("Tree.World"));
    582           workspace_root.insert(world_root);
    583           // For each of the children directories, which are collections...
    584           File cols[] = start.listFiles();
    585           ArrayTools.sort(cols);
    586           // We add their import and gimport directories, but only if its not our current collection.
    587           for(int i = 0; cols != null && i < cols.length; i++) {
    588                 if(collection == null || !(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName()).equals(cols[i].getAbsolutePath())) {
    589                      File dirs[] = cols[i].listFiles();
    590                      ArrayTools.sort(dirs);
    591                      File import_dir = new File(cols[i], "gimport");
    592                      if(!import_dir.exists()) {
    593                           import_dir = new File(cols[i], "import");
    594                      }
    595                      if(import_dir.exists()) {
    596                           FileNode collection_root = new FileNode(import_dir, cols[i].getName(), true);
    597                           world_root.insert(collection_root);
    598                           collection_root = null;
    599                      }
    600                      import_dir = null;
    601                 }
    602           }
    603           // Create Local File space.
    604           // Get all the available roots mounted on the system.
    605           File roots[] = File.listRoots();
    606           // If there is just one root use it as the tree root (linux)
    607           if(roots != null) {
    608                 FileNode file_root;
    609                 String name = get("Tree.Root");
    610                 if(roots.length == 1) {
    611                      file_root = new FileNode(roots[0], name);
    612                      workspace_root.insert(file_root);
    613                 }
     563        if(fm_tree_model_listener == null) {
     564        fm_tree_model_listener = new FMTreeModelListener();
     565        }
     566        collection_model.addTreeModelListener(fm_tree_model_listener);
     567    }
     568    return collection_model;
     569    }
     570    /** Create and return the model behind the workspace tree. Quite an extensive method, as it must first map known greenstone collections, then the local file system and finally any public or private download workspaces. */
     571    public TreeModel getWorkspace() {
     572    if(workspace_model != null) {
     573        return workspace_model;
     574    }
     575    // Create the workspace tree.
     576    FileNode workspace_root = new FileNode("ABS_ROOT");
     577    workspace_model = new FileSystemModel(workspace_root);
     578    // Create and add Greenstone collections node.
     579    // Starting at the collection directory of gsdl...
     580    File start = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
     581    FileNode world_root = new FileNode(get("Tree.World"));
     582    workspace_root.insert(world_root);
     583    // For each of the children directories, which are collections...
     584    File cols[] = start.listFiles();
     585    ArrayTools.sort(cols);
     586    // We add their import and gimport directories, but only if its not our current collection.
     587    for(int i = 0; cols != null && i < cols.length; i++) {
     588        if(collection == null || !(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName()).equals(cols[i].getAbsolutePath())) {
     589        File dirs[] = cols[i].listFiles();
     590        ArrayTools.sort(dirs);
     591        File import_dir = new File(cols[i], "gimport");
     592        if(!import_dir.exists()) {
     593            import_dir = new File(cols[i], "import");
     594        }
     595        if(import_dir.exists()) {
     596            FileNode collection_root = new FileNode(import_dir, cols[i].getName(), true);
     597            world_root.insert(collection_root);
     598            collection_root = null;
     599        }
     600        import_dir = null;
     601        }
     602    }
     603    // Create Local File space.
     604    // Get all the available roots mounted on the system.
     605    File roots[] = File.listRoots();
     606    // If there is just one root use it as the tree root (linux)
     607    if(roots != null) {
     608        FileNode file_root;
     609        String name = get("Tree.Root");
     610        if(roots.length == 1) {
     611        file_root = new FileNode(roots[0], name);
     612        workspace_root.insert(file_root);
     613        }
    614614                // Otherwise build a dummy node which has these nodes as
    615615                // children.
    616                 else {
    617                      file_root = new FileNode(name);
    618                      workspace_root.insert(file_root);
    619                      // Hopefully this does an alphabetic sort.
    620                      ArrayTools.sort(roots);
    621                      for(int i = 0; i < roots.length; i++) {
    622                           FileNode child_root = new FileNode(roots[i]);
    623                           file_root.insert(child_root);
    624                           child_root = null;
    625                      }
    626                 }
    627                 name = null;
    628                 file_root = null;
    629           }
    630           // If mirroring is enabled show the public and private caches.
    631           if(Gatherer.config.get("workflow.mirror", false)) {
     616        else {
     617        file_root = new FileNode(name);
     618        workspace_root.insert(file_root);
     619        // Hopefully this does an alphabetic sort.
     620        ArrayTools.sort(roots);
     621        for(int i = 0; i < roots.length; i++) {
     622            FileNode child_root = new FileNode(roots[i]);
     623            file_root.insert(child_root);
     624            child_root = null;
     625        }
     626        }
     627        name = null;
     628        file_root = null;
     629    }
     630    // If mirroring is enabled show the public and private caches.
     631    if(Gatherer.config.get("workflow.mirror", false)) {
    632632                // Add Public workspace
    633                 FileNode public_root = new FileNode(new File(Utility.CACHE_DIR), get("Tree.Public"));
    634                 workspace_root.insert(public_root);
     633        FileNode public_root = new FileNode(new File(Utility.CACHE_DIR), get("Tree.Public"));
     634        workspace_root.insert(public_root);
    635635                // Add Private workspace if a collection has been loaded.
    636                 if(ready()) {
    637                      FileNode private_root = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
    638                      workspace_root.insert(private_root);
    639                 }
    640           }
    641           // Finally we retrieve and map any predefined special directories.
    642           if(ready()) {
    643                 HashMap mappings = collection.getDirectoryMappings();
    644                 for(Iterator names = mappings.keySet().iterator(); names.hasNext(); ) {
    645                      String name = (String) names.next();
    646                      File file = (File) mappings.get(name);
    647                      FileNode special_root = new FileNode(file, name);
    648                      //workspace_root.insert(special_root);
    649                      SynchronizedTreeModelTools.insertNodeInto(workspace_model, workspace_root, special_root);
    650                 }
    651           }
    652           return workspace_model;
    653     }
    654     /** This method when called, creates a new GShell in order to run the import.pl script.
     636        if(ready()) {
     637        FileNode private_root = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
     638        workspace_root.insert(private_root);
     639        }
     640    }
     641    // Finally we retrieve and map any predefined special directories.
     642    if(ready()) {
     643        HashMap mappings = collection.getDirectoryMappings();
     644        for(Iterator names = mappings.keySet().iterator(); names.hasNext(); ) {
     645        String name = (String) names.next();
     646        File file = (File) mappings.get(name);
     647        FileNode special_root = new FileNode(file, name);
     648        //workspace_root.insert(special_root);
     649        SynchronizedTreeModelTools.insertNodeInto(workspace_model, workspace_root, special_root);
     650        }
     651    }
     652    return workspace_model;
     653    }
     654    /** This method when called, creates a new GShell in order to run the import.pl script.
    655655      * @see org.greenstone.gatherer.Configuration
    656656      * @see org.greenstone.gatherer.Gatherer
     
    662662      * @see org.greenstone.gatherer.util.Utility
    663663      */
    664     public void importCollection() {
    665           if(!saved()) {
     664    public void importCollection() {
     665    if(!saved()) {
    666666                // Force save.
    667                 try {
    668                      SaveCollectionTask save_task = new SaveCollectionTask(collection);
    669                      save_task.setImportAfter(true);
    670                      save_task.start();
    671                 }
    672                 catch(Exception error) {
    673                      Gatherer.printStackTrace(error);
    674                 }
    675           }
    676           else {
    677                 importing = true;
    678                 String args[];
    679                 if(Utility.isWindows()) {
    680                      args = new String[6];
    681                      args[0] = Gatherer.config.perl_path;
    682                      args[1] = "-S";
    683                      args[2] = Gatherer.config.getScriptPath() + "import.pl";
    684                      args[3] = "-importdir";
    685                      args[4] = getCollectionImport();
    686                      args[5] = collection.getName();
    687                 }
    688                 else {
    689                      args = new String[4];
    690                      args[0] = Gatherer.config.getScriptPath() + "import.pl";
    691                      args[1] = "-importdir";
    692                      args[2] = getCollectionImport();
    693                      args[3] = collection.getName();
    694                 }
    695                 args = ArrayTools.add(args, collection.build_options.getImportValues());
    696                 GShell shell = new GShell(args, GShell.IMPORT, Message.BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
    697                 shell.addGShellListener(Gatherer.g_man.create_pane);
    698                 shell.start();
    699           }
    700     }
    701     /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
     667        try {
     668        SaveCollectionTask save_task = new SaveCollectionTask(collection);
     669        save_task.setImportAfter(true);
     670        save_task.start();
     671        }
     672        catch(Exception error) {
     673        Gatherer.printStackTrace(error);
     674        }
     675    }
     676    else {
     677        importing = true;
     678        String args[];
     679        if(Utility.isWindows()) {
     680        args = new String[6];
     681        args[0] = Gatherer.config.perl_path;
     682        args[1] = "-S";
     683        args[2] = Gatherer.config.getScriptPath() + "import.pl";
     684        args[3] = "-importdir";
     685        args[4] = getCollectionImport();
     686        args[5] = collection.getName();
     687        }
     688        else {
     689        args = new String[4];
     690        args[0] = Gatherer.config.getScriptPath() + "import.pl";
     691        args[1] = "-importdir";
     692        args[2] = getCollectionImport();
     693        args[3] = collection.getName();
     694        }
     695        args = ArrayTools.add(args, collection.build_options.getImportValues());
     696        GShell shell = new GShell(args, GShell.IMPORT, Message.BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
     697        shell.addGShellListener(Gatherer.g_man.create_pane);
     698        shell.start();
     699    }
     700    }
     701    /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
    702702      * @param location The path to the collection as a <strong>String</strong>.
    703703      * @see org.greenstone.gatherer.Configuration
     
    709709      * @see org.greenstone.gatherer.util.Utility
    710710      */
    711     public boolean loadCollection(String location) {
    712           ///ystem.err.println("Load Collection '" + location + "'");
    713           String[] args2 = new String[1];
    714           args2[0] = location;
    715           boolean result = false;
    716           // Check we have actually been given a .col file.
    717           if(location.endsWith(".col")) {
    718                 File collection_file = new File(location);
     711    public boolean loadCollection(String location) {
     712    ///ystem.err.println("Load Collection '" + location + "'");
     713    String[] args2 = new String[1];
     714    args2[0] = location;
     715    boolean result = false;
     716    // Check we have actually been given a .col file.
     717    if(location.endsWith(".col")) {
     718        File collection_file = new File(location);
    719719                // Ensure that the directory exists.
    720                 File collection_directory = collection_file.getParentFile();
    721                 if(collection_directory.exists()) {
    722                      String name = collection_directory.getName();
    723                      File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
    724                      // Now determine if a lock already exists on this collection.
    725                      int choice = LockFileDialog.YES_OPTION;
    726                      if(lock_file.exists()) {
    727                           LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
    728                           choice = dialog.getChoice();
    729                      }
    730                      if(choice == LockFileDialog.YES_OPTION) {
    731                           try {
    732                                 if(lock_file.exists()) {
    733                                     lock_file.delete();
    734                                 }
    735                                 // Create a lock file.
    736                                 createLockFile(lock_file);
    737                                 // Open the collection file
    738                                 collection = new Collection(collection_file);
    739                                 collection.msm = new MetadataSetManager();
    740                                 msm = collection.msm; // Legacy
    741                                 collection.msm.load();
    742                                 collection.cdm = new CollectionDesignManager();
    743                                 collection.gdm = new GDMManager();
    744                                 // Tell everyone that it worked.
    745                                 Gatherer.println(get("Loading_Successful", name));
    746                                 // Now we need to hook up classes that depend on messages from the metadata set manager to keep their content fresh.
    747                                 collection.msm.addMSMListener(this);
    748                                 // We're done. Let everyone know.
    749                                 if(Gatherer.g_man != null) {
    750                                     workspace_model = null;
    751                                     Gatherer.g_man.collectionChanged(ready());
    752                                 }
    753                                 result = true;
    754                           } catch (Exception error) {
    755                                 // There is obviously no existing collection present.
    756                                 Gatherer.printStackTrace(error);
    757                                 JOptionPane.showMessageDialog(Gatherer.g_man, get("Cannot_Open", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
    758                           }
    759                      }
    760                      lock_file = null;
    761                 }
    762                 else {
    763                      JOptionPane.showMessageDialog(Gatherer.g_man, get("CollectionManager.File_Not_Found", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
    764                 }
    765                 collection_directory = null;
    766           }
    767           else {
    768                 JOptionPane.showMessageDialog(Gatherer.g_man, get("Not_Col_File", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
    769                 Gatherer.println("Not a Gatherer Collection.");
    770           }
    771           args2 = null;
    772           return result;
    773     }
    774 
    775     public void makeCollection(String description, String email, String name, String title) {
    776           // Run the mkcol command.
    777           String command[];
    778           if(Utility.isWindows()) {
    779                 if(description == null || email == null || title == null) {
    780                      command = new String[4];
    781                 }
    782                 else {
    783                      command = new String[10];
    784                 }
    785                 command[0] = Gatherer.config.perl_path;
    786                 command[1] = "-S";
    787                 command[2] = Gatherer.config.getScriptPath() + "mkcol.pl";
    788                 if(description == null || email == null || title == null) {
    789                      command[3] = name;
    790                 }
    791                 else {
    792                      command[3] = "-title";
    793                      command[4] = title;
    794                      command[5] = "-creator";
    795                      command[6] = email;
    796                      command[7] = "-about";
    797                      command[8] = description;
    798                      command[9] = name;
    799                 }
    800           }
    801           else {
    802                 if(description == null || email == null || title == null) {
    803                      command = new String[2];
    804                      command[0] = "mkcol.pl";
    805                      command[1] = name;
    806                 }
    807                 else {
    808                      command = new String[8];
    809                      command[0] = "mkcol.pl";
    810                      command[1] = "-title";
    811                      command[2] = title;
    812                      command[3] = "-creator";
    813                      command[4] = email;
    814                      command[5] = "-about";
    815                      command[6] = description;
    816                      command[7] = name;
    817                 }
    818           }
    819           GShell process = new GShell(command, GShell.NEW, Message.COLLECT, this, null, GShell.GSHELL_NEW);
    820           process.addGShellListener(this);
    821           process.run(); // Don't bother threading this... yet
    822     }
    823 
    824     /** Any implementation of GShellListener must include this method to allow the GShell to send messages to listeners. However in this case the CollectionManager is in no way interested in what the messages are, just the import events which have a specific type and are handled elsewhere. Thus we can safely ignore this event.
     720        File collection_directory = collection_file.getParentFile();
     721        if(collection_directory.exists()) {
     722        String name = collection_directory.getName();
     723        File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
     724        // Now determine if a lock already exists on this collection.
     725        int choice = LockFileDialog.YES_OPTION;
     726        if(lock_file.exists()) {
     727            LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
     728            choice = dialog.getChoice();
     729        }
     730        if(choice == LockFileDialog.YES_OPTION) {
     731            try {
     732            if(lock_file.exists()) {
     733                lock_file.delete();
     734            }
     735            // Create a lock file.
     736            createLockFile(lock_file);
     737            // Open the collection file
     738            collection = new Collection(collection_file);
     739            collection.msm = new MetadataSetManager();
     740            msm = collection.msm; // Legacy
     741            collection.msm.load();
     742            collection.cdm = new CollectionDesignManager();
     743            collection.gdm = new GDMManager();
     744            // Tell everyone that it worked.
     745            Gatherer.println(get("Loading_Successful", name));
     746            // Now we need to hook up classes that depend on messages from the metadata set manager to keep their content fresh.
     747            collection.msm.addMSMListener(this);
     748            // We're done. Let everyone know.
     749            if(Gatherer.g_man != null) {
     750                workspace_model = null;
     751                Gatherer.g_man.collectionChanged(ready());
     752            }
     753            result = true;
     754            } catch (Exception error) {
     755            // There is obviously no existing collection present.
     756            Gatherer.printStackTrace(error);
     757            JOptionPane.showMessageDialog(Gatherer.g_man, get("Cannot_Open", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
     758            }
     759        }
     760        lock_file = null;
     761        }
     762        else {
     763        JOptionPane.showMessageDialog(Gatherer.g_man, get("CollectionManager.File_Not_Found", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
     764        }
     765        collection_directory = null;
     766    }
     767    else {
     768        JOptionPane.showMessageDialog(Gatherer.g_man, get("Not_Col_File", args2), get("General.Error"), JOptionPane.ERROR_MESSAGE);
     769        Gatherer.println("Not a Gatherer Collection.");
     770    }
     771    args2 = null;
     772    return result;
     773    }
     774
     775    public void makeCollection(String description, String email, String name, String title) {
     776    // Run the mkcol command.
     777    String command[];
     778    if(Utility.isWindows()) {
     779        if(description == null || email == null || title == null) {
     780        command = new String[4];
     781        }
     782        else {
     783        command = new String[10];
     784        }
     785        command[0] = Gatherer.config.perl_path;
     786        command[1] = "-S";
     787        command[2] = Gatherer.config.getScriptPath() + "mkcol.pl";
     788        if(description == null || email == null || title == null) {
     789        command[3] = name;
     790        }
     791        else {
     792        command[3] = "-title";
     793        command[4] = title;
     794        command[5] = "-creator";
     795        command[6] = email;
     796        command[7] = "-about";
     797        command[8] = description;
     798        command[9] = name;
     799        }
     800    }
     801    else {
     802        if(description == null || email == null || title == null) {
     803        command = new String[2];
     804        command[0] = "mkcol.pl";
     805        command[1] = name;
     806        }
     807        else {
     808        command = new String[8];
     809        command[0] = "mkcol.pl";
     810        command[1] = "-title";
     811        command[2] = title;
     812        command[3] = "-creator";
     813        command[4] = email;
     814        command[5] = "-about";
     815        command[6] = description;
     816        command[7] = name;
     817        }
     818    }
     819    GShell process = new GShell(command, GShell.NEW, Message.COLLECT, this, null, GShell.GSHELL_NEW);
     820    process.addGShellListener(this);
     821    process.run(); // Don't bother threading this... yet
     822    }
     823
     824    /** Any implementation of GShellListener must include this method to allow the GShell to send messages to listeners. However in this case the CollectionManager is in no way interested in what the messages are, just the import events which have a specific type and are handled elsewhere. Thus we can safely ignore this event.
    825825      * @param event A <strong>GShellEvent</strong> which contains a the message.
    826826      */
    827     public synchronized void message(GShellEvent event) {
    828     }
    829     /** Called whenever the metadata value changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
     827    public synchronized void message(GShellEvent event) {
     828    }
     829    /** Called whenever the metadata value changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
    830830      * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
    831831      * @see org.greenstone.gatherer.collection.Collection
    832832      */
    833     public void metadataChanged(MSMEvent event) {
    834           // Again this change means we need to save the collection again.
    835           collection.setSaved(false);
    836     }
    837     /** This call is fired whenever a process within a GShell created by this class begins.
     833    public void metadataChanged(MSMEvent event) {
     834    // Again this change means we need to save the collection again.
     835    collection.setSaved(false);
     836    }
     837    /** This call is fired whenever a process within a GShell created by this class begins.
    838838      * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
    839839      * @see org.greenstone.gatherer.Gatherer
     
    841841      * @see org.greenstone.gatherer.shell.GShell
    842842      */
    843     public synchronized void processBegun(GShellEvent event) {
    844           ///ystem.err.println("ProcessBegun " + event.getType());
    845           // If this is one of the types where we wish to lock user control
    846           Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
    847     }
    848     /** This call is fired whenever a process within a GShell created by this class ends.
     843    public synchronized void processBegun(GShellEvent event) {
     844    ///ystem.err.println("ProcessBegun " + event.getType());
     845    // If this is one of the types where we wish to lock user control
     846    Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
     847    }
     848    /** This call is fired whenever a process within a GShell created by this class ends.
    849849      * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
    850850      * @see org.greenstone.gatherer.Gatherer
     
    852852      * @see org.greenstone.gatherer.shell.GShell
    853853      */
    854     public synchronized void processComplete(GShellEvent event) {
    855           ///ystem.err.println("ProcessComplete " + event.getType());
    856           Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
    857           ///ystem.err.println("Recieved process complete event - " + event);
    858           // If we were running an import, now run a build.
    859           if(event.getType() == GShell.IMPORT && event.getStatus() != GShell.ERROR) {
     854    public synchronized void processComplete(GShellEvent event) {
     855    ///ystem.err.println("ProcessComplete " + event.getType());
     856    Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
     857    ///ystem.err.println("Recieved process complete event - " + event);
     858    // If we were running an import, now run a build.
     859    if(event.getType() == GShell.IMPORT && event.getStatus() != GShell.ERROR) {
    860860                // Finish import.
    861                 collection.setImported(true);
    862                 buildCollection();
    863           }
    864           // If we were running a build, now is when we move files across.
    865           else if(event.getType() == GShell.BUILD && event.getStatus() != GShell.ERROR) {
     861        collection.setImported(true);
     862        buildCollection();
     863    }
     864    // If we were running a build, now is when we move files across.
     865    else if(event.getType() == GShell.BUILD && event.getStatus() != GShell.ERROR) {
    866866                ///ystem.err.println("Installing collection.");
    867                 installCollection();
    868                 collection.setBuilt(true);
     867        installCollection();
     868        collection.setBuilt(true);
    869869                // If we have a local library running (that we know about) then we ask it to add our newly create collection
    870870                ///ystem.err.println("Check if we should reset local server.");
    871                 if(Gatherer.config.exec_file != null) {
    872                      ///ystem.err.println("Local Library Found!");
    873                     Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.ADD_COMMAND + collection.getName());
    874                 }
     871        if(Gatherer.config.exec_file != null) {
     872        ///ystem.err.println("Local Library Found!");
     873        Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.ADD_COMMAND + collection.getName());
     874        }
    875875                //else {
    876876                ///ystem.err.println("GLI can't recognize a local library.");
    877877                //}
    878878                // Signal collection changed.
    879                 workspace_model = null;
    880                 Gatherer.g_man.collectionChanged(ready());
    881                 JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready"), get("Preview_Ready_Title"), JOptionPane.INFORMATION_MESSAGE);
    882           }
    883           else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.ERROR) {
    884                 JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready_Failed"), get("Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
    885           }
    886     }
    887     /** Determine if the manager is ready for actions apon its collection.
     879        workspace_model = null;
     880        Gatherer.g_man.collectionChanged(ready());
     881        JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready"), get("Preview_Ready_Title"), JOptionPane.INFORMATION_MESSAGE);
     882    }
     883    else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.ERROR) {
     884        JOptionPane.showMessageDialog(Gatherer.g_man, get("Preview_Ready_Failed"), get("Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
     885    }
     886    }
     887    /** Determine if the manager is ready for actions apon its collection.
    888888      * @return A <i>boolean</i> which is <i>true</i> to indicate a collection has been loaded and thus the collection is ready for editing, <i>false</i> otherwise.
    889889      */
    890     public boolean ready() {
    891           if(collection != null) {
    892                 return true;
    893           }
    894           return false;
    895     }
    896     /** Called to refresh the models upon which the trees are based.
    897       * @see org.greenstone.gatherer.collection.Collection
    898       */
    899     public void refreshTrees() {
    900     }
    901     /** This method associates the collection build monitor with the build monitor created in CreatePane.
     890    public boolean ready() {
     891    if(collection != null) {
     892        return true;
     893    }
     894    return false;
     895    }
     896    /** Called to refresh the models upon which the trees are based.
     897      * @see org.greenstone.gatherer.collection.Collection
     898      */
     899    public void refreshTrees() {
     900    }
     901    /** This method associates the collection build monitor with the build monitor created in CreatePane.
    902902      * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
    903903      */
    904     public void registerBuildMonitor(GShellProgressMonitor monitor) {
    905           build_monitor = monitor;
    906     }
    907     /** This method associates the collection copy monitor with the copy monitor created in CreatePane.
     904    public void registerBuildMonitor(GShellProgressMonitor monitor) {
     905    build_monitor = monitor;
     906    }
     907    /** This method associates the collection copy monitor with the copy monitor created in CreatePane.
    908908      * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the copy monitor.
    909909      */
    910     public void registerCopyMonitor(GShellProgressMonitor monitor) {
    911           copy_monitor = monitor;
    912     }
    913     /** This method associates the collection import monitor with the import monitor created in CreatePane.
     910    public void registerCopyMonitor(GShellProgressMonitor monitor) {
     911    copy_monitor = monitor;
     912    }
     913    /** This method associates the collection import monitor with the import monitor created in CreatePane.
    914914      * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
    915915      */
    916     public void registerImportMonitor(GShellProgressMonitor monitor) {
    917           import_monitor = monitor;
    918     }
    919     /** Remove a previously assigned special directory mapping.
     916    public void registerImportMonitor(GShellProgressMonitor monitor) {
     917    import_monitor = monitor;
     918    }
     919    /** Remove a previously assigned special directory mapping.
    920920      * @param name The symbolic name of the special directory mapping to remove as a <strong>String</strong>.
    921921      * @return The <strong>File</strong> of the mapping removed.
    922922      */
    923     public File removeDirectoryMapping(FileNode target) {
    924           File file = null;
    925           if(ready()) {
     923    public File removeDirectoryMapping(FileNode target) {
     924    File file = null;
     925    if(ready()) {
    926926                // Remove from collection, remembering file
    927                 file = collection.removeDirectoryMapping(target.toString());
     927        file = collection.removeDirectoryMapping(target.toString());
    928928                // Update tree.
    929                 FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
    930                 SynchronizedTreeModelTools.removeNodeFromParent(model, target);
    931           }
    932           return file;
    933     }
    934     /** Used to check whether all open collections have a 'saved' state.
     929        FileSystemModel model = (FileSystemModel) Gatherer.g_man.collection_pane.getWorkspaceTree().getModel();
     930        SynchronizedTreeModelTools.removeNodeFromParent(model, target);
     931    }
     932    return file;
     933    }
     934    /** Used to check whether all open collections have a 'saved' state.
    935935      * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
    936936      * @see org.greenstone.gatherer.collection.Collection
    937937      */
    938     public boolean saved() {
    939           boolean result = true;
    940           if(collection != null) {
    941                 result = collection.getSaved();
    942           }
    943           return result;
    944     }
    945     /** Saves a collection by serializing it to file.
     938    public boolean saved() {
     939    boolean result = true;
     940    if(collection != null) {
     941        result = collection.getSaved();
     942    }
     943    return result;
     944    }
     945    /** Saves a collection by serializing it to file.
    946946      * @param close_after <i>true</i> to cause the Gatherer to close the collection once save is complete, <i>false</i> otherwise.
    947947      * @param exit_after <i>true</i> to cause the Gatherer to exit once save is complete, <i>false</i> otherwise.
     
    952952      * @see org.greenstone.gatherer.collection.Collection
    953953      */
    954     public void saveCollection(boolean close_after, boolean exit_after) {
    955           try {
    956                 SaveCollectionTask save_task = new SaveCollectionTask(collection, close_after, exit_after);
    957                 save_task.start();
    958           }
    959           catch(Exception error) {
    960                 Gatherer.printStackTrace(error);
    961           }
    962     }
    963     /** Saves the current collection to a new filename, then restores the original collection. Finally opens the collection copy.
     954    public void saveCollection(boolean close_after, boolean exit_after) {
     955    try {
     956        SaveCollectionTask save_task = new SaveCollectionTask(collection, close_after, exit_after);
     957        save_task.start();
     958    }
     959    catch(Exception error) {
     960        Gatherer.printStackTrace(error);
     961    }
     962    }
     963    /** Saves the current collection to a new filename, then restores the original collection. Finally opens the collection copy.
    964964      * @param name The name collection name.
    965965      */
    966     public void saveCollectionAs(String name) {
    967           // We need to do this in a separate thread so create a SaveCollectionAsTask
    968           try {
    969                 SaveCollectionTask save_task = new SaveCollectionTask(collection, name);
    970                 save_task.start();
    971           }
    972           catch(Exception error) {
    973                 Gatherer.printStackTrace(error);
    974           }
    975     }
    976 
    977     /** Method that is called whenever the metadata set collection changes in some way, such as the addition of a new set or the merging of two sets. We want to mark the collection so that it needs saving again.
     966    public void saveCollectionAs(String name) {
     967    // We need to do this in a separate thread so create a SaveCollectionAsTask
     968    try {
     969        SaveCollectionTask save_task = new SaveCollectionTask(collection, name);
     970        save_task.start();
     971    }
     972    catch(Exception error) {
     973        Gatherer.printStackTrace(error);
     974    }
     975    }
     976
     977    /** Method that is called whenever the metadata set collection changes in some way, such as the addition of a new set or the merging of two sets. We want to mark the collection so that it needs saving again.
    978978      * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
    979979      * @see org.greenstone.gatherer.collection.Collection
    980980      */
    981     public void setChanged(MSMEvent event) {
    982           // Invalidate saved
    983           collection.setSaved(false);
    984     }
    985 
    986     /** Updates the given workspace tree model to reference the private cache of the currently loaded collection. */
    987     public void updatePrivateWorkspace(DefaultTreeModel model) {
    988           // Add Private workspace if a collection has been loaded.
    989           if(ready() && !Gatherer.config.get("workflow.mirror", true)) {
    990                 FileNode root = (FileNode)model.getRoot();
     981    public void setChanged(MSMEvent event) {
     982    // Invalidate saved
     983    collection.setSaved(false);
     984    }
     985
     986    /** Updates the given workspace tree model to reference the private cache of the currently loaded collection. */
     987    public void updatePrivateWorkspace(DefaultTreeModel model) {
     988    // Add Private workspace if a collection has been loaded.
     989    if(ready() && !Gatherer.config.get("workflow.mirror", true)) {
     990        FileNode root = (FileNode)model.getRoot();
    991991                // Remove old private workspace
    992                 FileNode old = (FileNode)model.getChild(root, 2);
    993                 model.removeNodeFromParent(old);
     992        FileNode old = (FileNode)model.getChild(root, 2);
     993        model.removeNodeFromParent(old);
    994994                // Create and insert new.
    995                 FileNode private_workspace = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
    996                 model.insertNodeInto(private_workspace, root, 2);
    997           }
    998     }
    999     /** Called whenever the value tree of an metadata element changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
     995        FileNode private_workspace = new FileNode(new File(getCollectionCache()), get("Tree.Private"));
     996        model.insertNodeInto(private_workspace, root, 2);
     997    }
     998    }
     999    /** Called whenever the value tree of an metadata element changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
    10001000      * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
    10011001      * @see org.greenstone.gatherer.collection.Collection
    10021002      */
    1003     public void valueChanged(MSMEvent event) {
    1004           collection.setSaved(false);
    1005     }
    1006     /** Used to retrive a value from the dictionary based on the key.
     1003    public void valueChanged(MSMEvent event) {
     1004    collection.setSaved(false);
     1005    }
     1006    /** Used to retrive a value from the dictionary based on the key.
    10071007      * @param key A <strong>String</strong> indicating what value to retrieve.
    10081008      * @return A <strong>String</strong> representing the value.
    10091009      */
    1010     private String get(String key) {
    1011           return get(key, (String[])null);
    1012     }
    1013 
    1014     /** Used to retrive a value from the dictionary based on the key. */
    1015     private String get(String key, String arg) {
    1016           String[] args = new String[1];
    1017           args[0] = arg;
    1018           return get(key, args);
    1019     }
    1020 
    1021     /** Used to retrive a value from the dictionary based on the key, and an array of arguments.
     1010    private String get(String key) {
     1011    return get(key, (String[])null);
     1012    }
     1013
     1014    /** Used to retrive a value from the dictionary based on the key. */
     1015    private String get(String key, String arg) {
     1016    String[] args = new String[1];
     1017    args[0] = arg;
     1018    return get(key, args);
     1019    }
     1020
     1021    /** Used to retrive a value from the dictionary based on the key, and an array of arguments.
    10221022      * @param key A <strong>String</strong> indicating what value to retrieve.
    10231023      * @param args A <strong>String[]</strong> of arguments to be inserted into the phrase.
    10241024      * @return A <strong>String</strong> representing the value.
    10251025      */
    1026     private String get(String key, String args[]) {
    1027           if(key.indexOf('.') == -1) {
    1028                 key = "CollectionManager." + key;
    1029           }
    1030           return Gatherer.dictionary.get(key, args);
    1031     }
    1032     /** Install collection by moving its files from building to index after a successful build.
    1033       * @see org.greenstone.gatherer.Gatherer
    1034       * @see org.greenstone.gatherer.util.Utility
    1035       */
    1036     private void installCollection() {
    1037           Gatherer.println("Build complete. Moving files.");
     1026    private String get(String key, String args[]) {
     1027    if(key.indexOf('.') == -1) {
     1028        key = "CollectionManager." + key;
     1029    }
     1030    return Gatherer.dictionary.get(key, args);
     1031    }
     1032    /** Install collection by moving its files from building to index after a successful build.
     1033      * @see org.greenstone.gatherer.Gatherer
     1034      * @see org.greenstone.gatherer.util.Utility
     1035      */
     1036    private void installCollection() {
     1037    Gatherer.println("Build complete. Moving files.");
    10381038         
    1039           try {
     1039    try {
    10401040                // We have to ensure that the local library
    1041                 if(Gatherer.config.exec_file != null) {
    1042                      ///ystem.err.println("Local Library Found!");
    1043                     Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.RELEASE_COMMAND + collection.getName());
    1044                 }
     1041        if(Gatherer.config.exec_file != null) {
     1042        ///ystem.err.println("Local Library Found!");
     1043        Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.RELEASE_COMMAND + collection.getName());
     1044        }
    10451045               
    1046                 File index_dir = new File(getCollectionIndex(), "temp.txt");
    1047                 index_dir = index_dir.getParentFile();
    1048                 Gatherer.println("Index = " + index_dir.getAbsolutePath());
     1046        File index_dir = new File(getCollectionIndex(), "temp.txt");
     1047        index_dir = index_dir.getParentFile();
     1048        Gatherer.println("Index = " + index_dir.getAbsolutePath());
    10491049               
    1050                 if(index_dir.exists()) {
    1051                      Utility.delete(index_dir);
    1052                 }
    1053 
    1054                 if(index_dir.exists()) {
    1055                      throw(new Exception("Index directory cannot be removed."));
    1056                 }
     1050        if(index_dir.exists()) {
     1051        Utility.delete(index_dir);
     1052        }
     1053
     1054        if(index_dir.exists()) {
     1055        throw(new Exception("Index directory cannot be removed."));
     1056        }
    10571057               
    1058                 File build_dir = new File(getCollectionBuild(), "temp.txt");
    1059                 build_dir = build_dir.getParentFile();
    1060                 Gatherer.println("Build = " + build_dir.getAbsolutePath());
    1061                 build_dir.renameTo(index_dir);
    1062 
    1063                 File new_build = new File(getCollectionBuild(), "temp.txt");
    1064                 new_build = new_build.getParentFile();
    1065 
    1066                 if(new_build.exists()) {
    1067                      throw(new Exception("Build directory cannot be moved."));
    1068                 }
    1069 
    1070                 new_build.mkdir();
    1071           }
    1072           catch (Exception exception) {
    1073                 JOptionPane.showMessageDialog(Gatherer.g_man, "Exception detected during collection install.\nMost likely caused by Windows or Local Library holding locks on files:\n" + exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
    1074           }
    1075     }
    1076     /** Creates and dispatches a message given the initial details.
     1058        File build_dir = new File(getCollectionBuild(), "temp.txt");
     1059        build_dir = build_dir.getParentFile();
     1060        Gatherer.println("Build = " + build_dir.getAbsolutePath());
     1061        build_dir.renameTo(index_dir);
     1062
     1063        File new_build = new File(getCollectionBuild(), "temp.txt");
     1064        new_build = new_build.getParentFile();
     1065
     1066        if(new_build.exists()) {
     1067        throw(new Exception("Build directory cannot be moved."));
     1068        }
     1069
     1070        new_build.mkdir();
     1071    }
     1072    catch (Exception exception) {
     1073        JOptionPane.showMessageDialog(Gatherer.g_man, "Exception detected during collection install.\nMost likely caused by Windows or Local Library holding locks on files:\n" + exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
     1074    }
     1075    }
     1076    /** Creates and dispatches a message given the initial details.
    10771077      * @param level An <i>int</i> indicating the message level for this message.
    10781078      * @param message A <strong>String</strong> which contains the payload of this message.
     
    10801080      * @see org.greenstone.gatherer.Message
    10811081      */
    1082      private void message(int level, String message) {
    1083           Message msg = new Message(Message.COLLECT, level, message);
    1084           if(Gatherer.g_man != null) {
    1085                 Gatherer.log.add(msg);
    1086           } else {
    1087                 Gatherer.println(msg.toString());
    1088           }
    1089      }
    1090 
    1091      private boolean searchArchivesForMetadata(File archive_directory) {
    1092           /** @todo - ensure GreenstoneArchiveParser works as expected. */
    1093           return true;
    1094      }
    1095 
    1096      private boolean searchForMetadata(File current_file) {
    1097           boolean cancelled = false;
    1098           if(current_file.isFile() && current_file.getName().equals(Utility.METADATA_XML)) {
    1099                 cancelled = collection.msm.searchForMetadata(null, new FileNode(current_file), false, true); // A dummy run only.
    1100           }
    1101           else {
    1102                 File[] children_files = current_file.listFiles();
    1103                 for(int i = 0; !cancelled && children_files != null && i < children_files.length; i++) {
    1104                      cancelled = searchForMetadata(children_files[i]);
     1082    private void message(int level, String message) {
     1083    Message msg = new Message(Message.COLLECT, level, message);
     1084    if(Gatherer.g_man != null) {
     1085        Gatherer.log.add(msg);
     1086    } else {
     1087        Gatherer.println(msg.toString());
     1088    }
     1089    }
     1090
     1091    private boolean searchArchivesForMetadata(File archive_directory) {
     1092    /** @todo - ensure GreenstoneArchiveParser works as expected. */
     1093    return true;
     1094    }
     1095
     1096    private boolean searchForMetadata(File current_file) {
     1097    boolean cancelled = false;
     1098    if(current_file.isFile() && current_file.getName().equals(Utility.METADATA_XML)) {
     1099        cancelled = collection.msm.searchForMetadata(null, new FileNode(current_file), false, true); // A dummy run only.
     1100    }
     1101    else {
     1102        File[] children_files = current_file.listFiles();
     1103        for(int i = 0; !cancelled && children_files != null && i < children_files.length; i++) {
     1104        cancelled = searchForMetadata(children_files[i]);
     1105        }
     1106    }
     1107    return cancelled;
     1108    }
     1109
     1110    private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title) {
     1111    boolean first_name = true;
     1112    boolean first_extra = true;
     1113    String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
     1114
     1115    HashMap mappings = collection.msm.profiler.getActions(collection_path);
     1116
     1117    // Now read in base_cfg line by line, parsing important onces and/or replacing them with information pertinent to our collection. Each line is then written back out to the new collect.cfg file.
     1118    try {
     1119        BufferedReader in = new BufferedReader(new FileReader(base_cfg));
     1120        BufferedWriter out = new BufferedWriter(new FileWriter(new_cfg, false)); // Overwrite whats there.
     1121        String command = null;
     1122        while((command = in.readLine()) != null) {
     1123        // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
     1124        while(command.trim().endsWith("\\")) {
     1125            command = command.substring(0, command.lastIndexOf("\\"));
     1126            String next_line = in.readLine();
     1127            if(next_line != null) {
     1128            command = command + next_line;
     1129            }
     1130        }
     1131        ///ystem.err.println("Read: " + command);
     1132        // Now we've finished parsing a line, determine what to do with it.
     1133        String command_lc = command.toLowerCase();
     1134        // We replace the creator string with our own.
     1135        if(command_lc.startsWith(Utility.CFG_CREATOR)) {
     1136            write(out, Utility.CFG_CREATOR + " " + email);
     1137        }
     1138        else if(command_lc.startsWith(Utility.CFG_MAINTAINER)) {
     1139            write(out, Utility.CFG_MAINTAINER + " " + email);
     1140        }
     1141        else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONNAME)) {
     1142            if(first_name) {
     1143            write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONNAME + " \"" + title + "\"");
     1144            first_name = false;
     1145            }
     1146        }
     1147        else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA)) {
     1148            if(first_extra) {
     1149            write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA + " \"" + description + "\"");
     1150            first_extra = false;
     1151            }
     1152        }
     1153        else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_ICONCOLLECTION)) {
     1154            write(out, Utility.CFG_COLLECTIONMETA_ICONCOLLECTION + " \"\"");
     1155        }
     1156
     1157        // Just before we try more general parsing there are the special cases to check. These are explicit changes required by some collections to produce sensible results.
     1158        else if(special_case == SPECIAL_DLS && command_lc.equals("classify      hierarchy -hfile azlist.txt -metadata azlist -sort title -buttonname title -hlist_at_top")) {
     1159            write(out, "classify AZList -metadata dls.Title -buttonname Title");
     1160        }
     1161        else if(command_lc.startsWith(Utility.CFG_CLASSIFY)) {
     1162            StringTokenizer tokenizer = new StringTokenizer(command);
     1163            StringBuffer text = new StringBuffer(tokenizer.nextToken());
     1164            // Read in the classifier command watching for hfile, metadata and sort arguments.
     1165            String buttonname = null;
     1166            String hfile = null;
     1167            String new_metadata = null;
     1168            String old_metadata = null;
     1169            while(tokenizer.hasMoreTokens()) {
     1170            String token = tokenizer.nextToken();
     1171            if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
     1172                if(tokenizer.hasMoreTokens()) {
     1173                text.append(" ");
     1174                text.append(token);
     1175                token = tokenizer.nextToken();
     1176                hfile = token;
     1177                }
     1178            }
     1179            else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
     1180                if(tokenizer.hasMoreTokens()) {
     1181                text.append(" ");
     1182                text.append(token);
     1183                String temp_metadata = tokenizer.nextToken();
     1184                String replacement = (String) mappings.get(temp_metadata);
     1185                if(replacement != null) {
     1186                    token = replacement;
     1187                    old_metadata = temp_metadata;
     1188                    new_metadata = replacement;
    11051189                }
    1106           }
    1107           return cancelled;
    1108      }
    1109 
    1110      private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title) {
    1111           boolean first_name = true;
    1112           boolean first_extra = true;
    1113           String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
    1114 
    1115           HashMap mappings = collection.msm.profiler.getActions(collection_path);
    1116 
    1117           // Now read in base_cfg line by line, parsing important onces and/or replacing them with information pertinent to our collection. Each line is then written back out to the new collect.cfg file.
    1118           try {
    1119                 BufferedReader in = new BufferedReader(new FileReader(base_cfg));
    1120                 BufferedWriter out = new BufferedWriter(new FileWriter(new_cfg, false)); // Overwrite whats there.
    1121                 String command = null;
    1122                 while((command = in.readLine()) != null) {
    1123                      // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
    1124                      while(command.trim().endsWith("\\")) {
    1125                           command = command.substring(0, command.lastIndexOf("\\"));
    1126                           String next_line = in.readLine();
    1127                           if(next_line != null) {
    1128                                 command = command + next_line;
    1129                           }
    1130                      }
    1131                      ///ystem.err.println("Read: " + command);
    1132                      // Now we've finished parsing a line, determine what to do with it.
    1133                      String command_lc = command.toLowerCase();
    1134                      // We replace the creator string with our own.
    1135                      if(command_lc.startsWith(Utility.CFG_CREATOR)) {
    1136                           write(out, Utility.CFG_CREATOR + " " + email);
    1137                      }
    1138                      else if(command_lc.startsWith(Utility.CFG_MAINTAINER)) {
    1139                           write(out, Utility.CFG_MAINTAINER + " " + email);
    1140                      }
    1141                      else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONNAME)) {
    1142                           if(first_name) {
    1143                                 write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONNAME + " \"" + title + "\"");
    1144                                 first_name = false;
    1145                           }
    1146                      }
    1147                      else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA)) {
    1148                           if(first_extra) {
    1149                                 write(out, Utility.CFG_COLLECTIONMETA_COLLECTIONEXTRA + " \"" + description + "\"");
    1150                                 first_extra = false;
    1151                           }
    1152                      }
    1153                      else if(command_lc.startsWith(Utility.CFG_COLLECTIONMETA_ICONCOLLECTION)) {
    1154                           write(out, Utility.CFG_COLLECTIONMETA_ICONCOLLECTION + " \"\"");
    1155                      }
    1156 
    1157                      // Just before we try more general parsing there are the special cases to check. These are explicit changes required by some collections to produce sensible results.
    1158                      else if(special_case == SPECIAL_DLS && command_lc.equals("classify      hierarchy -hfile azlist.txt -metadata azlist -sort title -buttonname title -hlist_at_top")) {
    1159                           write(out, "classify AZList -metadata dls.Title -buttonname Title");
    1160                      }
    1161                      else if(command_lc.startsWith(Utility.CFG_CLASSIFY)) {
    1162                           StringTokenizer tokenizer = new StringTokenizer(command);
    1163                           StringBuffer text = new StringBuffer(tokenizer.nextToken());
    1164                           // Read in the classifier command watching for hfile, metadata and sort arguments.
    1165                           String buttonname = null;
    1166                           String hfile = null;
    1167                           String new_metadata = null;
    1168                           String old_metadata = null;
    1169                           while(tokenizer.hasMoreTokens()) {
    1170                                 String token = tokenizer.nextToken();
    1171                                 if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
    1172                                      if(tokenizer.hasMoreTokens()) {
    1173                                           text.append(" ");
    1174                                           text.append(token);
    1175                                           token = tokenizer.nextToken();
    1176                                           hfile = token;
    1177                                      }
    1178                                 }
    1179                                 else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
    1180                                      if(tokenizer.hasMoreTokens()) {
    1181                                           text.append(" ");
    1182                                           text.append(token);
    1183                                           String temp_metadata = tokenizer.nextToken();
    1184                                           String replacement = (String) mappings.get(temp_metadata);
    1185                                           if(replacement != null) {
    1186                                                 token = replacement;
    1187                                                 old_metadata = temp_metadata;
    1188                                                 new_metadata = replacement;
    1189                                           }
    1190                                           else {
    1191                                                 token = temp_metadata;
    1192                                           }
    1193                                           temp_metadata = null;
    1194                                           replacement = null;
    1195                                      }
    1196                                 }
    1197                                 else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
    1198                                      if(tokenizer.hasMoreTokens()) {
    1199                                           text.append(" ");
    1200                                           text.append(token);
    1201                                           String temp_metadata = tokenizer.nextToken();
    1202                                           String replacement = (String) mappings.get(temp_metadata);
    1203                                           if(replacement != null) {
    1204                                                 token = replacement;
    1205                                           }
    1206                                           else {
    1207                                                 token = temp_metadata;
    1208                                           }
    1209                                           temp_metadata = null;
    1210                                           replacement = null;
    1211                                      }
    1212                                 }
    1213                                 else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
    1214                                     buttonname = token;
    1215                                 }
    1216                                 text.append(' ');
    1217                                 text.append(token);
    1218                                 token = null;
    1219                           }
    1220                           tokenizer = null;
    1221 
    1222                           // If we replaced the metadata argument and didn't encounter a buttonname, then add one now pointing back to the old metadata name in order to accomodate macro files which required such names (buttonname is metadata name by default)!
    1223                           if(old_metadata != null && new_metadata != null && buttonname == null) {
    1224                             text.append(' ');
    1225                             text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
    1226                             text.append(' ');
    1227                             text.append(old_metadata);
    1228                           }
    1229                           command = text.toString();
    1230                           // Replace the hfile if we found it
    1231                           if(hfile != null && new_metadata != null) {
    1232                                 command = command.replaceAll(hfile, new_metadata + ".txt");
    1233                           }
    1234                           buttonname = null;
    1235                           hfile = null;
    1236                           new_metadata = null;
    1237                           old_metadata = null;
    1238                           write(out, command);
    1239                      }
    1240                      else {
    1241                           // There is still one special case, that of the format command. In such a command we have to search for [<target>] to ensure we don't change parts of the format which have nothing to do with the metadata elements.
    1242                           boolean format_command = command_lc.startsWith(Utility.CFG_FORMAT);
    1243                           // Replace mapping strings
    1244                           if(mappings != null) {
    1245                                 for(Iterator keys = mappings.keySet().iterator(); keys.hasNext(); ) {
    1246                                      String target = (String) keys.next();
    1247                                      String replacement = (String) mappings.get(target);
    1248                                      if(format_command) {
    1249                                           target = "\\[" + target + "\\]";
    1250                                           replacement = "{Or}{[" + replacement + "]," + target + "}";
    1251                                      }
    1252                                      command = command.replaceAll(target, replacement);
    1253                                 }
    1254                           }
    1255                           write(out, command);
    1256                      }
     1190                else {
     1191                    token = temp_metadata;
    12571192                }
    1258                 in.close();
    1259                 in = null;
    1260                 out.flush();
    1261                 out.close();
    1262                 out = null;
    1263           }
    1264           catch(Exception error) {
    1265                 Gatherer.printStackTrace(error);
    1266           }
    1267           // All done, I hope.
    1268      }
    1269 
    1270      private void write(BufferedWriter out, String message)
    1271           throws Exception {
    1272           ///ystem.err.println("Writing: " + message);
    1273           out.write(message, 0, message.length());
    1274           out.newLine();
    1275      }
    1276 
    1277      /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
    1278      private class FMTreeModelListener
    1279           implements TreeModelListener {
    1280           /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
     1193                temp_metadata = null;
     1194                replacement = null;
     1195                }
     1196            }
     1197            else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
     1198                if(tokenizer.hasMoreTokens()) {
     1199                text.append(" ");
     1200                text.append(token);
     1201                String temp_metadata = tokenizer.nextToken();
     1202                String replacement = (String) mappings.get(temp_metadata);
     1203                if(replacement != null) {
     1204                    token = replacement;
     1205                }
     1206                else {
     1207                    token = temp_metadata;
     1208                }
     1209                temp_metadata = null;
     1210                replacement = null;
     1211                }
     1212            }
     1213            else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
     1214                buttonname = token;
     1215            }
     1216            text.append(' ');
     1217            text.append(token);
     1218            token = null;
     1219            }
     1220            tokenizer = null;
     1221
     1222            // If we replaced the metadata argument and didn't encounter a buttonname, then add one now pointing back to the old metadata name in order to accomodate macro files which required such names (buttonname is metadata name by default)!
     1223            if(old_metadata != null && new_metadata != null && buttonname == null) {
     1224            text.append(' ');
     1225            text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
     1226            text.append(' ');
     1227            text.append(old_metadata);
     1228            }
     1229            command = text.toString();
     1230            // Replace the hfile if we found it
     1231            if(hfile != null && new_metadata != null) {
     1232            command = command.replaceAll(hfile, new_metadata + ".txt");
     1233            }
     1234            buttonname = null;
     1235            hfile = null;
     1236            new_metadata = null;
     1237            old_metadata = null;
     1238            write(out, command);
     1239        }
     1240        else {
     1241            // There is still one special case, that of the format command. In such a command we have to search for [<target>] to ensure we don't change parts of the format which have nothing to do with the metadata elements.
     1242            boolean format_command = command_lc.startsWith(Utility.CFG_FORMAT);
     1243            // Replace mapping strings
     1244            if(mappings != null) {
     1245            for(Iterator keys = mappings.keySet().iterator(); keys.hasNext(); ) {
     1246                String target = (String) keys.next();
     1247                String replacement = (String) mappings.get(target);
     1248                if(format_command) {
     1249                target = "\\[" + target + "\\]";
     1250                replacement = "{Or}{[" + replacement + "]," + target + "}";
     1251                }
     1252                command = command.replaceAll(target, replacement);
     1253            }
     1254            }
     1255            write(out, command);
     1256        }
     1257        }
     1258        in.close();
     1259        in = null;
     1260        out.flush();
     1261        out.close();
     1262        out = null;
     1263    }
     1264    catch(Exception error) {
     1265        Gatherer.printStackTrace(error);
     1266    }
     1267    // All done, I hope.
     1268    }
     1269
     1270    private void write(BufferedWriter out, String message)
     1271    throws Exception {
     1272    ///ystem.err.println("Writing: " + message);
     1273    out.write(message, 0, message.length());
     1274    out.newLine();
     1275    }
     1276
     1277    /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
     1278    private class FMTreeModelListener
     1279    implements TreeModelListener {
     1280    /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
     1281     * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
     1282            */
     1283    public void treeNodesChanged(TreeModelEvent event) {
     1284        if(collection != null) {
     1285        collection.setSaved(false);
     1286        }
     1287    }
     1288    /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
    12811289            * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
    12821290            */
    1283           public void treeNodesChanged(TreeModelEvent event) {
    1284                 if(collection != null) {
    1285                      collection.setSaved(false);
    1286                 }
    1287           }
    1288           /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
     1291    public void treeNodesInserted(TreeModelEvent event) {
     1292        if(collection != null) {
     1293        collection.setSaved(false);
     1294        }
     1295    }
     1296    /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
    12891297            * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
    12901298            */
    1291           public void treeNodesInserted(TreeModelEvent event) {
    1292                 if(collection != null) {
    1293                      collection.setSaved(false);
    1294                 }
    1295           }
    1296           /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
     1299    public void treeNodesRemoved(TreeModelEvent event) {
     1300        if(collection != null) {
     1301        collection.setSaved(false);
     1302        }
     1303    }
     1304    /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
    12971305            * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
    12981306            */
    1299           public void treeNodesRemoved(TreeModelEvent event) {
    1300                 if(collection != null) {
    1301                      collection.setSaved(false);
    1302                 }
    1303           }
    1304           /** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
    1305             * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
    1306             */
    1307           public void treeStructureChanged(TreeModelEvent event) {
    1308                 if(collection != null) {
    1309                      collection.setSaved(false);
    1310                 }
    1311           }
    1312      }
     1307    public void treeStructureChanged(TreeModelEvent event) {
     1308        if(collection != null) {
     1309        collection.setSaved(false);
     1310        }
     1311    }
     1312    }
    13131313}
  • trunk/gli/src/org/greenstone/gatherer/collection/DeleteCollectionPrompt.java

    r4293 r4366  
    5050 */
    5151public class DeleteCollectionPrompt
    52     extends JDialog {
    53     /** The currently selected collection for deletion. */
    54     private Collection collection = null;
    55     /** The model behind the list. */
    56     private DefaultListModel list_model = null;
    57     /** A reference to ourself so any inner-classes get dispose of us. */
    58     private DeleteCollectionPrompt prompt = null;
    59     /** The close button, which exits the prompt without deleting anything. */
    60     private JButton close_button = null;
    61     /** The ok button which causes the selected collection to be deleted. */
    62     private JButton ok_button = null;
    63     /** The confirmation check box. */
    64     private JCheckBox confirmation = null;
    65     /** The label above details. */
    66     private JLabel details_label = null;
    67     /** The label above the list. */
    68     private JLabel list_label = null;
    69     /** The list of available collections. */
    70     private JList list = null;
    71     /** The text area used to display details about the collection selected. */
    72     private JTextArea details = null;
    73     /** A string array used to pass arguments to the phrase retrieval method. */
    74     private String args[] = null;
    75     /** The size of the delete prompt screen. */
    76     public static final Dimension SIZE = new Dimension(500, 500);
    77     /** Constructor.
    78       * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.CloseButtonListener
    79       * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.CollectionListListener
    80       * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.ConfirmationCheckBoxListener
    81       * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.OKButtonListener
    82       */
    83     public DeleteCollectionPrompt() {
    84           super();
    85           this.close_button = new JButton(get("General.Close", null));
    86           this.confirmation = new JCheckBox(get("Confirm_Delete", null));
    87           this.details = new JTextArea();
    88           this.details_label = new JLabel(get("Collection_Details", null));
    89           this.list = new JList();
    90           this.list_label = new JLabel(get("Collection_List", null));
    91           this.list_model = new DefaultListModel();
    92           this.ok_button = new JButton(get("General.OK", null));
    93           this.prompt = this;
    94           this.setModal(true);
    95           this.setSize(SIZE);
    96           this.setTitle(get("Title", null));
    97           close_button.addActionListener(new CloseButtonListener());
    98           confirmation.addActionListener(new ConfirmationCheckBoxListener());
    99           confirmation.setEnabled(false);
    100           confirmation.setSelected(false);
    101           details.setFont(Gatherer.config.getFont("general.tooltip_font", false));
    102           details.setText(get("No_Collection", null));
    103           list.addListSelectionListener(new CollectionListListener());
    104           list.clearSelection();
    105           list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    106           list.setModel(list_model);
    107           ok_button.addActionListener(new OKButtonListener());
    108           ok_button.setEnabled(false);
    109           scanForCollections();
    110     }
    111     /** Destructor. */
    112     public void destroy() {
    113           close_button = null;
    114           confirmation = null;
    115           details = null;
    116           details_label = null;
    117           list_model.clear();
    118           list_model = null;
    119           list = null;
    120           ok_button = null;
    121           prompt = null;
    122     }
    123     /** This method causes the modal prompt to be displayed. */
    124     public void display() {
    125           // Central pane
    126           JPanel list_pane = new JPanel(new BorderLayout());
    127           list_pane.add(list_label, BorderLayout.NORTH);
    128           list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
    129           list_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
    130 
    131           JPanel details_pane = new JPanel(new BorderLayout());
    132           details_pane.add(details_label, BorderLayout.NORTH);
    133           details_pane.add(new JScrollPane(details), BorderLayout.CENTER);
    134           details_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    135 
    136           JPanel central_pane = new JPanel(new GridLayout(2, 1));
    137           central_pane.add(list_pane);
    138           central_pane.add(details_pane);
    139           central_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    140 
    141           // Lower pane
    142           JPanel confirmation_pane = new JPanel(new BorderLayout());
    143           confirmation_pane.add(confirmation, BorderLayout.CENTER);
    144           confirmation_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
    145 
    146           JPanel button_pane = new JPanel(new GridLayout(1, 2));
    147           button_pane.add(ok_button);
    148           button_pane.add(close_button);
    149           button_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    150 
    151           JPanel lower_pane = new JPanel(new BorderLayout());
    152           lower_pane.add(confirmation_pane, BorderLayout.NORTH);
    153           lower_pane.add(button_pane, BorderLayout.SOUTH);
    154           lower_pane.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
    155 
    156           // Final.
    157           JPanel content_pane = (JPanel)this.getContentPane();
    158           content_pane.setLayout(new BorderLayout());
    159           content_pane.add(central_pane, BorderLayout.CENTER);
    160           content_pane.add(lower_pane, BorderLayout.SOUTH);
    161 
    162           // Center and display.
    163           Dimension screen_size = Gatherer.config.screen_size;
    164           this.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
    165           this.show();
    166     }
    167     /** Shows a delete complete prompt.
     52    extends JDialog {
     53    /** The currently selected collection for deletion. */
     54    private Collection collection = null;
     55    /** The model behind the list. */
     56    private DefaultListModel list_model = null;
     57    /** A reference to ourself so any inner-classes get dispose of us. */
     58    private DeleteCollectionPrompt prompt = null;
     59    /** The close button, which exits the prompt without deleting anything. */
     60    private JButton close_button = null;
     61    /** The ok button which causes the selected collection to be deleted. */
     62    private JButton ok_button = null;
     63    /** The confirmation check box. */
     64    private JCheckBox confirmation = null;
     65    /** The label above details. */
     66    private JLabel details_label = null;
     67    /** The label above the list. */
     68    private JLabel list_label = null;
     69    /** The list of available collections. */
     70    private JList list = null;
     71    /** The text area used to display details about the collection selected. */
     72    private JTextArea details = null;
     73    /** A string array used to pass arguments to the phrase retrieval method. */
     74    private String args[] = null;
     75    /** The size of the delete prompt screen. */
     76    public static final Dimension SIZE = new Dimension(500, 500);
     77    /** Constructor.
     78     * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.CloseButtonListener
     79     * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.CollectionListListener
     80     * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.ConfirmationCheckBoxListener
     81     * @see org.greenstone.gatherer.collection.DeleteCollectionPrompt.OKButtonListener
     82     */
     83    public DeleteCollectionPrompt() {
     84    super();
     85    this.close_button = new JButton(get("General.Close", null));
     86    this.confirmation = new JCheckBox(get("Confirm_Delete", null));
     87    this.details = new JTextArea();
     88    this.details_label = new JLabel(get("Collection_Details", null));
     89    this.list = new JList();
     90    this.list_label = new JLabel(get("Collection_List", null));
     91    this.list_model = new DefaultListModel();
     92    this.ok_button = new JButton(get("General.OK", null));
     93    this.prompt = this;
     94    this.setModal(true);
     95    this.setSize(SIZE);
     96    this.setTitle(get("Title", null));
     97    close_button.addActionListener(new CloseButtonListener());
     98    confirmation.addActionListener(new ConfirmationCheckBoxListener());
     99    confirmation.setEnabled(false);
     100    confirmation.setSelected(false);
     101    details.setFont(Gatherer.config.getFont("general.tooltip_font", false));
     102    details.setText(get("No_Collection", null));
     103    list.addListSelectionListener(new CollectionListListener());
     104    list.clearSelection();
     105    list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     106    list.setModel(list_model);
     107    ok_button.addActionListener(new OKButtonListener());
     108    ok_button.setEnabled(false);
     109    scanForCollections();
     110    }
     111    /** Destructor. */
     112    public void destroy() {
     113    close_button = null;
     114    confirmation = null;
     115    details = null;
     116    details_label = null;
     117    list_model.clear();
     118    list_model = null;
     119    list = null;
     120    ok_button = null;
     121    prompt = null;
     122    }
     123    /** This method causes the modal prompt to be displayed. */
     124    public void display() {
     125    // Central pane
     126    JPanel list_pane = new JPanel(new BorderLayout());
     127    list_pane.add(list_label, BorderLayout.NORTH);
     128    list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
     129    list_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
     130
     131    JPanel details_pane = new JPanel(new BorderLayout());
     132    details_pane.add(details_label, BorderLayout.NORTH);
     133    details_pane.add(new JScrollPane(details), BorderLayout.CENTER);
     134    details_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
     135
     136    JPanel central_pane = new JPanel(new GridLayout(2, 1));
     137    central_pane.add(list_pane);
     138    central_pane.add(details_pane);
     139    central_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
     140
     141    // Lower pane
     142    JPanel confirmation_pane = new JPanel(new BorderLayout());
     143    confirmation_pane.add(confirmation, BorderLayout.CENTER);
     144    confirmation_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     145
     146    JPanel button_pane = new JPanel(new GridLayout(1, 2));
     147    button_pane.add(ok_button);
     148    button_pane.add(close_button);
     149    button_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
     150
     151    JPanel lower_pane = new JPanel(new BorderLayout());
     152    lower_pane.add(confirmation_pane, BorderLayout.NORTH);
     153    lower_pane.add(button_pane, BorderLayout.SOUTH);
     154    lower_pane.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
     155
     156    // Final.
     157    JPanel content_pane = (JPanel)this.getContentPane();
     158    content_pane.setLayout(new BorderLayout());
     159    content_pane.add(central_pane, BorderLayout.CENTER);
     160    content_pane.add(lower_pane, BorderLayout.SOUTH);
     161
     162    // Center and display.
     163    Dimension screen_size = Gatherer.config.screen_size;
     164    this.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
     165    this.show();
     166    }
     167    /** Shows a delete complete prompt.
    168168      * @param success A <strong>boolean</strong> indicating if the collection was successfully deleted.
    169169      * @see org.greenstone.gatherer.collection.Collection
    170170      */
    171     public void resultPrompt(boolean success) {
    172           args = new String[1];
    173           args[0] = collection.getName();
    174           if(success) {
    175                 JOptionPane.showMessageDialog(prompt,get("Successful_Delete", args),get("Successful_Title", null),JOptionPane.INFORMATION_MESSAGE);
    176           }
    177           else {
    178                 JOptionPane.showMessageDialog(prompt,get("Failed_Delete", args),get("Failed_Title", null),JOptionPane.WARNING_MESSAGE);
    179           }
    180     }
    181     /** Retrieves a phrase from the <strong>Dictionary</strong> in <strong>Gatherer</strong>.
     171    public void resultPrompt(boolean success) {
     172    args = new String[1];
     173    args[0] = collection.getName();
     174    if(success) {
     175        JOptionPane.showMessageDialog(prompt,get("Successful_Delete", args),get("Successful_Title", null),JOptionPane.INFORMATION_MESSAGE);
     176    }
     177    else {
     178        JOptionPane.showMessageDialog(prompt,get("Failed_Delete", args),get("Failed_Title", null),JOptionPane.WARNING_MESSAGE);
     179    }
     180    }
     181    /** Retrieves a phrase from the <strong>Dictionary</strong> in <strong>Gatherer</strong>.
    182182      * @param key A <strong>String</strong> used to match against a specific phrase in the dictionary.
    183183      * @see org.greenstone.gatherer.Dictionary
    184184      * @see org.greenstone.gatherer.Gatherer
    185185      */
    186     private String get(String key, String args[]) {
    187           if(key.indexOf(".") == -1) {
    188                 key = "DeleteCollectionPrompt." + key;
    189           }
    190           return Gatherer.dictionary.get(key, args);
    191     }
    192     /** Attempts to load the given collection. Currently uses simple
     186    private String get(String key, String args[]) {
     187    if(key.indexOf(".") == -1) {
     188        key = "DeleteCollectionPrompt." + key;
     189    }
     190    return Gatherer.dictionary.get(key, args);
     191    }
     192    /** Attempts to load the given collection. Currently uses simple
    193193      * serialization of the collection class.
    194194      * @param location The path to the serialized collection.
    195195      */
    196     public Collection loadCollection(File file) {
    197           Collection col = null;
    198           try {
    199                 FileInputStream fis = new FileInputStream(file);
    200                 BufferedInputStream bin = new BufferedInputStream(fis);
    201                 ObjectInputStream input = new ObjectInputStream(bin);
    202                 col = (Collection) input.readObject();
    203                 input.close();
    204                 input = null;
    205                 bin.close();
    206                 bin = null;
    207                 fis.close();
    208                 fis = null;
    209           }
    210           catch (Exception error) {
    211                 error.printStackTrace();
    212           }
    213           return col;
    214     }
    215     /** Method to scan the collect directory retrieving and reloading each collection it finds, while building the list of known collections.
     196    public Collection loadCollection(File file) {
     197    Collection col = null;
     198    try {
     199        FileInputStream fis = new FileInputStream(file);
     200        BufferedInputStream bin = new BufferedInputStream(fis);
     201        ObjectInputStream input = new ObjectInputStream(bin);
     202        col = (Collection) input.readObject();
     203        input.close();
     204        input = null;
     205        bin.close();
     206        bin = null;
     207        fis.close();
     208        fis = null;
     209    }
     210    catch (Exception error) {
     211        error.printStackTrace();
     212    }
     213    return col;
     214    }
     215    /** Method to scan the collect directory retrieving and reloading each collection it finds, while building the list of known collections.
    216216      * @see org.greenstone.gatherer.Configuration
    217217      * @see org.greenstone.gatherer.Gatherer
     
    219219      * @see org.greenstone.gatherer.util.Utility
    220220      */
    221     private void scanForCollections() {
    222           // Start at the collect dir.
    223           String collect_directory_name = Utility.getCollectionDir(Gatherer.config.gsdl_path);
    224           File collect_directory = new File(collect_directory_name);
    225           if(collect_directory.exists()) {
     221    private void scanForCollections() {
     222    // Start at the collect dir.
     223    String collect_directory_name = Utility.getCollectionDir(Gatherer.config.gsdl_path);
     224    File collect_directory = new File(collect_directory_name);
     225    if(collect_directory.exists()) {
    226226                // Now for each child directory see if it contains a .col file and
    227227                // if so try to load it..
    228                 File collections[] = collect_directory.listFiles();
    229                 ArrayTools.sort(collections);
    230                 for(int i = 0; collections != null && i < collections.length; i++) {
    231                      File children[] = collections[i].listFiles();
    232                      for(int j = 0; children != null && j < children.length; j++) {
    233                           if(children[j].getAbsolutePath().endsWith(".col")) {
    234                                 Collection col = loadCollection(children[j]);
    235                                 // If we've actually loaded
    236                                 if(col != null) {
    237                                     list_model.addElement(col);
    238                                 }
    239                           }
    240                      }
    241                 }
    242           }
    243           // Otherwise the collect directory doesn't actually exist, so there ain't much we can do.
    244     }
    245     /** A button listener implementation, which listens for actions on the close button and disposes of the dialog when detected. */
    246     private class CloseButtonListener
    247           implements ActionListener {
    248           /** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
    249             * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
     228        File collections[] = collect_directory.listFiles();
     229        ArrayTools.sort(collections);
     230        for(int i = 0; collections != null && i < collections.length; i++) {
     231        File children[] = collections[i].listFiles();
     232        for(int j = 0; children != null && j < children.length; j++) {
     233            if(children[j].getAbsolutePath().endsWith(".col")) {
     234            Collection col = loadCollection(children[j]);
     235            // If we've actually loaded
     236            if(col != null) {
     237                list_model.addElement(col);
     238            }
     239            }
     240        }
     241        }
     242    }
     243    // Otherwise the collect directory doesn't actually exist, so there ain't much we can do.
     244    }
     245    /** A button listener implementation, which listens for actions on the close button and disposes of the dialog when detected. */
     246    private class CloseButtonListener
     247    implements ActionListener {
     248    /** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
     249     * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
    250250            */
    251           public void actionPerformed(ActionEvent event) {
    252                 prompt.dispose();
    253           }
    254     }
    255     /** This private class listens for selection events in from the list and then displays the appropriate details for that collection.
    256       */
    257     private class CollectionListListener
    258           implements ListSelectionListener {
    259           /** Any implementation of ListSelectionListener must include this method so we can be informed when the list selection changes.
    260             * @param event A <strong>ListSelectionEvent</strong> containing all the relevant information garnered from the event itself.
     251    public void actionPerformed(ActionEvent event) {
     252        prompt.dispose();
     253    }
     254    }
     255    /** This private class listens for selection events in from the list and then displays the appropriate details for that collection.
     256      */
     257    private class CollectionListListener
     258    implements ListSelectionListener {
     259    /** Any implementation of ListSelectionListener must include this method so we can be informed when the list selection changes.
     260     * @param event A <strong>ListSelectionEvent</strong> containing all the relevant information garnered from the event itself.
    261261            */
    262           public void valueChanged(ListSelectionEvent event) {
    263                 if(!list.isSelectionEmpty()) {
    264                      confirmation.setEnabled(true);
    265                      collection = (Collection) list.getSelectedValue();
    266                      args = new String[4];
    267                      args[0] = collection.getTitle();
    268                      args[1] = collection.getName();
    269                      args[2] = collection.getEmail();
    270                      args[3] = collection.getDescription();
    271                      details.setText(get("Details", args));
    272                 }
    273                 else {
    274                      confirmation.setEnabled(false);
    275                      details.setText(get("No_Collection", null));
    276                 }
    277           }
    278     }
    279     /** A check box listener so we can tell if the users selected confirm. */
    280     private class ConfirmationCheckBoxListener
    281           implements ActionListener {
    282           /** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
    283             * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
     262    public void valueChanged(ListSelectionEvent event) {
     263        if(!list.isSelectionEmpty()) {
     264        confirmation.setEnabled(true);
     265        collection = (Collection) list.getSelectedValue();
     266        args = new String[4];
     267        args[0] = collection.getTitle();
     268        args[1] = collection.getName();
     269        args[2] = collection.getEmail();
     270        args[3] = collection.getDescription();
     271        details.setText(get("Details", args));
     272        }
     273        else {
     274        confirmation.setEnabled(false);
     275        details.setText(get("No_Collection", null));
     276        }
     277    }
     278    }
     279    /** A check box listener so we can tell if the users selected confirm. */
     280    private class ConfirmationCheckBoxListener
     281    implements ActionListener {
     282    /** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
     283     * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
    284284            */
    285           public void actionPerformed(ActionEvent event) {
    286                 if(confirmation.isSelected()) {
    287                      ok_button.setEnabled(true);
    288                 }
    289                 else {
    290                      ok_button.setEnabled(false);
    291                 }
    292           }
    293     }       
    294     /** The OK button listener implementation. */
    295     private class OKButtonListener
    296           implements ActionListener {
    297           /** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
    298             * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
    299             * @see org.greenstone.gatherer.Configuration
    300             * @see org.greenstone.gatherer.Gatherer
    301             * @see org.greenstone.gatherer.util.Utility
    302             */
    303           public void actionPerformed(ActionEvent event) {
     285    public void actionPerformed(ActionEvent event) {
     286        if(confirmation.isSelected()) {
     287        ok_button.setEnabled(true);
     288        }
     289        else {
     290        ok_button.setEnabled(false);
     291        }
     292    }
     293    }         
     294    /** The OK button listener implementation. */
     295    private class OKButtonListener
     296    implements ActionListener {
     297    /** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
     298     * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
     299     * @see org.greenstone.gatherer.Configuration
     300     * @see org.greenstone.gatherer.Gatherer
     301     * @see org.greenstone.gatherer.util.Utility
     302     */
     303    public void actionPerformed(ActionEvent event) {
    304304                // Delete the selected collection.
    305                 File delete_me = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
    306                 if(Utility.delete(delete_me)) {
    307                      resultPrompt(true);
    308                      list_model.removeElement(collection);
    309                      details.setText(get("No_Collection", null));
    310                      confirmation.setEnabled(false);
    311                      confirmation.setSelected(false);
    312                      ok_button.setEnabled(false);
    313                      collection = null;
    314                 }
    315                 else {
    316                      resultPrompt(false);
    317                 }
    318           }
    319     }
     305        File delete_me = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + collection.getName() + File.separator);
     306        if(Utility.delete(delete_me)) {
     307        resultPrompt(true);
     308        list_model.removeElement(collection);
     309        details.setText(get("No_Collection", null));
     310        confirmation.setEnabled(false);
     311        confirmation.setSelected(false);
     312        ok_button.setEnabled(false);
     313        collection = null;
     314        }
     315        else {
     316        resultPrompt(false);
     317        }
     318    }
     319    }
    320320}
    321321
  • trunk/gli/src/org/greenstone/gatherer/collection/Job.java

    r4293 r4366  
    5050 */
    5151public class Job
    52     implements ActionListener {
     52    implements ActionListener {
    5353     
    54     private boolean clobber;
     54    private boolean clobber;
    5555    private boolean debug;
    56     private boolean higher_directories;
    57     private boolean no_parents;
    58     private boolean other_hosts;
    59     private boolean page_requisites;
    60     private boolean quiet;
    61 
    62     private GProgressBar progress;
    63 
    64     private GURL initial = null;
    65     private GURL url = null;
    66 
    67     private TreeModel model;
    68 
    69     private int depth;
    70     private int previous_state;
    71     private int state;
    72 
    73     private String current_url;
    74     private String destination;
    75     private String proxy_pass;
    76     private String proxy_user;
    77 
    78     private Vector encountered_urls;
    79     private Vector failed_urls;
    80 
    81     private WGet mummy;
    82 
    83     public static int COMPLETE = 0;
    84     public static int PAUSED   = 1;
     56    private boolean higher_directories;
     57    private boolean no_parents;
     58    private boolean other_hosts;
     59    private boolean page_requisites;
     60    private boolean quiet;
     61
     62    private GProgressBar progress;
     63
     64    private GURL initial = null;
     65    private GURL url = null;
     66
     67    private TreeModel model;
     68
     69    private int depth;
     70    private int previous_state;
     71    private int state;
     72
     73    private String current_url;
     74    private String destination;
     75    private String proxy_pass;
     76    private String proxy_user;
     77
     78    private Vector encountered_urls;
     79    private Vector failed_urls;
     80
     81    private WGet mummy;
     82
     83    public static int COMPLETE = 0;
     84    public static int PAUSED   = 1;
    8585    public static int RUNNING  = 2;
    8686    public static int STOPPED  = 3;
    8787
    88     /**
    89       */
    90     public Job(TreeModel model, boolean clobber, boolean debug, boolean no_parents, boolean other_hosts, boolean page_requisites, boolean quiet, GURL initial, int depth, String destination, String proxy_pass, String proxy_user, WGet mummy, boolean simple) {
    91           this.model = model;
    92 
    93           this.debug = debug;
    94           this.clobber = clobber;
    95           this.no_parents = no_parents;
    96           this.other_hosts = other_hosts;
    97           this.page_requisites = page_requisites;
    98           this.quiet = quiet;
    99           this.initial = initial;
    100           this.depth = depth;
    101           this.destination = destination;
    102           this.proxy_pass = proxy_pass;
    103           this.proxy_user = proxy_user;
    104           this.mummy = mummy;
    105 
    106           progress = new GProgressBar(this, initial.toString(), simple);
    107 
    108           encountered_urls = new Vector();
    109           failed_urls = new Vector();
    110 
    111           previous_state = STOPPED;
    112           state = STOPPED;
    113     }
    114 
    115     /** Depending on which button on the progress bar was pushed,
    116       * this method will affect the state of the Job and perhaps make
    117       * calls to wget.class if necessary.
    118       * @param event The ActionEvent fired from within the GProgressBar
    119       * which we must respond to.
    120       */
    121     public void actionPerformed(ActionEvent event) {
    122         // The action button is used to alternately start or stop the
    123         // job. If the current state of the job is paused then this
    124         // restart is logically equivelent to a resume.
    125           if(event.getSource() == progress.action) {
    126                 previous_state = state;
    127                 if(state == RUNNING) {
    128                      state = PAUSED;
    129                 }
    130                 else {
    131                      state = RUNNING;
    132                      mummy.resumeThread();
    133                 }
    134           }
    135           else if (event.getSource() == progress.cancel) {
    136                 state = STOPPED; // Should already be stopped.
    137                 mummy.deleteJob(this);
    138           }
    139     }
    140 
    141     /** Called by the WGet native code to inform us of a new download starting.
    142       * @param url The url that is being downloaded, as a String.
    143       */
    144     public void addDownload(String raw_url) {
    145           if(!encountered_urls.contains(raw_url)) {
    146                 encountered_urls.add(raw_url);
    147           }
    148           // Regardless create a new GURL
    149           current_url = raw_url;
    150           url = new GURL(raw_url);
    151           progress.addDownload(raw_url);
    152     }
    153 
    154     /** Used to advise the Job of a newly parsed link. Its up to Job
    155       * to decide if it already knows about this url, and if not to
    156       * update its progress bar.
    157       * @param url The url in question as a String.
    158       * @param type Whether the link is an internal or external link.
    159       * @return A boolean indicating if the url was added.
    160       */
    161     public boolean addLink(String raw_url, int type) {
    162         ///ystem.out.println("addLink("+url+", "+type+")");
    163           if(!encountered_urls.contains(raw_url)) {
     88    /**
     89     */
     90    public Job(TreeModel model, boolean clobber, boolean debug, boolean no_parents, boolean other_hosts, boolean page_requisites, boolean quiet, GURL initial, int depth, String destination, String proxy_pass, String proxy_user, WGet mummy, boolean simple) {
     91    this.model = model;
     92
     93    this.debug = debug;
     94    this.clobber = clobber;
     95    this.no_parents = no_parents;
     96    this.other_hosts = other_hosts;
     97    this.page_requisites = page_requisites;
     98    this.quiet = quiet;
     99    this.initial = initial;
     100    this.depth = depth;
     101    this.destination = destination;
     102    this.proxy_pass = proxy_pass;
     103    this.proxy_user = proxy_user;
     104    this.mummy = mummy;
     105
     106    progress = new GProgressBar(this, initial.toString(), simple);
     107
     108    encountered_urls = new Vector();
     109    failed_urls = new Vector();
     110
     111    previous_state = STOPPED;
     112    state = STOPPED;
     113    }
     114
     115    /** Depending on which button on the progress bar was pushed,
     116     * this method will affect the state of the Job and perhaps make
     117     * calls to wget.class if necessary.
     118     * @param event The ActionEvent fired from within the GProgressBar
     119     * which we must respond to.
     120     */
     121    public void actionPerformed(ActionEvent event) {
     122    // The action button is used to alternately start or stop the
     123    // job. If the current state of the job is paused then this
     124    // restart is logically equivelent to a resume.
     125    if(event.getSource() == progress.action) {
     126        previous_state = state;
     127        if(state == RUNNING) {
     128        state = PAUSED;
     129        }
     130        else {
     131        state = RUNNING;
     132        mummy.resumeThread();
     133        }
     134    }
     135    else if (event.getSource() == progress.cancel) {
     136        state = STOPPED; // Should already be stopped.
     137        mummy.deleteJob(this);
     138    }
     139    }
     140
     141    /** Called by the WGet native code to inform us of a new download starting.
     142     * @param url The url that is being downloaded, as a String.
     143     */
     144    public void addDownload(String raw_url) {
     145    if(!encountered_urls.contains(raw_url)) {
     146        encountered_urls.add(raw_url);
     147    }
     148    // Regardless create a new GURL
     149    current_url = raw_url;
     150    url = new GURL(raw_url);
     151    progress.addDownload(raw_url);
     152    }
     153
     154    /** Used to advise the Job of a newly parsed link. Its up to Job
     155     * to decide if it already knows about this url, and if not to
     156     * update its progress bar.
     157     * @param url The url in question as a String.
     158     * @param type Whether the link is an internal or external link.
     159     * @return A boolean indicating if the url was added.
     160     */
     161    public boolean addLink(String raw_url, int type) {
     162    ///ystem.out.println("addLink("+url+", "+type+")");
     163    if(!encountered_urls.contains(raw_url)) {
    164164                // Add it to the urls we've seen.
    165                 encountered_urls.add(raw_url);
     165        encountered_urls.add(raw_url);
    166166                // Add it the to links for the current GURL.
    167167
    168168                // Add it to the progress file count.
    169                 progress.increaseFileCount();
    170                 return true;
    171           }
    172           // Regardless add it to the children links of the current GURL
    173           initial.addLink(raw_url);
    174 
    175           // We've seen it before. Don't count it again.
    176           return false;
    177     }
    178 
    179     public void callWGet() {
    180           // Build parameter string
    181           String command = "wget ";
    182 
    183           // Parse arguments into array.
    184           // Always:
    185           // rewrite links to be local if possible - NOOOOOO,
    186           // output a debug file and debug messages,
    187           // run quietly.
    188           //command = command + "-k ";
    189 
    190           if(destination != null) {
    191             command = command + "-P " + destination + " ";
    192           }
    193 
    194           if(depth < 0) {
     169        progress.increaseFileCount();
     170        return true;
     171    }
     172    // Regardless add it to the children links of the current GURL
     173    initial.addLink(raw_url);
     174
     175    // We've seen it before. Don't count it again.
     176    return false;
     177    }
     178
     179    public void callWGet() {
     180    // Build parameter string
     181    String command = "wget ";
     182
     183    // Parse arguments into array.
     184    // Always:
     185    // rewrite links to be local if possible - NOOOOOO,
     186    // output a debug file and debug messages,
     187    // run quietly.
     188    //command = command + "-k ";
     189
     190    if(destination != null) {
     191        command = command + "-P " + destination + " ";
     192    }
     193
     194    if(depth < 0) {
    195195                // Infinite recursion
    196                 command = command + "-r ";
    197           }
    198           else if (depth == 0) {
     196        command = command + "-r ";
     197    }
     198    else if (depth == 0) {
    199199                // Just this page.
    200           }
    201           else if (depth > 0) {
     200    }
     201    else if (depth > 0) {
    202202                // Recursion to the specified depth.
    203                 command = command + "-r -l" + depth + " ";
    204           }
    205 
    206           if(!clobber || previous_state == Job.PAUSED) {
    207                 command = command + "-nc -c ";
    208           }
    209 
    210           if(proxy_user != null) {
    211                 command = command + "--proxy-user=" + proxy_user
    212                      + " --proxy-passwd=" + proxy_pass + " ";
    213           }
     203        command = command + "-r -l" + depth + " ";
     204    }
     205
     206    if(!clobber || previous_state == Job.PAUSED) {
     207        command = command + "-nc -c ";
     208    }
     209
     210    if(proxy_user != null) {
     211        command = command + "--proxy-user=" + proxy_user
     212        + " --proxy-passwd=" + proxy_pass + " ";
     213    }
    214214         
    215           if(page_requisites) {
    216                 command = command + "-p ";
    217           }
    218 
    219           if(other_hosts) {
    220                 command = command + "-H ";
    221           }
    222 
    223           // Finally tell it the site to download.
    224           command = command + initial.toString();
    225 
    226           if(previous_state == Job.COMPLETE) {
    227                 progress.mirrorBegun(true);
    228           }
    229           else {
    230                 progress.mirrorBegun(false);
    231           }       
    232 
    233           // Run it
    234           try {
    235                 Gatherer.println("Cmd: " + command);
    236                 Runtime rt = Runtime.getRuntime();
    237                 Process prcs = rt.exec(command);
    238                 InputStreamReader isr =
    239                      new InputStreamReader( prcs.getErrorStream() );
    240                 BufferedReader br = new BufferedReader( isr );
     215    if(page_requisites) {
     216        command = command + "-p ";
     217    }
     218
     219    if(other_hosts) {
     220        command = command + "-H ";
     221    }
     222
     223    // Finally tell it the site to download.
     224    command = command + initial.toString();
     225
     226    if(previous_state == Job.COMPLETE) {
     227        progress.mirrorBegun(true);
     228    }
     229    else {
     230        progress.mirrorBegun(false);
     231    }         
     232
     233    // Run it
     234    try {
     235        Gatherer.println("Cmd: " + command);
     236        Runtime rt = Runtime.getRuntime();
     237        Process prcs = rt.exec(command);
     238        InputStreamReader isr =
     239        new InputStreamReader( prcs.getErrorStream() );
     240        BufferedReader br = new BufferedReader( isr );
    241241                // Capture the standard error stream and seach for two particular
    242242                // occurances.
    243                 String line;
    244                 boolean ignore_for_robots = false;
    245                 while ((line = br.readLine()) != null) {
    246                      Gatherer.println(line);
    247 
    248                      // The first magic special test is to see if we've just
    249                      // asked for the robots.txt file. If so we ignore
    250                      // the next add and then the next complete/error.
    251                      if(line.lastIndexOf("robots.txt;") != -1) {
    252                           Gatherer.println("***** Requesting robot.txt");
    253                           ignore_for_robots = true;
    254                      }
    255                      // If line contains "=> `" display text as the
    256                      // currently downloading url. Unique to add download.
    257                      else if(line.lastIndexOf("=> `") != -1) {
    258                           if(!ignore_for_robots) {
    259                                 // Add download
    260                                 String new_url =
    261                                     line.substring(line.indexOf("`") + 1,
    262                                                         line.lastIndexOf("'"));
    263                                 // Remove the destination guff
    264                                 if(destination != null) {
    265                                     new_url = new_url.substring(destination.length());
    266                                 }
    267                                 addDownload("http:/" + new_url);
    268                           }
    269                      }
    270                      // If line contains "saved [<size>]" set currently
    271                      // downloading url to "Download Complete".
    272                      else if(line.lastIndexOf(") - `") != -1) {
    273                           if(!ignore_for_robots) {
    274                                 // Download complete
    275                                 downloadComplete();
    276                           }
    277                           else {
    278                                 ignore_for_robots = false;
    279                           }
    280                      }
    281                      // The already there line begins "File `..." However this
    282                      // is only true in english, so instead I looked and there
    283                      // are few (if any at all) other messages than those above
    284                      // and not overwriting messages that use " `" so we'll
    285                      // look for that. Note this method is not guarenteed to be
    286                      // unique like the previous two.
    287                      else if(line.lastIndexOf(" `") != -1) {
    288                           // Not Overwriting
    289                           Gatherer.println("Already there.");
    290                           String new_url =
    291                                 line.substring(line.indexOf("`") + 1,
    292                                                     line.lastIndexOf("'"));
    293                           // Remove the destination guff
    294                           if(destination != null) {
    295                                 new_url = new_url.substring(destination.length());
    296                           }
    297                           addDownload("http:/" + new_url);
    298                           downloadWarning();
    299                      }
    300                      // Any other important message starts with the time in the form hh:mm:ss
    301                      else if(line.length() > 7) {
    302                           if(line.charAt(2) == ':' && line.charAt(5) == ':') {
    303                                 if(!ignore_for_robots) {
    304                                     Gatherer.println("Error.");
    305                                     downloadFailed();
    306                                 }
    307                                 else {
    308                                     ignore_for_robots = false;
    309                                 }
    310                           }
    311                      }
    312                 }
     243        String line;
     244        boolean ignore_for_robots = false;
     245        while ((line = br.readLine()) != null) {
     246        Gatherer.println(line);
     247
     248        // The first magic special test is to see if we've just
     249        // asked for the robots.txt file. If so we ignore
     250        // the next add and then the next complete/error.
     251        if(line.lastIndexOf("robots.txt;") != -1) {
     252            Gatherer.println("***** Requesting robot.txt");
     253            ignore_for_robots = true;
     254        }
     255        // If line contains "=> `" display text as the
     256        // currently downloading url. Unique to add download.
     257        else if(line.lastIndexOf("=> `") != -1) {
     258            if(!ignore_for_robots) {
     259            // Add download
     260            String new_url =
     261                line.substring(line.indexOf("`") + 1,
     262                      line.lastIndexOf("'"));
     263            // Remove the destination guff
     264            if(destination != null) {
     265                new_url = new_url.substring(destination.length());
     266            }
     267            addDownload("http:/" + new_url);
     268            }
     269        }
     270        // If line contains "saved [<size>]" set currently
     271        // downloading url to "Download Complete".
     272        else if(line.lastIndexOf(") - `") != -1) {
     273            if(!ignore_for_robots) {
     274            // Download complete
     275            downloadComplete();
     276            }
     277            else {
     278            ignore_for_robots = false;
     279            }
     280        }
     281        // The already there line begins "File `..." However this
     282        // is only true in english, so instead I looked and there
     283        // are few (if any at all) other messages than those above
     284        // and not overwriting messages that use " `" so we'll
     285        // look for that. Note this method is not guarenteed to be
     286        // unique like the previous two.
     287        else if(line.lastIndexOf(" `") != -1) {
     288            // Not Overwriting
     289            Gatherer.println("Already there.");
     290            String new_url =
     291            line.substring(line.indexOf("`") + 1,
     292                       line.lastIndexOf("'"));
     293            // Remove the destination guff
     294            if(destination != null) {
     295            new_url = new_url.substring(destination.length());
     296            }
     297            addDownload("http:/" + new_url);
     298            downloadWarning();
     299        }
     300        // Any other important message starts with the time in the form hh:mm:ss
     301        else if(line.length() > 7) {
     302            if(line.charAt(2) == ':' && line.charAt(5) == ':') {
     303            if(!ignore_for_robots) {
     304                Gatherer.println("Error.");
     305                downloadFailed();
     306            }
     307            else {
     308                ignore_for_robots = false;
     309            }
     310            }
     311        }
     312        }
    313313                // Now display final message based on exit value
    314                 prcs.waitFor();
    315           } catch (Exception ioe) {
     314        prcs.waitFor();
     315    } catch (Exception ioe) {
    316316                //message(Utility.ERROR, ioe.toString());
    317                 Gatherer.printStackTrace(ioe);
    318           }
    319           // If we've got to here and the state isn't STOPPED then the
    320           // job is complete.
    321           if(state == Job.RUNNING) {
    322                 progress.mirrorComplete();
    323                 previous_state = state;
    324                 state = Job.COMPLETE;
    325           }
    326     }
    327 
    328     /** The most important part of the Job class, this method is
    329       * responsible for calling the WGet native methods used to
    330       * mirror the indicated url. By this stage all the variables
    331       * necessary should be set and we need only build up the
    332       * parameter string and make the call.
    333       */
    334     public void callWGetNative() {
    335           Vector args = new Vector();
    336 
    337           // Let the GProgressBar know we're starting, just in case
    338           // the user hasn't told us to. If this is the second time the
    339           // urls downloaded and the first attempt was successful (ie
    340           // the previous job was complete), then we have the case where
    341           // the user is forcing us to remirror. Reset all the values etc
    342           // if this is the case then reset the variables.
    343           // Note that this can cause the result line to look something
    344           // like this.
    345           // Downloaded 12 of 12 files (8 warnings, 0 errors).
    346           // The warnings would be something like, 'File already downloaded'
    347           // but the total number of files and the file successfully
    348           // downloaded will be correct.
    349           if(previous_state == Job.COMPLETE) {
    350                 progress.mirrorBegun(true);
    351           }
    352           else {
    353                 progress.mirrorBegun(false);
    354           }
    355 
    356           // Parse arguments into array.
    357           args.add(Utility.BASE_DIR + "wget");
    358           //args.add("-k");
    359           args.add("-d");
    360           args.add("-o");
    361           args.add("debug.txt");
     317        Gatherer.printStackTrace(ioe);
     318    }
     319    // If we've got to here and the state isn't STOPPED then the
     320    // job is complete.
     321    if(state == Job.RUNNING) {
     322        progress.mirrorComplete();
     323        previous_state = state;
     324        state = Job.COMPLETE;
     325    }
     326    }
     327
     328    /** The most important part of the Job class, this method is
     329     * responsible for calling the WGet native methods used to
     330     * mirror the indicated url. By this stage all the variables
     331     * necessary should be set and we need only build up the
     332     * parameter string and make the call.
     333     */
     334    public void callWGetNative() {
     335    Vector args = new Vector();
     336
     337    // Let the GProgressBar know we're starting, just in case
     338    // the user hasn't told us to. If this is the second time the
     339    // urls downloaded and the first attempt was successful (ie
     340    // the previous job was complete), then we have the case where
     341    // the user is forcing us to remirror. Reset all the values etc
     342    // if this is the case then reset the variables.
     343    // Note that this can cause the result line to look something
     344    // like this.
     345    // Downloaded 12 of 12 files (8 warnings, 0 errors).
     346    // The warnings would be something like, 'File already downloaded'
     347    // but the total number of files and the file successfully
     348    // downloaded will be correct.
     349    if(previous_state == Job.COMPLETE) {
     350        progress.mirrorBegun(true);
     351    }
     352    else {
     353        progress.mirrorBegun(false);
     354    }
     355
     356    // Parse arguments into array.
     357    args.add(Utility.BASE_DIR + "wget");
     358    //args.add("-k");
     359    args.add("-d");
     360    args.add("-o");
     361    args.add("debug.txt");
    362362         
    363           if(destination != null) {
    364             args.add("-P");
    365             args.add(destination);
    366           }
    367 
    368           if(depth < 0) {
     363    if(destination != null) {
     364        args.add("-P");
     365        args.add(destination);
     366    }
     367
     368    if(depth < 0) {
    369369                // Infinite recursion
    370                 args.add("-r");
    371           }
    372           else if (depth == 0) {
     370        args.add("-r");
     371    }
     372    else if (depth == 0) {
    373373                // Just this page.
    374           }
    375           else if (depth > 0) {
     374    }
     375    else if (depth > 0) {
    376376                // Recursion to the specified depth.
    377                 args.add("-r");
    378                 args.add("-l");
    379                 args.add("" + depth + ""); // Hacky
    380           }
    381 
    382           if(!clobber || previous_state == PAUSED) {
    383                 args.add("-nc");
    384                 args.add("-c");
    385           }
    386 
    387           if(proxy_user != null) {
    388                 args.add("--proxy-user=" + proxy_user);
    389                 args.add("--proxy-passwd=" + proxy_pass);
    390           }
     377        args.add("-r");
     378        args.add("-l");
     379        args.add("" + depth + ""); // Hacky
     380    }
     381
     382    if(!clobber || previous_state == PAUSED) {
     383        args.add("-nc");
     384        args.add("-c");
     385    }
     386
     387    if(proxy_user != null) {
     388        args.add("--proxy-user=" + proxy_user);
     389        args.add("--proxy-passwd=" + proxy_pass);
     390    }
    391391         
    392           if(page_requisites) {
    393                 args.add("-p");
    394           }
    395 
    396           if(quiet) {
    397             args.add("-q");
    398           }
    399 
    400           if(other_hosts) {
    401             args.add("-H");
    402           }
    403 
    404           args.add(initial.toString());
    405 
    406           Gatherer.println("Calling wget ");
    407           for(Enumeration e = args.elements(); e.hasMoreElements();) {
    408                 Gatherer.println(e.nextElement() + " ");
    409           }
    410           Gatherer.println("");
    411 
    412           // Run home to mummy.
    413           int value = mummy.wget(args.size(), args.toArray(), debug);
    414 
    415           // If we've got to here and the state isn't STOPPED then the job is complete.
    416           if(state == RUNNING) {
    417                 progress.mirrorComplete();
    418                 previous_state = state;
    419                 state = COMPLETE;
    420           }
    421     }
    422 
    423     /** Called by the WGet native code when the current download is
    424       * completed. In turn all download listeners are informed.
    425       */
    426     public void downloadComplete() {
    427           progress.downloadComplete();
    428           /* @todo
    429               model.add(url.getURL(), destination);
    430           */
    431           url = null;
    432           current_url = null;
    433     }
     392    if(page_requisites) {
     393        args.add("-p");
     394    }
     395
     396    if(quiet) {
     397        args.add("-q");
     398    }
     399
     400    if(other_hosts) {
     401        args.add("-H");
     402    }
     403
     404    args.add(initial.toString());
     405
     406    Gatherer.println("Calling wget ");
     407    for(Enumeration e = args.elements(); e.hasMoreElements();) {
     408        Gatherer.println(e.nextElement() + " ");
     409    }
     410    Gatherer.println("");
     411
     412    // Run home to mummy.
     413    int value = mummy.wget(args.size(), args.toArray(), debug);
     414
     415    // If we've got to here and the state isn't STOPPED then the job is complete.
     416    if(state == RUNNING) {
     417        progress.mirrorComplete();
     418        previous_state = state;
     419        state = COMPLETE;
     420    }
     421    }
     422
     423    /** Called by the WGet native code when the current download is
     424     * completed. In turn all download listeners are informed.
     425     */
     426    public void downloadComplete() {
     427    progress.downloadComplete();
     428    /* @todo
     429       model.add(url.getURL(), destination);
     430    */
     431    url = null;
     432    current_url = null;
     433    }
    434434     
    435     /** Called by the WGet native code when the requested download returns
    436       * a status code other than 200.
    437       */
    438     public void downloadFailed() {
    439           ///ystem.out.println("downloadFailed("+current_url+")");
    440           failed_urls.add(current_url); // Its the current url thats failed.
    441           progress.downloadFailed();
    442     }
     435    /** Called by the WGet native code when the requested download returns
     436     * a status code other than 200.
     437     */
     438    public void downloadFailed() {
     439    ///ystem.out.println("downloadFailed("+current_url+")");
     440    failed_urls.add(current_url); // Its the current url thats failed.
     441    progress.downloadFailed();
     442    }
    443443     
    444     /**
    445       */
    446     public void downloadWarning() {
    447           progress.downloadWarning();
    448     }
    449 
    450     /**
    451       * @return A String representing the currently downloading url.
    452       */
    453     public String getCurrent() {
    454           return current_url;
    455     }
    456 
    457     /**
    458       * @return A String representing the initial urls host (root node
    459       * of tree that we are mirroring).
    460       */
    461     public String getHost() {
    462           return url.getHost();
    463     }
    464 
    465   /**
    466     * @return Returns the progress bar associated with this job.
    467     */
    468   public GProgressBar getProgressBar() {
    469      return progress;
    470   }
    471 
    472     /** Called to discover if the user wanted this thread to run or if
    473       * it is paused.
    474       * @return An int representing the current Job state.
    475       */
    476     public int getState() {
    477           return state;
    478     }
    479 
    480     /** Returns the current state of the stop flag for this job.
    481       * @return A boolean representing whether the user has requested to
    482       * stop.
    483       */
    484     public boolean hasSignalledStop() {
    485           if(state == Job.STOPPED || state == Job.PAUSED ||
    486               state == Job.COMPLETE) {
    487                 return true;
    488           }
    489           return false;
    490     }
    491 
    492     /** A convinence call.
    493       * @return A String representing the url of the initial url (root node of the mirrored tree).
    494       */
    495     public String toString() {
    496           return initial.toString();
    497     }
    498 
    499     /** Called by the WGet native code to signal the current progress of
    500       * downloading.
    501       * @param current A long representing the number of bytes that have
    502       * been downloaded since the last update.
    503       * @param expected A long representing the total number of bytes
    504       * expected for this download.
    505       */
    506     public void updateProgress(long current, long expected) {
    507         progress.updateProgress(current, expected);
    508     }
     444    /**
     445     */
     446    public void downloadWarning() {
     447    progress.downloadWarning();
     448    }
     449
     450    /**
     451     * @return A String representing the currently downloading url.
     452     */
     453    public String getCurrent() {
     454    return current_url;
     455    }
     456
     457    /**
     458     * @return A String representing the initial urls host (root node
     459     * of tree that we are mirroring).
     460     */
     461    public String getHost() {
     462    return url.getHost();
     463    }
     464
     465    /**
     466     * @return Returns the progress bar associated with this job.
     467     */
     468    public GProgressBar getProgressBar() {
     469    return progress;
     470    }
     471
     472    /** Called to discover if the user wanted this thread to run or if
     473     * it is paused.
     474     * @return An int representing the current Job state.
     475     */
     476    public int getState() {
     477    return state;
     478    }
     479
     480    /** Returns the current state of the stop flag for this job.
     481     * @return A boolean representing whether the user has requested to
     482     * stop.
     483     */
     484    public boolean hasSignalledStop() {
     485    if(state == Job.STOPPED || state == Job.PAUSED ||
     486       state == Job.COMPLETE) {
     487        return true;
     488    }
     489    return false;
     490    }
     491
     492    /** A convinence call.
     493     * @return A String representing the url of the initial url (root node of the mirrored tree).
     494     */
     495    public String toString() {
     496    return initial.toString();
     497    }
     498
     499    /** Called by the WGet native code to signal the current progress of
     500     * downloading.
     501     * @param current A long representing the number of bytes that have
     502     * been downloaded since the last update.
     503     * @param expected A long representing the total number of bytes
     504     * expected for this download.
     505     */
     506    public void updateProgress(long current, long expected) {
     507    progress.updateProgress(current, expected);
     508    }
    509509}
    510510
  • trunk/gli/src/org/greenstone/gatherer/collection/LoadCollectionBox.java

    r4293 r4366  
    4949public class LoadCollectionBox {
    5050
    51     private JFileChooser chooser = null;
    52     public LoadCollectionBox() {
    53     }
     51    private JFileChooser chooser = null;
     52    public LoadCollectionBox() {
     53    }
    5454
    55     public String getFileName() {
    56           String defaultPath = Utility.getCollectionDir(Gatherer.config.gsdl_path);
    57           chooser = new JFileChooser(new File(defaultPath));
    58           chooser.setDialogTitle(Gatherer.dictionary.get("SaveCollectionBox.Title"));
    59           ExtensionFileFilter filter1 = new ExtensionFileFilter(".col", Gatherer.dictionary.get("General.File_Description"));
    60           chooser.setFileFilter(filter1);
    61           chooser.setAcceptAllFileFilterUsed(false);
    62           int return_val = chooser.showOpenDialog(null);
    63           if(return_val == JFileChooser.APPROVE_OPTION) {
    64                 return chooser.getSelectedFile().getAbsolutePath();
    65           }
    66           else {
    67                 return null;
    68           }
    69     }
     55    public String getFileName() {
     56    String defaultPath = Utility.getCollectionDir(Gatherer.config.gsdl_path);
     57    chooser = new JFileChooser(new File(defaultPath));
     58    chooser.setDialogTitle(Gatherer.dictionary.get("SaveCollectionBox.Title"));
     59    ExtensionFileFilter filter1 = new ExtensionFileFilter(".col", Gatherer.dictionary.get("General.File_Description"));
     60    chooser.setFileFilter(filter1);
     61    chooser.setAcceptAllFileFilterUsed(false);
     62    int return_val = chooser.showOpenDialog(null);
     63    if(return_val == JFileChooser.APPROVE_OPTION) {
     64        return chooser.getSelectedFile().getAbsolutePath();
     65    }
     66    else {
     67        return null;
     68    }
     69    }
    7070}
  • trunk/gli/src/org/greenstone/gatherer/collection/SaveCollectionBox.java

    r4293 r4366  
    4242/** Provides a prompt allowing the user some choice in whether a collection saves. */
    4343public class SaveCollectionBox
    44     extends JDialog
    45     implements ActionListener{
    46     /** What option the user has choosen. */
    47     private int result = 0;
    48     /** Button to cancel prompt, no save. */
    49     private JButton cancel = null;
    50     /** Button for no save. */
    51     private JButton no = null;
    52     /** Button to save. */
    53     private JButton yes = null;
    54     /** A reference to ourselves so our inner classes can dispose of us. */
    55     private SaveCollectionBox myself = null;
    56     /** Result value if the user has choosen cancel. */
    57     static final public int SAVE_CANCEL  = 0;
    58     /** Result value if the user has choosen no. */
    59     static final public int SAVE_NO      = 1;
    60     /** Result value if the user has choosen yes. */
    61     static final public int SAVE_YES     = 2;
    62     /** Construtor. */
    63     public SaveCollectionBox() {
    64           super(Gatherer.g_man);
    65           this.myself = this;
    66           result = SAVE_CANCEL;
    67           // Dialog setup
    68           this.setModal(true);
    69           this.setTitle(get("Title"));
    70           this.setSize(360,100);
    71     }
    72     /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured. In this case we see what button the users clicked, set the appropriate result then dispose of the dialog. */
    73     public void actionPerformed(ActionEvent event) {
    74           if(event.getSource() == yes) {
    75                 result = SAVE_YES;
    76                 this.dispose();
    77           } else if(event.getSource() == no) {
    78                 result = SAVE_NO;
    79                 this.dispose();
    80           } else if(event.getSource() == cancel) {
    81                 result = SAVE_CANCEL;
    82                 this.dispose();
    83           }
    84     }
    85     /** Destructor. */
    86     public void destroy() {
    87           cancel = null;
    88           no.removeActionListener(this);
    89           no = null;
    90           yes.removeActionListener(this);
    91           yes = null;
    92           myself = null;
    93           rootPane = null;
    94     }
    95     /** Displays the prompt by first building the controls, then waits for a user selection.
     44    extends JDialog
     45    implements ActionListener{
     46    /** What option the user has choosen. */
     47    private int result = 0;
     48    /** Button to cancel prompt, no save. */
     49    private JButton cancel = null;
     50    /** Button for no save. */
     51    private JButton no = null;
     52    /** Button to save. */
     53    private JButton yes = null;
     54    /** A reference to ourselves so our inner classes can dispose of us. */
     55    private SaveCollectionBox myself = null;
     56    /** Result value if the user has choosen cancel. */
     57    static final public int SAVE_CANCEL  = 0;
     58    /** Result value if the user has choosen no. */
     59    static final public int SAVE_NO      = 1;
     60    /** Result value if the user has choosen yes. */
     61    static final public int SAVE_YES     = 2;
     62    /** Construtor. */
     63    public SaveCollectionBox() {
     64    super(Gatherer.g_man);
     65    this.myself = this;
     66    result = SAVE_CANCEL;
     67    // Dialog setup
     68    this.setModal(true);
     69    this.setTitle(get("Title"));
     70    this.setSize(360,100);
     71    }
     72    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured. In this case we see what button the users clicked, set the appropriate result then dispose of the dialog. */
     73    public void actionPerformed(ActionEvent event) {
     74    if(event.getSource() == yes) {
     75        result = SAVE_YES;
     76        this.dispose();
     77    } else if(event.getSource() == no) {
     78        result = SAVE_NO;
     79        this.dispose();
     80    } else if(event.getSource() == cancel) {
     81        result = SAVE_CANCEL;
     82        this.dispose();
     83    }
     84    }
     85    /** Destructor. */
     86    public void destroy() {
     87    cancel = null;
     88    no.removeActionListener(this);
     89    no = null;
     90    yes.removeActionListener(this);
     91    yes = null;
     92    myself = null;
     93    rootPane = null;
     94    }
     95    /** Displays the prompt by first building the controls, then waits for a user selection.
    9696      * @param name The name of the current collection as a <strong>String</strong>.
    9797      */
    98     public int getUserOption(String name) {
    99           JPanel content_pane = (JPanel) this.getContentPane();
    100           content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    101           content_pane.setLayout(new GridLayout(2,1));
     98    public int getUserOption(String name) {
     99    JPanel content_pane = (JPanel) this.getContentPane();
     100    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     101    content_pane.setLayout(new GridLayout(2,1));
    102102
    103           String args[] = new String[1];
    104           args[0] = name;
    105           JLabel save_label = new JLabel(get("Label", args));
    106           content_pane.add(save_label);
    107           JPanel button_pane = new JPanel(new GridLayout(1,3));
    108           content_pane.add(button_pane);
    109           // We add both mnemonics and key listener so that the 'y' of yes is underlined, but pressing just [Y] (rather than [CTL]-[Y]) performs a systematic click.
    110           yes = new JButton(get("General.Yes"));
    111           yes.addActionListener(this);
    112           KeyListenerImpl key_listener = new KeyListenerImpl();
    113           yes.addKeyListener(key_listener);
    114           yes.setMnemonic(KeyEvent.VK_Y);
    115           button_pane.add(yes);
    116           no = new JButton(get("General.No"));
    117           no.addActionListener(this);
    118           no.addKeyListener(key_listener);
    119           no.setMnemonic(KeyEvent.VK_N);
    120           button_pane.add(no);
    121           cancel = new JButton(get("General.Cancel"));
    122           cancel.addActionListener(this);
    123           cancel.addKeyListener(key_listener);
    124           cancel.setMnemonic(KeyEvent.VK_C);
    125           button_pane.add(cancel);
    126           // Center on screen.
    127           Dimension dlgSize = getSize();
    128           Dimension frmSize = Gatherer.g_man.getSize();
    129           Point loc = Gatherer.g_man.getLocation();
    130           setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
    131           show();
    132           // Deallocate things we allocated here.
    133           yes.removeKeyListener(key_listener);
    134           no.removeKeyListener(key_listener);
    135           cancel.removeKeyListener(key_listener);
    136           key_listener = null;
    137           content_pane = null;
    138           args = null;
    139           save_label = null;
    140           button_pane = null;
    141           dlgSize = null;
    142           frmSize = null;
    143           loc = null;
    144           return result;
    145     }
    146     /** Method to retrieve a phrase from the dictionary based of a key.
     103    String args[] = new String[1];
     104    args[0] = name;
     105    JLabel save_label = new JLabel(get("Label", args));
     106    content_pane.add(save_label);
     107    JPanel button_pane = new JPanel(new GridLayout(1,3));
     108    content_pane.add(button_pane);
     109    // We add both mnemonics and key listener so that the 'y' of yes is underlined, but pressing just [Y] (rather than [CTL]-[Y]) performs a systematic click.
     110    yes = new JButton(get("General.Yes"));
     111    yes.addActionListener(this);
     112    KeyListenerImpl key_listener = new KeyListenerImpl();
     113    yes.addKeyListener(key_listener);
     114    yes.setMnemonic(KeyEvent.VK_Y);
     115    button_pane.add(yes);
     116    no = new JButton(get("General.No"));
     117    no.addActionListener(this);
     118    no.addKeyListener(key_listener);
     119    no.setMnemonic(KeyEvent.VK_N);
     120    button_pane.add(no);
     121    cancel = new JButton(get("General.Cancel"));
     122    cancel.addActionListener(this);
     123    cancel.addKeyListener(key_listener);
     124    cancel.setMnemonic(KeyEvent.VK_C);
     125    button_pane.add(cancel);
     126    // Center on screen.
     127    Dimension dlgSize = getSize();
     128    Dimension frmSize = Gatherer.g_man.getSize();
     129    Point loc = Gatherer.g_man.getLocation();
     130    setLocation((frmSize.width - dlgSize.width) / 2 + loc.x, (frmSize.height - dlgSize.height) / 2 + loc.y);
     131    show();
     132    // Deallocate things we allocated here.
     133    yes.removeKeyListener(key_listener);
     134    no.removeKeyListener(key_listener);
     135    cancel.removeKeyListener(key_listener);
     136    key_listener = null;
     137    content_pane = null;
     138    args = null;
     139    save_label = null;
     140    button_pane = null;
     141    dlgSize = null;
     142    frmSize = null;
     143    loc = null;
     144    return result;
     145    }
     146    /** Method to retrieve a phrase from the dictionary based of a key.
    147147      * @param key A <strong>String</strong> used to find the correct phrase.
    148148      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    149149      */
    150     private String get(String key) {
    151           return get(key, null);
    152     }
    153     /** Method to retrieve a phrase from the dictionary based of a key and including arguments.
     150    private String get(String key) {
     151    return get(key, null);
     152    }
     153    /** Method to retrieve a phrase from the dictionary based of a key and including arguments.
    154154      * @param key A <strong>String</strong> used to find the correct phrase.
    155155      * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
    156156      * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
    157157      */
    158     private String get(String key, String args[]) {
    159           if(key.indexOf('.') == -1) {
    160                 key = "SaveCollectionBox." + key;
    161           }
    162           return Gatherer.dictionary.get(key, args);
    163     }
    164     /** Listens for key presses when the focus is on one of the buttons. Note that the key pressed needn't be the one associated with the button in focus. */
    165     private class KeyListenerImpl
    166           extends KeyAdapter {
    167           /** Any extension of KeyAdapter can override this method so that we can be informed whenever a key is released (ie after a keyTyped event). In this case we map the key press to an appropriate click on one of the buttons (not necessarily the one the key release was detected on).
    168             * @param event A <strong>KeyEvent</strong> containing details about the key release event.
     158    private String get(String key, String args[]) {
     159    if(key.indexOf('.') == -1) {
     160        key = "SaveCollectionBox." + key;
     161    }
     162    return Gatherer.dictionary.get(key, args);
     163    }
     164    /** Listens for key presses when the focus is on one of the buttons. Note that the key pressed needn't be the one associated with the button in focus. */
     165    private class KeyListenerImpl
     166    extends KeyAdapter {
     167    /** Any extension of KeyAdapter can override this method so that we can be informed whenever a key is released (ie after a keyTyped event). In this case we map the key press to an appropriate click on one of the buttons (not necessarily the one the key release was detected on).
     168     * @param event A <strong>KeyEvent</strong> containing details about the key release event.
    169169            */
    170           public void keyReleased(KeyEvent event) {
    171                 if(event.getKeyCode() == KeyEvent.VK_Y) {
    172                      yes.doClick(10);
    173                 }
    174                 else if(event.getKeyCode() == KeyEvent.VK_N) {
    175                      no.doClick(10);
    176                 }
    177                 else if(event.getKeyCode() == KeyEvent.VK_C) {
    178                      cancel.doClick(10);
    179                 }
    180           }
    181     }
     170    public void keyReleased(KeyEvent event) {
     171        if(event.getKeyCode() == KeyEvent.VK_Y) {
     172        yes.doClick(10);
     173        }
     174        else if(event.getKeyCode() == KeyEvent.VK_N) {
     175        no.doClick(10);
     176        }
     177        else if(event.getKeyCode() == KeyEvent.VK_C) {
     178        cancel.doClick(10);
     179        }
     180    }
     181    }
    182182}
  • trunk/gli/src/org/greenstone/gatherer/collection/SaveCollectionTask.java

    r4293 r4366  
    5050 */
    5151public class SaveCollectionTask
    52     extends Thread {
    53     private boolean close_after = false;
    54     /** Should we exit the Gatherer once this save is complete. */
    55     private boolean exit_after = false;
    56     /** Do we run the import scripts once this save is complete. */
    57     private boolean import_after = false;
    58     /** The current collection. */
    59     private Collection collection = null;
    60     /** The filename of the collection we are saving. */
    61     private String name = null;
    62     static final private int CLOSE_COLLECTION     = 0;
    63     static final private int COLLECTION_COPIED    = 1;
    64     static final private int COLLECTION_SAVED     = 2;
    65     static final private int COLLECTION_CFG_SAVED = 3;
    66     static final private int COPY_COLLECTION      = 4;
    67     static final private int MAKE_COLLECTION      = 5;
    68     static final private int METADATA_SAVED       = 6;
    69     static final private int METADATA_XML_SAVED   = 7;
    70     static final private int OPEN_COLLECTION      = 8;
    71     static final private int RESTORE_COLLECTION   = 9;
    72     /** Constructor.
    73       * @param name The filename of the collection we are saving as.
    74       */
    75     public SaveCollectionTask(Collection collection) {
    76           this.collection = collection;
    77     }
    78     /** Constructor.
    79       * @param exit_after <i>true</i> to cause the Gatherer to exit once save is complete, <i>false</i> otherwise.
    80       */
    81     public SaveCollectionTask(Collection collection, boolean close_after, boolean exit_after) {
    82           this.close_after = close_after;
    83           this.collection = collection;
    84           this.exit_after = exit_after;
    85     }
    86     /** Constructor.
    87       * @param name The filename of the collection we are saving as.
    88       */
    89     public SaveCollectionTask(Collection collection, String name) {
    90           this.collection = collection;
    91           this.name = name;
    92     }
    93     /** <p>This method, when created in a forked process by start(), performs the actions necessary to save a collection. If this is a regular save it saves the state of the current collection, ensuring all files, metadata files, and configuration files are written to disk. If, instead, this is a "Save As" action then there as several more steps involved:</p>
    94       * <p>1. Perform a regular collection save on what we will later refer to as the origin collection.</p>
    95       * <p>2. Call CollectionManager.makeCollection() to create the collection structure to save into (copied collection).</p>
    96       * <p>3. Copy files from the origin to the copied collections (except special collection files ending with ~).</p>
    97       * <p>4. Restore origin collection by undoing file copy actions and removing the ~ from the end of collection files.</p>
    98       * <p>5. Close the origin collection.</p>
    99       * <p>6. Open the copied collection.</p>
    100       * <p>Of course all of this takes a while, and depends on several other bits of code to work properly.</p>.
    101       * @see org.greenstone.gatherer.collection.Collection
    102       * @see org.greenstone.gatherer.collection.CollectionModel
    103       * @see org.greenstone.gatherer.gui.GUIManager
    104       * @see org.greenstone.gatherer.gui.GConfigPane
    105       * @see org.greenstone.gatherer.msm.MetadataSetManager
    106       * @see org.greenstone.gatherer.util.Utility
    107       */
    108     public void run() {
    109           // Change cursor to hourglass.
    110           Gatherer.g_man.wait(true);
    111           // Create progress monitor box. It will display itself as necessary.
    112           ProgressMonitor spd = new ProgressMonitor(Gatherer.g_man, Gatherer.dictionary.get("SaveProgressDialog.Title", collection.getName()), null, 0, 100);
    113           spd.setMillisToDecideToPopup(100);
    114           spd.setMillisToPopup(100);
    115           // 0. Force all remaining metadata.xml files to load.
    116           // 1. Perform a regular collection save on what we will later refer to as the origin collection.
    117           ///ystem.err.println("1. Save origin.");
    118           String tmp_loc = Gatherer.c_man.getCollectionFilename();
    119           String args[] = new String[1];
    120           args[0] = collection.getName() + ".col";
    121           try {
     52    extends Thread {
     53    private boolean close_after = false;
     54    /** Should we exit the Gatherer once this save is complete. */
     55    private boolean exit_after = false;
     56    /** Do we run the import scripts once this save is complete. */
     57    private boolean import_after = false;
     58    /** The current collection. */
     59    private Collection collection = null;
     60    /** The filename of the collection we are saving. */
     61    private String name = null;
     62    static final private int CLOSE_COLLECTION     = 0;
     63    static final private int COLLECTION_COPIED    = 1;
     64    static final private int COLLECTION_SAVED     = 2;
     65    static final private int COLLECTION_CFG_SAVED = 3;
     66    static final private int COPY_COLLECTION      = 4;
     67    static final private int MAKE_COLLECTION      = 5;
     68    static final private int METADATA_SAVED       = 6;
     69    static final private int METADATA_XML_SAVED   = 7;
     70    static final private int OPEN_COLLECTION      = 8;
     71    static final private int RESTORE_COLLECTION   = 9;
     72    /** Constructor.
     73     * @param name The filename of the collection we are saving as.
     74     */
     75    public SaveCollectionTask(Collection collection) {
     76    this.collection = collection;
     77    }
     78    /** Constructor.
     79     * @param exit_after <i>true</i> to cause the Gatherer to exit once save is complete, <i>false</i> otherwise.
     80     */
     81    public SaveCollectionTask(Collection collection, boolean close_after, boolean exit_after) {
     82    this.close_after = close_after;
     83    this.collection = collection;
     84    this.exit_after = exit_after;
     85    }
     86    /** Constructor.
     87     * @param name The filename of the collection we are saving as.
     88     */
     89    public SaveCollectionTask(Collection collection, String name) {
     90    this.collection = collection;
     91    this.name = name;
     92    }
     93    /** <p>This method, when created in a forked process by start(), performs the actions necessary to save a collection. If this is a regular save it saves the state of the current collection, ensuring all files, metadata files, and configuration files are written to disk. If, instead, this is a "Save As" action then there as several more steps involved:</p>
     94     * <p>1. Perform a regular collection save on what we will later refer to as the origin collection.</p>
     95     * <p>2. Call CollectionManager.makeCollection() to create the collection structure to save into (copied collection).</p>
     96     * <p>3. Copy files from the origin to the copied collections (except special collection files ending with ~).</p>
     97     * <p>4. Restore origin collection by undoing file copy actions and removing the ~ from the end of collection files.</p>
     98     * <p>5. Close the origin collection.</p>
     99     * <p>6. Open the copied collection.</p>
     100     * <p>Of course all of this takes a while, and depends on several other bits of code to work properly.</p>.
     101     * @see org.greenstone.gatherer.collection.Collection
     102     * @see org.greenstone.gatherer.collection.CollectionModel
     103     * @see org.greenstone.gatherer.gui.GUIManager
     104     * @see org.greenstone.gatherer.gui.GConfigPane
     105     * @see org.greenstone.gatherer.msm.MetadataSetManager
     106     * @see org.greenstone.gatherer.util.Utility
     107     */
     108    public void run() {
     109    // Change cursor to hourglass.
     110    Gatherer.g_man.wait(true);
     111    // Create progress monitor box. It will display itself as necessary.
     112    ProgressMonitor spd = new ProgressMonitor(Gatherer.g_man, Gatherer.dictionary.get("SaveProgressDialog.Title", collection.getName()), null, 0, 100);
     113    spd.setMillisToDecideToPopup(100);
     114    spd.setMillisToPopup(100);
     115    // 0. Force all remaining metadata.xml files to load.
     116    // 1. Perform a regular collection save on what we will later refer to as the origin collection.
     117    ///ystem.err.println("1. Save origin.");
     118    String tmp_loc = Gatherer.c_man.getCollectionFilename();
     119    String args[] = new String[1];
     120    args[0] = collection.getName() + ".col";
     121    try {
    122122                // Block until all of the metadata files have been read in.
    123                 collection.gdm.waitUntilComplete();
     123        collection.gdm.waitUntilComplete();
    124124                // Write out the metadata xml files. The destroy below is meant to do this, but never does.
    125                 collection.gdm.save();
     125        collection.gdm.save();
    126126               
    127                 spd.setProgress(getValue(METADATA_XML_SAVED));
    128                 File file = new File(tmp_loc);
     127        spd.setProgress(getValue(METADATA_XML_SAVED));
     128        File file = new File(tmp_loc);
    129129                // Create backup
    130                 if(file.exists()) {
    131                      File backup = new File(tmp_loc + "~");
    132                      backup.deleteOnExit();
    133                      if(!file.renameTo(backup)) {
    134                           Gatherer.println("Error in CollectionManager.load(): FileNotRenamedException");
    135                      }
    136                 }
     130        if(file.exists()) {
     131        File backup = new File(tmp_loc + "~");
     132        backup.deleteOnExit();
     133        if(!file.renameTo(backup)) {
     134            Gatherer.println("Error in CollectionManager.load(): FileNotRenamedException");
     135        }
     136        }
    137137                // Carry on.
    138                 collection.save();
    139                 spd.setProgress(getValue(COLLECTION_SAVED));
     138        collection.save();
     139        spd.setProgress(getValue(COLLECTION_SAVED));
    140140                // Write out the collection configuration file.
    141                 Gatherer.g_man.config_pane.saveConfiguration();
    142                 spd.setProgress(getValue(COLLECTION_CFG_SAVED));
     141        Gatherer.g_man.config_pane.saveConfiguration();
     142        spd.setProgress(getValue(COLLECTION_CFG_SAVED));
    143143                // Write out the metadata files.
    144                 Gatherer.c_man.msm.save();
    145                 spd.setProgress(getValue(METADATA_SAVED));
     144        Gatherer.c_man.msm.save();
     145        spd.setProgress(getValue(METADATA_SAVED));
    146146                // Clean-up
    147                 spd.setProgress(100);
     147        spd.setProgress(100);
    148148                ///atherer.g_man.collectionChanged(Gatherer.c_man.ready());
    149                 collection.setSaved(true);
    150           }
    151           catch (Exception error) {
    152                 Gatherer.printStackTrace(error);
    153           }
    154           // Now we check whether we've finished, or is this a Save As action, in which case we've got miles to go.
    155           if(name != null) {
     149        collection.setSaved(true);
     150    }
     151    catch (Exception error) {
     152        Gatherer.printStackTrace(error);
     153    }
     154    // Now we check whether we've finished, or is this a Save As action, in which case we've got miles to go.
     155    if(name != null) {
    156156                // 2. Call CollectionManager.makeCollection() to create the collection structure to save into (copied collection).
    157157                ///ystem.err.println("2. Make copy.");
    158                 Gatherer.c_man.createCollection(null, null, name, null, null, null);
    159                 spd.setProgress(getValue(MAKE_COLLECTION));
     158        Gatherer.c_man.createCollection(null, null, name, null, null, null);
     159        spd.setProgress(getValue(MAKE_COLLECTION));
    160160                // 3. Copy files from the origin to the copied collections (except special collection files ending with ~).
    161161                // As part of this we must rename origin.col to copy.col
    162162                ///ystem.err.println("3. Copy origin.");
    163                 ArrayList files = new ArrayList();
    164                 File collection_file = new File(Gatherer.c_man.getCollectionFilename());
    165                 File copied_dir = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + name);
    166                 files.add(collection_file.getParentFile());
    167                 while(files.size() > 0) {
    168                      File file = (File) files.get(0);
    169                      files.remove(0);
    170                      if(file.isDirectory()) {
    171                           File children[] = file.listFiles();
    172                           for(int i = 0; i < children.length; i++) {
    173                                 files.add(children[i]);
    174                           }
    175                           children = null;
    176                      }
    177                      else {
    178                           // Rename origin.col file.
    179                           if(file.equals(collection_file)) {
    180                                 File copied_file = new File(copied_dir, name + ".col");
    181                                 copy(collection_file, copied_file);
    182                                 copied_file = null;
    183                           }
    184                           // Exclude *~ files from certain locations and lock.tmp file.
    185                           else if(!file.getName().endsWith("~") && !file.getName().equals(CollectionManager.LOCK_FILE)) {
    186                                 StringTokenizer origin = new StringTokenizer(file.getAbsolutePath(), File.separator);
    187                                 StringTokenizer destin = new StringTokenizer(copied_dir.getAbsolutePath(), File.separator);
    188                                 while(destin.hasMoreTokens()) {
    189                                     origin.nextToken();
    190                                     destin.nextToken();
    191                                 }
    192                                 File copied_file = new File(copied_dir.getAbsolutePath());
    193                                 while(origin.hasMoreTokens()) {
    194                                     copied_file = new File(copied_file, origin.nextToken());
    195                                 }
    196                                 copy(file, copied_file);
    197                                 copied_file = null;
    198                                 origin = null;
    199                                 destin = null;
    200                           }
    201                      }
    202                      file = null;
    203                 }
    204                 spd.setProgress(getValue(COPY_COLLECTION));
     163        ArrayList files = new ArrayList();
     164        File collection_file = new File(Gatherer.c_man.getCollectionFilename());
     165        File copied_dir = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path) + name);
     166        files.add(collection_file.getParentFile());
     167        while(files.size() > 0) {
     168        File file = (File) files.get(0);
     169        files.remove(0);
     170        if(file.isDirectory()) {
     171            File children[] = file.listFiles();
     172            for(int i = 0; i < children.length; i++) {
     173            files.add(children[i]);
     174            }
     175            children = null;
     176        }
     177        else {
     178            // Rename origin.col file.
     179            if(file.equals(collection_file)) {
     180            File copied_file = new File(copied_dir, name + ".col");
     181            copy(collection_file, copied_file);
     182            copied_file = null;
     183            }
     184            // Exclude *~ files from certain locations and lock.tmp file.
     185            else if(!file.getName().endsWith("~") && !file.getName().equals(CollectionManager.LOCK_FILE)) {
     186            StringTokenizer origin = new StringTokenizer(file.getAbsolutePath(), File.separator);
     187            StringTokenizer destin = new StringTokenizer(copied_dir.getAbsolutePath(), File.separator);
     188            while(destin.hasMoreTokens()) {
     189                origin.nextToken();
     190                destin.nextToken();
     191            }
     192            File copied_file = new File(copied_dir.getAbsolutePath());
     193            while(origin.hasMoreTokens()) {
     194                copied_file = new File(copied_file, origin.nextToken());
     195            }
     196            copy(file, copied_file);
     197            copied_file = null;
     198            origin = null;
     199            destin = null;
     200            }
     201        }
     202        file = null;
     203        }
     204        spd.setProgress(getValue(COPY_COLLECTION));
    205205                // 4. Restore origin collection by undoing file copy actions and removing the ~ from the end of collection files.
    206206                ///ystem.err.println("4. Restore origin.");
    207                 Gatherer.c_man.undo.undoAll();
     207        Gatherer.c_man.undo.undoAll();
    208208                ///ystem.err.println(" - UndoAll complete.");
    209209                // Recurse collection tree restoring *~
    210                 files.clear(); // Should be empty anyway.
    211                 files.add(collection_file.getParentFile());
    212                 while(files.size() > 0) {
    213                      File file = (File) files.get(0);
    214                      files.remove(0);
    215                      if(file.isDirectory()) {
    216                           File children[] = file.listFiles();
    217                           for(int i = 0; i < children.length; i++) {
    218                                 files.add(children[i]);
    219                           }
    220                           children = null;
    221                      }
    222                      else if(file.getName().endsWith("~")) {
    223                           String filename = file.getAbsolutePath();
    224                           File original_file = new File(filename.substring(0, filename.length() - 1));
    225                           ///ystem.err.println("Renaming " + filename);
    226                           if(!file.renameTo(original_file)) {
    227                                 Gatherer.println("Error in SaveCollectionTask.run(): FileRenameException");
    228                           }
    229                      }
    230                 }
     210        files.clear(); // Should be empty anyway.
     211        files.add(collection_file.getParentFile());
     212        while(files.size() > 0) {
     213        File file = (File) files.get(0);
     214        files.remove(0);
     215        if(file.isDirectory()) {
     216            File children[] = file.listFiles();
     217            for(int i = 0; i < children.length; i++) {
     218            files.add(children[i]);
     219            }
     220            children = null;
     221        }
     222        else if(file.getName().endsWith("~")) {
     223            String filename = file.getAbsolutePath();
     224            File original_file = new File(filename.substring(0, filename.length() - 1));
     225            ///ystem.err.println("Renaming " + filename);
     226            if(!file.renameTo(original_file)) {
     227            Gatherer.println("Error in SaveCollectionTask.run(): FileRenameException");
     228            }
     229        }
     230        }
    231231                ///ystem.err.println(" - Restore *~ complete.");
    232                 spd.setProgress(getValue(RESTORE_COLLECTION));
     232        spd.setProgress(getValue(RESTORE_COLLECTION));
    233233                // 5. Close the origin collection.
    234234                ///ystem.err.println("5. Close origin.");
    235                 collection.setSaved(true);
    236                 Gatherer.c_man.closeCollection();
    237                 spd.setProgress(getValue(CLOSE_COLLECTION));
     235        collection.setSaved(true);
     236        Gatherer.c_man.closeCollection();
     237        spd.setProgress(getValue(CLOSE_COLLECTION));
    238238                // 6. Open the copied collection.   
    239239                ///ystem.err.println("6. Open copy.");
    240                 Gatherer.c_man.loadCollection(copied_dir.getAbsolutePath() + File.separator + name + ".col");
    241                 spd.setProgress(getValue(OPEN_COLLECTION));
    242                 copied_dir = null;
    243           }
    244           spd.close();
    245           spd = null;
    246           tmp_loc = null;
    247           args = null;
    248           // Reset undo queue.
    249           if(Gatherer.c_man.ready()) {
    250                 Gatherer.c_man.undo.clear();
    251           }
    252           Gatherer.g_man.wait(false);
    253 
    254           // Now we are finished action any necessary action.
    255           if(import_after) {
    256                 Gatherer.c_man.importCollection();
    257           }
    258           if(close_after) {
    259                 Gatherer.c_man.closeCollection();
    260           }
    261           ///ystem.err.println("Save Complete.");
    262           if(exit_after) {
    263                 Gatherer.self.exit();
    264           }
    265     }
    266 
    267     public void setImportAfter(boolean state) {
    268           import_after = true;
    269     }
    270 
    271     private void copy(File source, File destination) {
    272           ///ystem.err.println("Copy: " + source.getAbsolutePath());
    273           ///ystem.err.println("  to: " + destination.getAbsolutePath());
    274           try {
    275                 destination.getParentFile().mkdirs();
    276                 FileInputStream f_in = new FileInputStream(source);
    277                 FileOutputStream f_out = new FileOutputStream(destination);
    278                 byte data[] = new byte[Utility.BUFFER_SIZE];
    279                 int data_size = 0;
    280                 while((data_size = f_in.read(data, 0, Utility.BUFFER_SIZE)) != -1) {
    281                      f_out.write(data, 0, data_size);
    282                 }
    283                 f_in.close();
    284                 f_out.close();
    285           }
    286           catch (Exception exception) {
    287                 Gatherer.printStackTrace(exception);
    288           }
    289     }
    290 
    291     private int getValue(int reference) {
    292           double multiplier;
    293           if(name == null) {
    294                 multiplier = 1.0;
    295           }
    296           else {
    297                 multiplier = 0.25;
    298           }
    299           switch(reference) {
    300           // Standard Save
    301           case COLLECTION_SAVED:
    302                 return (int)((double)70 * multiplier);
    303           case COLLECTION_CFG_SAVED:
    304           case METADATA_SAVED:
    305           case METADATA_XML_SAVED:
    306                 return (int)((double)10 * multiplier);
    307           // Save As
    308           case MAKE_COLLECTION:
    309                 return 5;
    310           case COPY_COLLECTION:
    311                 return 30;
    312           case RESTORE_COLLECTION:
    313                 return 30;
    314           case CLOSE_COLLECTION:
    315                 return 10;
    316           case OPEN_COLLECTION:
    317                 return 10;
    318           }
    319           return 0;
    320     }
     240        Gatherer.c_man.loadCollection(copied_dir.getAbsolutePath() + File.separator + name + ".col");
     241        spd.setProgress(getValue(OPEN_COLLECTION));
     242        copied_dir = null;
     243    }
     244    spd.close();
     245    spd = null;
     246    tmp_loc = null;
     247    args = null;
     248    // Reset undo queue.
     249    if(Gatherer.c_man.ready()) {
     250        Gatherer.c_man.undo.clear();
     251    }
     252    Gatherer.g_man.wait(false);
     253
     254    // Now we are finished action any necessary action.
     255    if(import_after) {
     256        Gatherer.c_man.importCollection();
     257    }
     258    if(close_after) {
     259        Gatherer.c_man.closeCollection();
     260    }
     261    ///ystem.err.println("Save Complete.");
     262    if(exit_after) {
     263        Gatherer.self.exit();
     264    }
     265    }
     266
     267    public void setImportAfter(boolean state) {
     268    import_after = true;
     269    }
     270
     271    private void copy(File source, File destination) {
     272    ///ystem.err.println("Copy: " + source.getAbsolutePath());
     273    ///ystem.err.println("  to: " + destination.getAbsolutePath());
     274    try {
     275        destination.getParentFile().mkdirs();
     276        FileInputStream f_in = new FileInputStream(source);
     277        FileOutputStream f_out = new FileOutputStream(destination);
     278        byte data[] = new byte[Utility.BUFFER_SIZE];
     279        int data_size = 0;
     280        while((data_size = f_in.read(data, 0, Utility.BUFFER_SIZE)) != -1) {
     281        f_out.write(data, 0, data_size);
     282        }
     283        f_in.close();
     284        f_out.close();
     285    }
     286    catch (Exception exception) {
     287        Gatherer.printStackTrace(exception);
     288    }
     289    }
     290
     291    private int getValue(int reference) {
     292    double multiplier;
     293    if(name == null) {
     294        multiplier = 1.0;
     295    }
     296    else {
     297        multiplier = 0.25;
     298    }
     299    switch(reference) {
     300        // Standard Save
     301    case COLLECTION_SAVED:
     302        return (int)((double)70 * multiplier);
     303    case COLLECTION_CFG_SAVED:
     304    case METADATA_SAVED:
     305    case METADATA_XML_SAVED:
     306        return (int)((double)10 * multiplier);
     307        // Save As
     308    case MAKE_COLLECTION:
     309        return 5;
     310    case COPY_COLLECTION:
     311        return 30;
     312    case RESTORE_COLLECTION:
     313        return 30;
     314    case CLOSE_COLLECTION:
     315        return 10;
     316    case OPEN_COLLECTION:
     317        return 10;
     318    }
     319    return 0;
     320    }
    321321}
    322322
  • trunk/gli/src/org/greenstone/gatherer/file/FileAlreadyExistsException.java

    r4293 r4366  
    44
    55public class FileAlreadyExistsException
    6     extends Exception {
     6    extends Exception {
    77
    8     public FileAlreadyExistsException() {
    9           super();
    10     }
     8    public FileAlreadyExistsException() {
     9    super();
     10    }
    1111}
  • trunk/gli/src/org/greenstone/gatherer/file/FileAssociation.java

    r4293 r4366  
    5555 */
    5656public class FileAssociation {
    57     /** The file extension, most likely three or four letters. */
    58     private String extension;
    59     /** The command string, which may include %1 which should be replaced with the target files name. */
    60     private String command;
    61     public FileAssociation(String extension, String command) {
    62           this.command = command;
    63           this.extension = extension;
    64     }
    65     /** Retrieve the command from this association.
    66       * @return The command as a <strong>String</strong>.
    67       */
    68     public String getCommand() {
    69           return command;
    70     }
    71     /** Retrieve the extension from this association.
    72       * @return The extension as a <strong>String</strong>.
    73       */
    74     public String getExtension() {
    75           return extension;
    76     }
    77     /** Set the command for this file association.
    78       * @param command The new command as a <strong>String</strong>.
    79       */
    80     public void setCommand(String command) {
    81           this.command = command;
    82     }
     57    /** The file extension, most likely three or four letters. */
     58    private String extension;
     59    /** The command string, which may include %1 which should be replaced with the target files name. */
     60    private String command;
     61    public FileAssociation(String extension, String command) {
     62    this.command = command;
     63    this.extension = extension;
     64    }
     65    /** Retrieve the command from this association.
     66     * @return The command as a <strong>String</strong>.
     67     */
     68    public String getCommand() {
     69    return command;
     70    }
     71    /** Retrieve the extension from this association.
     72     * @return The extension as a <strong>String</strong>.
     73     */
     74    public String getExtension() {
     75    return extension;
     76    }
     77    /** Set the command for this file association.
     78     * @param command The new command as a <strong>String</strong>.
     79     */
     80    public void setCommand(String command) {
     81    this.command = command;
     82    }
    8383}
  • trunk/gli/src/org/greenstone/gatherer/file/FileAssociationManager.java

    r4293 r4366  
    4949/** Provides a manager for relating a filetype to a command to open that filetype, and an optional icon. Under windows this will attempt to leverage the Windows Registry. If this fails, or under other platforms, the user will be prompted to enter the required details manually. This information will then be stored for any further sessions of the Gatherer. Of course the ability to edit these settings must also be provided. */
    5050public class FileAssociationManager
    51     extends HashMap {
     51    extends HashMap {
    5252     
    53     static private final File ASSOC_FILE = new File(Utility.BASE_DIR, "associations.xml");
     53    static private final File ASSOC_FILE = new File(Utility.BASE_DIR, "associations.xml");
    5454
    55     public FileAssociationManager() {
    56           // Attempt to load any previous file associations
    57           if(ASSOC_FILE.exists()) {
    58                 load();
    59           }
    60     }
     55    public FileAssociationManager() {
     56    // Attempt to load any previous file associations
     57    if(ASSOC_FILE.exists()) {
     58        load();
     59    }
     60    }
    6161
    62     public void destroy() {
    63           save();
    64     }
     62    public void destroy() {
     63    save();
     64    }
    6565
    66     public String getCommand(File file) {
    67           String command = null;
    68           String filename = file.toString();
    69           // Determine extension
    70           int index = -1;
    71           if((index = filename.lastIndexOf(".")) != -1) {
    72                 String extension = filename.substring(index + 1);
    73                 command = getCommand(file, extension);
    74           }
    75           return command;
    76     }
     66    public String getCommand(File file) {
     67    String command = null;
     68    String filename = file.toString();
     69    // Determine extension
     70    int index = -1;
     71    if((index = filename.lastIndexOf(".")) != -1) {
     72        String extension = filename.substring(index + 1);
     73        command = getCommand(file, extension);
     74    }
     75    return command;
     76    }
    7777
    78     public String getCommand(File file, String extension) {
    79           // We first check to see if we already know the answer to how to run this program.
    80           String command = (String) get(extension);
    81           if(command != null) {
    82                 command = command + " " + file.getAbsolutePath();
    83           }
    84           // If not, and we are on windows, try the registry.
    85           if(command == null && Utility.isWindows()) {
    86                 command = WinRegistry.openCommand(file.getAbsolutePath());
    87           }
    88           // Failing all that prompt the user to select the program to open this with.
    89           if(command == null) {
    90                 FileAssociationDialog dialog = new FileAssociationDialog(this);
    91                 command = dialog.display(extension);
    92                 dialog.destroy();
    93                 dialog = null;
    94                 if(command != null) {
    95                      put(extension, command);
    96                      command = command + " " + file.getAbsolutePath();
    97                 }
    98           }
    99           ///ystem.err.println("Get command: " + extension + " = " + command);
    100           return command;
    101     }
     78    public String getCommand(File file, String extension) {
     79    // We first check to see if we already know the answer to how to run this program.
     80    String command = (String) get(extension);
     81    if(command != null) {
     82        command = command + " " + file.getAbsolutePath();
     83    }
     84    // If not, and we are on windows, try the registry.
     85    if(command == null && Utility.isWindows()) {
     86        command = WinRegistry.openCommand(file.getAbsolutePath());
     87    }
     88    // Failing all that prompt the user to select the program to open this with.
     89    if(command == null) {
     90        FileAssociationDialog dialog = new FileAssociationDialog(this);
     91        command = dialog.display(extension);
     92        dialog.destroy();
     93        dialog = null;
     94        if(command != null) {
     95        put(extension, command);
     96        command = command + " " + file.getAbsolutePath();
     97        }
     98    }
     99    ///ystem.err.println("Get command: " + extension + " = " + command);
     100    return command;
     101    }
    102102
    103     public String getCommandImmediately(String extension) {
    104           return (String) get(extension);
    105     }
     103    public String getCommandImmediately(String extension) {
     104    return (String) get(extension);
     105    }
    106106
    107     public void edit() {
    108           FileAssociationDialog dialog = new FileAssociationDialog(this);
    109           dialog.display(null);
    110           dialog.destroy();
    111           dialog = null;         
    112     }
     107    public void edit() {
     108    FileAssociationDialog dialog = new FileAssociationDialog(this);
     109    dialog.display(null);
     110    dialog.destroy();
     111    dialog = null;       
     112    }
    113113
    114     private void load() {
    115           // Read in and parse the document.
    116           Document document = Utility.parse(ASSOC_FILE, false);
    117           if(document != null) {
     114    private void load() {
     115    // Read in and parse the document.
     116    Document document = Utility.parse(ASSOC_FILE, false);
     117    if(document != null) {
    118118                // Recover all the entry nodes of the association root.
    119                 for(Node entry_n = document.getDocumentElement().getFirstChild(); entry_n != null; entry_n = entry_n.getNextSibling()) {
    120                      if(entry_n.getNodeName().equals("Entry")) {
    121                           Element entry_e = (Element) entry_n;
    122                           String extension = entry_e.getAttribute("extension");
    123                           String command = MSMUtils.getValue(entry_e);
    124                           put(extension, command);
    125                           extension = null;
    126                           command = null;
    127                           entry_e = null;
    128                      }
    129                 }
    130           }
    131     }
     119        for(Node entry_n = document.getDocumentElement().getFirstChild(); entry_n != null; entry_n = entry_n.getNextSibling()) {
     120        if(entry_n.getNodeName().equals("Entry")) {
     121            Element entry_e = (Element) entry_n;
     122            String extension = entry_e.getAttribute("extension");
     123            String command = MSMUtils.getValue(entry_e);
     124            put(extension, command);
     125            extension = null;
     126            command = null;
     127            entry_e = null;
     128        }
     129        }
     130    }
     131    }
    132132
    133     private void save() {
    134           // Only save if there is something to save.
    135           if(size() > 0) {
    136                 StringBuffer assoc = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    137                 assoc.append("<!DOCTYPE Associations [\n");
    138                 assoc.append("  <!ELEMENT Associations (Entry*)>\n");
    139                 assoc.append("  <!ELEMENT Entry (#PCDATA)>\n");
    140                 assoc.append("  <!ATTLIST Entry\n");
    141                 assoc.append("            extension CDATA #REQUIRED>\n");
    142                 assoc.append("]>\n");
    143                 assoc.append("\n");
    144                 assoc.append("<Associations>\n");
    145                 for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
    146                      String extension = (String) keys.next();
    147                      String command = (String) get(extension);
    148                      assoc.append("\t<Entry extension=\"");
    149                      assoc.append(extension);
    150                      assoc.append("\">");
    151                      assoc.append(command);
    152                      assoc.append("</Entry>\n");
    153                 }
    154                 assoc.append("</Associations>");
     133    private void save() {
     134    // Only save if there is something to save.
     135    if(size() > 0) {
     136        StringBuffer assoc = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
     137        assoc.append("<!DOCTYPE Associations [\n");
     138        assoc.append("  <!ELEMENT Associations (Entry*)>\n");
     139        assoc.append("  <!ELEMENT Entry (#PCDATA)>\n");
     140        assoc.append("  <!ATTLIST Entry\n");
     141        assoc.append("            extension CDATA #REQUIRED>\n");
     142        assoc.append("]>\n");
     143        assoc.append("\n");
     144        assoc.append("<Associations>\n");
     145        for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
     146        String extension = (String) keys.next();
     147        String command = (String) get(extension);
     148        assoc.append("\t<Entry extension=\"");
     149        assoc.append(extension);
     150        assoc.append("\">");
     151        assoc.append(command);
     152        assoc.append("</Entry>\n");
     153        }
     154        assoc.append("</Associations>");
    155155
    156                 String assoc_str = assoc.toString();
    157                 assoc = null;
    158                 try {
    159                      FileOutputStream fos = new FileOutputStream(ASSOC_FILE);
    160                      OutputStreamWriter osw = new OutputStreamWriter(fos, Charset.forName("UTF-8"));
    161                      int position = 0;
    162                      int BLOCK_SIZE = 1024;
    163                      // Write x block sized chunks to file.
    164                      while(position + BLOCK_SIZE < assoc_str.length()) {
    165                           osw.write(assoc_str, position, BLOCK_SIZE);
    166                           position = position + BLOCK_SIZE;
    167                      }
    168                      // Write the remainder of the buffer.
    169                      if(position < assoc_str.length()) {
    170                           osw.write(assoc_str, position, assoc_str.length() - position);
    171                      }
    172                      osw.flush();
    173                      osw.close();
    174                      osw = null;
    175                      fos.close();
    176                      fos = null;
    177                      assoc_str = null;
    178                 }
    179                 catch (Exception error) {
    180                      Gatherer.printStackTrace(error);
    181                 }
    182           }
    183     }
     156        String assoc_str = assoc.toString();
     157        assoc = null;
     158        try {
     159        FileOutputStream fos = new FileOutputStream(ASSOC_FILE);
     160        OutputStreamWriter osw = new OutputStreamWriter(fos, Charset.forName("UTF-8"));
     161        int position = 0;
     162        int BLOCK_SIZE = 1024;
     163        // Write x block sized chunks to file.
     164        while(position + BLOCK_SIZE < assoc_str.length()) {
     165            osw.write(assoc_str, position, BLOCK_SIZE);
     166            position = position + BLOCK_SIZE;
     167        }
     168        // Write the remainder of the buffer.
     169        if(position < assoc_str.length()) {
     170            osw.write(assoc_str, position, assoc_str.length() - position);
     171        }
     172        osw.flush();
     173        osw.close();
     174        osw = null;
     175        fos.close();
     176        fos = null;
     177        assoc_str = null;
     178        }
     179        catch (Exception error) {
     180        Gatherer.printStackTrace(error);
     181        }
     182    }
     183    }
    184184
    185     public void setCommand(String extension, String command) {
    186           ///ystem.err.println("Set command: " + extension + " = " + command);
    187           if(command == null || command.length() == 0) {
    188                 remove(extension);
    189           }
    190           else {
    191                 put(extension, command);
    192           }
    193     }
     185    public void setCommand(String extension, String command) {
     186    ///ystem.err.println("Set command: " + extension + " = " + command);
     187    if(command == null || command.length() == 0) {
     188        remove(extension);
     189    }
     190    else {
     191        put(extension, command);
     192    }
     193    }
    194194}
    195195
  • trunk/gli/src/org/greenstone/gatherer/file/FileFilter.java

    r4293 r4366  
    22
    33public class FileFilter {
    4     public boolean exclude;
    5     public String filter;
    6     public FileFilter(String filter, boolean exclude) {
    7           this.exclude = exclude;
    8           this.filter = filter;
    9     }
     4    public boolean exclude;
     5    public String filter;
     6    public FileFilter(String filter, boolean exclude) {
     7    this.exclude = exclude;
     8    this.filter = filter;
     9    }
    1010}
  • trunk/gli/src/org/greenstone/gatherer/file/FileJob.java

    r4293 r4366  
    3535 */
    3636public class FileJob {
    37     /** true to mark that this file has already been copied, false otherwise. */
    38     public boolean done = false;
     37    /** true to mark that this file has already been copied, false otherwise. */
     38    public boolean done = false;
    3939
    40     public boolean folder_level = false;
    41     /** true if this should generate an undo event, false for a redo one. */
    42     public boolean undo = true;
    43     /** true if this job should generate an undo event of any kind. */
    44     public boolean undoable = false;
    45     /** The type of this movement as an byte. */
    46     public byte type = 0;
    47     /** The DragComponent source of this file, most likely a GTree. */
    48     public DragComponent source       = null;
    49     /** The DragComponent to move the file to, again most likely a GTree. */
    50     public DragComponent target       = null;
    51     /** The unique identifier shared by all jobs created by the same action. */
    52     private long id = 0;
    53     /** The path to the destination node as a string. Used because any reference based path or variables quickly becomes obsolete. */
    54     private TreePath destination_path = null;
    55     /** The path to the origin node as a string. Used because any reference based path or variables quickly becomes obsolete. */
    56     private TreePath origin_path = null;
    57     /** An element of the job type enumeration indicating a copy action. */
    58     static final public byte COPY   = 1;
    59     /** An element of the job type enumeration indicating a delete action. */
    60     static final public byte DELETE = 2;
    61     /** An element of the job type enumeration indicating a move action. */
    62     static final public byte MOVE   = 3;
    63     /** Constructor.
    64       * @param id A unique identifier for this job (and others created with a single gesture) as a long.
    65       * @param source The DragComponent source of this file, most likely a GTree.
    66       * @param orig The FileNode you wish to mode.
    67       * @param target The DragComponent to move the file to, again most likely a GTree.
    68       * @param dest The files new FileNode parent within the target.
    69       * @param type The type of this movement as an int, either COPY or DELETE.
    70       * @param undo true if this job some create an undo job when actioned, false for a redo job.
    71       * @param undoable true if this job can generate undo or redo jobs, false otherwise.
    72       */
    73     public FileJob(long id, DragComponent source, FileNode orig, DragComponent target, FileNode dest, byte type, boolean undo, boolean undoable) {
    74           this.id = id;
    75           this.source = source;
    76           this.target = target;
    77           this.type = type;
    78           this.undo = undo;
    79           this.undoable = undoable;
    80           ///ystem.err.println("New Job: " + type + ", " + source + ", " + target);
    81           // Dont store FileNodes which can go stale. Store paths instead, which are used to locate current 'fresh' versions of nodes.
    82           if(dest != null) {
    83                 this.destination_path = new TreePath(dest.getPath());
     40    public boolean folder_level = false;
     41    /** true if this should generate an undo event, false for a redo one. */
     42    public boolean undo = true;
     43    /** true if this job should generate an undo event of any kind. */
     44    public boolean undoable = false;
     45    /** The type of this movement as an byte. */
     46    public byte type = 0;
     47    /** The DragComponent source of this file, most likely a GTree. */
     48    public DragComponent source       = null;
     49    /** The DragComponent to move the file to, again most likely a GTree. */
     50    public DragComponent target       = null;
     51    /** The unique identifier shared by all jobs created by the same action. */
     52    private long id = 0;
     53    /** The path to the destination node as a string. Used because any reference based path or variables quickly becomes obsolete. */
     54    private TreePath destination_path = null;
     55    /** The path to the origin node as a string. Used because any reference based path or variables quickly becomes obsolete. */
     56    private TreePath origin_path = null;
     57    /** An element of the job type enumeration indicating a copy action. */
     58    static final public byte COPY   = 1;
     59    /** An element of the job type enumeration indicating a delete action. */
     60    static final public byte DELETE = 2;
     61    /** An element of the job type enumeration indicating a move action. */
     62    static final public byte MOVE   = 3;
     63    /** Constructor.
     64     * @param id A unique identifier for this job (and others created with a single gesture) as a long.
     65     * @param source The DragComponent source of this file, most likely a GTree.
     66     * @param orig The FileNode you wish to mode.
     67     * @param target The DragComponent to move the file to, again most likely a GTree.
     68     * @param dest The files new FileNode parent within the target.
     69     * @param type The type of this movement as an int, either COPY or DELETE.
     70     * @param undo true if this job some create an undo job when actioned, false for a redo job.
     71     * @param undoable true if this job can generate undo or redo jobs, false otherwise.
     72     */
     73    public FileJob(long id, DragComponent source, FileNode orig, DragComponent target, FileNode dest, byte type, boolean undo, boolean undoable) {
     74    this.id = id;
     75    this.source = source;
     76    this.target = target;
     77    this.type = type;
     78    this.undo = undo;
     79    this.undoable = undoable;
     80    ///ystem.err.println("New Job: " + type + ", " + source + ", " + target);
     81    // Dont store FileNodes which can go stale. Store paths instead, which are used to locate current 'fresh' versions of nodes.
     82    if(dest != null) {
     83        this.destination_path = new TreePath(dest.getPath());
    8484                ///ystem.err.println("Destination Path: " + destination_path);
    85           }
    86           if(orig != null) {
    87                 this.origin_path = new TreePath(orig.getPath());
     85    }
     86    if(orig != null) {
     87        this.origin_path = new TreePath(orig.getPath());
    8888                ///ystem.err.println("Origin Path: " + origin_path);
    89           }
    90     }
    91     /** Retrieve the destination node. Watch out for stale versions by always attempting to load the node at destination_path first. */
    92     public FileNode getDestination() {
    93           FileNode destination = null;
    94           if(destination_path != null) {
    95                 if(target != null) {
    96                      FileSystemModel model = (FileSystemModel)target.getTreeModel();
    97                      destination = model.getNode(destination_path);
    98                 }
     89    }
     90    }
     91    /** Retrieve the destination node. Watch out for stale versions by always attempting to load the node at destination_path first. */
     92    public FileNode getDestination() {
     93    FileNode destination = null;
     94    if(destination_path != null) {
     95        if(target != null) {
     96        FileSystemModel model = (FileSystemModel)target.getTreeModel();
     97        destination = model.getNode(destination_path);
     98        }
    9999                // If the above fails, a stale copy may be better than nothing.
    100                 else {
    101                      destination = (FileNode) destination_path.getLastPathComponent();
    102                 }
    103           }
    104           return destination;
    105     }
    106     /** Retrieve the origin node. Watch out for stale versions by always attempting to load the node at origin_path first. */
    107     public FileNode getOrigin() {
    108           FileNode origin = null;
    109           if(origin_path != null) {
    110                 if(source != null) {
    111                      FileSystemModel model = (FileSystemModel)source.getTreeModel();
    112                      origin = model.getNode(origin_path);
    113                 }
     100        else {
     101        destination = (FileNode) destination_path.getLastPathComponent();
     102        }
     103    }
     104    return destination;
     105    }
     106    /** Retrieve the origin node. Watch out for stale versions by always attempting to load the node at origin_path first. */
     107    public FileNode getOrigin() {
     108    FileNode origin = null;
     109    if(origin_path != null) {
     110        if(source != null) {
     111        FileSystemModel model = (FileSystemModel)source.getTreeModel();
     112        origin = model.getNode(origin_path);
     113        }
    114114                // If the above fails, a stale copy may be better than nothing.
    115                 else {
    116                      origin = (FileNode) origin_path.getLastPathComponent();
    117                 }
    118           }
    119           return origin;
    120     }
    121     /** Retrieve the id for this job. */
    122     public long ID() {
    123           return id;
    124     }
     115        else {
     116        origin = (FileNode) origin_path.getLastPathComponent();
     117        }
     118    }
     119    return origin;
     120    }
     121    /** Retrieve the id for this job. */
     122    public long ID() {
     123    return id;
     124    }
    125125
    126     public String toString() {
    127           StringBuffer text = new StringBuffer("");
    128           switch(type) {
    129           case COPY:
    130                 text.append("copy ");
    131                 break;
    132           case DELETE:
    133                 text.append("delete ");
    134                 break;
    135           case MOVE:
    136                 text.append("move ");
    137                 break;
    138           default:
    139                 text.append("unknown ");
    140           }
    141           FileNode origin = getOrigin();
    142           if(origin != null) {
    143                 text.append(origin.getFile().getAbsolutePath());
    144           }
    145           else {
    146                 text.append("ERROR!");
    147           }
    148           text.append(" -> ");
    149           FileNode destination = getDestination();
    150           if(destination != null) {
    151                 text.append(destination.getFile().getAbsolutePath());
    152           }   
    153           else {
    154                 text.append("Recycle Bin");
    155           }
    156           return text.toString();
    157     }
     126    public String toString() {
     127    StringBuffer text = new StringBuffer("");
     128    switch(type) {
     129    case COPY:
     130        text.append("copy ");
     131        break;
     132    case DELETE:
     133        text.append("delete ");
     134        break;
     135    case MOVE:
     136        text.append("move ");
     137        break;
     138    default:
     139        text.append("unknown ");
     140    }
     141    FileNode origin = getOrigin();
     142    if(origin != null) {
     143        text.append(origin.getFile().getAbsolutePath());
     144    }
     145    else {
     146        text.append("ERROR!");
     147    }
     148    text.append(" -> ");
     149    FileNode destination = getDestination();
     150    if(destination != null) {
     151        text.append(destination.getFile().getAbsolutePath());
     152    }     
     153    else {
     154        text.append("Recycle Bin");
     155    }
     156    return text.toString();
     157    }
    158158}
  • trunk/gli/src/org/greenstone/gatherer/file/FileManager.java

    r4293 r4366  
    5151 */
    5252public class FileManager {
    53     /** Not only the queue of files to be moved, but also the object that moves them. */
    54     private FileQueue queue = null;
    55     /** Constructor.
    56       * @see org.greenstone.gatherer.file.FileQueue
    57       */
    58     public FileManager() {
    59           queue = new FileQueue(false);
    60           queue.start();
    61     }
     53    /** Not only the queue of files to be moved, but also the object that moves them. */
     54    private FileQueue queue = null;
     55    /** Constructor.
     56     * @see org.greenstone.gatherer.file.FileQueue
     57     */
     58    public FileManager() {
     59    queue = new FileQueue(false);
     60    queue.start();
     61    }
    6262
    63     /** Given the arguments, determine what action should be carried out by the file queue, and add all of the necessary file jobs. */
    64     public void action(DragComponent source, FileNode[] source_nodes, DragComponent target, FileNode target_node) {
    65           byte type = 0;
    66           // If source and target are the same we are moving
    67           if(source == target) {
    68                 type = FileJob.MOVE;
    69           }
    70           // If source and target are different
    71           else {
     63    /** Given the arguments, determine what action should be carried out by the file queue, and add all of the necessary file jobs. */
     64    public void action(DragComponent source, FileNode[] source_nodes, DragComponent target, FileNode target_node) {
     65    byte type = 0;
     66    // If source and target are the same we are moving
     67    if(source == target) {
     68        type = FileJob.MOVE;
     69    }
     70    // If source and target are different
     71    else {
    7272                // If target is the UndoManager, we're deleting
    73                 if(target instanceof UndoManager) {
    74                      // If the source is the workspace then display an error message. Workspace is read only.
    75                      if(source.toString().equals("Workspace")) {
    76                           JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.Read_Only"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
    77                           return;
    78                      }
    79                      // Normal delete. Go ahead.
    80                      else {
    81                           type = FileJob.DELETE;
    82                      }
    83                 }
     73        if(target instanceof UndoManager) {
     74        // If the source is the workspace then display an error message. Workspace is read only.
     75        if(source.toString().equals("Workspace")) {
     76            JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.Read_Only"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
     77            return;
     78        }
     79        // Normal delete. Go ahead.
     80        else {
     81            type = FileJob.DELETE;
     82        }
     83        }
    8484                // Otherwise we are copying
    85                 else {
    86                      type = FileJob.COPY;
    87                 }
    88           }
    89           Task task = new Task(System.currentTimeMillis(), source, source_nodes, target, target_node, type);
    90           SwingUtilities.invokeLater(task);
    91     }
     85        else {
     86        type = FileJob.COPY;
     87        }
     88    }
     89    Task task = new Task(System.currentTimeMillis(), source, source_nodes, target, target_node, type);
     90    SwingUtilities.invokeLater(task);
     91    }
    9292
    93     /** Retrieves the file queue object. */
    94     public FileQueue getQueue() {
    95           return queue;
    96     }
     93    /** Retrieves the file queue object. */
     94    public FileQueue getQueue() {
     95    return queue;
     96    }
    9797
    98     public void newFolder(DragTree tree, FileNode parent_node) {
    99           // Ask the user for the directories name.
    100           NewFolderPrompt new_folder_prompt = new NewFolderPrompt(parent_node);
    101           String name = new_folder_prompt.display();
    102           new_folder_prompt.dispose();
    103           new_folder_prompt = null;
    104           // And if the name is non-null...
    105           if(name != null) {
    106                 FileSystemModel model = (FileSystemModel) tree.getModel();
    107                 File folder_file = new File(parent_node.getFile(), name);
     98    public void newFolder(DragTree tree, FileNode parent_node) {
     99    // Ask the user for the directories name.
     100    NewFolderPrompt new_folder_prompt = new NewFolderPrompt(parent_node);
     101    String name = new_folder_prompt.display();
     102    new_folder_prompt.dispose();
     103    new_folder_prompt = null;
     104    // And if the name is non-null...
     105    if(name != null) {
     106        FileSystemModel model = (FileSystemModel) tree.getModel();
     107        File folder_file = new File(parent_node.getFile(), name);
    108108                //... check if it already exists.
    109                 if(folder_file.exists()) {
    110                      JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.Folder_Already_Exists", name), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
    111                 }
     109        if(folder_file.exists()) {
     110        JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.Folder_Already_Exists", name), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
     111        }
    112112                // Otherwise create it.
    113                 else {
    114                      folder_file.mkdirs();
    115                      FileNode folder_node = new FileNode(folder_file);
    116                      SynchronizedTreeModelTools.insertNodeInto(model, parent_node, folder_node);
    117                      folder_node = null;
    118                 }
    119                 folder_file = null;
    120                 model = null;
    121           }
    122           name = null;
    123     }
     113        else {
     114        folder_file.mkdirs();
     115        FileNode folder_node = new FileNode(folder_file);
     116        SynchronizedTreeModelTools.insertNodeInto(model, parent_node, folder_node);
     117        folder_node = null;
     118        }
     119        folder_file = null;
     120        model = null;
     121    }
     122    name = null;
     123    }
    124124
    125     private class Task
    126           implements Runnable {
    127           private byte type;
    128           private DragComponent source;
    129           private DragComponent target;
    130           private FileNode target_node;
    131           private FileNode[] source_nodes;
    132           private long id;
    133           public Task(long id, DragComponent source, FileNode[] source_nodes, DragComponent target, FileNode target_node, byte type) {
    134                 this.id = id;
    135                 this.source = source;
    136                 this.source_nodes = source_nodes;
    137                 this.target = target;
    138                 this.target_node = target_node;
    139                 this.type = type;
    140           }
    141           public void run() {
     125    private class Task
     126    implements Runnable {
     127    private byte type;
     128    private DragComponent source;
     129    private DragComponent target;
     130    private FileNode target_node;
     131    private FileNode[] source_nodes;
     132    private long id;
     133    public Task(long id, DragComponent source, FileNode[] source_nodes, DragComponent target, FileNode target_node, byte type) {
     134        this.id = id;
     135        this.source = source;
     136        this.source_nodes = source_nodes;
     137        this.target = target;
     138        this.target_node = target_node;
     139        this.type = type;
     140    }
     141    public void run() {
    142142                // Reset, and calculate progress bar size.
    143                 queue.calculateSize(source_nodes);
     143        queue.calculateSize(source_nodes);
    144144                // Now we queue the job(s). Note that this may fail if a read only file is encountered and we have been asked to delete.
    145                 for(int i = 0; source_nodes != null && i < source_nodes.length; i++) {
    146                      queue.addJob(id, source, source_nodes[i], target, target_node, type, true, true, true);
    147                 }
    148           }
    149     }
     145        for(int i = 0; source_nodes != null && i < source_nodes.length; i++) {
     146        queue.addJob(id, source, source_nodes[i], target, target_node, type, true, true, true);
     147        }
     148    }
     149    }
    150150}
    151151
  • trunk/gli/src/org/greenstone/gatherer/file/FileNode.java

    r4293 r4366  
    1010
    1111public class FileNode
    12     implements MutableTreeNode {
    13 
    14     static final private int FALSE   = 0;
    15     static final private int TRUE    = 1;
    16     static final private int UNKNOWN = 2;
    17 
    18     private ArrayList children;
    19     private boolean children_readonly = true;
    20     private boolean readonly = true;
    21     private File file;
    22     private FileSystemModel model;
    23     private int allows_children = UNKNOWN;
    24     private MutableTreeNode parent;
    25     private String title;
    26 
    27     public FileNode(File file) {
    28           ///ystem.err.println("New FileNode(" + file.getAbsolutePath() + ")");
    29           this.file = file;
    30     }
    31 
    32     public FileNode(File file, boolean readonly) {
    33           this(file);
    34           this.children_readonly = readonly;
    35           this.readonly = readonly;
    36     }
    37 
    38     public FileNode(File file, FileSystemModel model) {
    39           this(file);
    40           this.model = model;
    41     }
    42 
    43     public FileNode(File file, FileSystemModel model, boolean readonly) {
    44           this(file, readonly);
    45           this.model = model;
    46     }
    47 
    48     public FileNode(File file, FileSystemModel model, String title) {
    49           this(file, model);
    50           this.title = title;
    51     }
    52 
    53     public FileNode(File file, String title) {
    54           this(file);
    55           this.title = title;
    56     }
    57 
    58     public FileNode(File file, String title, boolean readonly) {
    59           this(file, readonly);
    60           this.title = title;
    61     }
    62 
    63     public FileNode(File file, FileSystemModel model, String title, boolean readonly) {
    64           this(file, model, readonly);
    65           this.title = title;
    66     }
    67 
    68     /** The special 'dummy' root node, that is not based on a particular file, but instead holds several special directory mappings. */
    69     public FileNode(String title) {
    70           this.children = new ArrayList();
    71           this.title = title;
    72     }
    73 
    74     /** Returns the children of the receiver as an Enumeration. */
    75     public Enumeration children() {
    76           return new FileEnumeration();
    77     }
     12    implements MutableTreeNode {
     13
     14    static final private int FALSE   = 0;
     15    static final private int TRUE    = 1;
     16    static final private int UNKNOWN = 2;
     17
     18    private ArrayList children;
     19    private boolean children_readonly = true;
     20    private boolean readonly = true;
     21    private File file;
     22    private FileSystemModel model;
     23    private int allows_children = UNKNOWN;
     24    private MutableTreeNode parent;
     25    private String title;
     26
     27    public FileNode(File file) {
     28    ///ystem.err.println("New FileNode(" + file.getAbsolutePath() + ")");
     29    this.file = file;
     30    }
     31
     32    public FileNode(File file, boolean readonly) {
     33    this(file);
     34    this.children_readonly = readonly;
     35    this.readonly = readonly;
     36    }
     37
     38    public FileNode(File file, FileSystemModel model) {
     39    this(file);
     40    this.model = model;
     41    }
     42
     43    public FileNode(File file, FileSystemModel model, boolean readonly) {
     44    this(file, readonly);
     45    this.model = model;
     46    }
     47
     48    public FileNode(File file, FileSystemModel model, String title) {
     49    this(file, model);
     50    this.title = title;
     51    }
     52
     53    public FileNode(File file, String title) {
     54    this(file);
     55    this.title = title;
     56    }
     57
     58    public FileNode(File file, String title, boolean readonly) {
     59    this(file, readonly);
     60    this.title = title;
     61    }
     62
     63    public FileNode(File file, FileSystemModel model, String title, boolean readonly) {
     64    this(file, model, readonly);
     65    this.title = title;
     66    }
     67
     68    /** The special 'dummy' root node, that is not based on a particular file, but instead holds several special directory mappings. */
     69    public FileNode(String title) {
     70    this.children = new ArrayList();
     71    this.title = title;
     72    }
     73
     74    /** Returns the children of the receiver as an Enumeration. */
     75    public Enumeration children() {
     76    return new FileEnumeration();
     77    }
    7878
    7979    /** Compare two filenodes for equality. */
    8080    public boolean equals(FileNode node) {
    81           boolean result = false;
    82           if(node != null) {
    83                 if(file != null) {
    84                      result = (file.equals(node.getFile()));
    85                 }
    86                 else {
    87                      result = toString().equals(node.toString());
    88                 }
    89           }
    90           return result;
     81    boolean result = false;
     82    if(node != null) {
     83        if(file != null) {
     84        result = (file.equals(node.getFile()));
     85        }
     86        else {
     87        result = toString().equals(node.toString());
     88        }
     89    }
     90    return result;
    9191    }
    9292
    9393    /** Returns true if the receiver allows children. We have to cache the result of this call to prevent unceasing missing disk messages being thrown if the removable media was, um, removed after directory mapped. */
    9494    public boolean getAllowsChildren() {
    95           if(readonly) {
    96                 if(allows_children == UNKNOWN) {
    97                      // If the file is non-null but doesn't exist (as is the case for removable media), return true anyway.
    98                      if(file != null) {
    99                           if(FileSystemView.getFileSystemView().isFileSystemRoot(file)) {
    100                                 allows_children = TRUE;
    101                           }
    102                           else if(file.exists() && file.isDirectory()) {
    103                                 allows_children = TRUE;
    104                           }
    105                           // Any mapped directories always allow children.
    106                           else if(getParent() != null && getParent().getParent() == null) {
    107                                 allows_children = TRUE;
    108                           }
    109                           else {
    110                                 allows_children = FALSE;
    111                           }
    112                      }
    113                      // Allows children is always true for dummy nodes.
    114                      else {
    115                           allows_children = TRUE;
    116                      }
    117                 }
    118                 return (allows_children == TRUE);
    119           }
    120           else {
    121                 return (file == null || file.isDirectory());
    122           }
     95    if(readonly) {
     96        if(allows_children == UNKNOWN) {
     97        // If the file is non-null but doesn't exist (as is the case for removable media), return true anyway.
     98        if(file != null) {
     99            if(FileSystemView.getFileSystemView().isFileSystemRoot(file)) {
     100            allows_children = TRUE;
     101            }
     102            else if(file.exists() && file.isDirectory()) {
     103            allows_children = TRUE;
     104            }
     105            // Any mapped directories always allow children.
     106            else if(getParent() != null && getParent().getParent() == null) {
     107            allows_children = TRUE;
     108            }
     109            else {
     110            allows_children = FALSE;
     111            }
     112        }
     113        // Allows children is always true for dummy nodes.
     114        else {
     115            allows_children = TRUE;
     116        }
     117        }
     118        return (allows_children == TRUE);
     119    }
     120    else {
     121        return (file == null || file.isDirectory());
     122    }
    123123    }
    124124   
    125     /** Returns the child TreeNode at index childIndex. */
    126     public TreeNode getChildAt(int index) {
    127           TreeNode result = null;
    128           map();
    129           if(0 <= index && index < children.size()) {
    130                 result = (TreeNode) children.get(index);
    131           }
    132           else {
    133                 result = new DefaultMutableTreeNode("Error");
    134           }
    135           return result;
    136     }
    137 
    138     /** Returns the number of children TreeNodes the receiver contains. */
    139     public int getChildCount() {
    140           int size = 0;
    141           // We don't automatically map if this is a system root, or we risk the 50,000 Disk not found error messages of death.
    142           if(FileSystemView.getFileSystemView().isFileSystemRoot(file)) {
    143               size = 1; // Size is always non-zero for a system root
    144           }
    145           else {
    146               map();
    147           }
    148           ///ystem.err.println(this + ".getChildCount() = " + children.size());
    149           if(children != null) {
    150                 size = children.size();
    151           }
    152           return size;
    153     }
    154 
    155     public File getFile() {
    156           return file;
    157     }
    158 
    159     /** Returns the index of node in the receivers children. */
    160     public int getIndex(TreeNode node) {
    161           map();
    162           return children.indexOf(node);
    163     }
    164 
    165     /** Returns the parent TreeNode of the receiver. */
    166     public TreeNode getParent() {
    167           return parent;
    168     }
    169 
    170     /** Retrieves the tree path from the root node to this node. */
    171     public TreeNode[] getPath() {
    172           int count = 0;
    173           TreeNode current = this;
    174           while(current != null) {
    175                 count++;
    176                 current = current.getParent();
    177           }
    178           TreeNode[] path = new TreeNode[count];
    179           current = this;
    180           while(current != null) {
    181                 path[count - 1] = current;
    182                 count--;
    183                 current = current.getParent();
    184           }
    185           return path;
    186     }
    187 
    188     public void insert(MutableTreeNode child) {
    189           insert(child, children.size());
    190     }
    191 
    192     /** Adds child to the receiver at index. */
    193     public void insert(MutableTreeNode child, int index) {
    194           ///ystem.err.println("Insert " + child + " in " + this + " at index " + index);
    195           //map();
    196           try {
    197                 children.add(index, child);
     125    /** Returns the child TreeNode at index childIndex. */
     126    public TreeNode getChildAt(int index) {
     127    TreeNode result = null;
     128    map();
     129    if(0 <= index && index < children.size()) {
     130        result = (TreeNode) children.get(index);
     131    }
     132    else {
     133        result = new DefaultMutableTreeNode("Error");
     134    }
     135    return result;
     136    }
     137
     138    /** Returns the number of children TreeNodes the receiver contains. */
     139    public int getChildCount() {
     140    int size = 0;
     141    // We don't automatically map if this is a system root, or we risk the 50,000 Disk not found error messages of death.
     142    if(FileSystemView.getFileSystemView().isFileSystemRoot(file)) {
     143        size = 1; // Size is always non-zero for a system root
     144    }
     145    else {
     146        map();
     147    }
     148    ///ystem.err.println(this + ".getChildCount() = " + children.size());
     149    if(children != null) {
     150        size = children.size();
     151    }
     152    return size;
     153    }
     154
     155    public File getFile() {
     156    return file;
     157    }
     158
     159    /** Returns the index of node in the receivers children. */
     160    public int getIndex(TreeNode node) {
     161    map();
     162    return children.indexOf(node);
     163    }
     164
     165    /** Returns the parent TreeNode of the receiver. */
     166    public TreeNode getParent() {
     167    return parent;
     168    }
     169
     170    /** Retrieves the tree path from the root node to this node. */
     171    public TreeNode[] getPath() {
     172    int count = 0;
     173    TreeNode current = this;
     174    while(current != null) {
     175        count++;
     176        current = current.getParent();
     177    }
     178    TreeNode[] path = new TreeNode[count];
     179    current = this;
     180    while(current != null) {
     181        path[count - 1] = current;
     182        count--;
     183        current = current.getParent();
     184    }
     185    return path;
     186    }
     187
     188    public void insert(MutableTreeNode child) {
     189    insert(child, children.size());
     190    }
     191
     192    /** Adds child to the receiver at index. */
     193    public void insert(MutableTreeNode child, int index) {
     194    ///ystem.err.println("Insert " + child + " in " + this + " at index " + index);
     195    //map();
     196    try {
     197        children.add(index, child);
    198198                // Set parent and model.
    199                 FileNode new_child = (FileNode) child;
    200                 new_child.setModel(model);
    201                 new_child.setParent(this);
    202                 new_child.setReadOnly(readonly);
    203           }
    204           catch(Exception error) {
    205                 error.printStackTrace();
    206           }
    207     }
    208 
    209     /** Returns true if the receiver is a leaf. */
    210     public boolean isLeaf() {
    211           return !getAllowsChildren();
    212     }
    213 
    214     public boolean isReadOnly() {
    215           return readonly;
    216     }
    217 
    218     public void map() {
    219           // Only map if there are no children.
    220           if(children == null && file != null && getAllowsChildren()) {
     199        FileNode new_child = (FileNode) child;
     200        new_child.setModel(model);
     201        new_child.setParent(this);
     202        new_child.setReadOnly(readonly);
     203    }
     204    catch(Exception error) {
     205        error.printStackTrace();
     206    }
     207    }
     208
     209    /** Returns true if the receiver is a leaf. */
     210    public boolean isLeaf() {
     211    return !getAllowsChildren();
     212    }
     213
     214    public boolean isReadOnly() {
     215    return readonly;
     216    }
     217
     218    public void map() {
     219    // Only map if there are no children.
     220    if(children == null && file != null && getAllowsChildren()) {
    221221                ///ystem.err.println("Map: " + this);
    222                 children = new ArrayList();
    223                 File[] files = file.listFiles();
    224                 if(files != null && files.length > 0) {
    225                      ArrayTools tools = new ArrayTools();
    226                      // Apply the filters set in the model.
    227                      FileFilter[] filters = model.getFilters();
    228                      for(int i = 0; filters != null && i < filters.length; i++) {
    229                           files = tools.filter(files, filters[i].filter, filters[i].exclude);
    230                      }
    231                      // Sort the remaining files.
    232                      tools.sort(files, true);
    233                      // Now add them to children.
    234                      for(int i = 0; i < files.length; i++) {
    235                           FileNode child = new FileNode(files[i], model, children_readonly);
    236                           child.setParent(this);
    237                           children.add(child);
    238                      }
    239                 }
    240                 model.nodeStructureChanged(this);
    241           }
    242           else {
    243               ///ystem.err.println("Can't map: " + this + ". No file or doesn't allow children.");
    244           }
    245     }
    246 
    247     /** Removes the child at index from the receiver. */
    248     public void remove(int index) {
    249           if(0 <= index && index < children.size()) {
    250                 children.remove(index);
    251           }
    252     }
    253 
    254     /** Removes node from the receiver. */
    255     public void remove(MutableTreeNode node){
    256           int index = getIndex(node);
    257           if(index != -1) {
    258                 children.remove(index);
    259           }
    260     }
    261 
    262     /** Removes the receiver from its parent. */
    263     public void removeFromParent() {
    264           parent.remove(this);
    265           parent = null;
    266     }
    267 
    268     public void setChildrenReadOnly(boolean children_readonly) {
    269           this.children_readonly = children_readonly;
    270     }
    271 
    272     public void setFile(File file) {
    273           this.file = file;
    274     }
    275 
    276     public void setModel(FileSystemModel model) {
    277           this.model = model;
    278     }
    279 
    280     public void setParent(MutableTreeNode parent) {
    281           this.parent = parent;
    282     }
    283 
    284     public void setReadOnly(boolean readonly) {
    285           this.readonly = readonly;
    286     }
    287 
    288     /** Resets the user object of the receiver to object. */
    289     public void setUserObject(Object object) {
    290           try {
    291                 file = (File) object;
    292                 title = null;
    293           }
    294           catch(Exception error) {
    295                 error.printStackTrace();
    296           }
    297     }
    298 
    299     public String toString() {
    300           if(title == null) {
    301             if(FileSystemView.getFileSystemView().isFileSystemRoot(file)) {
    302               title = file.getAbsolutePath();
    303             }
    304             else {
    305                 title = file.getName();
    306             }
    307           }
    308           return title;
    309     }
    310 
    311     /** Unmap this nodes children. */
    312     public void unmap() {
    313           // You cannot unmap nodes that have no file basis.
    314           if(file != null) {
     222        children = new ArrayList();
     223        File[] files = file.listFiles();
     224        if(files != null && files.length > 0) {
     225        ArrayTools tools = new ArrayTools();
     226        // Apply the filters set in the model.
     227        FileFilter[] filters = model.getFilters();
     228        for(int i = 0; filters != null && i < filters.length; i++) {
     229            files = tools.filter(files, filters[i].filter, filters[i].exclude);
     230        }
     231        // Sort the remaining files.
     232        tools.sort(files, true);
     233        // Now add them to children.
     234        for(int i = 0; i < files.length; i++) {
     235            FileNode child = new FileNode(files[i], model, children_readonly);
     236            child.setParent(this);
     237            children.add(child);
     238        }
     239        }
     240        model.nodeStructureChanged(this);
     241    }
     242    else {
     243        ///ystem.err.println("Can't map: " + this + ". No file or doesn't allow children.");
     244    }
     245    }
     246
     247    /** Removes the child at index from the receiver. */
     248    public void remove(int index) {
     249    if(0 <= index && index < children.size()) {
     250        children.remove(index);
     251    }
     252    }
     253
     254    /** Removes node from the receiver. */
     255    public void remove(MutableTreeNode node){
     256    int index = getIndex(node);
     257    if(index != -1) {
     258        children.remove(index);
     259    }
     260    }
     261
     262    /** Removes the receiver from its parent. */
     263    public void removeFromParent() {
     264    parent.remove(this);
     265    parent = null;
     266    }
     267
     268    public void setChildrenReadOnly(boolean children_readonly) {
     269    this.children_readonly = children_readonly;
     270    }
     271
     272    public void setFile(File file) {
     273    this.file = file;
     274    }
     275
     276    public void setModel(FileSystemModel model) {
     277    this.model = model;
     278    }
     279
     280    public void setParent(MutableTreeNode parent) {
     281    this.parent = parent;
     282    }
     283
     284    public void setReadOnly(boolean readonly) {
     285    this.readonly = readonly;
     286    }
     287
     288    /** Resets the user object of the receiver to object. */
     289    public void setUserObject(Object object) {
     290    try {
     291        file = (File) object;
     292        title = null;
     293    }
     294    catch(Exception error) {
     295        error.printStackTrace();
     296    }
     297    }
     298
     299    public String toString() {
     300    if(title == null) {
     301        if(FileSystemView.getFileSystemView().isFileSystemRoot(file)) {
     302        title = file.getAbsolutePath();
     303        }
     304        else {
     305        title = file.getName();
     306        }
     307    }
     308    return title;
     309    }
     310
     311    /** Unmap this nodes children. */
     312    public void unmap() {
     313    // You cannot unmap nodes that have no file basis.
     314    if(file != null) {
    315315                ///ystem.err.println("Unmap: " + this);
    316                 children = null;
    317           }
    318           else {
     316        children = null;
     317    }
     318    else {
    319319                ///ystem.err.println("No file for " + this + " - can't unmap.");
    320           }
    321     }
    322 
    323     private class FileEnumeration
    324           implements Enumeration {
    325           private int index = 0;
    326           /** Tests if this enumeration contains more elements. */
    327           public boolean hasMoreElements() {
    328                 return (index < children.size());
    329           }
    330           /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
    331           public Object nextElement() {
    332                 Object result = null;
    333                 if(index < children.size()) {
    334                      result = children.get(index);
    335                      index++;
    336                 }
    337                 return result;
    338           }
    339     }
     320    }
     321    }
     322
     323    private class FileEnumeration
     324    implements Enumeration {
     325    private int index = 0;
     326    /** Tests if this enumeration contains more elements. */
     327    public boolean hasMoreElements() {
     328        return (index < children.size());
     329    }
     330    /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
     331    public Object nextElement() {
     332        Object result = null;
     333        if(index < children.size()) {
     334        result = children.get(index);
     335        index++;
     336        }
     337        return result;
     338    }
     339    }
    340340}
  • trunk/gli/src/org/greenstone/gatherer/file/FileOpenActionListener.java

    r4293 r4366  
    4848 */
    4949public class FileOpenActionListener
    50     extends MouseAdapter
    51     implements TreeExpansionListener {
    52     /** This flag gets toggled to <i>true</i> if the listener determines that the next mouse clicked event it will recieve is actually caused by the tree expanding or collapsing. */
    53     private boolean ignore = false;
    54     /** The constructor. */
    55     public FileOpenActionListener() {
    56     }
    57     /** Any subclass of MouseAdapter can override this method to respond to mouse click events. In this case we want to start an external application if someone double clicks on an appropriate file record.
     50    extends MouseAdapter
     51    implements TreeExpansionListener {
     52    /** This flag gets toggled to <i>true</i> if the listener determines that the next mouse clicked event it will recieve is actually caused by the tree expanding or collapsing. */
     53    private boolean ignore = false;
     54    /** The constructor. */
     55    public FileOpenActionListener() {
     56    }
     57    /** Any subclass of MouseAdapter can override this method to respond to mouse click events. In this case we want to start an external application if someone double clicks on an appropriate file record.
    5858      * @param event A <strong>MouseEvent</strong> containing further information about the mouse click performed.
    5959      * @see org.greenstone.gatherer.Gatherer
     
    6161      * @see org.greenstone.gatherer.tree.GTree
    6262      */
    63     public void mouseClicked(MouseEvent event) {
    64           ///ystem.err.println("Mouse clicked");
    65           if(!ignore) {
    66                 if(event.getClickCount() >= 2) {
    67                      // Find the file we're clicking on.
    68                      JTree tree = (JTree)event.getSource();
    69                      TreePath path = tree.getClosestPathForLocation(event.getX(), event.getY());
    70                      if(path != null) {
    71                           FileNode record = (FileNode)path.getLastPathComponent();
    72                           ///ystem.err.println("Double clicked on " + record);
    73                           File file = record.getFile();
    74                           if(file != null && file.isFile()) {
    75                                 ///ystem.err.println("Running " + file);
    76                                 Gatherer.self.spawnApplication(file);
    77                           }
    78                      }
    79                 }
    80           }
    81           else {
     63    public void mouseClicked(MouseEvent event) {
     64    ///ystem.err.println("Mouse clicked");
     65    if(!ignore) {
     66        if(event.getClickCount() >= 2) {
     67        // Find the file we're clicking on.
     68        JTree tree = (JTree)event.getSource();
     69        TreePath path = tree.getClosestPathForLocation(event.getX(), event.getY());
     70        if(path != null) {
     71            FileNode record = (FileNode)path.getLastPathComponent();
     72            ///ystem.err.println("Double clicked on " + record);
     73            File file = record.getFile();
     74            if(file != null && file.isFile()) {
     75            ///ystem.err.println("Running " + file);
     76            Gatherer.self.spawnApplication(file);
     77            }
     78        }
     79        }
     80    }
     81    else {
    8282                ///ystem.err.println("Caused by tree expansion / collapse. Ignoring.");
    83                 ignore = false;
    84           }
    85     }
    86     /** Any implementation of TreeExpansionListener must include this method so that we can be informed when a tree node has been collapsed, thus indicating that any mouse click events about to be recieved are most likely related to this event.
     83        ignore = false;
     84    }
     85    }
     86    /** Any implementation of TreeExpansionListener must include this method so that we can be informed when a tree node has been collapsed, thus indicating that any mouse click events about to be recieved are most likely related to this event.
    8787      * @param event A <strong>TreeExpansionEvent</strong> containing information about the node collapsed.
    8888      */
    89     public void treeCollapsed(TreeExpansionEvent event) {
    90           ///ystem.err.println("Tree Collapsed");
    91           ignore = true;
    92     }
    93     /** Any implementation of TreeExpansionListener must include this method so that we can be informed when a tree node has been expanded, thus indicating that any mouse click events about to be recieved are most likely related to this event.
     89    public void treeCollapsed(TreeExpansionEvent event) {
     90    ///ystem.err.println("Tree Collapsed");
     91    ignore = true;
     92    }
     93    /** Any implementation of TreeExpansionListener must include this method so that we can be informed when a tree node has been expanded, thus indicating that any mouse click events about to be recieved are most likely related to this event.
    9494      * @param event A <strong>TreeExpansionEvent</strong> containing information about the node expanded.
    9595      */
    96     public void treeExpanded(TreeExpansionEvent event) {
    97           ///ystem.err.println("Tree Expanded");
    98           ignore = true;
    99     }
     96    public void treeExpanded(TreeExpansionEvent event) {
     97    ///ystem.err.println("Tree Expanded");
     98    ignore = true;
     99    }
    100100}
  • trunk/gli/src/org/greenstone/gatherer/file/FileQueue.java

    r4293 r4366  
    5858 */
    5959public class FileQueue
    60     extends Thread
     60    extends Thread
    6161    implements TreeSelectionListener {
    62     /** When someone requests the movement queue to be dumped this cancel flag is set to true. */
    63     private boolean cancel_action = false;
    64     /** A temporary mapping from currently existing FileNode folder to their equivelent FileNode folder within the undo managers tree. */
    65     private HashMap completed_folder_mappings = new HashMap();
    66     /** true to cause this file queue to return from run() as soon as there are no jobs left on the queue. Useful for undo jobs which must occur before a specific action. */
    67     private boolean return_immediately = false;
    68     /** We are only allowed to wait under specific circumstances. */
    69     private boolean wait_allowed = true;
    70     /** true if the user has selected yes to all from a file 'clash' dialog. */
    71     private boolean yes_to_all = false;
    72     /** A temporary mapping from currently existing FileNodes to the potential FileNode folder within the undo managers tree. */
    73     private HashMap recycle_folder_mappings = new HashMap();
    74     /** A label explaining the current moving files status. */
    75     private SmudgyLabel file_status = null;
    76     /** A label explaining the status of this job. */
    77     private JLabel job_status = null;
    78     /** A list containing a queue of waiting movement jobs. */
    79     //private LinkedList queue;
    80     private ArrayList queue;
    81     /** A progress bar which shows how many bytes, out of the total size of bytes, has been moved. */
    82     private LongProgressBar progress = null;
    83     /** The last piece of text shown on the file status label, just incase we are displaying a very temporary message. */
    84     private String previous = null;
    85     /** Constructor.
     62    /** When someone requests the movement queue to be dumped this cancel flag is set to true. */
     63    private boolean cancel_action = false;
     64    /** A temporary mapping from currently existing FileNode folder to their equivelent FileNode folder within the undo managers tree. */
     65    private HashMap completed_folder_mappings = new HashMap();
     66    /** true to cause this file queue to return from run() as soon as there are no jobs left on the queue. Useful for undo jobs which must occur before a specific action. */
     67    private boolean return_immediately = false;
     68    /** We are only allowed to wait under specific circumstances. */
     69    private boolean wait_allowed = true;
     70    /** true if the user has selected yes to all from a file 'clash' dialog. */
     71    private boolean yes_to_all = false;
     72    /** A temporary mapping from currently existing FileNodes to the potential FileNode folder within the undo managers tree. */
     73    private HashMap recycle_folder_mappings = new HashMap();
     74    /** A label explaining the current moving files status. */
     75    private SmudgyLabel file_status = null;
     76    /** A label explaining the status of this job. */
     77    private JLabel job_status = null;
     78    /** A list containing a queue of waiting movement jobs. */
     79    //private LinkedList queue;
     80    private ArrayList queue;
     81    /** A progress bar which shows how many bytes, out of the total size of bytes, has been moved. */
     82    private LongProgressBar progress = null;
     83    /** The last piece of text shown on the file status label, just incase we are displaying a very temporary message. */
     84    private String previous = null;
     85    /** Constructor.
    8686      * @param return_immediately true to cause this file queue to return from run() as soon as there are no jobs left on the queue.
    8787      * @see org.greenstone.gatherer.Configuration
     
    8989      * @see org.greenstone.gatherer.gui.LongProgressBar
    9090      */
    91     public FileQueue(boolean return_immediately) {
    92           this.return_immediately = return_immediately;
    93           this.queue = new ArrayList();//LinkedList();
    94           String args[] = new String[2];
    95           args[0] = "0";
    96           args[1] = "0";
    97           file_status = new SmudgyLabel(get("Selected", args));
    98           job_status = new JLabel(get("No_Activity"));
    99           progress = new LongProgressBar();
    100           progress.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
    101           progress.setForeground(Gatherer.config.getColor("coloring.collection_tree_foreground", false));
    102           progress.setString(get("No_Activity"));
    103           progress.setStringPainted(true);
    104           args = null;
    105     }
    106 
    107     /** Requeue an existing job into the queue.
     91    public FileQueue(boolean return_immediately) {
     92    this.return_immediately = return_immediately;
     93    this.queue = new ArrayList();//LinkedList();
     94    String args[] = new String[2];
     95    args[0] = "0";
     96    args[1] = "0";
     97    file_status = new SmudgyLabel(get("Selected", args));
     98    job_status = new JLabel(get("No_Activity"));
     99    progress = new LongProgressBar();
     100    progress.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
     101    progress.setForeground(Gatherer.config.getColor("coloring.collection_tree_foreground", false));
     102    progress.setString(get("No_Activity"));
     103    progress.setStringPainted(true);
     104    args = null;
     105    }
     106
     107    /** Requeue an existing job into the queue.
    108108      * @param job A previously created FileJob.
    109109      */
    110     synchronized public void addJob(FileJob job, int position) {
    111           job.done = true; // Ensure that the requeued job is marked as done.
    112           queue.add(position, job);
    113           notify();
    114     }
    115 
    116     /** Add a new job to the queue, specifiying as many arguments as is necessary to complete this type of job (ie delete needs no target information).
     110    synchronized public void addJob(FileJob job, int position) {
     111    job.done = true; // Ensure that the requeued job is marked as done.
     112    queue.add(position, job);
     113    notify();
     114    }
     115
     116    /** Add a new job to the queue, specifiying as many arguments as is necessary to complete this type of job (ie delete needs no target information).
    117117      * @param id A long id unique to all jobs created by a single action.
    118118      * @param source The DragComponent source of this file, most likely a DragTree.
     
    124124      * @param undoable true if this job can generate undo or redo jobs at all, false otherwise.
    125125      */
    126     public void addJob(long id, DragComponent source, FileNode child, DragComponent target, FileNode parent, byte type, boolean undo, boolean undoable, boolean folder_level) {
    127           addJob(id, source, child, target, parent, type, undo, undoable, folder_level, -1);
    128     }
    129     synchronized public void addJob(long id, DragComponent source, FileNode child, DragComponent target, FileNode parent, byte type, boolean undo, boolean undoable, boolean folder_level, int position) {
    130           FileJob job = new FileJob(id, source, child, target, parent, type, undo, undoable);
    131           job.folder_level = folder_level;
    132           ///ystem.err.println("Adding job: " + job);
    133           if(position != -1 && position <= queue.size() + 1) {
    134                 queue.add(position, job);
    135           }
    136           else {
    137                 queue.add(job);
    138           }
    139           notify();
    140     }
    141 
    142     public void calculateSize(FileNode[] files) {
    143           progress.reset();
    144           progress.setString(get("FileActions.Calculating_Size"));
    145           progress.setIndeterminate(true);
    146           Vector remaining = new Vector();
    147           for(int i = 0; i < files.length; i++) {
    148                 remaining.add(files[i]);
    149           }
    150           while(remaining.size() > 0) {
    151                 FileNode node = (FileNode)remaining.remove(0);
    152                 if(node.isLeaf()) {
    153                      progress.addMaximum(node.getFile().length());
    154                 }
    155                 else {
    156                      for(int i = 0; i < node.getChildCount(); i++) {
    157                           remaining.add(node.getChildAt(i));
    158                      }
    159                 }
    160           }
    161           progress.setString(get("No_Activity"));
    162           progress.setIndeterminate(false);
    163     }
    164 
    165     /** This method is called to cancel the job queue at the next available moment. */
    166     public void cancelAction() {
    167           cancel_action = true;
    168     }
    169     /** Access to the file state label. */
    170     public JLabel getFileStatus() {
    171           return file_status;
    172     }
    173     /** Access to the job state label. */   
    174     public JLabel getJobStatus() {
    175           return job_status;
    176     }
    177     /** Access to the progress bar. */
    178     public LongProgressBar getProgress() {
    179           return progress;
    180     }
    181     /** Prevent the progress bar updating momentarily, while the progress bar size is re-adjusted. */
    182     public void pause() {
    183           progress.setIndeterminate(true);
    184     }
    185     /** The run method exists in every thread, and here it is used to work its way through the queue of Jobs. If no jobs are waiting and it cans, it waits until a job arrives. If a job is present then it is either COPIED or DELETED, with the records being copied or removed as necessary, and directories being recursed through. Finally the user can press cancel to cause the loop to prematurely dump the job queue then wait.
     126    public void addJob(long id, DragComponent source, FileNode child, DragComponent target, FileNode parent, byte type, boolean undo, boolean undoable, boolean folder_level) {
     127    addJob(id, source, child, target, parent, type, undo, undoable, folder_level, -1);
     128    }
     129    synchronized public void addJob(long id, DragComponent source, FileNode child, DragComponent target, FileNode parent, byte type, boolean undo, boolean undoable, boolean folder_level, int position) {
     130    FileJob job = new FileJob(id, source, child, target, parent, type, undo, undoable);
     131    job.folder_level = folder_level;
     132    ///ystem.err.println("Adding job: " + job);
     133    if(position != -1 && position <= queue.size() + 1) {
     134        queue.add(position, job);
     135    }
     136    else {
     137        queue.add(job);
     138    }
     139    notify();
     140    }
     141
     142    public void calculateSize(FileNode[] files) {
     143    progress.reset();
     144    progress.setString(get("FileActions.Calculating_Size"));
     145    progress.setIndeterminate(true);
     146    Vector remaining = new Vector();
     147    for(int i = 0; i < files.length; i++) {
     148        remaining.add(files[i]);
     149    }
     150    while(remaining.size() > 0) {
     151        FileNode node = (FileNode)remaining.remove(0);
     152        if(node.isLeaf()) {
     153        progress.addMaximum(node.getFile().length());
     154        }
     155        else {
     156        for(int i = 0; i < node.getChildCount(); i++) {
     157            remaining.add(node.getChildAt(i));
     158        }
     159        }
     160    }
     161    progress.setString(get("No_Activity"));
     162    progress.setIndeterminate(false);
     163    }
     164
     165    /** This method is called to cancel the job queue at the next available moment. */
     166    public void cancelAction() {
     167    cancel_action = true;
     168    }
     169    /** Access to the file state label. */
     170    public JLabel getFileStatus() {
     171    return file_status;
     172    }
     173    /** Access to the job state label. */   
     174    public JLabel getJobStatus() {
     175    return job_status;
     176    }
     177    /** Access to the progress bar. */
     178    public LongProgressBar getProgress() {
     179    return progress;
     180    }
     181    /** Prevent the progress bar updating momentarily, while the progress bar size is re-adjusted. */
     182    public void pause() {
     183    progress.setIndeterminate(true);
     184    }
     185    /** The run method exists in every thread, and here it is used to work its way through the queue of Jobs. If no jobs are waiting and it cans, it waits until a job arrives. If a job is present then it is either COPIED or DELETED, with the records being copied or removed as necessary, and directories being recursed through. Finally the user can press cancel to cause the loop to prematurely dump the job queue then wait.
    186186      * @see org.greenstone.gatherer.Gatherer
    187187      * @see org.greenstone.gatherer.collection.CollectionManager
     
    193193      * @see org.greenstone.gatherer.util.Utility
    194194      */
    195      public void run() {
    196           super.setName("FileQueue");
    197           while(!Gatherer.self.exit) {
     195    public void run() {
     196    super.setName("FileQueue");
     197    while(!Gatherer.self.exit) {
     198        try {
     199        // Retrieve the next job
     200        int position = queue.size() - 1;
     201        FileJob job = removeJob(position);
     202        if(job != null) {
     203            ///ystem.err.println("Found job: " + job);
     204            // The user can cancel this individual action at several places, so keep track if the state is 'ready' for the next step.
     205            boolean ready = true;
     206            FileNode origin_node = job.getOrigin();
     207            FileNode destination_node = job.getDestination();
     208            FileSystemModel source_model = (FileSystemModel)job.source.getTreeModel();
     209            FileSystemModel target_model = (FileSystemModel)job.target.getTreeModel();
     210            if(destination_node == null) {
     211            // Retrieve the root node of the target model instead. A delete, or course, has no target file so all deleted files are added to the root of the Recycle Bin model.
     212            destination_node = (FileNode) target_model.getRoot();
     213            }
     214            // Extract common job details.
     215            File source_file = origin_node.getFile();
     216            File target_file = null;
     217            // Determine the target file for a copy or move.
     218            if(job.type == FileJob.COPY || job.type == FileJob.MOVE) {
     219            target_file = new File(destination_node.getFile(), source_file.getName());
     220            }
     221            // To copy a file, copy it then add any metadata found at the source. If this file was already in our collection then we must ensure the lastest version of its metadata.xml has been saved to disk. To copy a directory simply create the directory at the destination, then add all of its children files as new jobs.
     222            if((job.type == FileJob.COPY || job.type == FileJob.MOVE) && !job.done) {
     223            ///ystem.err.println("Copy/Move: " + origin_node);
     224            FileNode new_node = null;
     225            // Check if file exists, and action as necessary. Be aware the user can choose to cancel the action all together (where upon ready becomes false).
     226            if(target_file.exists()) {
     227                // We've previously been told
     228                if(yes_to_all) {
     229                // Remove the old file and tree entry.
     230                target_file.delete();
     231                ready = true;
     232                }
     233                else {
     234                ///atherer.println("Opps! This filename already exists. Give the user some options.");
     235                Object[] options = { get("General.Yes"), get("Yes_To_All"), get("General.No"), get("General.Cancel") };
     236                int result = JOptionPane.showOptionDialog(Gatherer.g_man, get("File_Exists", target_file.getName()), get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
     237                switch(result) {
     238                case 1: // Yes To All
     239                    yes_to_all = true;
     240                case 0: // Yes
     241                    // Remove the old file and tree entry.
     242                    if(destination_node != null) {
     243                    TreePath destination_path = new TreePath(destination_node.getPath());
     244                    FileNode temp_target_node = new FileNode(target_file, target_model, true);
     245                    TreePath target_path = destination_path.pathByAddingChild(temp_target_node);
     246                    SynchronizedTreeModelTools.removeNodeFromParent(target_model, target_model.getNode(target_path));
     247                    target_path = null;
     248                    temp_target_node = null;
     249                    destination_path = null;
     250                    }
     251                    target_file.delete();
     252                    ready = true;
     253                    break;
     254                case 3: // No To All
     255                    cancel_action = true;
     256                case 2: // No
     257                default:
     258                    ready = false;
     259                }
     260                }
     261            }
     262            // We proceed with the copy/move if the ready flag is still set. If it is that means there is no longer any existing file of the same name.
     263            if(ready) {
     264                // update status area
     265                String args[] = new String[1];
     266                args[0] = "" + (queue.size() + 1) + "";
     267                job_status.setText(get("Jobs", args));
     268                if(job.type == FileJob.COPY) {
     269                args[0] = Utility.formatPath("FileActions.Copying", source_file.getAbsolutePath(), file_status.getSize().width);
     270                file_status.setText(get("Copying", args));
     271                }
     272                else {
     273                args[0] = Utility.formatPath("FileActions.Moving", source_file.getAbsolutePath(), file_status.getSize().width);
     274                file_status.setText(get("Moving", args));
     275                }
     276                args = null;
     277                file_status.setToolTipText(Utility.formatHTMLWidth(file_status.getText(), 80));
     278                // If source is a file
     279                if(source_file.isFile()) {
     280                // copy the file. If anything goes wrong the copy file should throw the appropriate exception. No matter what exception is thrown (bar an IOException) we display some message, perhaps take some action, then cancel the remainder of the pending file jobs. No point in being told your out of hard drive space for each one of six thousand files eh?
    198281                try {
    199                      // Retrieve the next job
    200                      int position = queue.size() - 1;
    201                      FileJob job = removeJob(position);
    202                      if(job != null) {
    203                           ///ystem.err.println("Found job: " + job);
    204                           // The user can cancel this individual action at several places, so keep track if the state is 'ready' for the next step.
    205                           boolean ready = true;
    206                           FileNode origin_node = job.getOrigin();
    207                           FileNode destination_node = job.getDestination();
    208                           FileSystemModel source_model = (FileSystemModel)job.source.getTreeModel();
    209                           FileSystemModel target_model = (FileSystemModel)job.target.getTreeModel();
    210                           if(destination_node == null) {
    211                                 // Retrieve the root node of the target model instead. A delete, or course, has no target file so all deleted files are added to the root of the Recycle Bin model.
    212                                 destination_node = (FileNode) target_model.getRoot();
    213                           }
    214                           // Extract common job details.
    215                           File source_file = origin_node.getFile();
    216                           File target_file = null;
    217                           // Determine the target file for a copy or move.
    218                           if(job.type == FileJob.COPY || job.type == FileJob.MOVE) {
    219                                 target_file = new File(destination_node.getFile(), source_file.getName());
    220                           }
    221                           // To copy a file, copy it then add any metadata found at the source. If this file was already in our collection then we must ensure the lastest version of its metadata.xml has been saved to disk. To copy a directory simply create the directory at the destination, then add all of its children files as new jobs.
    222                           if((job.type == FileJob.COPY || job.type == FileJob.MOVE) && !job.done) {
    223                                 ///ystem.err.println("Copy/Move: " + origin_node);
    224                                 FileNode new_node = null;
    225                                 // Check if file exists, and action as necessary. Be aware the user can choose to cancel the action all together (where upon ready becomes false).
    226                                 if(target_file.exists()) {
    227                                      // We've previously been told
    228                                      if(yes_to_all) {
    229                                           // Remove the old file and tree entry.
    230                                           target_file.delete();
    231                                           ready = true;
    232                                      }
    233                                      else {
    234                                           ///atherer.println("Opps! This filename already exists. Give the user some options.");
    235                                           Object[] options = { get("General.Yes"), get("Yes_To_All"), get("General.No"), get("General.Cancel") };
    236                                           int result = JOptionPane.showOptionDialog(Gatherer.g_man, get("File_Exists", target_file.getName()), get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
    237                                           switch(result) {
    238                                           case 1: // Yes To All
    239                                                 yes_to_all = true;
    240                                           case 0: // Yes
    241                                                 // Remove the old file and tree entry.
    242                                                 if(destination_node != null) {
    243                                                      TreePath destination_path = new TreePath(destination_node.getPath());
    244                                                      FileNode temp_target_node = new FileNode(target_file, target_model, true);
    245                                                      TreePath target_path = destination_path.pathByAddingChild(temp_target_node);
    246                                                      SynchronizedTreeModelTools.removeNodeFromParent(target_model, target_model.getNode(target_path));
    247                                                      target_path = null;
    248                                                      temp_target_node = null;
    249                                                      destination_path = null;
    250                                                 }
    251                                                 target_file.delete();
    252                                                 ready = true;
    253                                                 break;
    254                                           case 3: // No To All
    255                                                 cancel_action = true;
    256                                           case 2: // No
    257                                           default:
    258                                                 ready = false;
    259                                           }
    260                                      }
    261                                 }
    262                                 // We proceed with the copy/move if the ready flag is still set. If it is that means there is no longer any existing file of the same name.
    263                                 if(ready) {
    264                                      // update status area
    265                                      String args[] = new String[1];
    266                                      args[0] = "" + (queue.size() + 1) + "";
    267                                      job_status.setText(get("Jobs", args));
    268                                      if(job.type == FileJob.COPY) {
    269                                           args[0] = Utility.formatPath("FileActions.Copying", source_file.getAbsolutePath(), file_status.getSize().width);
    270                                           file_status.setText(get("Copying", args));
    271                                      }
    272                                      else {
    273                                           args[0] = Utility.formatPath("FileActions.Moving", source_file.getAbsolutePath(), file_status.getSize().width);
    274                                           file_status.setText(get("Moving", args));
    275                                      }
    276                                      args = null;
    277                                      file_status.setToolTipText(Utility.formatHTMLWidth(file_status.getText(), 80));
    278                                      // If source is a file
    279                                      if(source_file.isFile()) {
    280                                           // copy the file. If anything goes wrong the copy file should throw the appropriate exception. No matter what exception is thrown (bar an IOException) we display some message, perhaps take some action, then cancel the remainder of the pending file jobs. No point in being told your out of hard drive space for each one of six thousand files eh?
    281                                           try {
    282                                                 copyFile(source_file, target_file, progress);
    283                                           }
    284                                           // If we can't find the source file, then the most likely reason is that the file system has changed since the last time it was mapped. Warn the user that the requested file can't be found, then force a refresh of the source folder involved.
    285                                           catch(FileNotFoundException fnf_exception) {
    286                                                 Gatherer.printStackTrace(fnf_exception);
    287                                                 cancel_action = true;
    288                                                 // Show warning.
    289                                                 JOptionPane.showMessageDialog(Gatherer.g_man, get("File_Not_Found_Message", source_file.getName()), get("File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
    290                                                 // Force refresh of source folder.
    291                                                 source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
    292                                           }
    293                                           catch(FileAlreadyExistsException fae_exception) {
    294                                                 Gatherer.printStackTrace(fae_exception);
    295                                                 cancel_action = true;
    296                                                 // Show warning.
    297                                                 JOptionPane.showMessageDialog(Gatherer.g_man, get("File_Already_Exists_Message", target_file.getName()), get("File_Already_Exists_Title"), JOptionPane.ERROR_MESSAGE);
    298                                                 // Nothing else can be done by the Gatherer.
    299                                           }
    300                                           catch(InsufficientSpaceException is_exception) {
    301                                                 Gatherer.printStackTrace(is_exception);
    302                                                 cancel_action = true;
    303                                                 // Show warning. The message body of the expection explains how much more space is required for this file copy.
    304                                                 JOptionPane.showMessageDialog(Gatherer.g_man, get("Insufficient_Space_Message", is_exception.getMessage()), get("Insufficient_Space_Title"), JOptionPane.ERROR_MESSAGE);
    305                                                 // Nothing else can be done by the Gatherer. In fact if we are really out of space I'm not even sure we can quit safely.
    306                                           }
    307                                           catch(UnknownFileErrorException ufe_exception) {
    308                                                 Gatherer.printStackTrace(ufe_exception);
    309                                                 cancel_action = true;
    310                                                 // Show warning
    311                                                 JOptionPane.showMessageDialog(Gatherer.g_man, get("Unknown_File_Error_Message"), get("Unknown_File_Error_Title"), JOptionPane.ERROR_MESSAGE);
    312                                                 // Nothing else we can do.
    313                                           }
    314                                           catch(IOException exception) {
    315                                                 // Can't really do much about this.
    316                                                 Gatherer.printStackTrace(exception);
    317                                           }
    318                                           // If not cancelled
    319                                           if(!cancel_action) {
    320                                                 // Step one is to create a dummy FileNode. Its important it has the correct structure so getPath works.
    321                                                 FileNode new_record = new FileNode(target_file);
    322                                                 SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, new_record);
    323                                               new_node = new_record;
    324 
    325                                               // create undo job
    326                                                 if(job.undoable) {
    327                                                      job.undoable = false;
    328                                                      if(job.type == FileJob.COPY) {
    329                                                           // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent!
    330                                                           Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, new_record, job.undo);
    331                                                      }
    332                                                      else {
    333                                                           // Movements however do need a source and source parent so the file can be moved back to the correct place.
    334                                                           Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, new_record, job.undo);
    335                                                      }
    336                                                 }
    337                                                 new_record = null;
    338                                           }
    339                                      }
    340                                      // Else
    341                                      else if(source_file.isDirectory()) {
    342                                           // create new record
    343                                           FileNode directory_record = new FileNode(target_file);
    344                                           ///ystem.err.println("Directory record = " + directory_record + " (" + target_file.getAbsolutePath() + ")");
    345                                           SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, directory_record);
    346                                           // Why is this not happening eh?
    347                                           directory_record.setParent(destination_node);
    348                                           if(!target_file.exists()) {
    349                                              // make the directory
    350                                                 target_file.mkdirs();
    351                                                 new_node = directory_record;
    352                                               // create undo job
    353                                                 if(job.undoable) {
    354                                                      job.undoable = false;
    355                                                      if(job.type == FileJob.COPY) {
    356                                                           // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent!
    357                                                           Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, directory_record, job.undo);
    358                                                      }
    359                                                      else {
    360                                                           // Movements however do need a source and source parent so the file can be moved back to the correct place.
    361                                                           Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, directory_record, job.undo);
    362                                                      }
    363                                                 }
    364                                           }
    365                                           // Else inform the users that a directory already exists and files will be copied into it
    366                                           else {
    367                                                 JOptionPane.showMessageDialog(null, get("Directory_Exists", target_file.toString()), get("General.Warning"), JOptionPane.WARNING_MESSAGE);
    368                                           }
    369                                           // Queue non-filtered child files for copying. If this directory already existed, the child records will have to generate the undo jobs, as we don't want to entirely delete this directory if it already existed.
    370                                           FileNode child_record = null;
    371                                           // In order to have a sane copy proceedure (rather than always copying last file first as it used to) we always add the child node at the position the parent was removed from. Consider the file job 'a' at the end of the queue which generates three new jobs 'b', 'c' and 'd'. The resulting flow should look like this.
    372                                           // -- Starting queue                   ...[a]
    373                                           // remove(position) = 'a'              ...
    374                                           // add(position, 'b')                  ...[b]
    375                                           // add(position, 'c')                  ...[c][b]
    376                                           // add(position, 'd')                  ...[d][c][b]
    377                                           // Next loop
    378                                           // remove(position) = 'b'              ...[d][c]
    379                                           for(int i = 0; i < origin_node.getChildCount(); i++) {
    380                                                 child_record = (FileNode) origin_node.getChildAt(i);
    381                                                 addJob(job.ID(), job.source, child_record, job.target, directory_record, job.type, job.undo, false, false, position);
    382                                           }
    383                                           child_record = null;
    384                                           directory_record = null;
    385                                      }
    386                                      // The file wasn't found!
    387                                      else {
    388                                           cancel_action = true;
    389                                           // Show warning.
    390                                           JOptionPane.showMessageDialog(Gatherer.g_man, get("File_Not_Found_Message", source_file.getName()), get("File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
    391                                           // Force refresh of source folder.
    392                                           source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
    393                                      }
     282                    copyFile(source_file, target_file, progress);
     283                }
     284                // If we can't find the source file, then the most likely reason is that the file system has changed since the last time it was mapped. Warn the user that the requested file can't be found, then force a refresh of the source folder involved.
     285                catch(FileNotFoundException fnf_exception) {
     286                    Gatherer.printStackTrace(fnf_exception);
     287                    cancel_action = true;
     288                    // Show warning.
     289                    JOptionPane.showMessageDialog(Gatherer.g_man, get("File_Not_Found_Message", source_file.getName()), get("File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
     290                    // Force refresh of source folder.
     291                    source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
     292                }
     293                catch(FileAlreadyExistsException fae_exception) {
     294                    Gatherer.printStackTrace(fae_exception);
     295                    cancel_action = true;
     296                    // Show warning.
     297                    JOptionPane.showMessageDialog(Gatherer.g_man, get("File_Already_Exists_Message", target_file.getName()), get("File_Already_Exists_Title"), JOptionPane.ERROR_MESSAGE);
     298                    // Nothing else can be done by the Gatherer.
     299                }
     300                catch(InsufficientSpaceException is_exception) {
     301                    Gatherer.printStackTrace(is_exception);
     302                    cancel_action = true;
     303                    // Show warning. The message body of the expection explains how much more space is required for this file copy.
     304                    JOptionPane.showMessageDialog(Gatherer.g_man, get("Insufficient_Space_Message", is_exception.getMessage()), get("Insufficient_Space_Title"), JOptionPane.ERROR_MESSAGE);
     305                    // Nothing else can be done by the Gatherer. In fact if we are really out of space I'm not even sure we can quit safely.
     306                }
     307                catch(UnknownFileErrorException ufe_exception) {
     308                    Gatherer.printStackTrace(ufe_exception);
     309                    cancel_action = true;
     310                    // Show warning
     311                    JOptionPane.showMessageDialog(Gatherer.g_man, get("Unknown_File_Error_Message"), get("Unknown_File_Error_Title"), JOptionPane.ERROR_MESSAGE);
     312                    // Nothing else we can do.
     313                }
     314                catch(IOException exception) {
     315                    // Can't really do much about this.
     316                    Gatherer.printStackTrace(exception);
     317                }
     318                // If not cancelled
     319                if(!cancel_action) {
     320                    // Step one is to create a dummy FileNode. Its important it has the correct structure so getPath works.
     321                    FileNode new_record = new FileNode(target_file);
     322                    SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, new_record);
     323                    new_node = new_record;
     324
     325                    // create undo job
     326                    if(job.undoable) {
     327                    job.undoable = false;
     328                    if(job.type == FileJob.COPY) {
     329                        // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent!
     330                        Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, new_record, job.undo);
     331                    }
     332                    else {
     333                        // Movements however do need a source and source parent so the file can be moved back to the correct place.
     334                        Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, new_record, job.undo);
     335                    }
     336                    }
     337                    new_record = null;
     338                }
     339                }
     340                // Else
     341                else if(source_file.isDirectory()) {
     342                // create new record
     343                FileNode directory_record = new FileNode(target_file);
     344                ///ystem.err.println("Directory record = " + directory_record + " (" + target_file.getAbsolutePath() + ")");
     345                SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, directory_record);
     346                // Why is this not happening eh?
     347                directory_record.setParent(destination_node);
     348                if(!target_file.exists()) {
     349                    // make the directory
     350                    target_file.mkdirs();
     351                    new_node = directory_record;
     352                    // create undo job
     353                    if(job.undoable) {
     354                    job.undoable = false;
     355                    if(job.type == FileJob.COPY) {
     356                        // A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent!
     357                        Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, directory_record, job.undo);
     358                    }
     359                    else {
     360                        // Movements however do need a source and source parent so the file can be moved back to the correct place.
     361                        Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, directory_record, job.undo);
     362                    }
     363                    }
     364                }
     365                // Else inform the users that a directory already exists and files will be copied into it
     366                else {
     367                    JOptionPane.showMessageDialog(null, get("Directory_Exists", target_file.toString()), get("General.Warning"), JOptionPane.WARNING_MESSAGE);
     368                }
     369                // Queue non-filtered child files for copying. If this directory already existed, the child records will have to generate the undo jobs, as we don't want to entirely delete this directory if it already existed.
     370                FileNode child_record = null;
     371                // In order to have a sane copy proceedure (rather than always copying last file first as it used to) we always add the child node at the position the parent was removed from. Consider the file job 'a' at the end of the queue which generates three new jobs 'b', 'c' and 'd'. The resulting flow should look like this.
     372                // -- Starting queue                   ...[a]
     373                // remove(position) = 'a'              ...
     374                // add(position, 'b')                  ...[b]
     375                // add(position, 'c')                  ...[c][b]
     376                // add(position, 'd')                  ...[d][c][b]
     377                // Next loop
     378                // remove(position) = 'b'              ...[d][c]
     379                for(int i = 0; i < origin_node.getChildCount(); i++) {
     380                    child_record = (FileNode) origin_node.getChildAt(i);
     381                    addJob(job.ID(), job.source, child_record, job.target, directory_record, job.type, job.undo, false, false, position);
     382                }
     383                child_record = null;
     384                directory_record = null;
     385                }
     386                // The file wasn't found!
     387                else {
     388                cancel_action = true;
     389                // Show warning.
     390                JOptionPane.showMessageDialog(Gatherer.g_man, get("File_Not_Found_Message", source_file.getName()), get("File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
     391                // Force refresh of source folder.
     392                source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
     393                }
    394394                                     
    395                                     // We can't have been cancelled, and we must have created a new FileNode during the above phase, before we can handle metadata.
    396                                     if(!cancel_action && new_node != null) {
    397                                           /* Time to handle any existing metadata. */
    398                                           // If the directory came from inside our collection...
    399                                           if (job.source.toString().equals("Collection")) {
    400                                                 ///ystem.err.println("Move within collection...");
    401                                                 GDMManager gdm = Gatherer.c_man.getCollection().gdm;
    402                                               // we just retrieve the metadata attached to the origin node...
    403                                                 ArrayList existing_metadata = gdm.getMetadata(source_file);
    404                                                 ///ystem.err.println("Existing metadata for " + origin_node + ": " + gdm.toString(existing_metadata));
    405                                               // then assign this remainder to the new folder.
    406                                                 ///ystem.err.println("New metadata: " + gdm.toString(existing_metadata));
    407                                                 gdm.addMetadata(new_node, existing_metadata);
    408                                                 existing_metadata = null;
    409                                                 gdm = null;
    410                                           }
    411                                           // If it came from the recycle bin retrieve the metadata from there, once again remembering to account for inherited metadata
    412                                           else if (job.source.toString().equals("Undo")) {
    413                                                 GDMManager gdm = Gatherer.c_man.getCollection().gdm;
    414                                                 // Retrieve metadata from the recycle bin
    415                                                 ArrayList existing_metadata = Gatherer.c_man.undo.getMetadata(source_file);
    416                                                 // then assign this remainder to the new folder.
    417                                                 gdm.addMetadata(new_node, existing_metadata);
    418                                                 existing_metadata = null;
    419                                                 gdm = null;
    420                                           }
    421                                           // Otherwise if it came from the workspace use the MSMs parsers to search for folder level metadata (such as metadata.xml or marc records).
    422                                           else if (job.source.toString().equals("Workspace")) {
    423                                                 cancel_action = Gatherer.c_man.getCollection().msm.searchForMetadata(new_node, origin_node, source_file.isDirectory());
    424                                           }
    425                                     }
    426                                     new_node = null;
    427 
    428                                 }
    429                           }
    430                           // If we haven't been cancelled, and we've been asked to delete a directory/file, or perhaps as part of a move, we delete the file. This involves removing any existing metadata and then copying the file to the recycled bin (for a delete only), then deleting the file. When deleting a directory record from the tree (or from the filesystem for that matter) we must ensure that all of the descendant records have already been removed. If we fail to do this the delete will fail, or you will be bombarded with hundreds of 'Parent node of null not allowed' error messages. Also be aware that if the user has cancelled just this action, because of say a name clash, then we shouldn't do any deleting of any sort dammit.
    431                           if(!cancel_action && ready && (job.type == FileJob.DELETE || job.type == FileJob.MOVE)) {
    432                                 ///ystem.err.print("Delete/Move: " + origin_node + " -> ");
    433                                 // If the source is an empty directory or a file. Don't do anything to the root node of a tree.
    434                                 File[] child_list = source_file.listFiles();
    435                                 if(source_file.isFile() || (child_list != null && (child_list.length == 0 || (child_list.length == 1 && child_list[0].getName().equals(Utility.METADATA_XML))) && origin_node.getParent() != null)) {
    436                                     ///ystem.err.println("File or empty directory.");
    437                                     // Delete any metadata.xml still in the directory.
    438                                     if(child_list != null && child_list.length == 1) {
    439                                           child_list[0].delete();
    440                                     }
    441 
    442                                     ///ystem.err.println("Origin is file or is directory and is empty.");
    443                                     // update status area
    444                                     String args[] = new String[1];
    445                                     args[0] = "" + (queue.size() + 1) + "";
    446                                     job_status.setText(get("Jobs", args));
    447                                     args[0] = Utility.formatPath("FileActions.Deleting", source_file.getAbsolutePath(), file_status.getSize().width);
    448                                     file_status.setText(get("Deleting", args));
    449                                     args = null;
    450                                     file_status.setToolTipText(Utility.formatHTMLWidth(file_status.getText(), 80));
    451                                     // Remove its metadata
    452                                     ArrayList metadatum = null;
    453                                     if(job.source == Gatherer.c_man.undo) {
    454                                           Gatherer.c_man.undo.addMetadata(target_file, metadatum);
    455                                     }
    456                                     else {
    457                                           metadatum= Gatherer.c_man.getCollection().gdm.removeMetadata(origin_node.getFile());
    458                                     }
    459                                     // determine it parent node
    460                                     FileNode parent_record = (FileNode)origin_node.getParent();
    461                                     // Remove from model
    462                                     SynchronizedTreeModelTools.removeNodeFromParent(source_model, origin_node);
    463                                     // If we are deleting
    464                                     File recycled_file = null;
    465                                     FileNode recycled_parent = null;
    466                                     if(job.type == FileJob.DELETE) {
    467                                           // See if this record already has a previous recycle folder noted in the recycle folder mappings.
    468                                           recycled_parent = (FileNode) recycle_folder_mappings.get(origin_node);
    469                                           if(recycled_parent != null) {
    470                                                 recycle_folder_mappings.remove(origin_node);
    471                                           }
    472                                           else {
    473                                                 recycled_parent = (FileNode) Gatherer.c_man.undo.getTreeModel().getRoot();
    474                                           }
    475                                           // This may be a directory which we have already added previously.
    476                                           if(completed_folder_mappings.containsKey(origin_node)) {
    477                                                 FileNode recycled_record = (FileNode) completed_folder_mappings.get(origin_node);
    478                                               // Replace the temporary directory record in the undo tree with this one.
    479                                               SynchronizedTreeModelTools.replaceNode(Gatherer.c_man.undo.getTreeModel(), recycled_record, origin_node);
    480                                                 origin_node.setFile(recycled_record.getFile());
    481                                           }
    482                                           else {
    483                                               // copy the file to the recycle bin
    484                                                 recycled_file = new File(recycled_parent.getFile(), origin_node.toString());
    485                                                 // If the file already exists, delete it.
    486                                                 if(recycled_file.exists()) {
    487                                                      recycled_file.delete();
    488                                                 }
    489                                                 recycled_file.deleteOnExit();
    490                                                 copyFile(source_file, recycled_file, progress);
    491                                                 origin_node.setFile(recycled_file);
    492                                               // Add the node to the appropriate place in the UndoManagers tree model. Unfortunately this one does have the possibility of altering the GUI (if the removeNodeFromParent above hasn't occured yet), so we must put it on the queue.
    493                                               SynchronizedTreeModelTools.insertNodeInto(Gatherer.c_man.undo.getTreeModel(), recycled_parent, origin_node);
    494                                           }
    495                                           Gatherer.c_man.undo.addMetadata(source_file, metadatum);
    496                                     }
    497                                     // delete the source file
    498                                     Utility.delete(source_file);
    499                                     // create undo job as necessary. File move would have been handled above.
    500                                     if(job.undoable) {
    501                                           job.undoable = false;
    502                                           // The target is null, indicating that we moved this file to the recycle bin. The UndoManager will replace null with 'this'.
    503                                           Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_DELETE, job.source, parent_record, null, origin_node, job.undo);
    504                                     }
    505                                     recycled_parent = null;
    506                                     recycled_file = null;
    507                                     //metadatum = null;
    508                                 }
    509                                 // Else the source is a directory and it has children remaining
    510                                 else if(child_list != null && child_list.length > 0) {
    511                                     ///ystem.err.print("Nonempty directory -> ");
    512                                     ///ystem.err.println("Directory is non-empty. Remove children first.");
    513                                     FileNode recycle_folder_record = null;
    514                                     // Don't worry about all this for true file move actions.
    515                                     if(job.type == FileJob.DELETE) {
    516                                           // See if this record already has a previous recycle folder noted in the recycle folder mappings.
    517                                           FileNode parent = (FileNode) recycle_folder_mappings.get(origin_node);
    518                                           if(parent != null) {
    519                                                 recycle_folder_mappings.remove(origin_node);
    520                                           }
    521                                           else {
    522                                                 parent = (FileNode) Gatherer.c_man.undo.getTreeModel().getRoot();
    523                                           }
    524                                           // We must add the folder node to our undo manager tree now, so we'll have something to add children to. We use a copy of the directory file record.
    525                                           File recycle_folder = new File(parent.getFile(), origin_node.toString());
    526                                           recycle_folder.deleteOnExit();
    527                                           recycle_folder.mkdirs();
    528                                           recycle_folder_record = new FileNode(recycle_folder);
    529                                           // Add this node to the undo tree model.
    530                                           SynchronizedTreeModelTools.insertNodeInto(Gatherer.c_man.undo.getTreeModel(), parent, recycle_folder_record);
    531                                           // We add an entry to the complete mappings to ensure this directory isn't added again
    532                                           completed_folder_mappings.put(origin_node, recycle_folder_record);
    533                                           ///ystem.err.println("Added completed directories mapping " + origin_node);
    534                                           // queue all of its children, (both filtered and non-filtered), but for deleting only. Don't queue jobs for a current move event, as they would be queued as part of copying. I have no idea way, per sec, however the children within the origin node are always invalid during deletion (there are several copies of some nodes?!?). I'll check that each child is only added once.
    535                                           ///ystem.err.println("Directory has " + origin_node.getChildCount() + " children.");
    536                                           ///ystem.err.println("Directory actually has " + child_list.length + " children.");
    537                                           origin_node.unmap();
    538                                           origin_node.map();
    539                                           ///ystem.err.println("Directory has " + origin_node.getChildCount() + " children.");
    540                                           ///ystem.err.println("Directory actually has " + child_list.length + " children.");
    541                                           for(int i = 0; i < origin_node.getChildCount(); i++) {
    542                                                 FileNode child_record = (FileNode) origin_node.getChildAt(i);
    543                                                 addJob(job.ID(), job.source, child_record, job.target, destination_node, FileJob.DELETE, job.undo, false, false, position);
    544                                                 if(recycle_folder_record != null) {
    545                                                      recycle_folder_mappings.put(child_record, recycle_folder_record);
    546                                                 }
    547                                           }
    548                                     }
    549                                     // Requeue a delete job -after- the children have been dealt with. Remember I've reversed the direction of the queue so sooner is later. Te-he. Also have to remember that we have have followed this path to get here for a move job: Copy Directory -> Queue Child Files -> Delete Directory (must occur after child files) -> Queue Directory.
    550                                     // One special case. Do not requeue root nodes. Don't requeue jobs marked as done.
    551                                     if(origin_node.getParent() != null && !job.done) {
    552                                           ///ystem.err.println("Requeue");
    553                                           job.type = FileJob.DELETE; // You only requeue jobs that are deletes, as directories must be inspected before children, but deleted after.
    554                                           addJob(job, position);
    555                                     }
    556                                     else {
    557                                           ///ystem.err.println("I've already done this job twice. I refuse to requeue it again!!!");
    558                                     }
    559                                 }
    560                           }
    561                           job = null;
    562                           source_file = null;
    563                           target_file = null;
    564                           origin_node = null;
    565                           // We can only break out of the while loop if we are out of files, or if the action was cancelled.
    566                           if(cancel_action) {
    567                                 // Empty queue
    568                                 clearJobs();
    569                                 cancel_action = false;
    570                           }
    571                           // Debugging pause.
    572                           ///ystem.err.println("Job complete.");
    573                      }
    574                      else {
    575                           synchronized(this) {
    576                                 ///ystem.err.println("Queue size = " + queue.size());
    577                                 // Force the trees to refresh (but only if there is something on screen!)
    578                                 if(Gatherer.g_man != null) {
    579                                     Gatherer.g_man.refreshTrees();
    580                                 }
    581                                 // Reset status area
    582                                 job_status.setText(get("No_Selection"));
    583                                 file_status.setText(get("No_Activity"));
    584                                 progress.reset();
    585                                 progress.setString(get("No_Activity"));
    586                                 yes_to_all = false;         
    587                                 completed_folder_mappings.clear();
    588                                 recycle_folder_mappings.clear();
    589                                 // Now wait if applicable.
    590                                 if(return_immediately) {
    591                                     return;
    592                                 }
    593                                 ///ystem.err.println("Waiting");
    594                                 wait();
    595                           }
    596                      }
    597                 }
    598                 catch (Exception error) {
    599                      Gatherer.printStackTrace(error);
    600                 }
    601           }
    602     }
    603     /** A second lock is necessary to prevent the thread waiting, because its notify occured momentarily before it waited. If the flag is set then the thread can't wait, but loops around. This may chew processor time so should only be used if you are certain files are about to be placed on the queue.
     395                // We can't have been cancelled, and we must have created a new FileNode during the above phase, before we can handle metadata.
     396                if(!cancel_action && new_node != null) {
     397                /* Time to handle any existing metadata. */
     398                // If the directory came from inside our collection...
     399                if (job.source.toString().equals("Collection")) {
     400                    ///ystem.err.println("Move within collection...");
     401                    GDMManager gdm = Gatherer.c_man.getCollection().gdm;
     402                    // we just retrieve the metadata attached to the origin node...
     403                    ArrayList existing_metadata = gdm.getMetadata(source_file);
     404                    ///ystem.err.println("Existing metadata for " + origin_node + ": " + gdm.toString(existing_metadata));
     405                    // then assign this remainder to the new folder.
     406                    ///ystem.err.println("New metadata: " + gdm.toString(existing_metadata));
     407                    gdm.addMetadata(new_node, existing_metadata);
     408                    existing_metadata = null;
     409                    gdm = null;
     410                }
     411                // If it came from the recycle bin retrieve the metadata from there, once again remembering to account for inherited metadata
     412                else if (job.source.toString().equals("Undo")) {
     413                    GDMManager gdm = Gatherer.c_man.getCollection().gdm;
     414                    // Retrieve metadata from the recycle bin
     415                    ArrayList existing_metadata = Gatherer.c_man.undo.getMetadata(source_file);
     416                    // then assign this remainder to the new folder.
     417                    gdm.addMetadata(new_node, existing_metadata);
     418                    existing_metadata = null;
     419                    gdm = null;
     420                }
     421                // Otherwise if it came from the workspace use the MSMs parsers to search for folder level metadata (such as metadata.xml or marc records).
     422                else if (job.source.toString().equals("Workspace")) {
     423                    cancel_action = Gatherer.c_man.getCollection().msm.searchForMetadata(new_node, origin_node, source_file.isDirectory());
     424                }
     425                }
     426                new_node = null;
     427
     428            }
     429            }
     430            // If we haven't been cancelled, and we've been asked to delete a directory/file, or perhaps as part of a move, we delete the file. This involves removing any existing metadata and then copying the file to the recycled bin (for a delete only), then deleting the file. When deleting a directory record from the tree (or from the filesystem for that matter) we must ensure that all of the descendant records have already been removed. If we fail to do this the delete will fail, or you will be bombarded with hundreds of 'Parent node of null not allowed' error messages. Also be aware that if the user has cancelled just this action, because of say a name clash, then we shouldn't do any deleting of any sort dammit.
     431            if(!cancel_action && ready && (job.type == FileJob.DELETE || job.type == FileJob.MOVE)) {
     432            ///ystem.err.print("Delete/Move: " + origin_node + " -> ");
     433            // If the source is an empty directory or a file. Don't do anything to the root node of a tree.
     434            File[] child_list = source_file.listFiles();
     435            if(source_file.isFile() || (child_list != null && (child_list.length == 0 || (child_list.length == 1 && child_list[0].getName().equals(Utility.METADATA_XML))) && origin_node.getParent() != null)) {
     436                ///ystem.err.println("File or empty directory.");
     437                // Delete any metadata.xml still in the directory.
     438                if(child_list != null && child_list.length == 1) {
     439                child_list[0].delete();
     440                }
     441
     442                ///ystem.err.println("Origin is file or is directory and is empty.");
     443                // update status area
     444                String args[] = new String[1];
     445                args[0] = "" + (queue.size() + 1) + "";
     446                job_status.setText(get("Jobs", args));
     447                args[0] = Utility.formatPath("FileActions.Deleting", source_file.getAbsolutePath(), file_status.getSize().width);
     448                file_status.setText(get("Deleting", args));
     449                args = null;
     450                file_status.setToolTipText(Utility.formatHTMLWidth(file_status.getText(), 80));
     451                // Remove its metadata
     452                ArrayList metadatum = null;
     453                if(job.source == Gatherer.c_man.undo) {
     454                Gatherer.c_man.undo.addMetadata(target_file, metadatum);
     455                }
     456                else {
     457                metadatum= Gatherer.c_man.getCollection().gdm.removeMetadata(origin_node.getFile());
     458                }
     459                // determine it parent node
     460                FileNode parent_record = (FileNode)origin_node.getParent();
     461                // Remove from model
     462                SynchronizedTreeModelTools.removeNodeFromParent(source_model, origin_node);
     463                // If we are deleting
     464                File recycled_file = null;
     465                FileNode recycled_parent = null;
     466                if(job.type == FileJob.DELETE) {
     467                // See if this record already has a previous recycle folder noted in the recycle folder mappings.
     468                recycled_parent = (FileNode) recycle_folder_mappings.get(origin_node);
     469                if(recycled_parent != null) {
     470                    recycle_folder_mappings.remove(origin_node);
     471                }
     472                else {
     473                    recycled_parent = (FileNode) Gatherer.c_man.undo.getTreeModel().getRoot();
     474                }
     475                // This may be a directory which we have already added previously.
     476                if(completed_folder_mappings.containsKey(origin_node)) {
     477                    FileNode recycled_record = (FileNode) completed_folder_mappings.get(origin_node);
     478                    // Replace the temporary directory record in the undo tree with this one.
     479                    SynchronizedTreeModelTools.replaceNode(Gatherer.c_man.undo.getTreeModel(), recycled_record, origin_node);
     480                    origin_node.setFile(recycled_record.getFile());
     481                }
     482                else {
     483                    // copy the file to the recycle bin
     484                    recycled_file = new File(recycled_parent.getFile(), origin_node.toString());
     485                    // If the file already exists, delete it.
     486                    if(recycled_file.exists()) {
     487                    recycled_file.delete();
     488                    }
     489                    recycled_file.deleteOnExit();
     490                    copyFile(source_file, recycled_file, progress);
     491                    origin_node.setFile(recycled_file);
     492                    // Add the node to the appropriate place in the UndoManagers tree model. Unfortunately this one does have the possibility of altering the GUI (if the removeNodeFromParent above hasn't occured yet), so we must put it on the queue.
     493                    SynchronizedTreeModelTools.insertNodeInto(Gatherer.c_man.undo.getTreeModel(), recycled_parent, origin_node);
     494                }
     495                Gatherer.c_man.undo.addMetadata(source_file, metadatum);
     496                }
     497                // delete the source file
     498                Utility.delete(source_file);
     499                // create undo job as necessary. File move would have been handled above.
     500                if(job.undoable) {
     501                job.undoable = false;
     502                // The target is null, indicating that we moved this file to the recycle bin. The UndoManager will replace null with 'this'.
     503                Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_DELETE, job.source, parent_record, null, origin_node, job.undo);
     504                }
     505                recycled_parent = null;
     506                recycled_file = null;
     507                //metadatum = null;
     508            }
     509            // Else the source is a directory and it has children remaining
     510            else if(child_list != null && child_list.length > 0) {
     511                ///ystem.err.print("Nonempty directory -> ");
     512                ///ystem.err.println("Directory is non-empty. Remove children first.");
     513                FileNode recycle_folder_record = null;
     514                // Don't worry about all this for true file move actions.
     515                if(job.type == FileJob.DELETE) {
     516                // See if this record already has a previous recycle folder noted in the recycle folder mappings.
     517                FileNode parent = (FileNode) recycle_folder_mappings.get(origin_node);
     518                if(parent != null) {
     519                    recycle_folder_mappings.remove(origin_node);
     520                }
     521                else {
     522                    parent = (FileNode) Gatherer.c_man.undo.getTreeModel().getRoot();
     523                }
     524                // We must add the folder node to our undo manager tree now, so we'll have something to add children to. We use a copy of the directory file record.
     525                File recycle_folder = new File(parent.getFile(), origin_node.toString());
     526                recycle_folder.deleteOnExit();
     527                recycle_folder.mkdirs();
     528                recycle_folder_record = new FileNode(recycle_folder);
     529                // Add this node to the undo tree model.
     530                SynchronizedTreeModelTools.insertNodeInto(Gatherer.c_man.undo.getTreeModel(), parent, recycle_folder_record);
     531                // We add an entry to the complete mappings to ensure this directory isn't added again
     532                completed_folder_mappings.put(origin_node, recycle_folder_record);
     533                ///ystem.err.println("Added completed directories mapping " + origin_node);
     534                // queue all of its children, (both filtered and non-filtered), but for deleting only. Don't queue jobs for a current move event, as they would be queued as part of copying. I have no idea way, per sec, however the children within the origin node are always invalid during deletion (there are several copies of some nodes?!?). I'll check that each child is only added once.
     535                ///ystem.err.println("Directory has " + origin_node.getChildCount() + " children.");
     536                ///ystem.err.println("Directory actually has " + child_list.length + " children.");
     537                origin_node.unmap();
     538                origin_node.map();
     539                ///ystem.err.println("Directory has " + origin_node.getChildCount() + " children.");
     540                ///ystem.err.println("Directory actually has " + child_list.length + " children.");
     541                for(int i = 0; i < origin_node.getChildCount(); i++) {
     542                    FileNode child_record = (FileNode) origin_node.getChildAt(i);
     543                    addJob(job.ID(), job.source, child_record, job.target, destination_node, FileJob.DELETE, job.undo, false, false, position);
     544                    if(recycle_folder_record != null) {
     545                    recycle_folder_mappings.put(child_record, recycle_folder_record);
     546                    }
     547                }
     548                }
     549                // Requeue a delete job -after- the children have been dealt with. Remember I've reversed the direction of the queue so sooner is later. Te-he. Also have to remember that we have have followed this path to get here for a move job: Copy Directory -> Queue Child Files -> Delete Directory (must occur after child files) -> Queue Directory.
     550                // One special case. Do not requeue root nodes. Don't requeue jobs marked as done.
     551                if(origin_node.getParent() != null && !job.done) {
     552                ///ystem.err.println("Requeue");
     553                job.type = FileJob.DELETE; // You only requeue jobs that are deletes, as directories must be inspected before children, but deleted after.
     554                addJob(job, position);
     555                }
     556                else {
     557                ///ystem.err.println("I've already done this job twice. I refuse to requeue it again!!!");
     558                }
     559            }
     560            }
     561            job = null;
     562            source_file = null;
     563            target_file = null;
     564            origin_node = null;
     565            // We can only break out of the while loop if we are out of files, or if the action was cancelled.
     566            if(cancel_action) {
     567            // Empty queue
     568            clearJobs();
     569            cancel_action = false;
     570            }
     571            // Debugging pause.
     572            ///ystem.err.println("Job complete.");
     573        }
     574        else {
     575            synchronized(this) {
     576            ///ystem.err.println("Queue size = " + queue.size());
     577            // Force the trees to refresh (but only if there is something on screen!)
     578            if(Gatherer.g_man != null) {
     579                Gatherer.g_man.refreshTrees();
     580            }
     581            // Reset status area
     582            job_status.setText(get("No_Selection"));
     583            file_status.setText(get("No_Activity"));
     584            progress.reset();
     585            progress.setString(get("No_Activity"));
     586            yes_to_all = false;         
     587            completed_folder_mappings.clear();
     588            recycle_folder_mappings.clear();
     589            // Now wait if applicable.
     590            if(return_immediately) {
     591                return;
     592            }
     593            ///ystem.err.println("Waiting");
     594            wait();
     595            }
     596        }
     597        }
     598        catch (Exception error) {
     599        Gatherer.printStackTrace(error);
     600        }
     601    }
     602    }
     603    /** A second lock is necessary to prevent the thread waiting, because its notify occured momentarily before it waited. If the flag is set then the thread can't wait, but loops around. This may chew processor time so should only be used if you are certain files are about to be placed on the queue.
    604604      * @param wait_allowed The new state of the wait_allowed flag, as a boolean.
    605605      */
    606     public void setWaitAllowed(boolean wait_allowed) {
    607           this.wait_allowed = wait_allowed;
    608     }
    609     /** Restore the progress bar so that it updates normally.
     606    public void setWaitAllowed(boolean wait_allowed) {
     607    this.wait_allowed = wait_allowed;
     608    }
     609    /** Restore the progress bar so that it updates normally.
    610610      * @see org.greenstone.gatherer.gui.LongProgressBar
    611611      */
    612     synchronized public void unpause() {
    613           progress.setIndeterminate(false);
    614           if(previous != null) {
    615                 progress.setString(previous);
    616                 previous = null;
    617           }
    618     }
    619     /** Called when the user makes some selection in one of the trees we are listening to. From this we update the status details. */
    620     public void valueChanged(TreeSelectionEvent event) {
    621           JTree tree = (JTree) event.getSource();
    622           if(tree.getSelectionCount() > 0) {
    623                 TreePath selection[] = tree.getSelectionPaths();
    624                 int file_count = 0;
    625                 int dir_count = 0;
    626                 for(int i = 0; i < selection.length; i++) {
    627                      TreeNode record = (TreeNode) selection[i].getLastPathComponent();
    628                      if(record.isLeaf()) {
    629                           file_count++;
    630                      }
    631                      else {
    632                           dir_count++;
    633                      }
    634                      record = null;
    635                 }
    636                 selection = null;
    637                 String args[] = new String[2];
    638                 args[0] = "" + file_count + "";
    639                 args[1] = "" + dir_count + "";
    640                 job_status.setText(get("Selected", args));
    641                 args = null;
    642           }
    643           tree = null;
    644     }
    645 
    646     synchronized private void clearJobs() {
    647           queue.clear();
    648     }
    649 
    650     /** Copy a file from the source location to the destination location.
     612    synchronized public void unpause() {
     613    progress.setIndeterminate(false);
     614    if(previous != null) {
     615        progress.setString(previous);
     616        previous = null;
     617    }
     618    }
     619    /** Called when the user makes some selection in one of the trees we are listening to. From this we update the status details. */
     620    public void valueChanged(TreeSelectionEvent event) {
     621    JTree tree = (JTree) event.getSource();
     622    if(tree.getSelectionCount() > 0) {
     623        TreePath selection[] = tree.getSelectionPaths();
     624        int file_count = 0;
     625        int dir_count = 0;
     626        for(int i = 0; i < selection.length; i++) {
     627        TreeNode record = (TreeNode) selection[i].getLastPathComponent();
     628        if(record.isLeaf()) {
     629            file_count++;
     630        }
     631        else {
     632            dir_count++;
     633        }
     634        record = null;
     635        }
     636        selection = null;
     637        String args[] = new String[2];
     638        args[0] = "" + file_count + "";
     639        args[1] = "" + dir_count + "";
     640        job_status.setText(get("Selected", args));
     641        args = null;
     642    }
     643    tree = null;
     644    }
     645
     646    synchronized private void clearJobs() {
     647    queue.clear();
     648    }
     649
     650    /** Copy a file from the source location to the destination location.
    651651      * @param source The source File.
    652652      * @param destination The destination File.
    653653      * @see org.greenstone.gatherer.Gatherer
    654654      */
    655     public void copyFile(File source, File destination, LongProgressBar progress)
    656           throws FileAlreadyExistsException, FileNotFoundException, InsufficientSpaceException, IOException, UnknownFileErrorException {
    657           if(source.isDirectory()) {
    658                 destination.mkdirs();
    659           }
    660           else {
     655    public void copyFile(File source, File destination, LongProgressBar progress)
     656    throws FileAlreadyExistsException, FileNotFoundException, InsufficientSpaceException, IOException, UnknownFileErrorException {
     657    if(source.isDirectory()) {
     658        destination.mkdirs();
     659    }
     660    else {
    661661                // Check if the origin file exists.
    662                 if(!source.exists()) {
    663                      throw(new FileNotFoundException());
    664                 }
     662        if(!source.exists()) {
     663        throw(new FileNotFoundException());
     664        }
    665665                // Check if the destination file does not exist.
    666                 if(destination.exists()) {
    667                      throw(new FileAlreadyExistsException());
    668                 }
    669                 File dirs = destination.getParentFile();
    670                 dirs.mkdirs();
     666        if(destination.exists()) {
     667        throw(new FileAlreadyExistsException());
     668        }
     669        File dirs = destination.getParentFile();
     670        dirs.mkdirs();
    671671                // Copy the file.
    672                 FileInputStream f_in = new FileInputStream(source);
    673                 FileOutputStream f_out = new FileOutputStream(destination);
    674                 byte data[] = new byte[Utility.BUFFER_SIZE];
    675                 int data_size = 0;
    676                 while((data_size = f_in.read(data, 0, Utility.BUFFER_SIZE)) != -1 && !cancel_action) {
    677                      long destination_size = destination.length();
    678                      try {
    679                           f_out.write(data, 0, data_size);
    680                      }
    681                      // If an IO exception occurs, we can do some maths to determine if the number of bytes written to the file was less than expected. If so we assume a InsufficientSpace exception. If not we just throw the exception again.
    682                      catch (IOException io_exception) {
    683                           if(destination_size + (long) data_size > destination.length()) {
    684                                 // Determine the difference (which I guess is in bytes).
    685                                 long difference = (destination_size + (long) data_size) - destination.length();
    686                                 // Transform that into a human readable string.
    687                                 String message = Utility.formatFileLength(difference);
    688                                 throw(new InsufficientSpaceException(message));
    689                           }
    690                           else {
    691                                 throw(io_exception);
    692                           }
    693                      }
    694                      if(progress != null) {
    695                           progress.addValue(data_size);
    696                      }
    697                 }
     672        FileInputStream f_in = new FileInputStream(source);
     673        FileOutputStream f_out = new FileOutputStream(destination);
     674        byte data[] = new byte[Utility.BUFFER_SIZE];
     675        int data_size = 0;
     676        while((data_size = f_in.read(data, 0, Utility.BUFFER_SIZE)) != -1 && !cancel_action) {
     677        long destination_size = destination.length();
     678        try {
     679            f_out.write(data, 0, data_size);
     680        }
     681        // If an IO exception occurs, we can do some maths to determine if the number of bytes written to the file was less than expected. If so we assume a InsufficientSpace exception. If not we just throw the exception again.
     682        catch (IOException io_exception) {
     683            if(destination_size + (long) data_size > destination.length()) {
     684            // Determine the difference (which I guess is in bytes).
     685            long difference = (destination_size + (long) data_size) - destination.length();
     686            // Transform that into a human readable string.
     687            String message = Utility.formatFileLength(difference);
     688            throw(new InsufficientSpaceException(message));
     689            }
     690            else {
     691            throw(io_exception);
     692            }
     693        }
     694        if(progress != null) {
     695            progress.addValue(data_size);
     696        }
     697        }
    698698                // Flush and close the streams to ensure all bytes are written.
    699                 f_in.close();
    700                 f_out.close();
     699        f_in.close();
     700        f_out.close();
    701701                // We have now, in theory, produced an exact copy of the source file. Check this by comparing sizes.
    702                 if(!cancel_action && source.length() != destination.length()) {
    703                      throw(new UnknownFileErrorException());
    704                 }
     702        if(!cancel_action && source.length() != destination.length()) {
     703        throw(new UnknownFileErrorException());
     704        }
    705705                // If we were cancelled, ensure that none of the destination file exists.
    706                 if(cancel_action) {
    707                      destination.delete();
    708                 }
    709           }
    710     }
    711     /** Retrieve a phrase from the dictionary based on the key.
     706        if(cancel_action) {
     707        destination.delete();
     708        }
     709    }
     710    }
     711    /** Retrieve a phrase from the dictionary based on the key.
    712712      * @param key The key index as a String.
    713713      * @return The desired phrase also as a String.
    714714      */
    715     private String get(String key) {
    716           return get(key, (String[])null);
    717     }
    718     /** Retrieve a phrase from the dictionary based on the key, and taking into account the given argument.
     715    private String get(String key) {
     716    return get(key, (String[])null);
     717    }
     718    /** Retrieve a phrase from the dictionary based on the key, and taking into account the given argument.
    719719      * @param key The key index as a String.
    720720      * @param args A String which is the argument to be added to the phrase.
    721721      * @return The desired phrase also as a String.
    722722      */
    723     private String get(String key, String arg) {
    724           String args[] = new String[1];
    725           args[0] = arg;
    726           return get(key, args);
    727     }
    728     /** Retrieve a phrase from the dictionary based on the key, and taking into account the given arguments.
     723    private String get(String key, String arg) {
     724    String args[] = new String[1];
     725    args[0] = arg;
     726    return get(key, args);
     727    }
     728    /** Retrieve a phrase from the dictionary based on the key, and taking into account the given arguments.
    729729      * @param key The key index as a String.
    730730      * @param args A String[] of arguments to be added to the phrase.
     
    733733      * @see org.greenstone.gatherer.Gatherer
    734734      */
    735     private String get(String key, String args[]) {
    736           if(key.indexOf('.') == -1) {
    737                 key = "FileActions." + key;
    738           }
    739           return Gatherer.dictionary.get(key, args);
    740     }
    741 
    742     private FileJob removeJob(int position) {
    743           FileJob job = null;
    744           if(queue.size() > 0) {
    745                 job = (FileJob) queue.remove(position);
    746           }
    747           return job;
    748     }
     735    private String get(String key, String args[]) {
     736    if(key.indexOf('.') == -1) {
     737        key = "FileActions." + key;
     738    }
     739    return Gatherer.dictionary.get(key, args);
     740    }
     741
     742    private FileJob removeJob(int position) {
     743    FileJob job = null;
     744    if(queue.size() > 0) {
     745        job = (FileJob) queue.remove(position);
     746    }
     747    return job;
     748    }
    749749}
  • trunk/gli/src/org/greenstone/gatherer/file/FileSystemModel.java

    r4293 r4366  
    1414
    1515public class FileSystemModel
    16     extends DefaultTreeModel
    17     implements TreeExpansionListener, TreeWillExpandListener {
    18 
    19     private DragTree tree;
    20     private FileFilter current_filter;
    21     private FileFilter[] filters;
    22     static private FileFilter[] default_filters = { new FileFilter("\\..*", true), new FileFilter("metadata\\.xml", true) };
    23 
    24     public FileSystemModel(FileNode root) {
    25           super(root);
    26           current_filter = null;
    27           filters = null;
    28           tree = null;
    29           root.setModel(this);
    30           root.map();
    31     }
    32 
    33     public FileFilter[] getFilters() {
    34           if(filters == null) {
    35                 if(current_filter != null) {
    36                      filters = new FileFilter[default_filters.length + 1];
    37                      filters[default_filters.length] = current_filter;
    38                 }
    39                 else {
    40                      filters = new FileFilter[default_filters.length];
    41                 }
    42                 System.arraycopy(default_filters, 0, filters, 0, default_filters.length);
    43           }
    44           return filters;
    45     }
     16    extends DefaultTreeModel
     17    implements TreeExpansionListener, TreeWillExpandListener {
     18
     19    private DragTree tree;
     20    private FileFilter current_filter;
     21    private FileFilter[] filters;
     22    static private FileFilter[] default_filters = { new FileFilter("\\..*", true), new FileFilter("metadata\\.xml", true) };
     23
     24    public FileSystemModel(FileNode root) {
     25    super(root);
     26    current_filter = null;
     27    filters = null;
     28    tree = null;
     29    root.setModel(this);
     30    root.map();
     31    }
     32
     33    public FileFilter[] getFilters() {
     34    if(filters == null) {
     35        if(current_filter != null) {
     36        filters = new FileFilter[default_filters.length + 1];
     37        filters[default_filters.length] = current_filter;
     38        }
     39        else {
     40        filters = new FileFilter[default_filters.length];
     41        }
     42        System.arraycopy(default_filters, 0, filters, 0, default_filters.length);
     43    }
     44    return filters;
     45    }
    4646     
    47     /** Retrieve the node denoted by the given tree path. Note that this isn't equivelent to saying path.lastPathComponent, as the references within the path may be stale. */
    48     public FileNode getNode(TreePath path) {
    49           ///ystem.err.println("**** getNode(" + path + ") ****");
    50           FileNode current = (FileNode)root;
    51           // Special case for the root node. Check the first path component is the root node.
    52           FileNode first_node = (FileNode)path.getPathComponent(0);
    53           if(current.equals(first_node)) {
     47    /** Retrieve the node denoted by the given tree path. Note that this isn't equivelent to saying path.lastPathComponent, as the references within the path may be stale. */
     48    public FileNode getNode(TreePath path) {
     49    ///ystem.err.println("**** getNode(" + path + ") ****");
     50    FileNode current = (FileNode)root;
     51    // Special case for the root node. Check the first path component is the root node.
     52    FileNode first_node = (FileNode)path.getPathComponent(0);
     53    if(current.equals(first_node)) {
    5454                ///ystem.err.println("First path component matches root node.");
    5555                // For each path with this tree path
    56                 for(int i = 1; current != null && i < path.getPathCount(); i++) {
    57                      // Retrieve the stale path
    58                      FileNode stale_node = (FileNode) path.getPathComponent(i);
    59                      ///ystem.err.print("Searching for '" + stale_node + "': ");
    60                      // Locate the fresh node by searching current's children. Remember to ensure that current is mapped.
    61                      current.map();
    62                      boolean found = false;
    63                      for(int j = 0; !found && j < current.getChildCount(); j++) {
    64                           FileNode child_node = (FileNode) current.getChildAt(j);
    65                           ///ystem.err.print(child_node + " ");
    66                           if(stale_node.equals(child_node)) {
    67                                 found = true;
    68                                 current = child_node;
    69                                 ///ystem.err.println("Found!");
    70                           }
    71                           child_node = null;
    72                      }
    73                      // If no match is found, then set current to null and exit.
    74                      if(!found) {
    75                           current = null;
    76                           ///ystem.err.println("Not Found!");
    77                      }
    78                      // Repeat as necessary
    79                 }
    80           }
    81           ///ystem.err.println("Returning node: " + new TreePath(current.getPath()));
    82           return current;
    83     }
    84 
    85     public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index) {
    86           ///ystem.err.println("insertNodeInto(" + newChild + ", " + parent + ", " + index + ")");
    87           super.insertNodeInto(newChild, parent, index);
    88     }
    89 
    90     public void mapDirectory(File directory, String title) {
    91           FileNode node = new FileNode(directory, this, title, true);
    92           SynchronizedTreeModelTools.insertNodeInto(this, (FileNode)root, node);
    93     }
    94 
    95     /** Used to refresh the contents of the FileNode indicated by the tree path. While the refresh itself is a piece of the proverbial, the restoring of expanded folders afterwards is a nightmare, mainly because all of the tree paths are no longer valid (remember that refresh involves throwing away the node currents children and remapping them).
    96       * @param path The TreePath to the node to be refreshed.
    97       */
    98     public void refresh(TreePath path) {
    99           // If no path is set, take the path to the root node (ie update the whole tree)
    100           if(path == null) {
     56        for(int i = 1; current != null && i < path.getPathCount(); i++) {
     57        // Retrieve the stale path
     58        FileNode stale_node = (FileNode) path.getPathComponent(i);
     59        ///ystem.err.print("Searching for '" + stale_node + "': ");
     60        // Locate the fresh node by searching current's children. Remember to ensure that current is mapped.
     61        current.map();
     62        boolean found = false;
     63        for(int j = 0; !found && j < current.getChildCount(); j++) {
     64            FileNode child_node = (FileNode) current.getChildAt(j);
     65            ///ystem.err.print(child_node + " ");
     66            if(stale_node.equals(child_node)) {
     67            found = true;
     68            current = child_node;
     69            ///ystem.err.println("Found!");
     70            }
     71            child_node = null;
     72        }
     73        // If no match is found, then set current to null and exit.
     74        if(!found) {
     75            current = null;
     76            ///ystem.err.println("Not Found!");
     77        }
     78        // Repeat as necessary
     79        }
     80    }
     81    ///ystem.err.println("Returning node: " + new TreePath(current.getPath()));
     82    return current;
     83    }
     84
     85    public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index) {
     86    ///ystem.err.println("insertNodeInto(" + newChild + ", " + parent + ", " + index + ")");
     87    super.insertNodeInto(newChild, parent, index);
     88    }
     89
     90    public void mapDirectory(File directory, String title) {
     91    FileNode node = new FileNode(directory, this, title, true);
     92    SynchronizedTreeModelTools.insertNodeInto(this, (FileNode)root, node);
     93    }
     94
     95    /** Used to refresh the contents of the FileNode indicated by the tree path. While the refresh itself is a piece of the proverbial, the restoring of expanded folders afterwards is a nightmare, mainly because all of the tree paths are no longer valid (remember that refresh involves throwing away the node currents children and remapping them).
     96     * @param path The TreePath to the node to be refreshed.
     97     */
     98    public void refresh(TreePath path) {
     99    // If no path is set, take the path to the root node (ie update the whole tree)
     100    if(path == null) {
    101101                ///ystem.err.println("Refresh entire tree.");
    102                 path = new TreePath(((FileNode)root).getPath());
    103           }
    104           else {
     102        path = new TreePath(((FileNode)root).getPath());
     103    }
     104    else {
    105105                ///ystem.err.println("Refresh: " + path.getLastPathComponent());
    106           }
    107           // Only a valid action if this model is currently being displayed in a tree.
    108           if(tree != null) {
     106    }
     107    // Only a valid action if this model is currently being displayed in a tree.
     108    if(tree != null) {
    109109                // Retrieve the error node.
    110                 FileNode node = (FileNode) path.getLastPathComponent();
     110        FileNode node = (FileNode) path.getLastPathComponent();
    111111                // If this error node is a dummy node (ie has no associated file) we can't unmap it, so we iterate through its children refreshing each in turn.
    112                 if(node.getFile() == null) {
    113                      for(int i = 0; i < node.getChildCount(); i++) {
    114                           FileNode child = (FileNode) node.getChildAt(i);
    115                           refresh(new TreePath(child.getPath()));
    116                           child = null;
    117                      }
    118                 }
     112        if(node.getFile() == null) {
     113        for(int i = 0; i < node.getChildCount(); i++) {
     114            FileNode child = (FileNode) node.getChildAt(i);
     115            refresh(new TreePath(child.getPath()));
     116            child = null;
     117        }
     118        }
    119119                // Otherwise we refresh this node.
    120                 else {
    121                      // Record all of the expanded paths under this node. How come getExpandedDescendants returns more results each time.
    122                      Enumeration old_tree_paths = tree.getExpandedDescendants(path);
    123                      // Refresh the tree structure.
    124                      node.unmap();
    125                      node.map();
    126                      // Fire the appropriate event.
    127                      nodeStructureChanged(node);
    128                      // Then (painfully) restore the expanded paths. Note that the paths stored in the enumeration no longer exist, so I have to restore by node matching.
    129                      //counter = 0;
    130                      ///ystem.err.println("After:");
    131                      while(old_tree_paths != null && old_tree_paths.hasMoreElements()) {
    132                           //counter++;
    133                           FileNode current_node = node;
    134                           TreePath old_tree_path = (TreePath) old_tree_paths.nextElement();
    135                           ///ystem.err.println(counter + ". " + old_tree_path);
    136                           TreePath new_tree_path = new TreePath(path.getPath()); // Why isn't there a treepath copy constructor!
    137                           boolean not_found = false;
    138                           while(!not_found && old_tree_path.getPathCount() > new_tree_path.getPathCount()) {
    139                                 // Retrieve the new node in the old tree path
    140                                 FileNode old_path_node = (FileNode) old_tree_path.getPathComponent(new_tree_path.getPathCount());
    141                                 // Ensure the current node is mapped
    142                                 current_node.map();
    143                                 // Now attempt to match it to a child of the new paths last node.
    144                                 boolean found = false;
    145                                 for(int i = 0; !found && i < current_node.getChildCount(); i++) {
    146                                     FileNode target = (FileNode) current_node.getChildAt(i);
    147                                     ///ystem.err.println("Comparing " + old_path_node.toString() + " with " + target);
    148                                     if(target.toString().equals(old_path_node.toString())) {
    149                                           current_node = target;
    150                                           found = true;
    151                                     }
    152                                     target = null;
    153                                 }
    154                                 old_path_node = null;
    155                                 // If we found a match, we add that to the new Tree Path and continue.
    156                                 if(found) {
    157                                     ///ystem.err.println("Found a match!");
    158                                     new_tree_path = new_tree_path.pathByAddingChild(current_node);
    159                                 }
    160                                 // We also have to record if we were unable to find a match in the current nodes children.
    161                                 else {
    162                                     ///ystem.err.println("Node not found.");
    163                                     not_found = true;
    164                                 }
    165                           }
    166                           old_tree_path = null;
    167                           // If we've got this far, and haven't hit a not found, then we can assume we have the appropriate path, and ask the program to expand the new tree path
    168                           if(!not_found) {
    169                                 tree.expandPath(new_tree_path);
    170                                 ///ystem.err.println(" -> Expanded " + new_tree_path);
    171                           }
    172                           else {
    173                                 ///ystem.err.println(" -> Cannot Expand " + new_tree_path);
    174                           }
    175                           new_tree_path = null;
    176                           current_node = null;
    177                      }
    178                      node = null;
    179                 }
    180           }
    181           else {
     120        else {
     121        // Record all of the expanded paths under this node. How come getExpandedDescendants returns more results each time.
     122        Enumeration old_tree_paths = tree.getExpandedDescendants(path);
     123        // Refresh the tree structure.
     124        node.unmap();
     125        node.map();
     126        // Fire the appropriate event.
     127        nodeStructureChanged(node);
     128        // Then (painfully) restore the expanded paths. Note that the paths stored in the enumeration no longer exist, so I have to restore by node matching.
     129        //counter = 0;
     130        ///ystem.err.println("After:");
     131        while(old_tree_paths != null && old_tree_paths.hasMoreElements()) {
     132            //counter++;
     133            FileNode current_node = node;
     134            TreePath old_tree_path = (TreePath) old_tree_paths.nextElement();
     135            ///ystem.err.println(counter + ". " + old_tree_path);
     136            TreePath new_tree_path = new TreePath(path.getPath()); // Why isn't there a treepath copy constructor!
     137            boolean not_found = false;
     138            while(!not_found && old_tree_path.getPathCount() > new_tree_path.getPathCount()) {
     139            // Retrieve the new node in the old tree path
     140            FileNode old_path_node = (FileNode) old_tree_path.getPathComponent(new_tree_path.getPathCount());
     141            // Ensure the current node is mapped
     142            current_node.map();
     143            // Now attempt to match it to a child of the new paths last node.
     144            boolean found = false;
     145            for(int i = 0; !found && i < current_node.getChildCount(); i++) {
     146                FileNode target = (FileNode) current_node.getChildAt(i);
     147                ///ystem.err.println("Comparing " + old_path_node.toString() + " with " + target);
     148                if(target.toString().equals(old_path_node.toString())) {
     149                current_node = target;
     150                found = true;
     151                }
     152                target = null;
     153            }
     154            old_path_node = null;
     155            // If we found a match, we add that to the new Tree Path and continue.
     156            if(found) {
     157                ///ystem.err.println("Found a match!");
     158                new_tree_path = new_tree_path.pathByAddingChild(current_node);
     159            }
     160            // We also have to record if we were unable to find a match in the current nodes children.
     161            else {
     162                ///ystem.err.println("Node not found.");
     163                not_found = true;
     164            }
     165            }
     166            old_tree_path = null;
     167            // If we've got this far, and haven't hit a not found, then we can assume we have the appropriate path, and ask the program to expand the new tree path
     168            if(!not_found) {
     169            tree.expandPath(new_tree_path);
     170            ///ystem.err.println(" -> Expanded " + new_tree_path);
     171            }
     172            else {
     173            ///ystem.err.println(" -> Cannot Expand " + new_tree_path);
     174            }
     175            new_tree_path = null;
     176            current_node = null;
     177        }
     178        node = null;
     179        }
     180    }
     181    else {
    182182                ///ystem.err.println("No Tree!");
    183           }
    184     }
    185 
    186     public void setFilter(String pattern) {
    187           if(pattern != null) {
    188                 current_filter = new FileFilter(pattern, false);
    189           }
    190           else {
    191                 current_filter = null;
    192           }
    193           filters = null;
    194     }
    195 
    196     public void setTree(DragTree tree) {
    197           this.tree = tree;
    198     }
    199 
    200     public String toString() {
    201           if(tree != null) {
    202                 return tree.toString();
    203           }
    204           return "FileSystemModel";
    205     }
    206 
    207     /** Called whenever an item in the tree has been collapsed. */
    208     public void treeCollapsed(TreeExpansionEvent event) {
    209           // Deallocate the affected nodes children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
    210           TreePath path = event.getPath();
    211           FileNode node = (FileNode) path.getLastPathComponent();
    212           node.unmap();
    213           // Fire the appropriate event.
    214           nodeStructureChanged(node);
    215     }
    216 
    217     /** Called whenever an item in the tree has been expanded. */
    218     public void treeExpanded(TreeExpansionEvent event) {
    219     }
    220 
    221     /** Invoked whenever a node in the tree is about to be collapsed. */
    222     public void treeWillCollapse(TreeExpansionEvent event)
    223           throws ExpandVetoException {
    224           // Veto the event if the user is attempting to collapse the root node (regardless of whether it is visible.
    225           TreePath path = event.getPath();
    226           if(path.getPathCount() == 1) {
    227                 throw new ExpandVetoException(event, "Cannot collapse root node!");
    228           }
    229     }
     183    }
     184    }
     185
     186    public void setFilter(String pattern) {
     187    if(pattern != null) {
     188        current_filter = new FileFilter(pattern, false);
     189    }
     190    else {
     191        current_filter = null;
     192    }
     193    filters = null;
     194    }
     195
     196    public void setTree(DragTree tree) {
     197    this.tree = tree;
     198    }
     199
     200    public String toString() {
     201    if(tree != null) {
     202        return tree.toString();
     203    }
     204    return "FileSystemModel";
     205    }
     206
     207    /** Called whenever an item in the tree has been collapsed. */
     208    public void treeCollapsed(TreeExpansionEvent event) {
     209    // Deallocate the affected nodes children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
     210    TreePath path = event.getPath();
     211    FileNode node = (FileNode) path.getLastPathComponent();
     212    node.unmap();
     213    // Fire the appropriate event.
     214    nodeStructureChanged(node);
     215    }
     216
     217    /** Called whenever an item in the tree has been expanded. */
     218    public void treeExpanded(TreeExpansionEvent event) {
     219    }
     220
     221    /** Invoked whenever a node in the tree is about to be collapsed. */
     222    public void treeWillCollapse(TreeExpansionEvent event)
     223    throws ExpandVetoException {
     224    // Veto the event if the user is attempting to collapse the root node (regardless of whether it is visible.
     225    TreePath path = event.getPath();
     226    if(path.getPathCount() == 1) {
     227        throw new ExpandVetoException(event, "Cannot collapse root node!");
     228    }
     229    }
    230230     
    231     /** Invoked whenever a node in the tree is about to be expanded. */
    232     public void treeWillExpand(TreeExpansionEvent event)
    233           throws ExpandVetoException {
    234           // Set the wait cursor.
    235           Gatherer.g_man.wait(true);
    236           // Allocate the children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
    237           TreePath path = event.getPath();
    238           FileNode node = (FileNode) path.getLastPathComponent();
    239           node.map();
    240           nodeStructureChanged(node);
    241           // Restore the cursor.
    242           Gatherer.g_man.wait(false);
    243     }
     231    /** Invoked whenever a node in the tree is about to be expanded. */
     232    public void treeWillExpand(TreeExpansionEvent event)
     233    throws ExpandVetoException {
     234    // Set the wait cursor.
     235    Gatherer.g_man.wait(true);
     236    // Allocate the children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
     237    TreePath path = event.getPath();
     238    FileNode node = (FileNode) path.getLastPathComponent();
     239    node.map();
     240    nodeStructureChanged(node);
     241    // Restore the cursor.
     242    Gatherer.g_man.wait(false);
     243    }
    244244}
  • trunk/gli/src/org/greenstone/gatherer/file/InsufficientSpaceException.java

    r4293 r4366  
    44
    55public class InsufficientSpaceException
    6     extends Exception {
     6    extends Exception {
    77
    8     public InsufficientSpaceException(String message) {
    9           super(message);
    10     }
     8    public InsufficientSpaceException(String message) {
     9    super(message);
     10    }
    1111}
  • trunk/gli/src/org/greenstone/gatherer/file/UnknownFileErrorException.java

    r4293 r4366  
    44
    55public class UnknownFileErrorException
    6     extends Exception {
     6    extends Exception {
    77
    8     public UnknownFileErrorException() {
    9           super();
    10     }
     8    public UnknownFileErrorException() {
     9    super();
     10    }
    1111}
  • trunk/gli/src/org/greenstone/gatherer/gui/browser/GBrowserEvent.java

    r4293 r4366  
    5353 */
    5454public class GBrowserEvent
    55     extends AWTEvent {
     55    extends AWTEvent {
    5656
    57     /** The url payload of this event. */
    58     private GURL url = null;
     57    /** The url payload of this event. */
     58    private GURL url = null;
    5959
    60     private JProgressBar progress = null;
     60    private JProgressBar progress = null;
    6161
    62     /** The message payload of this event. */
    63     private String message = null;
     62    /** The message payload of this event. */
     63    private String message = null;
    6464
    65     /** This contructor is used to pass events about GURLs out to its
    66       * listeners. The source and id are needed by the super class of AWTEvents
    67       * but the url is specific to this class.
    68       * @param source the class Object that fired this event.
    69       * @param id a numeric identifier for this event.
    70       * @param url the GURL about which this event is concerned.
    71       */
    72     public GBrowserEvent(Object source, int id, GURL url) {
    73           super(source, id);
    74           this.url = url;
    75     }
     65    /** This contructor is used to pass events about GURLs out to its
     66     * listeners. The source and id are needed by the super class of AWTEvents
     67     * but the url is specific to this class.
     68     * @param source the class Object that fired this event.
     69     * @param id a numeric identifier for this event.
     70     * @param url the GURL about which this event is concerned.
     71     */
     72    public GBrowserEvent(Object source, int id, GURL url) {
     73    super(source, id);
     74    this.url = url;
     75    }
    7676
    77     /** This contructor is used to pass events about GURLs out to its
    78       * listeners. The source and id are needed by the super class of AWTEvents
    79       * but the url and message are specific to this class.
    80       * @param source the class Object that fired this event.
    81       * @param id a numeric identifier for this event.
    82       * @param url the GURL about which this event is concerned.
    83       * @param message a message String, the reason for this event.
    84       */
    85     public GBrowserEvent(Object source, int id, GURL url, String message) {
    86           super(source, id);
    87           this.url = url;
    88     }
     77    /** This contructor is used to pass events about GURLs out to its
     78     * listeners. The source and id are needed by the super class of AWTEvents
     79     * but the url and message are specific to this class.
     80     * @param source the class Object that fired this event.
     81     * @param id a numeric identifier for this event.
     82     * @param url the GURL about which this event is concerned.
     83     * @param message a message String, the reason for this event.
     84     */
     85    public GBrowserEvent(Object source, int id, GURL url, String message) {
     86    super(source, id);
     87    this.url = url;
     88    }
    8989
    90     /** This constructor is used to pass message events out to its listeners.
    91       * It is much the same as the first constructor, however instead of a
    92       * GURL as payload, we instead have a message String.
    93       * @param source the class Object that fired this event.
    94       * @param id a numeric identifier for this event.
    95       * @param message a message String, the reason for this event.
    96       */
    97     public GBrowserEvent(Object source, int id, String message) {
    98           super(source, id);
    99           this.message = message;
    100     }
     90    /** This constructor is used to pass message events out to its listeners.
     91     * It is much the same as the first constructor, however instead of a
     92     * GURL as payload, we instead have a message String.
     93     * @param source the class Object that fired this event.
     94     * @param id a numeric identifier for this event.
     95     * @param message a message String, the reason for this event.
     96     */
     97    public GBrowserEvent(Object source, int id, String message) {
     98    super(source, id);
     99    this.message = message;
     100    }
    101101
    102     /** Used to get the GURL contained within this event.
    103       * @return a GURL specifying the url this event is concerned with, or null
    104       * if this is a message type event.
    105       */
    106     public GURL getURL() {
    107           return url;
    108     }
     102    /** Used to get the GURL contained within this event.
     103     * @return a GURL specifying the url this event is concerned with, or null
     104     * if this is a message type event.
     105     */
     106    public GURL getURL() {
     107    return url;
     108    }
    109109
    110     /** Used to get the String message contained within this event.
    111       * @return a String containing the message for this event, or null if this
    112       * is a GURL type event.
    113       */
    114     public String getMessage() {
    115           return message;
    116     }
     110    /** Used to get the String message contained within this event.
     111     * @return a String containing the message for this event, or null if this
     112     * is a GURL type event.
     113     */
     114    public String getMessage() {
     115    return message;
     116    }
    117117
    118     /** Returns a boolean showing whether it is legal to request this GURLs
    119       * progress bar. All GURLs have progress bars, but only those spawned in
    120       * GHTMLPanes etc will actually have their progress bars updated. Webclient
    121       * does not yet support this functionality but will eventually via the
    122       * DocumentProgressEvent.
    123       * @return A boolean specifying whether this GURL supports ProgressBar
    124       * requests.
    125       */
    126     public boolean hasProgress() {
    127           if(progress != null) {
    128                 return true;
    129           }
    130           return false;
    131     }
     118    /** Returns a boolean showing whether it is legal to request this GURLs
     119     * progress bar. All GURLs have progress bars, but only those spawned in
     120     * GHTMLPanes etc will actually have their progress bars updated. Webclient
     121     * does not yet support this functionality but will eventually via the
     122     * DocumentProgressEvent.
     123     * @return A boolean specifying whether this GURL supports ProgressBar
     124     * requests.
     125     */
     126    public boolean hasProgress() {
     127    if(progress != null) {
     128        return true;
     129    }
     130    return false;
     131    }
    132132}
    133133
  • trunk/gli/src/org/greenstone/gatherer/gui/browser/GBrowserListener.java

    r4293 r4366  
    4747
    4848public interface GBrowserListener
    49     extends EventListener {
    50     public void actionFailed(GBrowserEvent event);
    51     public void controlsChanged();
    52     public void hyperlinkClick(GBrowserEvent event);
    53     public void renderBegun(GBrowserEvent event);
    54     public void renderComplete(GBrowserEvent event);
    55     public void statusChanged(GBrowserEvent event);
     49    extends EventListener {
     50    public void actionFailed(GBrowserEvent event);
     51    public void controlsChanged();
     52    public void hyperlinkClick(GBrowserEvent event);
     53    public void renderBegun(GBrowserEvent event);
     54    public void renderComplete(GBrowserEvent event);
     55    public void statusChanged(GBrowserEvent event);
    5656}
  • trunk/gli/src/org/greenstone/gatherer/gui/browser/GHTMLPane.java

    r4293 r4366  
    7171 */
    7272public class GHTMLPane
    73     extends JPanel
    74     implements HTMLViewPane, HyperlinkListener, PropertyChangeListener {
     73    extends JPanel
     74    implements HTMLViewPane, HyperlinkListener, PropertyChangeListener {
    7575     
    76     /** follow_links - does the class automatically follow hyperlinks. */
    77     boolean follow_links = true;
    78     /** ready - has the view finished rendering the current URL. */
    79     boolean ready = true;
    80     /** the list of listeners associated with this class. */
    81     EventListenerList listeners = null;
    82     /** gatherer - a reference to the main class of Gatherer for messaging. */
    83     Gatherer gatherer = null;
    84     /** view - the JEditorPane the page content will be rendered on to. */
    85     JEditorPane view = null;
    86     Object control = null;
    87     /** current_page - the URL of the currently shown page. */
    88     GURL current_url = null;
    89     /** back_pages - Vector of pages that have been visited. */
    90     Vector back_pages = null;
    91     /** Vector of pages that have been backed up from.
    92       *  Reset whenever a new url 'path' is entered.
    93       */
    94     Vector forward_pages = null;
    95 
    96 
    97     /** Constructor - collects initial settings, lays out view, renders initial
    98       *  URL.
    99       *  @param gatherer - the main class of Gatherer
    100       */
    101     public GHTMLPane(Gatherer gatherer, Object control) {
    102           this.gatherer = gatherer;
    103           this.control = control;
    104           this.setLayout(new BorderLayout());
    105 
    106           listeners = new EventListenerList();
    107 
    108           back_pages = new Vector();
    109           forward_pages = new Vector();
    110 
    111           gatherer.debug("\t\tCreating GHTMLPane");
    112           view = new JEditorPane();
    113           view.setEditable(false);
    114           view.addHyperlinkListener(this);
    115           view.addPropertyChangeListener(this);
    116           this.add(new JScrollPane(view), BorderLayout.CENTER);
    117     }
    118 
    119     public void addGBrowserListener(GBrowserListener listener) {
    120           listeners.add(GBrowserListener.class, listener);
    121     }
    122 
    123     public void afterDisplay() {
    124           // Nothing to do. Only realy for embedded apps.
    125     }
    126 
    127     public boolean back() {
    128           // Add current page to forward
    129           forward_pages.add(0,current_url);
    130           // Back up one page.
    131           current_url = (GURL) back_pages.lastElement();
    132           back_pages.remove(back_pages.size() - 1);
    133           this.setPage(current_url);
    134           return true;
    135     }
    136 
    137     public boolean canBack() {
    138           if(back_pages.size() > 0 && ready) {
    139                 return true;
    140           }
    141           return false;
    142     }
    143 
    144     public boolean canForward() {
    145           if(forward_pages.size() > 0 && ready) {
    146                 return true;
    147           }
    148           return false;
    149     }
    150 
    151     public boolean canStop() {
    152           if(!ready) {
    153                 return true;
    154           }
    155           return false;
    156     }
    157 
    158     // This code courtesy of Horst ([email protected]) who provides this solution
    159     // to the crap null exception I keep getting when I try to grab the image
    160     // of a rendered HTML.
    161     public BufferedImage capture() {
    162           if(ready) {
     76    /** follow_links - does the class automatically follow hyperlinks. */
     77    boolean follow_links = true;
     78    /** ready - has the view finished rendering the current URL. */
     79    boolean ready = true;
     80    /** the list of listeners associated with this class. */
     81    EventListenerList listeners = null;
     82    /** gatherer - a reference to the main class of Gatherer for messaging. */
     83    Gatherer gatherer = null;
     84    /** view - the JEditorPane the page content will be rendered on to. */
     85    JEditorPane view = null;
     86    Object control = null;
     87    /** current_page - the URL of the currently shown page. */
     88    GURL current_url = null;
     89    /** back_pages - Vector of pages that have been visited. */
     90    Vector back_pages = null;
     91    /** Vector of pages that have been backed up from.
     92     *  Reset whenever a new url 'path' is entered.
     93     */
     94    Vector forward_pages = null;
     95
     96
     97    /** Constructor - collects initial settings, lays out view, renders initial
     98     *  URL.
     99     *  @param gatherer - the main class of Gatherer
     100     */
     101    public GHTMLPane(Gatherer gatherer, Object control) {
     102    this.gatherer = gatherer;
     103    this.control = control;
     104    this.setLayout(new BorderLayout());
     105
     106    listeners = new EventListenerList();
     107
     108    back_pages = new Vector();
     109    forward_pages = new Vector();
     110
     111    gatherer.debug("\t\tCreating GHTMLPane");
     112    view = new JEditorPane();
     113    view.setEditable(false);
     114    view.addHyperlinkListener(this);
     115    view.addPropertyChangeListener(this);
     116    this.add(new JScrollPane(view), BorderLayout.CENTER);
     117    }
     118
     119    public void addGBrowserListener(GBrowserListener listener) {
     120    listeners.add(GBrowserListener.class, listener);
     121    }
     122
     123    public void afterDisplay() {
     124    // Nothing to do. Only realy for embedded apps.
     125    }
     126
     127    public boolean back() {
     128    // Add current page to forward
     129    forward_pages.add(0,current_url);
     130    // Back up one page.
     131    current_url = (GURL) back_pages.lastElement();
     132    back_pages.remove(back_pages.size() - 1);
     133    this.setPage(current_url);
     134    return true;
     135    }
     136
     137    public boolean canBack() {
     138    if(back_pages.size() > 0 && ready) {
     139        return true;
     140    }
     141    return false;
     142    }
     143
     144    public boolean canForward() {
     145    if(forward_pages.size() > 0 && ready) {
     146        return true;
     147    }
     148    return false;
     149    }
     150
     151    public boolean canStop() {
     152    if(!ready) {
     153        return true;
     154    }
     155    return false;
     156    }
     157
     158    // This code courtesy of Horst ([email protected]) who provides this solution
     159    // to the crap null exception I keep getting when I try to grab the image
     160    // of a rendered HTML.
     161    public BufferedImage capture() {
     162    if(ready) {
    163163                // Paint to an off screen buffer
    164                 Dimension size = view.getSize();
     164        Dimension size = view.getSize();
    165165                //Graphics offgraphics = offscreen.getGraphics();
    166                 BufferedImage offscreen =
    167                      new BufferedImage(size.width, size.height,
    168                                             BufferedImage.TYPE_INT_RGB);
    169                 Graphics2D offgraphics = (Graphics2D) offscreen.getGraphics();
     166        BufferedImage offscreen =
     167        new BufferedImage(size.width, size.height,
     168                  BufferedImage.TYPE_INT_RGB);
     169        Graphics2D offgraphics = (Graphics2D) offscreen.getGraphics();
    170170                // For some reason the clip rect is null for the created image
    171171                // (usually it is set to the size of the image) so set it.
    172                 offgraphics.setClip(0, 0, size.width, size.height);
    173                 offgraphics.setColor(getBackground());
    174                 offgraphics.fillRect(0, 0, size.width, size.height);
     172        offgraphics.setClip(0, 0, size.width, size.height);
     173        offgraphics.setColor(getBackground());
     174        offgraphics.fillRect(0, 0, size.width, size.height);
    175175                // This will display components in the HTML Page
    176                 view.paint(offgraphics);
    177                 return offscreen;
    178           }
    179           return null;
    180     }
     176        view.paint(offgraphics);
     177        return offscreen;
     178    }
     179    return null;
     180    }
    181181         
    182     public GURL current() {
    183           return current_url;
    184     }
    185 
    186     public void followHyperlinks(boolean value) {
    187           follow_links = value;
    188     }
    189 
    190     public boolean forward() {
    191           // Add current page to back
    192           back_pages.add(current_url);
    193           // Show forward page.
    194           current_url = (GURL) forward_pages.firstElement();
    195           forward_pages.remove(0);
    196           setPage(current_url);
    197           return true;
    198     }
    199 
    200     /** Since you can't add an interface to a component hierarchy this method is required to get a reference of the actual rendering component.
    201       * @return This HTMLViewPane implementation as a component.
    202       */
    203     public Component getContent() {
    204           return this;
    205     }
    206 
    207     public JProgressBar getProgress() {
    208           // Currently not available. Will have to do some magic using the
    209           // view.getStream() function.
    210           return null;
    211     }
    212 
    213     /** When a hyperlink event is fired we handle it in one of several ways,
    214       * based on the event type. Enters and exits get fired off as messages to
    215       * the listeners so they can update their status bars. Clicks also fire
    216       * status changes, but their event messages include the GURLs incase we
    217       * to do something special to them. Furthermore if follow hyperlinks is
    218       * set the browser is responsible for loading up the newly designated url.
    219       * @param event A HyperlinkEvent containing useful data about the event,
    220       * such as the url in question and the position of the mouse. It also is
    221       * marked as one of several types of events including ENTERED and EXITED
    222       * (for mouseovers) and ACTIVATED (clicked).
    223       */
    224     public void hyperlinkUpdate(HyperlinkEvent event) {
    225           Object event_type = event.getEventType();
    226           GURL new_url = new GURL(event.getURL());
    227           // The mouse has been moved over a hyperlink.
    228           if (event_type == HyperlinkEvent.EventType.ENTERED) {
    229                 fireStatusChange(new GURL(event.getURL()));
    230           }
    231           else if (event_type == HyperlinkEvent.EventType.EXITED) {
    232                 fireStatusChange(null);
    233           }
    234           else if (event_type == HyperlinkEvent.EventType.ACTIVATED) {
    235                 fireHyperlinkClick(new_url);
    236                 if(follow_links) {
    237                      show(new_url);
    238                 }
    239           }
    240     }
    241 
    242     public boolean isReady() {
    243           return ready;
    244     }
    245 
    246     public void propertyChange(PropertyChangeEvent evt) {
    247           if(evt.getPropertyName() == "page") {
    248                 ready = true;
    249                 fireRenderComplete(current_url);
    250           }
    251     }
    252 
    253     public void removeGBrowserListener(GBrowserListener listener) {
    254           listeners.remove(GBrowserListener.class, listener);
    255     }
    256 
    257     public void setEnabled(boolean value) {
    258           ready = value;
    259     }
    260 
    261     public boolean show(String filename) {
    262           return show(new GURL("file:"+filename));
    263     }
    264 
    265     /**
    266       *
    267       * Precondition: ready = true <BR>
    268       */
    269     public boolean show(GURL url) {
    270           if(current_url == null) {
    271                 fireRenderBegun(url);
    272                 current_url = url;
    273                 setPage(current_url);
    274                 return true;
    275           }
    276           else {
     182    public GURL current() {
     183    return current_url;
     184    }
     185
     186    public void followHyperlinks(boolean value) {
     187    follow_links = value;
     188    }
     189
     190    public boolean forward() {
     191    // Add current page to back
     192    back_pages.add(current_url);
     193    // Show forward page.
     194    current_url = (GURL) forward_pages.firstElement();
     195    forward_pages.remove(0);
     196    setPage(current_url);
     197    return true;
     198    }
     199
     200    /** Since you can't add an interface to a component hierarchy this method is required to get a reference of the actual rendering component.
     201     * @return This HTMLViewPane implementation as a component.
     202     */
     203    public Component getContent() {
     204    return this;
     205    }
     206
     207    public JProgressBar getProgress() {
     208    // Currently not available. Will have to do some magic using the
     209    // view.getStream() function.
     210    return null;
     211    }
     212
     213    /** When a hyperlink event is fired we handle it in one of several ways,
     214     * based on the event type. Enters and exits get fired off as messages to
     215     * the listeners so they can update their status bars. Clicks also fire
     216     * status changes, but their event messages include the GURLs incase we
     217     * to do something special to them. Furthermore if follow hyperlinks is
     218     * set the browser is responsible for loading up the newly designated url.
     219     * @param event A HyperlinkEvent containing useful data about the event,
     220     * such as the url in question and the position of the mouse. It also is
     221     * marked as one of several types of events including ENTERED and EXITED
     222     * (for mouseovers) and ACTIVATED (clicked).
     223     */
     224    public void hyperlinkUpdate(HyperlinkEvent event) {
     225    Object event_type = event.getEventType();
     226    GURL new_url = new GURL(event.getURL());
     227    // The mouse has been moved over a hyperlink.
     228    if (event_type == HyperlinkEvent.EventType.ENTERED) {
     229        fireStatusChange(new GURL(event.getURL()));
     230    }
     231    else if (event_type == HyperlinkEvent.EventType.EXITED) {
     232        fireStatusChange(null);
     233    }
     234    else if (event_type == HyperlinkEvent.EventType.ACTIVATED) {
     235        fireHyperlinkClick(new_url);
     236        if(follow_links) {
     237        show(new_url);
     238        }
     239    }
     240    }
     241
     242    public boolean isReady() {
     243    return ready;
     244    }
     245
     246    public void propertyChange(PropertyChangeEvent evt) {
     247    if(evt.getPropertyName() == "page") {
     248        ready = true;
     249        fireRenderComplete(current_url);
     250    }
     251    }
     252
     253    public void removeGBrowserListener(GBrowserListener listener) {
     254    listeners.remove(GBrowserListener.class, listener);
     255    }
     256
     257    public void setEnabled(boolean value) {
     258    ready = value;
     259    }
     260
     261    public boolean show(String filename) {
     262    return show(new GURL("file:"+filename));
     263    }
     264
     265    /**
     266     *
     267     * Precondition: ready = true <BR>
     268     */
     269    public boolean show(GURL url) {
     270    if(current_url == null) {
     271        fireRenderBegun(url);
     272        current_url = url;
     273        setPage(current_url);
     274        return true;
     275    }
     276    else {
    277277                // If we are not already showing this url
    278                 if(!current_url.toString().equals(url.toString())) {
    279                      fireRenderBegun(url);
    280                      // Save a copy of the current page
    281                      back_pages.add(current_url);
    282                      current_url = url;
    283                      setPage(current_url);
    284                      return true;
    285                 }
    286           }
    287           return false;
    288     }
    289 
    290     public boolean stop() {
    291           // Unfortunately a JEditorPane is not sophisticated enough to support
    292           // this. Pretty much once you send the page to be rendered only killing
    293           // the thread will stop it, and I'm not sure you can restart the thread
    294           // later.
    295           return false;
    296     }
    297 
    298     protected void fireActionFailed(GURL url) {
    299           GBrowserEvent event = new GBrowserEvent(this,0,url);
    300           Object[] concerned = listeners.getListenerList();
    301           for(int i = 0; i < concerned.length ; i++) {
    302                 if(concerned[i] == GBrowserListener.class) {
    303                      ((GBrowserListener)concerned[i+1]).actionFailed(event);
    304                 }
    305           }
    306     }
    307 
    308     protected void fireControlsChanged() {
    309           Object[] concerned = listeners.getListenerList();
    310           for(int i = 0; i < concerned.length ; i++) {
    311                 if(concerned[i] == GBrowserListener.class) {
    312                      ((GBrowserListener)concerned[i+1]).controlsChanged();
    313                 }
    314           }
    315     }
    316 
    317     protected void fireHyperlinkClick(GURL url) {
    318           GBrowserEvent event = new GBrowserEvent(this,0,url);
    319           Object[] concerned = listeners.getListenerList();
    320           for(int i = 0; i < concerned.length ; i++) {
    321                 if(concerned[i] == GBrowserListener.class) {
    322                      ((GBrowserListener)concerned[i+1]).hyperlinkClick(event);
    323                 }
    324           }
    325     }
    326 
    327     protected void fireRenderBegun(GURL url) {
    328           GBrowserEvent event = new GBrowserEvent(this,0,url);
    329           Object[] concerned = listeners.getListenerList();
    330           for(int i = 0; i < concerned.length ; i++) {
    331                 if(concerned[i] == GBrowserListener.class) {
    332                      ((GBrowserListener)concerned[i+1]).renderBegun(event);
    333                 }
    334           }
    335     }
    336 
    337     protected void fireRenderComplete(GURL url) {
    338           GBrowserEvent event = new GBrowserEvent(this,0,url);
    339           Object[] concerned = listeners.getListenerList();
    340           for(int i = 0; i < concerned.length ; i++) {
    341                 if(concerned[i] == GBrowserListener.class) {
    342                      ((GBrowserListener)concerned[i+1]).renderComplete(event);
    343                 }
    344           }
    345     }               
    346 
    347     protected void fireStatusChange(GURL url) {
    348           GBrowserEvent event = new GBrowserEvent(this,0,url);
    349           Object[] concerned = listeners.getListenerList();
    350           for(int i = 0; i < concerned.length ; i++) {
    351                 if(concerned[i] == GBrowserListener.class) {
    352                      ((GBrowserListener)concerned[i+1]).statusChanged(event);
    353                 }
    354           }
    355     }
    356 
    357     private void setPage(GURL url) {
    358           try {
    359                 view.setPage(url.getURL());
    360           }
    361           catch (IOException e) {
    362                 Utility.showError(gatherer, "GHTMLPane.setPage()", e);
    363           }
    364           catch (Exception e) {
    365                 Utility.showError(gatherer, "Arrggg...", e);
    366           }
    367     }
     278        if(!current_url.toString().equals(url.toString())) {
     279        fireRenderBegun(url);
     280        // Save a copy of the current page
     281        back_pages.add(current_url);
     282        current_url = url;
     283        setPage(current_url);
     284        return true;
     285        }
     286    }
     287    return false;
     288    }
     289
     290    public boolean stop() {
     291    // Unfortunately a JEditorPane is not sophisticated enough to support
     292    // this. Pretty much once you send the page to be rendered only killing
     293    // the thread will stop it, and I'm not sure you can restart the thread
     294    // later.
     295    return false;
     296    }
     297
     298    protected void fireActionFailed(GURL url) {
     299    GBrowserEvent event = new GBrowserEvent(this,0,url);
     300    Object[] concerned = listeners.getListenerList();
     301    for(int i = 0; i < concerned.length ; i++) {
     302        if(concerned[i] == GBrowserListener.class) {
     303        ((GBrowserListener)concerned[i+1]).actionFailed(event);
     304        }
     305    }
     306    }
     307
     308    protected void fireControlsChanged() {
     309    Object[] concerned = listeners.getListenerList();
     310    for(int i = 0; i < concerned.length ; i++) {
     311        if(concerned[i] == GBrowserListener.class) {
     312        ((GBrowserListener)concerned[i+1]).controlsChanged();
     313        }
     314    }
     315    }
     316
     317    protected void fireHyperlinkClick(GURL url) {
     318    GBrowserEvent event = new GBrowserEvent(this,0,url);
     319    Object[] concerned = listeners.getListenerList();
     320    for(int i = 0; i < concerned.length ; i++) {
     321        if(concerned[i] == GBrowserListener.class) {
     322        ((GBrowserListener)concerned[i+1]).hyperlinkClick(event);
     323        }
     324    }
     325    }
     326
     327    protected void fireRenderBegun(GURL url) {
     328    GBrowserEvent event = new GBrowserEvent(this,0,url);
     329    Object[] concerned = listeners.getListenerList();
     330    for(int i = 0; i < concerned.length ; i++) {
     331        if(concerned[i] == GBrowserListener.class) {
     332        ((GBrowserListener)concerned[i+1]).renderBegun(event);
     333        }
     334    }
     335    }
     336
     337    protected void fireRenderComplete(GURL url) {
     338    GBrowserEvent event = new GBrowserEvent(this,0,url);
     339    Object[] concerned = listeners.getListenerList();
     340    for(int i = 0; i < concerned.length ; i++) {
     341        if(concerned[i] == GBrowserListener.class) {
     342        ((GBrowserListener)concerned[i+1]).renderComplete(event);
     343        }
     344    }
     345    }               
     346
     347    protected void fireStatusChange(GURL url) {
     348    GBrowserEvent event = new GBrowserEvent(this,0,url);
     349    Object[] concerned = listeners.getListenerList();
     350    for(int i = 0; i < concerned.length ; i++) {
     351        if(concerned[i] == GBrowserListener.class) {
     352        ((GBrowserListener)concerned[i+1]).statusChanged(event);
     353        }
     354    }
     355    }
     356
     357    private void setPage(GURL url) {
     358    try {
     359        view.setPage(url.getURL());
     360    }
     361    catch (IOException e) {
     362        Utility.showError(gatherer, "GHTMLPane.setPage()", e);
     363    }
     364    catch (Exception e) {
     365        Utility.showError(gatherer, "Arrggg...", e);
     366    }
     367    }
    368368}
    369369
  • trunk/gli/src/org/greenstone/gatherer/gui/browser/HTMLViewPane.java

    r4293 r4366  
    5555/** HTMLViewPane provides the interface that all implementations must adhere to. The methods shown are used by Gatherer to interact with the rendered HTML pane, and in turn recieve messages back. */
    5656public interface HTMLViewPane {
    57     /** Add a GBrowserListener to this browser.
    58       * @param listener an object which implements the GBrowserListener interface.
     57    /** Add a GBrowserListener to this browser.
     58     * @param listener an object which implements the GBrowserListener interface.
    5959      */
    60     public void addGBrowserListener(GBrowserListener listener);
     60    public void addGBrowserListener(GBrowserListener listener);
    6161
    62     public void afterDisplay();
     62    public void afterDisplay();
    6363
    6464  /**
     
    7070    * @return value - whether or not the operation was successful
    7171    */
    72   public boolean back();
    73   /**
     72    public boolean back();
     73    /**
    7474    * CanBack is used to determine if there are further pages to 'back' to, and
    7575    * based on the result whether the functionality should be available
    7676    */
    77   public boolean canBack();
    78   /**
     77    public boolean canBack();
     78    /**
    7979    * CanForward performs approximately the same duty as canBack except, of
    8080    * course, in the opposite direction.
    8181    */
    82   public boolean canForward();
    83     /**
     82    public boolean canForward();
     83    /**
    8484      * CanStop determines whether the stop functionality is available. In general
    8585      * you have to be doing something before you can stop it!
    8686      */
    87     public boolean canStop();
    88   /**
     87    public boolean canStop();
     88    /**
    8989   * Capture is used to grab a buffered image of the current graphics context of
    9090   * the HTML pane. Note that this may not actually be feasible in embedded
     
    9494   * panes graphics buffer.
    9595   */
    96   public BufferedImage capture();
    97   /**
     96    public BufferedImage capture();
     97    /**
    9898   * When called this method returns the URL of the resource currently being
    9999   * displayed (or rendered). If no resource has been requested the return URL
     
    101101   * @return url - the GURL of the currently displayed resource.
    102102   */
    103   public GURL current();
    104   /**
     103    public GURL current();
     104    /**
    105105   * This method is used to tell the HTML pane whether it should attempt to
    106106   * follow hyperlinks when a user clicks them. Whether this is set or not the
     
    109109   * @param on - whether followHyperlinks is; on (= true) or off.
    110110   */
    111   public void followHyperlinks(boolean value);
    112   /**
     111    public void followHyperlinks(boolean value);
     112    /**
    113113    * Forward is a call for the HTMLViewPane implementation to move forward one
    114114    * page in its browser history. It should react appropriately to calls to this
     
    116116    * @return value - whether of not the operation was successfull
    117117    */
    118   public boolean forward();
    119     /** In order to add the class that implements this interface to a component hierarchy you require some way to get at the component. This is that way.
     118    public boolean forward();
     119    /** In order to add the class that implements this interface to a component hierarchy you require some way to get at the component. This is that way.
    120120      * @return a component reference of this class (as compared to the interface one you started with).
    121121      */ 
    122     public Component getContent();
    123   /**
     122    public Component getContent();
     123    /**
    124124   * If called, getProgressBar should return a reference to a JProgress bar. The
    125125   * HTML pane is then resposible for updating the progress bar for its lifetime
     
    129129   * towards displaying a url or null.
    130130   */
    131   public JProgressBar getProgress();
    132   /** Before attempting to issue futher instructions to the HTML pane, Gatherer must first ensure that its ready. A pane should always be responsive but there are foreseeable times when an interrupt to go to a new page may cause the renderer to become unstable, or perhaps a user is filling out a form and thus shouldn't be pre-empted.
     131    public JProgressBar getProgress();
     132    /** Before attempting to issue futher instructions to the HTML pane, Gatherer must first ensure that its ready. A pane should always be responsive but there are foreseeable times when an interrupt to go to a new page may cause the renderer to become unstable, or perhaps a user is filling out a form and thus shouldn't be pre-empted.
    133133   * @return <i>true</i> if the pane is ready for further instructions, <i>false</i> if not.
    134134   */
    135   public boolean isReady();
    136   /**
     135    public boolean isReady();
     136    /**
    137137   * SetEnabled is used to temporarily prevent further user interaction with the
    138138   * pane. This may be caused by certain user requests in other parts of Gatherer
     
    143143   * @param on - what state the component should be in; on (= true) or off.
    144144   */
    145   public void setEnabled(boolean value);
    146     /** Remove a GBrowserListener from this browser.
     145    public void setEnabled(boolean value);
     146    /** Remove a GBrowserListener from this browser.
    147147      * @param listener an object which implements the GBrowserListener interface.
    148148      */
    149     public void removeGBrowserListener(GBrowserListener listener);
    150     /**
     149    public void removeGBrowserListener(GBrowserListener listener);
     150    /**
    151151   * Show, in both of its forms, allows Gatherer to display a certain URL or file
    152152   * in the HTML pane.
     
    155155   * @return whether a page has been queued to be rendered.
    156156   */
    157   public boolean show(String filename);
    158   /**
     157    public boolean show(String filename);
     158    /**
    159159   * Show, in both of its forms, allows Gatherer to display a certain URL or file
    160160   * in the HTML pane.
     
    163163   * @return whether a page has been queued to be rendered.
    164164   */
    165   public boolean show(GURL url);
    166   /**
     165    public boolean show(GURL url);
     166    /**
    167167   * Stop() kills the current rendering.
    168168   * @return whether the rendering was successfully killed.
    169169   */
    170   public boolean stop();
     170    public boolean stop();
    171171}
    172172
  • trunk/gli/src/org/greenstone/gatherer/gui/combobox/GComboBox.java

    r4293 r4366  
    5555 */
    5656public class GComboBox
    57     extends JComboBox {
     57    extends JComboBox {
    5858
    59     private JTextField text;
     59    private JTextField text;
    6060
    61     public GComboBox() {
    62           super();
    63           text = (JTextField) this.getEditor().getEditorComponent();
    64     }
     61    public GComboBox() {
     62    super();
     63    text = (JTextField) this.getEditor().getEditorComponent();
     64    }
    6565
    66     public GComboBox(ComboBoxModel model) {
    67           super(model);
    68           text = (JTextField) this.getEditor().getEditorComponent();
    69     }   
     66    public GComboBox(ComboBoxModel model) {
     67    super(model);
     68    text = (JTextField) this.getEditor().getEditorComponent();
     69    }   
    7070
    71     public void addDocumentListener(DocumentListener listener) {
    72           if(text != null) text.getDocument().addDocumentListener(listener);
    73     }
     71    public void addDocumentListener(DocumentListener listener) {
     72    if(text != null) text.getDocument().addDocumentListener(listener);
     73    }
    7474
    75     public void addKeyListener(KeyListener listener) {
    76           if(text != null) text.addKeyListener(listener);
    77     }
     75    public void addKeyListener(KeyListener listener) {
     76    if(text != null) text.addKeyListener(listener);
     77    }
    7878
    79     public String getText() {
    80           if(text != null) {
    81                 return text.getText();
    82           }
    83           GComboBoxModel model = (GComboBoxModel)this.getModel();
    84           return (String)model.getSelectedItem();
    85     }
     79    public String getText() {
     80    if(text != null) {
     81        return text.getText();
     82    }
     83    GComboBoxModel model = (GComboBoxModel)this.getModel();
     84    return (String)model.getSelectedItem();
     85    }
    8686
    87     public void setText(String value) {
    88           if(text != null) text.setText(value);
    89     }
     87    public void setText(String value) {
     88    if(text != null) text.setText(value);
     89    }
    9090
    91     public void removeDocumentListener(DocumentListener listener) {
    92           if(text != null) text.getDocument().removeDocumentListener(listener);
    93     }
     91    public void removeDocumentListener(DocumentListener listener) {
     92    if(text != null) text.getDocument().removeDocumentListener(listener);
     93    }
    9494
    95     public void removeKeyListener(KeyListener listener) {
    96           if(text != null) text.removeKeyListener(listener);
    97     }
     95    public void removeKeyListener(KeyListener listener) {
     96    if(text != null) text.removeKeyListener(listener);
     97    }
    9898}
  • trunk/gli/src/org/greenstone/gatherer/gui/combobox/GComboBoxModel.java

    r4293 r4366  
    5353
    5454public class GComboBoxModel
    55     extends AbstractListModel
    56     implements MutableComboBoxModel {
     55    extends AbstractListModel
     56    implements MutableComboBoxModel {
    5757
    58     // Data.
    59     private boolean   isMetadataElement = false;
     58    // Data.
     59    private boolean   isMetadataElement = false;
    6060
    61     private Hashtable name_to_element   = new Hashtable();
     61    private Hashtable name_to_element   = new Hashtable();
    6262
    63     private Object    selected_item     = null;
     63    private Object    selected_item     = null;
    6464
    65     private Vector    contents          = new Vector();
     65    private Vector    contents          = new Vector();
    6666
    67     public GComboBoxModel() {
    68     }
     67    public GComboBoxModel() {
     68    }
    6969
    70     public GComboBoxModel(Vector contents) {
    71           this.contents = contents;
    72           Collections.sort(contents);
    73     }
     70    public GComboBoxModel(Vector contents) {
     71    this.contents = contents;
     72    Collections.sort(contents);
     73    }
    7474
    75     public GComboBoxModel(Vector elements, boolean isMetadataElement) {
    76           this.isMetadataElement = isMetadataElement;
    77           for(int i = 0; i < elements.size(); i++) {
    78                 ElementWrapper element = (ElementWrapper)elements.get(i);
    79                 contents.add(element.toString());
    80                 name_to_element.put(element.toString(), element);
    81           }
    82           Collections.sort(contents);
    83     }
     75    public GComboBoxModel(Vector elements, boolean isMetadataElement) {
     76    this.isMetadataElement = isMetadataElement;
     77    for(int i = 0; i < elements.size(); i++) {
     78        ElementWrapper element = (ElementWrapper)elements.get(i);
     79        contents.add(element.toString());
     80        name_to_element.put(element.toString(), element);
     81    }
     82    Collections.sort(contents);
     83    }
    8484
    85     private boolean contains(Vector vector, Object key) {
    86           for(int i = 0; i < vector.size(); i++) {
    87                 if(vector.get(i).toString().equals(key.toString())) {
    88                      return true;
    89                 }
    90           }
    91           return false;
    92     }
     85    private boolean contains(Vector vector, Object key) {
     86    for(int i = 0; i < vector.size(); i++) {
     87        if(vector.get(i).toString().equals(key.toString())) {
     88        return true;
     89        }
     90    }
     91    return false;
     92    }
    9393
    94     // Methods.
    95     public void addElement(Object obj) {
    96           if(!contents.contains(obj)) {
    97                 contents.add(obj);
    98                 Collections.sort(contents);
    99                 refresh();
    100           }
    101     }
     94    // Methods.
     95    public void addElement(Object obj) {
     96    if(!contents.contains(obj)) {
     97        contents.add(obj);
     98        Collections.sort(contents);
     99        refresh();
     100    }
     101    }
    102102
    103     public Object getElementAt(int index) {
    104           return contents.get(index);
    105     }
     103    public Object getElementAt(int index) {
     104    return contents.get(index);
     105    }
    106106
    107     public Object getSelectedItem() {
    108           return selected_item;
    109     }
     107    public Object getSelectedItem() {
     108    return selected_item;
     109    }
    110110
    111     public ElementWrapper getSelectedMetadata() {
    112           if(isMetadataElement) {
    113                 return (ElementWrapper)name_to_element.get(selected_item);
    114           }
    115           return null;
    116     }
     111    public ElementWrapper getSelectedMetadata() {
     112    if(isMetadataElement) {
     113        return (ElementWrapper)name_to_element.get(selected_item);
     114    }
     115    return null;
     116    }
    117117
    118     public int getSize() {
    119           return contents.size();
    120     }
     118    public int getSize() {
     119    return contents.size();
     120    }
    121121
    122     public void insertElementAt(Object obj, int index) {
    123           contents.add(index, obj);
    124           fireIntervalAdded(this, index, index);
    125     }
     122    public void insertElementAt(Object obj, int index) {
     123    contents.add(index, obj);
     124    fireIntervalAdded(this, index, index);
     125    }
    126126
    127     public void refresh() {
    128           fireContentsChanged(this, 0, getSize());
    129     }
     127    public void refresh() {
     128    fireContentsChanged(this, 0, getSize());
     129    }
    130130
    131     public void removeElement(Object obj) {
    132           int index = contents.indexOf(obj);
    133           contents.remove(index);
    134           fireIntervalRemoved(this, index, index);
    135     }
     131    public void removeElement(Object obj) {
     132    int index = contents.indexOf(obj);
     133    contents.remove(index);
     134    fireIntervalRemoved(this, index, index);
     135    }
    136136
    137     public void removeElementAt(int index) {
    138           contents.remove(index);
    139           fireIntervalRemoved(this, index, index);
    140     }
     137    public void removeElementAt(int index) {
     138    contents.remove(index);
     139    fireIntervalRemoved(this, index, index);
     140    }
    141141
    142     public void setSelectedItem(Object obj) {
    143           selected_item = obj;
    144           int index = contents.indexOf(obj);
    145           fireContentsChanged(this, index, index);
    146     }
     142    public void setSelectedItem(Object obj) {
     143    selected_item = obj;
     144    int index = contents.indexOf(obj);
     145    fireContentsChanged(this, index, index);
     146    }
    147147}
  • trunk/gli/src/org/greenstone/gatherer/gui/messages/MessageListModel.java

    r4293 r4366  
    4747import org.greenstone.gatherer.util.Utility;
    4848class MessageListModel
    49     extends AbstractListModel {
     49    extends AbstractListModel {
    5050
    51     Hashtable mappings;
     51    Hashtable mappings;
    5252
    53     int current_index;
     53    int current_index;
    5454
    55     int current_message;
     55    int current_message;
    5656
    57     int sizes[][] = new int[6][4];
     57    int sizes[][] = new int[6][4];
    5858
    59     Vector data;
     59    Vector data;
    6060
    61     // Contructor
     61    // Contructor
    6262    public MessageListModel() {
    63           current_index = 0;
    64           current_message = 0;
    65           data = new Vector();
    66           mappings = new Hashtable();
    67           for(int i = 0; i < 6; i++) {
    68                 for(int j = 0; j < 4; j++) {
    69                      sizes[i][j] = 0;
    70                 }
    71           }
     63    current_index = 0;
     64    current_message = 0;
     65    data = new Vector();
     66    mappings = new Hashtable();
     67    for(int i = 0; i < 6; i++) {
     68        for(int j = 0; j < 4; j++) {
     69        sizes[i][j] = 0;
     70        }
     71    }
    7272    }
    7373   
    74     // Add a new message in the correct place
     74    // Add a new message in the correct place
    7575    public synchronized void add(Message message) {
    76           // Add the element to the model
    77           data.add(message);
    78           // Increment the count for that type of message
    79           sizes[message.source][message.level]++;
    80           // An announce to the world that I have changed!
     76    // Add the element to the model
     77    data.add(message);
     78    // Increment the count for that type of message
     79    sizes[message.source][message.level]++;
     80    // An announce to the world that I have changed!
    8181        fireContentsChanged(this, 0, getSize() - 1);
    8282    }
     
    8484    // Return the size of the list
    8585    public int getSize() {
    86           int size = 0;
    87           // Each each source...
    88           for(int i = 0; i < 6; i++) {
     86    int size = 0;
     87    // Each each source...
     88    for(int i = 0; i < 6; i++) {
    8989                // and each level...
    90                 for(int j = 0; j < 4; j++) {
    91                      // If both this source and level are active, add its size
    92                      /** @todo reenabled
    93                       * if(gatherer.config.source[i] && gatherer.config.level[j]) {
    94                       * size = size + sizes[i][j];
    95                       * }
    96                       */
    97                 }
    98           }
    99           return size;
     90        for(int j = 0; j < 4; j++) {
     91        // If both this source and level are active, add its size
     92        /** @todo reenabled
     93        * if(gatherer.config.source[i] && gatherer.config.level[j]) {
     94        *  size = size + sizes[i][j];
     95        * }
     96        */
     97        }
     98    }
     99    return size;
    100100    }
    101101
    102     public int getTotalSize() {
    103       int size = 0;
    104           // Each each source...
    105           for(int i = 0; i < 6; i++) {
     102    public int getTotalSize() {
     103    int size = 0;
     104    // Each each source...
     105    for(int i = 0; i < 6; i++) {
    106106                // and each level...
    107                 for(int j = 0; j < 4; j++) {
    108                      size = size + sizes[i][j];
    109                 }
    110           }
    111           return size;
    112     }
     107        for(int j = 0; j < 4; j++) {
     108        size = size + sizes[i][j];
     109        }
     110    }
     111    return size;
     112    }
    113113
    114     public String getSizeStr() {
    115           return "" + getSize() + "";
    116     }
     114    public String getSizeStr() {
     115    return "" + getSize() + "";
     116    }
    117117
    118     public String getTotalSizeStr() {
    119           return "" + getTotalSize() + "";
    120     }
     118    public String getTotalSizeStr() {
     119    return "" + getTotalSize() + "";
     120    }
    121121
    122122    // Return a message from the list
    123123    public Object getElementAt( int index ) {
    124           Integer index_int = new Integer(index);
    125           // Maybe we've already found this message.
    126           if(mappings.containsKey(index_int)) {
    127                 current_message = ((Integer)mappings.get(index_int)).intValue();
    128           }
    129           // Otherwise we're going to have to search for it.
    130           else {
    131                 while(index != current_index) {
    132                      // Asking for an index lower than the one we're at.
    133                      if(index < current_index) {
    134                           Message temp;
    135                           /*
    136                           do {
    137                                 current_message--;
    138                                 temp = (Message)data.get(current_message);
    139                           } while(!(gatherer.config.source[temp.source] &&
    140                                     gatherer.config.level[temp.level]));
    141                           // We are now at a new visible message.
    142                           */
    143                           current_index--;
    144                      }
    145                      else {
    146                           Message temp;
    147                           /*
    148                           do {
    149                                 current_message++;
    150                                 temp = (Message)data.get(current_message);
    151                           } while(!(gatherer.config.source[temp.source] &&
    152                                     gatherer.config.level[temp.level]));
    153                           // We are now at a new visible message.
    154                           current_index++;
    155                           */
    156                      }
    157                 }
     124    Integer index_int = new Integer(index);
     125    // Maybe we've already found this message.
     126    if(mappings.containsKey(index_int)) {
     127        current_message = ((Integer)mappings.get(index_int)).intValue();
     128    }
     129    // Otherwise we're going to have to search for it.
     130    else {
     131        while(index != current_index) {
     132        // Asking for an index lower than the one we're at.
     133        if(index < current_index) {
     134            Message temp;
     135            /*
     136              do {
     137              current_message--;
     138              temp = (Message)data.get(current_message);
     139              } while(!(gatherer.config.source[temp.source] &&
     140              gatherer.config.level[temp.level]));
     141              // We are now at a new visible message.
     142            */
     143            current_index--;
     144        }
     145        else {
     146            Message temp;
     147            /*
     148              do {
     149              current_message++;
     150              temp = (Message)data.get(current_message);
     151              } while(!(gatherer.config.source[temp.source] &&
     152              gatherer.config.level[temp.level]));
     153              // We are now at a new visible message.
     154              current_index++;
     155            */
     156        }
     157        }
    158158                // Now that we've found the blighter, add a mapping so its quicker
    159159                // next time.
    160                 mappings.put(new Integer(index),new Integer(current_message));
    161           }
    162           return ((Message)data.get(current_message)).toString();
     160        mappings.put(new Integer(index),new Integer(current_message));
     161    }
     162    return ((Message)data.get(current_message)).toString();
    163163    }
    164164
    165     public void refresh() {
    166           if(getSize() > 0) {
    167                 current_index = 0;
     165    public void refresh() {
     166    if(getSize() > 0) {
     167        current_index = 0;
    168168                // Find the first message that meets the requirements. Its index 0 y'know.
    169                 current_message = -1;
    170                 Message temp;
     169        current_message = -1;
     170        Message temp;
    171171                /*
    172                 do {
    173                     current_message++;
    174                     temp = (Message)data.get(current_message);
    175                 } while(!(gatherer.config.source[temp.source] &&
    176                             gatherer.config.level[temp.level]));   
     172                  do {
     173                  current_message++;
     174                  temp = (Message)data.get(current_message);
     175                  } while(!(gatherer.config.source[temp.source] &&
     176                  gatherer.config.level[temp.level])); 
    177177                */ 
    178178                // Reset mappings.
    179                 mappings.clear();
    180                 mappings.put(new Integer(current_index), new Integer(current_message));
     179        mappings.clear();
     180        mappings.put(new Integer(current_index), new Integer(current_message));
    181181                // Let everyone who cares know we've changed.
    182                 fireContentsChanged(this, 0, getSize() - 1);
    183           }
    184           // Else don't bother doning anything on an empty list!
    185     }
     182        fireContentsChanged(this, 0, getSize() - 1);
     183    }
     184    // Else don't bother doning anything on an empty list!
     185    }
    186186}
    187187
  • trunk/gli/src/org/greenstone/gatherer/gui/messages/MessageListRenderer.java

    r4293 r4366  
    4545 */
    4646class MessageListRenderer
    47     extends JLabel
    48     implements ListCellRenderer {
     47    extends JLabel
     48    implements ListCellRenderer {
    4949
    5050    // Constructor
     
    5454    // We just reconfigure the JLabel each time we're called.
    5555    public Component getListCellRendererComponent(
    56          JList list,
    57           Object value,            // value to display
    58           int index,               // cell index
    59           boolean isSelected,      // is the cell selected
    60           boolean cellHasFocus) {  // the list and the cell have the focus
    61           // Get the message
    62           String s = value.toString();
    63           setText(s);
    64           // Now parse out the level
    65           StringTokenizer tokenizer = new StringTokenizer(s);
    66           // Throw away source.
    67           tokenizer.nextToken();
    68           // Now add color details based on level
    69           String level = tokenizer.nextToken();
    70           if(level.equals(get("Main"))) {
    71                 setForeground(Color.black);
    72           } else if (level.equals(get("Event"))) {
    73                 setForeground(Color.blue);
    74           } else if (level.equals(get("Information"))) {
    75                 setForeground(Color.gray);
    76           } else {
    77                 setForeground(Color.red);
    78           }
    79           setEnabled(list.isEnabled());
    80           setFont(list.getFont());
    81           return this;
     56                          JList list,
     57                          Object value,            // value to display
     58                          int index,               // cell index
     59                          boolean isSelected,      // is the cell selected
     60                          boolean cellHasFocus) {  // the list and the cell have the focus
     61    // Get the message
     62    String s = value.toString();
     63    setText(s);
     64    // Now parse out the level
     65    StringTokenizer tokenizer = new StringTokenizer(s);
     66    // Throw away source.
     67    tokenizer.nextToken();
     68    // Now add color details based on level
     69    String level = tokenizer.nextToken();
     70    if(level.equals(get("Main"))) {
     71        setForeground(Color.black);
     72    } else if (level.equals(get("Event"))) {
     73        setForeground(Color.blue);
     74    } else if (level.equals(get("Information"))) {
     75        setForeground(Color.gray);
     76    } else {
     77        setForeground(Color.red);
     78    }
     79    setEnabled(list.isEnabled());
     80    setFont(list.getFont());
     81    return this;
    8282    }
    8383
    84     private String get(String key) {
    85           if(key.indexOf('.') == -1) {
    86                 key = "Level." + key;
    87           }
    88           return Gatherer.dictionary.get(key);
    89     }
     84    private String get(String key) {
     85    if(key.indexOf('.') == -1) {
     86        key = "Level." + key;
     87    }
     88    return Gatherer.dictionary.get(key);
     89    }
    9090}
  • trunk/gli/src/org/greenstone/gatherer/gui/messages/MessagePane.java

    r4293 r4366  
    4848 */
    4949public class MessagePane
    50     extends JPanel
     50    extends JPanel
    5151    implements ActionListener {
    5252
    53     GridBagConstraints grid_constraints = null;
    54 
    55     GridBagLayout grid_layout = null;
    56 
    57     JButton save_messages = null;
    58 
    59     JLabel level_label = null;
    60     JLabel message_count = null;
    61     JLabel source_label = null;
    62 
    63     JPanel central_pane = null;
    64     JPanel corner_pane = null;
    65     JPanel count_pane = null;
    66     JPanel horizontal_pane = null;
    67     JPanel level_pane = null;
    68     JPanel source_pane = null;
    69     JPanel vertical_pane = null;
    70 
    71     JScrollPane scroll_pane = null;
    72 
    73     JToggleButton level_event = null;
    74     JToggleButton level_error = null;
    75     JToggleButton level_information = null;
    76     JToggleButton level_main = null;
    77     JToggleButton source_browser = null;
    78     JToggleButton source_build = null;
    79     JToggleButton source_general = null;
    80     JToggleButton source_mirroring = null;
    81     JToggleButton source_metaedit = null;
    82     JToggleButton source_session = null;
    83 
    84     JList message_list = null;
    85 
    86     MessageListModel model = null;
    87 
    88     MessageListRenderer renderer = null;
    89 
    90     String args[];
    91 
    92     public MessagePane() {
    93     }
    94 
    95     public void display() {
    96           // Setup main layout managers
    97           grid_layout = new GridBagLayout();
    98           grid_constraints = new GridBagConstraints();
    99           this.setLayout(grid_layout);
    100 
    101           // Vertical Buttons
    102           source_pane = new JPanel(new BorderLayout());
    103           source_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,3));
    104 
    105           vertical_pane = new JPanel(new GridLayout(6,1));
    106 
    107           Gatherer.println("\tCreating source_label");
    108           source_label = new JLabel(get("Source"));
    109           source_label.setHorizontalAlignment(JLabel.CENTER);
    110 
    111           Gatherer.println("\tCreating source_general");
    112           source_general = new JToggleButton(get("General"), Gatherer.config.get("messages.source_general", false));
    113           source_general.setIcon(Utility.OFF_ICON);
    114           source_general.setSelectedIcon(Utility.ON_ICON);
    115           source_general.setHorizontalTextPosition(JToggleButton.CENTER);
    116           source_general.setVerticalTextPosition(JToggleButton.BOTTOM);
    117           source_general.addActionListener(this);
    118 
    119           Gatherer.println("\tCreating source_browser");
    120           source_browser = new JToggleButton(get("Browser"), Gatherer.config.get("messages.source_browser", false));
    121           source_browser.setIcon(Utility.OFF_ICON);
    122           source_browser.setSelectedIcon(Utility.ON_ICON);
    123           source_browser.setHorizontalTextPosition(JToggleButton.CENTER);
    124           source_browser.setVerticalTextPosition(JToggleButton.BOTTOM);
    125           source_browser.addActionListener(this);
    126 
    127           Gatherer.println("\tCreating source_mirroring");
    128           source_mirroring = new JToggleButton(get("Mirroring"), Gatherer.config.get("messages.source_mirroring", false));
    129           source_mirroring.setIcon(Utility.OFF_ICON);
    130           source_mirroring.setSelectedIcon(Utility.ON_ICON);
    131           source_mirroring.setHorizontalTextPosition(JToggleButton.CENTER);
    132           source_mirroring.setVerticalTextPosition(JToggleButton.BOTTOM);
    133           source_mirroring.addActionListener(this);
    134 
    135           Gatherer.println("\tCreating source_session");
    136           source_session = new JToggleButton(get("Session"), Gatherer.config.get("messages.source_session", false));
    137           source_session.setIcon(Utility.OFF_ICON);
    138           source_session.setSelectedIcon(Utility.ON_ICON);
    139          source_session.setHorizontalTextPosition(JToggleButton.CENTER);
    140           source_session.setVerticalTextPosition(JToggleButton.BOTTOM);
    141           source_session.addActionListener(this);
    142 
    143           Gatherer.println("\tCreating source_metaedit");
    144           source_metaedit = new JToggleButton(get("Metaedit"), Gatherer.config.get("messages.source_metaedit", false));
    145           source_metaedit.setIcon(Utility.OFF_ICON);
    146           source_metaedit.setSelectedIcon(Utility.ON_ICON);
    147           source_metaedit.setHorizontalTextPosition(JToggleButton.CENTER);
    148           source_metaedit.setVerticalTextPosition(JToggleButton.BOTTOM);
    149           source_metaedit.addActionListener(this);
    150 
    151           Gatherer.println("\tCreating source_build");
    152           source_build = new JToggleButton(get("Build"), Gatherer.config.get("messages.source_build", false));
    153           source_build.setIcon(Utility.OFF_ICON);
    154           source_build.setSelectedIcon(Utility.ON_ICON);
    155           source_build.setHorizontalTextPosition(JToggleButton.CENTER);
    156           source_build.setVerticalTextPosition(JToggleButton.BOTTOM);
    157           source_build.addActionListener(this);
    158 
    159           source_pane.add(source_label, BorderLayout.NORTH);
    160           vertical_pane.add(source_general);
    161           vertical_pane.add(source_browser);
    162           vertical_pane.add(source_mirroring);
    163           vertical_pane.add(source_session);
    164           vertical_pane.add(source_metaedit);
    165           vertical_pane.add(source_build);
    166           source_pane.add(vertical_pane, BorderLayout.CENTER);
    167 
    168           // Central pane
    169           central_pane = new JPanel(new BorderLayout());
    170 
    171           Gatherer.println("\tCreating message_list");
    172           model = new MessageListModel();
    173           renderer = new MessageListRenderer();
    174           message_list = new JList();
    175           message_list.setModel(model);
    176           message_list.setCellRenderer(renderer);
    177 
    178           scroll_pane = new JScrollPane(message_list);
    179           central_pane.add(scroll_pane, BorderLayout.CENTER);
    180 
    181           Gatherer.println("\tCreating message_count");
    182           count_pane = new JPanel(new BorderLayout());
    183           args = new String[2];
    184           args[0] = model.getSizeStr();
    185           args[1] = model.getTotalSizeStr();
    186           message_count = new JLabel(get("Message_Count",args));
    187           message_count.setHorizontalAlignment(JLabel.RIGHT);
    188 
    189           central_pane.add(scroll_pane, BorderLayout.CENTER);
    190           central_pane.add(message_count, BorderLayout.SOUTH);
    191 
    192           // Corner area
    193           corner_pane = new JPanel(new BorderLayout());
    194           corner_pane.setBorder(BorderFactory.createEmptyBorder(3,5,5,5));
    195 
    196           Gatherer.println("\tCreating save_message");
    197           save_messages = new JButton(get("Save_Messages"),
    198                                                 new ImageIcon(Utility.RES_DIR+"save.gif"));
    199           save_messages.addActionListener(this);
    200 
    201           corner_pane.add(save_messages, BorderLayout.CENTER);
    202 
    203           // Horizontal buttons.
    204           level_pane = new JPanel(new BorderLayout());
    205 
    206           horizontal_pane = new JPanel(new GridLayout(1,4));
    207 
    208           Gatherer.println("\tCreating level_label");
    209           level_label = new JLabel(get("Level"));
    210           level_label.setHorizontalAlignment(JLabel.CENTER);
    211 
    212           Gatherer.println("\tCreating level_main");
    213           level_main = new JToggleButton(get("Main"), Gatherer.config.get("messages.level_main", false));
    214           level_main.setIcon(Utility.OFF_ICON);
    215           level_main.setSelectedIcon(Utility.ON_ICON);
    216           level_main.addActionListener(this);
    217 
    218           Gatherer.println("\tCreating level_event");
    219           level_event = new JToggleButton(get("Event"), Gatherer.config.get("messages.level_event", false));
    220           level_event.setIcon(Utility.OFF_ICON);
    221           level_event.setSelectedIcon(Utility.ON_ICON);
    222           level_event.addActionListener(this);
    223 
    224           Gatherer.println("\tCreating level_information");
    225           level_information = new JToggleButton(get("Information"), Gatherer.config.get("messages.level_information", false));
    226           level_information.setIcon(Utility.OFF_ICON);
    227           level_information.setSelectedIcon(Utility.ON_ICON);
    228           level_information.addActionListener(this);
    229 
    230           Gatherer.println("\tCreating level_error");
    231           level_error = new JToggleButton(get("Error"), Gatherer.config.get("messages.level_error", false));
    232           level_error.setIcon(Utility.OFF_ICON);
    233           level_error.setSelectedIcon(Utility.ON_ICON);
    234           level_error.addActionListener(this);
    235 
    236           level_pane.add(level_label, BorderLayout.NORTH);
    237           horizontal_pane.add(level_main);
    238           horizontal_pane.add(level_event);
    239           horizontal_pane.add(level_information);
    240           horizontal_pane.add(level_error);
    241           level_pane.add(horizontal_pane, BorderLayout.CENTER);
    242 
    243           // Terrifying gridbag layout
    244           grid_constraints.fill = GridBagConstraints.BOTH;
    245           grid_layout.setConstraints(source_pane, grid_constraints);
    246           this.add(source_pane);
    247           grid_constraints.weightx = 1.0;
    248           grid_constraints.weighty = 1.0;
    249           grid_constraints.gridwidth = GridBagConstraints.REMAINDER;
    250           grid_layout.setConstraints(central_pane, grid_constraints);
    251           this.add(central_pane);
    252           grid_constraints.weightx = 0.0;
    253           grid_constraints.weighty = 0.0;
    254           grid_constraints.gridwidth = 1;
    255           grid_layout.setConstraints(corner_pane, grid_constraints);
    256           this.add(corner_pane);
    257           grid_constraints.gridwidth = GridBagConstraints.REMAINDER;
    258           grid_layout.setConstraints(level_pane, grid_constraints);
    259           this.add(level_pane);
    260     }
    261 
    262     public void actionPerformed(ActionEvent event) {
    263           Object source = event.getSource();
    264 
    265           // Eventually this will dump the messages to a text file, but for now
    266           // I'm using it in testing.
    267           if(source == save_messages) {
    268                 for(int i = 0; i < 20; i++) {
    269                      model.add(Message.random());
    270                      message_list.ensureIndexIsVisible(model.getSize() - 1);
    271                 }
    272           }
    273           // We've been asked to toggle whether we show general messages.
    274           else if(source == source_general) {
    275                 // Toggle config setting
    276                 Gatherer.config.set("messages.source_general", false, !Gatherer.config.get("messages.source_general", false));
    277                 // Inform model something has changed.
    278                 model.refresh();
    279                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    280           }
    281           // We've been asked to toggle whether we show browser messages.
    282           else if(source == source_browser) {
    283                 // Toggle config setting
    284                 Gatherer.config.set("messages.source_browser", false, !Gatherer.config.get("messages.source_browser", false));
    285                 // Inform model something has changed.
    286                 model.refresh();
    287                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    288           }
    289           // We've been asked to toggle whether we show general messages.
    290           else if(source == source_mirroring) {
    291                 // Toggle config setting
    292                 Gatherer.config.set("messages.source_mirroring", false, !Gatherer.config.get("messages.source_mirroring", false));
    293                 // Inform model something has changed.
    294                 model.refresh();
    295                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    296           }
    297           // We've been asked to toggle whether we show session messages.
    298           else if(source == source_session) {
    299                 // Toggle config setting
    300                 Gatherer.config.set("messages.source_session", false, !Gatherer.config.get("messages.source_session", false));
    301                 // Inform model something has changed.
    302                 model.refresh();
    303                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    304           }
    305           // We've been asked to toggle whether we show metaedit messages.
    306           else if(source == source_metaedit) {
    307                 // Toggle config setting
    308                 Gatherer.config.set("messages.source_metaedit", false, !Gatherer.config.get("messages.source_metaedit", false));
    309                 // Inform model something has changed.
    310                 model.refresh();
    311                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    312           }
    313           // We've been asked to toggle whether we show build messages.
    314           else if(source == source_build) {
    315                 // Toggle config setting
    316                 Gatherer.config.set("messages.source_build", false, !Gatherer.config.get("messages.source_build", false));
    317                 // Inform model something has changed.
    318                 model.refresh();
    319                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    320           }
    321           // We've been asked to toggle whether we show main level messages.
    322           else if(source == level_main) {
    323                 // Toggle config setting
    324                 Gatherer.config.set("messages.level_main", false, !Gatherer.config.get("messages.level_main", false));
    325                 // Inform model something has changed.
    326                 model.refresh();
    327                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    328           }
    329           // We've been asked to toggle whether we show event level messages.
    330           else if(source == level_event) {
    331                 // Toggle config setting
    332                 Gatherer.config.set("messages.level_event", false, !Gatherer.config.get("messages.level_event", false));
    333                 // Inform model something has changed.
    334                 model.refresh();
    335                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    336           }
    337           // We've been asked to toggle whether we show information level messages.
    338           else if(source == level_information) {
    339                 // Toggle config setting
    340                 Gatherer.config.set("messages.level_information", false, !Gatherer.config.get("messages.level_information", false));
    341                 // Inform model something has changed.
    342                 model.refresh();
    343                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    344           }
    345           // We've been asked to toggle whether we show error level messages.
    346           else if(source == level_error) {
    347                 // Toggle config setting
    348                 Gatherer.config.set("messages.level_error", false, !Gatherer.config.get("messages.level_error", false));
    349                 // Inform model something has changed.
    350                 model.refresh();
    351                 message_list.ensureIndexIsVisible(model.getSize() - 1);
    352           }
    353           // Pretty much no matter what happens we need to get the new size
    354           args = new String[2];
    355           args[0] = model.getSizeStr();
    356           args[1] = model.getTotalSizeStr();
    357           message_count.setText(get("Message_Count",args));
    358     }
    359 
    360     /** The callback for the message listener. Here all of the messages are
    361       * displayed onto the list.
    362       * @param message The Message to be displayed.
    363       */
    364     public void show(Message message) {
    365           model.add(message);
    366           message_list.ensureIndexIsVisible(model.getSize() - 1);
    367     }
    368 
    369 
    370     private String get(String key) {
    371           return get(key, null);
    372     }
    373 
    374     private String get(String key, String args[]) {
    375           if(key.indexOf('.') == -1) {
    376                 key = "Messages." + key;
    377           }
    378           return Gatherer.dictionary.get(key, args);
    379     }
     53    GridBagConstraints grid_constraints = null;
     54
     55    GridBagLayout grid_layout = null;
     56
     57    JButton save_messages = null;
     58
     59    JLabel level_label = null;
     60    JLabel message_count = null;
     61    JLabel source_label = null;
     62
     63    JPanel central_pane = null;
     64    JPanel corner_pane = null;
     65    JPanel count_pane = null;
     66    JPanel horizontal_pane = null;
     67    JPanel level_pane = null;
     68    JPanel source_pane = null;
     69    JPanel vertical_pane = null;
     70
     71    JScrollPane scroll_pane = null;
     72
     73    JToggleButton level_event = null;
     74    JToggleButton level_error = null;
     75    JToggleButton level_information = null;
     76    JToggleButton level_main = null;
     77    JToggleButton source_browser = null;
     78    JToggleButton source_build = null;
     79    JToggleButton source_general = null;
     80    JToggleButton source_mirroring = null;
     81    JToggleButton source_metaedit = null;
     82    JToggleButton source_session = null;
     83
     84    JList message_list = null;
     85
     86    MessageListModel model = null;
     87
     88    MessageListRenderer renderer = null;
     89
     90    String args[];
     91
     92    public MessagePane() {
     93    }
     94
     95    public void display() {
     96    // Setup main layout managers
     97    grid_layout = new GridBagLayout();
     98    grid_constraints = new GridBagConstraints();
     99    this.setLayout(grid_layout);
     100
     101    // Vertical Buttons
     102    source_pane = new JPanel(new BorderLayout());
     103    source_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,3));
     104
     105    vertical_pane = new JPanel(new GridLayout(6,1));
     106
     107    Gatherer.println("\tCreating source_label");
     108    source_label = new JLabel(get("Source"));
     109    source_label.setHorizontalAlignment(JLabel.CENTER);
     110
     111    Gatherer.println("\tCreating source_general");
     112    source_general = new JToggleButton(get("General"), Gatherer.config.get("messages.source_general", false));
     113    source_general.setIcon(Utility.OFF_ICON);
     114    source_general.setSelectedIcon(Utility.ON_ICON);
     115    source_general.setHorizontalTextPosition(JToggleButton.CENTER);
     116    source_general.setVerticalTextPosition(JToggleButton.BOTTOM);
     117    source_general.addActionListener(this);
     118
     119    Gatherer.println("\tCreating source_browser");
     120    source_browser = new JToggleButton(get("Browser"), Gatherer.config.get("messages.source_browser", false));
     121    source_browser.setIcon(Utility.OFF_ICON);
     122    source_browser.setSelectedIcon(Utility.ON_ICON);
     123    source_browser.setHorizontalTextPosition(JToggleButton.CENTER);
     124    source_browser.setVerticalTextPosition(JToggleButton.BOTTOM);
     125    source_browser.addActionListener(this);
     126
     127    Gatherer.println("\tCreating source_mirroring");
     128    source_mirroring = new JToggleButton(get("Mirroring"), Gatherer.config.get("messages.source_mirroring", false));
     129    source_mirroring.setIcon(Utility.OFF_ICON);
     130    source_mirroring.setSelectedIcon(Utility.ON_ICON);
     131    source_mirroring.setHorizontalTextPosition(JToggleButton.CENTER);
     132    source_mirroring.setVerticalTextPosition(JToggleButton.BOTTOM);
     133    source_mirroring.addActionListener(this);
     134
     135    Gatherer.println("\tCreating source_session");
     136    source_session = new JToggleButton(get("Session"), Gatherer.config.get("messages.source_session", false));
     137    source_session.setIcon(Utility.OFF_ICON);
     138    source_session.setSelectedIcon(Utility.ON_ICON);
     139    source_session.setHorizontalTextPosition(JToggleButton.CENTER);
     140    source_session.setVerticalTextPosition(JToggleButton.BOTTOM);
     141    source_session.addActionListener(this);
     142
     143    Gatherer.println("\tCreating source_metaedit");
     144    source_metaedit = new JToggleButton(get("Metaedit"), Gatherer.config.get("messages.source_metaedit", false));
     145    source_metaedit.setIcon(Utility.OFF_ICON);
     146    source_metaedit.setSelectedIcon(Utility.ON_ICON);
     147    source_metaedit.setHorizontalTextPosition(JToggleButton.CENTER);
     148    source_metaedit.setVerticalTextPosition(JToggleButton.BOTTOM);
     149    source_metaedit.addActionListener(this);
     150
     151    Gatherer.println("\tCreating source_build");
     152    source_build = new JToggleButton(get("Build"), Gatherer.config.get("messages.source_build", false));
     153    source_build.setIcon(Utility.OFF_ICON);
     154    source_build.setSelectedIcon(Utility.ON_ICON);
     155    source_build.setHorizontalTextPosition(JToggleButton.CENTER);
     156    source_build.setVerticalTextPosition(JToggleButton.BOTTOM);
     157    source_build.addActionListener(this);
     158
     159    source_pane.add(source_label, BorderLayout.NORTH);
     160    vertical_pane.add(source_general);
     161    vertical_pane.add(source_browser);
     162    vertical_pane.add(source_mirroring);
     163    vertical_pane.add(source_session);
     164    vertical_pane.add(source_metaedit);
     165    vertical_pane.add(source_build);
     166    source_pane.add(vertical_pane, BorderLayout.CENTER);
     167
     168    // Central pane
     169    central_pane = new JPanel(new BorderLayout());
     170
     171    Gatherer.println("\tCreating message_list");
     172    model = new MessageListModel();
     173    renderer = new MessageListRenderer();
     174    message_list = new JList();
     175    message_list.setModel(model);
     176    message_list.setCellRenderer(renderer);
     177
     178    scroll_pane = new JScrollPane(message_list);
     179    central_pane.add(scroll_pane, BorderLayout.CENTER);
     180
     181    Gatherer.println("\tCreating message_count");
     182    count_pane = new JPanel(new BorderLayout());
     183    args = new String[2];
     184    args[0] = model.getSizeStr();
     185    args[1] = model.getTotalSizeStr();
     186    message_count = new JLabel(get("Message_Count",args));
     187    message_count.setHorizontalAlignment(JLabel.RIGHT);
     188
     189    central_pane.add(scroll_pane, BorderLayout.CENTER);
     190    central_pane.add(message_count, BorderLayout.SOUTH);
     191
     192    // Corner area
     193    corner_pane = new JPanel(new BorderLayout());
     194    corner_pane.setBorder(BorderFactory.createEmptyBorder(3,5,5,5));
     195
     196    Gatherer.println("\tCreating save_message");
     197    save_messages = new JButton(get("Save_Messages"),
     198                    new ImageIcon(Utility.RES_DIR+"save.gif"));
     199    save_messages.addActionListener(this);
     200
     201    corner_pane.add(save_messages, BorderLayout.CENTER);
     202
     203    // Horizontal buttons.
     204    level_pane = new JPanel(new BorderLayout());
     205
     206    horizontal_pane = new JPanel(new GridLayout(1,4));
     207
     208    Gatherer.println("\tCreating level_label");
     209    level_label = new JLabel(get("Level"));
     210    level_label.setHorizontalAlignment(JLabel.CENTER);
     211
     212    Gatherer.println("\tCreating level_main");
     213    level_main = new JToggleButton(get("Main"), Gatherer.config.get("messages.level_main", false));
     214    level_main.setIcon(Utility.OFF_ICON);
     215    level_main.setSelectedIcon(Utility.ON_ICON);
     216    level_main.addActionListener(this);
     217
     218    Gatherer.println("\tCreating level_event");
     219    level_event = new JToggleButton(get("Event"), Gatherer.config.get("messages.level_event", false));
     220    level_event.setIcon(Utility.OFF_ICON);
     221    level_event.setSelectedIcon(Utility.ON_ICON);
     222    level_event.addActionListener(this);
     223
     224    Gatherer.println("\tCreating level_information");
     225    level_information = new JToggleButton(get("Information"), Gatherer.config.get("messages.level_information", false));
     226    level_information.setIcon(Utility.OFF_ICON);
     227    level_information.setSelectedIcon(Utility.ON_ICON);
     228    level_information.addActionListener(this);
     229
     230    Gatherer.println("\tCreating level_error");
     231    level_error = new JToggleButton(get("Error"), Gatherer.config.get("messages.level_error", false));
     232    level_error.setIcon(Utility.OFF_ICON);
     233    level_error.setSelectedIcon(Utility.ON_ICON);
     234    level_error.addActionListener(this);
     235
     236    level_pane.add(level_label, BorderLayout.NORTH);
     237    horizontal_pane.add(level_main);
     238    horizontal_pane.add(level_event);
     239    horizontal_pane.add(level_information);
     240    horizontal_pane.add(level_error);
     241    level_pane.add(horizontal_pane, BorderLayout.CENTER);
     242
     243    // Terrifying gridbag layout
     244    grid_constraints.fill = GridBagConstraints.BOTH;
     245    grid_layout.setConstraints(source_pane, grid_constraints);
     246    this.add(source_pane);
     247    grid_constraints.weightx = 1.0;
     248    grid_constraints.weighty = 1.0;
     249    grid_constraints.gridwidth = GridBagConstraints.REMAINDER;
     250    grid_layout.setConstraints(central_pane, grid_constraints);
     251    this.add(central_pane);
     252    grid_constraints.weightx = 0.0;
     253    grid_constraints.weighty = 0.0;
     254    grid_constraints.gridwidth = 1;
     255    grid_layout.setConstraints(corner_pane, grid_constraints);
     256    this.add(corner_pane);
     257    grid_constraints.gridwidth = GridBagConstraints.REMAINDER;
     258    grid_layout.setConstraints(level_pane, grid_constraints);
     259    this.add(level_pane);
     260    }
     261
     262    public void actionPerformed(ActionEvent event) {
     263    Object source = event.getSource();
     264
     265    // Eventually this will dump the messages to a text file, but for now
     266    // I'm using it in testing.
     267    if(source == save_messages) {
     268        for(int i = 0; i < 20; i++) {
     269        model.add(Message.random());
     270        message_list.ensureIndexIsVisible(model.getSize() - 1);
     271        }
     272    }
     273    // We've been asked to toggle whether we show general messages.
     274    else if(source == source_general) {
     275                // Toggle config setting
     276        Gatherer.config.set("messages.source_general", false, !Gatherer.config.get("messages.source_general", false));
     277                // Inform model something has changed.
     278        model.refresh();
     279        message_list.ensureIndexIsVisible(model.getSize() - 1);
     280    }
     281    // We've been asked to toggle whether we show browser messages.
     282    else if(source == source_browser) {
     283                // Toggle config setting
     284        Gatherer.config.set("messages.source_browser", false, !Gatherer.config.get("messages.source_browser", false));
     285                // Inform model something has changed.
     286        model.refresh();
     287        message_list.ensureIndexIsVisible(model.getSize() - 1);
     288    }
     289    // We've been asked to toggle whether we show general messages.
     290    else if(source == source_mirroring) {
     291                // Toggle config setting
     292        Gatherer.config.set("messages.source_mirroring", false, !Gatherer.config.get("messages.source_mirroring", false));
     293                // Inform model something has changed.
     294        model.refresh();
     295        message_list.ensureIndexIsVisible(model.getSize() - 1);
     296    }
     297    // We've been asked to toggle whether we show session messages.
     298    else if(source == source_session) {
     299                // Toggle config setting
     300        Gatherer.config.set("messages.source_session", false, !Gatherer.config.get("messages.source_session", false));
     301                // Inform model something has changed.
     302        model.refresh();
     303        message_list.ensureIndexIsVisible(model.getSize() - 1);
     304    }
     305    // We've been asked to toggle whether we show metaedit messages.
     306    else if(source == source_metaedit) {
     307                // Toggle config setting
     308        Gatherer.config.set("messages.source_metaedit", false, !Gatherer.config.get("messages.source_metaedit", false));
     309                // Inform model something has changed.
     310        model.refresh();
     311        message_list.ensureIndexIsVisible(model.getSize() - 1);
     312    }
     313    // We've been asked to toggle whether we show build messages.
     314    else if(source == source_build) {
     315                // Toggle config setting
     316        Gatherer.config.set("messages.source_build", false, !Gatherer.config.get("messages.source_build", false));
     317                // Inform model something has changed.
     318        model.refresh();
     319        message_list.ensureIndexIsVisible(model.getSize() - 1);
     320    }
     321    // We've been asked to toggle whether we show main level messages.
     322    else if(source == level_main) {
     323                // Toggle config setting
     324        Gatherer.config.set("messages.level_main", false, !Gatherer.config.get("messages.level_main", false));
     325                // Inform model something has changed.
     326        model.refresh();
     327        message_list.ensureIndexIsVisible(model.getSize() - 1);
     328    }
     329    // We've been asked to toggle whether we show event level messages.
     330    else if(source == level_event) {
     331                // Toggle config setting
     332        Gatherer.config.set("messages.level_event", false, !Gatherer.config.get("messages.level_event", false));
     333                // Inform model something has changed.
     334        model.refresh();
     335        message_list.ensureIndexIsVisible(model.getSize() - 1);
     336    }
     337    // We've been asked to toggle whether we show information level messages.
     338    else if(source == level_information) {
     339                // Toggle config setting
     340        Gatherer.config.set("messages.level_information", false, !Gatherer.config.get("messages.level_information", false));
     341                // Inform model something has changed.
     342        model.refresh();
     343        message_list.ensureIndexIsVisible(model.getSize() - 1);
     344    }
     345    // We've been asked to toggle whether we show error level messages.
     346    else if(source == level_error) {
     347                // Toggle config setting
     348        Gatherer.config.set("messages.level_error", false, !Gatherer.config.get("messages.level_error", false));
     349                // Inform model something has changed.
     350        model.refresh();
     351        message_list.ensureIndexIsVisible(model.getSize() - 1);
     352    }
     353    // Pretty much no matter what happens we need to get the new size
     354    args = new String[2];
     355    args[0] = model.getSizeStr();
     356    args[1] = model.getTotalSizeStr();
     357    message_count.setText(get("Message_Count",args));
     358    }
     359
     360    /** The callback for the message listener. Here all of the messages are
     361     * displayed onto the list.
     362     * @param message The Message to be displayed.
     363     */
     364    public void show(Message message) {
     365    model.add(message);
     366    message_list.ensureIndexIsVisible(model.getSize() - 1);
     367    }
     368
     369
     370    private String get(String key) {
     371    return get(key, null);
     372    }
     373
     374    private String get(String key, String args[]) {
     375    if(key.indexOf('.') == -1) {
     376        key = "Messages." + key;
     377    }
     378    return Gatherer.dictionary.get(key, args);
     379    }
    380380}
    381381
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/Autofilter.java

    r4293 r4366  
    5858 */
    5959public class Autofilter {
    60     /** <i>true</i> if the filter should be applied, <i>false</i> to indicate the filter is turned off. */
    61     public boolean active;
    62     /** <i>true</i> if the matching for the first expression should be case sensitive, <i>false</i> otherwise. */
    63     public boolean casesense_one;
    64     /** <i>true</i> if the matching for the second expression should be case sensitive, <i>false</i> otherwise. */
    65     public boolean casesense_two;
    66     /** Used to determine the operation intended when applying two filters, and set using the values of the OPERATION_TYPE enumeration. */
    67     public boolean operation;
    68     /** Used to determine how the column this filter is applied to should be sorted, and set using the values of the SORT_TYPE enumeration. */
    69     public boolean sort;
    70     /** The method to be used for the first filter expression, set from the values of the METHOD_LIST enumeration. */
    71     public int method_one;
    72     /** The method to be used for the second filter expression, set from the values of the METHOD_LIST enumeration. */
    73     public int method_two;
    74     /** The value to be matched against for the first expression. */
    75     public String value_one;
    76     /** The value to be matched against for the second expression. */
    77     public String value_two;
    78     /** An element of the SORT_TYPE enumeration, indicates lowest to highest value column ordering. */
    79     public static final boolean ASCENDING = true;
    80     /** An element of the OPERATION_TYPE enumeration, indicates that both filter expressions must be met (conjunction). */
    81     public static final boolean AND = true;
    82     /** An element of the SORT_TYPE enumeration, indicates highest to lowest value column ordering. */
    83     public static final boolean DESCENDING = false;
    84     /** An element of the OPERATION_TYPE enumeration, indicates that either (or both) filter expressions must be met (disjunction). */
    85     public static final boolean OR = false;
    86     /** An enumeration of symbolic names of various matching methods. */
    87     public static final String METHOD_LIST[] = {"eqeq", "!eq", "<", "<eq", ">", ">eq", "^", "!^", "$", "!$", "?", "!?"};
    88     /** Default Constructor. */
    89     public Autofilter() {
    90           operation = OR;
    91           sort = ASCENDING;
    92     }
    93     /** Determine if this filter is currently active.
    94       * @return <i>true</i> if it is active, <i>false</i> otherwise.
    95       */
    96     public boolean active() {
    97           return active;
    98     }
    99     /** Determine if this list of values (for a certain cell) passes the filter.
    100       * @param values An <strong>ArrayList</strong> of values sourced from a single cell in the associated column.
    101       * @return <i>true</i> if the values match and should be displayed, <i>false</i> otherwise.
    102       */
    103     public boolean filter(ArrayList values) {
    104           boolean result = false;
    105           if(value_one != null) {
    106                 result = filter(values, method_one, value_one, casesense_one);
    107                 if(result) {
    108                      if(operation == AND && value_two != null) {
    109                           result = filter(values, method_two, value_two, casesense_two);
    110                      }
    111                 }
    112                 else if(operation == OR && value_two != null) {
    113                      result = filter(values, method_two, value_two, casesense_two);
    114                 }
    115           }
    116           return result;
    117     }
    118     /** Set the current activity state of this filter.
    119       * @param active The new state of this filter, <i>true</i> to activate, <i>false</i> otherwise.
    120       */
    121     public void setActive(boolean active) {
    122           this.active = active;
    123     }
    124     /** Set one of the filter expressions using the given information.
    125       * @param number The number of the filter you wish to set as an <i>int</i>. Either 1 or 2.
    126       * @param method An <i>int</i> indicating the method to be used when matching.
    127       * @param value The <strong>String</strong> to be matched against.
    128       * @param casesense <i>true</i> if this expression should be case sensitive, <i>false</i> otherwise.
    129       */
    130     public void setFilter(int number, int method, String value, boolean casesense) {
    131           if(!casesense && value != null) {
    132                 value = value.toLowerCase();
    133           }
    134           if(number == 1) {
    135                 casesense_one = casesense;
    136                 method_one = method;
    137                 value_one = value;
    138           }
    139           else {
    140                 casesense_two = casesense;
    141                 method_two = method;
    142                 value_two = value;
    143           }
    144     }
    145     /** Set the operation to be used to join the two filters (if a second filter is set).
    146       * @param operation <i>true</i> for conjunct filters, <i>false</i> for disjunct.
    147       */
    148     public void setOperation(boolean operation) {
    149           this.operation = operation;
    150     }
    151     /** Set the sort order of this column.
    152       * @param sort <i>true</i> for ascending sort, <i>false</i> for descending.
    153       */
    154     public void setSort(boolean sort) {
    155           this.sort = sort;
    156     }
    157     /** Decide whether a row should be displayed or filtered. The result depends on the selector set with setFilterType.
    158       * @param values An <strong>ArrayList</strong> of values to be checked against the filter.
    159       * @param method The method of matching to be used, as an <i>int</i>.
    160       * @param target The <strong>String</Strong> to match against.
    161       * @param casesense <i>true</i> if the match is to be case sensitive, <i>false</i> otherwise.
    162       * @return <i>true</i> to display the row, <i>false</i> to hide it.
    163       */
    164     public boolean filter(ArrayList values, int method, String target, boolean casesense) {
    165           boolean result = false;
    166           // There are several special cases when the filter always returns turn, such as when the target is the wildcard character.
    167           if(target == null || target.length() == 0 || target.equals("*")) {
    168                 result = true;
    169           }
    170           else {
     60    /** <i>true</i> if the filter should be applied, <i>false</i> to indicate the filter is turned off. */
     61    public boolean active;
     62    /** <i>true</i> if the matching for the first expression should be case sensitive, <i>false</i> otherwise. */
     63    public boolean casesense_one;
     64    /** <i>true</i> if the matching for the second expression should be case sensitive, <i>false</i> otherwise. */
     65    public boolean casesense_two;
     66    /** Used to determine the operation intended when applying two filters, and set using the values of the OPERATION_TYPE enumeration. */
     67    public boolean operation;
     68    /** Used to determine how the column this filter is applied to should be sorted, and set using the values of the SORT_TYPE enumeration. */
     69    public boolean sort;
     70    /** The method to be used for the first filter expression, set from the values of the METHOD_LIST enumeration. */
     71    public int method_one;
     72    /** The method to be used for the second filter expression, set from the values of the METHOD_LIST enumeration. */
     73    public int method_two;
     74    /** The value to be matched against for the first expression. */
     75    public String value_one;
     76    /** The value to be matched against for the second expression. */
     77    public String value_two;
     78    /** An element of the SORT_TYPE enumeration, indicates lowest to highest value column ordering. */
     79    public static final boolean ASCENDING = true;
     80    /** An element of the OPERATION_TYPE enumeration, indicates that both filter expressions must be met (conjunction). */
     81    public static final boolean AND = true;
     82    /** An element of the SORT_TYPE enumeration, indicates highest to lowest value column ordering. */
     83    public static final boolean DESCENDING = false;
     84    /** An element of the OPERATION_TYPE enumeration, indicates that either (or both) filter expressions must be met (disjunction). */
     85    public static final boolean OR = false;
     86    /** An enumeration of symbolic names of various matching methods. */
     87    public static final String METHOD_LIST[] = {"eqeq", "!eq", "<", "<eq", ">", ">eq", "^", "!^", "$", "!$", "?", "!?"};
     88    /** Default Constructor. */
     89    public Autofilter() {
     90    operation = OR;
     91    sort = ASCENDING;
     92    }
     93    /** Determine if this filter is currently active.
     94     * @return <i>true</i> if it is active, <i>false</i> otherwise.
     95     */
     96    public boolean active() {
     97    return active;
     98    }
     99    /** Determine if this list of values (for a certain cell) passes the filter.
     100     * @param values An <strong>ArrayList</strong> of values sourced from a single cell in the associated column.
     101     * @return <i>true</i> if the values match and should be displayed, <i>false</i> otherwise.
     102     */
     103    public boolean filter(ArrayList values) {
     104    boolean result = false;
     105    if(value_one != null) {
     106        result = filter(values, method_one, value_one, casesense_one);
     107        if(result) {
     108        if(operation == AND && value_two != null) {
     109            result = filter(values, method_two, value_two, casesense_two);
     110        }
     111        }
     112        else if(operation == OR && value_two != null) {
     113        result = filter(values, method_two, value_two, casesense_two);
     114        }
     115    }
     116    return result;
     117    }
     118    /** Set the current activity state of this filter.
     119     * @param active The new state of this filter, <i>true</i> to activate, <i>false</i> otherwise.
     120     */
     121    public void setActive(boolean active) {
     122    this.active = active;
     123    }
     124    /** Set one of the filter expressions using the given information.
     125     * @param number The number of the filter you wish to set as an <i>int</i>. Either 1 or 2.
     126     * @param method An <i>int</i> indicating the method to be used when matching.
     127     * @param value The <strong>String</strong> to be matched against.
     128     * @param casesense <i>true</i> if this expression should be case sensitive, <i>false</i> otherwise.
     129     */
     130    public void setFilter(int number, int method, String value, boolean casesense) {
     131    if(!casesense && value != null) {
     132        value = value.toLowerCase();
     133    }
     134    if(number == 1) {
     135        casesense_one = casesense;
     136        method_one = method;
     137        value_one = value;
     138    }
     139    else {
     140        casesense_two = casesense;
     141        method_two = method;
     142        value_two = value;
     143    }
     144    }
     145    /** Set the operation to be used to join the two filters (if a second filter is set).
     146     * @param operation <i>true</i> for conjunct filters, <i>false</i> for disjunct.
     147     */
     148    public void setOperation(boolean operation) {
     149    this.operation = operation;
     150    }
     151    /** Set the sort order of this column.
     152     * @param sort <i>true</i> for ascending sort, <i>false</i> for descending.
     153     */
     154    public void setSort(boolean sort) {
     155    this.sort = sort;
     156    }
     157    /** Decide whether a row should be displayed or filtered. The result depends on the selector set with setFilterType.
     158     * @param values An <strong>ArrayList</strong> of values to be checked against the filter.
     159     * @param method The method of matching to be used, as an <i>int</i>.
     160     * @param target The <strong>String</Strong> to match against.
     161     * @param casesense <i>true</i> if the match is to be case sensitive, <i>false</i> otherwise.
     162     * @return <i>true</i> to display the row, <i>false</i> to hide it.
     163     */
     164    public boolean filter(ArrayList values, int method, String target, boolean casesense) {
     165    boolean result = false;
     166    // There are several special cases when the filter always returns turn, such as when the target is the wildcard character.
     167    if(target == null || target.length() == 0 || target.equals("*")) {
     168        result = true;
     169    }
     170    else {
    171171                // For each value in the list...
    172                 for(int i = 0; i < values.size(); i++) {
    173                      boolean pass;
    174                      String source;
    175                      // Account for case sensitivity.
    176                      if(casesense) {
    177                           source = values.get(i).toString();
    178                      }
    179                      else {
    180                           source = values.get(i).toString().toLowerCase();
    181                      }
    182                      // Perform the match, based on the selected method.
    183                      switch(method) {
    184                      case 1: // !EQ
    185                           pass = !(source.equals(target));
    186                           break;
    187                      case 2: // <
    188                           pass = (source.compareTo(target) < 0);
    189                           break;
    190                      case 3: // <eq
    191                           pass = (source.compareTo(target) <= 0);
    192                     break;
    193                      case 4: // >
    194                           pass = (source.compareTo(target) > 0);
    195                           break;
    196                      case 5: // >eq
    197                           pass = (source.compareTo(target) >= 0);
    198                           break;
    199                      case 6: // ^
    200                           pass = source.startsWith(target);
    201                           break;
    202                      case 7: // !^
    203                           pass = !(source.startsWith(target));
    204                           break;
    205                      case 8: // $
    206                           pass = source.endsWith(target);
    207                           break;
    208                      case 9: // !$
    209                           pass = !(source.endsWith(target));
    210                           break;
    211                      case 10: // ?
    212                           pass = (source.indexOf(target) != -1);
    213                           break;
    214                      case 11: // !?
    215                           pass = (source.indexOf(target) == -1);
    216                           break;
    217                      default: // EQEQ
    218                           pass = source.equals(target);
    219                           break;
    220                      }
    221                      result = result || pass;
    222                 }
    223           }
    224           return result;         
    225     }
    226     /** Produce a textual representation of this autofilter.
    227       * @return A <strong>String</strong> displaying details of this autofilter.
    228       */
    229     public String toString() {
    230           String result = "One: " + method_one + " - " + value_one + " - " + casesense_one;
    231           if(value_two != null) {
    232                 result = result + "\n" + "Operation: " + (operation?"AND":"OR") + "\n";
    233                 result = result + "Two: " + method_two + " - " + value_two + " - " + casesense_two;
    234           }
    235           return result;
    236     }
     172        for(int i = 0; i < values.size(); i++) {
     173        boolean pass;
     174        String source;
     175        // Account for case sensitivity.
     176        if(casesense) {
     177            source = values.get(i).toString();
     178        }
     179        else {
     180            source = values.get(i).toString().toLowerCase();
     181        }
     182        // Perform the match, based on the selected method.
     183        switch(method) {
     184        case 1: // !EQ
     185            pass = !(source.equals(target));
     186            break;
     187        case 2: // <
     188            pass = (source.compareTo(target) < 0);
     189            break;
     190        case 3: // <eq
     191            pass = (source.compareTo(target) <= 0);
     192            break;
     193        case 4: // >
     194            pass = (source.compareTo(target) > 0);
     195            break;
     196        case 5: // >eq
     197            pass = (source.compareTo(target) >= 0);
     198            break;
     199        case 6: // ^
     200            pass = source.startsWith(target);
     201            break;
     202        case 7: // !^
     203            pass = !(source.startsWith(target));
     204            break;
     205        case 8: // $
     206            pass = source.endsWith(target);
     207            break;
     208        case 9: // !$
     209            pass = !(source.endsWith(target));
     210            break;
     211        case 10: // ?
     212            pass = (source.indexOf(target) != -1);
     213            break;
     214        case 11: // !?
     215            pass = (source.indexOf(target) == -1);
     216            break;
     217        default: // EQEQ
     218            pass = source.equals(target);
     219            break;
     220        }
     221        result = result || pass;
     222        }
     223    }
     224    return result;       
     225    }
     226    /** Produce a textual representation of this autofilter.
     227     * @return A <strong>String</strong> displaying details of this autofilter.
     228     */
     229    public String toString() {
     230    String result = "One: " + method_one + " - " + value_one + " - " + casesense_one;
     231    if(value_two != null) {
     232        result = result + "\n" + "Operation: " + (operation?"AND":"OR") + "\n";
     233        result = result + "Two: " + method_two + " - " + value_two + " - " + casesense_two;
     234    }
     235    return result;
     236    }
    237237}
    238238
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/AutofilterDialog.java

    r4293 r4366  
    4949 */
    5050public final class AutofilterDialog
    51     extends JDialog {
    52     /** The filter being edited. */
    53     private Autofilter filter;
    54     /** A reference to ourselves so our inner classes can reference us. */
    55     private AutofilterDialog self;
    56     /** The value returned from the filter dialog prompt. Used to determine if a prompt was set or unset, and what subsequent action to take. */
    57     private byte return_value = 0;
    58     /** The button used to cancel the prompt. */
    59     private JButton cancel_button = null;
    60     /** The button used to accept and commit any changes to the autofilter. */
    61     private JButton ok_button = null;
    62     /** A check box used to specify that the given filters should be applied conjunctly. */
    63     private JCheckBox and_check = null;
    64     /** The check box used to specify whether the first filter is case sensitive. */
    65     private JCheckBox first_case = null;
    66     /** The none check is used to disable the second filter. */
    67     private JCheckBox none_check = null;
    68     /** The check box used to specify that the given filters should be applied disjunctly. */
    69     private JCheckBox or_check = null;
    70     /** The check box used to specify whether the second filter is case sensitive. */
    71     private JCheckBox second_case = null;
    72     /** Used to specify the order of the resulting set: Ascending or Descending. */
    73     private JComboBox order = null;
    74     /** The method used to match the first filter: Contains, Doesn't contain etc. */
    75     private JComboBox first_method = null;
    76     /** The value to be matched for the first filter. */
    77     private JComboBox first_value = null;
    78     /** The method used to match the first filter. Options as for the first method. */
    79     private JComboBox second_method = null;
    80     /** The value to be matched for the second filter. */
    81     private JComboBox second_value = null;
    82     /** Used for the most basic filter where an Equals, Case sensitive method is automatically used. */
    83     private JComboBox value = null;
    84     /** The label which displays the name of the currently selected column (the column that will be associated with the autofilter this dialog produces). */
    85     private JLabel name;
    86     /** The autofilter prompt contains two different panes, one for basic functionality and one for advanced. This containiner component is used to allow access to each via a 'tabbed' interface. */
    87     private JTabbedPane control = null;
    88     /** A reference back to the MetaAudit dialog that spawned this prompt. Used to make sure that any open dialog window is always in front of the audit pane. */
    89     private MetaAuditFrame dialog;
    90     /** The default size for the autofilter control. */
    91     static final private Dimension SIZE = new Dimension(640, 220);
    92     /** Constructor.
    93       * @param dialog A reference to the <strong>MetaAuditFrame</strong> that spawned this dialog.
    94       * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
    95       * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.ButtonListener
    96       * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.CheckListener
    97       */
    98     public AutofilterDialog(MetaAuditFrame dialog) {
    99           super(Gatherer.g_man);
    100           this.dialog = dialog;
    101           this.self = this;
    102           setModal(true);
    103           setSize(SIZE);
    104           setTitle(get("Title"));
    105           // Creation
    106           JPanel content_pane = (JPanel) getContentPane();
    107           JPanel name_pane = new JPanel();
    108           JLabel name_label = new JLabel(get("Name"));
    109           JTextField name_template = new JTextField();
    110           name = new JLabel();
    111           name.setBorder(name_template.getBorder());
    112           control = new JTabbedPane();
    113           JPanel value_pane = new JPanel();
    114           JPanel inner_value_pane = new JPanel();
    115           JLabel value_label = new JLabel(get("eqeq"));
    116           value = new JComboBox();
    117           value.setEditable(false);
    118           JPanel custom_pane = new JPanel();
    119           JPanel first_pane = new JPanel();
    120           first_method = new JComboBox();
    121           first_value = new JComboBox();
    122           first_value.setEditable(true);
    123           first_value.addItem("");
    124           first_value.setSelectedItem("");
    125           first_case = new JCheckBox(get("Case_Sensitive"));
    126           JPanel operator_pane = new JPanel();
    127           JLabel operator_label = new JLabel(get("Operator"));
    128           ButtonGroup operator_group = new ButtonGroup();
    129           and_check = new JCheckBox(get("AND"));
    130           none_check = new JCheckBox(get("None"));
    131           or_check = new JCheckBox(get("OR"));
    132           none_check.setSelected(true);
    133           operator_group.add(none_check);
    134           operator_group.add(and_check);
    135           operator_group.add(or_check);
    136           JPanel second_pane = new JPanel();
    137           second_method = new JComboBox();
    138           second_method.setEnabled(false);
    139           second_value = new JComboBox();
    140           second_value.setEditable(true);
    141           second_value.setEnabled(false);
    142           second_value.addItem("");
    143           second_value.setSelectedItem("");
    144           second_case = new JCheckBox(get("Case_Sensitive"));
    145           JPanel lower_pane = new JPanel();
    146           JPanel order_pane = new JPanel();
    147           JLabel order_label = new JLabel(get("Order"));
    148           order = new JComboBox();
    149           order.addItem(get("Ascending"));
    150           order.addItem(get("Descending"));
    151           // Assign values to method comboboxes.
    152           for(int i = 0; i < Autofilter.METHOD_LIST.length; i++) {
    153                 first_method.addItem(get(Autofilter.METHOD_LIST[i]));
    154                 second_method.addItem(get(Autofilter.METHOD_LIST[i]));
    155           }
    156           JPanel button_pane = new JPanel();
    157           cancel_button = new JButton(get("Clear"));
    158           cancel_button.setMnemonic(KeyEvent.VK_C);
    159           ok_button = new JButton(get("Set"));
    160           ok_button.setMnemonic(KeyEvent.VK_S);
    161           // Connection
    162           and_check.addActionListener(new CheckListener(true));
    163           cancel_button.addActionListener(new ButtonListener(false));
    164           none_check.addActionListener(new CheckListener(false));
    165           ok_button.addActionListener(new ButtonListener(true));
    166           or_check.addActionListener(new CheckListener(true));
    167           // Layout       
    168           name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    169 
    170           name_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
    171           name_pane.setLayout(new BorderLayout());
    172           name_pane.add(name_label, BorderLayout.WEST);
    173           name_pane.add(name, BorderLayout.CENTER);
    174 
    175           value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    176 
    177           inner_value_pane.setLayout(new BorderLayout());
    178           inner_value_pane.add(value_label, BorderLayout.WEST);
    179           inner_value_pane.add(value, BorderLayout.CENTER);
    180 
    181           value_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
    182           value_pane.setLayout(new BorderLayout());
    183           value_pane.add(inner_value_pane, BorderLayout.NORTH);
    184 
    185           first_pane.setLayout(new BorderLayout());
    186           first_pane.add(first_method, BorderLayout.WEST);
    187           first_pane.add(first_value, BorderLayout.CENTER);
    188           first_pane.add(first_case, BorderLayout.EAST);
    189 
    190           operator_pane.setLayout(new GridLayout(1,4));
    191           operator_pane.add(operator_label);
    192           operator_pane.add(none_check);
    193           operator_pane.add(and_check);
    194           operator_pane.add(or_check);
    195 
    196           second_pane.setLayout(new BorderLayout());
    197           second_pane.add(second_method, BorderLayout.WEST);
    198           second_pane.add(second_value, BorderLayout.CENTER);
    199           second_pane.add(second_case, BorderLayout.EAST);
    200 
    201           order_pane.setLayout(new GridLayout(1,2));
    202           order_pane.add(order_label);
    203           order_pane.add(order);
    204 
    205           custom_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
    206           custom_pane.setLayout(new GridLayout(3,1));
    207           custom_pane.add(first_pane);
    208           custom_pane.add(operator_pane);
    209           custom_pane.add(second_pane);
     51    extends JDialog {
     52    /** The filter being edited. */
     53    private Autofilter filter;
     54    /** A reference to ourselves so our inner classes can reference us. */
     55    private AutofilterDialog self;
     56    /** The value returned from the filter dialog prompt. Used to determine if a prompt was set or unset, and what subsequent action to take. */
     57    private byte return_value = 0;
     58    /** The button used to cancel the prompt. */
     59    private JButton cancel_button = null;
     60    /** The button used to accept and commit any changes to the autofilter. */
     61    private JButton ok_button = null;
     62    /** A check box used to specify that the given filters should be applied conjunctly. */
     63    private JCheckBox and_check = null;
     64    /** The check box used to specify whether the first filter is case sensitive. */
     65    private JCheckBox first_case = null;
     66    /** The none check is used to disable the second filter. */
     67    private JCheckBox none_check = null;
     68    /** The check box used to specify that the given filters should be applied disjunctly. */
     69    private JCheckBox or_check = null;
     70    /** The check box used to specify whether the second filter is case sensitive. */
     71    private JCheckBox second_case = null;
     72    /** Used to specify the order of the resulting set: Ascending or Descending. */
     73    private JComboBox order = null;
     74    /** The method used to match the first filter: Contains, Doesn't contain etc. */
     75    private JComboBox first_method = null;
     76    /** The value to be matched for the first filter. */
     77    private JComboBox first_value = null;
     78    /** The method used to match the first filter. Options as for the first method. */
     79    private JComboBox second_method = null;
     80    /** The value to be matched for the second filter. */
     81    private JComboBox second_value = null;
     82    /** Used for the most basic filter where an Equals, Case sensitive method is automatically used. */
     83    private JComboBox value = null;
     84    /** The label which displays the name of the currently selected column (the column that will be associated with the autofilter this dialog produces). */
     85    private JLabel name;
     86    /** The autofilter prompt contains two different panes, one for basic functionality and one for advanced. This containiner component is used to allow access to each via a 'tabbed' interface. */
     87    private JTabbedPane control = null;
     88    /** A reference back to the MetaAudit dialog that spawned this prompt. Used to make sure that any open dialog window is always in front of the audit pane. */
     89    private MetaAuditFrame dialog;
     90    /** The default size for the autofilter control. */
     91    static final private Dimension SIZE = new Dimension(640, 220);
     92    /** Constructor.
     93     * @param dialog A reference to the <strong>MetaAuditFrame</strong> that spawned this dialog.
     94     * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
     95     * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.ButtonListener
     96     * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.CheckListener
     97     */
     98    public AutofilterDialog(MetaAuditFrame dialog) {
     99    super(Gatherer.g_man);
     100    this.dialog = dialog;
     101    this.self = this;
     102    setModal(true);
     103    setSize(SIZE);
     104    setTitle(get("Title"));
     105    // Creation
     106    JPanel content_pane = (JPanel) getContentPane();
     107    JPanel name_pane = new JPanel();
     108    JLabel name_label = new JLabel(get("Name"));
     109    JTextField name_template = new JTextField();
     110    name = new JLabel();
     111    name.setBorder(name_template.getBorder());
     112    control = new JTabbedPane();
     113    JPanel value_pane = new JPanel();
     114    JPanel inner_value_pane = new JPanel();
     115    JLabel value_label = new JLabel(get("eqeq"));
     116    value = new JComboBox();
     117    value.setEditable(false);
     118    JPanel custom_pane = new JPanel();
     119    JPanel first_pane = new JPanel();
     120    first_method = new JComboBox();
     121    first_value = new JComboBox();
     122    first_value.setEditable(true);
     123    first_value.addItem("");
     124    first_value.setSelectedItem("");
     125    first_case = new JCheckBox(get("Case_Sensitive"));
     126    JPanel operator_pane = new JPanel();
     127    JLabel operator_label = new JLabel(get("Operator"));
     128    ButtonGroup operator_group = new ButtonGroup();
     129    and_check = new JCheckBox(get("AND"));
     130    none_check = new JCheckBox(get("None"));
     131    or_check = new JCheckBox(get("OR"));
     132    none_check.setSelected(true);
     133    operator_group.add(none_check);
     134    operator_group.add(and_check);
     135    operator_group.add(or_check);
     136    JPanel second_pane = new JPanel();
     137    second_method = new JComboBox();
     138    second_method.setEnabled(false);
     139    second_value = new JComboBox();
     140    second_value.setEditable(true);
     141    second_value.setEnabled(false);
     142    second_value.addItem("");
     143    second_value.setSelectedItem("");
     144    second_case = new JCheckBox(get("Case_Sensitive"));
     145    JPanel lower_pane = new JPanel();
     146    JPanel order_pane = new JPanel();
     147    JLabel order_label = new JLabel(get("Order"));
     148    order = new JComboBox();
     149    order.addItem(get("Ascending"));
     150    order.addItem(get("Descending"));
     151    // Assign values to method comboboxes.
     152    for(int i = 0; i < Autofilter.METHOD_LIST.length; i++) {
     153        first_method.addItem(get(Autofilter.METHOD_LIST[i]));
     154        second_method.addItem(get(Autofilter.METHOD_LIST[i]));
     155    }
     156    JPanel button_pane = new JPanel();
     157    cancel_button = new JButton(get("Clear"));
     158    cancel_button.setMnemonic(KeyEvent.VK_C);
     159    ok_button = new JButton(get("Set"));
     160    ok_button.setMnemonic(KeyEvent.VK_S);
     161    // Connection
     162    and_check.addActionListener(new CheckListener(true));
     163    cancel_button.addActionListener(new ButtonListener(false));
     164    none_check.addActionListener(new CheckListener(false));
     165    ok_button.addActionListener(new ButtonListener(true));
     166    or_check.addActionListener(new CheckListener(true));
     167    // Layout         
     168    name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     169
     170    name_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
     171    name_pane.setLayout(new BorderLayout());
     172    name_pane.add(name_label, BorderLayout.WEST);
     173    name_pane.add(name, BorderLayout.CENTER);
     174
     175    value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
     176
     177    inner_value_pane.setLayout(new BorderLayout());
     178    inner_value_pane.add(value_label, BorderLayout.WEST);
     179    inner_value_pane.add(value, BorderLayout.CENTER);
     180
     181    value_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
     182    value_pane.setLayout(new BorderLayout());
     183    value_pane.add(inner_value_pane, BorderLayout.NORTH);
     184
     185    first_pane.setLayout(new BorderLayout());
     186    first_pane.add(first_method, BorderLayout.WEST);
     187    first_pane.add(first_value, BorderLayout.CENTER);
     188    first_pane.add(first_case, BorderLayout.EAST);
     189
     190    operator_pane.setLayout(new GridLayout(1,4));
     191    operator_pane.add(operator_label);
     192    operator_pane.add(none_check);
     193    operator_pane.add(and_check);
     194    operator_pane.add(or_check);
     195
     196    second_pane.setLayout(new BorderLayout());
     197    second_pane.add(second_method, BorderLayout.WEST);
     198    second_pane.add(second_value, BorderLayout.CENTER);
     199    second_pane.add(second_case, BorderLayout.EAST);
     200
     201    order_pane.setLayout(new GridLayout(1,2));
     202    order_pane.add(order_label);
     203    order_pane.add(order);
     204
     205    custom_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
     206    custom_pane.setLayout(new GridLayout(3,1));
     207    custom_pane.add(first_pane);
     208    custom_pane.add(operator_pane);
     209    custom_pane.add(second_pane);
    210210         
    211           control.add(get("Filter_By_Value"), value_pane);
    212           control.add(get("Custom_Filter"), custom_pane);
    213 
    214           button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
    215           button_pane.setLayout(new GridLayout(1,2));
    216           button_pane.add(ok_button);
    217           button_pane.add(cancel_button);
    218 
    219           lower_pane.setLayout(new BorderLayout());
    220           lower_pane.add(order_pane, BorderLayout.CENTER);
    221           lower_pane.add(button_pane, BorderLayout.SOUTH);
    222 
    223           content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    224           content_pane.setLayout(new BorderLayout());
    225           content_pane.add(name_pane, BorderLayout.NORTH);
    226           content_pane.add(control, BorderLayout.CENTER);
    227           content_pane.add(lower_pane, BorderLayout.SOUTH);
    228 
    229           Dimension screen_size = Gatherer.config.screen_size;
    230           setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
    231           screen_size = null;
    232     }
    233     /** Destructor. */
    234     public void destroy() {
    235           dispose();
    236           cancel_button = null;
    237           ok_button = null;
    238           and_check = null;
    239           first_case = null;
    240           none_check = null;
    241           or_check = null;
    242           second_case = null;
    243           order = null;
    244           first_method = null;
    245           first_value = null;
    246           second_method = null;
    247           second_value = null;
    248           value = null;
    249           control = null;
    250           dialog = null;
    251           self = null;
    252           name = null;
    253     }
    254     /** Display the modal dialog box, allowing the user to define the filter. When the user presses one of the buttons, dispose and return to the caller providing an indication of which button was pressed.
     211    control.add(get("Filter_By_Value"), value_pane);
     212    control.add(get("Custom_Filter"), custom_pane);
     213
     214    button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
     215    button_pane.setLayout(new GridLayout(1,2));
     216    button_pane.add(ok_button);
     217    button_pane.add(cancel_button);
     218
     219    lower_pane.setLayout(new BorderLayout());
     220    lower_pane.add(order_pane, BorderLayout.CENTER);
     221    lower_pane.add(button_pane, BorderLayout.SOUTH);
     222
     223    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     224    content_pane.setLayout(new BorderLayout());
     225    content_pane.add(name_pane, BorderLayout.NORTH);
     226    content_pane.add(control, BorderLayout.CENTER);
     227    content_pane.add(lower_pane, BorderLayout.SOUTH);
     228
     229    Dimension screen_size = Gatherer.config.screen_size;
     230    setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
     231    screen_size = null;
     232    }
     233    /** Destructor. */
     234    public void destroy() {
     235    dispose();
     236    cancel_button = null;
     237    ok_button = null;
     238    and_check = null;
     239    first_case = null;
     240    none_check = null;
     241    or_check = null;
     242    second_case = null;
     243    order = null;
     244    first_method = null;
     245    first_value = null;
     246    second_method = null;
     247    second_value = null;
     248    value = null;
     249    control = null;
     250    dialog = null;
     251    self = null;
     252    name = null;
     253    }
     254    /** Display the modal dialog box, allowing the user to define the filter. When the user presses one of the buttons, dispose and return to the caller providing an indication of which button was pressed.
    255255      * @return An <i>int</i> which indicates which button was pressed to dismiss the dialog.
    256256      */
    257     public Autofilter display(Autofilter filter, ArrayList raw_values, String column_name) {
    258           this.filter = filter;
    259           name.setText(column_name);
    260           // Prune values so it only contains unique entries, then order.
    261           TreeSet values = new TreeSet(raw_values);
    262           value.setModel(new DefaultComboBoxModel(values.toArray()));
    263           String star = "*";
    264           value.insertItemAt(star, 0);
    265           value.setSelectedItem(star);
    266           first_value.setModel(new DefaultComboBoxModel(values.toArray()));
    267           second_value.setModel(new DefaultComboBoxModel(values.toArray()));
    268           // Restore previous values.
    269           if(filter != null && filter.value_one != null) {
    270                 value.setSelectedItem(filter.value_one);
    271                 first_method.setSelectedIndex(filter.method_one);
    272                 first_value.setSelectedItem(filter.value_one);
    273                 first_case.setSelected(filter.casesense_one);
    274                 if(filter.value_two == null) {
    275                      none_check.setSelected(true);
    276                 }
    277                 else {
    278                      if(filter.operation) {
    279                           and_check.setSelected(true);
    280                      }
    281                      else {
    282                           or_check.setSelected(true);
    283                      }
    284                      second_method.setSelectedIndex(filter.method_two);
    285                      second_value.setSelectedItem(filter.value_two);
    286                      second_case.setSelected(filter.casesense_two);
    287                 }
    288                 if(filter.sort) {
    289                      order.setSelectedIndex(0);
    290                 }
    291                 else {
    292                      order.setSelectedIndex(1);
    293                 }
    294           }
    295           // Display     
    296           show();
    297           dialog.toFront();
    298           return this.filter;
    299     }
    300     /** Use the given key to retrieve a phrase from the dictionary.
     257    public Autofilter display(Autofilter filter, ArrayList raw_values, String column_name) {
     258    this.filter = filter;
     259    name.setText(column_name);
     260    // Prune values so it only contains unique entries, then order.
     261    TreeSet values = new TreeSet(raw_values);
     262    value.setModel(new DefaultComboBoxModel(values.toArray()));
     263    String star = "*";
     264    value.insertItemAt(star, 0);
     265    value.setSelectedItem(star);
     266    first_value.setModel(new DefaultComboBoxModel(values.toArray()));
     267    second_value.setModel(new DefaultComboBoxModel(values.toArray()));
     268    // Restore previous values.
     269    if(filter != null && filter.value_one != null) {
     270        value.setSelectedItem(filter.value_one);
     271        first_method.setSelectedIndex(filter.method_one);
     272        first_value.setSelectedItem(filter.value_one);
     273        first_case.setSelected(filter.casesense_one);
     274        if(filter.value_two == null) {
     275        none_check.setSelected(true);
     276        }
     277        else {
     278        if(filter.operation) {
     279            and_check.setSelected(true);
     280        }
     281        else {
     282            or_check.setSelected(true);
     283        }
     284        second_method.setSelectedIndex(filter.method_two);
     285        second_value.setSelectedItem(filter.value_two);
     286        second_case.setSelected(filter.casesense_two);
     287        }
     288        if(filter.sort) {
     289        order.setSelectedIndex(0);
     290        }
     291        else {
     292        order.setSelectedIndex(1);
     293        }
     294    }
     295    // Display   
     296    show();
     297    dialog.toFront();
     298    return this.filter;
     299    }
     300    /** Use the given key to retrieve a phrase from the dictionary.
    301301      * @param key A <strong>String</strong> which uniquely maps to an entry in the Dictionary.
    302302      * @return The <strong>String</strong> to key mapped to.
    303303      * @see org.greenstone.gatherer.Dictionary
    304304      */
    305      private final String get(String key) {
    306           if(key.indexOf(".") == -1) {
    307                 key = "Autofilter." + key;
    308           }
    309           return Gatherer.dictionary.get(key, (String[])null);
    310      }
    311      /** Listens for actions on the button it is attached to, and when notified sets the return_value and disposes of the dialog. */
    312      private final class ButtonListener
    313           implements ActionListener {
    314           private boolean return_filter;
    315           /** Does an action on this button cause a filter to be returned. */
    316           /** Constructor takes an associated return value as an argument.
    317             * @param return_filter <i>true</i> if we update then return the filter, <i>false</i> to clear existing filter.
     305    private final String get(String key) {
     306    if(key.indexOf(".") == -1) {
     307        key = "Autofilter." + key;
     308    }
     309    return Gatherer.dictionary.get(key, (String[])null);
     310    }
     311    /** Listens for actions on the button it is attached to, and when notified sets the return_value and disposes of the dialog. */
     312    private final class ButtonListener
     313    implements ActionListener {
     314    private boolean return_filter;
     315    /** Does an action on this button cause a filter to be returned. */
     316    /** Constructor takes an associated return value as an argument.
     317     * @param return_filter <i>true</i> if we update then return the filter, <i>false</i> to clear existing filter.
     318     */
     319    public ButtonListener(boolean return_filter) {
     320        this.return_filter = return_filter;
     321    }
     322    /** When any registered component is actioned apon, set the value and hide the dialog. We hide rather than dispose, because hide assures the data values will be retained.
     323     * @param event An <strong>ActionEvent</strong> containing information about the action that caused this method call.
     324     * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
     325     */
     326    public void actionPerformed(ActionEvent event) {
     327        if(return_filter) {
     328        if(control.getSelectedIndex() == 0) {
     329            filter.setFilter(1, 0, (String)value.getSelectedItem(), true);
     330            filter.setFilter(2, 0, null, true);
     331        }
     332        else {
     333            filter.setFilter(1, first_method.getSelectedIndex(), (String)first_value.getSelectedItem(), first_case.isSelected());
     334            if(!none_check.isSelected()) {
     335            if(and_check.isSelected()) {
     336                filter.setOperation(Autofilter.AND);
     337            }
     338            else {
     339                filter.setOperation(Autofilter.OR);
     340            }
     341            filter.setFilter(2, second_method.getSelectedIndex(), (String)second_value.getSelectedItem(), second_case.isSelected());
     342            }
     343        }
     344        if(order.getSelectedIndex() == 0) {
     345            filter.setSort(Autofilter.ASCENDING);
     346        }
     347        else {
     348            filter.setSort(Autofilter.DESCENDING);
     349        }
     350        }
     351        else {
     352        filter = null;
     353        }
     354        hide();
     355    }
     356    }
     357    /** Listens for actions on the check box it is attached to, and when notified sets the state of the second method and value to the specified state. */
     358    private final class CheckListener
     359    implements ActionListener {
     360    /** The default desire state any check button this listens to. */
     361    private boolean desired_state = false;
     362    /** The constructor takes an associated desired state.
     363     * @param desired_state The state that should be set when this is actioned, as a <i>boolean</i>.
    318364            */
    319           public ButtonListener(boolean return_filter) {
    320                 this.return_filter = return_filter;
    321           }
    322           /** When any registered component is actioned apon, set the value and hide the dialog. We hide rather than dispose, because hide assures the data values will be retained.
    323             * @param event An <strong>ActionEvent</strong> containing information about the action that caused this method call.
    324             * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
    325             */
    326           public void actionPerformed(ActionEvent event) {
    327                 if(return_filter) {
    328                      if(control.getSelectedIndex() == 0) {
    329                           filter.setFilter(1, 0, (String)value.getSelectedItem(), true);
    330                           filter.setFilter(2, 0, null, true);
    331                      }
    332                      else {
    333                           filter.setFilter(1, first_method.getSelectedIndex(), (String)first_value.getSelectedItem(), first_case.isSelected());
    334                           if(!none_check.isSelected()) {
    335                                 if(and_check.isSelected()) {
    336                                      filter.setOperation(Autofilter.AND);
    337                                 }
    338                                 else {
    339                                      filter.setOperation(Autofilter.OR);
    340                                 }
    341                                 filter.setFilter(2, second_method.getSelectedIndex(), (String)second_value.getSelectedItem(), second_case.isSelected());
    342                           }
    343                      }
    344                      if(order.getSelectedIndex() == 0) {
    345                           filter.setSort(Autofilter.ASCENDING);
    346                      }
    347                      else {
    348                           filter.setSort(Autofilter.DESCENDING);
    349                      }
    350                 }
    351                 else {
    352                      filter = null;
    353                 }
    354                 hide();
    355           }
    356      }
    357      /** Listens for actions on the check box it is attached to, and when notified sets the state of the second method and value to the specified state. */
    358      private final class CheckListener
    359           implements ActionListener {
    360           /** The default desire state any check button this listens to. */
    361           private boolean desired_state = false;
    362           /** The constructor takes an associated desired state.
    363             * @param desired_state The state that should be set when this is actioned, as a <i>boolean</i>.
    364             */
    365           public CheckListener(boolean desired_state) {
    366                 this.desired_state = desired_state;
    367           }
    368           /** Whenever our registered components are actioned apon, set the state of the second method and value to the desired state. */
    369           public void actionPerformed(ActionEvent event) {
    370                 second_method.setEnabled(desired_state);
    371                 second_value.setEnabled(desired_state);
    372           }
    373      }
     365    public CheckListener(boolean desired_state) {
     366        this.desired_state = desired_state;
     367    }
     368    /** Whenever our registered components are actioned apon, set the state of the second method and value to the desired state. */
     369    public void actionPerformed(ActionEvent event) {
     370        second_method.setEnabled(desired_state);
     371        second_value.setEnabled(desired_state);
     372    }
     373    }
    374374}
    375375
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/Filter.java

    r4293 r4366  
    6363 */
    6464public class Filter
    65     implements TableModelFilter {
    66     /** An array of autofilters. */
    67     private Autofilter filters[];
    68     /** The registered TableModelFilterListeners. */
    69     private Vector listeners = new Vector ();
    70     /** Constructor.
    71       * @param columns The number of columns this Filter will be expected to filter, as an <i>int</i>.
     65    implements TableModelFilter {
     66    /** An array of autofilters. */
     67    private Autofilter filters[];
     68    /** The registered TableModelFilterListeners. */
     69    private Vector listeners = new Vector ();
     70    /** Constructor.
     71     * @param columns The number of columns this Filter will be expected to filter, as an <i>int</i>.
    7272      */
    73     public Filter(int columns) {
    74           filters = new Autofilter[columns];
    75     }
    76     /** Add a TableModelFilterListener to the TableModelFilter.
     73    public Filter(int columns) {
     74    filters = new Autofilter[columns];
     75    }
     76    /** Add a TableModelFilterListener to the TableModelFilter.
    7777      * @param listener The <strong>TableModelFilterListener</strong> to add, if it isn't already registered.
    7878      */
    79     public synchronized void addTableModelFilterListener(TableModelFilterListener listener) {
    80           if (!listeners.contains(listener)) {
    81                 listeners.addElement(listener);
    82           }
    83     }
    84     /** Remove a filter from a column.
     79    public synchronized void addTableModelFilterListener(TableModelFilterListener listener) {
     80    if (!listeners.contains(listener)) {
     81        listeners.addElement(listener);
     82    }
     83    }
     84    /** Remove a filter from a column.
    8585      * @param column The column number to remove the filter from, as an <i>int</i>.
    8686      */
    87     public void clearFilter(int column) {
    88           if(filters[column] != null) {
    89                 filters[column].setActive(false);
    90           }
    91     }
    92     /** Determine if a certain row should be shown in the table by checking it against all the current filters.
     87    public void clearFilter(int column) {
     88    if(filters[column] != null) {
     89        filters[column].setActive(false);
     90    }
     91    }
     92    /** Determine if a certain row should be shown in the table by checking it against all the current filters.
    9393      * @param model The <strong>TableModel</strong> the row is from.
    9494      * @param row The row number as an <i>int</i>
    9595      * @return <i>true</i> if the rows data matches all autofilters set and should be displayed, <i>false</i> otherwise.
    9696      */
    97     public boolean filter(TableModel model, int row) {
    98           boolean result = true;
    99           for(int i = 0; result && i < filters.length; i++) {
    100                 if(filters[i] != null && filters[i].active()) {
    101                      ArrayList values = (ArrayList) model.getValueAt(row, i);
    102                      result = result && filters[i].filter(values);
    103                 }
    104           }
    105           return result;
    106     }
    107     /** Retrieve the autofilter associated with a certain column.
     97    public boolean filter(TableModel model, int row) {
     98    boolean result = true;
     99    for(int i = 0; result && i < filters.length; i++) {
     100        if(filters[i] != null && filters[i].active()) {
     101        ArrayList values = (ArrayList) model.getValueAt(row, i);
     102        result = result && filters[i].filter(values);
     103        }
     104    }
     105    return result;
     106    }
     107    /** Retrieve the autofilter associated with a certain column.
    108108      * @param column The column number as an <i>int</i>.
    109109      * @return The <strong>Autofilter</strong> assigned to that column.
    110110      */
    111     public Autofilter getFilter(int column) {
    112           Autofilter filter = filters[column];
    113           if(filter == null) {
    114                 filter = new Autofilter();
    115                 filters[column] = filter;
    116           }
    117           return filter;
    118     }
    119     /** Determine if a certain column is filtered.
     111    public Autofilter getFilter(int column) {
     112    Autofilter filter = filters[column];
     113    if(filter == null) {
     114        filter = new Autofilter();
     115        filters[column] = filter;
     116    }
     117    return filter;
     118    }
     119    /** Determine if a certain column is filtered.
    120120      * @param column The column number as an <i>int</i>.
    121121      * @return <i>true</i> if there is an active autofilter assigned to this column, <i>false</i> otherwise.
    122122      */
    123     public boolean isFiltered(int column) {
    124           boolean result = false;
    125           if(filters[column] != null) {
    126                 result = filters[column].active();
    127           }
    128           return result;
    129     }
    130     /** Remove a TableModelFilterListener from the TableModelFilter.
     123    public boolean isFiltered(int column) {
     124    boolean result = false;
     125    if(filters[column] != null) {
     126        result = filters[column].active();
     127    }
     128    return result;
     129    }
     130    /** Remove a TableModelFilterListener from the TableModelFilter.
    131131      * @param listener The <strong>TableModelFilterListener</strong> to remove.
    132132      */
    133     public synchronized  void removeTableModelFilterListener(TableModelFilterListener listener) {
    134           listeners.removeElement(listener);
    135     }
    136     /** Called whenever the filters assigned changes significantly, thus prompting a reload of the table model data. */
    137     public void fireFilterChanged() {
    138           ///ystem.err.println("Filter Changed!");
    139           Vector tmp;
    140           synchronized(this) {
    141                 tmp = (Vector) listeners.clone();
    142           }
     133    public synchronized  void removeTableModelFilterListener(TableModelFilterListener listener) {
     134    listeners.removeElement(listener);
     135    }
     136    /** Called whenever the filters assigned changes significantly, thus prompting a reload of the table model data. */
     137    public void fireFilterChanged() {
     138    ///ystem.err.println("Filter Changed!");
     139    Vector tmp;
     140    synchronized(this) {
     141        tmp = (Vector) listeners.clone();
     142    }
    143143         
    144           TableModelFilterEvent event = new TableModelFilterEvent (this);
    145           for (Enumeration enum = tmp.elements();
    146                 enum.hasMoreElements(); ) {
    147                 ((TableModelFilterListener)enum.nextElement()).filterChanged(event);
    148           }
    149     }
     144    TableModelFilterEvent event = new TableModelFilterEvent (this);
     145    for (Enumeration enum = tmp.elements();
     146        enum.hasMoreElements(); ) {
     147        ((TableModelFilterListener)enum.nextElement()).filterChanged(event);
     148    }
     149    }
    150150}
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java

    r4293 r4366  
    6060
    6161public class HeaderListener
    62     extends MouseAdapter {
    63     private MetaAuditFrame parent_frame;
    64     private MetaAuditTable table;
    65     public HeaderListener(MetaAuditFrame parent_frame, MetaAuditTable table) {
    66           this.parent_frame = parent_frame;
    67           this.table = table;
    68     }
     62    extends MouseAdapter {
     63    private MetaAuditFrame parent_frame;
     64    private MetaAuditTable table;
     65    public HeaderListener(MetaAuditFrame parent_frame, MetaAuditTable table) {
     66    this.parent_frame = parent_frame;
     67    this.table = table;
     68    }
    6969
    70     public void mouseClicked(MouseEvent event) {
    71           // Determine the column this was clicked on.
    72           int column = table.getColumnModel().getColumnIndexAtX(event.getX());
    73           int clicked_column = table.convertColumnIndexToModel(column);
    74           // Display the currently assigned filter.
    75           Filter filter_model = table.getFilter();
    76           Autofilter filter = filter_model.getFilter(clicked_column);
    77           MetaAuditModel model = table.getOriginalModel();
    78           ArrayList default_values = model.getColumnValues(clicked_column);
    79           String column_name = model.getColumnName(clicked_column);
    80           filter = parent_frame.autofilter_dialog.display(filter, default_values, column_name);
    81           if(filter == null) {
    82                 filter_model.clearFilter(clicked_column);
    83           }
    84           else {
    85                 filter.setActive(true);
    86                 TableModelSorter sorter = table.getSorter();
    87                 sorter.setSortColumn(clicked_column);
    88                 sorter.setSortAscending(filter.sort);
    89           }
    90           filter_model.fireFilterChanged();
    91     }
     70    public void mouseClicked(MouseEvent event) {
     71    // Determine the column this was clicked on.
     72    int column = table.getColumnModel().getColumnIndexAtX(event.getX());
     73    int clicked_column = table.convertColumnIndexToModel(column);
     74    // Display the currently assigned filter.
     75    Filter filter_model = table.getFilter();
     76    Autofilter filter = filter_model.getFilter(clicked_column);
     77    MetaAuditModel model = table.getOriginalModel();
     78    ArrayList default_values = model.getColumnValues(clicked_column);
     79    String column_name = model.getColumnName(clicked_column);
     80    filter = parent_frame.autofilter_dialog.display(filter, default_values, column_name);
     81    if(filter == null) {
     82        filter_model.clearFilter(clicked_column);
     83    }
     84    else {
     85        filter.setActive(true);
     86        TableModelSorter sorter = table.getSorter();
     87        sorter.setSortColumn(clicked_column);
     88        sorter.setSortAscending(filter.sort);
     89    }
     90    filter_model.fireFilterChanged();
     91    }
    9292}
    9393
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderRenderer.java

    r4293 r4366  
    4747 */
    4848public class HeaderRenderer
    49     extends JToggleButton
    50     implements TableCellRenderer {
    51     /** The constructor sets up a margin around the button, and adds the filter icons.
    52       * @see org.greenstone.gatherer.util.Utility
    53       */
    54     public HeaderRenderer() {
    55           setMargin(new Insets(0,0,0,0));
    56           setIcon(Utility.getImage("filter.gif"));
    57           setSelectedIcon(Utility.getImage("filter-on.gif"));
    58     }
    59     /** Called to create the component to be used as the 'rubber-stamp' for the table cell given the follwing arguments.
     49    extends JToggleButton
     50    implements TableCellRenderer {
     51    /** The constructor sets up a margin around the button, and adds the filter icons.
     52     * @see org.greenstone.gatherer.util.Utility
     53     */
     54    public HeaderRenderer() {
     55    setMargin(new Insets(0,0,0,0));
     56    setIcon(Utility.getImage("filter.gif"));
     57    setSelectedIcon(Utility.getImage("filter-on.gif"));
     58    }
     59    /** Called to create the component to be used as the 'rubber-stamp' for the table cell given the follwing arguments.
    6060      * @param table The <strong>JTable</strong> that is asking the renderer to draw; can be <i>null</i>.
    6161      * @param value The value of the cell to be rendered as an <strong>Object</strong>. It is up to the specific renderer to interpret and draw the value. For example, if value is the string "true", it could be rendered as a string or it could be rendered as a check box that is checked. null is a valid value.
     
    6666      * @see org.greenstone.gatherer.gui.metaaudit.MetaAuditTable
    6767      */
    68     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    69           setText(value.toString());
    70           MetaAuditTable temp = (MetaAuditTable) table;
    71           if(temp != null) { // And it may if this is called during table init.
    72                 setSelected(temp.isFiltered(column));
    73           }
    74           return this;
    75     }
     68    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     69    setText(value.toString());
     70    MetaAuditTable temp = (MetaAuditTable) table;
     71    if(temp != null) { // And it may if this is called during table init.
     72        setSelected(temp.isFiltered(column));
     73    }
     74    return this;
     75    }
    7676}
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditFrame.java

    r4293 r4366  
    7878 */
    7979public class MetaAuditFrame
    80     extends JDialog
    81     implements TreeSelectionListener {
    82     public AutofilterDialog autofilter_dialog;
    83     /** Whether the selection has changed since the last time we built the model (because it has been hidden and theres no point refreshing a model you can't see!). */
    84     private boolean invalid = true;
    85     /** An array holding the most recent list of paths selected (plus some nulls for those paths removed). */
    86     private FileNode records[];
    87     /** A reference to ourselves so that inner classes can interact with us. */
    88     private MetaAuditFrame self;
    89     /** The table in which the metadata is shown. */
    90     private MetaAuditTable table;
    91     /** The default size for the metaaudit dialog. */
    92     static final private Dimension SIZE = new Dimension(640,480);
    93     /** The tolerance used to determine between a column resize, and a request for an AutoFilterDialog. */
    94     static final private int TOLERANCE = 3;
    95     /** Constructor.*/
    96     public MetaAuditFrame(TreeSynchronizer tree_sync, FileNode records[]) {
    97           super();
    98           // Arguments
    99           this.autofilter_dialog = new AutofilterDialog(this);
    100           this.records = records;
    101           this.self = this;
    102           this.table = new MetaAuditTable(this);
    103           // Creation
    104           setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
    105           setSize(SIZE);
    106           setTitle(get("Title"));
    107 
    108           JPanel content_pane = (JPanel) getContentPane();
    109           JPanel button_pane = new JPanel();
    110 
    111           JButton close_button = new JButton(get("Close"));
    112           close_button.setMnemonic(KeyEvent.VK_C);
    113           // Connection
    114           close_button.addActionListener(new CloseListener());
    115           tree_sync.addTreeSelectionListener(this);
    116           // Layout
    117           button_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    118           button_pane.setLayout(new BorderLayout());
    119           button_pane.add(close_button, BorderLayout.CENTER);
     80    extends JDialog
     81    implements TreeSelectionListener {
     82    public AutofilterDialog autofilter_dialog;
     83    /** Whether the selection has changed since the last time we built the model (because it has been hidden and theres no point refreshing a model you can't see!). */
     84    private boolean invalid = true;
     85    /** An array holding the most recent list of paths selected (plus some nulls for those paths removed). */
     86    private FileNode records[];
     87    /** A reference to ourselves so that inner classes can interact with us. */
     88    private MetaAuditFrame self;
     89    /** The table in which the metadata is shown. */
     90    private MetaAuditTable table;
     91    /** The default size for the metaaudit dialog. */
     92    static final private Dimension SIZE = new Dimension(640,480);
     93    /** The tolerance used to determine between a column resize, and a request for an AutoFilterDialog. */
     94    static final private int TOLERANCE = 3;
     95    /** Constructor.*/
     96    public MetaAuditFrame(TreeSynchronizer tree_sync, FileNode records[]) {
     97    super();
     98    // Arguments
     99    this.autofilter_dialog = new AutofilterDialog(this);
     100    this.records = records;
     101    this.self = this;
     102    this.table = new MetaAuditTable(this);
     103    // Creation
     104    setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
     105    setSize(SIZE);
     106    setTitle(get("Title"));
     107
     108    JPanel content_pane = (JPanel) getContentPane();
     109    JPanel button_pane = new JPanel();
     110
     111    JButton close_button = new JButton(get("Close"));
     112    close_button.setMnemonic(KeyEvent.VK_C);
     113    // Connection
     114    close_button.addActionListener(new CloseListener());
     115    tree_sync.addTreeSelectionListener(this);
     116    // Layout
     117    button_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     118    button_pane.setLayout(new BorderLayout());
     119    button_pane.add(close_button, BorderLayout.CENTER);
    120120         
    121           content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    122           content_pane.setLayout(new BorderLayout());
    123           content_pane.add(new JScrollPane(table), BorderLayout.CENTER);
    124           content_pane.add(button_pane, BorderLayout.SOUTH);
     121    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     122    content_pane.setLayout(new BorderLayout());
     123    content_pane.add(new JScrollPane(table), BorderLayout.CENTER);
     124    content_pane.add(button_pane, BorderLayout.SOUTH);
    125125         
    126           Dimension screen_size = Gatherer.config.screen_size;
    127           setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
    128           screen_size = null;
    129           close_button = null;
    130           button_pane = null;
    131           content_pane = null;
    132     }
    133     /** Destructor. */
    134     public void destroy() {
    135           records = null;
    136           self = null;
    137           table = null;
    138     }
    139     /** Display the dialog on screen. */
    140     public void display() {
    141           if(invalid) {
    142                 rebuildModel();
    143           }
    144           show();
    145     }
    146     /** This method is called whenever the selection within the collection tree changes. This causes the table to be rebuilt with a new model.
    147       * @param event A <strong>TreeSelectionEvent</strong> containing information about the event.
    148       */
    149     public void valueChanged(TreeSelectionEvent event) {
    150           if(event.getSource() instanceof JTree) {
    151                 TreePath paths[] = Gatherer.g_man.metaedit_pane.collection_tree.getSelectionPaths();
    152                 if(paths != null) {
    153                      records = new FileNode[paths.length];
    154                      for(int i = 0; i < paths.length; i++) {
    155                           records[i] = (FileNode) paths[i].getLastPathComponent();
    156                      }
    157                      if(isVisible()) {
    158                           rebuildModel();
    159                      }
    160                      else {
    161                           invalid = true;
    162                      }
    163                 }
    164           }
    165     }
    166 
    167     public void wait(boolean waiting) {
    168           Component glass_pane = getGlassPane();
    169           if(waiting) {
     126    Dimension screen_size = Gatherer.config.screen_size;
     127    setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
     128    screen_size = null;
     129    close_button = null;
     130    button_pane = null;
     131    content_pane = null;
     132    }
     133    /** Destructor. */
     134    public void destroy() {
     135    records = null;
     136    self = null;
     137    table = null;
     138    }
     139    /** Display the dialog on screen. */
     140    public void display() {
     141    if(invalid) {
     142        rebuildModel();
     143    }
     144    show();
     145    }
     146    /** This method is called whenever the selection within the collection tree changes. This causes the table to be rebuilt with a new model.
     147     * @param event A <strong>TreeSelectionEvent</strong> containing information about the event.
     148     */
     149    public void valueChanged(TreeSelectionEvent event) {
     150    if(event.getSource() instanceof JTree) {
     151        TreePath paths[] = Gatherer.g_man.metaedit_pane.collection_tree.getSelectionPaths();
     152        if(paths != null) {
     153        records = new FileNode[paths.length];
     154        for(int i = 0; i < paths.length; i++) {
     155            records[i] = (FileNode) paths[i].getLastPathComponent();
     156        }
     157        if(isVisible()) {
     158            rebuildModel();
     159        }
     160        else {
     161            invalid = true;
     162        }
     163        }
     164    }
     165    }
     166
     167    public void wait(boolean waiting) {
     168    Component glass_pane = getGlassPane();
     169    if(waiting) {
    170170                // Show wait cursor.
    171                 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    172                 glass_pane.setVisible(true);
    173           }
    174           else {
     171        glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
     172        glass_pane.setVisible(true);
     173    }
     174    else {
    175175                // Hide wait cursor.
    176                 glass_pane.setVisible(false);
    177                 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    178           }
    179           glass_pane = null;
    180     }
    181 
    182     /** Retrieve a phrase from the Dictionary.
    183       * @param key A <strong>String</strong> which uniquely maps to a phrase.
    184       * @return The desired phrase as a </strong>String</strong>.
    185       * @see org.greenstone.gatherer.Dictionary
    186       */
    187     private String get(String key) {
    188           return Gatherer.dictionary.get("MetaAudit." + key);
    189     }
    190     /** Rebuild the metaaudit table model using the current collection tree selection.
    191       */
    192     private void rebuildModel() {
    193           // Build and set model
    194           table.newModel(records);
    195           // Done.
    196           invalid = false;
    197     }
    198     /** Listens for actions apon the close button, and if detected closes the dialog (storing its current size first). */
    199     private class CloseListener
    200           implements ActionListener {
    201           /** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on our target control(s).
    202             * @param event An <strong>ActionEvent</strong> containing information about the event.
    203             */
    204           public void actionPerformed(ActionEvent event) {
    205                 self.hide();
    206           }
    207     }
     176        glass_pane.setVisible(false);
     177        glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
     178    }
     179    glass_pane = null;
     180    }
     181
     182    /** Retrieve a phrase from the Dictionary.
     183     * @param key A <strong>String</strong> which uniquely maps to a phrase.
     184     * @return The desired phrase as a </strong>String</strong>.
     185     * @see org.greenstone.gatherer.Dictionary
     186     */
     187    private String get(String key) {
     188    return Gatherer.dictionary.get("MetaAudit." + key);
     189    }
     190    /** Rebuild the metaaudit table model using the current collection tree selection.
     191     */
     192    private void rebuildModel() {
     193    // Build and set model
     194    table.newModel(records);
     195    // Done.
     196    invalid = false;
     197    }
     198    /** Listens for actions apon the close button, and if detected closes the dialog (storing its current size first). */
     199    private class CloseListener
     200    implements ActionListener {
     201    /** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on our target control(s).
     202     * @param event An <strong>ActionEvent</strong> containing information about the event.
     203     */
     204    public void actionPerformed(ActionEvent event) {
     205        self.hide();
     206    }
     207    }
    208208}
    209209     
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditModel.java

    r4293 r4366  
    5151 */
    5252public class MetaAuditModel
    53     extends AbstractTableModel {
     53    extends AbstractTableModel {
    5454
    55     private ArrayList elements;
    56     private MetadataTableCache data;
     55    private ArrayList elements;
     56    private MetadataTableCache data;
    5757
    58     public MetaAuditModel(FileNode records[]) {
    59           this.elements = new ArrayList(Gatherer.c_man.getCollection().msm.getElements());
    60           Collections.sort(this.elements);
    61           this.data = new MetadataTableCache(elements.size() + 1);
    62           // Work our way through the record array provided, adding files, skipping blanks and recursively searching directories.
    63           for(int i = 0; records != null && i < records.length; i++) {
    64                 if(records[i] != null) {
    65                      addRecord(records[i]);
    66                 }
    67           }
    68     }
    69     public Class getColumnClass(int column) {
    70           return ArrayList.class;
    71     }
    72     public int getColumnCount() {
    73           return elements.size() + 1;
    74     }
    75     public String getColumnName(int column) {
    76           String result;
    77           if(column == 0) {
    78                 result = Gatherer.dictionary.get("AuditTable.File");
    79           }
    80           else {
    81                 result = elements.get(column - 1).toString();
    82           }
    83           return result;
    84     }
    85     public ArrayList getColumnValues(int column) {
    86           ArrayList column_values = new ArrayList();
    87           if(0 <= column && column < getColumnCount()) {
    88                 for(int i = 0; i < data.size(); i++) {
    89                      ArrayList values = (ArrayList) data.get(i, column);
    90                      for(int j = 0; j < values.size(); j++) {
    91                           column_values.add(values.get(j).toString());
    92                      }
    93                 }
    94           }
    95           return column_values;
    96     }
    97     public int getRowCount() {
    98           return data.size();
    99     }
    100     public Object getValueAt(int row, int column) {
    101           Object result = "";
    102           if(0 <= row && row < data.size() && 0 <= column && column < elements.size() + 1) {
    103                 result = data.get(row, column);
    104           }
    105           return result;
    106     }
     58    public MetaAuditModel(FileNode records[]) {
     59    this.elements = new ArrayList(Gatherer.c_man.getCollection().msm.getElements());
     60    Collections.sort(this.elements);
     61    this.data = new MetadataTableCache(elements.size() + 1);
     62    // Work our way through the record array provided, adding files, skipping blanks and recursively searching directories.
     63    for(int i = 0; records != null && i < records.length; i++) {
     64        if(records[i] != null) {
     65        addRecord(records[i]);
     66        }
     67    }
     68    }
     69    public Class getColumnClass(int column) {
     70    return ArrayList.class;
     71    }
     72    public int getColumnCount() {
     73    return elements.size() + 1;
     74    }
     75    public String getColumnName(int column) {
     76    String result;
     77    if(column == 0) {
     78        result = Gatherer.dictionary.get("AuditTable.File");
     79    }
     80    else {
     81        result = elements.get(column - 1).toString();
     82    }
     83    return result;
     84    }
     85    public ArrayList getColumnValues(int column) {
     86    ArrayList column_values = new ArrayList();
     87    if(0 <= column && column < getColumnCount()) {
     88        for(int i = 0; i < data.size(); i++) {
     89        ArrayList values = (ArrayList) data.get(i, column);
     90        for(int j = 0; j < values.size(); j++) {
     91            column_values.add(values.get(j).toString());
     92        }
     93        }
     94    }
     95    return column_values;
     96    }
     97    public int getRowCount() {
     98    return data.size();
     99    }
     100    public Object getValueAt(int row, int column) {
     101    Object result = "";
     102    if(0 <= row && row < data.size() && 0 <= column && column < elements.size() + 1) {
     103        result = data.get(row, column);
     104    }
     105    return result;
     106    }
    107107
    108     public void reset() {
    109     }
     108    public void reset() {
     109    }
    110110
    111     private void addRecord(FileNode record) {
    112           if(record.isLeaf()) {
    113                 File file = record.getFile();
    114                 data.newRow();
    115                 data.put(0, file.getName());
    116                 ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getMetadata(file);
    117                 for(int i = 0; i < metadatum.size(); i++) {
    118                      Metadata metadata = (Metadata) metadatum.get(i);
    119                      data.put(elements.indexOf(metadata.getElement()) + 1, metadata.getValueNode());
    120                 }
    121           }
    122           else {
    123                 for(int i = 0; i < record.getChildCount(); i++) {
    124                      addRecord((FileNode)record.getChildAt(i));
    125                 }
    126           }
    127     }
     111    private void addRecord(FileNode record) {
     112    if(record.isLeaf()) {
     113        File file = record.getFile();
     114        data.newRow();
     115        data.put(0, file.getName());
     116        ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getMetadata(file);
     117        for(int i = 0; i < metadatum.size(); i++) {
     118        Metadata metadata = (Metadata) metadatum.get(i);
     119        data.put(elements.indexOf(metadata.getElement()) + 1, metadata.getValueNode());
     120        }
     121    }
     122    else {
     123        for(int i = 0; i < record.getChildCount(); i++) {
     124        addRecord((FileNode)record.getChildAt(i));
     125        }
     126    }
     127    }
    128128
    129     private class MetadataTableCache {
    130           private ArrayList data;
    131           private ArrayList current_row[];
    132           private int columns;
    133           private RowComparator row_comparator = new RowComparator();
    134           public MetadataTableCache(int columns) {
    135                 this.columns = columns;
    136                 this.data = new ArrayList();
    137           }
     129    private class MetadataTableCache {
     130    private ArrayList data;
     131    private ArrayList current_row[];
     132    private int columns;
     133    private RowComparator row_comparator = new RowComparator();
     134    public MetadataTableCache(int columns) {
     135        this.columns = columns;
     136        this.data = new ArrayList();
     137    }
    138138
    139           public ArrayList get(int row, int column) {
    140                 ArrayList array_list[] = (ArrayList[]) data.get(row);
    141                 return array_list[column];
    142           }
     139    public ArrayList get(int row, int column) {
     140        ArrayList array_list[] = (ArrayList[]) data.get(row);
     141        return array_list[column];
     142    }
    143143
    144           public void newRow() {
    145                 if(current_row != null) {
    146                      for(int i = 0; i < columns; i++) {
    147                           Collections.sort(current_row[i], row_comparator);
    148                      }
    149                 }
    150                 current_row = new ArrayList[columns];
    151                 for(int i = 0; i < columns; i++) {
    152                      current_row[i] = new ArrayList();
    153                 }
    154                 data.add(current_row);
    155           }
     144    public void newRow() {
     145        if(current_row != null) {
     146        for(int i = 0; i < columns; i++) {
     147            Collections.sort(current_row[i], row_comparator);
     148        }
     149        }
     150        current_row = new ArrayList[columns];
     151        for(int i = 0; i < columns; i++) {
     152        current_row[i] = new ArrayList();
     153        }
     154        data.add(current_row);
     155    }
    156156
    157           public void put(int column, Object value) {
    158                 current_row[column].add(value);
    159           }
     157    public void put(int column, Object value) {
     158        current_row[column].add(value);
     159    }
    160160
    161           public int size() {
    162                 return data.size();
    163           }
    164     }
     161    public int size() {
     162        return data.size();
     163    }
     164    }
    165165
    166     private class RowComparator
    167           implements Comparator {
    168           public int compare(Object o1, Object o2) {
    169                 return o1.toString().compareTo(o2.toString());
    170           }
    171           public boolean equals(Object obj) {
    172                 return toString().equals(obj.toString());
    173           }
    174     }
     166    private class RowComparator
     167    implements Comparator {
     168    public int compare(Object o1, Object o2) {
     169        return o1.toString().compareTo(o2.toString());
     170    }
     171    public boolean equals(Object obj) {
     172        return toString().equals(obj.toString());
     173    }
     174    }
    175175}
    176176
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditRenderer.java

    r4293 r4366  
    5252
    5353public class MetaAuditRenderer
    54     extends DefaultTableCellRenderer {
     54    extends DefaultTableCellRenderer {
    5555
    56     public Component getTableCellRendererComponent(JTable table, Object value, boolean is_selected, boolean has_focus, int row, int column) {
    57           ArrayList array = (ArrayList) value;
    58           JLabel label = (JLabel) super.getTableCellRendererComponent(table, "", is_selected, has_focus, row, column);
    59           JPanel panel = new JPanel();
    60           panel.setBackground(label.getBackground());
    61           panel.setBorder(label.getBorder());
    62           if(array != null) {
    63                 panel.setLayout(new GridLayout(array.size(), 1));
    64                 for(int i = 0; i < array.size(); i++) {
    65                      JLabel entry = new JLabel(array.get(i).toString());
    66                      entry.setFont(label.getFont());
    67                      panel.add(entry);
    68                 }
    69           }
    70           return panel;
    71     }
     56    public Component getTableCellRendererComponent(JTable table, Object value, boolean is_selected, boolean has_focus, int row, int column) {
     57    ArrayList array = (ArrayList) value;
     58    JLabel label = (JLabel) super.getTableCellRendererComponent(table, "", is_selected, has_focus, row, column);
     59    JPanel panel = new JPanel();
     60    panel.setBackground(label.getBackground());
     61    panel.setBorder(label.getBorder());
     62    if(array != null) {
     63        panel.setLayout(new GridLayout(array.size(), 1));
     64        for(int i = 0; i < array.size(); i++) {
     65        JLabel entry = new JLabel(array.get(i).toString());
     66        entry.setFont(label.getFont());
     67        panel.add(entry);
     68        }
     69    }
     70    return panel;
     71    }
    7272}
  • trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java

    r4293 r4366  
    5555 */
    5656public class MetaAuditTable
    57     extends JTable
    58     implements TableModelSorterListener {
    59 
    60     private boolean initial_state;
    61 
    62     private boolean ready;
    63 
    64     private Filter filter;
    65 
    66     private HeaderRenderer header_renderer;
    67 
    68     private MetaAuditFrame parent_frame;
    69 
    70     private MetaAuditModel model;
    71 
    72     private SortedTableHelper helper;
    73 
    74     static final private int MARGIN = 10;
    75 
    76     public MetaAuditTable(MetaAuditFrame parent_frame) {
    77           super();
    78           this.header_renderer = new HeaderRenderer();
    79           this.parent_frame = parent_frame;
    80           getTableHeader().addMouseListener(new HeaderListener(parent_frame, this));
    81           setAutoResizeMode(AUTO_RESIZE_OFF);
    82           setDefaultRenderer(ArrayList.class, new MetaAuditRenderer());
    83           ready = true;
    84     }
    85 
    86     public Filter getFilter() {
    87           return filter;
    88     }
    89 
    90     public MetaAuditModel getOriginalModel() {
    91           return model;
    92     }
    93 
    94     public TableModelSorter getSorter() {
    95           return helper.getTableModelSorter();
    96     }
    97 
    98     public boolean isFiltered(int column) {
    99           if(filter == null) {
    100                 return false;
    101           }
    102           return filter.isFiltered(column);
    103     }
    104 
    105     public void newModel(FileNode records[]) {
    106           if(records == null || records.length == 0) {
    107                 return;
    108           }
    109           wait(true);
    110           initial_state = true;
    111           ///ystem.err.println("Build new Model - should only be called once per click!");
    112           model = new MetaAuditModel(records);
    113           setModel(model);
    114           filter = new Filter(model.getColumnCount());
    115           helper = new SortedTableHelper (this, filter, new DefaultTableModelSorter(), header_renderer, null);
    116           helper.prepareTable();
    117           // Add renderer to columns.
    118           TableColumnModel column_model = getColumnModel();
    119           for(int i = 0; i < column_model.getColumnCount(); i++) {
    120                 column_model.getColumn(i).setHeaderRenderer(header_renderer);
    121           }
    122           wait(false);
    123           initial_state = false;
    124     }
    125 
    126     public void tableChanged(TableModelEvent e) {
    127           wait(true);
    128           super.tableChanged(e);
    129           if(ready) {
     57    extends JTable
     58    implements TableModelSorterListener {
     59
     60    private boolean initial_state;
     61
     62    private boolean ready;
     63
     64    private Filter filter;
     65
     66    private HeaderRenderer header_renderer;
     67
     68    private MetaAuditFrame parent_frame;
     69
     70    private MetaAuditModel model;
     71
     72    private SortedTableHelper helper;
     73
     74    static final private int MARGIN = 10;
     75
     76    public MetaAuditTable(MetaAuditFrame parent_frame) {
     77    super();
     78    this.header_renderer = new HeaderRenderer();
     79    this.parent_frame = parent_frame;
     80    getTableHeader().addMouseListener(new HeaderListener(parent_frame, this));
     81    setAutoResizeMode(AUTO_RESIZE_OFF);
     82    setDefaultRenderer(ArrayList.class, new MetaAuditRenderer());
     83    ready = true;
     84    }
     85
     86    public Filter getFilter() {
     87    return filter;
     88    }
     89
     90    public MetaAuditModel getOriginalModel() {
     91    return model;
     92    }
     93
     94    public TableModelSorter getSorter() {
     95    return helper.getTableModelSorter();
     96    }
     97
     98    public boolean isFiltered(int column) {
     99    if(filter == null) {
     100        return false;
     101    }
     102    return filter.isFiltered(column);
     103    }
     104
     105    public void newModel(FileNode records[]) {
     106    if(records == null || records.length == 0) {
     107        return;
     108    }
     109    wait(true);
     110    initial_state = true;
     111    ///ystem.err.println("Build new Model - should only be called once per click!");
     112    model = new MetaAuditModel(records);
     113    setModel(model);
     114    filter = new Filter(model.getColumnCount());
     115    helper = new SortedTableHelper (this, filter, new DefaultTableModelSorter(), header_renderer, null);
     116    helper.prepareTable();
     117    // Add renderer to columns.
     118    TableColumnModel column_model = getColumnModel();
     119    for(int i = 0; i < column_model.getColumnCount(); i++) {
     120        column_model.getColumn(i).setHeaderRenderer(header_renderer);
     121    }
     122    wait(false);
     123    initial_state = false;
     124    }
     125
     126    public void tableChanged(TableModelEvent e) {
     127    wait(true);
     128    super.tableChanged(e);
     129    if(ready) {
    130130                // Create storage area
    131                 ArrayList heights[] = new ArrayList[dataModel.getRowCount()];
    132                 int widths_value[] = new int[dataModel.getColumnCount()];
    133                ArrayList widths[] = new ArrayList[dataModel.getColumnCount()];
     131        ArrayList heights[] = new ArrayList[dataModel.getRowCount()];
     132        int widths_value[] = new int[dataModel.getColumnCount()];
     133        ArrayList widths[] = new ArrayList[dataModel.getColumnCount()];
    134134                // Iterate through cell values finding tallest and widest for each row and column respectively.
    135                 for(int j = 0; j < dataModel.getRowCount(); j++) {
    136                      for(int k = 0; k < dataModel.getColumnCount(); k++) {
    137                           Object object = dataModel.getValueAt(j, k);
    138                           if(object instanceof ArrayList) {
    139                                 ArrayList data = (ArrayList) object;
    140                                 if(heights[j] == null || data.size() > heights[j].size()) {
    141                                     heights[j] = data;
    142                                 }
    143                                 String longest = "";
    144                                 for(int i = 0; i < data.size(); i++) {
    145                                     String temp = data.get(i).toString();
    146                                     if(temp.length() > longest.length()) {
    147                                           longest = temp;
    148                                     }
    149                                     temp = null;
    150                                 }
    151                                 if(widths[k] == null || longest.length() > widths_value[k]) {
    152                                     widths_value[k] = longest.length();
    153                                     widths[k] = data;
    154                                 }
    155                                 longest = null;
    156                                 data = null;
    157                           }
    158                      }
    159                 }
     135        for(int j = 0; j < dataModel.getRowCount(); j++) {
     136        for(int k = 0; k < dataModel.getColumnCount(); k++) {
     137            Object object = dataModel.getValueAt(j, k);
     138            if(object instanceof ArrayList) {
     139            ArrayList data = (ArrayList) object;
     140            if(heights[j] == null || data.size() > heights[j].size()) {
     141                heights[j] = data;
     142            }
     143            String longest = "";
     144            for(int i = 0; i < data.size(); i++) {
     145                String temp = data.get(i).toString();
     146                if(temp.length() > longest.length()) {
     147                longest = temp;
     148                }
     149                temp = null;
     150            }
     151            if(widths[k] == null || longest.length() > widths_value[k]) {
     152                widths_value[k] = longest.length();
     153                widths[k] = data;
     154            }
     155            longest = null;
     156            data = null;
     157            }
     158        }
     159        }
    160160                // Now assign the dimensions we have determined to be the largest.
    161                 TableCellRenderer renderer = getDefaultRenderer(ArrayList.class);
    162                 for(int l = 0; l < heights.length; l++) {
    163                      if(heights[l] != null) {
    164                           Component component = renderer.getTableCellRendererComponent(this, heights[l], false, false, 0, 0);
    165                           Dimension size = component.getPreferredSize();
    166                           setRowHeight(l, size.height);
    167                           size = null;
    168                           component = null;
    169                      }
    170                 }
    171                 heights = null;
    172                 for(int m = 0; m < widths.length; m++) {
    173                      if(widths[m] != null) {
    174                           Component component = renderer.getTableCellRendererComponent(this, widths[m], false, false, 0, 0);
    175                           Dimension size = component.getPreferredSize();
    176                           int width = size.width + MARGIN;
    177                           if(width > (2 * parent_frame.getSize().width) / 3) {
    178                                 width = (2 * parent_frame.getSize().width) / 3;
    179                           }
    180                           Component header = header_renderer.getTableCellRendererComponent(this, dataModel.getColumnName(m), false, false, 0, 0);
    181                           if(header.getPreferredSize().width + MARGIN > width) {
    182                                 width = header.getPreferredSize().width + MARGIN;
    183                           }
    184                           columnModel.getColumn(m).setPreferredWidth(width);
    185                           size = null;
    186                           component = null;
    187                      }
    188                 }
    189                 widths = null;
    190                 renderer = null;
    191           }
    192           wait(initial_state);
    193     }
    194 
    195     public void sortOrderChanged(TableModelSorterEvent event) {
    196     }
    197 
    198     private void wait(boolean waiting) {
    199           if(parent_frame != null) {
    200                 parent_frame.wait(waiting);
    201           }
    202     }
     161        TableCellRenderer renderer = getDefaultRenderer(ArrayList.class);
     162        for(int l = 0; l < heights.length; l++) {
     163        if(heights[l] != null) {
     164            Component component = renderer.getTableCellRendererComponent(this, heights[l], false, false, 0, 0);
     165            Dimension size = component.getPreferredSize();
     166            setRowHeight(l, size.height);
     167            size = null;
     168            component = null;
     169        }
     170        }
     171        heights = null;
     172        for(int m = 0; m < widths.length; m++) {
     173        if(widths[m] != null) {
     174            Component component = renderer.getTableCellRendererComponent(this, widths[m], false, false, 0, 0);
     175            Dimension size = component.getPreferredSize();
     176            int width = size.width + MARGIN;
     177            if(width > (2 * parent_frame.getSize().width) / 3) {
     178            width = (2 * parent_frame.getSize().width) / 3;
     179            }
     180            Component header = header_renderer.getTableCellRendererComponent(this, dataModel.getColumnName(m), false, false, 0, 0);
     181            if(header.getPreferredSize().width + MARGIN > width) {
     182            width = header.getPreferredSize().width + MARGIN;
     183            }
     184            columnModel.getColumn(m).setPreferredWidth(width);
     185            size = null;
     186            component = null;
     187        }
     188        }
     189        widths = null;
     190        renderer = null;
     191    }
     192    wait(initial_state);
     193    }
     194
     195    public void sortOrderChanged(TableModelSorterEvent event) {
     196    }
     197
     198    private void wait(boolean waiting) {
     199    if(parent_frame != null) {
     200        parent_frame.wait(waiting);
     201    }
     202    }
    203203}
    204204
  • trunk/gli/src/org/greenstone/gatherer/gui/table/GTable.java

    r4293 r4366  
    6161
    6262public class GTable
    63     extends JTable {
     63    extends JTable {
    6464     
    65     private boolean building = false;
    66     private JLabel label = null;
    67     public GTable() {
    68           // First draw the background image - tiled
    69           label = new JLabel("<HTML><FONT SIZE=5>Building Collection</FONT></HTML>");
    70           //label.setHorizontalAlignment(JLabel.CENTER);
    71           //label.setVerticalAlignment(JLabel.CENTER);
    72           //label.setSize(new Dimension(505, 200));
    73     }
     65    private boolean building = false;
     66    private JLabel label = null;
     67    public GTable() {
     68    // First draw the background image - tiled
     69    label = new JLabel("<HTML><FONT SIZE=5>Building Collection</FONT></HTML>");
     70    //label.setHorizontalAlignment(JLabel.CENTER);
     71    //label.setVerticalAlignment(JLabel.CENTER);
     72    //label.setSize(new Dimension(505, 200));
     73    }
    7474     
    75     public synchronized void setBuilding(boolean building) {
    76           this.building = building;
    77           repaint();
    78     }
     75    public synchronized void setBuilding(boolean building) {
     76    this.building = building;
     77    repaint();
     78    }
    7979
    80     public void paint(Graphics g) {
    81           // Now let the regular paint code do it's work
    82           super.paint(g);
    83           //if(building) {
    84                 label.paint(g);
     80    public void paint(Graphics g) {
     81    // Now let the regular paint code do it's work
     82    super.paint(g);
     83    //if(building) {
     84    label.paint(g);
    8585                //}
    86     }   
     86    }   
    8787}
  • trunk/gli/src/org/greenstone/gatherer/gui/table/GTableCellEditor.java

    r4293 r4366  
    5858 */
    5959public class GTableCellEditor
    60     extends DefaultCellEditor {
     60    extends DefaultCellEditor {
    6161
    62     private Gatherer        gatherer      = null;
     62    private Gatherer        gatherer      = null;
    6363
    64     private GComboBox      editor       = null;
     64    private GComboBox      editor       = null;
    6565
    66     private GComboBoxModel editor_model = null;
     66    private GComboBoxModel editor_model = null;
    6767
    68     /** The default constructor simply add the standard new argument, a
    69       * reference to the Gatherer class.
    70       * @param gatherer A reference to Gatherer for communication and dictionary
    71       * purposes.
    72       */
    73     public GTableCellEditor(Gatherer gatherer) {
    74           super(new JTextField());
    75           this.gatherer = gatherer;
    76     }
     68    /** The default constructor simply add the standard new argument, a
     69     * reference to the Gatherer class.
     70     * @param gatherer A reference to Gatherer for communication and dictionary
     71     * purposes.
     72     */
     73    public GTableCellEditor(Gatherer gatherer) {
     74    super(new JTextField());
     75    this.gatherer = gatherer;
     76    }
    7777
    78     /** This method returns the currently selected value of our editor
    79       * GCombobox.
    80       * @return An Object which is the selected items value.
    81       */
    82     public Object getCellEditorValue() {
    83           return editor.getSelectedItem();
    84     }
     78    /** This method returns the currently selected value of our editor
     79     * GCombobox.
     80     * @return An Object which is the selected items value.
     81     */
     82    public Object getCellEditorValue() {
     83    return editor.getSelectedItem();
     84    }
    8585
    86     /** Returns a reference to the editor GComboBox.
    87       * @return A Component reference to our editor.
    88       */
    89     public Component getComponent() {
    90           return editor;
    91     }
     86    /** Returns a reference to the editor GComboBox.
     87     * @return A Component reference to our editor.
     88     */
     89    public Component getComponent() {
     90    return editor;
     91    }
    9292
    93     /** This method is called to retrieve the correct editor component for
    94       * a certain row and column within the target JTable. It is here that
    95       * we create the custom GComboBox for each row of the 'values' column
    96       * using a different model for each. If the call comes from any other
    97       * column (which it shouldn't but what the hell) we let the super
    98       * handle it which returns a plain old JTextField as the editing component.
    99       * @param table The JTable which called this method.
    100       * @param value The initial value of the cell this editor will be used
    101       * for, as an Object. Format this to suit the editor you wish to return.
    102       * @param isSelected A Boolean specifying whether the selected cell
    103       * is currently highlighted in such a way so as to allow the user to
    104       * know it is being edited.
    105       * @param row An Int specifying the cells row.
    106       * @param column An Int specifying the cells column.
    107       * @return A Component which will be placed in the table as the method
    108       * of editing the specified cell.
    109       */
    110     public Component getTableCellEditorComponent(JTable table, Object value,
    111                                                                 boolean isSelected, int row,
    112                                                                 int column) {
    113           GTableModel model = (GTableModel)table.getModel();
    114           // Create a new GComboBox with a model based on the selected
    115           // records metadata.
    116           Metadata selected_metadata = model.getMetadataAtRow(row);
    117           //editor_model = gatherer.c_man.getCollection().getValueModel
    118           //    (selected_metadata.element);
    119           editor = new GComboBox(editor_model);
    120           editor.setEditable(true);
    121           // Make sure that value is the currently selected option in the
    122           // editor.
    123           editor.setSelectedItem(value);
    124           // Done.
    125           return editor;
    126     }
     93    /** This method is called to retrieve the correct editor component for
     94     * a certain row and column within the target JTable. It is here that
     95     * we create the custom GComboBox for each row of the 'values' column
     96     * using a different model for each. If the call comes from any other
     97     * column (which it shouldn't but what the hell) we let the super
     98     * handle it which returns a plain old JTextField as the editing component.
     99     * @param table The JTable which called this method.
     100     * @param value The initial value of the cell this editor will be used
     101     * for, as an Object. Format this to suit the editor you wish to return.
     102     * @param isSelected A Boolean specifying whether the selected cell
     103     * is currently highlighted in such a way so as to allow the user to
     104     * know it is being edited.
     105     * @param row An Int specifying the cells row.
     106     * @param column An Int specifying the cells column.
     107     * @return A Component which will be placed in the table as the method
     108     * of editing the specified cell.
     109     */
     110    public Component getTableCellEditorComponent(JTable table, Object value,
     111                        boolean isSelected, int row,
     112                        int column) {
     113    GTableModel model = (GTableModel)table.getModel();
     114    // Create a new GComboBox with a model based on the selected
     115    // records metadata.
     116    Metadata selected_metadata = model.getMetadataAtRow(row);
     117    //editor_model = gatherer.c_man.getCollection().getValueModel
     118    //  (selected_metadata.element);
     119    editor = new GComboBox(editor_model);
     120    editor.setEditable(true);
     121    // Make sure that value is the currently selected option in the
     122    // editor.
     123    editor.setSelectedItem(value);
     124    // Done.
     125    return editor;
     126    }
    127127}
    128128
  • trunk/gli/src/org/greenstone/gatherer/gui/table/GTableModel.java

    r4350 r4366  
    4646 */
    4747public class GTableModel
    48     extends AbstractTableModel
    49     implements MSMListener {
    50     /** The source for the data currently shown in the table. May be any of the other three metadata lists, or the union of all of them. */
    51     private ArrayList current_metadata    = new ArrayList();
    52     /** The metadata currently assigned at the file level. */
    53     private ArrayList file_metadata       = null; // new ArrayList();
    54     /** The metadata currently assigned at the folder level. */
    55     private ArrayList inherited_metadata  = null; // new ArrayList();
    56     /** The metadata currently unassigned. */
    57     private ArrayList unassigned_metadata = null; // new ArrayList();
    58     /** The file nodes this model is built upon. */
    59     private FileNode[] file_nodes;
    60     /** The current view. */
    61     //private int current_view;
     48    extends AbstractTableModel
     49    implements MSMListener {
     50    /** The source for the data currently shown in the table. May be any of the other three metadata lists, or the union of all of them. */
     51    private ArrayList current_metadata    = new ArrayList();
     52    /** The metadata currently assigned at the file level. */
     53    private ArrayList file_metadata       = null; // new ArrayList();
     54    /** The metadata currently assigned at the folder level. */
     55    private ArrayList inherited_metadata  = null; // new ArrayList();
     56    /** The metadata currently unassigned. */
     57    private ArrayList unassigned_metadata = null; // new ArrayList();
     58    /** The file nodes this model is built upon. */
     59    private FileNode[] file_nodes;
     60    /** The current view. */
     61    //private int current_view;
    6262
    6363     //private JToggleButton assigned_metadata_view;
     
    6767     //private JProgressBar activity_bar;
    6868     /** The table this model is being displayed in. */
    69     private JTable table;
    70 
    71     private ModelBuilder builder;
    72 
    73     static final public int SHOW_ALL         = 0;
    74     static final public int SHOW_ASSIGNED    = 1;
    75     static final public int SHOW_FILE        = 2;
    76     static final public int SHOW_INHERITED   = 3;
    77     static final public int SHOW_UNASSIGNED  = 4;
    78     static final private String[] COLUMN_NAMES = {"", Gatherer.dictionary.get("Metadata.Element"),  Gatherer.dictionary.get("Metadata.Value")};
    79 
    80     public GTableModel(JTable table) {
    81           this.builder = null;
    82           this.file_metadata = current_metadata;
    83           this.inherited_metadata = current_metadata;
    84           this.table = table;
    85           this.unassigned_metadata = current_metadata;
    86           //changeView();
    87           // Register this model with the msm manager.
    88           if(Gatherer.c_man.ready()) {
    89                 Gatherer.c_man.getCollection().msm.addMSMListener(this);
    90           }
    91     }
    92 
    93     public GTableModel(JTable table, FileNode[] file_nodes) {
    94           this(table);
    95           this.file_nodes = file_nodes;
    96           if(file_nodes != null && file_nodes.length > 0) {
     69    private JTable table;
     70
     71    private ModelBuilder builder;
     72
     73    static final public int SHOW_ALL         = 0;
     74    static final public int SHOW_ASSIGNED    = 1;
     75    static final public int SHOW_FILE        = 2;
     76    static final public int SHOW_INHERITED   = 3;
     77    static final public int SHOW_UNASSIGNED  = 4;
     78    static final private String[] COLUMN_NAMES = {"", Gatherer.dictionary.get("Metadata.Element"),  Gatherer.dictionary.get("Metadata.Value")};
     79
     80    public GTableModel(JTable table) {
     81    this.builder = null;
     82    this.file_metadata = current_metadata;
     83    this.inherited_metadata = current_metadata;
     84    this.table = table;
     85    this.unassigned_metadata = current_metadata;
     86    //changeView();
     87    // Register this model with the msm manager.
     88    if(Gatherer.c_man.ready()) {
     89        Gatherer.c_man.getCollection().msm.addMSMListener(this);
     90    }
     91    }
     92
     93    public GTableModel(JTable table, FileNode[] file_nodes) {
     94    this(table);
     95    this.file_nodes = file_nodes;
     96    if(file_nodes != null && file_nodes.length > 0) {
    9797                // Create model builder
    98                 builder = new ModelBuilder();
    99                 builder.start();
    100           }
    101     }
    102 
    103     /** The default constructor creates a new empty model with the current view set to an emtpy 'all metadata'. */
    104     /*
    105         public GTableModel(JTable table, JToggleButton assigned_metadata_view, JToggleButton unassigned_metadata_view, JProgressBar activity_bar) {
    106           this.activity_bar = activity_bar;
    107           this.assigned_metadata_view = assigned_metadata_view;
    108           this.builder = null;
    109           this.table = table;
    110           this.unassigned_metadata_view = unassigned_metadata_view;
    111           changeView();
    112           // Register this model with the msm manager.
    113           if(Gatherer.c_man.ready()) {
    114                 Gatherer.c_man.getCollection().msm.addMSMListener(this);
    115           }
    116         }
    117     */
     98        builder = new ModelBuilder();
     99        builder.start();
     100    }
     101    }
     102
     103    /** The default constructor creates a new empty model with the current view set to an emtpy 'all metadata'. */
     104    /*
     105      public GTableModel(JTable table, JToggleButton assigned_metadata_view, JToggleButton unassigned_metadata_view, JProgressBar activity_bar) {
     106      this.activity_bar = activity_bar;
     107      this.assigned_metadata_view = assigned_metadata_view;
     108      this.builder = null;
     109      this.table = table;
     110      this.unassigned_metadata_view = unassigned_metadata_view;
     111      changeView();
     112      // Register this model with the msm manager.
     113      if(Gatherer.c_man.ready()) {
     114      Gatherer.c_man.getCollection().msm.addMSMListener(this);
     115      }
     116      }
     117    */
    118118
    119119     /** This constuctor starts by creating an empty model then, using a separate model builder thread, builds a model from the given files. */
     
    130130     */
    131131
    132     public void changeView() {
    133           changeView(SHOW_ALL);
    134     }
    135 
    136     /*
     132    public void changeView() {
     133    changeView(SHOW_ALL);
     134    }
     135
     136    /*
    137137     public void changeView() {
    138138          boolean show_assigned = assigned_metadata_view.isSelected();
     
    151151
    152152     /** Change the current view by changing the model that the table is currently based on. */
    153     public void changeView(int view) {
    154           //current_view = view;
    155           /*
    156           switch(view) {
    157           case SHOW_ASSIGNED:
     153    public void changeView(int view) {
     154    //current_view = view;
     155    /*
     156      switch(view) {
     157      case SHOW_ASSIGNED:
    158158                ///ystem.err.println("Show assigned");
    159159                current_metadata = new ArrayList();
     
    162162                Collections.sort(current_metadata, MSMUtils.METADATA_COMPARATOR);
    163163                break;
    164           case SHOW_FILE:
     164                case SHOW_FILE:
    165165                ///ystem.err.println("Show file");
    166166                current_metadata = file_metadata;
    167167                break;
    168           case SHOW_INHERITED:
     168                case SHOW_INHERITED:
    169169                ///ystem.err.println("Show inherited");
    170170                current_metadata = inherited_metadata;
    171171                break;
    172           case SHOW_UNASSIGNED:
     172                case SHOW_UNASSIGNED:
    173173                ///ystem.err.println("Show unassigned");
    174174                current_metadata = unassigned_metadata;
    175175                break;
    176           default:
     176                default:
    177177                // SHOW_ALL
    178178                System.err.println("Show all");
     
    183183                current_metadata.addAll(unassigned_metadata);
    184184                Collections.sort(current_metadata, MSMUtils.METADATA_COMPARATOR);
    185           }
    186           // Inform everyone that the model has changed.
    187           fireTableDataChanged();
    188           */
    189     }
    190 
    191     /** Called whenever an element in a set is added, edited or removed from the metadata set manager. We listen for this just incase the name of one of the elements currently shown changes. After that the table will be up to date, as the element references are otherwise live. */
    192     public void elementChanged(MSMEvent event) {
    193           MSMAction profile = event.getProfile();
    194           if(profile != null) {
     185                }
     186                // Inform everyone that the model has changed.
     187                fireTableDataChanged();
     188    */
     189    }
     190
     191    /** Called whenever an element in a set is added, edited or removed from the metadata set manager. We listen for this just incase the name of one of the elements currently shown changes. After that the table will be up to date, as the element references are otherwise live. */
     192    public void elementChanged(MSMEvent event) {
     193    MSMAction profile = event.getProfile();
     194    if(profile != null) {
    195195                // Retrieve the elements new name (thats hopefully what will be returned by getValue()).
    196                 String name = profile.getTarget();
    197                 int row = 0;
    198                 for( ; row < current_metadata.size(); row++) {
    199                      if(getValueAt(row, 0).equals(name)) {
    200                           fireTableCellUpdated(row, 0);
    201                      }
    202                 }
    203                 name = null;
    204           }
    205           profile = null;
    206           event = null;
    207     }
    208 
    209     /** Returns the number of columns in this table. */
    210     public int getColumnCount() {
    211           return COLUMN_NAMES.length;
    212     }
    213 
    214     /** Returns the data class of the specified column. */
    215     public Class getColumnClass(int col) {
    216           if(col == 2) {
    217                 return JButton.class;
    218           }
    219           return String.class;
    220     }
    221 
    222     /** Retrieves the name of the specified column. */
    223     public String getColumnName(int col) {
    224           return COLUMN_NAMES[col];
    225     }
    226 
    227     /* Called to retrieve the Metadata record that matches a certain row. Usually caused by the user selectiong a row in the table. It synchronized so that the model doesn't up and change while we're trying to retrieve the indicated element. */
    228     public synchronized Metadata getMetadataAtRow(int row) {
    229           if(0 <= row && row < current_metadata.size()) {
    230                 return (Metadata) current_metadata.get(row);
    231           }
    232           return null;
    233     }
    234 
    235     /** Returns the number of rows in this table. */
    236     public int getRowCount() {
    237           return current_metadata.size();
    238     }
    239 
    240     /** Returns the cell value at a given row and column as an Object. */
    241     public Object getValueAt(int row, int col) {
    242           Object result = "";
    243           if(0 <= row && row < current_metadata.size()) {
    244                 Metadata m = (Metadata) current_metadata.get(row);
    245                 if(0 <= col && col < COLUMN_NAMES.length) {
    246                      switch(col) {
    247                      case 0:
    248                           if(!m.isFileLevel()) {
    249                                 result = m.getFile();
    250                           }
    251                           break;
    252                      case 1:
    253                           ElementWrapper element = m.getElement();
    254                           if(element != null) {
    255                                 result = element.toString();
    256                           }
    257                           break;
    258                      case 2:
    259                           result = m.getValue();
    260                           break;
    261                      case 3:
    262                           result = (m.isFileLevel() ? "true" : "false");
    263                           break;
    264                      }
    265                 }
    266           }
    267           return result;
    268     }
     196        String name = profile.getTarget();
     197        int row = 0;
     198        for( ; row < current_metadata.size(); row++) {
     199        if(getValueAt(row, 0).equals(name)) {
     200            fireTableCellUpdated(row, 0);
     201        }
     202        }
     203        name = null;
     204    }
     205    profile = null;
     206    event = null;
     207    }
     208
     209    /** Returns the number of columns in this table. */
     210    public int getColumnCount() {
     211    return COLUMN_NAMES.length;
     212    }
     213
     214    /** Returns the data class of the specified column. */
     215    public Class getColumnClass(int col) {
     216    if(col == 2) {
     217        return JButton.class;
     218    }
     219    return String.class;
     220    }
     221
     222    /** Retrieves the name of the specified column. */
     223    public String getColumnName(int col) {
     224    return COLUMN_NAMES[col];
     225    }
     226
     227    /* Called to retrieve the Metadata record that matches a certain row. Usually caused by the user selectiong a row in the table. It synchronized so that the model doesn't up and change while we're trying to retrieve the indicated element. */
     228    public synchronized Metadata getMetadataAtRow(int row) {
     229    if(0 <= row && row < current_metadata.size()) {
     230        return (Metadata) current_metadata.get(row);
     231    }
     232    return null;
     233    }
     234
     235    /** Returns the number of rows in this table. */
     236    public int getRowCount() {
     237    return current_metadata.size();
     238    }
     239
     240    /** Returns the cell value at a given row and column as an Object. */
     241    public Object getValueAt(int row, int col) {
     242    Object result = "";
     243    if(0 <= row && row < current_metadata.size()) {
     244        Metadata m = (Metadata) current_metadata.get(row);
     245        if(0 <= col && col < COLUMN_NAMES.length) {
     246        switch(col) {
     247        case 0:
     248            if(!m.isFileLevel()) {
     249            result = m.getFile();
     250            }
     251            break;
     252        case 1:
     253            ElementWrapper element = m.getElement();
     254            if(element != null) {
     255            result = element.toString();
     256            }
     257            break;
     258        case 2:
     259            result = m.getValue();
     260            break;
     261        case 3:
     262            result = (m.isFileLevel() ? "true" : "false");
     263            break;
     264        }
     265        }
     266    }
     267    return result;
     268    }
    269269     
    270     /** Allows access to this models current view. */
    271     public int getView() {
    272           return SHOW_ALL; //current_view;
    273     }
    274 
    275     /** Determine if the given metadata is common to all selected file nodes given the context of the current view. */
    276     public boolean isCommon(int row) {
    277           if(0 <= row && row < current_metadata.size()) {
    278                 Metadata entry = (Metadata) current_metadata.get(row);
     270    /** Allows access to this models current view. */
     271    public int getView() {
     272    return SHOW_ALL; //current_view;
     273    }
     274
     275    /** Determine if the given metadata is common to all selected file nodes given the context of the current view. */
     276    public boolean isCommon(int row) {
     277    if(0 <= row && row < current_metadata.size()) {
     278        Metadata entry = (Metadata) current_metadata.get(row);
    279279                ///ystem.err.println("There are " + file_nodes.length + " selected files.");
    280280                ///ystem.err.println("This metadata is attached to " + entry.getCount() + " of them.");
    281                 if(entry.getCount() == file_nodes.length) {
    282                      return true;
    283                 }
    284           }
    285           return false;
    286     }
    287 
    288     /** Whenever there is a metadata change we must determine if there are any changes to our various lists of metadata, and also if there is any need to refresh the table currently being viewed. */
    289     public void metadataChanged(MSMEvent event) {
    290           FileNode file_node = event.getRecord();
    291           ///ystem.err.println("File node effected");
    292           // First check whether this record is one of those that we have showing.
    293           if(file_nodes != null && file_node != null && ArrayTools.contains(file_nodes, file_node)) {
     281        if(entry.getCount() == file_nodes.length) {
     282        return true;
     283        }
     284    }
     285    return false;
     286    }
     287
     288    /** Whenever there is a metadata change we must determine if there are any changes to our various lists of metadata, and also if there is any need to refresh the table currently being viewed. */
     289    public void metadataChanged(MSMEvent event) {
     290    FileNode file_node = event.getRecord();
     291    ///ystem.err.println("File node effected");
     292    // First check whether this record is one of those that we have showing.
     293    if(file_nodes != null && file_node != null && ArrayTools.contains(file_nodes, file_node)) {
    294294                // Brute force solution... rebuild the table.
    295                 if(file_nodes != null && file_nodes.length > 0) {
    296                      current_metadata.clear();
    297                      // Create model builder
    298                      builder = new ModelBuilder();
    299                      builder.start();
    300                 }
     295        if(file_nodes != null && file_nodes.length > 0) {
     296        current_metadata.clear();
     297        // Create model builder
     298        builder = new ModelBuilder();
     299        builder.start();
     300        }
    301301
    302302                /*
    303303                // If old metadata has been removed then remove it. Update the unassigned list if necessary (first checking if there are other metadata entries with the same element, and furthermore if the were inherited metadata being supressed).
    304304                if(old_data != null) {
    305                      System.err.println("Remove: " + old_data);
    306                      // Determine the level of this metadata
    307                      ArrayList modified_metadata = null;
    308                      if(old_data.isFileLevel()) {
    309                           modified_metadata = file_metadata;
    310                      }
    311                      else {
    312                           modified_metadata = inherited_metadata;
    313                      }
     305                System.err.println("Remove: " + old_data);
     306                // Determine the level of this metadata
     307                ArrayList modified_metadata = null;
     308                if(old_data.isFileLevel()) {
     309                modified_metadata = file_metadata;
     310                }
     311                else {
     312                modified_metadata = inherited_metadata;
     313                }
    314314                     
    315                      int index = -1;
    316                      if((index = modified_metadata.indexOf(old_data)) != -1) {
    317                           Metadata data = (Metadata) modified_metadata.get(index);
    318                           data.dec();
    319                           // If we just removed the last occurance of this metadata, delete it
    320                           if(data.getCount() == 0) {
    321                                 remove(modified_metadata, data);
    322                                 // If there are no further occurances of the element of this entry, add entry to unassigned_metadata.
    323                                 boolean found = false;
    324                                 ElementWrapper element = data.getElement();
    325                                 // Search the current metadata
    326                                 for(int i = 0; i < modified_metadata.size(); i++) {
    327                                      Metadata sibling = (Metadata) modified_metadata.get(i);
    328                                      if(sibling.getElement().equals(element)) {
    329                                           found = true;
    330                                      }
    331                                 }
    332                                 // And the inherited metadata if we haven't already
    333                                 if(modified_metadata != inherited_metadata) {
    334                                      for(int i = 0; !found && i < inherited_metadata.size(); i++) {
    335                                           Metadata sibling = (Metadata) inherited_metadata.get(i);
    336                                           if(sibling.getElement().equals(element)) {
    337                                                 found = true;
    338                                           }
    339                                      }
    340                                 }
    341                                 // If we get this far and still haven't found a match then we do something very tricky. We retrieve all of the metadata for the parent file and notice any inherited nodes that were previously overwritten by the metadata entry we removed. The reason we use the parent is that we can't just assume that the GDMDocument changes occured before this method was called. Thus our about-to-be-removed overwritting metadata may still be in effect if we just called getMetadata for this file.
    342                                 if(!found) {
    343                                      ArrayList parent_metadatum = Gatherer.c_man.getCollection().gdm.getMetadata((file_node.getFile()).getParentFile());
    344                                      // For each piece of parent metadata
    345                                      for(int i = parent_metadatum.size(); i > 0; i--) {
    346                                           Metadata parent_metadata = (Metadata) parent_metadatum.get(i - 1);
    347                                           // If we found some previously suppressed metadata then add it and say we found something.
    348                                           if(!inherited_metadata.contains(parent_metadata)) {
    349                                                 ///ystem.err.println("Restoring overwritten inherited metadata: " + parent_metadata);
    350                                                 found = true;
    351                                                 parent_metadata.setCount(1);
    352                                                 parent_metadata.setFileLevel(false); // Has to be folder level doesn't it.
    353                                                 add(inherited_metadata, parent_metadata);
    354                                           }
    355                                      }
    356                                      // Run this getMetadata again to restore all of the file level and source file entries (they would have changed to reflect the parents call.
    357                                      Gatherer.c_man.getCollection().gdm.getMetadata(file_node.getFile());
    358                                 }
    359                                 // And only then, if we haven't found a substitute, may we add a null metadata.
    360                                 if(!found) {
    361                                      add(unassigned_metadata, new Metadata(data.getElement()));
    362                                 }
    363                           }
    364                      }
     315                int index = -1;
     316                if((index = modified_metadata.indexOf(old_data)) != -1) {
     317                Metadata data = (Metadata) modified_metadata.get(index);
     318                data.dec();
     319                // If we just removed the last occurance of this metadata, delete it
     320                if(data.getCount() == 0) {
     321                remove(modified_metadata, data);
     322                // If there are no further occurances of the element of this entry, add entry to unassigned_metadata.
     323                boolean found = false;
     324                ElementWrapper element = data.getElement();
     325                // Search the current metadata
     326                for(int i = 0; i < modified_metadata.size(); i++) {
     327                Metadata sibling = (Metadata) modified_metadata.get(i);
     328                if(sibling.getElement().equals(element)) {
     329                found = true;
     330                }
     331                }
     332                // And the inherited metadata if we haven't already
     333                if(modified_metadata != inherited_metadata) {
     334                for(int i = 0; !found && i < inherited_metadata.size(); i++) {
     335                Metadata sibling = (Metadata) inherited_metadata.get(i);
     336                if(sibling.getElement().equals(element)) {
     337                found = true;
     338                }
     339                }
     340                }
     341                // If we get this far and still haven't found a match then we do something very tricky. We retrieve all of the metadata for the parent file and notice any inherited nodes that were previously overwritten by the metadata entry we removed. The reason we use the parent is that we can't just assume that the GDMDocument changes occured before this method was called. Thus our about-to-be-removed overwritting metadata may still be in effect if we just called getMetadata for this file.
     342                if(!found) {
     343                ArrayList parent_metadatum = Gatherer.c_man.getCollection().gdm.getMetadata((file_node.getFile()).getParentFile());
     344                // For each piece of parent metadata
     345                for(int i = parent_metadatum.size(); i > 0; i--) {
     346                Metadata parent_metadata = (Metadata) parent_metadatum.get(i - 1);
     347                // If we found some previously suppressed metadata then add it and say we found something.
     348                if(!inherited_metadata.contains(parent_metadata)) {
     349                ///ystem.err.println("Restoring overwritten inherited metadata: " + parent_metadata);
     350                found = true;
     351                parent_metadata.setCount(1);
     352                parent_metadata.setFileLevel(false); // Has to be folder level doesn't it.
     353                add(inherited_metadata, parent_metadata);
     354                }
     355                }
     356                // Run this getMetadata again to restore all of the file level and source file entries (they would have changed to reflect the parents call.
     357                Gatherer.c_man.getCollection().gdm.getMetadata(file_node.getFile());
     358                }
     359                // And only then, if we haven't found a substitute, may we add a null metadata.
     360                if(!found) {
     361                add(unassigned_metadata, new Metadata(data.getElement()));
     362                }
     363                }
     364                }
    365365                }
    366366                // If new metadata has been assigned, remove its entry from the unassigned metadata list. Furthermore add the new entry to either the file or folder metadata list depending on its level. Remember to rebuild the common metadata lists.
    367367                if(new_data != null) {
    368                      ///ystem.err.println("Add: " + new_data);
    369                      // Create dummy 'unassigned' metadata from the new metadata and remove it from the unassigned list (if its even there)
    370                      remove(unassigned_metadata, new Metadata(new_data.getElement()));
    371                      // Determine if we are adding the new node at the file or folder level.
    372                      ArrayList modified_metadata = null;
    373                      if(new_data.isFileLevel()) {
    374                           modified_metadata = file_metadata;
    375                           // If its file metadata, and its set to overwrite, then we need to remove any row it would overwrite.
    376                           if(new_data.accumulates()) {
    377                                 // All good.
    378                           }
    379                           else {
    380                                 // Remove any entries in the inherited_metadata that would be overwritten
    381                                 ElementWrapper element = new_data.getElement();
    382                                 for(int i = 0; i < inherited_metadata.size(); i++) {
    383                                      Metadata sibling = (Metadata) inherited_metadata.get(i);
    384                                      if(sibling.getElement().equals(element)) {
    385                                           inherited_metadata.remove(sibling);
    386                                      }
    387                                 }
    388                           }
    389                      }
    390                      else {
    391                           modified_metadata = inherited_metadata;
    392                      }
    393                      // And add it.
    394                      int index = -1;
    395                      if((index = modified_metadata.indexOf(new_data)) == -1) {
    396                           add(modified_metadata, new_data);
    397                           new_data.setCount(1);
    398                      }
    399                      else {
    400                           Metadata data = (Metadata) modified_metadata.get(index);
    401                           data.inc();
    402                           data = null;
    403                      }
    404                      modified_metadata = null;
     368                ///ystem.err.println("Add: " + new_data);
     369                // Create dummy 'unassigned' metadata from the new metadata and remove it from the unassigned list (if its even there)
     370                remove(unassigned_metadata, new Metadata(new_data.getElement()));
     371                // Determine if we are adding the new node at the file or folder level.
     372                ArrayList modified_metadata = null;
     373                if(new_data.isFileLevel()) {
     374                modified_metadata = file_metadata;
     375                // If its file metadata, and its set to overwrite, then we need to remove any row it would overwrite.
     376                if(new_data.accumulates()) {
     377                // All good.
     378                }
     379                else {
     380                // Remove any entries in the inherited_metadata that would be overwritten
     381                ElementWrapper element = new_data.getElement();
     382                for(int i = 0; i < inherited_metadata.size(); i++) {
     383                Metadata sibling = (Metadata) inherited_metadata.get(i);
     384                if(sibling.getElement().equals(element)) {
     385                inherited_metadata.remove(sibling);
     386                }
     387                }
     388                }
     389                }
     390                else {
     391                modified_metadata = inherited_metadata;
     392                }
     393                // And add it.
     394                int index = -1;
     395                if((index = modified_metadata.indexOf(new_data)) == -1) {
     396                add(modified_metadata, new_data);
     397                new_data.setCount(1);
     398                }
     399                else {
     400                Metadata data = (Metadata) modified_metadata.get(index);
     401                data.inc();
     402                data = null;
     403                }
     404                modified_metadata = null;
    405405                }
    406406                // As a current visible table is most likely affected, update the table component. We do this by calling changeView so as to also update any compound list.
    407407                //changeView(current_view);
    408408                */
    409           }
    410           else {
     409    }
     410    else {
    411411                ///ystem.err.println("FileNodes = " + file_nodes);
    412412                ///ystem.err.println("FileNode = " + file_node);
    413           }
    414     }
    415 
    416     /** Called whenever a set is added or removed from the metadata set manager. */
    417     public void setChanged(MSMEvent event) {
    418           // No, don't care. Still don't care. Couldn't care less.
    419     }
    420 
    421     public Rectangle setSelectedMetadata(Metadata data) {
    422           Rectangle bounds = null;
    423           if (builder != null) {
    424               if(builder.complete) {
    425               for(int i = 0; i < getRowCount(); i++) {
    426                   if(getMetadataAtRow(i).equals(data)) {
    427                   ///ystem.err.println("Found matching metadata at row " + i + " (of " + getRowCount() + " rows)");
    428                   ///ystem.err.println("Table shows " + table.getRowCount() + " rows!");
    429                   bounds = table.getCellRect(i, 0, true);
    430                   table.scrollRectToVisible(bounds);
    431                   table.setRowSelectionInterval(i, i);
    432                   }
    433               }
    434               }
    435               else {
    436               builder.selected_metadata = data;
    437               }
    438           }
    439           return bounds;
    440     }
    441 
    442     public int size() {
    443           return file_nodes.length;
    444     }
    445 
    446     /** Called when the value tree of a certain element has changed significantly but, although we display metadata values, we only care about those coming through metadataChanged() events. */
    447     public void valueChanged(MSMEvent event) {
    448           // Don't care. Tra-la-la-la-la.
    449     }
    450 
    451     /** Alphabetically inserts the new_metadata in the target vector. */
    452     private int add(ArrayList target, Metadata new_metadata) {
    453           int i = 0;
    454           while(i < target.size()) {
    455                 Metadata current = (Metadata)target.get(i);
    456                 if(current.compareTo(new_metadata) > 0) {
    457                      target.add(i, new_metadata);
    458                      return i;
    459                 }
    460                 i++;
    461           }
    462           target.add(new_metadata);
    463           return i;
    464     }
    465 
    466     /** Remove a certain piece of data from a certain vector. */
    467     private void remove(ArrayList target, Metadata old_metadata) {
    468           if(target != null) {
    469                 for(int i = 0; i < target.size(); i++) {
    470                      Metadata current_metadata = (Metadata) target.get(i);
    471                      if(current_metadata.equals(old_metadata)) {
    472                           target.remove(current_metadata);
    473                           return;
    474                      }
    475                 }
    476           }
    477     }
    478 
    479     private class ModelBuilder
    480           extends Thread {
    481 
    482           public boolean had_warning = false;
    483 
    484           public boolean complete = false;
    485 
    486           public Metadata selected_metadata = null;;
     413    }
     414    }
     415
     416    /** Called whenever a set is added or removed from the metadata set manager. */
     417    public void setChanged(MSMEvent event) {
     418    // No, don't care. Still don't care. Couldn't care less.
     419    }
     420
     421    public Rectangle setSelectedMetadata(Metadata data) {
     422    Rectangle bounds = null;
     423    if (builder != null) {
     424        if(builder.complete) {
     425        for(int i = 0; i < getRowCount(); i++) {
     426            if(getMetadataAtRow(i).equals(data)) {
     427            ///ystem.err.println("Found matching metadata at row " + i + " (of " + getRowCount() + " rows)");
     428            ///ystem.err.println("Table shows " + table.getRowCount() + " rows!");
     429            bounds = table.getCellRect(i, 0, true);
     430            table.scrollRectToVisible(bounds);
     431            table.setRowSelectionInterval(i, i);
     432            }
     433        }
     434        }
     435        else {
     436        builder.selected_metadata = data;
     437        }
     438    }
     439    return bounds;
     440    }
     441
     442    public int size() {
     443    return file_nodes.length;
     444    }
     445
     446    /** Called when the value tree of a certain element has changed significantly but, although we display metadata values, we only care about those coming through metadataChanged() events. */
     447    public void valueChanged(MSMEvent event) {
     448    // Don't care. Tra-la-la-la-la.
     449    }
     450
     451    /** Alphabetically inserts the new_metadata in the target vector. */
     452    private int add(ArrayList target, Metadata new_metadata) {
     453    int i = 0;
     454    while(i < target.size()) {
     455        Metadata current = (Metadata)target.get(i);
     456        if(current.compareTo(new_metadata) > 0) {
     457        target.add(i, new_metadata);
     458        return i;
     459        }
     460        i++;
     461    }
     462    target.add(new_metadata);
     463    return i;
     464    }
     465
     466    /** Remove a certain piece of data from a certain vector. */
     467    private void remove(ArrayList target, Metadata old_metadata) {
     468    if(target != null) {
     469        for(int i = 0; i < target.size(); i++) {
     470        Metadata current_metadata = (Metadata) target.get(i);
     471        if(current_metadata.equals(old_metadata)) {
     472            target.remove(current_metadata);
     473            return;
     474        }
     475        }
     476    }
     477    }
     478
     479    private class ModelBuilder
     480    extends Thread {
     481
     482    public boolean had_warning = false;
     483
     484    public boolean complete = false;
     485
     486    public Metadata selected_metadata = null;;
    487487         
    488           public void run() {
    489                 Vector elements = Gatherer.c_man.getCollection().msm.getElements();
     488    public void run() {
     489        Vector elements = Gatherer.c_man.getCollection().msm.getElements();
    490490                // Show some visual indication that building is occuring.
    491491                //assigned_metadata_view.setEnabled(false);
     
    496496                //long start = System.currentTimeMillis();
    497497               
    498                 ArrayList known_elements = new ArrayList(); // Elements that have metadata assigned.
    499                 for(int i = 0; i < file_nodes.length; i++) {
    500                      File current_file = file_nodes[i].getFile();
    501                      // The current assigned metadata for this file.
    502                      ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getAllMetadata(current_file);
    503                      for(int j = 0; j < metadatum.size(); j++) {
    504                           Metadata data = (Metadata) metadatum.get(j);
    505                           // Determine the target list by the metadata level
    506                           ArrayList modified_metadata;
    507                           if(data.isFileLevel()) {
    508                                 modified_metadata = file_metadata;
    509                           }
    510                           else {
    511                                 showInheritedMetadataWarning();
    512                                 modified_metadata = inherited_metadata;
    513                           }
    514                           int index = -1;
    515                           // Don't show hidden metadata
    516                           // If the given metadata already exists in our list of modified metadata then increment its commonality count.
    517                           if((index = modified_metadata.indexOf(data)) != -1) {
    518                                 data = (Metadata) modified_metadata.get(index);
    519                                 ///ystem.err.println("Increasing count:" + element);
    520                                 data.inc();
    521                                 // If the table shown is stale, refresh it.
    522                                 //if((modified_metadata == file_metadata && current_view == SHOW_FILE) || (modified_metadata == inherited_metadata && current_view == SHOW_INHERITED)) {
    523                                 // fireTableRowsUpdated(index, index);
    524                                 //}
    525                                 // We may have to update a compound list
    526                                 //else if(current_view == SHOW_ALL || current_view == SHOW_ASSIGNED) {
    527                                 if((index = current_metadata.indexOf(data)) == -1) {
    528                                     fireTableRowsUpdated(index, index);
    529                                 }
    530                                 //}
    531                           }
    532                           // Ensure the metadata's element is in our list of showable elements.
    533                           else if(contains(elements, data.getElement())) {
    534                                 ///ystem.err.println("Setting count to one: " + element);
    535                                 data.setCount(1);
    536                                 index = add(modified_metadata, data); // Add to assigned metadata.
    537                                 known_elements.add(data.getElement());
    538                                 // If the table shown is stale, refresh it.
    539                                 //if((modified_metadata == file_metadata && current_view == SHOW_FILE) || (modified_metadata == inherited_metadata && current_view == SHOW_INHERITED)) {
    540                                 //   fireTableRowsInserted(index, index);
    541                                 //}
    542                                 // We may have to update a compound list
    543                                 //else if(current_view == SHOW_ALL || current_view == SHOW_ASSIGNED) {
    544                                 if((index = current_metadata.indexOf(data)) == -1) {
    545                                     index = add(current_metadata, data);
    546                                     fireTableRowsInserted(index, index);
    547                                 }
    548                                 else {
    549                                     fireTableRowsUpdated(index, index);     
    550                                 }
    551                                 //}
    552                           }
    553                           else {
    554                                 ///ystem.err.println("No.\n***** Cannot match element so it must be hidden, right? *****");
    555                           }
    556                      }
    557                      //activity_bar.setValue(activity_bar.getValue() + 1);
    558                      Gatherer.g_man.metaedit_pane.validateMetadataTable();
    559                 }
     498        ArrayList known_elements = new ArrayList(); // Elements that have metadata assigned.
     499        for(int i = 0; i < file_nodes.length; i++) {
     500        File current_file = file_nodes[i].getFile();
     501        // The current assigned metadata for this file.
     502        ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getAllMetadata(current_file);
     503        for(int j = 0; j < metadatum.size(); j++) {
     504            Metadata data = (Metadata) metadatum.get(j);
     505            // Determine the target list by the metadata level
     506            ArrayList modified_metadata;
     507            if(data.isFileLevel()) {
     508            modified_metadata = file_metadata;
     509            }
     510            else {
     511            showInheritedMetadataWarning();
     512            modified_metadata = inherited_metadata;
     513            }
     514            int index = -1;
     515            // Don't show hidden metadata
     516            // If the given metadata already exists in our list of modified metadata then increment its commonality count.
     517            if((index = modified_metadata.indexOf(data)) != -1) {
     518            data = (Metadata) modified_metadata.get(index);
     519            ///ystem.err.println("Increasing count:" + element);
     520            data.inc();
     521            // If the table shown is stale, refresh it.
     522            //if((modified_metadata == file_metadata && current_view == SHOW_FILE) || (modified_metadata == inherited_metadata && current_view == SHOW_INHERITED)) {
     523            // fireTableRowsUpdated(index, index);
     524            //}
     525            // We may have to update a compound list
     526            //else if(current_view == SHOW_ALL || current_view == SHOW_ASSIGNED) {
     527            if((index = current_metadata.indexOf(data)) == -1) {
     528                fireTableRowsUpdated(index, index);
     529            }
     530            //}
     531            }
     532            // Ensure the metadata's element is in our list of showable elements.
     533            else if(contains(elements, data.getElement())) {
     534            ///ystem.err.println("Setting count to one: " + element);
     535            data.setCount(1);
     536            index = add(modified_metadata, data); // Add to assigned metadata.
     537            known_elements.add(data.getElement());
     538            // If the table shown is stale, refresh it.
     539            //if((modified_metadata == file_metadata && current_view == SHOW_FILE) || (modified_metadata == inherited_metadata && current_view == SHOW_INHERITED)) {
     540            //   fireTableRowsInserted(index, index);
     541            //}
     542            // We may have to update a compound list
     543            //else if(current_view == SHOW_ALL || current_view == SHOW_ASSIGNED) {
     544            if((index = current_metadata.indexOf(data)) == -1) {
     545                index = add(current_metadata, data);
     546                fireTableRowsInserted(index, index);
     547            }
     548            else {
     549                fireTableRowsUpdated(index, index); 
     550            }
     551            //}
     552            }
     553            else {
     554            ///ystem.err.println("No.\n***** Cannot match element so it must be hidden, right? *****");
     555            }
     556        }
     557        //activity_bar.setValue(activity_bar.getValue() + 1);
     558        Gatherer.g_man.metaedit_pane.validateMetadataTable();
     559        }
    560560                // Add entries for the currently unassigned metadata. You can determine these as the difference between elements and known_elements.
    561                 for(int k = 0; k < elements.size(); k++) {
    562                      // For each key.
    563                      ElementWrapper element = (ElementWrapper) elements.get(k);
    564                      if(!known_elements.contains(element)) {
    565                           Metadata data = new Metadata(element);
    566                           int index = add(unassigned_metadata, data);
    567                           // Inform everyone that the model has changed, but only if it affects the current view.
    568                           //if(current_view == SHOW_UNASSIGNED) {
    569                           //    fireTableRowsInserted(index, index);
    570                           //}
    571                           //else if(current_view == SHOW_ALL) {
    572                           if((index = current_metadata.indexOf(data)) == -1) {
    573                                 index = add(current_metadata, data);
    574                                 fireTableRowsInserted(index, index);
    575                           }
    576                           else {
    577                                 fireTableRowsUpdated(index, index);
    578                           }
    579                           //}
    580                      }
    581                      //activity_bar.setValue(activity_bar.getValue() + 1);
    582                      Gatherer.g_man.metaedit_pane.validateMetadataTable();
    583                 }
     561        for(int k = 0; k < elements.size(); k++) {
     562        // For each key.
     563        ElementWrapper element = (ElementWrapper) elements.get(k);
     564        if(!known_elements.contains(element)) {
     565            Metadata data = new Metadata(element);
     566            int index = add(unassigned_metadata, data);
     567            // Inform everyone that the model has changed, but only if it affects the current view.
     568            //if(current_view == SHOW_UNASSIGNED) {
     569            //  fireTableRowsInserted(index, index);
     570            //}
     571            //else if(current_view == SHOW_ALL) {
     572            if((index = current_metadata.indexOf(data)) == -1) {
     573            index = add(current_metadata, data);
     574            fireTableRowsInserted(index, index);
     575            }
     576            else {
     577            fireTableRowsUpdated(index, index);
     578            }
     579            //}
     580        }
     581        //activity_bar.setValue(activity_bar.getValue() + 1);
     582        Gatherer.g_man.metaedit_pane.validateMetadataTable();
     583        }
    584584                //long end = System.currentTimeMillis();
    585585                ///ystem.err.println("Took " + (end - start) + "ms to build table.");
     
    588588                //activity_bar.setValue(activity_bar.getMaximum());
    589589                //activity_bar.setString(Gatherer.dictionary.get("MetaEdit.Ready"));
    590                 Collections.sort(current_metadata, MSMUtils.METADATA_COMPARATOR);
    591                 fireTableDataChanged();
     590        Collections.sort(current_metadata, MSMUtils.METADATA_COMPARATOR);
     591        fireTableDataChanged();
    592592                // Finally complete
    593                 complete = true;
     593        complete = true;
    594594                // If in the in between we've been asked to select a certain metadata, we action that now.
    595                 if(selected_metadata != null) {
    596                      setSelectedMetadata(selected_metadata);
    597                 }
    598           }
    599 
    600           /** For some reason contains doesn't always work. It appear not to use equals() properly, as ElementWrappers need to compare themselves by their string content as other data members are nearly always different even between to ElementWrappers generated from the same DOM Element. */
    601           private boolean contains(Vector elements, ElementWrapper element) {
    602                 if(element != null) {
    603                      for(int i = 0; i < elements.size(); i++) {
    604                           if(element.equals(elements.get(i))) {
    605                                 return true;
    606                           }
    607                      }
    608                 }
    609                 return false;
    610           }
    611 
    612           private void showInheritedMetadataWarning() {
    613                 if(!had_warning) {
    614                      had_warning = true;
    615                      Runnable task = new Runnable() {
    616                                 public void run() {
    617                                     WarningDialog dialog = new WarningDialog("warning.InheritedMetadata", false);
    618                                     dialog.display();
    619                                     dialog.dispose();
    620                                     dialog = null;
    621                                 }
    622                           };
    623                      SwingUtilities.invokeLater(task);
    624                 }
    625           }
    626     }
     595        if(selected_metadata != null) {
     596        setSelectedMetadata(selected_metadata);
     597        }
     598    }
     599
     600    /** For some reason contains doesn't always work. It appear not to use equals() properly, as ElementWrappers need to compare themselves by their string content as other data members are nearly always different even between to ElementWrappers generated from the same DOM Element. */
     601    private boolean contains(Vector elements, ElementWrapper element) {
     602        if(element != null) {
     603        for(int i = 0; i < elements.size(); i++) {
     604            if(element.equals(elements.get(i))) {
     605            return true;
     606            }
     607        }
     608        }
     609        return false;
     610    }
     611
     612    private void showInheritedMetadataWarning() {
     613        if(!had_warning) {
     614        had_warning = true;
     615        Runnable task = new Runnable() {
     616            public void run() {
     617                WarningDialog dialog = new WarningDialog("warning.InheritedMetadata", false);
     618                dialog.display();
     619                dialog.dispose();
     620                dialog = null;
     621            }
     622            };
     623        SwingUtilities.invokeLater(task);
     624        }
     625    }
     626    }
    627627}
  • trunk/gli/src/org/greenstone/gatherer/gui/table/TableCellRenderer.java

    r4293 r4366  
    5353
    5454public class TableCellRenderer
    55     extends DefaultTableCellRenderer {
     55    extends DefaultTableCellRenderer {
    5656
    57     private GTableModel model = null;
     57    private GTableModel model = null;
    5858
    59     public TableCellRenderer(GTableModel model) {
    60           super();
    61           this.model = model;
    62     }
     59    public TableCellRenderer(GTableModel model) {
     60    super();
     61    this.model = model;
     62    }
    6363
    64     /** Returns the default table cell renderer.
    65       * @param table The <strong>JTable</strong>.
    66       * @param value The value to assign to the cell at [row, column] as an <strong>Object</strong>.
    67       * @param isSelected <i>true</i> if cell is selected.
    68       * @param row The row of the cell to render as an <i>int</i>.
    69       * @param column The column of the cell to render as an <i>int</i>.
    70       * @param hasFocus <i>true</i> if cell has focus, render cell appropriately. For example, put a special border on the cell, if the cell can be edited, render in the color used to indicate editing.
    71       * @return The default table cell renderer <strong>Component</strong>.
    72       */
    73     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    74           JLabel renderer = null;
    75           if(value instanceof File) {
    76                 if(value != null) {
    77                      if(isSelected && hasFocus) {
    78                           Metadata data = model.getMetadataAtRow(row);
    79                           Gatherer.g_man.metaedit_pane.setSelection((File)value);
    80                           Gatherer.g_man.metaedit_pane.setSelectedMetadata(data);
    81                      }
    82                      renderer = new JLabel(Utility.getImage("upfolder.gif"));
    83                 }
    84           }
    85           if(renderer == null) {
    86                 renderer = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    87           }
    88           // Set up the component
    89           renderer.setOpaque(true);
    90           // Foreground
    91           if(model.isCommon(row)) {
    92                 renderer.setForeground(Color.black);
    93           }
    94           else {
    95                 renderer.setForeground(Color.gray);
    96           }
    97           // Background
    98           if(column <= 1) {
    99                 if(isSelected) {
    100                      renderer.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", true));
    101                 }
    102                 else {
    103                      renderer.setBackground(Gatherer.config.getColor("coloring.collection_heading_background", true));
    104                 }
    105           }
    106           else {
    107                 if(isSelected) {
    108                      renderer.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", true));
    109                 }
    110                 else {
    111                      renderer.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", true));
    112                 }
    113           }
    114           // Finally the 3rd column of cells never paint focus.
    115           if(column == 2) {
    116                 renderer.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
    117           }
    118           return renderer;
    119     }
     64    /** Returns the default table cell renderer.
     65     * @param table The <strong>JTable</strong>.
     66     * @param value The value to assign to the cell at [row, column] as an <strong>Object</strong>.
     67     * @param isSelected <i>true</i> if cell is selected.
     68     * @param row The row of the cell to render as an <i>int</i>.
     69     * @param column The column of the cell to render as an <i>int</i>.
     70     * @param hasFocus <i>true</i> if cell has focus, render cell appropriately. For example, put a special border on the cell, if the cell can be edited, render in the color used to indicate editing.
     71     * @return The default table cell renderer <strong>Component</strong>.
     72     */
     73    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     74    JLabel renderer = null;
     75    if(value instanceof File) {
     76        if(value != null) {
     77        if(isSelected && hasFocus) {
     78            Metadata data = model.getMetadataAtRow(row);
     79            Gatherer.g_man.metaedit_pane.setSelection((File)value);
     80            Gatherer.g_man.metaedit_pane.setSelectedMetadata(data);
     81        }
     82        renderer = new JLabel(Utility.getImage("upfolder.gif"));
     83        }
     84    }
     85    if(renderer == null) {
     86        renderer = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     87    }
     88    // Set up the component
     89    renderer.setOpaque(true);
     90    // Foreground
     91    if(model.isCommon(row)) {
     92        renderer.setForeground(Color.black);
     93    }
     94    else {
     95        renderer.setForeground(Color.gray);
     96    }
     97    // Background
     98    if(column <= 1) {
     99        if(isSelected) {
     100        renderer.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", true));
     101        }
     102        else {
     103        renderer.setBackground(Gatherer.config.getColor("coloring.collection_heading_background", true));
     104        }
     105    }
     106    else {
     107        if(isSelected) {
     108        renderer.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", true));
     109        }
     110        else {
     111        renderer.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", true));
     112        }
     113    }
     114    // Finally the 3rd column of cells never paint focus.
     115    if(column == 2) {
     116        renderer.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
     117    }
     118    return renderer;
     119    }
    120120}
  • trunk/gli/src/org/greenstone/gatherer/gui/tree/DragTree.java

    r4313 r4366  
    2121
    2222public class DragTree
    23     extends JTree
    24     implements Autoscroll, DragGestureListener, DragSourceListener, DropTargetListener, DragComponent, TreeSelectionListener {
    25     /** The normal background color. */
    26     private Color background_color;
    27     /** The normal foreground color. */
    28     private Color foreground_color;
    29     /** The Group this component belongs to. */
    30     private DragGroup group;
    31     /** The image to use for the disabled background. */
    32     private ImageIcon disabled_background;
    33     /** The image to use for a normal background. */
    34     private ImageIcon normal_background;
    35     /** The icon to use for multiple node drag'n'drops. We decided against using the windows paradigm or a block of x horizontal lines for x files. */
    36     private ImageIcon multiple_icon = new ImageIcon("resource"+File.separator+"multiple.gif");
    37     /** The default drag action, although its not that important as we provide custom icons during drags. */
    38     private int drag_action = DnDConstants.ACTION_MOVE;
    39     /** The location of the last ghost drawn, so that we can repair the 'spoilt' area. */
    40     private Point pt_last = null;
    41     /** The region borderer by the lower cue line. */
    42     private Rectangle lower_cue_line;
    43     /** The region covered by the drag ghost icon. */
    44     private Rectangle ra_ghost = new Rectangle();
    45     /** The region borderer by the upper cue line. */
    46     private Rectangle upper_cue_line;
    47     /** The identifying name of this Tree. */
    48     private String name;
    49     /** The last tree path the drag was hovered over. */
    50     private TreePath previous_path = null;
    51     static private final Color TRANSPARENT_COLOR = new Color(0,0,0,0);
    52     /** The distance from the edge of the current view within the scroll bar which if entered causes the view to scroll. */
    53     static private final int AUTOSCROLL_MARGIN = 12;
    54 
    55     public DragTree(String name, String background_name) {
    56           super();
    57           init(name, background_name);
    58     }
    59 
    60     public DragTree(String name, TreeModel model, String background_name) {
    61           super(model);
    62           init(name, background_name);
    63           // Connection
    64           setModel(model);
    65     }
    66 
    67     public void init(String name, String background_name) {
    68           // Init
    69           this.name = name;
    70           if(background_name != null) {
    71                 this.disabled_background = new ImageIcon("background.gif");
    72                 this.normal_background = new ImageIcon(background_name);
    73           }
    74 
    75           // Creation
    76           this.putClientProperty("JTree.lineStyle", "Angled");
    77           this.setAutoscrolls(true);
    78           this.setEditable(false);
    79           this.setLargeModel(true);
    80           this.setOpaque(true);
    81           this.setSelectionModel(new DragTreeSelectionModel(this));
    82           // Connection
    83           addTreeSelectionListener(this);
    84 
    85           DragTreeCellRenderer renderer = new DragTreeCellRenderer();
    86           //make the renderer paint nodes as transparent when not selected
    87           //renderer.setBackgroundNonSelectionColor(new Color(0,0,0,0));
    88           setCellRenderer(renderer);
     23    extends JTree
     24    implements Autoscroll, DragGestureListener, DragSourceListener, DropTargetListener, DragComponent, TreeSelectionListener {
     25    /** The normal background color. */
     26    private Color background_color;
     27    /** The normal foreground color. */
     28    private Color foreground_color;
     29    /** The Group this component belongs to. */
     30    private DragGroup group;
     31    /** The image to use for the disabled background. */
     32    private ImageIcon disabled_background;
     33    /** The image to use for a normal background. */
     34    private ImageIcon normal_background;
     35    /** The icon to use for multiple node drag'n'drops. We decided against using the windows paradigm or a block of x horizontal lines for x files. */
     36    private ImageIcon multiple_icon = new ImageIcon("resource"+File.separator+"multiple.gif");
     37    /** The default drag action, although its not that important as we provide custom icons during drags. */
     38    private int drag_action = DnDConstants.ACTION_MOVE;
     39    /** The location of the last ghost drawn, so that we can repair the 'spoilt' area. */
     40    private Point pt_last = null;
     41    /** The region borderer by the lower cue line. */
     42    private Rectangle lower_cue_line;
     43    /** The region covered by the drag ghost icon. */
     44    private Rectangle ra_ghost = new Rectangle();
     45    /** The region borderer by the upper cue line. */
     46    private Rectangle upper_cue_line;
     47    /** The identifying name of this Tree. */
     48    private String name;
     49    /** The last tree path the drag was hovered over. */
     50    private TreePath previous_path = null;
     51    static private final Color TRANSPARENT_COLOR = new Color(0,0,0,0);
     52    /** The distance from the edge of the current view within the scroll bar which if entered causes the view to scroll. */
     53    static private final int AUTOSCROLL_MARGIN = 12;
     54
     55    public DragTree(String name, String background_name) {
     56    super();
     57    init(name, background_name);
     58    }
     59
     60    public DragTree(String name, TreeModel model, String background_name) {
     61    super(model);
     62    init(name, background_name);
     63    // Connection
     64    setModel(model);
     65    }
     66
     67    public void init(String name, String background_name) {
     68    // Init
     69    this.name = name;
     70    if(background_name != null) {
     71        this.disabled_background = new ImageIcon("background.gif");
     72        this.normal_background = new ImageIcon(background_name);
     73    }
     74
     75    // Creation
     76    this.putClientProperty("JTree.lineStyle", "Angled");
     77    this.setAutoscrolls(true);
     78    this.setEditable(false);
     79    this.setLargeModel(true);
     80    this.setOpaque(true);
     81    this.setSelectionModel(new DragTreeSelectionModel(this));
     82    // Connection
     83    addTreeSelectionListener(this);
     84
     85    DragTreeCellRenderer renderer = new DragTreeCellRenderer();
     86    //make the renderer paint nodes as transparent when not selected
     87    //renderer.setBackgroundNonSelectionColor(new Color(0,0,0,0));
     88    setCellRenderer(renderer);
    8989
    9090          // Drag'n'drop Setup
    9191          // Drag source setup.
    92           DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this, drag_action, this);
    93           // Drop destination setup.
    94           new DropTarget(this, drag_action, this, true);
    95     }
    96 
    97     // Autoscroll Interface - Scroll because the mouse cursor is in our scroll zone.<br>
    98     // The following code was borrowed from the book:<br>
    99     //              Java Swing<br>
    100     //              By Robert Eckstein, Marc Loy & Dave Wood<br>
    101     //              Paperback - 1221 pages 1 Ed edition (September 1998)<br>
    102     //              O'Reilly & Associates; ISBN: 156592455X<br>
    103     // The relevant chapter of which can be found at:<br>
    104     //              http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf<br>
    105     // But I've probably tortured it beyond all recognition anyway.
    106     public void autoscroll(Point pt) {
    107           // Figure out which row we're on.
    108           int row = getRowForLocation(pt.x, pt.y);
    109           // If we are not on a row then ignore this autoscroll request
    110           if (row < 0) return;
    111           Rectangle bounds = getBounds();// Yes, scroll up one row
    112           // Now decide if the row is at the top of the screen or at the bottom. We do this to make the previous row (or the next row) visible as appropriate. If we're at the absolute top or bottom, just return the first or last row respectively.
    113           // Is row at top of screen?
    114           if(pt.y + bounds.y <= AUTOSCROLL_MARGIN) {
     92    DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this, drag_action, this);
     93    // Drop destination setup.
     94    new DropTarget(this, drag_action, this, true);
     95    }
     96
     97    // Autoscroll Interface - Scroll because the mouse cursor is in our scroll zone.<br>
     98    // The following code was borrowed from the book:<br>
     99    //              Java Swing<br>
     100    //              By Robert Eckstein, Marc Loy & Dave Wood<br>
     101    //              Paperback - 1221 pages 1 Ed edition (September 1998)<br>
     102    //              O'Reilly & Associates; ISBN: 156592455X<br>
     103    // The relevant chapter of which can be found at:<br>
     104    //              http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf<br>
     105    // But I've probably tortured it beyond all recognition anyway.
     106    public void autoscroll(Point pt) {
     107    // Figure out which row we're on.
     108    int row = getRowForLocation(pt.x, pt.y);
     109    // If we are not on a row then ignore this autoscroll request
     110    if (row < 0) return;
     111    Rectangle bounds = getBounds();// Yes, scroll up one row
     112    // Now decide if the row is at the top of the screen or at the bottom. We do this to make the previous row (or the next row) visible as appropriate. If we're at the absolute top or bottom, just return the first or last row respectively.
     113    // Is row at top of screen?
     114    if(pt.y + bounds.y <= AUTOSCROLL_MARGIN) {
    115115                // Yes, scroll up one row
    116                 if(row <= 0) {
    117                      row = 0;
    118                 }
    119                 else {
    120                      row = row - 1;
    121                 }
    122           }
    123           else {
     116        if(row <= 0) {
     117        row = 0;
     118        }
     119        else {
     120        row = row - 1;
     121        }
     122    }
     123    else {
    124124                // No, scroll down one row
    125                 if(row < getRowCount() - 1) {
    126                      row = row + 1;
    127                 }
    128           }
    129           this.scrollRowToVisible(row);
    130     }
    131 
    132     /** In order for the appearance to be consistant, given we may be in the situation where the pointer has left our focus but the ghost remains, this method allows other members of the GGroup to tell this component to clear its ghost.
    133       */
    134     public void clearGhost() {
    135           // Erase the last ghost image and cue line
    136           paintImmediately(ra_ghost.getBounds());
    137     }
    138 
    139     /** Any implementation of DragSourceListener must include this method so we can be notified when the drag event ends (somewhere else), which will in turn remove actions.
     125        if(row < getRowCount() - 1) {
     126        row = row + 1;
     127        }
     128    }
     129    this.scrollRowToVisible(row);
     130    }
     131
     132    /** In order for the appearance to be consistant, given we may be in the situation where the pointer has left our focus but the ghost remains, this method allows other members of the GGroup to tell this component to clear its ghost.
     133      */
     134    public void clearGhost() {
     135    // Erase the last ghost image and cue line
     136    paintImmediately(ra_ghost.getBounds());
     137    }
     138
     139    /** Any implementation of DragSourceListener must include this method so we can be notified when the drag event ends (somewhere else), which will in turn remove actions.
    140140      * @param event A <strong>DragSourceDropEvent</strong> containing all the information about the end of the drag event.
    141141      */
    142     public void dragDropEnd(DragSourceDropEvent event) {
    143           if(event.getDropSuccess()) {
     142    public void dragDropEnd(DragSourceDropEvent event) {
     143    if(event.getDropSuccess()) {
    144144                // Do whatever I do when the drop is successful.
    145           }
    146     }
    147      /** Any implementation of DragSourceListener must include this method so we can be notified when the drag focus enters this component.
     145    }
     146    }
     147   /** Any implementation of DragSourceListener must include this method so we can be notified when the drag focus enters this component.
    148148      * @param event A <strong>DragSourceDragEvent</strong> containing all the information
    149149      * about the drag event.
    150150      */
    151     public void dragEnter(DragSourceDragEvent event) {
    152           // Handled elsewhere.
    153     }
    154      /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus enters this component, which in this case is to grab focus from within our group.
     151    public void dragEnter(DragSourceDragEvent event) {
     152    // Handled elsewhere.
     153    }
     154   /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus enters this component, which in this case is to grab focus from within our group.
    155155      * @param event A <strong>DropTargetDragEvent</strong> containing all the information about the drag event.
    156156      */
    157     public void dragEnter(DropTargetDragEvent event) {
    158           group.grabFocus(this);
    159     }
    160     /** Any implementation of DragSourceListener must include this method so we can be notified when the drag focus leaves this component.
     157    public void dragEnter(DropTargetDragEvent event) {
     158    group.grabFocus(this);
     159    }
     160    /** Any implementation of DragSourceListener must include this method so we can be notified when the drag focus leaves this component.
    161161      * @param event A <strong>DragSourceEvent</strong> containing all the information about the drag event.
    162162      */
    163     public void dragExit(DragSourceEvent event) {
    164           clearGhost();
    165     }
    166 
    167     /** Any implementation of DropTargetListener must include this method
     163    public void dragExit(DragSourceEvent event) {
     164    clearGhost();
     165    }
     166
     167    /** Any implementation of DropTargetListener must include this method
    168168      * so we can be notified when the drag focus leaves this component.
    169169      * @param event A DropTargetEvent containing all the information
    170170      * about the drag event.
    171171      */
    172     public void dragExit(DropTargetEvent event) {
    173           clearGhost();
    174     }
    175 
    176     /** Any implementation of DragGestureListener must include this method
     172    public void dragExit(DropTargetEvent event) {
     173    clearGhost();
     174    }
     175
     176    /** Any implementation of DragGestureListener must include this method
    177177      * so we can be notified when a drag action has been noticed, thus a
    178178      * drag action has begun.
     
    180180      * the drag event.
    181181      */
    182     public void dragGestureRecognized(DragGestureEvent event) {
    183           // Disable editing, unless you want to have the edit box pop-up part way through dragging.
    184           this.setEditable(false);
    185           // We need this to find one of the selected nodes.
    186           Point origin = event.getDragOrigin();
    187           TreePath path = this.getPathForLocation(origin.x, origin.y);
    188           // Taking into account our delayed model of selection, it is possible the user has performed a select and drag in one click. Here we utilize the Windows paradigm like so: If the node at the origin of the drag and drop is already in our selection then we perform multiple drag and drop. Otherwise we recognise that this is a distinct drag-drop and move only the origin node.
    189           if(!isPathSelected(path)) {
    190                 ((DragTreeSelectionModel)selectionModel).setImmediate(true);
    191                 setSelectionPath(path);
    192           }
    193           // Now update the selection stored as far as the group is concerned.
    194           group.setSelection(getSelectionPaths());
    195           group.setSource(this);
    196           // First grab ghost.
    197           group.grabFocus(this);
    198           // Ghost Image stuff.
    199           if(path != null) {
    200                 Rectangle rect = this.getPathBounds(path);
    201                 group.mouse_offset = new Point(origin.x - rect.x, origin.y - rect.y);
     182    public void dragGestureRecognized(DragGestureEvent event) {
     183    // Disable editing, unless you want to have the edit box pop-up part way through dragging.
     184    this.setEditable(false);
     185    // We need this to find one of the selected nodes.
     186    Point origin = event.getDragOrigin();
     187    TreePath path = this.getPathForLocation(origin.x, origin.y);
     188    // Taking into account our delayed model of selection, it is possible the user has performed a select and drag in one click. Here we utilize the Windows paradigm like so: If the node at the origin of the drag and drop is already in our selection then we perform multiple drag and drop. Otherwise we recognise that this is a distinct drag-drop and move only the origin node.
     189    if(!isPathSelected(path)) {
     190        ((DragTreeSelectionModel)selectionModel).setImmediate(true);
     191        setSelectionPath(path);
     192    }
     193    // Now update the selection stored as far as the group is concerned.
     194    group.setSelection(getSelectionPaths());
     195    group.setSource(this);
     196    // First grab ghost.
     197    group.grabFocus(this);
     198    // Ghost Image stuff.
     199    if(path != null) {
     200        Rectangle rect = this.getPathBounds(path);
     201        group.mouse_offset = new Point(origin.x - rect.x, origin.y - rect.y);
    202202                // Create the ghost image.
    203203                // Retrieve the selected files.
    204                 int selection_count = getSelectionCount();
    205                 if(selection_count > 0) {
    206                      JLabel label;
    207                      if(selection_count == 1) {
    208                           TreePath node_path = getSelectionPath();
    209                           FileNode node = (FileNode) path.getLastPathComponent();
    210                           label = new JLabel(node.toString(), ((DefaultTreeCellRenderer)getCellRenderer()).getLeafIcon(), JLabel.CENTER);
    211                      }
    212                      else {
    213                           String title = getSelectionCount() + " files";
    214                           label = new JLabel(title, ((DefaultTreeCellRenderer)getCellRenderer()).getClosedIcon(), JLabel.CENTER);
    215                           title = null;
    216                      }
    217                      // The layout manager normally does this.
    218                      Dimension label_size = label.getPreferredSize();
    219                      label.setSize(label_size);
    220                      label.setBackground(TRANSPARENT_COLOR);
    221                      label.setOpaque(true);
    222                      // Get a buffered image of the selection for dragging a ghost image.
    223                      group.image_ghost = new BufferedImage(label_size.width, label_size.height, BufferedImage.TYPE_INT_ARGB_PRE);
    224                      label_size = null;
    225                      // Get a graphics context for this image.
    226                      Graphics2D g2 = group.image_ghost.createGraphics();
    227                      // Make the image ghostlike
    228                      g2.setComposite(AlphaComposite.getInstance (AlphaComposite.SRC, 0.5f));
    229                      // Ask the cell renderer to paint itself into the BufferedImage
    230                      label.paint(g2);
    231                      g2 = null;
    232                      label = null;
    233                      try {
    234                           event.startDrag(new Cursor(Cursor.DEFAULT_CURSOR), group.image_ghost, new Point(5,5), new StringSelection("dummy"), this);
    235                           //dragging = true;
    236                      }
    237                      catch(Exception error) {
    238                           error.printStackTrace();
    239                      }
    240                 }
    241           }
    242     }
    243 
    244     /** Implementation side-effect.
     204        int selection_count = getSelectionCount();
     205        if(selection_count > 0) {
     206        JLabel label;
     207        if(selection_count == 1) {
     208            TreePath node_path = getSelectionPath();
     209            FileNode node = (FileNode) path.getLastPathComponent();
     210            label = new JLabel(node.toString(), ((DefaultTreeCellRenderer)getCellRenderer()).getLeafIcon(), JLabel.CENTER);
     211        }
     212        else {
     213            String title = getSelectionCount() + " files";
     214            label = new JLabel(title, ((DefaultTreeCellRenderer)getCellRenderer()).getClosedIcon(), JLabel.CENTER);
     215            title = null;
     216        }
     217        // The layout manager normally does this.
     218        Dimension label_size = label.getPreferredSize();
     219        label.setSize(label_size);
     220        label.setBackground(TRANSPARENT_COLOR);
     221        label.setOpaque(true);
     222        // Get a buffered image of the selection for dragging a ghost image.
     223        group.image_ghost = new BufferedImage(label_size.width, label_size.height, BufferedImage.TYPE_INT_ARGB_PRE);
     224        label_size = null;
     225        // Get a graphics context for this image.
     226        Graphics2D g2 = group.image_ghost.createGraphics();
     227        // Make the image ghostlike
     228        g2.setComposite(AlphaComposite.getInstance (AlphaComposite.SRC, 0.5f));
     229        // Ask the cell renderer to paint itself into the BufferedImage
     230        label.paint(g2);
     231        g2 = null;
     232        label = null;
     233        try {
     234            event.startDrag(new Cursor(Cursor.DEFAULT_CURSOR), group.image_ghost, new Point(5,5), new StringSelection("dummy"), this);
     235            //dragging = true;
     236        }
     237        catch(Exception error) {
     238            error.printStackTrace();
     239        }
     240        }
     241    }
     242    }
     243
     244    /** Implementation side-effect.
    245245      * @param event A DragSourceDragEvent containing all the information about the drag event.
    246246      */
    247     public void dragOver(DragSourceDragEvent event) {
    248     }
    249 
    250     /** Any implementation of DropTargetListener must include this method
     247    public void dragOver(DragSourceDragEvent event) {
     248    }
     249
     250    /** Any implementation of DropTargetListener must include this method
    251251      * so we can be notified when the drag moves in this component.
    252252      * @param event A DropTargetDragEvent containing all the information
    253253      * about the drag event.
    254254      */
    255     public void dragOver(DropTargetDragEvent event) {
    256           // Draw the mouse ghost
    257           Graphics2D g2 = (Graphics2D) getGraphics();
    258           Point pt = event.getLocation();
    259           if(pt_last != null && pt.equals(pt_last)) {
    260                 return;
    261           }
    262           pt_last = pt;
    263           if(!DragSource.isDragImageSupported()) {
     255    public void dragOver(DropTargetDragEvent event) {
     256    // Draw the mouse ghost
     257    Graphics2D g2 = (Graphics2D) getGraphics();
     258    Point pt = event.getLocation();
     259    if(pt_last != null && pt.equals(pt_last)) {
     260        return;
     261    }
     262    pt_last = pt;
     263    if(!DragSource.isDragImageSupported()) {
    264264                // Erase the last ghost image and cue line
    265                 paintImmediately(ra_ghost.getBounds());
     265        paintImmediately(ra_ghost.getBounds());
    266266                // Remember where you are about to draw the new ghost image
    267                 ra_ghost.setRect(pt.x - group.mouse_offset.x, pt.y - group.mouse_offset.y, group.image_ghost.getWidth(), group.image_ghost.getHeight());
     267        ra_ghost.setRect(pt.x - group.mouse_offset.x, pt.y - group.mouse_offset.y, group.image_ghost.getWidth(), group.image_ghost.getHeight());
    268268                // Draw the ghost image
    269                 g2.drawImage(group.image_ghost, AffineTransform.getTranslateInstance(ra_ghost.getX(), ra_ghost.getY()), null);
    270           }
    271           // Now we highlight the target node if it is a valid drop target. Of course we don't bother if we are still over a node which has already been identified as to whether its a drop target.
    272           TreePath target_path = this.getPathForLocation(pt.x, pt.y);
    273           if(previous_path == null || target_path != null && !target_path.equals(previous_path)) {
     269        g2.drawImage(group.image_ghost, AffineTransform.getTranslateInstance(ra_ghost.getX(), ra_ghost.getY()), null);
     270    }
     271    // Now we highlight the target node if it is a valid drop target. Of course we don't bother if we are still over a node which has already been identified as to whether its a drop target.
     272    TreePath target_path = this.getPathForLocation(pt.x, pt.y);
     273    if(previous_path == null || target_path != null && !target_path.equals(previous_path)) {
    274274                // Immediately clear the old cue lines.
    275                 if(upper_cue_line != null && lower_cue_line != null) {
    276                      paintImmediately(upper_cue_line.getBounds());
    277                      paintImmediately(lower_cue_line.getBounds());
    278                 }
    279                 if(isValidDrop(target_path)) {
    280                      ///ystem.err.println("Valid. Painting cues.");
    281                      // Get the drop target's bounding rectangle
    282                      Rectangle raPath = getPathBounds(target_path);
    283                      // Cue line bounds (2 pixels beneath the drop target)
    284                      upper_cue_line = new Rectangle(0,  raPath.y + (int)raPath.getHeight(), getWidth(), 2);
    285                      lower_cue_line = new Rectangle(0,  raPath.y, getWidth(), 2);
    286                      g2.setColor(((DefaultTreeCellRenderer)cellRenderer).getBackgroundSelectionColor()); // The cue line color
    287                      g2.fill(upper_cue_line);         // Draw the cue line
    288                      g2.fill(lower_cue_line);
    289                 }
    290                 else {
    291                      upper_cue_line = null;
    292                      lower_cue_line = null;
    293                 }
    294           }
    295     }
    296 
    297     /** Any implementation of DropTargetListener must include this method
     275        if(upper_cue_line != null && lower_cue_line != null) {
     276        paintImmediately(upper_cue_line.getBounds());
     277        paintImmediately(lower_cue_line.getBounds());
     278        }
     279        if(isValidDrop(target_path)) {
     280        ///ystem.err.println("Valid. Painting cues.");
     281        // Get the drop target's bounding rectangle
     282        Rectangle raPath = getPathBounds(target_path);
     283        // Cue line bounds (2 pixels beneath the drop target)
     284        upper_cue_line = new Rectangle(0,  raPath.y + (int)raPath.getHeight(), getWidth(), 2);
     285        lower_cue_line = new Rectangle(0,  raPath.y, getWidth(), 2);
     286        g2.setColor(((DefaultTreeCellRenderer)cellRenderer).getBackgroundSelectionColor()); // The cue line color
     287        g2.fill(upper_cue_line);         // Draw the cue line
     288        g2.fill(lower_cue_line);
     289        }
     290        else {
     291        upper_cue_line = null;
     292        lower_cue_line = null;
     293        }
     294    }
     295    }
     296
     297    /** Any implementation of DropTargetListener must include this method
    298298      * so we can be notified when the drag ends, ie the transferable is
    299299      * dropped.
     
    301301      * about the end of the drag event.
    302302      */
    303     public void drop(DropTargetDropEvent event) {
    304           ///start = System.currentTimeMillis();
    305           ///ystem.err.println("Drop target drop: " + this);
    306           event.acceptDrop(drag_action);
    307           if(!name.equals(Utility.WORKSPACE_TREE)) {
     303    public void drop(DropTargetDropEvent event) {
     304    ///start = System.currentTimeMillis();
     305    ///ystem.err.println("Drop target drop: " + this);
     306    event.acceptDrop(drag_action);
     307    if(!name.equals(Utility.WORKSPACE_TREE)) {
    308308                // Determine what node we dropped over.
    309                 Point pt = event.getLocation();
    310                 TreePath target_path = this.getPathForLocation(pt.x, pt.y);
    311                 FileNode target = null;
    312                 if(target_path != null) {
    313                      if(isValidDrop(target_path)) {
    314                           target = (FileNode) target_path.getLastPathComponent();
    315                      }
    316                      else {
    317                           // Warn that this is an invalid drop.
    318                           JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.InvalidTarget"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
    319                      }
    320                 }
    321                 else {
    322                      target = (FileNode) getModel().getRoot();
    323                 }
    324                 target_path = null;
    325                 pt = null;
    326                 if(target != null) {
    327                      ///ystem.err.println("Valid drop.");
    328                      TreePath[] selection = group.getSelection();
    329                      if(target != null) {
    330                           FileNode[] source_nodes = new FileNode[selection.length];
    331                           for(int i = 0; i < source_nodes.length; i++) {
    332                                 source_nodes[i] = (FileNode) selection[i].getLastPathComponent();
    333                           }
    334                           Gatherer.f_man.action(group.getSource(), source_nodes, this, target);
    335                           source_nodes = null;
    336                      }
    337                      group.setSelection(null);
    338                      group.setSource(null);
    339                      selection = null;
    340                      target = null;
    341                 }
    342           }
    343           else {
     309        Point pt = event.getLocation();
     310        TreePath target_path = this.getPathForLocation(pt.x, pt.y);
     311        FileNode target = null;
     312        if(target_path != null) {
     313        if(isValidDrop(target_path)) {
     314            target = (FileNode) target_path.getLastPathComponent();
     315        }
     316        else {
     317            // Warn that this is an invalid drop.
     318            JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.InvalidTarget"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
     319        }
     320        }
     321        else {
     322        target = (FileNode) getModel().getRoot();
     323        }
     324        target_path = null;
     325        pt = null;
     326        if(target != null) {
     327        ///ystem.err.println("Valid drop.");
     328        TreePath[] selection = group.getSelection();
     329        if(target != null) {
     330            FileNode[] source_nodes = new FileNode[selection.length];
     331            for(int i = 0; i < source_nodes.length; i++) {
     332            source_nodes[i] = (FileNode) selection[i].getLastPathComponent();
     333            }
     334            Gatherer.f_man.action(group.getSource(), source_nodes, this, target);
     335            source_nodes = null;
     336        }
     337        group.setSelection(null);
     338        group.setSource(null);
     339        selection = null;
     340        target = null;
     341        }
     342    }
     343    else {
    344344                // Warn that this is an invalid drop.
    345                 JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.ReadOnlyTarget"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
    346           }
    347           // Clear up the group.image_ghost
    348           paintImmediately(ra_ghost.getBounds());
    349           event.getDropTargetContext().dropComplete(true);
    350     }
    351 
    352     /** Any implementation of DragSourceListener must include this method
     345        JOptionPane.showMessageDialog(Gatherer.g_man, Gatherer.dictionary.get("FileActions.ReadOnlyTarget"), Gatherer.dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
     346    }
     347    // Clear up the group.image_ghost
     348    paintImmediately(ra_ghost.getBounds());
     349    event.getDropTargetContext().dropComplete(true);
     350    }
     351
     352    /** Any implementation of DragSourceListener must include this method
    353353      * so we can be notified when the action to be taken upon drop changes.
    354354      * @param event A DragSourceDragEvent containing all the information
    355355      * about the drag event.
    356356      */
    357     public void dropActionChanged(DragSourceDragEvent event) {
    358     }
    359 
    360     /** Any implementation of DropTargetListener must include this method
     357    public void dropActionChanged(DragSourceDragEvent event) {
     358    }
     359
     360    /** Any implementation of DropTargetListener must include this method
    361361      * so we can be notified when the action to be taken upon drop changes.
    362362      * @param event A DropTargetDragEvent containing all the information
    363363      * about the drag event.
    364364      */
    365     public void dropActionChanged(DropTargetDragEvent event) {
    366     }
    367 
    368     /** Used to notify this component that it has gained focus. It should
     365    public void dropActionChanged(DropTargetDragEvent event) {
     366    }
     367
     368    /** Used to notify this component that it has gained focus. It should
    369369      * make some effort to inform the user of this.
    370370      */
    371     public void gainFocus() {
    372           ///ystem.err.println("Gained focus: " + this);
    373           ((DragTreeCellRenderer)cellRenderer).gainFocus();
    374           repaint();
    375     }
    376 
    377     /** Autoscroll Interface...
     371    public void gainFocus() {
     372    ///ystem.err.println("Gained focus: " + this);
     373    ((DragTreeCellRenderer)cellRenderer).gainFocus();
     374    repaint();
     375    }
     376
     377    /** Autoscroll Interface...
    378378      * The following code was borrowed from the book:
    379379      *              Java Swing
     
    387387      * the tree is in. This makes it a bit messy.
    388388      */
    389     public Insets getAutoscrollInsets()
    390     {
    391           Rectangle raOuter = this.getBounds();
    392           Rectangle raInner = this.getParent().getBounds();
    393           return new Insets(raInner.y - raOuter.y + AUTOSCROLL_MARGIN,
    394                                   raInner.x - raOuter.x + AUTOSCROLL_MARGIN,
    395                                   raOuter.height - raInner.height - raInner.y + raOuter.y + AUTOSCROLL_MARGIN,
    396                                   raOuter.width - raInner.width - raInner.x + raOuter.x + AUTOSCROLL_MARGIN);
    397     }
    398 
    399     public String getSelectionDetails() {
    400           return ((DragTreeSelectionModel)selectionModel).getDetails();
    401     }
    402 
    403     public FileSystemModel getTreeModel() {
    404           return (FileSystemModel) getModel();
    405     }
    406 
    407     /** This method is used to inform this component when it loses focus,
     389    public Insets getAutoscrollInsets()
     390    {
     391    Rectangle raOuter = this.getBounds();
     392    Rectangle raInner = this.getParent().getBounds();
     393    return new Insets(raInner.y - raOuter.y + AUTOSCROLL_MARGIN,
     394              raInner.x - raOuter.x + AUTOSCROLL_MARGIN,
     395              raOuter.height - raInner.height - raInner.y + raOuter.y + AUTOSCROLL_MARGIN,
     396              raOuter.width - raInner.width - raInner.x + raOuter.x + AUTOSCROLL_MARGIN);
     397    }
     398
     399    public String getSelectionDetails() {
     400    return ((DragTreeSelectionModel)selectionModel).getDetails();
     401    }
     402
     403    public FileSystemModel getTreeModel() {
     404    return (FileSystemModel) getModel();
     405    }
     406
     407    /** This method is used to inform this component when it loses focus,
    408408      * and should indicate this somehow.
    409409      */
    410     public void loseFocus() {
    411           ///ystem.err.println("Lost focus: " + this);
    412           ((DragTreeCellRenderer)cellRenderer).loseFocus();
    413           repaint();
    414     }
    415 
    416     public void mapDirectory(File file, String title) {
    417           try {
    418                 ((FileSystemModel)treeModel).mapDirectory(file, title);
    419           }
    420           catch (Exception error) {
    421                 error.printStackTrace();
    422           }
    423     }
    424 
    425     public void paint(Graphics g) {
    426           if(disabled_background != null) {
    427                 int height = getSize().height;
    428                 int offset = 0;
    429                 ImageIcon background;
    430                 if(isEnabled()) {
    431                      background = normal_background;
    432                 }
    433                 else {
    434                      background = disabled_background;
    435                 }
    436                 while((height - offset) > 0) {
    437                      g.drawImage(background.getImage(), 0, offset, null);
    438                      offset = offset + background.getIconHeight();
    439                 }
    440                 background = null;
    441           }
    442           super.paint(g);
    443     }
    444 
    445     public void refresh(TreePath path) {
    446           ((FileSystemModel)treeModel).refresh(path);
    447     }
    448 
    449     public void setBackgroundNonSelectionColor(Color color) {
    450           background_color = color;
    451           if(isEnabled()) {
    452                 setBackground(color);
    453                 ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(color);
    454           }
    455           else {
    456                 setBackground(Color.lightGray);
    457                 ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(Color.lightGray);
    458           }
    459           repaint();
    460     }
    461 
    462     public void setBackgroundSelectionColor(Color color) {
    463           ((DefaultTreeCellRenderer)cellRenderer).setBackgroundSelectionColor(color);
    464             repaint();
    465     }
    466 
    467     /** Override the normal setEnabled so the Tree exhibits a little more
     410    public void loseFocus() {
     411    ///ystem.err.println("Lost focus: " + this);
     412    ((DragTreeCellRenderer)cellRenderer).loseFocus();
     413    repaint();
     414    }
     415
     416    public void mapDirectory(File file, String title) {
     417    try {
     418        ((FileSystemModel)treeModel).mapDirectory(file, title);
     419    }
     420    catch (Exception error) {
     421        error.printStackTrace();
     422    }
     423    }
     424
     425    public void paint(Graphics g) {
     426    if(disabled_background != null) {
     427        int height = getSize().height;
     428        int offset = 0;
     429        ImageIcon background;
     430        if(isEnabled()) {
     431        background = normal_background;
     432        }
     433        else {
     434        background = disabled_background;
     435        }
     436        while((height - offset) > 0) {
     437        g.drawImage(background.getImage(), 0, offset, null);
     438        offset = offset + background.getIconHeight();
     439        }
     440        background = null;
     441    }
     442    super.paint(g);
     443    }
     444
     445    public void refresh(TreePath path) {
     446    ((FileSystemModel)treeModel).refresh(path);
     447    }
     448
     449    public void setBackgroundNonSelectionColor(Color color) {
     450    background_color = color;
     451    if(isEnabled()) {
     452        setBackground(color);
     453        ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(color);
     454    }
     455    else {
     456        setBackground(Color.lightGray);
     457        ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(Color.lightGray);
     458    }
     459    repaint();
     460    }
     461
     462    public void setBackgroundSelectionColor(Color color) {
     463    ((DefaultTreeCellRenderer)cellRenderer).setBackgroundSelectionColor(color);
     464    repaint();
     465    }
     466
     467    /** Override the normal setEnabled so the Tree exhibits a little more
    468468      * change, which in this instance is the background colour changing.
    469469      * @param state Whether this GTree should be in an enabled state.
    470470      */
    471     public void setEnabled(boolean state) {
    472           super.setEnabled(state);
    473           clearSelection();
    474           // Change some colors
    475           if(state) {
    476                 setBackground(background_color);
    477                 ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(background_color);
    478                 ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(foreground_color);
    479           }
    480           else {
    481                 setBackground(Color.lightGray);
    482                 ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(Color.lightGray);
    483                 ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(Color.black);
    484           }
    485           repaint();
    486     }
    487 
    488     public void setGroup(DragGroup group) {
    489           this.group = group;
    490     }
    491 
    492     /** Determines whether the following selection attempts should go through the normal delayed selection model, or should happen immediately.*/
    493     public void setImmediate(boolean state) {
    494           ((DragTreeSelectionModel)selectionModel).setImmediate(state);
    495     }
    496 
    497     public void setModel(TreeModel model) {
    498           super.setModel(model);
    499           if(model instanceof FileSystemModel) {
    500                 FileSystemModel file_system_model = (FileSystemModel) model;
    501                 file_system_model.setTree(this);
    502                 addTreeExpansionListener(file_system_model);
    503                 addTreeWillExpandListener(file_system_model);
    504                 file_system_model = null;
    505           }
    506     }
    507 
    508     /** Ensure that that file node denoted by the given file is selected. */
    509     public void setSelection(File file) {
    510           // We know the file exists, and thus that it must exists somewhere in our tree hierarchy.
    511           // 1. Retrieve the root node of our tree.
    512           FileNode current = (FileNode) getModel().getRoot();
    513           // 2. Find that node in the file parents, keeping track of each intermediate file.
    514           ArrayList files = new ArrayList();
    515           while(file != null && !current.toString().equals(file.getName())) {
    516                 files.add(0, file);
    517                 file = file.getParentFile();
    518           }
    519           if(file == null) {
    520                 return;
    521           }
    522           // 3. While there are still remaining intermediate files.
    523           while(files.size() > 0) {
    524                 file = (File) files.remove(0);
     471    public void setEnabled(boolean state) {
     472    super.setEnabled(state);
     473    clearSelection();
     474    // Change some colors
     475    if(state) {
     476        setBackground(background_color);
     477        ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(background_color);
     478        ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(foreground_color);
     479    }
     480    else {
     481        setBackground(Color.lightGray);
     482        ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(Color.lightGray);
     483        ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(Color.black);
     484    }
     485    repaint();
     486    }
     487
     488    public void setGroup(DragGroup group) {
     489    this.group = group;
     490    }
     491
     492    /** Determines whether the following selection attempts should go through the normal delayed selection model, or should happen immediately.*/
     493    public void setImmediate(boolean state) {
     494    ((DragTreeSelectionModel)selectionModel).setImmediate(state);
     495    }
     496
     497    public void setModel(TreeModel model) {
     498    super.setModel(model);
     499    if(model instanceof FileSystemModel) {
     500        FileSystemModel file_system_model = (FileSystemModel) model;
     501        file_system_model.setTree(this);
     502        addTreeExpansionListener(file_system_model);
     503        addTreeWillExpandListener(file_system_model);
     504        file_system_model = null;
     505    }
     506    }
     507
     508    /** Ensure that that file node denoted by the given file is selected. */
     509    public void setSelection(File file) {
     510    // We know the file exists, and thus that it must exists somewhere in our tree hierarchy.
     511    // 1. Retrieve the root node of our tree.
     512    FileNode current = (FileNode) getModel().getRoot();
     513    // 2. Find that node in the file parents, keeping track of each intermediate file.
     514    ArrayList files = new ArrayList();
     515    while(file != null && !current.toString().equals(file.getName())) {
     516        files.add(0, file);
     517        file = file.getParentFile();
     518    }
     519    if(file == null) {
     520        return;
     521    }
     522    // 3. While there are still remaining intermediate files.
     523    while(files.size() > 0) {
     524        file = (File) files.remove(0);
    525525                // 3a. Find the next file in the current nodes children.
    526                 boolean found = false;
    527                 current.map();
    528                 for(int i = 0; !found && i < current.getChildCount(); i++) {
    529                      FileNode child = (FileNode) current.getChildAt(i);
    530                      if(child.toString().equals(file.getName())) {
    531                           // 3b. Make the current node this node (if found) and continue.
    532                           found = true;
    533                           current = child;
    534                      }
    535                 }
     526        boolean found = false;
     527        current.map();
     528        for(int i = 0; !found && i < current.getChildCount(); i++) {
     529        FileNode child = (FileNode) current.getChildAt(i);
     530        if(child.toString().equals(file.getName())) {
     531            // 3b. Make the current node this node (if found) and continue.
     532            found = true;
     533            current = child;
     534        }
     535        }
    536536                // 3c. If not found then return as this node can't exists somehow.
    537                 if(!found) {
    538                      return;
    539                 }
    540           }
    541           // 4. We should now have the desired node. Remember to make the selection immediate.
    542           TreePath path = new TreePath(current.getPath());
    543           setImmediate(true);
    544           setSelectionPath(path);
    545           setImmediate(false);
    546     }
    547 
    548     public void setTextNonSelectionColor(Color color) {
    549           foreground_color = color;
    550           if(isEnabled()) {
    551                 ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(color);
    552           }
    553           else {
    554                 ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(Color.black);
    555           }
    556           repaint();
    557     }
    558 
    559     public void setTextSelectionColor(Color color) {
    560           ((DefaultTreeCellRenderer)cellRenderer).setTextSelectionColor(color);
    561             repaint();
    562     }
    563 
    564     public String toString() {
    565           return name;
    566     }
    567 
    568     public void valueChanged(TreeSelectionEvent e) {
    569           if(group == null) {
     537        if(!found) {
     538        return;
     539        }
     540    }
     541    // 4. We should now have the desired node. Remember to make the selection immediate.
     542    TreePath path = new TreePath(current.getPath());
     543    setImmediate(true);
     544    setSelectionPath(path);
     545    setImmediate(false);
     546    }
     547
     548    public void setTextNonSelectionColor(Color color) {
     549    foreground_color = color;
     550    if(isEnabled()) {
     551        ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(color);
     552    }
     553    else {
     554        ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(Color.black);
     555    }
     556    repaint();
     557    }
     558
     559    public void setTextSelectionColor(Color color) {
     560    ((DefaultTreeCellRenderer)cellRenderer).setTextSelectionColor(color);
     561    repaint();
     562    }
     563
     564    public String toString() {
     565    return name;
     566    }
     567
     568    public void valueChanged(TreeSelectionEvent e) {
     569    if(group == null) {
    570570                ///ystem.err.println("Oh my god, this tree has no group: " + this);
    571           }
    572           else {
    573             group.grabFocus(this);
    574           }
    575           Gatherer.g_man.menu_bar.setMetaAuditSuffix(getSelectionDetails());
    576     }
    577 
    578     private boolean isValidDrop(TreePath target_path) {
    579           boolean valid = false;
    580           if(target_path != null) {
    581                 FileNode target_node = (FileNode) target_path.getLastPathComponent();
     571    }
     572    else {
     573        group.grabFocus(this);
     574    }
     575    Gatherer.g_man.menu_bar.setMetaAuditSuffix(getSelectionDetails());
     576    }
     577
     578    private boolean isValidDrop(TreePath target_path) {
     579    boolean valid = false;
     580    if(target_path != null) {
     581        FileNode target_node = (FileNode) target_path.getLastPathComponent();
    582582                // We can only continue testing if the node is a folder.
    583                 if(!target_node.isLeaf()) {
    584                      // Now we check if the node is readonly.
    585                      if(!target_node.isReadOnly()) {
    586                           // Finally we check the target path against the paths in the selection to ensure we are not adding to our own ancestors!
    587                           TreePath[] selection = group.getSelection();
    588                           boolean failed = false;
    589                           for(int i = 0; !failed && selection != null && i < selection.length; i++) {
    590                                 failed = selection[i].isDescendant(target_path);
    591                           }
    592                           // Having finally completed all the tests, we can highlight the drop target.
    593                           if(!failed) {
    594                                 valid = true;
    595                           }
    596                           else {
    597                                 ///ystem.err.println("Invalid. Target is descendant of itself.");
    598                           }
    599                      }
    600                      else {
    601                           ///ystem.err.println("Read only.");
    602                      }
    603                 }
    604                 else {
    605                      ///ystem.err.println("Leaf node. Children not allowed.");
    606                 }
    607                 previous_path = target_path;
    608           }
    609           else {
    610                 if(target_path == null) {
    611                      previous_path = null;
    612                 }
    613           }
    614           return valid;
    615     }
     583        if(!target_node.isLeaf()) {
     584        // Now we check if the node is readonly.
     585        if(!target_node.isReadOnly()) {
     586            // Finally we check the target path against the paths in the selection to ensure we are not adding to our own ancestors!
     587            TreePath[] selection = group.getSelection();
     588            boolean failed = false;
     589            for(int i = 0; !failed && selection != null && i < selection.length; i++) {
     590            failed = selection[i].isDescendant(target_path);
     591            }
     592            // Having finally completed all the tests, we can highlight the drop target.
     593            if(!failed) {
     594            valid = true;
     595            }
     596            else {
     597            ///ystem.err.println("Invalid. Target is descendant of itself.");
     598            }
     599        }
     600        else {
     601            ///ystem.err.println("Read only.");
     602        }
     603        }
     604        else {
     605        ///ystem.err.println("Leaf node. Children not allowed.");
     606        }
     607        previous_path = target_path;
     608    }
     609    else {
     610        if(target_path == null) {
     611        previous_path = null;
     612        }
     613    }
     614    return valid;
     615    }
    616616}
  • trunk/gli/src/org/greenstone/gatherer/gui/tree/DragTreeCellRenderer.java

    r4293 r4366  
    4242
    4343public class DragTreeCellRenderer
    44     extends DefaultTreeCellRenderer {
     44    extends DefaultTreeCellRenderer {
    4545     
    46     private boolean in_focus = false;
    47     private Color selection_background;
    48     private Color selection_foreground;
     46    private boolean in_focus = false;
     47    private Color selection_background;
     48    private Color selection_foreground;
    4949     
    50     public DragTreeCellRenderer() {
    51           super();
    52           selection_background = getBackgroundSelectionColor();
    53           selection_foreground = getTextSelectionColor();
    54     }
     50    public DragTreeCellRenderer() {
     51    super();
     52    selection_background = getBackgroundSelectionColor();
     53    selection_foreground = getTextSelectionColor();
     54    }
    5555
    56     public void gainFocus() {
    57           setBackgroundSelectionColor(selection_background);
    58           setTextSelectionColor(selection_foreground);
    59     }
     56    public void gainFocus() {
     57    setBackgroundSelectionColor(selection_background);
     58    setTextSelectionColor(selection_foreground);
     59    }
    6060
    61     public void loseFocus() {
    62           setBackgroundSelectionColor(Color.lightGray);
    63           setTextSelectionColor(Color.black);
    64     }
     61    public void loseFocus() {
     62    setBackgroundSelectionColor(Color.lightGray);
     63    setTextSelectionColor(Color.black);
     64    }
    6565}
    6666
Note: See TracChangeset for help on using the changeset viewer.