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

Last change on this file since 7739 was 7739, checked in by davidb, 20 years ago

General restructuring to allow GLI to be run as an applet.
Main area of change: making code look in the JAR file first
for a file rather than assume on local file system.
Stores data locally on system in '.gli' or Greenstone/GLI
folder in users home space for subsequent uses of applet.

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