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

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

Replaced all Gatherer.print* with DebugStream.print*.

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