source: trunk/gli/src/org/greenstone/gatherer/collection/CollectionManager.java@ 8253

Last change on this file since 8253 was 8253, checked in by mdewsnip, 20 years ago

Moved some stuff out of Configuration.updateUI into GUIManager because it depends on the Gatherer.class. More to come.

  • Property svn:keywords set to Author Date Id Revision
File size: 74.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.lang.Class;
41import java.util.*;
42import javax.swing.*;
43import javax.swing.event.*;
44import javax.swing.filechooser.FileSystemView;
45import javax.swing.tree.*;
46import org.greenstone.gatherer.Configuration;
47import org.greenstone.gatherer.DebugStream;
48import org.greenstone.gatherer.Dictionary;
49import org.greenstone.gatherer.Gatherer;
50import org.greenstone.gatherer.ServletConfiguration;
51import org.greenstone.gatherer.cdm.CollectionDesignManager;
52import org.greenstone.gatherer.cdm.CollectionMeta;
53import org.greenstone.gatherer.cdm.CollectionMetaManager;
54import org.greenstone.gatherer.cdm.CommandTokenizer;
55import org.greenstone.gatherer.file.FileNode;
56import org.greenstone.gatherer.file.FileQueue;
57import org.greenstone.gatherer.file.FileSystemModel;
58import org.greenstone.gatherer.gui.LockFileDialog;
59import org.greenstone.gatherer.gui.NewCollectionMetadataPrompt;
60import org.greenstone.gatherer.gui.ExternalCollectionPrompt;
61import org.greenstone.gatherer.gui.NewMetaSetPrompt;
62import org.greenstone.gatherer.gui.WarningDialog;
63import org.greenstone.gatherer.gui.tree.WorkspaceTree;
64import org.greenstone.gatherer.msm.ElementWrapper;
65import org.greenstone.gatherer.msm.MetadataXMLFileManager;
66import org.greenstone.gatherer.msm.GreenstoneArchiveParser;
67import org.greenstone.gatherer.msm.LegacyCollectionImporter;
68import org.greenstone.gatherer.msm.MetadataSet;
69import org.greenstone.gatherer.msm.MetadataSetManager;
70import org.greenstone.gatherer.msm.MSMEvent;
71import org.greenstone.gatherer.msm.MSMListener;
72import org.greenstone.gatherer.msm.MSMProfiler;
73import org.greenstone.gatherer.shell.GShell;
74import org.greenstone.gatherer.shell.GShellEvent;
75import org.greenstone.gatherer.shell.GShellListener;
76import org.greenstone.gatherer.shell.GShellProgressMonitor;
77import org.greenstone.gatherer.util.ArrayTools;
78import org.greenstone.gatherer.util.Codec;
79import org.greenstone.gatherer.util.GSDLSiteConfig;
80import org.greenstone.gatherer.util.StaticStrings;
81import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
82import org.greenstone.gatherer.util.Utility;
83import org.greenstone.gatherer.util.XMLTools;
84import org.w3c.dom.*;
85
86/** This class manages many aspects of the collection, from its creation via scripts, data access via methods and its importing and building into the final collection. It is also resposible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
87 * @author John Thompson
88 * @version 2.3
89 */
90public class CollectionManager
91 implements GShellListener, MSMListener {
92 /** A reference to the metadata set manager. */
93 public MetadataSetManager msm;
94 /** Are we currently in the process of building? */
95 private boolean building = false;
96 /** Are we currently in the process of importing? */
97 private boolean importing = false;
98 /** The collection this manager is managing! */
99 static private Collection collection = null;
100 /** The collection_model. */
101 private FileSystemModel collection_model = null;
102 /** The workspace model. This becomes invalid on a collection change. */
103 // private FileSystemModel workspace_model = null;
104 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
105 private FMTreeModelListener fm_tree_model_listener = null;
106 /** The monitor resposible for parsing the build process. */
107 private GShellProgressMonitor build_monitor = null;
108 /** The monitor resposible for parsing the import process. */
109 private GShellProgressMonitor import_monitor = null;
110
111 /** Holds a reference to the thread responsible for closing the collection. If non-null then only calls from the given thread will see the collection is non-ready. All other threads will have to wait until closing thread, and all of it consequential calls, are completely finished. */
112 private Thread closing_thread = null;
113
114 /** The name of the standard lock file. */
115 static final public String LOCK_FILE = "gli.lck";
116
117 /** Used to indicate the source of the message is the file collection methods. */
118 static final public int COLLECT = 3;
119 /** Used to indicate the source of the message is the building methods. */
120 static final public int BUILDING = 5;
121
122 /** Constructor. */
123 public CollectionManager() {
124 // Initialisation.
125 this.building = false;
126 this.importing = false;
127 this.collection = null;
128 }
129 /** Add a special directory mapping.
130 * @param name The name for this directory mapping as a <strong>String</strong>.
131 * @param file The directory this mapping maps to as a <strong>File</strong>.
132 */
133 public void addDirectoryMapping(String name, File file) {
134 // Update the information stored in the Gatherer config
135 Configuration.addDirectoryMapping(name, file);
136 // Now update the tree
137 Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.FOLDER_SHORTCUTS_CHANGED);
138 }
139 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
140 * @see org.greenstone.gatherer.Configuration
141 * @see org.greenstone.gatherer.Gatherer
142 * @see org.greenstone.gatherer.collection.Collection
143 * @see org.greenstone.gatherer.gui.BuildOptions
144 * @see org.greenstone.gatherer.shell.GShell
145 * @see org.greenstone.gatherer.shell.GShellListener
146 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
147 * @see org.greenstone.gatherer.util.Utility
148 */
149 public void buildCollection() {
150 DebugStream.println("CollectionManager.buildCollection()");
151 building = true;
152 String lang = Configuration.getLanguage();
153 String collect_dir = getCollectDirectory();
154
155 String args[];
156 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
157 args = new String[8];
158 args[0] = Configuration.perl_path;
159 args[1] = "-S";
160 args[2] = Configuration.getScriptPath() + "buildcol.pl";
161 args[3] = "-gli";
162 args[4] = "-language";
163 args[5] = lang;
164 args[6] = "-collectdir";
165 args[7] = collect_dir;
166 }
167 else {
168 args = new String[6];
169 args[0] = Configuration.getScriptPath() + "buildcol.pl";
170 args[1] = "-gli";
171 args[2] = "-language";
172 args[3] = lang;
173 args[4] = "-collectdir";
174 args[5] = collect_dir;
175 }
176 args = ArrayTools.add(args, collection.build_options.getBuildValues());
177 args = ArrayTools.add(args, collection.getName());
178 GShell shell = new GShell(args, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
179 shell.addGShellListener(Gatherer.g_man.create_pane);
180 shell.start();
181 DebugStream.println("CollectionManager.buildCollection().return");
182 }
183
184 /** Used to determine whether the currently active collection has been built.
185 * @return A boolean indicating the built status of the collection.
186 */
187 public boolean built() {
188 if(collection != null) {
189 // Determine if the collection has been built by looking for the build.cfg file
190 File build_cfg_file = new File(getCollectionIndex() + Utility.BUILD_CFG_FILENAME);
191 return build_cfg_file.exists();
192 }
193 return false;
194 }
195
196 /** a test method to see if we can delete a directory/file - returns false is the file or any of the contents of a directory cannot be deleted */
197 public boolean canDelete(File file) {
198 if (!file.isDirectory()) {
199 return file.canWrite();
200 }
201 File [] file_list = file.listFiles();
202 for (int i=0; i<file_list.length; i++) {
203 if (!canDelete(file_list[i])) {
204 return false;
205 }
206 }
207 return true;
208 }
209 /** Called to close the current collection and remove its lock file.
210 * @see org.greenstone.gatherer.Gatherer
211 * @see org.greenstone.gatherer.collection.Collection
212 * @see org.greenstone.gatherer.util.Utility
213 */
214 public void closeCollection() {
215 DebugStream.println("Close collection: " + collection.getName());
216 // We set the closing thread, as it should be the only one who can actually see the collection is closed, at least until the closing thread expires.
217 closing_thread = Thread.currentThread();
218 // Remove the lock on this file, then remove the collection.
219 String collection_dir;
220 if (Gatherer.GS3) {
221 collection_dir = Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName());
222 } else {
223 collection_dir = Utility.getCollectionDir(Configuration.gsdl_path, collection.getName());
224
225 }
226 File lock_file = new File(collection_dir + LOCK_FILE);
227 lock_file.delete();
228 if(lock_file.exists()) {
229 System.err.println("Lockfile was not successfully deleted.");
230 }
231 collection.msm.destroy();
232 collection = null;
233 collection_model = null;
234 // workspace_model = null;
235 Configuration.setCollectionConfiguration(null);
236 if (Gatherer.g_man != null) {
237 Gatherer.g_man.updateUI();
238 Gatherer.g_man.collectionChanged(false);
239 }
240 // All of the consequences of a close should have been processed by now, so others should now see the collection as non-ready.
241 closing_thread = null;
242 }
243
244 /** Method that is called whenever something has changed in the configuration of this collection. */
245 public void configurationChanged() {
246 if(collection != null) {
247 collection.setSaved(false);
248 }
249 }
250
251 public void convertToGS3Collection() {
252 // Run the mkcol command.
253 String command[];
254 String collect_dir = getCollectDirectory();
255
256 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
257 command = new String[6];
258 command[0] = Configuration.perl_path;
259 command[1] = "-S";
260 command[2] = Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl";
261 command[3] = "-collectdir";
262 command[4] = collect_dir;
263 command[5] = collection.getName();
264 } else {
265 command = new String[4];
266 command[0] = Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl";
267 command[1] = "-collectdir";
268 command[2] = collect_dir;
269 command[3] = collection.getName();
270 }
271 DebugStream.println("running command "+command);
272 GShell process = new GShell(command, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
273 process.addGShellListener(this);
274 process.run(); // Don't bother threading this... yet
275
276 }
277
278 /** When basing a new collection on an existing one, we need to copy
279 * over some extra directories: images and macros
280 */
281 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
282 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
283 return false;
284 }
285 DebugStream.println("Copying images and macros dirs from the base collection");
286 FileQueue fq = Gatherer.f_man.getQueue();
287 try {
288 // do the images dir
289 File base_coll_images = new File(base_coll_dir, Utility.IMAGES_DIR);
290 if (base_coll_images.isDirectory()) {
291 // copy all the images over
292 File new_coll_images = new File(new_coll_dir, Utility.IMAGES_DIR);
293 new_coll_images.mkdirs();
294
295 // copy the contents over
296 fq.copyDirectoryContents(base_coll_images, new_coll_images, null);
297 }
298 } catch (Exception e) {
299 DebugStream.println("Couldn't copy over the images dir from the base collection: "+e.toString());
300 }
301 try {
302 // do the macros dir
303 File base_coll_macros = new File(base_coll_dir, Utility.MACROS_DIR);
304 if (base_coll_macros.isDirectory()) {
305 // copy all the macros over
306 File new_coll_macros = new File(new_coll_dir, Utility.MACROS_DIR);
307 new_coll_macros.mkdirs();
308
309 // copy the contents over
310 fq.copyDirectoryContents(base_coll_macros, new_coll_macros, null);
311 }
312 } catch (Exception e) {
313 DebugStream.println("Couldn't copy over the macros dir from the base collection: "+e.toString());
314 }
315 return true;
316 }
317
318 /** 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.
319 * @param description a description of the collection as a String
320 * @param email the email address of the author/maintainer as a String
321 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
322 * @param title the longer title of the collection as a String
323 * @param base_collection_directory if the user has chosen to base their new collection on an existing one, this is the directory where this base collection can be found, as a File, otherwise its null
324 * @param metadata_sets if the user has decided to select several metadata sets with which to initially populate the GLI then this is an ArrayList of metadata set file names, otherwise its null
325 */
326 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets) {
327 boolean cancelled = false;
328
329 try {
330 // first make sure that the collect directory exists
331 File collect_dir = new File(getCollectDirectory());
332 if (!collect_dir.exists()) {
333 collect_dir.mkdirs();
334 }
335 // Create a progress monitor.
336 ProgressMonitor progress = new ProgressMonitor(Gatherer.g_man, Dictionary.get("CollectionManager.Creating_New"), "mkcol.pl", 0, 7);
337 // Create the new collection.
338 makeCollection(description, email, name, title);
339
340 // *******************
341 //check that this creation has worked - simply by checking for the existence of the collect.cfg file
342 String a_dir;
343 if (Gatherer.GS3) {
344 a_dir = Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, name);
345 } else {
346 a_dir = Utility.getCollectionDir(Configuration.gsdl_path, name);
347 }
348 File config_file = new File(Utility.getConfigFile(a_dir));
349 if (!config_file.exists()) {
350 // no point continuing
351 DebugStream.println("The collection could not be created");
352 progress.close();
353 return;
354 }
355 progress.setProgress(1);
356
357 // ACTIVE_DIR/log/
358 File log_dir_temp = new File(Utility.getLogDir(a_dir)+"temp.dat");
359 File log_dir = log_dir_temp.getParentFile();
360 log_dir.mkdirs();
361 if(progress != null) {
362 progress.setNote(Dictionary.get("CollectionManager.Log_Created"));
363 }
364
365 // Make sure an import folder exists
366 File import_directory = new File(Utility.getImportDir(a_dir));
367 if (!import_directory.exists()) {
368 import_directory.mkdirs();
369 }
370
371 progress.setProgress(2);
372
373 // Now create the collection object around the directory.
374 collection = new Collection(new File(a_dir, name + ".col"));
375 collection.msm = new MetadataSetManager();
376 msm = collection.msm; // Legacy
377 collection.msm.load();
378
379 // Import default metadata sets if any.
380 for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
381 MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
382 collection.msm.importMDS(metadata_set.getFile(), false);
383 }
384
385 boolean skip_import_phase = false;
386
387 // Before we create the CollectionDesignManager we have to check if we are basing it upon some other collection.
388 if(base_collection_directory != null) {
389 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
390 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
391 // copy over other needed directories
392 copyExtraBaseCollStuff(new File(a_dir), base_collection_directory);
393 // Try to import any existing metadata sets for this collection. Look in base_collection_directory/metadata and import any metadata sets found.
394 File base_metadata = new File(base_collection_directory, Utility.META_DIR);
395 if(base_metadata.exists()) {
396 DebugStream.println("Found the metadata directory.");
397 File[] possible_metadata_sets = base_metadata.listFiles();
398 for(int i = 0; possible_metadata_sets != null && i < possible_metadata_sets.length; i++) {
399 String filename = possible_metadata_sets[i].getName();
400 if(filename.endsWith(".mds")) {
401 DebugStream.println("+ Found a metadata set. Importing: " + possible_metadata_sets[i].getAbsolutePath());
402 collection.msm.importMDS(possible_metadata_sets[i], false);
403 skip_import_phase = true;
404 }
405 }
406 }
407 else {
408 DebugStream.println("This base collection has no metadata directory.");
409 }
410 // If no sets were imported, then create a new metadata with this new collections name.
411 if(collection.msm.getSets().size() == 0) {
412 // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
413 DebugStream.println("This collection has no metadata sets. Present the user with the metadata set selection prompt.");
414 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
415 // If cancelled then they really do mean to start a collection with no metadata sets.
416 if(!ncm_prompt.isCancelled()) {
417 ArrayList initial_sets = ncm_prompt.getSets();
418 for(int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
419 MetadataSet metadata_set = (MetadataSet) initial_sets.get(i);
420 collection.msm.importMDS(metadata_set.getFile(), false);
421 metadata_set = null;
422 }
423 initial_sets = null;
424 }
425 ncm_prompt.dispose();
426 ncm_prompt = null;
427 }
428 // 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.
429 if(!skip_import_phase) {
430 File base_archive = new File(base_collection_directory, Utility.ARCHIVES_DIR);
431 if(base_archive.exists()) {
432 DebugStream.println("+ Archive directory found. Inspecting archives for metadata information.");
433 ArrayList metadata_elements = GreenstoneArchiveParser.extractMetadataElements(base_archive);
434 for(int i = 0; !cancelled && i < metadata_elements.size(); i++) {
435 String metadata_name = (String) metadata_elements.get(i);
436 ElementWrapper target = collection.msm.prompt.selectElement(metadata_name);
437 cancelled = Gatherer.c_man.getCollection().msm.prompt.wasDialogCancelled();
438 if(!cancelled) {
439 if(target != null) {
440 collection.msm.profiler.addAction(base_collection_directory.getAbsolutePath(), metadata_name, target.getName());
441 }
442 else {
443 collection.msm.profiler.addAction(base_collection_directory.getAbsolutePath(), metadata_name, null);
444 }
445 }
446 }
447 // Hopefully mappings should now be in place for metadata extracted from this collection.
448 }
449 else {
450 DebugStream.println("+ Searching files for metadata.xml information.");
451 // Find the import directory
452 File base_import = new File(base_collection_directory, Utility.IMPORT_DIR);
453 if(base_import.exists()) {
454 searchForMetadata(base_import);
455 }
456 }
457 }
458 // 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.
459
460 // Now we update our collect.cfg
461 DebugStream.println("Copy and update collect.cfg from base collection.");
462 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE), new File(a_dir, Utility.CONFIG_FILE), description, email, title);
463 }
464
465 // Always import the extracted metadata set if we didn't already
466 if(collection.msm.getSet(Utility.EXTRACTED_METADATA_NAMESPACE) == null) {
467 collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION), false);
468 }
469
470 collection.cdm = new CollectionDesignManager(new File(getCollectionConfig()));
471
472 // Now that we have a CDM, update several settings, such as if we created this collection by basing it on another, set it as public automatically
473 if(base_collection_directory != null) {
474 // Update the creator and maintainer
475 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
476 creator_collectionmeta.setValue(email);
477 creator_collectionmeta = null;
478 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
479 maintainer_collectionmeta.setValue(email);
480 maintainer_collectionmeta = null;
481 // Update the collection title
482 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
483 collection_name_collectionmeta.setValue(title);
484 collection_name_collectionmeta = null;
485 // And now the description
486 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
487 collection_extra_collectionmeta.setValue(description);
488 collection_extra_collectionmeta = null;
489 // All collections based on others are automatically public
490 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
491 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
492 public_collectionmeta = null;
493 // Finally reset the icons
494 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
495 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
496 icon_collection_collectionmeta = null;
497 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
498 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
499 icon_collection_small_collectionmeta = null;
500 }
501
502 collection.gdm = new MetadataXMLFileManager();
503
504 progress.setProgress(3);
505
506 // Has to be done after creating metadata set manager.
507 File gmeta_dir_temp = new File(getCollectionMetadata()+"temp.dat");
508 File gmeta_dir = gmeta_dir_temp.getParentFile();
509 gmeta_dir.mkdirs();
510 if(progress != null) {
511 progress.setNote("GMeta created");
512 }
513 progress.setProgress(4);
514
515 progress.setProgress(6);
516 // Register ourselves as being interested in what the msm has to say.
517 collection.msm.addMSMListener(this);
518 // Create a lock file.
519 File lock_file = new File(a_dir, LOCK_FILE);
520 FileOutputStream out = new FileOutputStream(lock_file);
521 out.write(LOCK_FILE.getBytes());
522 out.close();
523 out = null;
524 progress.setProgress(7);
525 String args[] = new String[1];
526 args[0] = name;
527 progress.setNote(Dictionary.get("CollectionManager.Session_Ready", args));
528 progress.close();
529 }
530 catch (Exception error) {
531 DebugStream.printStackTrace(error);
532 }
533
534 // Done, so refresh interface
535 if (Gatherer.g_man != null) {
536 // Return to some initial pane (Gather)
537 Gatherer.g_man.returnToInitialPane();
538
539 // Refresh the workspace tree to allow for the new collection
540 Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.LIBRARY_CONTENTS_CHANGED);
541
542 Gatherer.g_man.collectionChanged(ready());
543 }
544 }
545
546 public void createLockFile(File destination) {
547 try {
548 Document default_lockfile = Utility.parse("xml/" + LOCK_FILE, true);
549 String user_name = System.getProperty("user.name");
550 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
551 person_element.appendChild(default_lockfile.createTextNode(user_name));
552 person_element = null;
553 user_name = null;
554 String machine_name = Utility.getMachineName();
555 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
556 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
557 machine_element = null;
558 machine_name = null;
559 String date_time = Utility.getDateString();
560 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
561 date_element.appendChild(default_lockfile.createTextNode(date_time));
562 date_element = null;
563 date_time = null;
564 Utility.export(default_lockfile, destination);
565 }
566 catch (Exception error) {
567 DebugStream.printStackTrace(error);
568 }
569 }
570
571 /** 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.
572 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
573 * @see org.greenstone.gatherer.collection.Collection
574 */
575 public void elementChanged(MSMEvent event) {
576 // This means the state of the collections has changed, so we should set saved to false.
577 collection.setSaved(false);
578 }
579 /** Used to retrieve the build options associated with the currently loaded collection. If none yet exist, default ones are created.
580 * @return A <strong>BuildOptions</strong> object containing the build options for the current collection.
581 * @see org.greenstone.gatherer.collection.Collection
582 */
583 /* private BuildOptions getBuildOptions() {
584 return collection.build_options;
585 } */
586
587 /** Retrieve the current collection.
588 * @return The <strong>Collection</strong> itself.
589 */
590 public Collection getCollection() {
591 return collection;
592 }
593 /** Constructs the absolute filename of the collection archive directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archive/"
594 * @return A <strong>String</strong> containing the filename.
595 * @see org.greenstone.gatherer.Configuration
596 * @see org.greenstone.gatherer.Gatherer
597 * @see org.greenstone.gatherer.collection.Collection
598 * @see org.greenstone.gatherer.util.Utility
599 */
600 public String getCollectionArchive() {
601 if (Gatherer.GS3) {
602 return Utility.getArchiveDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
603 } else {
604 return Utility.getArchiveDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
605 }
606 }
607 /** Constructs the absolute filename of the collection building directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/building/"
608 * @return A <strong>String</strong> containing the filename.
609 * @see org.greenstone.gatherer.Configuration
610 * @see org.greenstone.gatherer.Gatherer
611 * @see org.greenstone.gatherer.collection.Collection
612 * @see org.greenstone.gatherer.util.Utility
613 */
614 public String getCollectionBuild() {
615 if (Gatherer.GS3) {
616 return Utility.getBuildDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
617 } else {
618 return Utility.getBuildDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
619 }
620 }
621 /** Constructs the absolute filename of the collection config file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/collect.cfg"
622 * @return A <strong>String</strong> containing the filename.
623 * @see org.greenstone.gatherer.Configuration
624 * @see org.greenstone.gatherer.Gatherer
625 * @see org.greenstone.gatherer.collection.Collection
626 * @see org.greenstone.gatherer.util.Utility
627 */
628 public String getCollectionConfig() {
629 if (Gatherer.GS3) {
630 return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
631 } else {
632 return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
633 }
634 }
635
636 /** Constructs the absolute filename of the collection directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;"
637 * @return A <strong>String</strong> containing the directory name.
638 * @see org.greenstone.gatherer.Configuration
639 * @see org.greenstone.gatherer.Gatherer
640 * @see org.greenstone.gatherer.collection.Collection
641 * @see org.greenstone.gatherer.util.Utility
642 */
643 public String getCollectionDirectory() {
644 if (Gatherer.GS3) {
645 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName());
646 } else {
647 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName());
648 }
649 }
650
651 /** Constructs the absolute filename of the collection etc directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/"
652 * @return A <strong>String</strong> containing the filename.
653 * @see org.greenstone.gatherer.Configuration
654 * @see org.greenstone.gatherer.Gatherer
655 * @see org.greenstone.gatherer.collection.Collection
656 * @see org.greenstone.gatherer.util.Utility
657 */
658 public String getCollectionEtc() {
659 if (Gatherer.GS3) {
660 return Utility.getEtcDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
661 } else {
662 return Utility.getEtcDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
663 }
664 }
665 /** Constructs the absolute filename of the collection file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/&lt;col_name&gt;.col"
666 * @return A <strong>String</strong> containing the filename.
667 * @see org.greenstone.gatherer.Configuration
668 * @see org.greenstone.gatherer.Gatherer
669 * @see org.greenstone.gatherer.collection.Collection
670 * @see org.greenstone.gatherer.util.Utility
671 */
672 public String getCollectionFilename() {
673 if (Gatherer.GS3) {
674 return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + collection.getName() + ".col";
675 } else {
676 return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + collection.getName() + ".col";
677 }
678 }
679 /** Constructs the absolute filename of the collection images directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/images/"
680 * @return A <strong>String</strong> containing the filename.
681 * @see org.greenstone.gatherer.Configuration
682 * @see org.greenstone.gatherer.Gatherer
683 * @see org.greenstone.gatherer.collection.Collection
684 * @see org.greenstone.gatherer.util.Utility
685 */
686 public String getCollectionImages() {
687 if (Gatherer.GS3) {
688 return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
689 } else {
690 return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
691 }
692 }
693 /** Constructs the absolute filename of the collection import directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/import/"
694 * @return A <strong>String</strong> containing the filename.
695 * @see org.greenstone.gatherer.Configuration
696 * @see org.greenstone.gatherer.Gatherer
697 * @see org.greenstone.gatherer.collection.Collection
698 * @see org.greenstone.gatherer.util.Utility
699 */
700 public String getCollectionImport() {
701 if (Gatherer.GS3) {
702 return Utility.getImportDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
703 } else {
704 return Utility.getImportDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
705 }
706 }
707 /** Constructs the absolute filename of the collection index directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/index/"
708 * @return A <strong>String</strong> containing the filename.
709 * @see org.greenstone.gatherer.Configuration
710 * @see org.greenstone.gatherer.Gatherer
711 * @see org.greenstone.gatherer.collection.Collection
712 * @see org.greenstone.gatherer.util.Utility
713 */
714 public String getCollectionIndex() {
715 if (Gatherer.GS3) {
716 return Utility.getIndexDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
717 } else {
718 return Utility.getIndexDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
719 }
720 }
721 /** Constructs the absolute filename of the collection log directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/log/"
722 * @return A <strong>String</strong> containing the filename.
723 * @see org.greenstone.gatherer.Configuration
724 * @see org.greenstone.gatherer.Gatherer
725 * @see org.greenstone.gatherer.collection.Collection
726 * @see org.greenstone.gatherer.util.Utility
727 */
728 public String getCollectionLog() {
729 if (Gatherer.GS3) {
730 return Utility.getLogDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
731 } else {
732 return Utility.getLogDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
733 }
734 }
735 /** Constructs the absolute filename of the collection metadata directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/metadata/"
736 * @return A <strong>String</strong> containing the filename.
737 * @see org.greenstone.gatherer.Configuration
738 * @see org.greenstone.gatherer.Gatherer
739 * @see org.greenstone.gatherer.collection.Collection
740 * @see org.greenstone.gatherer.util.Utility
741 */
742 public String getCollectionMetadata() {
743 if (Gatherer.GS3) {
744 return Utility.getMetadataDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
745 } else {
746 return Utility.getMetadataDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
747 }
748 }
749
750 /** This method either returns the title of the current collection, or a placeholder string of 'No Collection'.
751 * @return A <strong>String</strong> which represents what we wish to display for a collection title.
752 * @see org.greenstone.gatherer.collection.Collection
753 */
754 /* private String getCollectionTitle() {
755 if(collection != null) {
756 return collection.getTitle();
757 }
758 return Dictionary.get("Collection.No_Collection");
759 } */
760
761 /** Retrieve the record set (tree model) associated with the current collection. */
762 public TreeModel getRecordSet() {
763 if(collection_model == null && collection != null) {
764 // Use the import directory to generate a new FileSystemModel
765 collection_model = new FileSystemModel(new FileNode(new File(getCollectionImport()), false));
766 // Ensure that the manager is a change listener for the tree.
767 if(fm_tree_model_listener == null) {
768 fm_tree_model_listener = new FMTreeModelListener();
769 }
770 collection_model.addTreeModelListener(fm_tree_model_listener);
771 }
772 return collection_model;
773 }
774
775
776 static public FileNode getGreenstoneCollectionsMapping()
777 {
778 FileNode greenstone_collections_node = new FileNode(Dictionary.get("Tree.World"));
779 greenstone_collections_node.unmap();
780 return greenstone_collections_node;
781 }
782
783
784 static public FileNode[] getFolderShortcuts()
785 {
786 // Return any predefined special directories
787 HashMap mappings = Configuration.getDirectoryMappings();
788 FileNode[] mapping_nodes = new FileNode[mappings.size()];
789 Iterator mappings_iterator = mappings.keySet().iterator();
790 for (int i = 0; mappings_iterator.hasNext(); i++) {
791 String mapping_name = (String) mappings_iterator.next();
792 File mapping_file = (File) mappings.get(mapping_name);
793 mapping_nodes[i] = new FileNode(mapping_file, mapping_name);
794 }
795 return mapping_nodes;
796 }
797
798
799 /** This method when called, creates a new GShell in order to run the import.pl script.
800 * @see org.greenstone.gatherer.Configuration
801 * @see org.greenstone.gatherer.Gatherer
802 * @see org.greenstone.gatherer.gui.BuildOptions
803 * @see org.greenstone.gatherer.shell.GShell
804 * @see org.greenstone.gatherer.shell.GShellListener
805 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
806 * @see org.greenstone.gatherer.util.Utility
807 */
808 public void importCollection() {
809 importing = true;
810 if(!saved()) {
811 DebugStream.println("CollectionManager.importCollection().forcesave");
812 import_monitor.saving();
813 // Force save.
814 try {
815 SaveCollectionTask save_task = new SaveCollectionTask(collection);
816 save_task.setImportAfter(true);
817 save_task.start();
818 }
819 catch(Exception error) {
820 DebugStream.printStackTrace(error);
821 }
822 }
823 else {
824 DebugStream.println("CollectionManager.importCollection()");
825 //check that we can remove the old index before starting import
826 File index_dir = new File(getCollectionIndex(), "temp.txt");
827 index_dir = index_dir.getParentFile();
828 if(index_dir.exists()) {
829 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
830 if (!canDelete(index_dir)) {
831 // tell the user
832 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
833 // tell the gui manager
834 // a message for the building log
835 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
836 Gatherer.g_man.create_pane.message(event);
837 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
838 Gatherer.g_man.create_pane.processComplete(event);
839 importing = false;
840 return;
841 }
842
843 }
844
845 String collect_dir = getCollectDirectory();
846
847 String args[];
848 String lang = Configuration.getLanguage();
849 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
850 args = new String[8];
851 args[0] = Configuration.perl_path;
852 args[1] = "-S";
853 args[2] = Configuration.getScriptPath() + "import.pl";
854 args[3] = "-gli";
855 args[4] = "-language";
856 args[5] = lang;
857 args[6] = "-collectdir";
858 args[7] = collect_dir;
859 }
860 else {
861 args = new String[6];
862 args[0] = Configuration.getScriptPath() + "import.pl";
863 args[1] = "-gli";
864 args[2] = "-language";
865 args[3] = lang;
866 args[4] = "-collectdir";
867 args[5] = collect_dir;
868 }
869 collect_dir = null;
870 args = ArrayTools.add(args, collection.build_options.getImportValues());
871 args = ArrayTools.add(args, collection.getName());
872
873 GShell shell = new GShell(args, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
874 shell.addGShellListener(Gatherer.g_man.create_pane);
875 shell.start();
876 DebugStream.println("CollectionManager.importCollection().return");
877 }
878 importing = false;
879 }
880
881 /** Determine if we are currently in the middle of importing (and thus, in this case, we can't allow the log writer to exit). Boy was this a mission to track down. The cascade of crap rolls out something like this: Joe Schmo clicks 'Build Collection', which calls the importCollection() method above, which in turn saves the collection with a saveTask, which fires a collectionChanged message once its finished, which drives the list of logs shown on the create pane to update, which fires a itemChanged() event to the OptionsPane who dutifully tells the current log writer thread to finish up writing (all zero lines its been asked to write) and then die. Wereapon Joe Schmo gets a pretty log to look at, but it isn't actually being written to file so the next time he tries to view it faeces hits the air motion cooling device. Joy.
882 * @return true if the gli is currently importing
883 */
884 public boolean isImporting() {
885 return importing;
886 }
887
888 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
889 * @param location The path to the collection as a <strong>String</strong>.
890 * @see org.greenstone.gatherer.Configuration
891 * @see org.greenstone.gatherer.Gatherer
892 * @see org.greenstone.gatherer.collection.Collection
893 * @see org.greenstone.gatherer.msm.MetadataSetManager
894 * @see org.greenstone.gatherer.msm.MSMListener
895 * @see org.greenstone.gatherer.util.Utility
896 */
897 public boolean loadCollection(String location) {
898 DebugStream.println("Load Collection '" + location + "'");
899 String[] args2 = new String[1];
900 args2[0] = location;
901 boolean result = false;
902 boolean non_gatherer_collection = false;
903 // Check we have actually been given a .col file.
904 if(!location.endsWith(".col")) {
905 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", args2), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
906 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
907 return false;
908 }
909 // Check that there is the collection configuration file available
910
911 File collection_file = new File(location);
912 // Ensure that the directory exists.
913 File collection_directory = collection_file.getParentFile();
914 if(!collection_directory.exists()) {
915 // we cant open this
916 collection_directory = null;
917 return false;
918 }
919 File collection_config_file = new File(collection_directory, Utility.CONFIG_FILE);
920 if (!collection_config_file.exists()) {
921 DebugStream.println("CollectionManager.loadCollection: No config file");
922 collection_directory = null;
923 collection_config_file = null;
924 return false;
925 }
926
927 // Special case of a user trying to open an old greenstone collection.
928 File metadata_directory = new File(collection_directory, Utility.META_DIR);
929 if(!metadata_directory.exists()) {
930
931 DebugStream.println("CollectionManager.loadCollection: trying to load up a non-gatherer collection");
932 non_gatherer_collection = true;
933 }
934
935 String name = collection_directory.getName();
936 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
937 // Now determine if a lock already exists on this collection.
938 int choice = LockFileDialog.YES_OPTION;
939 if(lock_file.exists()) {
940 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
941 choice = dialog.getChoice();
942 dialog.dispose();
943 dialog = null;
944 }
945
946 if(choice != LockFileDialog.YES_OPTION) {
947 // user has cancelled
948 lock_file = null;
949 collection_directory = null;
950 collection_config_file = null;
951 return false;
952 }
953
954
955 try {
956 if(lock_file.exists()) {
957 lock_file.delete();
958 }
959 // Create a lock file.
960 createLockFile(lock_file);
961 // This lock file may not have been created so check
962 if(!lock_file.canWrite()) {
963 // The lock file cannot be written to. Most likely cause incorrect file permissions.
964 System.err.println("Cannot write lock file!");
965 String args[] = new String[2];
966 args[0] = args2[0];
967 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Title");
968 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
969 args = null;
970 return false;
971 }
972 // Open the collection file
973 this.collection = new Collection(collection_file);
974 if (collection.error) {
975 collection = null;
976 // Remove lock file
977 if(lock_file.exists()) {
978 lock_file.delete();
979 }
980 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
981 }
982
983 collection.msm = new MetadataSetManager();
984 msm = collection.msm; // Legacy
985 collection.msm.load();
986 // if non-gatherer collection, need to add some metadata sets
987 if (non_gatherer_collection) {
988 if (!addSomeMetadataSets(collection_directory)) {
989 // for now - return of false means its been cancelled. Any error messages should be sent from the function itself
990 lock_file = null;
991 collection_directory = null;
992 closeCollection();
993 return false;
994 }
995 }
996
997 collection.cdm = new CollectionDesignManager(collection_config_file);
998 if (non_gatherer_collection) {
999 // We first recurse the Import folder tree, reading in any metadata.xml files, and then altering the non-namespaced element names to be valid GLI names
1000 LegacyCollectionImporter lci = new LegacyCollectionImporter(collection_directory, collection.cdm);
1001 lci.backupMetadataXMLFiles(collection_directory);
1002 lci.importMetadata();
1003 lci.updateClassifiers();
1004 lci = null;
1005 }
1006 // Whether the collection is legacy or not, we should now be able to prepare the MetadataXMLFileManager
1007 collection.gdm = new MetadataXMLFileManager();
1008
1009 // Tell everyone that it worked.
1010 String[] args = new String[1];
1011 args[0] = name;
1012 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", args));
1013 // Now we need to hook up classes that depend on messages from the metadata set manager to keep their content fresh.
1014 collection.msm.addMSMListener(this);
1015 // We're done. Let everyone know.
1016 if(Gatherer.g_man != null) {
1017 // workspace_model = null;
1018 Gatherer.g_man.collectionChanged(ready());
1019 }
1020 result = true;
1021 } catch (Exception error) {
1022 // There is obviously no existing collection present.
1023 DebugStream.printStackTrace(error);
1024 if(error.getMessage() != null) {
1025 String[] args = new String[2];
1026 args[0] = args2[0];
1027 args[1] = error.getMessage();
1028 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1029 }
1030 else {
1031 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", args2), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1032 }
1033 }
1034
1035 lock_file = null;
1036 collection_directory = null;
1037 collection_config_file = null;
1038
1039 args2 = null;
1040 return result;
1041 }
1042
1043
1044 public void makeCollection(String description, String email, String name, String title) {
1045 // Encode the description so it is safe to write to shell
1046 if(Utility.isWindows()) {
1047 description = Codec.transform(description, Codec.TEXT_TO_SHELL_WINDOWS);
1048 }
1049 else {
1050 description = Codec.transform(description, Codec.TEXT_TO_SHELL_UNIX);
1051 }
1052 String collect_dir = getCollectDirectory();
1053 // Run the mkcol command.
1054 String command[];
1055 if((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
1056 if(description == null || title == null) {
1057 command = new String[8];
1058 command[0] = Configuration.perl_path;
1059 command[1] = "-S";
1060 command[2] = Configuration.getScriptPath() + "mkcol.pl";
1061 command[3] = "-collectdir";
1062 command[4] = collect_dir;
1063 command[5] = "-win31compat";
1064 command[6] = (Gatherer.isGsdlRemote) ? "false" : "true";
1065 command[7] = name;
1066 }
1067 // Users are no longer required to supply an email
1068 else if(email == null) {
1069 command = new String[12];
1070 command[0] = Configuration.perl_path;
1071 command[1] = "-S";
1072 command[2] = Configuration.getScriptPath() + "mkcol.pl";
1073 command[3] = "-collectdir";
1074 command[4] = collect_dir;
1075 command[5] = "-win31compat";
1076 command[6] = (Gatherer.isGsdlRemote) ? "false" : "true";
1077 command[7] = "-title";
1078 command[8] = title;
1079 command[9] = "-about";
1080 command[10] = description;
1081 command[11] = name;
1082 }
1083 else {
1084 command = new String[14];
1085 command[0] = Configuration.perl_path;
1086 command[1] = "-S";
1087 command[2] = Configuration.getScriptPath() + "mkcol.pl";
1088 command[3] = "-collectdir";
1089 command[4] = collect_dir;
1090 command[5] = "-win31compat";
1091 command[6] = (Gatherer.isGsdlRemote) ? "false" : "true";
1092 command[7] = "-title";
1093 command[8] = title;
1094 command[9] = "-creator";
1095 command[10] = email;
1096 command[11] = "-about";
1097 command[12] = description;
1098 command[13] = name;
1099 }
1100 }
1101 else {
1102 if(description == null || title == null) {
1103 command = new String[6];
1104 command[0] = "mkcol.pl";
1105 command[1] = "-collectdir";
1106 command[2] = collect_dir;
1107 command[3] = "-win31compat";
1108 command[4] = (Gatherer.isGsdlRemote) ? "false" : "true";
1109 command[5] = name;
1110 }
1111 else if(email == null) {
1112 command = new String[10];
1113 command[0] = "mkcol.pl";
1114 command[1] = "-collectdir";
1115 command[2] = collect_dir;
1116 command[3] = "-win31compat";
1117 command[4] = (Gatherer.isGsdlRemote) ? "false" : "true";
1118 command[5] = "-title";
1119 command[6] = title;
1120 command[7] = "-about";
1121 command[8] = description;
1122 command[9] = name;
1123 }
1124 else {
1125 command = new String[12];
1126 command[0] = "mkcol.pl";
1127 command[1] = "-collectdir";
1128 command[2] = collect_dir;
1129 command[3] = "-win31compat";
1130 command[4] = (Gatherer.isGsdlRemote) ? "false" : "true";
1131 command[5] = "-title";
1132 command[6] = title;
1133 command[7] = "-creator";
1134 command[8] = email;
1135 command[9] = "-about";
1136 command[10] = description;
1137 command[11] = name;
1138 }
1139 }
1140 GShell process = new GShell(command, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1141 process.run(); // Don't bother threading this... yet
1142 }
1143
1144 /** 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.
1145 * @param event A <strong>GShellEvent</strong> which contains a the message.
1146 */
1147 public synchronized void message(GShellEvent event) {
1148 }
1149 /** 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.
1150 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
1151 * @see org.greenstone.gatherer.collection.Collection
1152 */
1153 public void metadataChanged(MSMEvent event) {
1154 // Again this change means we need to save the collection again.
1155 collection.setSaved(false);
1156 }
1157 /** This call is fired whenever a process within a GShell created by this class begins.
1158 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1159 * @see org.greenstone.gatherer.Gatherer
1160 * @see org.greenstone.gatherer.gui.GUIManager
1161 * @see org.greenstone.gatherer.shell.GShell
1162 */
1163 public synchronized void processBegun(GShellEvent event) {
1164 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1165 ///ystem.err.println("ProcessBegun " + event.getType());
1166 // If this is one of the types where we wish to lock user control
1167 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1168 }
1169 /** This call is fired whenever a process within a GShell created by this class ends.
1170 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1171 * @see org.greenstone.gatherer.Gatherer
1172 * @see org.greenstone.gatherer.gui.GUIManager
1173 * @see org.greenstone.gatherer.shell.GShell
1174 */
1175 public synchronized void processComplete(GShellEvent event) {
1176 DebugStream.println("CollectionManager.processComplete(" + event.getType() + ")");
1177 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1178 ///ystem.err.println("Recieved process complete event - " + event);
1179 // If we were running an import, now run a build.
1180 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1181 // Finish import.
1182 collection.setImported(true);
1183 buildCollection();
1184 }
1185 // If we were running a build, now is when we move files across.
1186 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1187 if(installCollection()) {
1188 // If we have a local library running (that we know about) then we ask it to add our newly create collection
1189 if (Configuration.exec_file != null) {
1190 Gatherer.self.configServer(GSDLSiteConfig.ADD_COMMAND + collection.getName());
1191 // This is very important -- it ensures that the above command has finished
1192 Gatherer.self.configServer("");
1193 }
1194 else if (Gatherer.GS3) {
1195 convertToGS3Collection();
1196 Gatherer.self.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1197 }
1198
1199 // Fire a collection changed first to update the preview etc buttons
1200 Gatherer.g_man.collectionChanged(ready());
1201
1202 // Now display a message dialog saying its all built
1203 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", false);
1204 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1205 collection_built_warning_dialog.display();
1206 collection_built_warning_dialog.dispose();
1207 collection_built_warning_dialog = null;
1208 }
1209 else {
1210 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1211 Gatherer.g_man.collectionChanged(ready());
1212 }
1213 }
1214 else if(event.getStatus() == GShell.ERROR || event.getStatus() == GShell.CANCELLED) {
1215 DebugStream.println("There was an error in the gshell:"+ event.getMessage());
1216 if (event.getType() == GShell.NEW) {
1217 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1218 } else {
1219 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1220 Gatherer.g_man.collectionChanged(ready());
1221 }
1222
1223 Gatherer.g_man.repaint(); // It appears Java's own dialogs have the same not always painting correct area bug that I suffer from. Well I don't suffer from it personally, but my ModalDialog components do.
1224 }
1225 }
1226 /** Determine if the manager is ready for actions apon its collection.
1227 * @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.
1228 */
1229 static public synchronized boolean ready() {
1230 if(collection != null) {
1231 return true;
1232 }
1233 else {
1234 return false;
1235 }
1236 }
1237
1238 public synchronized boolean reallyReady() {
1239 // If the closing thread is non-null we should only allow that thread to see the collection as closed.
1240 if(closing_thread != null) {
1241 // Only the closing thread sees the truth
1242 if(Thread.currentThread() == closing_thread) {
1243 return (collection == null);
1244 }
1245 // All other threads are told a lie.
1246 else {
1247 return true;
1248 }
1249 }
1250 else {
1251 if(collection != null) {
1252 return true;
1253 }
1254 else {
1255 return false;
1256 }
1257 }
1258 }
1259
1260 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1261 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1262 */
1263 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1264 build_monitor = monitor;
1265 }
1266 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1267 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1268 */
1269 public void registerImportMonitor(GShellProgressMonitor monitor) {
1270 import_monitor = monitor;
1271 }
1272 /** Remove a previously assigned special directory mapping.
1273 * @param target The <string>FileNode</strong> representing the special directory mapping to remove as a <strong>String</strong>.
1274 * @return The <strong>File</strong> of the mapping removed.
1275 * @see org.greenstone.gatherer.file.FileNode
1276 */
1277 public File removeDirectoryMapping(FileNode target) {
1278 // Remove from config, remembering file
1279 File file = Configuration.removeDirectoryMapping(target.toString());
1280 // Update tree.
1281 Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.FOLDER_SHORTCUTS_CHANGED);
1282 return file;
1283 }
1284 /** Used to check whether all open collections have a 'saved' state.
1285 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1286 * @see org.greenstone.gatherer.collection.Collection
1287 */
1288 public boolean saved() {
1289 boolean result = true;
1290 if(collection != null) {
1291 result = collection.getSaved();
1292 }
1293 return result;
1294 }
1295 /** Saves a collection by serializing it to file.
1296 * @param close_after <i>true</i> to cause the Gatherer to close the collection once save is complete, <i>false</i> otherwise.
1297 * @param exit_after <i>true</i> to cause the Gatherer to exit once save is complete, <i>false</i> otherwise.
1298 * @see org.greenstone.gatherer.Gatherer
1299 * @see org.greenstone.gatherer.gui.GUIManager
1300 * @see org.greenstone.gatherer.collection.Collection
1301 */
1302 public void saveCollection(boolean close_after, boolean exit_after) {
1303 DebugStream.println("Save collection: " + collection.getName());
1304 try {
1305 SaveCollectionTask save_task = new SaveCollectionTask(collection, close_after, exit_after);
1306 save_task.start();
1307 // Run this in the same thread
1308 //save_task.run();
1309 }
1310 catch(Exception error) {
1311 DebugStream.printStackTrace(error);
1312 }
1313 }
1314
1315 /** 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.
1316 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
1317 * @see org.greenstone.gatherer.collection.Collection
1318 */
1319 public void setChanged(MSMEvent event) {
1320 // Invalidate saved
1321 collection.setSaved(false);
1322 }
1323
1324 public void setClosingThread(boolean set) {
1325 if(set) {
1326 closing_thread = Thread.currentThread();
1327 }
1328 else {
1329 closing_thread = null;
1330 }
1331 }
1332
1333 /** Updates the given workspace tree model to reference the private cache of the currently loaded collection. */
1334 /* private void updatePrivateWorkspace(DefaultTreeModel model) {
1335 // Add Private workspace if a collection has been loaded.
1336 if(ready() && !Configuration.get("workflow.mirror", true)) {
1337 FileNode root = (FileNode)model.getRoot();
1338 // Remove old private workspace
1339 FileNode old = (FileNode)model.getChild(root, 2);
1340 model.removeNodeFromParent(old);
1341 // Create and insert new.
1342 FileNode private_workspace = new FileNode(new File(getCollectionCache()), Dictionary.get("Tree.Private"));
1343 model.insertNodeInto(private_workspace, root, 2);
1344 }
1345 } */
1346 /** 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.
1347 * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
1348 * @see org.greenstone.gatherer.collection.Collection
1349 */
1350 public void valueChanged(MSMEvent event) {
1351 collection.setSaved(false);
1352 }
1353
1354 /** I started giving the user the choice of using an existing meta set or creating a new one. The second option being so that they didn't have to add/merge/ignore each element, they could all be added automatically. However, I am not sure where the merge prompt gets called from, and it is not essential, so I am leaving it for now - it should be added back in and finished. [kjdon] */
1355 private boolean addSomeMetadataSets(File collection_dir) {
1356
1357
1358 ExternalCollectionPrompt external_prompt = new ExternalCollectionPrompt();
1359 int meta_choice = external_prompt.getMetadataChoice();
1360 boolean cancelled = external_prompt.isCancelled();
1361 if (cancelled) {
1362 return false;
1363 }
1364
1365 /*if (meta_choice == ExternalCollectionPrompt.NEW_META_SET) {
1366 NewMetaSetPrompt nmsp = new NewMetaSetPrompt();
1367 if (nmsp.isCancelled()) {
1368 return false;
1369}
1370 String namespace_str = nmsp.getNamespace();
1371 String name_str = nmsp.getName();
1372 MetadataSet set = Gatherer.c_man.msm.addSet(namespace_str, name_str);
1373 } else if (meta_choice == ExternalCollectionPrompt.EXISTING_META_SET) {
1374 */
1375 // now we reuse the newcoll metadata prompt for the user to select metadata sets
1376 NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt(true);
1377 if (ncm_prompt.isCancelled()) {
1378 return false;
1379 }
1380 ArrayList metadata_sets = ncm_prompt.getSets();
1381 // Import default metadata sets if any.
1382 for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
1383 MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
1384 collection.msm.importMDS(metadata_set.getFile(), false);
1385 }
1386 /*} else {
1387 return false;
1388 }*/
1389 // Always import the extracted metadata set
1390 collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION), false);
1391
1392 return true;
1393 }
1394
1395
1396// // now try to load in existing metadata, delete the existing metadata.xml files, then save the new ones.
1397// private boolean findAndLoadExistingMetadata(File collection_dir)
1398// {
1399// TreeModel collection_tree = getRecordSet();
1400// FileNode root_node = (FileNode) collection_tree.getRoot();
1401// if (searchForMetadata(collection_tree, root_node) == false) {
1402// return false;
1403// }
1404// collection.gdm.save(root_node);
1405// return true;
1406// }
1407
1408 // used as arg in the perl scripts
1409 private String getCollectDirectory() {
1410 String collect_dir;
1411 if (Gatherer.GS3) {
1412 collect_dir = Utility.getCollectDir(Configuration.gsdl3_path, Configuration.site_name);
1413 } else {
1414 collect_dir = Utility.getCollectDir(Configuration.gsdl_path);
1415 }
1416
1417 // Remove erroneous file windows file separator as it causes problems when running import.pl
1418 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1419 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1420 }
1421
1422 return collect_dir;
1423 }
1424
1425 /** Install collection by moving its files from building to index after a successful build.
1426 * @see org.greenstone.gatherer.Gatherer
1427 * @see org.greenstone.gatherer.util.Utility
1428 */
1429 private boolean installCollection() {
1430 DebugStream.println("Build complete. Moving files.");
1431
1432 try {
1433 // We have to ensure that the local library has released this collection so we can delete the index directory
1434 if (!Gatherer.GS3 && Configuration.exec_file != null) {
1435 Gatherer.self.configServer(GSDLSiteConfig.RELEASE_COMMAND + collection.getName());
1436
1437 // This is very important -- it ensures that the above command has finished
1438 // This prevents the nasty "could not remove index directory" race condition!
1439 Gatherer.self.configServer("");
1440 }
1441
1442 File index_dir = new File(getCollectionIndex());
1443 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1444
1445 File building_dir = new File(getCollectionBuild());
1446 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1447
1448 // Get the build mode from the build options
1449 String build_mode = collection.build_options.getBuildValue("mode");
1450
1451 // Special case for build mode "all": replace index dir with building dir
1452 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1453 // Remove the old index directory
1454 if (index_dir.exists()) {
1455 Utility.delete(index_dir);
1456
1457 // Wait for a couple of seconds, just for luck
1458 wait(2000);
1459
1460 // Check the delete worked
1461 if (index_dir.exists()) {
1462 throw new Exception("Index directory could not be removed.");
1463 }
1464 }
1465
1466 // Move the building directory to become the new index directory
1467 if (building_dir.renameTo(index_dir) == false) {
1468 throw new Exception("Build directory could not be moved.");
1469 }
1470 }
1471
1472 // Otherwise copy everything in the building dir into the index dir
1473 else {
1474 moveContentsInto(building_dir, index_dir);
1475 }
1476 }
1477 catch (Exception exception) {
1478 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);
1479 return false;
1480 }
1481 return true;
1482 }
1483
1484
1485 /** Moves all the files in one directory into another, overwriting existing files */
1486 private void moveContentsInto(File source_directory, File target_directory)
1487 {
1488 File[] source_files = source_directory.listFiles();
1489 for (int i = 0; i < source_files.length; i++) {
1490 File source_file = source_files[i];
1491 File target_file = new File(target_directory, source_file.getName());
1492
1493 if (source_file.isDirectory()) {
1494 moveContentsInto(source_file, target_file);
1495 source_file.delete();
1496 }
1497 else {
1498 if (target_file.exists()) {
1499 target_file.delete();
1500 }
1501
1502 source_file.renameTo(target_file);
1503 }
1504 }
1505 }
1506
1507
1508 private boolean searchArchivesForMetadata(File archive_directory) {
1509 /** @todo - ensure GreenstoneArchiveParser works as expected. */
1510 return true;
1511 }
1512
1513 /** now this returns true if successful, false if unsuccessful or cancelled */
1514 private boolean searchForMetadata(File current_file) {
1515 boolean success = true;
1516 if(current_file.isFile() && current_file.getName().equals(Utility.METADATA_XML)) {
1517 success = collection.msm.searchForMetadata(null, new FileNode(current_file), false, true); // A dummy run only.
1518 }
1519 else {
1520 File[] children_files = current_file.listFiles();
1521 for(int i = 0; success && children_files != null && i < children_files.length; i++) {
1522 success = searchForMetadata(children_files[i]);
1523 }
1524 }
1525 return success;
1526 }
1527
1528 private boolean searchForMetadata(TreeModel collection_tree, FileNode current_node) {
1529 File source_file = current_node.getFile();
1530 String source_file_name = source_file.getName();
1531 if (source_file_name.equals(Utility.METADATA_XML) || source_file_name.equals("CVS")) {
1532 return true;
1533 }
1534 if (collection.msm.searchForMetadata(current_node, current_node, false)== false) {
1535 return false;
1536 }
1537 int num_children = collection_tree.getChildCount(current_node);
1538 for (int i=0; i<num_children; i++) {
1539 FileNode child = (FileNode)collection_tree.getChild(current_node, i);
1540 if (searchForMetadata(collection_tree, child)==false) {
1541 return false;
1542 }
1543 }
1544 return true;
1545 }
1546
1547 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title) {
1548 boolean first_name = true;
1549 boolean first_extra = true;
1550 String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
1551
1552 HashMap mappings = collection.msm.profiler.getActions(collection_path);
1553 if(mappings == null) {
1554 DebugStream.println("Mappings is null, which is odd. Leaving all configuration commands which use metadata as they are.");
1555 }
1556
1557 // 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.
1558 try {
1559 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1560 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1561 String command = null;
1562 while((command = in.readLine()) != null) {
1563 if (command.length()==0) {
1564 // output a new line
1565 out.newLine();
1566 continue;
1567 }
1568 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1569 while(command.trim().endsWith("\\")) {
1570 command = command.substring(0, command.lastIndexOf("\\"));
1571 String next_line = in.readLine();
1572 if(next_line != null) {
1573 command = command + next_line;
1574 }
1575 }
1576 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1577 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1578 String command_type_str = tokenizer.nextToken().toLowerCase();
1579
1580 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1581 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1582 StringBuffer new_command = new StringBuffer(command_type_str);
1583 String meta_name = tokenizer.nextToken();
1584 new_command.append(' ');
1585 new_command.append(meta_name);
1586 while (tokenizer.hasMoreTokens()) {
1587 new_command.append(' ');
1588 new_command.append(tokenizer.nextToken());
1589 }
1590 if (meta_name.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR)) {
1591 // dont save
1592 } else {
1593 write(out, new_command.toString());
1594 }
1595 new_command = null;
1596 continue;
1597 } // if collectionmeta
1598
1599 if(command_type_str.equals(Utility.CFG_CLASSIFY)) {
1600 StringBuffer text = new StringBuffer(command_type_str);
1601 // Read in the classifier command watching for hfile, metadata and sort arguments.
1602 String buttonname = null;
1603 String hfile = null;
1604 String new_metadata = null;
1605 String old_metadata = null;
1606
1607 while(tokenizer.hasMoreTokens()) {
1608 String token = tokenizer.nextToken();
1609 if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
1610 if(tokenizer.hasMoreTokens()) {
1611 text.append(" ");
1612 text.append(token);
1613 token = tokenizer.nextToken();
1614 hfile = token;
1615 }
1616 }
1617 else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
1618 if(tokenizer.hasMoreTokens()) {
1619 text.append(" ");
1620 text.append(token);
1621 String temp_metadata = tokenizer.nextToken();
1622 String replacement = null;
1623 if(mappings != null) {
1624 replacement = (String) mappings.get(temp_metadata);
1625 }
1626 if(replacement != null) {
1627 token = replacement;
1628 old_metadata = temp_metadata;
1629 new_metadata = replacement;
1630 }
1631 else {
1632 token = temp_metadata;
1633 }
1634 temp_metadata = null;
1635 replacement = null;
1636 }
1637 }
1638 else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
1639 if(tokenizer.hasMoreTokens()) {
1640 text.append(" ");
1641 text.append(token);
1642 String temp_metadata = tokenizer.nextToken();
1643 String replacement = null;
1644 if(mappings != null) {
1645 replacement = (String) mappings.get(temp_metadata);
1646 }
1647 if(replacement != null) {
1648 token = replacement;
1649 }
1650 else {
1651 token = temp_metadata;
1652 }
1653 temp_metadata = null;
1654 replacement = null;
1655 }
1656 }
1657 else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
1658 buttonname = token;
1659 }
1660 text.append(' ');
1661 text.append(token);
1662 token = null;
1663 }
1664
1665 // 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)!
1666 if(old_metadata != null && new_metadata != null && buttonname == null) {
1667 text.append(' ');
1668 text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
1669 text.append(' ');
1670 text.append(old_metadata);
1671 }
1672 command = text.toString();
1673 // Replace the hfile if we found it
1674 if(hfile != null && new_metadata != null) {
1675 command = command.replaceAll(hfile, new_metadata + ".txt");
1676 }
1677
1678 buttonname = null;
1679 hfile = null;
1680 new_metadata = null;
1681 old_metadata = null;
1682 write(out, command);
1683 } else {
1684 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
1685 StringBuffer new_command = new StringBuffer(command_type_str);
1686 while (tokenizer.hasMoreTokens()) {
1687 new_command.append(' ');
1688 new_command.append(tokenizer.nextToken());
1689 }
1690
1691 command = new_command.toString();
1692
1693 // 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.
1694 // we really want to build up the whole command here
1695 boolean format_command = command_type_str.equals(Utility.CFG_FORMAT);
1696 // Replace mapping strings
1697 if(mappings != null) {
1698 for(Iterator keys = mappings.keySet().iterator(); keys.hasNext(); ) {
1699 String target = (String) keys.next();
1700 String replacement = (String) mappings.get(target);
1701 if(format_command) {
1702 target = "\\[" + target + "\\]";
1703 replacement = "{Or}{[" + replacement + "]," + target + "}";
1704 }
1705 command = command.replaceAll(target, replacement);
1706 }
1707 }
1708 write(out, command);
1709 }
1710 tokenizer = null;
1711 }
1712 in.close();
1713 in = null;
1714 out.flush();
1715 out.close();
1716 out = null;
1717 }
1718 catch(Exception error) {
1719 DebugStream.printStackTrace(error);
1720 }
1721 // All done, I hope.
1722 }
1723
1724 private void write(BufferedWriter out, String message)
1725 throws Exception {
1726 out.write(message, 0, message.length());
1727 out.newLine();
1728 }
1729
1730 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
1731 private class FMTreeModelListener
1732 implements TreeModelListener {
1733 /** 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.
1734 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1735 */
1736 public void treeNodesChanged(TreeModelEvent event) {
1737 if(collection != null) {
1738 collection.setSaved(false);
1739 }
1740 }
1741 /** 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.
1742 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1743 */
1744 public void treeNodesInserted(TreeModelEvent event) {
1745 if(collection != null) {
1746 collection.setSaved(false);
1747 }
1748 }
1749 /** 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.
1750 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1751 */
1752 public void treeNodesRemoved(TreeModelEvent event) {
1753 if(collection != null) {
1754 collection.setSaved(false);
1755 }
1756 }
1757 /** 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.
1758 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1759 */
1760 public void treeStructureChanged(TreeModelEvent event) {
1761 if(collection != null) {
1762 collection.setSaved(false);
1763 }
1764 }
1765 }
1766}
Note: See TracBrowser for help on using the repository browser.