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

Last change on this file since 26402 was 26402, checked in by ak19, 12 years ago

Fixed issue with deleting fedora collections from GLI: it would start a process to call the new g2f-deletecol script and then immediately continue by deleting the collection directory. Unfortunately, the collection directory needs to be around until the script has finished purging the docs from fedora: the GS3 collection dir is how the g2f-deletecol.pl script works out what files (which pids) need purging.

  • Property svn:keywords set to Author Date Id Revision
File size: 92.8 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.cdm.BuildTypeManager;
54import org.greenstone.gatherer.cdm.CollectionConfiguration;
55import org.greenstone.gatherer.greenstone.Classifiers;
56import org.greenstone.gatherer.greenstone.LocalGreenstone;
57import org.greenstone.gatherer.greenstone.LocalLibraryServer;
58import org.greenstone.gatherer.greenstone.Plugins;
59import org.greenstone.gatherer.greenstone3.ServletConfiguration;
60import org.greenstone.gatherer.gui.LockFileDialog;
61import org.greenstone.gatherer.gui.ModalProgressPopup;
62import org.greenstone.gatherer.gui.WarningDialog;
63import org.greenstone.gatherer.metadata.DocXMLFileManager;
64import org.greenstone.gatherer.metadata.FilenameEncoding;
65import org.greenstone.gatherer.metadata.MetadataChangedListener;
66import org.greenstone.gatherer.metadata.MetadataSet;
67import org.greenstone.gatherer.metadata.MetadataSetManager;
68import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
69import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
70import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
71import org.greenstone.gatherer.shell.GShell;
72import org.greenstone.gatherer.shell.GShellEvent;
73import org.greenstone.gatherer.shell.GShellListener;
74import org.greenstone.gatherer.shell.GShellProgressMonitor;
75import org.greenstone.gatherer.util.Codec;
76import org.greenstone.gatherer.util.StaticStrings;
77import org.greenstone.gatherer.util.Utility;
78import org.greenstone.gatherer.util.XMLTools;
79import org.w3c.dom.*;
80
81/** 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 responsible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
82 * @author John Thompson
83 * @version 2.3
84 */
85public class CollectionManager
86 implements GShellListener, MetadataChangedListener
87{
88 /** Are we currently in the process of building? */
89 static private boolean building = false;
90 /** Are we currently in the process of importing? */
91 static private boolean importing = false;
92 /** Are we currently in the process of scheduling? */
93 static private boolean scheduling = false;
94 /** The objects listening for CollectionContentsChanged events. */
95 static private ArrayList collection_contents_changed_listeners = new ArrayList();
96 /** The collection this manager is managing! */
97 static private Collection collection = null;
98 /** The collection tree (used in both Gather and Enrich panes). */
99 static private CollectionTree collection_tree = null;
100 /** The collection tree model. */
101 static private CollectionTreeModel collection_tree_model = null;
102 /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
103 static private FMTreeModelListener fm_tree_model_listener = null;
104 /** The monitor responsible for parsing the build process. */
105 static private GShellProgressMonitor build_monitor = null;
106 /** The monitor responsible for parsing the import process. */
107 static private GShellProgressMonitor import_monitor = null;
108 /** The monitor responsible for parsing the scheduler process. */
109 static private GShellProgressMonitor schedule_monitor = null;
110 ///** The monitor responsible for parsing the fedora collection delete process. */
111 //static private GShellProgressMonitor fedora_coldelete_monitor = null;
112
113 static private String delete_collection_name = null;
114
115 /** The name of the standard lock file. */
116 static final public String LOCK_FILE = "gli.lck";
117
118 /** Used to indicate the source of the message is the file collection methods. */
119 static final public int COLLECT = 3;
120 /** Used to indicate the source of the message is the building methods. */
121 static final public int BUILDING = 5;
122 /** Used to indicate the source of the message is in the scheduling methods...? */
123 static final public int SCHEDULING = 7;
124
125 /** To store the path to the perl scripts. In the case of local Greenstone servers,
126 * this will be the local bin/script folder. */
127 static private String scriptPath = "";
128
129 /** Constructor. */
130 public CollectionManager() {
131 // Initialisation.
132 this.building = false;
133 this.importing = false;
134 this.scheduling = false;
135 this.collection = null;
136
137 MetadataXMLFileManager.addMetadataChangedListener(this);
138
139 // If using a remote Greenstone server, delete the local collect directory because it will be out of date
140 if (Gatherer.isGsdlRemote) {
141 System.err.println("Deleting user's local collect directory...");
142 Utility.delete(new File(Gatherer.getCollectDirectoryPath()));
143 System.err.println("Done.");
144 new File(Gatherer.getCollectDirectoryPath()).mkdirs();
145
146 scriptPath = ""; // remote greenstone: scriptPath will be determined on remote server side
147 }
148 else { // local greenstone case: scripts are inside bin/script
149 scriptPath = LocalGreenstone.getBinScriptDirectoryPath();
150 }
151 }
152
153
154 static public void addCollectionContentsChangedListener(CollectionContentsChangedListener listener)
155 {
156 collection_contents_changed_listeners.add(listener);
157 }
158
159
160 /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
161 * @see org.greenstone.gatherer.Configuration
162 * @see org.greenstone.gatherer.Gatherer
163 * @see org.greenstone.gatherer.collection.Collection
164 * @see org.greenstone.gatherer.gui.BuildOptions
165 * @see org.greenstone.gatherer.shell.GShell
166 * @see org.greenstone.gatherer.shell.GShellListener
167 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
168 * @see org.greenstone.gatherer.util.Utility
169 */
170 public void buildCollection()
171 {
172
173 DebugStream.println("In CollectionManager.buildCollection(), CollectionDesignManager.isCompleteBuild(): " + CollectionDesignManager.isCompleteBuild());
174 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
175 building = true;
176
177 // Generate the buildcol.pl command
178 ArrayList command_parts_list = new ArrayList();
179 if (!Gatherer.isGsdlRemote) {
180 command_parts_list.add(Configuration.perl_path);
181 command_parts_list.add("-S");
182 }
183
184 if (Configuration.fedora_info.isActive()) {
185 command_parts_list.add(scriptPath + "g2f-buildcol.pl");
186
187 command_parts_list.add("-hostname");
188 command_parts_list.add(Configuration.fedora_info.getHostname());
189
190 command_parts_list.add("-port");
191 command_parts_list.add(Configuration.fedora_info.getPort());
192
193 command_parts_list.add("-username");
194 command_parts_list.add(Configuration.fedora_info.getUsername());
195
196 command_parts_list.add("-password");
197 command_parts_list.add(Configuration.fedora_info.getPassword());
198
199 command_parts_list.add("-protocol");
200 command_parts_list.add(Configuration.fedora_info.getProtocol());
201
202 }
203 else {
204
205 if ( !CollectionDesignManager.isCompleteBuild() && CollectionDesignManager.index_manager.isLucene() ) {
206 command_parts_list.add(scriptPath + "incremental-buildcol.pl");
207 CollectionDesignManager.setBuildcolWasFull(false);
208 } else {
209 command_parts_list.add(scriptPath + "full-buildcol.pl");
210 CollectionDesignManager.setBuildcolWasFull(true);
211 }
212 }
213
214 command_parts_list.add("-gli");
215 command_parts_list.add("-language");
216 command_parts_list.add(Configuration.getLanguage());
217 if(!Gatherer.isGsdlRemote) {
218 command_parts_list.add("-collectdir");
219 command_parts_list.add(getCollectDirectory()); // <../collect/>
220 }
221
222 String[] build_options = collection.build_options.getValues();
223 for (int i = 0; i < build_options.length; i++) {
224 command_parts_list.add(build_options[i]);
225 }
226
227 command_parts_list.add(collection.getGroupQualifiedName(false)); // (colgroup/)colname
228
229 // Run the buildcol.pl and
230 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
231 GShell shell = new GShell(command_parts, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
232 shell.addGShellListener(Gatherer.g_man.create_pane);
233 shell.addGShellListener(Gatherer.g_man.format_pane);
234 shell.start();
235
236 }
237
238 /*probably repeating alot of work, but I want to keep this separate... wendy*/
239 public void scheduleBuild()
240 {
241 DebugStream.println("In CollectionManager.scheduleBuild(), CollectionDesignManager.isCompleteBuild(): " + CollectionDesignManager.isCompleteBuild());
242 DebugStream.println("Is event dispatch threa: " + SwingUtilities.isEventDispatchThread());
243
244 ArrayList sched_list = new ArrayList();
245 if (!Gatherer.isGsdlRemote) {
246 sched_list.add(Configuration.perl_path);
247 sched_list.add("-S");
248 }
249 sched_list.add(scriptPath + "schedule.pl");
250 sched_list.add("-colname");
251 sched_list.add(collection.getName());
252 sched_list.add("-gli");
253
254 // First, generate the import.pl command, also converting to a string
255 // Generate the import.pl command
256 ArrayList import_list = new ArrayList();
257 if (!Gatherer.isGsdlRemote) {
258 import_list.add(Configuration.perl_path);
259 import_list.add("-S");
260 }
261
262 String cmdPrefix = CollectionDesignManager.isCompleteBuild() ? "full-" : "incremental-";
263 import_list.add(scriptPath + cmdPrefix + "import.pl");
264 import_list.add("-language");
265 import_list.add(Configuration.getLanguage());
266 if(!Gatherer.isGsdlRemote) {
267 import_list.add("-collectdir");
268 import_list.add(getCollectDirectory());
269 }
270
271 String[] import_options = collection.import_options.getValues();
272 int i = 0;
273 for (i = 0; i < import_options.length; i++) {
274 import_list.add(import_options[i]);
275 }
276
277 import_list.add(collection.getGroupQualifiedName(false)); // (colgroup/)colname
278
279 String[] import_parts = (String[]) import_list.toArray(new String[0]);
280 String command = "";
281 i = 0;
282 for (i = 0; i < import_parts.length-1; i++) {
283 command = command + import_parts[i] + " ";
284 }
285 command = command + import_parts[i];
286
287 sched_list.add("-import");
288 sched_list.add("\"" + command + "\"");
289
290 // Generate the buildcol.pl command, also converting to a string
291 ArrayList build_list = new ArrayList();
292
293 // i'm not doing this in schedule.pl right now - should i be?
294 if (!Gatherer.isGsdlRemote) {
295 build_list.add(Configuration.perl_path);
296 build_list.add("-S");
297 }
298
299 String buildType = (new CollectionMeta( CollectionDesignManager.collect_config.getBuildType() )).getValue(CollectionMeta.TEXT);
300 if ( !CollectionDesignManager.isCompleteBuild() && buildType.equals( BuildTypeManager.BUILD_TYPE_LUCENE ) ) {
301 build_list.add(scriptPath + "incremental-buildcol.pl");
302 } else {
303 build_list.add(scriptPath + "full-buildcol.pl");
304 }
305
306 build_list.add("-language");
307 build_list.add(Configuration.getLanguage());
308 if(!Gatherer.isGsdlRemote) {
309 build_list.add("-collectdir");
310 build_list.add(getCollectDirectory());
311 }
312
313 String[] build_options = collection.build_options.getValues();
314 for (i = 0; i < build_options.length; i++) {
315 build_list.add(build_options[i]);
316 }
317
318 build_list.add(collection.getGroupQualifiedName(false)); // (colgroup/)colname
319
320 //build actual string
321 String[] build_parts = (String[]) build_list.toArray(new String[0]);
322 String command2 = "";
323 for(i = 0; i < build_parts.length-1; i++) {
324 command2 = command2 + build_parts[i] + " ";
325 }
326 command2 = command2 + build_parts[i];
327
328 sched_list.add("-build");
329 sched_list.add("\"" + command2 + "\"");
330
331 //next, the scheduling frequency goes here
332 String[] schedule_options = collection.schedule_options.getValues();
333 for(i = 0; i < schedule_options.length; i++) {
334 sched_list.add(schedule_options[i]);
335 }
336
337 //now, hope it will run. ;)
338 String[] sched_parts = (String[]) sched_list.toArray(new String[0]);
339
340 GShell shell = new GShell(sched_parts, GShell.SCHEDULE, SCHEDULING, this, schedule_monitor, GShell.GSHELL_SCHEDULE);
341 shell.addGShellListener(Gatherer.g_man.create_pane);
342 shell.addGShellListener(Gatherer.g_man.format_pane);
343 shell.start();
344 }
345
346 /** Used to determine whether the currently active collection has been built.
347 * @return A boolean indicating the built status of the collection.
348 */
349 public boolean built() {
350 if(collection != null) {
351 // Determine if the collection has been built by looking for the build.cfg (gs2)
352 // buildConfig.xml (gs3) or export.inf (fedora) file
353 String file_name = "";
354
355 if (Configuration.fedora_info != null && Configuration.fedora_info.isActive()) { // FLI case
356 // Fedora build
357 //file_name = getLoadedCollectionArchivesDirectoryPath() + "import.inf";
358 //file_name = getLoadedCollectionExportDirectoryPath() + "export.inf"; // export.pl no longer generates this
359 file_name = getLoadedCollectionExportDirectoryPath() + "archiveinf-doc.gdb";
360 } else {
361 // GLI is running, check if it's greenstone 3 or greenstone 2
362 if (Gatherer.GS3) { // GS3 GLI
363 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CONFIG_XML;
364 }
365 else { // greenstone 2 GLI
366 file_name = getLoadedCollectionIndexDirectoryPath() + Utility.BUILD_CFG;
367 }
368 }
369 File test_file = new File(file_name);
370 return test_file.exists();
371 }
372 return false;
373 }
374
375 /** Used to determine whether the currently active collection has been imported.
376 * @return A boolean indicating the imported status of the collection.
377 */
378 public boolean imported() {
379 if ( collection != null ) {
380 String file_name = getLoadedCollectionDirectoryPath() + "archives";
381 File test_file = new File(file_name);
382 return test_file.exists();
383 }
384 return false;
385 }
386
387 /** 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 */
388 static private boolean canDelete(File file)
389 {
390 if (!file.isDirectory()) {
391 return file.canWrite();
392 }
393 File [] file_list = file.listFiles();
394 for (int i=0; i<file_list.length; i++) {
395 if (!canDelete(file_list[i])) {
396 return false;
397 }
398 }
399 return true;
400 }
401
402
403 /** Called to close the current collection and remove its lock file.
404 * @see org.greenstone.gatherer.Gatherer
405 * @see org.greenstone.gatherer.collection.Collection
406 * @see org.greenstone.gatherer.util.Utility
407 */
408 public void closeCollection() {
409 if (collection == null) {
410 return;
411 }
412 DebugStream.println("Close collection: " + collection.getName());
413
414 // Remove the lock on this file, then remove the collection.
415 File lock_file = new File(getLoadedCollectionDirectoryPath() + LOCK_FILE);
416 lock_file.delete();
417 if (lock_file.exists()) {
418 System.err.println("Warning: Lockfile was not successfully deleted.");
419 }
420
421 // Remove the lock file on the server
422 if (Gatherer.isGsdlRemote) {
423 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getGroupQualifiedName(false), lock_file);
424 }
425
426 // release the current build_log file - else we're unable to delete the last closed collection
427 // until another collection is opened and its opening a new build_log closes this old one
428 Gatherer.g_man.create_pane.options_pane.closeCurrentLogDocument();
429
430 MetadataSetManager.clearMetadataSets();
431 MetadataXMLFileManager.clearMetadataXMLFiles();
432 DocXMLFileManager.clearDocXMLFiles();
433 ProfileXMLFileManager.clearProfileXMLFile();
434
435 collection.destroy();
436 collection = null;
437 collection_tree_model = null;
438 //Configuration.setCollectionConfiguration(null);
439 Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
440 if (Gatherer.g_man != null) {
441 Gatherer.g_man.updateUI(); // !!! Necessary?
442 }
443 }
444
445//This method is no longer used in gs3 since the modification of CollectionConfiguration.java
446// public void convertToGS3Collection() {
447// // Generate the convert_coll_from_gs2.pl command
448// ArrayList command_parts_list = new ArrayList();
449// if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
450// command_parts_list.add(Configuration.perl_path);
451// command_parts_list.add("-S");
452// }
453// command_parts_list.add(Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl");
454// command_parts_list.add("-collectdir");
455// command_parts_list.add(getCollectDirectory());
456// command_parts_list.add(collection.getGroupQualifiedName(false)); // (colgroup/)colname
457//
458// // Run the convert_coll_from_gs2.pl command
459// String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
460// GShell process = new GShell(command_parts, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
461// process.addGShellListener(this);
462// process.run(); // Don't bother threading this... yet
463//
464// }
465
466 /** When basing a new collection on an existing one, we need to copy
467 * over some extra directories: all except import, archives, building, index
468 * really we just want images, macros, perllib, but there may also be eg style, or other dirs.
469 */
470 private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
471 if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
472 return false;
473 }
474 DebugStream.println("Copying extra dirs from the base collection");
475
476
477 File subdirs[] = base_coll_dir.listFiles();
478 for (int i = 0; subdirs != null && i < subdirs.length; i++) {
479 File subdir = subdirs[i];
480 if (subdir.isDirectory()) {
481 String dir_name = subdir.getName();
482 // ignore those we don't need, (archives, buildng, index) and
483 // those we are handling in another place (import, etc, metadata)
484 if (dir_name.startsWith ("import") || dir_name.startsWith("archives") || dir_name.startsWith("building") || dir_name.startsWith("index") || dir_name.startsWith("etc") || dir_name.startsWith("metadata") || dir_name.startsWith("log") || dir_name.startsWith("tmp")) {
485 continue;
486 }
487 try {
488 // copy the directory
489 File new_coll_subdir = new File(new_coll_dir, dir_name);
490 new_coll_subdir.mkdirs();
491 // Copy with force overwrite, since it's a new collection that's currently
492 // being created and won't have anything in it but at most modelcol stuff
493 Gatherer.f_man.getQueue().copyDirectoryContents(subdir, new_coll_subdir, true);
494 }
495 catch (Exception e) {
496 DebugStream.println("Couldn't copy over the" + subdir+" dir from the base collection: "+e.toString());
497 }
498 }
499 }
500
501 return true;
502 }
503
504 /** 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.
505 * @param description a description of the collection as a String
506 * @param email the email address of the author/maintainer as a String
507 * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
508 * @param title the longer title of the collection as a String
509 * @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
510 * @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
511 */
512 public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
513 {
514 // Display a modal progress popup to indicate that the collection is being loaded
515 ModalProgressPopup create_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Creating_Collection"), Dictionary.get("CollectionManager.Creating_Collection_Please_Wait"));
516 create_collection_progress_popup.display();
517
518 // Create the collection on a separate thread so the progress bar updates correctly
519 (new CreateCollectionTask(description, email, name, title, base_collection_directory, metadata_sets, create_collection_progress_popup)).start();
520 }
521
522
523 private class CreateCollectionTask
524 extends Thread
525 {
526 private String description = null;
527 private String email = null;
528 private String name = null;
529 private String title = null;
530 private File base_collection_directory = null;
531 private ArrayList metadata_sets = null;
532 private ModalProgressPopup create_collection_progress_popup = null;
533
534 public CreateCollectionTask(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets, ModalProgressPopup create_collection_progress_popup)
535 {
536 this.description = description;
537 this.email = email;
538 this.name = name;
539 this.title = title;
540 this.base_collection_directory = base_collection_directory;
541 this.metadata_sets = metadata_sets;
542 this.create_collection_progress_popup = create_collection_progress_popup;
543 }
544
545 public void run()
546 {
547 createCollectionInternal(description, email, name, title, base_collection_directory, metadata_sets);
548 create_collection_progress_popup.close();
549 }
550 }
551
552
553 private void createCollectionInternal(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
554 {
555 try {
556 // first make sure that the collect directory exists
557 File collect_dir = new File(getDefaultCollectDirectory());
558 if (!collect_dir.exists()) {
559 collect_dir.mkdirs();
560 }
561
562 // Create the new collection
563 makeCollection(name, email);
564
565 // Check that the collection has been created successfully
566 String collection_directory_path = getCollectionDirectoryPath(name);
567 if (!new File(collection_directory_path).exists()) {
568 // If there is no collection directory then the creation was unsuccessful, or cancelled
569
570 return;
571 }
572
573 // Check for the existence of the collection configuration file
574 String file_name = ((Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG);
575 File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + file_name);
576
577 if (!collect_cfg_file.exists()) {
578 System.err.println("Error: no " + file_name + " file has been created!");
579 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);
580 return;
581 }
582
583 // ACTIVE_DIR/log/
584 File log_dir = new File(collection_directory_path + "log");
585 log_dir.mkdirs();
586
587 // Make sure an import folder exists
588 File collection_import_directory = new File(collection_directory_path + "import");
589 if (!collection_import_directory.exists()) {
590 collection_import_directory.mkdirs();
591 if (Gatherer.isGsdlRemote) {
592 Gatherer.remoteGreenstoneServer.newCollectionDirectory(name, collection_import_directory);
593 }
594 }
595
596 // Now create the collection object around the directory.
597 collection = new Collection(new File(collection_directory_path, "gli.col"));
598
599 // for remote case, scheduling causes an Exception on creating a new collection that
600 // can't be recovered from. For GS3, it doesn't work since it it trying to access etc/main.cfg
601 if (canDoScheduling()) {
602 scheduling();
603 }
604
605 MetadataSetManager.clearMetadataSets();
606 MetadataXMLFileManager.clearMetadataXMLFiles();
607 DocXMLFileManager.clearDocXMLFiles();
608
609 // Import default metadata sets, if any
610 // for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
611 // importMetadataSet((MetadataSet) metadata_sets.get(i));
612 // }
613
614 ProfileXMLFileManager.loadProfileXMLFile(new File(collection_directory_path + "metadata"));
615
616 // Before creating the CollectionDesignManager check if we are basing it upon some other collection
617 if (base_collection_directory != null) {
618 DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
619
620 // If we're using a remote Greenstone server, download the collection shell to get the files needed
621 if (Gatherer.isGsdlRemote) {
622 String base_collection_name = base_collection_directory.getName();
623 Gatherer.remoteGreenstoneServer.downloadCollection(base_collection_name);
624 }
625
626 collection.setBaseCollection(base_collection_directory.getAbsolutePath());
627 // copy over other needed directories
628 copyExtraBaseCollStuff(new File(collection_directory_path), base_collection_directory);
629
630 // Try to import any existing metadata sets for this collection
631 // Look in base_collection_directory/metadata and import any metadata sets found.
632 File base_metadata_directory = new File(base_collection_directory, "metadata");
633 ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
634 if (base_metadata_sets != null) {
635 for (int i = 0; i < base_metadata_sets.size(); i++) {
636 importMetadataSet((MetadataSet) base_metadata_sets.get(i));
637 }
638 }
639 else {
640 DebugStream.println("This base collection has no metadata directory.");
641 }
642
643 // Now we update our collect.cfg
644 DebugStream.println("Copy and update " + file_name + " from base collection.");
645
646 if (Gatherer.GS3 == true) {
647 updateCollectionConfigXML(new File(base_collection_directory, Utility.CONFIG_GS3_FILE),
648 new File(collection_directory_path, Utility.CONFIG_GS3_FILE));
649 } else {
650 updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE),
651 new File(collection_directory_path, Utility.CONFIG_FILE),
652 description, email, title);
653 }
654 }
655 else {
656 // only load metadata sets here if we have not based the collection on any other.
657 // Load the default metadata sets
658 addDefaultMetadataSets();
659
660 // Make sure we always have the extracted metadata set
661 addRequiredMetadataSets();
662 }
663
664 collection.cdm = new CollectionDesignManager(new File(getLoadedCollectionCfgFilePath()));
665
666 // We always set title and description here rather than calling mkcol.pl with Unicode arguments
667
668 // First though, if we based this collection on another collection and thereyby inherited multilingual
669 // collection names and descriptions, clear those before setting description and name to new values.
670 ArrayList colname_metas = collection.cdm.collectionmeta_manager.getMetadata(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR); // retrieves all languages
671 ArrayList coldesc_metas = collection.cdm.collectionmeta_manager.getMetadata(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
672 for(int i = 0; i < colname_metas.size(); i++) {
673 CollectionMeta colname_meta = (CollectionMeta)colname_metas.get(i);
674 colname_meta.setValue("");
675 }
676 for(int i = 0; i < coldesc_metas.size(); i++) {
677 CollectionMeta coldesc_meta = (CollectionMeta)coldesc_metas.get(i);
678 coldesc_meta.setValue("");
679 }
680
681 // set the collection name and description (in the default language)
682 CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR); // retrieves default language
683 collection_name_collectionmeta.setValue(title);
684 CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
685 collection_extra_collectionmeta.setValue(description);
686
687 // 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.
688 if (base_collection_directory != null) {
689 // Update the creator and maintainer
690 CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
691 creator_collectionmeta.setValue(email);
692 creator_collectionmeta = null;
693 CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
694 maintainer_collectionmeta.setValue(email);
695 maintainer_collectionmeta = null;
696
697 // All collections based on others are automatically public
698 CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
699 public_collectionmeta.setValue(StaticStrings.TRUE_STR);
700 public_collectionmeta = null;
701
702 // Finally reset the icons
703 CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
704 icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
705 icon_collection_collectionmeta = null;
706 CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
707 icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
708 icon_collection_small_collectionmeta = null;
709 }
710
711 saveCollection();
712
713 // Create a lock file
714 createLockFile(new File(collection_directory_path, LOCK_FILE));
715
716 // We're done. Let everyone know.
717 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
718 }
719 catch (Exception error) {
720 DebugStream.printStackTrace(error);
721 }
722 }
723
724 private void scheduling()
725 throws Exception
726 {
727 //try to obtain email address of collection owner if it exists...
728 String stmp = Configuration.getEmail();
729 if(stmp != null) {
730 collection.schedule_options.setValue("toaddr", false, Configuration.getEmail());
731 }
732
733 //The next few items deal with updating the SMTP server, and the to: and from: addresses
734 //from main.cfg and the collection configuration. if no changes are made, or the
735 //values are result to NULL, any existing values are kept.
736
737 //try to obtain email address of Greenstone installation webmaster for - used to indicate "sender".
738 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
739 BufferedReader maincfg = new BufferedReader(new FileReader(mcfg));
740 stmp = "";
741 String fromaddr = "";
742 while((stmp = maincfg.readLine()) != null) {
743 if(stmp.startsWith("maintainer")) {
744 fromaddr = stmp.substring(10); //length of MailServer
745 fromaddr = fromaddr.trim();
746 break;
747 }
748 }
749 maincfg.close();
750 if(!fromaddr.equals("NULL") && !fromaddr.equals("null")) {
751 collection.schedule_options.setValue("fromaddr", false, fromaddr);
752 }
753
754 //try to obtain an smtp server address from main.cfg. If that fails,
755 //try mail.server if an email address exists. If that fails,
756 //maybe a message to set attribute in main.cfg?
757 //i'm pretty sure there exists functionality to do this, but
758 //i'll finish this faster if I just wrote it
759
760
761 maincfg = new BufferedReader(new FileReader(mcfg));
762 String smtptmp = "NULL";
763 while((stmp = maincfg.readLine()) != null) {
764 if(stmp.startsWith("MailServer")) {
765 smtptmp = stmp.substring(10); //length of MailServer
766 smtptmp = smtptmp.trim();
767 break;
768 }
769 }
770 maincfg.close();
771
772 //try if lookup fails
773 if(smtptmp.equals("NULL") || smtptmp.equals("null")) {
774 String email2=fromaddr;
775 if(!email2.equals("NULL") && !email2.equals("null")) {
776 int loc = email2.indexOf('@');
777 email2 = email2.substring(loc+1);
778 smtptmp = "mail."+email2;
779 }
780 }
781 if(!smtptmp.equals("NULL") && !smtptmp.equals("null")) {
782 collection.schedule_options.setValue("smtp", false, smtptmp);
783 }
784
785 }
786
787
788 private void createLockFile(File lock_file)
789 {
790 try {
791 Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
792 String user_name = System.getProperty("user.name");
793 Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
794 person_element.appendChild(default_lockfile.createTextNode(user_name));
795 person_element = null;
796 user_name = null;
797 String machine_name = Utility.getMachineName();
798 Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
799 machine_element.appendChild(default_lockfile.createTextNode(machine_name));
800 machine_element = null;
801 machine_name = null;
802 String date_time = Utility.getDateString();
803 Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
804 date_element.appendChild(default_lockfile.createTextNode(date_time));
805 date_element = null;
806 date_time = null;
807 XMLTools.writeXMLFile(lock_file, default_lockfile);
808 }
809 catch (Exception exception) {
810 DebugStream.printStackTrace(exception);
811 }
812 }
813
814
815 public boolean deleteCollection(String collection_name)
816 {
817 // First we must release the collection from the local library, if it's running
818 if (LocalLibraryServer.isRunning() == true) {
819 LocalLibraryServer.releaseCollection(collection_name);
820 }
821
822 // if we're running FLI, it's a fedora collection, and we need to call a special
823 // delete script to delete the collection and all its documents from the fedora
824 // repository and from fedora-gsearch's index.
825 if (Configuration.fedora_info.isActive()) {
826
827 // Generate the buildcol.pl command
828 ArrayList command_parts_list = new ArrayList();
829 if (!Gatherer.isGsdlRemote) {
830 command_parts_list.add(Configuration.perl_path);
831 command_parts_list.add("-S");
832 }
833
834 command_parts_list.add(scriptPath + "g2f-deletecol.pl");
835
836 command_parts_list.add("-hostname");
837 command_parts_list.add(Configuration.fedora_info.getHostname());
838
839 command_parts_list.add("-port");
840 command_parts_list.add(Configuration.fedora_info.getPort());
841
842 command_parts_list.add("-username");
843 command_parts_list.add(Configuration.fedora_info.getUsername());
844
845 command_parts_list.add("-password");
846 command_parts_list.add(Configuration.fedora_info.getPassword());
847
848 command_parts_list.add("-protocol");
849 command_parts_list.add(Configuration.fedora_info.getProtocol());
850
851 command_parts_list.add("-gli");
852 command_parts_list.add("-language");
853 command_parts_list.add(Configuration.getLanguage());
854 if(!Gatherer.isGsdlRemote) {
855 command_parts_list.add("-collectdir");
856 command_parts_list.add(getCollectDirectory()); // <../collect/>
857 }
858
859 command_parts_list.add(collection_name);
860
861 // Run the g2f-deletecol.pl to remove the fedora collection
862 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
863 GShell shell = new GShell(command_parts, GShell.DELETE, COLLECT, this, null, GShell.GSHELL_FEDORA_COLDELETE); // fedora_coldelete_monitor set to null
864 shell.start();
865
866 delete_collection_name = collection_name;
867 return true; // we assume it succeeded for now, wait until the process returns
868 // and then proceed to delete the collection directory
869 }
870 else { // not a fedora collection
871
872 // Delete the collection on the server if we're using a remote Greenstone
873 if (Gatherer.isGsdlRemote) {
874 Gatherer.remoteGreenstoneServer.deleteCollection(collection_name);
875 }
876
877 // if Greenstone3, need to deactivate the collection on the server
878 if (Gatherer.GS3) {
879 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection_name);
880 }
881 // Now delete the collection directory
882 return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
883 }
884 }
885
886
887 public void fireFileAddedToCollection(File file)
888 {
889 // Send the event off to all the CollectionContentsChangedListeners
890 for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
891 ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
892 }
893 }
894
895
896 /** Retrieve the current collection.
897 * @return The <strong>Collection</strong> itself.
898 */
899 public Collection getCollection() {
900 return collection;
901 }
902
903
904 /** Returns the absolute filename of the specified collection's directory.
905 */
906 static public String getCollectionDirectoryPath(String collection_name)
907 {
908 return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
909 }
910
911
912 /** Returns the absolute filename of the loaded collection's archives directory.
913 */
914 static public String getLoadedCollectionArchivesDirectoryPath()
915 {
916 return getLoadedCollectionDirectoryPath() + "archives" + File.separator;
917 }
918
919 /** Returns the absolute filename of the loaded collection's export directory.
920 */
921 static public String getLoadedCollectionExportDirectoryPath()
922 {
923 return getLoadedCollectionDirectoryPath() + "export" + File.separator;
924 }
925
926
927
928 /** Returns the absolute filename of the loaded collection's building directory.
929 */
930 static public String getLoadedCollectionBuildingDirectoryPath()
931 {
932 return getLoadedCollectionDirectoryPath() + "building" + File.separator;
933 }
934
935
936 /** Returns the absolute filename of the loaded collection's collect.cfg file.
937 */
938 static public String getLoadedCollectionCfgFilePath()
939 {
940 String path = (Gatherer.GS3 == true)? Utility.COLLECTION_CONFIG_XML : Utility.COLLECT_CFG;
941 return getLoadedCollectionEtcDirectoryPath() + path;
942 }
943
944
945 /** Returns the absolute filename of the loaded collection's directory.
946 */
947 static public String getLoadedCollectionDirectoryPath()
948 {
949 return collection.getCollectionDirectory().getPath() + File.separator;
950 }
951
952
953 /** Returns the absolute filename of the loaded collection's etc directory.
954 */
955 static public String getLoadedCollectionEtcDirectoryPath()
956 {
957 return getLoadedCollectionDirectoryPath() + "etc" + File.separator;
958 }
959
960
961 /** Returns the absolute filename of the loaded collection's .col file.
962 */
963 static public String getLoadedCollectionColFilePath()
964 {
965 return getLoadedCollectionDirectoryPath() + "gli.col";
966 }
967
968
969 /** Returns the absolute filename of the loaded collection's images directory.
970 */
971 static public String getLoadedCollectionImagesDirectoryPath()
972 {
973 return getLoadedCollectionDirectoryPath() + "images" + File.separator;
974 }
975
976
977 /** Returns the absolute filename of the loaded collection's import directory.
978 */
979 static public String getLoadedCollectionImportDirectoryPath()
980 {
981 return getLoadedCollectionDirectoryPath() + "import" + File.separator;
982 }
983
984
985 /** Returns the absolute filename of the loaded collection's index directory.
986 */
987 static public String getLoadedCollectionIndexDirectoryPath()
988 {
989 return getLoadedCollectionDirectoryPath() + "index" + File.separator;
990 }
991
992
993 /** Returns the absolute filename of the loaded collection's log directory.
994 */
995 static public String getLoadedCollectionLogDirectoryPath()
996 {
997 return getLoadedCollectionDirectoryPath() + "log" + File.separator;
998 }
999
1000
1001 /** Returns the absolute filename of the loaded collection's macros directory.
1002 */
1003 static public String getLoadedCollectionMacrosDirectoryPath()
1004 {
1005 return getLoadedCollectionDirectoryPath() + "macros" + File.separator;
1006 }
1007
1008
1009 /** Returns the absolute filename of the loaded collection's metadata directory.
1010 */
1011 static public String getLoadedCollectionMetadataDirectoryPath()
1012 {
1013 return getLoadedCollectionDirectoryPath() + "metadata" + File.separator;
1014 }
1015
1016
1017 /** Returns the (group-qualified) name of the loaded collection with
1018 * OS-dependent file separator.
1019 */
1020 static public String getLoadedCollectionName()
1021 {
1022 return CollectionManager.getLoadedCollectionName(false);
1023 }
1024
1025 /** Returns the (group-qualified) name of the loaded collection with
1026 * OS-dependent space separator.
1027 * @url true if url-type forward slashes, false if OS-dependent filesystem slashes.
1028 */
1029 static public String getLoadedCollectionName(boolean url)
1030 {
1031 if (collection != null) {
1032 //return collection.getName();
1033 return collection.getGroupQualifiedName(url);
1034 }
1035
1036 return null;
1037 }
1038
1039 /** @return the subname of any collection (stripped of any collection-group). */
1040 static public String getLoadedCollectionTailName()
1041 {
1042 if (collection != null) {
1043 return collection.getCollectionTailName();
1044 }
1045
1046 return null;
1047 }
1048
1049 /** Returns the "collectionGroupName/collectionName" or just the collectionName
1050 * depending on whether the collection is part of a collection group or not.
1051 * If url = true, then returns the sub-path as a URL (containing / only),
1052 * and if url = false, then the sub-path is returned in filepath form
1053 * (\ or /, depending on the OS).
1054 */
1055 static public String getLoadedGroupQualifiedCollectionName(boolean url)
1056 {
1057 if (collection != null) {
1058 return collection.getGroupQualifiedName(url);
1059 }
1060
1061 return null;
1062 }
1063
1064 public CollectionTree getCollectionTree()
1065 {
1066 if (collection_tree == null) {
1067 collection_tree = new CollectionTree(collection_tree_model, true);
1068 }
1069
1070 return collection_tree;
1071 }
1072
1073
1074 /** Retrieve the tree model associated with the current collection. */
1075 public CollectionTreeModel getCollectionTreeModel()
1076 {
1077 if (collection_tree_model == null && collection != null) {
1078 // Use the import directory to generate a new CollectionTreeModel
1079 collection_tree_model = new CollectionTreeModel(new CollectionTreeNode(new File(getLoadedCollectionImportDirectoryPath())));
1080 // Ensure that the manager is a change listener for the tree.
1081 if (fm_tree_model_listener == null) {
1082 fm_tree_model_listener = new FMTreeModelListener();
1083 }
1084 collection_tree_model.addTreeModelListener(fm_tree_model_listener);
1085 }
1086 return collection_tree_model;
1087 }
1088
1089
1090 /** This method when called, creates a new GShell in order to run the import.pl script.
1091 * @see org.greenstone.gatherer.Configuration
1092 * @see org.greenstone.gatherer.Gatherer
1093 * @see org.greenstone.gatherer.gui.BuildOptions
1094 * @see org.greenstone.gatherer.shell.GShell
1095 * @see org.greenstone.gatherer.shell.GShellListener
1096 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
1097 * @see org.greenstone.gatherer.util.Utility
1098 */
1099 public void importCollection() {
1100 importing = true;
1101
1102 if (!saved()) {
1103 DebugStream.println("CollectionManager.importCollection().forcesave");
1104 import_monitor.saving();
1105 saveCollection();
1106 }
1107
1108 DebugStream.println("CollectionManager.importCollection()");
1109 DebugStream.println("Is event dispatch thread: " + SwingUtilities.isEventDispatchThread());
1110 //check that we can remove the old index before starting import
1111 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1112 if (index_dir.exists()) {
1113 DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
1114 if (!canDelete(index_dir)) {
1115 // tell the user
1116 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1117 // tell the gui manager
1118 // a message for the building log
1119 GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
1120 Gatherer.g_man.create_pane.message(event);
1121 event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
1122 Gatherer.g_man.create_pane.processComplete(event);
1123 importing = false;
1124 return;
1125 }
1126 }
1127
1128 // Generate the import.pl command
1129 ArrayList command_parts_list = new ArrayList();
1130 if (!Gatherer.isGsdlRemote) {
1131 command_parts_list.add(Configuration.perl_path);
1132 command_parts_list.add("-S");
1133 }
1134
1135 if (Configuration.fedora_info.isActive()) {
1136 command_parts_list.add(scriptPath + "g2f-import.pl");
1137
1138 command_parts_list.add("-hostname");
1139 command_parts_list.add(Configuration.fedora_info.getHostname());
1140
1141 command_parts_list.add("-port");
1142 command_parts_list.add(Configuration.fedora_info.getPort());
1143
1144 command_parts_list.add("-username");
1145 command_parts_list.add(Configuration.fedora_info.getUsername());
1146
1147 command_parts_list.add("-password");
1148 command_parts_list.add(Configuration.fedora_info.getPassword());
1149
1150 command_parts_list.add("-protocol");
1151 command_parts_list.add(Configuration.fedora_info.getProtocol());
1152 }
1153 else {
1154 String cmdPrefix = null;
1155 if ( CollectionDesignManager.isCompleteBuild() ) {
1156 cmdPrefix = "full-";
1157 CollectionDesignManager.setImportWasFull( true );
1158 } else {
1159 cmdPrefix = "incremental-";
1160 CollectionDesignManager.setImportWasFull( false );
1161 }
1162 command_parts_list.add(scriptPath + cmdPrefix + "import.pl"); // scriptPath already set according to local or remote case
1163 }
1164
1165 command_parts_list.add("-gli");
1166 command_parts_list.add("-language");
1167 command_parts_list.add(Configuration.getLanguage());
1168 if(!Gatherer.isGsdlRemote) {
1169 command_parts_list.add("-collectdir");
1170 command_parts_list.add(getCollectDirectory());
1171 }
1172
1173 String[] import_options = collection.import_options.getValues();
1174 for (int i = 0; i < import_options.length; i++) {
1175 System.err.println( "Tacking on option: " + import_options[i] );
1176 command_parts_list.add(import_options[i]);
1177 }
1178
1179 command_parts_list.add(collection.getGroupQualifiedName(false)); // (colgroup/)colname
1180
1181 // Run the import.pl command
1182 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1183 GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
1184 //shell.setEventProperty("is_incremental", Boolean.toString(is_incremental));
1185 shell.addGShellListener(Gatherer.g_man.create_pane);
1186 shell.addGShellListener(Gatherer.g_man.format_pane);
1187 shell.start();
1188 DebugStream.println("CollectionManager.importCollection().return");
1189
1190 importing = false;
1191 }
1192
1193
1194 public void importMetadataSet(MetadataSet external_metadata_set)
1195 {
1196 // Copy the .mds file into the collection's "metadata" folder...
1197 File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
1198
1199 // ...but not if it is the redundant "hidden.mds" file
1200 if (external_metadata_set_file.getName().equals("hidden.mds")) {
1201 return;
1202 }
1203
1204 // ...and only if it doesn't already exist
1205 File metadata_set_file = new File(getLoadedCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
1206 if (!metadata_set_file.exists()) {
1207 try {
1208 Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, false);
1209
1210 // If we're using a remote Greenstone server, upload the metadata file
1211 if (Gatherer.isGsdlRemote) {
1212 Gatherer.remoteGreenstoneServer.uploadCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1213 }
1214 }
1215 catch (Exception exception) {
1216 DebugStream.printStackTrace(exception);
1217 }
1218
1219 // Load it into the MetadataSetManager
1220 MetadataSetManager.loadMetadataSet(metadata_set_file);
1221 }
1222 }
1223
1224
1225 /** 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.
1226 * @return true if the gli is currently importing
1227 */
1228 public boolean isImporting() {
1229 return importing;
1230 }
1231
1232
1233 public void loadCollection(String collection_file_path)
1234 {
1235 // Display a modal progress popup to indicate that the collection is being loaded
1236 ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
1237 load_collection_progress_popup.display();
1238
1239 // Load the collection on a separate thread so the progress bar updates correctly
1240 (new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
1241 }
1242
1243
1244 private class LoadCollectionTask
1245 extends Thread
1246 {
1247 private String collection_file_path = null;
1248 private ModalProgressPopup load_collection_progress_popup = null;
1249
1250 public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
1251 {
1252 this.collection_file_path = collection_file_path;
1253 this.load_collection_progress_popup = load_collection_progress_popup;
1254 }
1255
1256 public void run()
1257 {
1258 loadCollectionInternal(collection_file_path);
1259 load_collection_progress_popup.close();
1260 Gatherer.setMenuBarEnabled(true);
1261 }
1262 }
1263
1264
1265 /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
1266 * @param location The path to the collection as a <strong>String</strong>.
1267 * @see org.greenstone.gatherer.Configuration
1268 * @see org.greenstone.gatherer.Gatherer
1269 * @see org.greenstone.gatherer.collection.Collection
1270 * @see org.greenstone.gatherer.util.Utility
1271 */
1272 private void loadCollectionInternal(String location)
1273 {
1274 DebugStream.println("Loading collection " + location + "...");
1275
1276
1277 // Check we have actually been given a .col file.
1278 if (!location.endsWith(".col")) {
1279 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1280 DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
1281 return;
1282 }
1283
1284 // Check that the collection configuration file is available
1285 File collection_file = new File(location);
1286
1287 //String collection_name = collection_directory.getName();
1288 String collection_name = "";
1289 File collection_directory = collection_file.getParentFile();
1290
1291 // To get colname = (colgroup/)coltailname, subtract Gatherer.getCollectDirectoryPath() from collection_directory:
1292 int index = collection_directory.getAbsolutePath().indexOf(Gatherer.getCollectDirectoryPath());
1293 if(index == -1) {
1294 System.err.println("*** ERROR: collection directory " + collection_directory + " is not located in collect folder: " + Gatherer.getCollectDirectoryPath());
1295 } else {
1296 index += Gatherer.getCollectDirectoryPath().length();
1297 collection_name = collection_directory.getAbsolutePath().substring(index);
1298 }
1299
1300 if (Gatherer.isGsdlRemote) {
1301 if (Gatherer.remoteGreenstoneServer.downloadCollection(collection_name).equals("")) {
1302 return;
1303 }
1304 }
1305
1306 // Ensure that the collection directory exists
1307 if (collection_directory == null || !collection_directory.exists()) {
1308 // We can't open this
1309 System.err.println("CollectionManager.loadCollection: No collection directory.");
1310 return;
1311 }
1312
1313 String file_str = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
1314 File collection_config_file = new File(collection_directory, file_str);
1315 if (!collection_config_file.exists()) {
1316 System.err.println("CollectionManager.loadCollection: No config file.");
1317 collection_directory = null;
1318 collection_config_file = null;
1319 return;
1320 }
1321
1322 // Ensure that an import directory exists for this collection
1323 File collection_import_directory = new File(collection_directory, "import");
1324 if (!collection_import_directory.exists()) {
1325 collection_import_directory.mkdir();
1326 }
1327
1328 // Special case of a user trying to open an old greenstone collection.
1329 boolean non_gli_collection = false;
1330 File collection_metadata_directory = new File(collection_directory, "metadata");
1331 if (!collection_metadata_directory.exists()) {
1332 DebugStream.println("Loading non-gatherer collection...");
1333 // Show a warning message in case user wants to quit now
1334 non_gli_collection = true;
1335 WarningDialog legacy_dialog = new WarningDialog("warning.LegacyCollection", Dictionary.get("LegacyCollection.Title"), Dictionary.get("LegacyCollection.Message"), null, true);
1336 if (legacy_dialog.display()==JOptionPane.CANCEL_OPTION) {
1337 legacy_dialog.dispose();
1338 collection_directory = null;
1339 collection_config_file = null;
1340 return;
1341 }
1342 legacy_dialog.dispose();
1343
1344 }
1345
1346 // Now determine if a lock already exists on this collection.
1347 File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
1348 if (lock_file.exists()) {
1349 LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, collection_name, lock_file);
1350 int choice = dialog.getChoice();
1351 dialog.dispose();
1352 dialog = null;
1353
1354 if (choice != LockFileDialog.YES_OPTION) {
1355 // user has cancelled
1356 lock_file = null;
1357 collection_directory = null;
1358 collection_config_file = null;
1359 return;
1360 }
1361
1362 lock_file.delete();
1363 }
1364
1365 // now we are using gli.col - old colls may have used the collection name
1366 if (!collection_file.exists()) {
1367 File old_coll_file = new File(collection_directory, collection_name+".col");
1368 if (old_coll_file.exists()) {
1369 try {
1370 old_coll_file.renameTo(collection_file);
1371 } catch (Exception e) {
1372 DebugStream.println("Couldn't rename "+old_coll_file.getName()+" to gli.col. Will just carry on with default gli.col");
1373 // but just carry on.
1374 }
1375 }
1376 }
1377
1378 try {
1379 // Create a lock file.
1380 createLockFile(lock_file);
1381 // This lock file may not have been created so check
1382 if(!lock_file.canWrite()) {
1383 // The lock file cannot be written to. Most likely cause incorrect file permissions.
1384 System.err.println("Cannot write lock file!");
1385 String args[] = new String[2];
1386 args[0] = location;
1387 args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{lock_file.getAbsolutePath()});
1388 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS")!=-1){
1389 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1390 args[1] += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1391 //}
1392 }
1393 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1394 args = null;
1395 return;
1396 }
1397
1398 // need to fix this up as currently it craps out if the .col file is not there, which is may not always be.
1399 if (canDoScheduling() && collection_file.exists()) {
1400 //THIS LOOKS LIKE THE BEST PLACE TO TRY AND UPDATE .col FILES FOR EXISTING COLLECTIONS...Wendy
1401 // Don't need to update anything if collection_file doesn't exist yet.
1402 //First, see if "Schedule" exists in the XMl File...
1403 BufferedReader bir = new BufferedReader(new FileReader(collection_file));
1404 boolean flag = false;
1405 try {
1406 String stmp = new String();
1407
1408 while((stmp = bir.readLine()) != null) {
1409 stmp = stmp.trim();
1410 if(stmp.equals("<Schedule>") || stmp.equals("<Schedule/>")) {
1411 flag = true;
1412 break;
1413 }
1414 }
1415 bir.close();
1416
1417 } catch (IOException ioe) {
1418 DebugStream.printStackTrace(ioe);
1419 }
1420
1421 //modify if old .col (i.e. no Schedule exists in XML file)
1422 if(!flag) {
1423 File new_collection_file = new File(collection_directory.getAbsolutePath() + "/tmp.col");
1424
1425
1426 BufferedWriter bor = new BufferedWriter(new FileWriter(new_collection_file));
1427 bir = new BufferedReader(new FileReader(collection_file));
1428
1429 try {
1430 String stmp = new String();
1431 while((stmp = bir.readLine()) != null) {
1432 String stmp2 = stmp.trim();
1433 if(stmp2.startsWith("<!ELEMENT Argument")) {
1434 bor.write(" <!ELEMENT Schedule (Arguments*)>\n");
1435 }
1436 else if(stmp2.equals("</BuildConfig>")) {
1437 bor.write(" <Schedule/>\n");
1438 }
1439
1440 bor.write(stmp + "\n");
1441
1442 }
1443 bir.close();
1444 bor.close();
1445 } catch (IOException ioe) {
1446 DebugStream.printStackTrace(ioe);
1447 }
1448
1449 //copy over tmp.col to replace
1450 try {
1451 collection_file.delete();
1452 new_collection_file.renameTo(collection_file);
1453 } catch (Exception e) {
1454 DebugStream.printStackTrace(e);
1455 }
1456 }
1457 }
1458
1459 // Open the collection file
1460 this.collection = new Collection(collection_file);
1461 if (collection.error) {
1462 collection = null;
1463 // Remove lock file
1464 if (lock_file.exists()) {
1465 lock_file.delete();
1466 }
1467 throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
1468 }
1469
1470 if (canDoScheduling()) {
1471 scheduling();
1472 }
1473
1474 // These may have been set in the past, but are no longer used
1475 // by GLI
1476 collection.import_options.removeValue("removeold");
1477 collection.import_options.removeValue("keepold");
1478
1479 MetadataSetManager.clearMetadataSets();
1480 MetadataSetManager.loadMetadataSets(collection_metadata_directory);
1481
1482 // Make sure we always have the extracted metadata set
1483 addRequiredMetadataSets();
1484
1485 ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
1486
1487 // If this is a non-GLI (legacy) collection, load the default metadata sets
1488 if (non_gli_collection) {
1489 addDefaultMetadataSets();
1490
1491 // Recurse the import folder tree, backing up the metadata.xml files before they are edited
1492 LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
1493 }
1494
1495 // Read through the metadata.xml files in the import directory, building up the metadata value trees
1496 MetadataXMLFileManager.clearMetadataXMLFiles();
1497 MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory,collection.toSkimFile());
1498
1499
1500 // get rid of the previous scan through docxml files
1501 DocXMLFileManager.clearDocXMLFiles();
1502
1503 if (Configuration.fedora_info.isActive()) { // FLI case
1504 // Read through the docmets.xml files in the export directory
1505 File collection_export_directory = new File(getLoadedCollectionExportDirectoryPath());
1506 DocXMLFileManager.loadDocXMLFiles(collection_export_directory,"docmets.xml");
1507 }
1508 else {
1509 // Read through the doc.xml files in the archives directory
1510 File collection_archives_directory = new File(getLoadedCollectionArchivesDirectoryPath());
1511 DocXMLFileManager.loadDocXMLFiles(collection_archives_directory,"doc.xml");
1512 }
1513
1514
1515 // Get a list of the collection specific classifiers and plugins
1516 Classifiers.loadClassifiersList(collection_name);
1517 Plugins.loadPluginsList(collection_name);
1518
1519 collection.cdm = new CollectionDesignManager(collection_config_file);
1520 if (non_gli_collection) {
1521 // Change the classifiers to use the namespaced element names
1522 LegacyCollectionImporter.updateClassifiers(collection.cdm);
1523 }
1524
1525 // We're done. Let everyone know.
1526 DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", collection_name));
1527 Gatherer.refresh(Gatherer.COLLECTION_OPENED);
1528 }
1529 catch (Exception error) {
1530 // There is obviously no existing collection present.
1531 DebugStream.printStackTrace(error);
1532 error.printStackTrace();
1533 if(error.getMessage() != null) {
1534 String[] args = new String[2];
1535 args[0] = location;
1536 args[1] = error.getMessage();
1537 //args[1] = "The Librarian Interface does not have permission to write to... Please check file permissions.";
1538 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1539 }
1540 else {
1541 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1542 }
1543 }
1544
1545 lock_file = null;
1546 collection_directory = null;
1547 collection_config_file = null;
1548 }
1549
1550 /** At present, scheduling only works for GS2, only when GS2 is local and only when GLI runs from
1551 * within a GS2 installation. This method can be adjusted as scheduling becomes available for more
1552 * more situations. */
1553 public static boolean canDoScheduling() {
1554 // Would be nice to support more of these, rather than returning false
1555 if(Gatherer.isGsdlRemote) {
1556 return false;
1557 }
1558 if(Gatherer.GS3) {
1559 return false;
1560 }
1561 if (Configuration.fedora_info.isActive()) {
1562 return false;
1563 }
1564
1565 // GS2's etc/main.cfg is necessary for scheduling, but scheduling looks for it locally:
1566 // it assumes GLI is inside a GS2 installation
1567 File mcfg = new File(LocalGreenstone.getDirectoryPath() + File.separator + "etc" + File.separator + "main.cfg");
1568 if(!mcfg.exists()) {
1569 System.out.println("Cannot do scheduling, since there is no file: " + mcfg.getAbsolutePath()
1570 + ".\nScheduling presently depends on GLI running from inside a GS2.");
1571 return false;
1572 }
1573
1574 return true;
1575 }
1576
1577 private void makeCollection(String name, String email)
1578 {
1579 // Generate the mkcol.pl command
1580 ArrayList command_parts_list = new ArrayList();
1581 if (!Gatherer.isGsdlRemote) {
1582 command_parts_list.add(Configuration.perl_path);
1583 command_parts_list.add("-S");
1584 }
1585 command_parts_list.add(scriptPath + "mkcol.pl");
1586 if(Gatherer.GS3) {
1587 command_parts_list.add(Utility.GS3MODE_ARGUMENT); // add '-gs3mode'
1588 }
1589 if(!Gatherer.isGsdlRemote) {
1590 command_parts_list.add("-collectdir");
1591 command_parts_list.add(getDefaultCollectDirectory());
1592 }
1593 command_parts_list.add("-win31compat");
1594 command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
1595
1596 if (email != null && !email.equals("")) {
1597 command_parts_list.add("-creator");
1598 command_parts_list.add(email);
1599 }
1600
1601 command_parts_list.add(name);
1602
1603 // Run the mkcol.pl command
1604 String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
1605 //for(int i = 0; i < command_parts.length; i++) {
1606 ///ystem.err.println("\""+command_parts[i]+"\"");
1607 //}
1608
1609 GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
1610 process.run(); // Don't bother threading this... yet
1611 }
1612
1613
1614 /** 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.
1615 * @param event A <strong>GShellEvent</strong> which contains a the message.
1616 */
1617 public synchronized void message(GShellEvent event) {
1618
1619 }
1620
1621
1622 public void metadataChanged(CollectionTreeNode[] file_nodes)
1623 {
1624 if (collection != null) {
1625 collection.setMetadataChanged(true);
1626
1627 // we're only going to refresh the tree's already visible nodes (and reselect them) IFF
1628 // gs.FilenameEncoding meta was set on any files/folders and the filenames of the
1629 // affected CollectionTreeNodes need to be recalculated
1630 if(FilenameEncoding.isRefreshRequired()) {
1631
1632 // refreshes the relevant part of the tree
1633 TreePath[] paths = collection_tree.getSelectionPaths();
1634 if(paths != null) {
1635 for(int i = 0; i < paths.length; i++) {
1636 collection_tree_model.refresh(paths[i]);
1637 collection_tree.setSelectionPath(paths[i]);
1638 }
1639 }
1640 // refreshed the tree, so turn off the requirement to refresh
1641 FilenameEncoding.setRefreshRequired(false);
1642 }
1643 }
1644 }
1645
1646
1647 public void openCollectionFromLastTime() {
1648 // If there was an open collection last session, reopen it.
1649 // (this method doesn't get called if there was no open collection or only a collect folder
1650 // instead of any previously-opened collection)
1651
1652 // Load the collection now
1653 loadCollection(Gatherer.open_collection_file_path);
1654 }
1655
1656
1657 /** This call is fired whenever a process within a GShell created by this class begins.
1658 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1659 * @see org.greenstone.gatherer.Gatherer
1660 * @see org.greenstone.gatherer.gui.GUIManager
1661 * @see org.greenstone.gatherer.shell.GShell
1662 */
1663 public synchronized void processBegun(GShellEvent event) {
1664 DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
1665 ///ystem.err.println("ProcessBegun " + event.getType());
1666 // If this is one of the types where we wish to lock user control
1667 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
1668 }
1669 /** This call is fired whenever a process within a GShell created by this class ends.
1670 * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
1671 * @see org.greenstone.gatherer.Gatherer
1672 * @see org.greenstone.gatherer.gui.GUIManager
1673 * @see org.greenstone.gatherer.shell.GShell
1674 */
1675 public synchronized void processComplete(GShellEvent event) {
1676 //ystem.err.println("CollectionManager.processComplete(" + event.getType() + ")");
1677 Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
1678 ///ystem.err.println("Received process complete event - " + event);
1679 // If we were running an import, now run a build.
1680 if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
1681 // Finish import.
1682 collection.setImported(true);
1683 collection.setFilesChanged(false);
1684 collection.setMetadataChanged(false);
1685 buildCollection();
1686 }
1687 else if(event.getType() == GShell.SCHEDULE && event.getStatus() == GShell.OK ) {
1688
1689 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.ScheduleBuilt", Dictionary.get("ScheduleBuilt.Title"), Dictionary.get("ScheduleBuilt.Message"), null, false);
1690 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1691 collection_built_warning_dialog.display();
1692 collection_built_warning_dialog.dispose();
1693 collection_built_warning_dialog = null;
1694 }
1695 // If we were running a build, now is when we move files across.
1696 else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
1697
1698 if ( CollectionDesignManager.buildcolWasFull() ) {
1699 if(installCollection()) {
1700 // If we have a local library running then ask it to add our newly create collection
1701 if (LocalLibraryServer.isRunning() == true) {
1702 LocalLibraryServer.addCollection(collection.getName());
1703 }
1704 else if (Gatherer.GS3) {
1705 //xiao comment out this: convertToGS3Collection();
1706 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
1707 }
1708
1709 // Fire a collection changed first to update the preview etc buttons
1710 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1711
1712 // Now display a message dialog saying its all built
1713 WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", Dictionary.get("CollectionBuilt.Title"), Dictionary.get("CollectionBuilt.Message"), null, false);
1714 collection_built_warning_dialog.setMessageOnly(true); // Not a warning
1715 collection_built_warning_dialog.display();
1716 collection_built_warning_dialog.dispose();
1717 collection_built_warning_dialog = null;
1718
1719 //Set nothing as needing rebuilding, as a build has just finished :-)
1720 CollectionDesignManager.resetRebuildTypeRequired();
1721 }
1722 else {
1723 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1724 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1725 DebugStream.println("Status is ok but !installCollection()");
1726 }
1727 }
1728 }
1729
1730 else if(event.getType() == GShell.DELETE) {
1731
1732 // we can only get here if we tried to delete a fedora collection
1733
1734 if(event.getStatus() == GShell.ERROR) { // error purging the collection from fedora
1735
1736 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Fedora_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1737 delete_collection_name = null; // re-zero
1738 }
1739
1740 else if(event.getStatus() == GShell.OK) { // fedora purge was successful
1741
1742 if(delete_collection_name != null) {
1743 if (Gatherer.isGsdlRemote) {
1744 Gatherer.remoteGreenstoneServer.deleteCollection(delete_collection_name);
1745 }
1746
1747 // if Greenstone3, need to deactivate the collection on the server
1748 if (Gatherer.GS3) {
1749 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + delete_collection_name);
1750 }
1751
1752 // Now at last, can delete the collection directory as for a normal collection
1753 boolean success = Utility.delete(new File(getCollectionDirectoryPath(delete_collection_name)));
1754
1755 if (!success) {
1756 JOptionPane.showMessageDialog(Gatherer.g_man,Dictionary.get("DeleteCollectionPrompt.Failed_Delete", new String[]{delete_collection_name}),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
1757 }
1758 delete_collection_name = null; // re-zero
1759 }
1760
1761 }
1762 }
1763
1764 else if (event.getStatus() == GShell.CANCELLED) {
1765 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1766 Gatherer.g_man.repaint();
1767 }
1768 else if (event.getStatus() == GShell.ERROR) {
1769 if (event.getType() == GShell.NEW) {
1770 String name = event.getMessage();
1771 String collectDir = getCollectionDirectoryPath(name);
1772 String errMsg = "";
1773 if (!new File(getCollectionDirectoryPath(name)).exists() || !new File(getCollectionDirectoryPath(name)).canWrite()) {
1774 String reason = Dictionary.get("FileActions.Write_Not_Permitted_Message", new String[]{collectDir});
1775 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", new String[]{reason});
1776 if(Gatherer.client_operating_system.toUpperCase().indexOf("WINDOWS") != -1){
1777 //if(Gatherer.client_operating_system.toUpperCase().indexOf("VISTA")!=-1){
1778 errMsg += Dictionary.get("FileActions.File_Permission_Detail", new String[]{Configuration.gsdl_path, System.getProperty("user.name")});
1779 //}
1780 }
1781 } else {
1782 errMsg = Dictionary.get("CollectionManager.Cannot_Create_Collection");
1783 }
1784 JOptionPane.showMessageDialog(Gatherer.g_man, errMsg, Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
1785 }
1786 else if(event.getType() == GShell.SCHEDULE) {
1787 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Schedule_Failed"), Dictionary.get("CollectionManager.Schedule_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1788 }
1789 else {
1790 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
1791 Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
1792 }
1793
1794 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.
1795 }
1796 }
1797
1798
1799 /** Determine if the manager is ready for actions apon its collection.
1800 * @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.
1801 */
1802 static public synchronized boolean ready() {
1803 if(collection != null) {
1804 return true;
1805 }
1806 else {
1807 return false;
1808 }
1809 }
1810
1811
1812 /** This method associates the collection build monitor with the build monitor created in CreatePane.
1813 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
1814 */
1815 public void registerBuildMonitor(GShellProgressMonitor monitor) {
1816 build_monitor = monitor;
1817 }
1818 /** This method associates the collection import monitor with the import monitor created in CreatePane.
1819 * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
1820 */
1821 public void registerImportMonitor(GShellProgressMonitor monitor) {
1822 import_monitor = monitor;
1823 }
1824
1825 public void registerScheduleMonitor(GShellProgressMonitor monitor) {
1826 schedule_monitor = monitor;
1827 }
1828
1829
1830 static public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
1831 {
1832 collection_contents_changed_listeners.remove(listener);
1833 }
1834
1835
1836 public void removeMetadataSet(MetadataSet metadata_set)
1837 {
1838 DebugStream.println("Removing metadata set...");
1839
1840 // Delete the .mds file from the collection's "metadata" folder...
1841 File metadata_set_file = metadata_set.getMetadataSetFile();
1842
1843 // ...but not if it is the "ex.mds" file
1844 if (metadata_set_file.getName().equals("ex.mds")) {
1845 return;
1846 }
1847
1848 // ...and only if it exists
1849 if (metadata_set_file.exists()) {
1850 metadata_set_file.delete();
1851
1852 // Unload it from the MetadataSetManager
1853 MetadataSetManager.unloadMetadataSet(metadata_set);
1854
1855 // If we're using a remote Greenstone server, delete the metadata file on the server
1856 if (Gatherer.isGsdlRemote) {
1857 Gatherer.remoteGreenstoneServer.deleteCollectionFile(collection.getGroupQualifiedName(false), metadata_set_file);
1858 }
1859 }
1860 }
1861
1862
1863 /** Used to check whether all open collections have a 'saved' state.
1864 * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
1865 * @see org.greenstone.gatherer.collection.Collection
1866 */
1867 public boolean saved() {
1868 boolean result = true;
1869 if(collection != null) {
1870 result = collection.getSaved();
1871 }
1872 return result;
1873 }
1874
1875
1876 /** Saves the currently loaded collection. */
1877 public void saveCollection()
1878 {
1879
1880 if (collection == null) return;
1881
1882 DebugStream.println("Saving collection " + collection.getName() + "...");
1883
1884 // Change cursor to hourglass
1885 Gatherer.g_man.wait(true);
1886
1887 // Create a backup of the collection file, just in case anything goes wrong
1888 File collection_file = new File(getLoadedCollectionColFilePath());
1889 if (collection_file.exists()) {
1890 File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
1891 if (!collection_file.renameTo(collection_file_backup)) {
1892 DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
1893 }
1894 collection_file_backup.deleteOnExit();
1895 }
1896
1897 // Write out the collection file
1898 collection.save();
1899
1900 // Write out the collection configuration file
1901 collection.cdm.save();
1902
1903 // Change cursor back to normal
1904 Gatherer.g_man.wait(false);
1905 }
1906
1907
1908 /** 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] */
1909 // now add in greenstone metadata set too.
1910 private void addDefaultMetadataSets()
1911 {
1912 // Add dublin core which is the default metadata set. The user
1913 // can change this later
1914 File dc_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"dublin.mds");
1915 if (dc_file.exists()) {
1916 importMetadataSet(new MetadataSet(dc_file));
1917 }
1918 File gs_file = new File(Gatherer.getGLIMetadataDirectoryPath()+"greenstone.mds");
1919 if (gs_file.exists()) {
1920 importMetadataSet(new MetadataSet(gs_file));
1921 }
1922 }
1923
1924
1925 private void addRequiredMetadataSets()
1926 {
1927 // Always import the extracted metadata set
1928 File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
1929 importMetadataSet(new MetadataSet(extracted_metadata_set_file));
1930 }
1931
1932 private String getDefaultCollectDirectory() {
1933 String collect_dir = Gatherer.getCollectDirectoryPath();
1934 // Remove erroneous file windows file separator as it causes problems when running import.pl
1935 if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
1936 collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
1937 }
1938 return collect_dir;
1939 }
1940
1941 // used as arg in the perl scripts
1942 private String getCollectDirectory() {
1943 String collect_dir = Gatherer.getCollectDirectoryPath();
1944 return collect_dir.substring(0, collect_dir.length()-1); // remove trailing slash
1945
1946 // the following will stick any colgroup at the end of the collect directory, making it no longer
1947 // possible to get the real collect dir in a general manner if this were located outside greenstone
1948 //String collect_dir = collection.getCollectionDirectory().getParentFile().getPath();
1949 //return collect_dir;
1950 }
1951
1952
1953 /** Install collection by moving its files from building to index after a successful build.
1954 * @see org.greenstone.gatherer.Gatherer
1955 * @see org.greenstone.gatherer.util.Utility
1956 */
1957 private boolean installCollection()
1958 {
1959 if (Configuration.fedora_info.isActive()) {
1960 DebugStream.println("Fedora build complete. No need to move files.");
1961 return true;
1962 }
1963
1964
1965 DebugStream.println("Build complete. Moving files.");
1966
1967 try {
1968 // Ensure that the local library has released this collection so we can delete the index directory
1969 if (LocalLibraryServer.isRunning() == true) {
1970 LocalLibraryServer.releaseCollection(getLoadedCollectionName(true)); // URL style slash //collection.getName());
1971 }
1972 // deactivate it in tomcat so that windows will release the index files
1973 if (Gatherer.GS3 && !Gatherer.isGsdlRemote) {
1974 Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
1975 }
1976 File index_dir = new File(getLoadedCollectionIndexDirectoryPath());
1977 DebugStream.println("Index = " + index_dir.getAbsolutePath());
1978
1979 File building_dir = new File(getLoadedCollectionBuildingDirectoryPath());
1980 DebugStream.println("Building = " + building_dir.getAbsolutePath());
1981
1982 // Get the build mode from the build options
1983 String build_mode = collection.build_options.getValue("mode");
1984
1985 // Special case for build mode "all": replace index dir with building dir
1986 if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
1987 // Remove the old index directory
1988 if (index_dir.exists()) {
1989 Utility.delete(index_dir);
1990
1991 // Wait for a couple of seconds, just for luck
1992 wait(2000);
1993
1994 // Check the delete worked
1995 if (index_dir.exists()) {
1996 throw new Exception(Dictionary.get("CollectionManager.Index_Not_Deleted"));
1997 }
1998 }
1999
2000 if (Gatherer.isGsdlRemote) {
2001 Gatherer.remoteGreenstoneServer.deleteCollectionFile(
2002 collection.getGroupQualifiedName(false), new File(getLoadedCollectionIndexDirectoryPath()));
2003 Gatherer.remoteGreenstoneServer.moveCollectionFile(collection.getGroupQualifiedName(false),
2004 new File(getLoadedCollectionBuildingDirectoryPath()), new File(getLoadedCollectionIndexDirectoryPath()));
2005 }
2006
2007 // Move the building directory to become the new index directory
2008 if (building_dir.renameTo(index_dir) == false) {
2009 throw new Exception(Dictionary.get("CollectionManager.Build_Not_Moved"));
2010 }
2011 }
2012
2013 // Otherwise copy everything in the building dir into the index dir
2014 else {
2015 moveContentsInto(building_dir, index_dir);
2016 }
2017 }
2018 catch (Exception exception) {
2019 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Install_Exception", exception.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);
2020 return false;
2021 }
2022 return true;
2023 }
2024
2025
2026 /** Moves all the files in one directory into another, overwriting existing files */
2027 private void moveContentsInto(File source_directory, File target_directory)
2028 {
2029 File[] source_files = source_directory.listFiles();
2030 for (int i = 0; i < source_files.length; i++) {
2031 File source_file = source_files[i];
2032 File target_file = new File(target_directory, source_file.getName());
2033
2034 if (source_file.isDirectory()) {
2035 moveContentsInto(source_file, target_file);
2036 source_file.delete();
2037 }
2038 else {
2039 if (target_file.exists()) {
2040 target_file.delete();
2041 }
2042
2043 source_file.renameTo(target_file);
2044 }
2045 }
2046 }
2047
2048 private void updateCollectionConfigXML(File base_cfg, File new_cfg) {
2049 //In this method, the files base_cfg and new_cfg are all xml files.
2050
2051 Document base_cfg_doc = XMLTools.parseXMLFile(base_cfg);
2052 XMLTools.writeXMLFile(new_cfg, base_cfg_doc);
2053 Document new_cfg_doc = XMLTools.parseXMLFile(new_cfg);
2054 Element collection_config = new_cfg_doc.getDocumentElement();
2055
2056 Node browseNode = XMLTools.getChildByTagNameIndexed(collection_config, StaticStrings.BROWSE_STR, 0);
2057 NodeList classifier_children = ((Element)browseNode).getElementsByTagName(StaticStrings.CLASSIFIER_STR);
2058 int num_nodes = classifier_children.getLength();
2059
2060 if (num_nodes < 1) {
2061 return;
2062 }
2063
2064 // Read in the classifier command watching for hfile, metadata and sort arguments.
2065 String buttonname = null;
2066 String hfile = null;
2067 String metadata = null;
2068 String sort = null;
2069
2070 for (int i=0; i<num_nodes; i++) {
2071 Element classifier_element = (Element)classifier_children.item(i);
2072 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2073 for (int j=0; j<option_children.getLength(); j++) {
2074 Element option_element = (Element)option_children.item(j);
2075 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2076 String value_str = option_element.getAttribute(StaticStrings.VALUE_ATTRIBUTE);
2077
2078 if (name_str == null || name_str.equals("")) {
2079 continue;
2080 }
2081 if (name_str != null && value_str == null ) {
2082 value_str = "";
2083 }
2084 if (name_str.equals("hfile")) {
2085 hfile = value_str;
2086 }
2087 else if (name_str.equals("metadata") && value_str != null) {
2088 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2089 if (replacement != null && !replacement.equals("")) {
2090 metadata = replacement;
2091 }
2092 }
2093 else if (name_str.equals("sort") && value_str != null) {
2094 String replacement = ProfileXMLFileManager.getMetadataElementFor(value_str);
2095 if (replacement != null && !replacement.equals("")) {
2096 sort = replacement;
2097 }
2098 }
2099 else if(name_str.equals("buttonname") && value_str != null) {
2100 buttonname = value_str;
2101 }
2102 }
2103 }
2104 for (int i=0; i<num_nodes; i++) {
2105 Element classifier_element = (Element)classifier_children.item(i);
2106 NodeList option_children = classifier_element.getElementsByTagName(StaticStrings.OPTION_STR);
2107 for (int j=0; j<option_children.getLength(); j++) {
2108 Element option_element = (Element)option_children.item(j);
2109 String name_str = option_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
2110
2111 if (name_str.equals("metadata") && metadata != null) {
2112 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2113 }
2114 else if (name_str.equals("hfile") && hfile != null) {
2115 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata + ".txt");
2116 }
2117 else if (name_str.equals("sort") && sort != null) {
2118 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, sort);
2119 }
2120 else if(name_str.equals("buttonname") && (buttonname == "" || buttonname == null)) {
2121 // No buttonname has been specified. Lets create one using the metadata as its value
2122 Element option = new_cfg_doc.createElement(StaticStrings.OPTION_STR);
2123 option.setAttribute(StaticStrings.NAME_ATTRIBUTE, "buttonname");
2124 option_element.setAttribute(StaticStrings.VALUE_ATTRIBUTE, metadata);
2125 classifier_element.appendChild(option);
2126 }
2127 }
2128 }
2129 }
2130
2131 private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
2132 {
2133 boolean first_name = true;
2134 boolean first_extra = true;
2135
2136 // 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.
2137 try {
2138 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
2139 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
2140 String command = null;
2141 while((command = in.readLine()) != null) {
2142 if (command.length()==0) {
2143 // output a new line
2144 out.newLine();
2145 continue;
2146 }
2147 // We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
2148 while(command.trim().endsWith("\\")) {
2149 command = command.substring(0, command.lastIndexOf("\\"));
2150 String next_line = in.readLine();
2151 if(next_line != null) {
2152 command = command + next_line;
2153 }
2154 }
2155 // commands can extend over more than one line so use the CommandTokenizer which takes care of that
2156 CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
2157 String command_type_str = tokenizer.nextToken().toLowerCase();
2158
2159 if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
2160 // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
2161 StringBuffer new_command = new StringBuffer(command_type_str);
2162 String meta_name = tokenizer.nextToken();
2163 new_command.append(' ');
2164 new_command.append(meta_name);
2165 while (tokenizer.hasMoreTokens()) {
2166 new_command.append(' ');
2167 new_command.append(tokenizer.nextToken());
2168 }
2169 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)) {
2170 // dont save
2171 } else {
2172 write(out, new_command.toString());
2173 }
2174 new_command = null;
2175 continue;
2176 } // if collectionmeta
2177
2178 if (command_type_str.equals("classify")) {
2179 StringBuffer text = new StringBuffer(command_type_str);
2180 // Read in the classifier command watching for hfile, metadata and sort arguments.
2181 String buttonname = null;
2182 String hfile = null;
2183 String new_metadata = null;
2184 String old_metadata = null;
2185
2186 while(tokenizer.hasMoreTokens()) {
2187 String token = tokenizer.nextToken();
2188 if (token.equals("-hfile")) {
2189 if(tokenizer.hasMoreTokens()) {
2190 text.append(" ");
2191 text.append(token);
2192 token = tokenizer.nextToken();
2193 hfile = token;
2194 }
2195 }
2196 else if (token.equals("-metadata")) {
2197 if(tokenizer.hasMoreTokens()) {
2198 text.append(" ");
2199 text.append(token);
2200 String temp_metadata = tokenizer.nextToken();
2201 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2202 if (replacement != null && !replacement.equals("")) {
2203 token = replacement;
2204 old_metadata = temp_metadata;
2205 new_metadata = replacement;
2206 }
2207 else {
2208 token = temp_metadata;
2209 }
2210 temp_metadata = null;
2211 replacement = null;
2212 }
2213 }
2214 else if (token.equals("-sort")) {
2215 if(tokenizer.hasMoreTokens()) {
2216 text.append(" ");
2217 text.append(token);
2218 String temp_metadata = tokenizer.nextToken();
2219 String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
2220 if (replacement != null && !replacement.equals("")) {
2221 token = replacement;
2222 }
2223 else {
2224 token = temp_metadata;
2225 }
2226 temp_metadata = null;
2227 replacement = null;
2228 }
2229 }
2230 else if(token.equals("-buttonname")) {
2231 buttonname = token;
2232 }
2233 text.append(' ');
2234 text.append(token);
2235 token = null;
2236 }
2237
2238 // 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)!
2239 if(old_metadata != null && new_metadata != null && buttonname == null) {
2240 text.append(' ');
2241 text.append("-buttonname");
2242 text.append(' ');
2243 text.append(old_metadata);
2244 }
2245 command = text.toString();
2246 // Replace the hfile if we found it
2247 if(hfile != null && new_metadata != null) {
2248 command = command.replaceAll(hfile, new_metadata + ".txt");
2249 }
2250
2251 buttonname = null;
2252 hfile = null;
2253 new_metadata = null;
2254 old_metadata = null;
2255 write(out, command);
2256 } else {
2257 // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
2258 StringBuffer new_command = new StringBuffer(command_type_str);
2259 while (tokenizer.hasMoreTokens()) {
2260 new_command.append(' ');
2261 new_command.append(tokenizer.nextToken());
2262 }
2263
2264 command = new_command.toString();
2265
2266 // 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.
2267 // we really want to build up the whole command here
2268 boolean format_command = command_type_str.equals("format");
2269 HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
2270 if (metadata_mapping != null) {
2271 Iterator keys = metadata_mapping.keySet().iterator();
2272 while (keys.hasNext()) {
2273 String target = (String) keys.next();
2274 String replacement = (String) metadata_mapping.get(target);
2275 if (replacement != null && !replacement.equals("")) {
2276 if (format_command) {
2277 target = "\\[" + target + "\\]";
2278 replacement = "{Or}{[" + replacement + "]," + target + "}";
2279 }
2280 command = command.replaceAll(target, replacement);
2281 }
2282 }
2283 }
2284
2285 write(out, command);
2286 }
2287 tokenizer = null;
2288 }
2289 in.close();
2290 in = null;
2291 out.flush();
2292 out.close();
2293 out = null;
2294 }
2295 catch(Exception error) {
2296 DebugStream.printStackTrace(error);
2297 }
2298 // All done, I hope.
2299 }
2300
2301 private void write(BufferedWriter out, String message)
2302 throws Exception {
2303 out.write(message, 0, message.length());
2304 out.newLine();
2305 }
2306
2307
2308 /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
2309 private class FMTreeModelListener
2310 implements TreeModelListener {
2311 /** 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.
2312 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2313 */
2314 public void treeNodesChanged(TreeModelEvent event) {
2315 if(collection != null) {
2316 collection.setSaved(false);
2317 collection.setFilesChanged(true);
2318 }
2319 }
2320 /** 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.
2321 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2322 */
2323 public void treeNodesInserted(TreeModelEvent event) {
2324 if(collection != null) {
2325 collection.setSaved(false);
2326 collection.setFilesChanged(true);
2327 }
2328 }
2329 /** 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.
2330 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2331 */
2332 public void treeNodesRemoved(TreeModelEvent event) {
2333 if(collection != null) {
2334 collection.setSaved(false);
2335 collection.setFilesChanged(true);
2336
2337 }
2338 }
2339 /** 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.
2340 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
2341 */
2342 public void treeStructureChanged(TreeModelEvent event) {
2343 if(collection != null) {
2344 collection.setSaved(false);
2345 }
2346 }
2347 }
2348}
Note: See TracBrowser for help on using the repository browser.