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

Last change on this file since 14974 was 14974, checked in by davidb, 16 years ago

Changes to GLI to support export into Fedora. New utility called flisvn diff gems/MetadataSetManager.java

  • Property svn:keywords set to Author Date Id Revision
File size: 70.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.collection;
38
39import java.io.*;
40import java.util.*;
41import javax.swing.*;
42import javax.swing.event.*;
43import javax.swing.filechooser.FileSystemView;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.Configuration;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
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.greenstone.Classifiers;
54import org.greenstone.gatherer.greenstone.LocalGreenstone;
55import org.greenstone.gatherer.greenstone.LocalLibraryServer;
56import org.greenstone.gatherer.greenstone.Plugins;
57import org.greenstone.gatherer.greenstone3.ServletConfiguration;
58import org.greenstone.gatherer.gui.LockFileDialog;
59import org.greenstone.gatherer.gui.ModalProgressPopup;
60import org.greenstone.gatherer.gui.WarningDialog;
61import org.greenstone.gatherer.metadata.DocXMLFileManager;
62import org.greenstone.gatherer.metadata.MetadataChangedListener;
63import org.greenstone.gatherer.metadata.MetadataSet;
64import org.greenstone.gatherer.metadata.MetadataSetManager;
65import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
66import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
67import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
68import org.greenstone.gatherer.shell.GShell;
69import org.greenstone.gatherer.shell.GShellEvent;
70import org.greenstone.gatherer.shell.GShellListener;
71import org.greenstone.gatherer.shell.GShellProgressMonitor;
72import org.greenstone.gatherer.util.Codec;
73import org.greenstone.gatherer.util.StaticStrings;
74import org.greenstone.gatherer.util.Utility;
75import org.greenstone.gatherer.util.XMLTools;
76import org.w3c.dom.*;
77
78/** 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.
79 * @author John Thompson
80 * @version 2.3
81 */
82public class CollectionManager
83 implements GShellListener, MetadataChangedListener
84{
85 /** Are we currently in the process of building? */
86 static private boolean building = false;
87 /** Are we currently in the process of importing? */
88 static private boolean importing = false;
89 /** The objects listening for CollectionContentsChanged events. */
90 static private ArrayList collection_contents_changed_listeners = new ArrayList();
91 /** The collection this manager is managing! */
92 static private Collection collection = null;
93 /** The collection tree (used in both Gather and Enrich panes). */
94 static private CollectionTree collection_tree = null;
95 /** The collection tree model. */
96 static private CollectionTreeModel collection_tree_model = null;
97 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
98 static private FMTreeModelListener fm_tree_model_listener = null;
99 /** The monitor resposible for parsing the build process. */
100 static private GShellProgressMonitor build_monitor = null;
101 /** The monitor resposible for parsing the import process. */
102 static private GShellProgressMonitor import_monitor = null;
103
104 /** The name of the standard lock file. */
105 static final public String LOCK_FILE = "gli.lck";
106
107 /** Used to indicate the source of the message is the file collection methods. */
108 static final public int COLLECT = 3;
109 /** Used to indicate the source of the message is the building methods. */
110 static final public int BUILDING = 5;
111
112
113 /** Constructor. */
114 public CollectionManager() {
115 // Initialisation.
116 this.building = false;
117 this.importing = false;
118 this.collection = null;
119
120 MetadataXMLFileManager.addMetadataChangedListener(this);
121
122 // If using a remote Greenstone server, delete the local collect directory because it will be out of date
123 if (Gatherer.isGsdlRemote) {
124 System.err.println("Deleting user's local collect directory...");
125 Utility.delete(new File(Gatherer.getCollectDirectoryPath()));
126 System.err.println("Done.");
127 new File(Gatherer.getCollectDirectoryPath()).mkdirs();
128 }
129 }
130
131
132 static public void addCollectionContentsChangedListener(CollectionContentsChangedListener listener)
133 {
134 collection_contents_changed_listeners.add(listener);
135 }
136
137
138 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
139 * @see org.greenstone.gatherer.Configuration
140 * @see org.greenstone.gatherer.Gatherer
141 * @see org.greenstone.gatherer.collection.Collection
142 * @see org.greenstone.gatherer.gui.BuildOptions
143 * @see org.greenstone.gatherer.shell.GShell
144 * @see org.greenstone.gatherer.shell.GShellListener
145 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
146 * @see org.greenstone.gatherer.util.Utility
147 */
148 public void buildCollection(boolean incremental_build)
149 {
150
151 DebugStream.println("In CollectionManager.buildCollection(), incremental_build: " + incremental_build);
152 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
153 building = true;
154
155 // Generate the buildcol.pl command
156 ArrayList command_parts_list = new ArrayList();
157 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
158 command_parts_list.add(Configuration.perl_path);
159 command_parts_list.add("-S");
160 }
161
162 if (Configuration.fedora_info.isActive()) {
163 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-buildcol.pl");
164
165 command_parts_list.add("-hostname");
166 command_parts_list.add(Configuration.fedora_info.getHostname());
167
168 command_parts_list.add("-port");
169 command_parts_list.add(Configuration.fedora_info.getPort());
170
171 command_parts_list.add("-username");
172 command_parts_list.add(Configuration.fedora_info.getUsername());
173
174 command_parts_list.add("-password");
175 command_parts_list.add(Configuration.fedora_info.getPassword());
176
177 command_parts_list.add("-protocol");
178 command_parts_list.add(Configuration.fedora_info.getProtocol());
179
180 }
181 else {
182 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "buildcol.pl");
183 }
184 command_parts_list.add("-gli");
185 command_parts_list.add("-language");
186 command_parts_list.add(Configuration.getLanguage());
187 command_parts_list.add("-collectdir");
188 command_parts_list.add(getCollectDirectory());
189
190 // If the user hasn't manually specified "-keepold" or "-removeold" then pick one based on incremental_build
191 if (!collection.build_options.getValueEnabled("keepold") && !collection.build_options.getValueEnabled("removeold")) {
192 command_parts_list.add(incremental_build ? "-keepold" : "-removeold");
193 }
194
195 String[] build_options = collection.build_options.getValues();
196 for (int i = 0; i < build_options.length; i++) {
197 command_parts_list.add(build_options[i]);
198 }
199
200 command_parts_list.add(collection.getName());
201
202 // Run the buildcol.pl command
203 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
204 GShell shell = new GShell(command_parts, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
205 shell.addGShellListener(Gatherer.g_man.create_pane);
206 shell.addGShellListener(Gatherer.g_man.format_pane);
207 shell.start();
208
209 }
210
211
212 /** Used to determine whether the currently active collection has been built.
213 * @return A boolean indicating the built status of the collection.
214 */
215 public boolean built() {
216 if(collection != null) {
217 // Determine if the collection has been built by looking for the build.cfg (gs20 buildConfig.xml (gs3) or export.inf (fedora) file
218 String file_name = "";
219
220 if (Gatherer.GS3) {
221 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CONFIG_XML;
222 }
223 else {
224 if (Configuration.fedora_info.isActive()) {
225 // Fedora build
226 //file_name = getLoadedCollectionArchivesDirectoryPath() + "import.inf";
227 file_name = getLoadedCollectionExportDirectoryPath() + "export.inf";
228 }
229 else {
230 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CFG;
231 }
232 }
233
234 File test_file = new File(file_name);
235 return test_file.exists();
236 }
237 return false;
238 }
239
240
241 /** 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 */
242 static private boolean canDelete(File file)
243 {
244 if (!file.isDirectory()) {
245 return file.canWrite();
246 }
247 File [] file_list = file.listFiles();
248 for (int i=0; i<file_list.length; i++) {
249 if (!canDelete(file_list[i])) {
250 return false;
251 }
252 }
253 return true;
254 }
255
256
257 /** Called to close the current collection and remove its lock file.
258 * @see org.greenstone.gatherer.Gatherer
259 * @see org.greenstone.gatherer.collection.Collection
260 * @see org.greenstone.gatherer.util.Utility
261 */
262 public void closeCollection() {
263 DebugStream.println("Close collection: " + collection.getName());
264
265 // Remove the lock on this file, then remove the collection.
266 File lock_file = new File(getLoadedCollectionDirectoryPath() + LOCK_FILE);
267 lock_file.delete();
268 if (lock_file.exists()) {
269 System.err.println("Warning: Lockfile was not successfully deleted.");
270 }
271
272 // Remove the lock file on the server
273 if (Gatherer.isGsdlRemote) {
274 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), lock_file);
275 }
276
277 MetadataSetManager.clearMetadataSets();
278 MetadataXMLFileManager.clearMetadataXMLFiles();
279 DocXMLFileManager.clearDocXMLFiles();
280 ProfileXMLFileManager.clearProfileXMLFile();
281
282 collection.destroy();
283 collection = null;
284 collection_tree_model = null;
285 //Configuration.setCollectionConfiguration(null);
286 Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
287 if (Gatherer.g_man != null) {
288 Gatherer.g_man.updateUI(); // !!! Necessary?
289 }
290 }
291
292//This method is no longer used in gs3 since the modification of CollectionConfiguration.java
293// public void convertToGS3Collection() {
294// // Generate the convert_coll_from_gs2.pl command
295// ArrayList command_parts_list = new ArrayList();
296// if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
297// command_parts_list.add(Configuration.perl_path);
298// command_parts_list.add("-S");
299// }
300// command_parts_list.add(Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl");
301// command_parts_list.add("-collectdir");
302// command_parts_list.add(getCollectDirectory());
303// command_parts_list.add(collection.getName());
304//
305// // Run the convert_coll_from_gs2.pl command
306// String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
307// GShell process = new GShell(command_parts, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
308// process.addGShellListener(this);
309// process.run(); // Don't bother threading this... yet
310//
311// }
312
313 /** When basing a new collection on an existing one, we need to copy
314 * over some extra directories: images and macros
315 */
316 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
317 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
318 return false;
319 }
320 DebugStream.println("Copying images and macros dirs from the base collection");
321 try {
322 // do the images dir
323 File base_coll_images = new File(base_coll_dir, "images");
324 if (base_coll_images.isDirectory()) {
325 // copy all the images over
326 File new_coll_images = new File(new_coll_dir, "images");
327 new_coll_images.mkdirs();
328
329 // copy the contents over
330 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_images, new_coll_images);
331 }
332 }
333 catch (Exception e) {
334 DebugStream.println("Couldn't copy over the images dir from the base collection: "+e.toString());
335 }
336 try {
337 // do the macros dir
338 File base_coll_macros = new File(base_coll_dir, "macros");
339 if (base_coll_macros.isDirectory()) {
340 // copy all the macros over
341 File new_coll_macros = new File(new_coll_dir, "macros");
342 new_coll_macros.mkdirs();
343
344 // copy the contents over
345 Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_macros, new_coll_macros);
346 }
347 }
348 catch (Exception e) {
349 DebugStream.println("Couldn't copy over the macros dir from the base collection: "+e.toString());
350 }
351 return true;
352 }
353
354 /** 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 collection 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.
355 * @param description a description of the collection as a String
356 * @param email the email address of the author/maintainer as a String
357 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
358 * @param title the longer title of the collection as a String
359 * @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
360 * @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
361 */
362 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
363 {
364 // Display a modal progress popup to indicate that the collection is being loaded
365 ModalProgressPopup create_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Creating_Collection"), Dictionary.get("CollectionManager.Creating_Collection_Please_Wait"));
366 create_collection_progress_popup.display();
367
368 // Create the collection on a separate thread so the progress bar updates correctly
369 (new CreateCollectionTask(description, email, name, title, base_collection_directory, metadata_sets, create_collection_progress_popup)).start();
370 }
371
372
373 private class CreateCollectionTask
374 extends Thread
375 {
376 private String description = null;
377 private String email = null;
378 private String name = null;
379 private String title = null;
380 private File base_collection_directory = null;
381 private ArrayList metadata_sets = null;
382 private ModalProgressPopup create_collection_progress_popup = null;
383
384 public CreateCollectionTask(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets, ModalProgressPopup create_collection_progress_popup)
385 {
386 this.description = description;
387 this.email = email;
388 this.name = name;
389 this.title = title;
390 this.base_collection_directory = base_collection_directory;
391 this.metadata_sets = metadata_sets;
392 this.create_collection_progress_popup = create_collection_progress_popup;
393 }
394
395 public void run()
396 {
397 createCollectionInternal(description, email, name, title, base_collection_directory, metadata_sets);
398 create_collection_progress_popup.close();
399 }
400 }
401
402
403 private void createCollectionInternal(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
404 {
405 try {
406 // first make sure that the collect directory exists
407 File collect_dir = new File(getCollectDirectory());
408 if (!collect_dir.exists()) {
409 collect_dir.mkdirs();
410 }
411
412 // Create the new collection
413 makeCollection(name, email);
414
415 // Check that the collection has been created successfully
416 String collection_directory_path = getCollectionDirectoryPath(name);
417 if (!new File(collection_directory_path).exists()) {
418 // If there is no collection directory then the creation was unsuccessful, or cancelled
419
420 return;
421 }
422
423 // Check for the existence of the collection configuration file
424 String file_name = ((Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG);
425 File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + file_name);
426
427 if (!collect_cfg_file.exists()) {
428 System.err.println("Error: no " + file_name + " file has been created!");
429 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", Dictionary.get("CollectionManager.No_Config_File")), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
430 return;
431 }
432
433 // ACTIVE_DIR/log/
434 File log_dir = new File(collection_directory_path + "log");
435 log_dir.mkdirs();
436
437 // Make sure an import folder exists
438 File collection_import_directory = new File(collection_directory_path + "import");
439 if (!collection_import_directory.exists()) {
440 collection_import_directory.mkdirs();
441 if (Gatherer.isGsdlRemote) {
442 RemoteGreenstoneServer.newCollectionDirectory(name, collection_import_directory);
443 }
444 }
445
446 // Now create the collection object around the directory.
447 collection = new Collection(new File(collection_directory_path, name + ".col"));
448
449 // "-removeold" is on by default for import.pl
450 collection.import_options.setValue("removeold", true, null);
451
452 MetadataSetManager.clearMetadataSets();
453 MetadataXMLFileManager.clearMetadataXMLFiles();
454 DocXMLFileManager.clearDocXMLFiles();
455
456 // Import default metadata sets, if any
457 // for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
458 // importMetadataSet((MetadataSet) metadata_sets.get(i));
459 // }
460
461 ProfileXMLFileManager.loadProfileXMLFile(new File(collection_directory_path + "metadata"));
462
463 // Before creating the CollectionDesignManager check if we are basing it upon some other collection
464 if (base_collection_directory != null) {
465 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
466
467 // If we're using a remote Greenstone server, download the collection shell to get the files needed
468 if (Gatherer.isGsdlRemote) {
469 String base_collection_name = base_collection_directory.getName();
470 RemoteGreenstoneServer.downloadCollection(base_collection_name);
471 }
472
473 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
474 // copy over other needed directories
475 copyExtraBaseCollStuff(new File(collection_directory_path), base_collection_directory);
476
477 // Try to import any existing metadata sets for this collection
478 // Look in base_collection_directory/metadata and import any metadata sets found.
479 File base_metadata_directory = new File(base_collection_directory, "metadata");
480 ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
481 if (base_metadata_sets != null) {
482 for (int i = 0; i < base_metadata_sets.size(); i++) {
483 importMetadataSet((MetadataSet) base_metadata_sets.get(i));
484 }
485 }
486 else {
487 DebugStream.println("This base collection has no metadata directory.");
488 }
489
490 // Now we update our collect.cfg
491 DebugStream.println("Copy and update " + file_name + " from base collection.");
492
493 if (Gatherer.GS3 == true) {
494 updateCollectionConfigXML(new File(base_collection_directory, Utility.CONFIG_GS3_FILE),
495 new File(collection_directory_path, Utility.CONFIG_GS3_FILE));
496 } else {
497 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE),
498 new File(collection_directory_path, Utility.CONFIG_FILE),
499 description, email, title);
500 }
501 }
502
503 // Load the default metadata sets
504 addDefaultMetadataSets();
505
506 // Make sure we always have the extracted metadata set
507 addRequiredMetadataSets();
508
509 collection.cdm = new CollectionDesignManager(new File(getLoadedCollectionCfgFilePath()));
510
511 // We always set title and description here rather than calling mkcol.pl with Unicode arguments
512 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
513 collection_name_collectionmeta.setValue(title);
514 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
515 collection_extra_collectionmeta.setValue(description);
516
517 // 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. This update is done to the internal xml structure which may be saved into collect.cfg or collectionConfig.xml accordingly.
518 if (base_collection_directory != null) {
519 // Update the creator and maintainer
520 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
521 creator_collectionmeta.setValue(email);
522 creator_collectionmeta = null;
523 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
524 maintainer_collectionmeta.setValue(email);
525 maintainer_collectionmeta = null;
526
527 // All collections based on others are automatically public
528 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
529 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
530 public_collectionmeta = null;
531
532 // Finally reset the icons
533 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
534 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
535 icon_collection_collectionmeta = null;
536 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
537 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
538 icon_collection_small_collectionmeta = null;
539 }
540
541 saveCollection();
542
543 // Create a lock file
544 createLockFile(new File(collection_directory_path, LOCK_FILE));
545
546 // We're done. Let everyone know.
547 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
548 }
549 catch (Exception error) {
550 DebugStream.printStackTrace(error);
551 }
552 }
553
554
555 private void createLockFile(File lock_file)
556 {
557 try {
558 Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
559 String user_name = System.getProperty("user.name");
560 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
561 person_element.appendChild(default_lockfile.createTextNode(user_name));
562 person_element = null;
563 user_name = null;
564 String machine_name = Utility.getMachineName();
565 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
566 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
567 machine_element = null;
568 machine_name = null;
569 String date_time = Utility.getDateString();
570 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
571 date_element.appendChild(default_lockfile.createTextNode(date_time));
572 date_element = null;
573 date_time = null;
574 XMLTools.writeXMLFile(lock_file, default_lockfile);
575 }
576 catch (Exception exception) {
577 DebugStream.printStackTrace(exception);
578 }
579 }
580
581
582 public boolean deleteCollection(String collection_name)
583 {
584 // First we must release the collection from the local library, if it's running
585 if (LocalLibraryServer.isRunning() == true) {
586 LocalLibraryServer.releaseCollection(collection_name);
587 }
588
589 // Delete the collection on the server if we're using a remote Greenstone
590 if (Gatherer.isGsdlRemote) {
591 RemoteGreenstoneServer.deleteCollection(collection_name);
592 }
593
594 // Now delete the collection directory
595 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
596 }
597
598
599 public void fireFileAddedToCollection(File file)
600 {
601 // Send the event off to all the CollectionContentsChangedListeners
602 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
603 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
604 }
605 }
606
607
608 /** Retrieve the current collection.
609 * @return The <strong>Collection</strong> itself.
610 */
611 public Collection getCollection() {
612 return collection;
613 }
614
615
616 /** Returns the absolute filename of the specified collection's directory.
617 */
618 static public String getCollectionDirectoryPath(String collection_name)
619 {
620 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
621 }
622
623
624 /** Returns the absolute filename of the loaded collection's archives directory.
625 */
626 static public String getLoadedCollectionArchivesDirectoryPath()
627 {
628 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
629 }
630
631 /** Returns the absolute filename of the loaded collection's export directory.
632 */
633 static public String getLoadedCollectionExportDirectoryPath()
634 {
635 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
636 }
637
638
639
640 /** Returns the absolute filename of the loaded collection's building directory.
641 */
642 static public String getLoadedCollectionBuildingDirectoryPath()
643 {
644 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
645 }
646
647
648 /** Returns the absolute filename of the loaded collection's collect.cfg file.
649 */
650 static public String getLoadedCollectionCfgFilePath()
651 {
652 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
653 return getLoadedCollectionEtcDirectoryPath() + path;
654 }
655
656
657 /** Returns the absolute filename of the loaded collection's directory.
658 */
659 static public String getLoadedCollectionDirectoryPath()
660 {
661 return Gatherer.getCollectDirectoryPath() + collection.getName() + File.separator;
662 }
663
664
665 /** Returns the absolute filename of the loaded collection's etc directory.
666 */
667 static public String getLoadedCollectionEtcDirectoryPath()
668 {
669 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
670 }
671
672
673 /** Returns the absolute filename of the loaded collection's .col file.
674 */
675 static public String getLoadedCollectionColFilePath()
676 {
677 return getLoadedCollectionDirectoryPath() + collection.getName() + ".col";
678 }
679
680
681 /** Returns the absolute filename of the loaded collection's images directory.
682 */
683 static public String getLoadedCollectionImagesDirectoryPath()
684 {
685 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
686 }
687
688
689 /** Returns the absolute filename of the loaded collection's import directory.
690 */
691 static public String getLoadedCollectionImportDirectoryPath()
692 {
693 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
694 }
695
696
697 /** Returns the absolute filename of the loaded collection's index directory.
698 */
699 static public String getLoadedCollectionIndexDirectoryPath()
700 {
701 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
702 }
703
704
705 /** Returns the absolute filename of the loaded collection's log directory.
706 */
707 static public String getLoadedCollectionLogDirectoryPath()
708 {
709 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
710 }
711
712
713 /** Returns the absolute filename of the loaded collection's macros directory.
714 */
715 static public String getLoadedCollectionMacrosDirectoryPath()
716 {
717 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
718 }
719
720
721 /** Returns the absolute filename of the loaded collection's metadata directory.
722 */
723 static public String getLoadedCollectionMetadataDirectoryPath()
724 {
725 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
726 }
727
728
729 /** Returns the name of the loaded collection.
730 */
731 static public String getLoadedCollectionName()
732 {
733 if (collection != null) {
734 return collection.getName();
735 }
736
737 return null;
738 }
739
740
741 public CollectionTree getCollectionTree()
742 {
743 if (collection_tree == null) {
744 collection_tree = new CollectionTree(collection_tree_model, true);
745 }
746
747 return collection_tree;
748 }
749
750
751 /** Retrieve the tree model associated with the current collection. */
752 public CollectionTreeModel getCollectionTreeModel()
753 {
754 if (collection_tree_model == null && collection != null) {
755 // Use the import directory to generate a new CollectionTreeModel
756 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
757 // Ensure that the manager is a change listener for the tree.
758 if (fm_tree_model_listener == null) {
759 fm_tree_model_listener = new FMTreeModelListener();
760 }
761 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
762 }
763 return collection_tree_model;
764 }
765
766
767 /** This method when called, creates a new GShell in order to run the import.pl script.
768 * @see org.greenstone.gatherer.Configuration
769 * @see org.greenstone.gatherer.Gatherer
770 * @see org.greenstone.gatherer.gui.BuildOptions
771 * @see org.greenstone.gatherer.shell.GShell
772 * @see org.greenstone.gatherer.shell.GShellListener
773 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
774 * @see org.greenstone.gatherer.util.Utility
775 */
776 public void importCollection() {
777 importing = true;
778
779 if (!saved()) {
780 DebugStream.println("CollectionManager.importCollection().forcesave");
781 import_monitor.saving();
782 saveCollection();
783 }
784
785 DebugStream.println("CollectionManager.importCollection()");
786 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
787 //check that we can remove the old index before starting import
788 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
789 if (index_dir.exists()) {
790 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
791 if (!canDelete(index_dir)) {
792 // tell the user
793 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
794 // tell the gui manager
795 // a message for the building log
796 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
797 Gatherer.g_man.create_pane.message(event);
798 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
799 Gatherer.g_man.create_pane.processComplete(event);
800 importing = false;
801 return;
802 }
803 }
804
805 // Generate the import.pl command
806 ArrayList command_parts_list = new ArrayList();
807 if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
808 command_parts_list.add(Configuration.perl_path);
809 command_parts_list.add("-S");
810 }
811
812 if (Configuration.fedora_info.isActive()) {
813 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "g2f-import.pl");
814
815 command_parts_list.add("-hostname");
816 command_parts_list.add(Configuration.fedora_info.getHostname());
817
818 command_parts_list.add("-port");
819 command_parts_list.add(Configuration.fedora_info.getPort());
820
821 command_parts_list.add("-username");
822 command_parts_list.add(Configuration.fedora_info.getUsername());
823
824 command_parts_list.add("-password");
825 command_parts_list.add(Configuration.fedora_info.getPassword());
826
827 command_parts_list.add("-protocol");
828 command_parts_list.add(Configuration.fedora_info.getProtocol());
829 }
830 else {
831 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
832 }
833
834 command_parts_list.add("-gli");
835 command_parts_list.add("-language");
836 command_parts_list.add(Configuration.getLanguage());
837 command_parts_list.add("-collectdir");
838 command_parts_list.add(getCollectDirectory());
839
840 String[] import_options = collection.import_options.getValues();
841 for (int i = 0; i < import_options.length; i++) {
842 command_parts_list.add(import_options[i]);
843 }
844
845 command_parts_list.add(collection.getName());
846
847 // Run the import.pl command
848 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
849 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
850 shell.addGShellListener(Gatherer.g_man.create_pane);
851 shell.addGShellListener(Gatherer.g_man.format_pane);
852 shell.start();
853 DebugStream.println("CollectionManager.importCollection().return");
854
855 importing = false;
856 }
857
858
859 public void importMetadataSet(MetadataSet external_metadata_set)
860 {
861 // Copy the .mds file into the collection's "metadata" folder...
862 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
863
864 // ...but not if it is the redundant "hidden.mds" file
865 if (external_metadata_set_file.getName().equals("hidden.mds")) {
866 return;
867 }
868
869 // ...and only if it doesn't already exist
870 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
871 if (!metadata_set_file.exists()) {
872 try {
873 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
874
875 // If we're using a remote Greenstone server, upload the metadata file
876 if (Gatherer.isGsdlRemote) {
877 RemoteGreenstoneServer.uploadCollectionFile(collection.getName(), metadata_set_file);
878 }
879 }
880 catch (Exception exception) {
881 DebugStream.printStackTrace(exception);
882 }
883
884 // Load it into the MetadataSetManager
885 MetadataSetManager.loadMetadataSet(metadata_set_file);
886 }
887 }
888
889
890 /** 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.
891 * @return true if the gli is currently importing
892 */
893 public boolean isImporting() {
894 return importing;
895 }
896
897
898 public void loadCollection(String collection_file_path)
899 {
900 // Display a modal progress popup to indicate that the collection is being loaded
901 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
902 load_collection_progress_popup.display();
903
904 // Load the collection on a separate thread so the progress bar updates correctly
905 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
906 }
907
908
909 private class LoadCollectionTask
910 extends Thread
911 {
912 private String collection_file_path = null;
913 private ModalProgressPopup load_collection_progress_popup = null;
914
915 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
916 {
917 this.collection_file_path = collection_file_path;
918 this.load_collection_progress_popup = load_collection_progress_popup;
919 }
920
921 public void run()
922 {
923 loadCollectionInternal(collection_file_path);
924 load_collection_progress_popup.close();
925 Gatherer.setMenuBarEnabled(true);
926 }
927 }
928
929
930 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
931 * @param location The path to the collection as a <strong>String</strong>.
932 * @see org.greenstone.gatherer.Configuration
933 * @see org.greenstone.gatherer.Gatherer
934 * @see org.greenstone.gatherer.collection.Collection
935 * @see org.greenstone.gatherer.util.Utility
936 */
937 private void loadCollectionInternal(String location)
938 {
939 DebugStream.println("Loading collection " + location + "...");
940
941 if (Gatherer.isGsdlRemote) {
942 String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
943 if (RemoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
944 return;
945 }
946 }
947
948 // Check we have actually been given a .col file.
949 if (!location.endsWith(".col")) {
950 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
951 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
952 return;
953 }
954
955 // Check that the collection configuration file is available
956 File collection_file = new File(location);
957
958 // Ensure that the directory exists
959 File collection_directory = collection_file.getParentFile();
960
961 if (collection_directory == null || !collection_directory.exists()) {
962 // We can't open this
963 System.err.println("CollectionManager.loadCollection: No collection directory.");
964 return;
965 }
966
967 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
968 File collection_config_file = new File(collection_directory, file_str);
969 if (!collection_config_file.exists()) {
970 System.err.println("CollectionManager.loadCollection: No config file.");
971 collection_directory = null;
972 collection_config_file = null;
973 return;
974 }
975
976 // Ensure that an import directory exists for this collection
977 File collection_import_directory = new File(collection_directory, "import");
978 if (!collection_import_directory.exists()) {
979 collection_import_directory.mkdir();
980 }
981
982 // Special case of a user trying to open an old greenstone collection.
983 boolean non_gli_collection = false;
984 File collection_metadata_directory = new File(collection_directory, "metadata");
985 if (!collection_metadata_directory.exists()) {
986 DebugStream.println("Loading non-gatherer collection...");
987 // Show a warning message in case user wants to quit now
988 non_gli_collection = true;
989 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
990 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
991 legacy_dialog.dispose();
992 collection_directory = null;
993 collection_config_file = null;
994 return;
995 }
996 legacy_dialog.dispose();
997
998 }
999
1000 // Now determine if a lock already exists on this collection.
1001 String collection_name = collection_directory.getName();
1002 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1003 if (lock_file.exists()) {
1004 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1005 int choice = dialog.getChoice();
1006 dialog.dispose();
1007 dialog = null;
1008
1009 if (choice != LockFileDialog.YES_OPTION) {
1010 // user has cancelled
1011 lock_file = null;
1012 collection_directory = null;
1013 collection_config_file = null;
1014 return;
1015 }
1016
1017 lock_file.delete();
1018 }
1019
1020 try {
1021 // Create a lock file.
1022 createLockFile(lock_file);
1023 // This lock file may not have been created so check
1024 if(!lock_file.canWrite()) {
1025 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1026 System.err.println("Cannot write lock file!");
1027 String args[] = new String[2];
1028 args[0] = location;
1029 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1030 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1031 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1032 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1033 //}
1034 }
1035 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1036 args = null;
1037 return;
1038 }
1039
1040 // Open the collection file
1041 this.collection = new Collection(collection_file);
1042 if (collection.error) {
1043 collection = null;
1044 // Remove lock file
1045 if (lock_file.exists()) {
1046 lock_file.delete();
1047 }
1048 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1049 }
1050
1051 MetadataSetManager.clearMetadataSets();
1052 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1053
1054 // Make sure we always have the extracted metadata set
1055 addRequiredMetadataSets();
1056
1057 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1058
1059 // If this is a non-GLI (legacy) collection, load the default metadata sets
1060 if (non_gli_collection) {
1061 addDefaultMetadataSets();
1062
1063 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1064 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1065 }
1066
1067 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1068 MetadataXMLFileManager.clearMetadataXMLFiles();
1069 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1070
1071 // Read through the doc.xml files in the archives directory
1072 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1073 DocXMLFileManager.clearDocXMLFiles();
1074 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
1075
1076 // Get a list of the collection specific classifiers and plugins
1077 Classifiers.loadClassifiersList(collection_name);
1078 Plugins.loadPluginsList(collection_name);
1079
1080 collection.cdm = new CollectionDesignManager(collection_config_file);
1081 if (non_gli_collection) {
1082 // Change the classifiers to use the namespaced element names
1083 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1084 }
1085
1086 // We're done. Let everyone know.
1087 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1088 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1089 }
1090 catch (Exception error) {
1091 // There is obviously no existing collection present.
1092 DebugStream.printStackTrace(error);
1093 error.printStackTrace();
1094 if(error.getMessage() != null) {
1095 String[] args = new String[2];
1096 args[0] = location;
1097 //args[1] = error.getMessage();
1098 args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1099 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1100 }
1101 else {
1102 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1103 }
1104 }
1105
1106 lock_file = null;
1107 collection_directory = null;
1108 collection_config_file = null;
1109 }
1110
1111
1112 private void makeCollection(String name, String email)
1113 {
1114 // Generate the mkcol.pl command
1115 ArrayList command_parts_list = new ArrayList();
1116 if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
1117 command_parts_list.add(Configuration.perl_path);
1118 command_parts_list.add("-S");
1119 }
1120 command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
1121 command_parts_list.add((Gatherer.GS3) ? Utility.GS3MODE_ARGUMENT : "");// add '-gs3mode'
1122
1123 command_parts_list.add("-collectdir");
1124 command_parts_list.add(getCollectDirectory());
1125
1126 command_parts_list.add("-win31compat");
1127 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1128
1129 if (email != null && !email.equals("")) {
1130 command_parts_list.add("-creator");
1131 command_parts_list.add(email);
1132 }
1133
1134 command_parts_list.add(name);
1135
1136 // Run the mkcol.pl command
1137 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1138
1139 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1140 process.run(); // Don't bother threading this... yet
1141 }
1142
1143
1144 /** Any implementation of GShellListener must include this method to allow the GShell to send messages to listeners. However in this case the CollectionManager is in no way interested in what the messages are, just the import events which have a specific type and are handled elsewhere. Thus we can safely ignore this event.
1145 * @param event A <strong>GShellEvent</strong> which contains a the message.
1146 */
1147 public synchronized void message(GShellEvent event) {
1148
1149 }
1150
1151
1152 public void metadataChanged(CollectionTreeNode[] file_nodes)
1153 {
1154 if (collection != null) {
1155 collection.setMetadataChanged(true);
1156 }
1157 }
1158
1159
1160 public void openCollectionFromLastTime() {
1161 // If there was an open collection last session, reopen it
1162 if (Gatherer.open_collection_file_path != null) {
1163 // Load the collection now
1164 loadCollection(Gatherer.open_collection_file_path);
1165 }
1166
1167 }
1168
1169
1170 /** This call is fired whenever a process within a GShell created by this class begins.
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 processBegun(GShellEvent event) {
1177 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1178 ///ystem.err.println("ProcessBegun " + event.getType());
1179 // If this is one of the types where we wish to lock user control
1180 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1181 }
1182 /** This call is fired whenever a process within a GShell created by this class ends.
1183 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1184 * @see org.greenstone.gatherer.Gatherer
1185 * @see org.greenstone.gatherer.gui.GUIManager
1186 * @see org.greenstone.gatherer.shell.GShell
1187 */
1188 public synchronized void processComplete(GShellEvent event) {
1189 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1190 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1191 ///ystem.err.println("Recieved process complete event - " + event);
1192 // If we were running an import, now run a build.
1193 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1194 // Finish import.
1195 collection.setImported(true);
1196 collection.setFilesChanged(false);
1197 collection.setMetadataChanged(false);
1198 buildCollection(false);
1199 }
1200 // If we were running a build, now is when we move files across.
1201 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1202
1203 if(installCollection()) {
1204 // If we have a local library running then ask it to add our newly create collection
1205 if (LocalLibraryServer.isRunning() == true) {
1206 LocalLibraryServer.addCollection(collection.getName());
1207 }
1208 else if (Gatherer.GS3) {
1209 //xiao comment out this: convertToGS3Collection();
1210 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1211 }
1212
1213 // Fire a collection changed first to update the preview etc buttons
1214 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1215
1216 // Now display a message dialog saying its all built
1217 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1218 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1219 collection_built_warning_dialog.display();
1220 collection_built_warning_dialog.dispose();
1221 collection_built_warning_dialog = null;
1222
1223 //Set nothing as needing rebuilding, as a build has just finished :-)
1224 CollectionDesignManager.resetRebuildTypeRequired();
1225 }
1226 else {
1227 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1228 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1229 DebugStream.println("Status is ok but !installCollection()");
1230 }
1231 }
1232 else if (event.getStatus() == GShell.CANCELLED) {
1233 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1234 Gatherer.g_man.repaint();
1235 }
1236 else if (event.getStatus() == GShell.ERROR) {
1237 if (event.getType() == GShell.NEW) {
1238 String name = event.getMessage();
1239 String collectDir = getCollectionDirectoryPath(name);
1240 String errMsg = "";
1241 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1242 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1243 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1244 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1245 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1246 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1247 //}
1248 }
1249 } else {
1250 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1251 }
1252 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1253 }
1254 else {
1255 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1256 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1257 }
1258
1259 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.
1260 }
1261 }
1262
1263
1264 /** Determine if the manager is ready for actions apon its collection.
1265 * @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.
1266 */
1267 static public synchronized boolean ready() {
1268 if(collection != null) {
1269 return true;
1270 }
1271 else {
1272 return false;
1273 }
1274 }
1275
1276
1277 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1278 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1279 */
1280 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1281 build_monitor = monitor;
1282 }
1283 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1284 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1285 */
1286 public void registerImportMonitor(GShellProgressMonitor monitor) {
1287 import_monitor = monitor;
1288 }
1289
1290
1291 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1292 {
1293 collection_contents_changed_listeners.remove(listener);
1294 }
1295
1296
1297 public void removeMetadataSet(MetadataSet metadata_set)
1298 {
1299 DebugStream.println("Removing metadata set...");
1300
1301 // Delete the .mds file from the collection's "metadata" folder...
1302 File metadata_set_file = metadata_set.getMetadataSetFile();
1303
1304 // ...but not if it is the "ex.mds" file
1305 if (metadata_set_file.getName().equals("ex.mds")) {
1306 return;
1307 }
1308
1309 // ...and only if it exists
1310 if (metadata_set_file.exists()) {
1311 metadata_set_file.delete();
1312
1313 // Unload it from the MetadataSetManager
1314 MetadataSetManager.unloadMetadataSet(metadata_set);
1315
1316 // If we're using a remote Greenstone server, delete the metadata file on the server
1317 if (Gatherer.isGsdlRemote) {
1318 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), metadata_set_file);
1319 }
1320 }
1321 }
1322
1323
1324 /** Used to check whether all open collections have a 'saved' state.
1325 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1326 * @see org.greenstone.gatherer.collection.Collection
1327 */
1328 public boolean saved() {
1329 boolean result = true;
1330 if(collection != null) {
1331 result = collection.getSaved();
1332 }
1333 return result;
1334 }
1335
1336
1337 /** Saves the currently loaded collection. */
1338 public void saveCollection()
1339 {
1340
1341 if (collection == null) return;
1342
1343 DebugStream.println("Saving collection " + collection.getName() + "...");
1344
1345 // Change cursor to hourglass
1346 Gatherer.g_man.wait(true);
1347
1348 // Create a backup of the collection file, just in case anything goes wrong
1349 File collection_file = new File(getLoadedCollectionColFilePath());
1350 if (collection_file.exists()) {
1351 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1352 if (!collection_file.renameTo(collection_file_backup)) {
1353 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1354 }
1355 collection_file_backup.deleteOnExit();
1356 }
1357
1358 // Write out the collection file
1359 collection.save();
1360
1361 // Write out the collection configuration file
1362 collection.cdm.save();
1363
1364 // Change cursor back to normal
1365 Gatherer.g_man.wait(false);
1366 }
1367
1368
1369 /** 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] */
1370 private void addDefaultMetadataSets()
1371 {
1372 // Add dublin core which is the default metadata set. The user
1373 // can change this later
1374 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1375 if (dc_file.exists()) {
1376 importMetadataSet(new MetadataSet(dc_file));
1377 }
1378 }
1379
1380
1381 private void addRequiredMetadataSets()
1382 {
1383 // Always import the extracted metadata set
1384 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1385 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1386 }
1387
1388
1389 // used as arg in the perl scripts
1390 private String getCollectDirectory() {
1391 String collect_dir = Gatherer.getCollectDirectoryPath();
1392
1393 // Remove erroneous file windows file separator as it causes problems when running import.pl
1394 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1395 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1396 }
1397
1398 return collect_dir;
1399 }
1400
1401
1402 /** Install collection by moving its files from building to index after a successful build.
1403 * @see org.greenstone.gatherer.Gatherer
1404 * @see org.greenstone.gatherer.util.Utility
1405 */
1406 private boolean installCollection()
1407 {
1408 if (Configuration.fedora_info.isActive()) {
1409 DebugStream.println("Fedora build complete. No need to move files.");
1410 return true;
1411 }
1412
1413
1414 DebugStream.println("Build complete. Moving files.");
1415
1416 try {
1417 // Ensure that the local library has released this collection so we can delete the index directory
1418 if (LocalLibraryServer.isRunning() == true) {
1419 LocalLibraryServer.releaseCollection(collection.getName());
1420 }
1421 // deactivate it in tomcat so that windows will release the index files
1422 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1423 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1424 }
1425 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1426 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1427
1428 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1429 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1430
1431 // Get the build mode from the build options
1432 String build_mode = collection.build_options.getValue("mode");
1433
1434 // Special case for build mode "all": replace index dir with building dir
1435 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1436 // Remove the old index directory
1437 if (index_dir.exists()) {
1438 Utility.delete(index_dir);
1439
1440 // Wait for a couple of seconds, just for luck
1441 wait(2000);
1442
1443 // Check the delete worked
1444 if (index_dir.exists()) {
1445 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1446 }
1447 }
1448
1449 if (Gatherer.isGsdlRemote) {
1450 RemoteGreenstoneServer.deleteCollectionFile(collection.getName(), new File(getLoadedCollectionIndexDirectoryPath()));
1451 RemoteGreenstoneServer.moveCollectionFile(collection.getName(), new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
1452 }
1453
1454 // Move the building directory to become the new index directory
1455 if (building_dir.renameTo(index_dir) == false) {
1456 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
1457 }
1458 }
1459
1460 // Otherwise copy everything in the building dir into the index dir
1461 else {
1462 moveContentsInto(building_dir, index_dir);
1463 }
1464 }
1465 catch (Exception exception) {
1466 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
1467 return false;
1468 }
1469 return true;
1470 }
1471
1472
1473 /** Moves all the files in one directory into another, overwriting existing files */
1474 private void moveContentsInto(File source_directory, File target_directory)
1475 {
1476 File[] source_files = source_directory.listFiles();
1477 for (int i = 0; i < source_files.length; i++) {
1478 File source_file = source_files[i];
1479 File target_file = new File(target_directory, source_file.getName());
1480
1481 if (source_file.isDirectory()) {
1482 moveContentsInto(source_file, target_file);
1483 source_file.delete();
1484 }
1485 else {
1486 if (target_file.exists()) {
1487 target_file.delete();
1488 }
1489
1490 source_file.renameTo(target_file);
1491 }
1492 }
1493 }
1494
1495 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
1496 //In this method, the files base_cfg and new_cfg are all xml files.
1497
1498 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
1499 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
1500 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
1501 Element collection_config = new_cfg_doc.getDocumentElement();
1502
1503 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
1504 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
1505 int num_nodes = classifier_children.getLength();
1506
1507 if (num_nodes < 1) {
1508 return;
1509 }
1510
1511 // Read in the classifier command watching for hfile, metadata and sort arguments.
1512 String buttonname = null;
1513 String hfile = null;
1514 String metadata = null;
1515 String sort = null;
1516
1517 for (int i=0; i<num_nodes; i++) {
1518 Element classifier_element = (Element)classifier_children.item(i);
1519 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1520 for (int j=0; j<option_children.getLength(); j++) {
1521 Element option_element = (Element)option_children.item(j);
1522 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1523 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
1524
1525 if (name_str == null || name_str.equals("")) {
1526 continue;
1527 }
1528 if (name_str != null && value_str == null ) {
1529 value_str = "";
1530 }
1531 if (name_str.equals("hfile")) {
1532 hfile = value_str;
1533 }
1534 else if (name_str.equals("metadata") && value_str != null) {
1535 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1536 if (replacement != null && !replacement.equals("")) {
1537 metadata = replacement;
1538 }
1539 }
1540 else if (name_str.equals("sort") && value_str != null) {
1541 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
1542 if (replacement != null && !replacement.equals("")) {
1543 sort = replacement;
1544 }
1545 }
1546 else if(name_str.equals("buttonname") && value_str != null) {
1547 buttonname = value_str;
1548 }
1549 }
1550 }
1551 for (int i=0; i<num_nodes; i++) {
1552 Element classifier_element = (Element)classifier_children.item(i);
1553 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
1554 for (int j=0; j<option_children.getLength(); j++) {
1555 Element option_element = (Element)option_children.item(j);
1556 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
1557
1558 if (name_str.equals("metadata") && metadata != null) {
1559 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1560 }
1561 else if (name_str.equals("hfile") && hfile != null) {
1562 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
1563 }
1564 else if (name_str.equals("sort") && sort != null) {
1565 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
1566 }
1567 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
1568 // No buttonname has been specified. Lets create one using the metadata as its value
1569 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
1570 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
1571 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
1572 classifier_element.appendChild(option);
1573 }
1574 }
1575 }
1576 }
1577
1578 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
1579 {
1580 boolean first_name = true;
1581 boolean first_extra = true;
1582
1583 // 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.
1584 try {
1585 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
1586 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
1587 String command = null;
1588 while((command = in.readLine()) != null) {
1589 if (command.length()==0) {
1590 // output a new line
1591 out.newLine();
1592 continue;
1593 }
1594 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
1595 while(command.trim().endsWith("\\")) {
1596 command = command.substring(0, command.lastIndexOf("\\"));
1597 String next_line = in.readLine();
1598 if(next_line != null) {
1599 command = command + next_line;
1600 }
1601 }
1602 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
1603 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
1604 String command_type_str = tokenizer.nextToken().toLowerCase();
1605
1606 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
1607 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
1608 StringBuffer new_command = new StringBuffer(command_type_str);
1609 String meta_name = tokenizer.nextToken();
1610 new_command.append(' ');
1611 new_command.append(meta_name);
1612 while (tokenizer.hasMoreTokens()) {
1613 new_command.append(' ');
1614 new_command.append(tokenizer.nextToken());
1615 }
1616 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)) {
1617 // dont save
1618 } else {
1619 write(out, new_command.toString());
1620 }
1621 new_command = null;
1622 continue;
1623 } // if collectionmeta
1624
1625 if (command_type_str.equals("classify")) {
1626 StringBuffer text = new StringBuffer(command_type_str);
1627 // Read in the classifier command watching for hfile, metadata and sort arguments.
1628 String buttonname = null;
1629 String hfile = null;
1630 String new_metadata = null;
1631 String old_metadata = null;
1632
1633 while(tokenizer.hasMoreTokens()) {
1634 String token = tokenizer.nextToken();
1635 if (token.equals("-hfile")) {
1636 if(tokenizer.hasMoreTokens()) {
1637 text.append(" ");
1638 text.append(token);
1639 token = tokenizer.nextToken();
1640 hfile = token;
1641 }
1642 }
1643 else if (token.equals("-metadata")) {
1644 if(tokenizer.hasMoreTokens()) {
1645 text.append(" ");
1646 text.append(token);
1647 String temp_metadata = tokenizer.nextToken();
1648 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1649 if (replacement != null && !replacement.equals("")) {
1650 token = replacement;
1651 old_metadata = temp_metadata;
1652 new_metadata = replacement;
1653 }
1654 else {
1655 token = temp_metadata;
1656 }
1657 temp_metadata = null;
1658 replacement = null;
1659 }
1660 }
1661 else if (token.equals("-sort")) {
1662 if(tokenizer.hasMoreTokens()) {
1663 text.append(" ");
1664 text.append(token);
1665 String temp_metadata = tokenizer.nextToken();
1666 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
1667 if (replacement != null && !replacement.equals("")) {
1668 token = replacement;
1669 }
1670 else {
1671 token = temp_metadata;
1672 }
1673 temp_metadata = null;
1674 replacement = null;
1675 }
1676 }
1677 else if(token.equals("-buttonname")) {
1678 buttonname = token;
1679 }
1680 text.append(' ');
1681 text.append(token);
1682 token = null;
1683 }
1684
1685 // 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)!
1686 if(old_metadata != null && new_metadata != null && buttonname == null) {
1687 text.append(' ');
1688 text.append("-buttonname");
1689 text.append(' ');
1690 text.append(old_metadata);
1691 }
1692 command = text.toString();
1693 // Replace the hfile if we found it
1694 if(hfile != null && new_metadata != null) {
1695 command = command.replaceAll(hfile, new_metadata + ".txt");
1696 }
1697
1698 buttonname = null;
1699 hfile = null;
1700 new_metadata = null;
1701 old_metadata = null;
1702 write(out, command);
1703 } else {
1704 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
1705 StringBuffer new_command = new StringBuffer(command_type_str);
1706 while (tokenizer.hasMoreTokens()) {
1707 new_command.append(' ');
1708 new_command.append(tokenizer.nextToken());
1709 }
1710
1711 command = new_command.toString();
1712
1713 // 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.
1714 // we really want to build up the whole command here
1715 boolean format_command = command_type_str.equals("format");
1716 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
1717 if (metadata_mapping != null) {
1718 Iterator keys = metadata_mapping.keySet().iterator();
1719 while (keys.hasNext()) {
1720 String target = (String) keys.next();
1721 String replacement = (String) metadata_mapping.get(target);
1722 if (replacement != null && !replacement.equals("")) {
1723 if (format_command) {
1724 target = "\\[" + target + "\\]";
1725 replacement = "{Or}{[" + replacement + "]," + target + "}";
1726 }
1727 command = command.replaceAll(target, replacement);
1728 }
1729 }
1730 }
1731
1732 write(out, command);
1733 }
1734 tokenizer = null;
1735 }
1736 in.close();
1737 in = null;
1738 out.flush();
1739 out.close();
1740 out = null;
1741 }
1742 catch(Exception error) {
1743 DebugStream.printStackTrace(error);
1744 }
1745 // All done, I hope.
1746 }
1747
1748 private void write(BufferedWriter out, String message)
1749 throws Exception {
1750 out.write(message, 0, message.length());
1751 out.newLine();
1752 }
1753
1754
1755 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
1756 private class FMTreeModelListener
1757 implements TreeModelListener {
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 treeNodesChanged(TreeModelEvent event) {
1762 if(collection != null) {
1763 collection.setSaved(false);
1764 collection.setFilesChanged(true);
1765 }
1766 }
1767 /** 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.
1768 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1769 */
1770 public void treeNodesInserted(TreeModelEvent event) {
1771 if(collection != null) {
1772 collection.setSaved(false);
1773 collection.setFilesChanged(true);
1774 }
1775 }
1776 /** 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.
1777 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1778 */
1779 public void treeNodesRemoved(TreeModelEvent event) {
1780 if(collection != null) {
1781 collection.setSaved(false);
1782 collection.setFilesChanged(true);
1783
1784 }
1785 }
1786 /** 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.
1787 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
1788 */
1789 public void treeStructureChanged(TreeModelEvent event) {
1790 if(collection != null) {
1791 collection.setSaved(false);
1792 }
1793 }
1794 }
1795}
Note: See TracBrowser for help on using the repository browser.