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/collection
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.