source: trunk/gli/src/org/greenstone/gatherer/gui/GUIManager.java@ 7484

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

Many more improvements to the workspace and collection trees and their refreshing.

  • Property svn:keywords set to Author Date Id Revision
File size: 39.7 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui;
38
39import java.awt.*;
40import java.awt.datatransfer.*;
41import java.awt.event.*;
42import java.io.*;
43import java.lang.*;
44import java.net.*;
45import java.util.*;
46import javax.swing.*;
47import javax.swing.event.*;
48import javax.swing.plaf.*;
49import javax.swing.text.*;
50import org.greenstone.gatherer.Configuration;
51import org.greenstone.gatherer.Dictionary;
52import org.greenstone.gatherer.Gatherer;
53import org.greenstone.gatherer.collection.Collection;
54import org.greenstone.gatherer.collection.DeleteCollectionPrompt;
55import org.greenstone.gatherer.collection.ExportCollectionPrompt;
56import org.greenstone.gatherer.collection.SaveCollectionBox;
57import org.greenstone.gatherer.file.FileNode;
58import org.greenstone.gatherer.file.FileOpenActionListener;
59import org.greenstone.gatherer.gui.AboutDialog;
60//import org.greenstone.gatherer.gui.BrowsingPane;
61import org.greenstone.gatherer.gui.GatherPane;
62import org.greenstone.gatherer.gui.CreatePane;
63import org.greenstone.gatherer.gui.Filter;
64import org.greenstone.gatherer.gui.DesignPane;
65import org.greenstone.gatherer.gui.MenuBar;
66import org.greenstone.gatherer.gui.EnrichPane;
67import org.greenstone.gatherer.gui.MirrorPane;
68import org.greenstone.gatherer.gui.OpenCollectionDialog;
69import org.greenstone.gatherer.gui.Preferences;
70//import org.greenstone.gatherer.gui.PreviewPane;
71import org.greenstone.gatherer.gui.SimpleOpenCollectionDialog;
72import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
73import org.greenstone.gatherer.gui.tree.DragTree;
74import org.greenstone.gatherer.gui.tree.WorkspaceTree;
75import org.greenstone.gatherer.help.HelpFrame;
76import org.greenstone.gatherer.mem.MetadataEditorManager;
77import org.greenstone.gatherer.msm.ElementWrapper;
78import org.greenstone.gatherer.msm.Metadata;
79import org.greenstone.gatherer.shell.GShell;
80import org.greenstone.gatherer.util.StaticStrings;
81import org.greenstone.gatherer.util.TreeSynchronizer;
82import org.greenstone.gatherer.util.Utility;
83
84/** The GUIManager is in charge of creating the Gatherer window frame then filling it with the goodness of the view panes. GUIManager not only creates these panes, but allows some messaging between them. Furthermore GUIManager includes functionality from menu driven choices, simply as it was easier to put it here once and have it accessible from all pane children. */
85public class GUIManager
86 extends JFrame
87 implements ActionListener, ChangeListener {
88 /** The browsing pane behaves much like an internet browser, or at least will some day. */
89 //public BrowsingPane browser_pane = null;
90 /** The mirror pane contains controls for mirroring internet sites. */
91 public MirrorPane mirror_pane = null;
92 /** The gather pane is more like a file manager where you drag files from one tree to another. */
93 private GatherPane gather_pane = null;
94 /** The enrich pane is used to assign, edit and remove metadata from files within the collection. */
95 public EnrichPane enrich_pane = null;
96 /** The design pane allows you to edit the design of the library in terms of the collection configuration file. */
97 public DesignPane design_pane = null;
98 /** The create pane contains scripting options for importing and building collections into libraries. */
99 public CreatePane create_pane = null;
100 /** The preview pane contains a preview of your build collection. */
101 //public PreviewPane preview_pane = null;
102
103 public FileOpenActionListener foa_listener = new FileOpenActionListener();
104
105 /** A reference to the currently instantiated help window, if any. */
106 public HelpFrame help = null;
107 /** The menu bar. */
108 public MenuBar menu_bar = null;
109 public MetaAuditFrame meta_audit;
110 /** Are certain panes currently locked? */
111 private boolean locked = false;
112 /** The size of the Gatherer window. */
113 private Dimension size = null;
114 /** The filters used to dynamically filter the trees at user request. */
115 private HashMap filters = new HashMap();
116 /** The panel within the window that other components are placed on. */
117 private JPanel content_pane = null;
118 /** The dummy export pane. */
119 private JPanel export_pane = new JPanel();
120 /** The last view pane selected. */
121 private JPanel previous_pane;
122 /** The main tab pane containing the different views, available here to trap view change events. */
123 private JTabbedPane tab_pane = null;
124 /** A threaded tab changer to try and avoid NPE on exit. */
125 private TabUpdater tab_updater = null;
126 /** The thread group this manager, and hence its child graphical rendering threads, belong to. In a vain attempts to make the Dictionary work across threads.
127 * @see org.greenstone.gatherer.Dictionary
128 */
129 private ThreadGroup thread_group = null;
130 /** Ensures that expansion events between like collection trees are synchronized. */
131 private TreeSynchronizer collection_tree_sync = null;
132 /** Ensures that expansion events between like workspace trees are synchronized. */
133 private TreeSynchronizer workspace_tree_sync = null;
134 /**Constructor. Enable window events and arranges all other components.
135 * @param size The intial <strong>Dimension</strong> of the screen.
136 */
137 public GUIManager(Dimension size) {
138 super();
139 // Initialization
140 this.help = new HelpFrame();
141 this.size = size;
142 this.collection_tree_sync = new TreeSynchronizer();
143 this.meta_audit = new MetaAuditFrame(collection_tree_sync, null);
144 this.workspace_tree_sync = new TreeSynchronizer();
145
146 this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
147
148 // Add a focus listener to ourselves. Thus if we gain focus when a Modal Dialog should instead have it, we can try to bring the modal dialog to the fore.
149 this.addFocusListener(new GLIGUIFocusListener());
150
151 // Make the Tool tip hang around for a rediculous amount of time.
152 ToolTipManager.sharedInstance().setDismissDelay(10000);
153 // Get a reference to the main thread group. Create a new thread, which defaults into the same thread group, then get its thread group. Easy.
154 Thread bob = new Thread();
155 thread_group = bob.getThreadGroup();
156 // Set up some other UI stuff. (fonts handled in Gatherer.main())
157 UIManager.put("FileChooser.lookInLabelText", Dictionary.get("SaveCollectionBox.Look_In"));
158 UIManager.put("FileChooser.filesOfTypeLabelText", Dictionary.get("SaveCollectionBox.Files_Of_Type"));
159 UIManager.put("FileChooser.fileNameLabelText", Dictionary.get("SaveCollectionBox.File_Name"));
160 }
161
162 private class GLIGUIFocusListener
163 extends FocusAdapter {
164 public void focusGained(FocusEvent e) {
165 if(Gatherer.current_modal != null) {
166 Gatherer.current_modal.makeVisible();
167 Gatherer.current_modal.toFront();
168 }
169 }
170 }
171
172 /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured. In this case we are listening to actions from the menu-bar, and should react appropriately.
173 * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
174 */
175 public void actionPerformed(ActionEvent event) {
176 boolean cont = true;
177 Object esrc = event.getSource();
178 // *************
179 // File Options.
180 // *************
181 if(esrc == menu_bar.file_associations) {
182 Gatherer.assoc_man.edit();
183 }
184 else if(esrc == menu_bar.file_close) {
185 // if(!Gatherer.c_man.saved()) {
186 cont = showSaveCollectionBox(true, false);
187 // }
188 if(cont) {
189 tab_pane.setSelectedComponent(gather_pane);
190 }
191 }
192 else if(esrc == menu_bar.file_delete) {
193 DeleteCollectionPrompt dcp = new DeleteCollectionPrompt();
194 if(dcp.display()) {
195 Gatherer.c_man.closeCollection();
196 }
197 dcp.destroy();
198 dcp = null;
199 System.gc();
200 }
201 else if(esrc == menu_bar.file_export) {
202 ExportCollectionPrompt ecp = new ExportCollectionPrompt();
203 ecp.display();
204 ecp.destroy();
205 ecp = null;
206 }
207 else if(esrc == menu_bar.file_exit) {
208 //menu_bar.exit();
209 exit();
210 }
211 else if(esrc == menu_bar.file_new) {
212 showNewCollectionPrompt();
213 }
214 else if(esrc == menu_bar.file_open) {
215 if (showLoadCollectionBox()) {
216 tab_pane.setSelectedComponent(gather_pane);
217 }
218 }
219 else if(esrc == menu_bar.file_options) {
220 // Just incase the user has edited the GeneralSettings of a collection without losing focus afterwards. Well I'm forever losing foc... ooh shiney.
221 design_pane.loseFocus();
222 // And spawn a new preferences.
223 new Preferences();
224 }
225 else if(esrc == menu_bar.file_save) {
226 Gatherer.c_man.saveCollection(false, false);
227 }
228// else if(esrc == menu_bar.file_save_as) {
229// String name = JOptionPane.showInputDialog(this, "Enter new collection filename.");
230// if(name != null) {
231// Gatherer.c_man.saveCollectionAs(name);
232// }
233// }
234 // *************
235 // Edit Options.
236 // *************
237 else if(esrc == menu_bar.edit_copy) {
238 try {
239 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
240 // Get the component with selected text as a JTextComponent
241 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
242 text.copy();
243 }
244 catch (Exception cce) {
245 // If the component is not a text component ignore the copy command
246 Gatherer.println(cce.toString());
247 }
248 }
249 else if(esrc == menu_bar.edit_cut) {
250 try {
251 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
252 // Get the component with selected text as a JTextComponent
253 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
254 // Cut the text to the clipboard
255 text.cut();
256 }
257 catch (ClassCastException cce) {
258 // If the component is not a text component ignore the cut command
259 Gatherer.println(cce.toString());
260 }
261 }
262 else if(esrc == menu_bar.edit_paste) {
263 try {
264 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
265 // Get the component with selected text as a JTextComponent
266 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
267 // Cut the text to the clipboard
268 text.paste();
269 }
270 catch (ClassCastException cce) {
271 // If the component is not a text component ignore the paste command
272 Gatherer.println(cce.toString());
273 }
274 }
275// else if(esrc == menu_bar.edit_search) {
276// if(sar != null) {
277// sar.dispose();
278// }
279// sar = new SearchAndReplace(false);
280// }
281// else if(esrc == menu_bar.edit_replace) {
282// if(sar != null) {
283// sar.dispose();
284// }
285// sar = new SearchAndReplace(true);
286// }
287
288 // *************
289 // Tools Options.
290 // *************
291// else if(esrc == menu_bar.tools_size) {
292// FileNode records[] = enrich_pane.getSelectedNode();
293// if(records != null && records.length > 0) {
294// ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getMetadata(records[0].getFile());
295// if(metadatum.size() >= 4) {
296// Metadata metadata = (Metadata) metadatum.get(0);
297// ElementWrapper ew = metadata.getElement();
298
299// int SIZE = 5000;
300// Object[] array = new Object[SIZE];
301// Runtime.getRuntime().gc();
302// long start = Runtime.getRuntime().freeMemory();
303// for (int i = 0; i < SIZE; i++) {
304// array[i] = ew.copy();
305// }
306// Runtime.getRuntime().gc();
307// long end = Runtime.getRuntime().freeMemory();
308// long difference = (( start - end ) / SIZE);
309// ///ystem.out.println(difference + " bytes used." );
310// }
311// }
312// }
313
314 // *************
315 // Help Options.
316 // *************
317 else if(esrc == menu_bar.help_about) {
318 new AboutDialog(this);
319 }
320// else if(esrc == menu_bar.help_browse) {
321// help.setView("huntingforfiles");
322// }
323 else if(esrc == menu_bar.help_build) {
324 help.setView("producingthecollection");
325 }
326 else if(esrc == menu_bar.help_collect) {
327 help.setView("collectingfiles");
328 }
329 else if(esrc == menu_bar.help_design) {
330 help.setView("designingacollection");
331 }
332 else if(esrc == menu_bar.help_general) {
333 help.setView("introduction");
334 }
335 else if(esrc == menu_bar.help_metaedit) {
336 help.setView("enrichingacollection");
337 }
338 else if(esrc == menu_bar.help_mirror) {
339 help.setView("downloadingfiles");
340 }
341 else if(esrc == menu_bar.help_preview) {
342 help.setView("previewingthecollection");
343 }
344 // *****************
345 // Metadata Options.
346 // *****************
347 else if(esrc == menu_bar.metadata_import) {
348 Gatherer.c_man.getCollection().msm.importMDS();
349 }
350 else if(esrc == menu_bar.metadata_edit) {
351 showEditMetadataBox();
352 }
353 else if(esrc == menu_bar.metadata_export) {
354 Gatherer.c_man.getCollection().msm.exportMDS();
355 }
356 else if(esrc == menu_bar.metadata_view) {
357 showMetaAuditBox();
358 }
359 }
360 /** Any actions that should happen after the display of the Gatherer window can be called here. Currently only updates the browser pane if it is active to work around bug in Mozilla renderer implementation.
361 */
362 public void afterDisplay() {
363// if(Gatherer.config.get("workflow.browse", true)) {
364// browser_pane.afterDisplay();
365// }
366 if (mirror_pane != null) {
367 mirror_pane.afterDisplay();
368 }
369 enrich_pane.afterDisplay();
370 }
371 public void closeCurrentCollection() {
372
373 boolean cont = showSaveCollectionBox(true, false);
374
375 if(cont) {
376 tab_pane.setSelectedComponent(gather_pane);
377 }
378
379 }
380 /** Once a collection has been made available to Gatherer, either by its creation or by it being reloaded, we need to inform all the visual components to update necessary data components (such as tree models), enable certain controls that depend on a collection being accessible, and refresh themselves.
381 * @param ready <i>true</i> if the collection is ready for editing, <i>false</i> otherwise.
382 */
383 public void collectionChanged(final boolean ready) {
384 if(Gatherer.config.get("workflow.mirror", true)) {
385 mirror_pane.collectionChanged(ready);
386 }
387 menu_bar.collectionChanged(ready); // Inform the menu bar that the collections changed.
388 gather_pane.collectionChanged(ready); // Used to update the collection workspace.
389 enrich_pane.collectionChanged(ready); // Very important that metaedit pane shows current collection and is listening to latest msm.
390 design_pane.collectionChanged(ready); // Also important config pane is listening to latest msm.
391 create_pane.collectionChanged(ready); // Used to indicate a new BuildOptions model should be loaded.
392 //preview_pane.collectionChanged(ready); // preview should know when teh coll has changed so it can reload the home page
393
394 if(!locked) {
395 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
396 if(tab_updater == null) {
397 tab_updater = new TabUpdater(tab_pane, ready);
398 }
399 else {
400 tab_updater.setReady(ready);
401 }
402 SwingUtilities.invokeLater(tab_updater);
403 }
404 // Set the title
405 String collection_title = null;
406 String collection_name = null;
407 if (ready) {
408 Collection collection = Gatherer.c_man.getCollection();
409 collection_title = collection.getTitle();
410 collection_name = collection.getName();
411 collection = null;
412 }
413 setTitle(collection_title, collection_name);
414 collection_title = null;
415 collection_name = null;
416 // Now is a good time to force a garbage collect.
417 ///ystem.err.println("Calling garbage collection.");
418 System.gc();
419 }
420
421 public void destroy() {
422 // Destroying create pane ensures the latest log has been closed
423 if(create_pane != null) {
424 create_pane.destroy();
425 }
426 }
427
428 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
429 */
430 public void display() {
431 content_pane = (JPanel) this.getContentPane();
432 // Enable window-type events to be fired.
433 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
434 // Initialise and layout sub-components, plus other window dressing.
435 try {
436 this.setSize(size);
437
438 // Set the title
439 String collection_title = null;
440 String collection_name = null;
441 if (Gatherer.c_man.ready()) {
442 Collection collection = Gatherer.c_man.getCollection();
443 collection_title = collection.getTitle();
444 collection_name = collection.getName();
445 collection = null;
446 }
447 setTitle(collection_title, collection_name);
448 collection_title = null;
449 collection_name = null;
450
451 // Pretty corner icon
452 this.setIconImage(Utility.getImage("gatherer_small.gif").getImage());
453 // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
454 content_pane.setLayout(new BorderLayout());
455 // Create the menu-bar and stick it up the top.
456 menu_bar = new MenuBar(new MenuListenerImpl());
457
458 //feedback changes
459 //content_pane.add(menu_bar, BorderLayout.NORTH);
460 this.setJMenuBar(menu_bar);
461 // end feedback changes
462
463 // Create the tabbed pane and plop it in the center where it will
464 // expand to consume all available space like any good gas would.
465 tab_pane = new JTabbedPane();
466 tab_pane.addChangeListener(this);
467 tab_pane.setFont(Gatherer.config.getFont("general.font", false));
468
469 if(Gatherer.config.get(StaticStrings.WORKFLOW_MIRROR, true)) {
470 mirror_pane = new MirrorPane();
471 tab_pane.addTab("GUI.Mirror", Utility.getImage("mirroring.gif"), mirror_pane);
472 tab_pane.setEnabledAt(tab_pane.indexOfComponent(mirror_pane), Gatherer.config.get(StaticStrings.WORKFLOW_MIRROR, false));
473 }
474
475 gather_pane = new GatherPane(workspace_tree_sync, collection_tree_sync);
476 gather_pane.display();
477 if(Gatherer.config.get("workflow.gather", true)) {
478 tab_pane.addTab("GUI.Gather", Utility.getImage("collection.gif"), gather_pane);
479 tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Gatherer.config.get("workflow.gather", false));
480 }
481
482 enrich_pane = new EnrichPane(collection_tree_sync);
483 enrich_pane.display();
484 if(Gatherer.config.get("workflow.enrich", true)) {
485 tab_pane.addTab("GUI.Enrich", Utility.getImage("metaedit.gif"), enrich_pane);
486 tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
487 }
488
489 design_pane = new DesignPane();
490 design_pane.display();
491 if(Gatherer.config.get("workflow.design", true)) {
492 tab_pane.addTab("GUI.Design", Utility.getImage("build.gif"), design_pane);
493 tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
494 }
495
496 if(Gatherer.config.get("workflow.export", true)) {
497 tab_pane.addTab("GUI.Export", Utility.getImage("export.gif"), export_pane);
498 tab_pane.setEnabledAt(tab_pane.indexOfComponent(export_pane), false);
499 }
500
501 create_pane = new CreatePane();
502 create_pane.display();
503 if(Gatherer.config.get("workflow.create", true)) {
504 tab_pane.addTab("GUI.Create", Utility.getImage("build session.gif"), create_pane);
505 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
506 }
507
508 //preview_pane = new PreviewPane();
509 //preview_pane.display();
510 //if(Gatherer.config.get("workflow.preview", true)) {
511 //tab_pane.addTab("GUI.Preview", Utility.getImage("final.gif"), preview_pane);
512 //tab_pane.setEnabledAt(tab_pane.indexOfComponent(preview_pane), false);
513 //}
514
515 // Select the collect pane if it is available
516 if(Gatherer.config.get("workflow.gather", false)) {
517 tab_pane.setSelectedComponent(gather_pane);
518 }
519 // Otherwise find the first tab that is enabled and select that.
520 else {
521 boolean found = false;
522 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
523 if(tab_pane.isEnabledAt(i)) {
524 tab_pane.setSelectedIndex(i);
525 found = true;
526 }
527 }
528 }
529
530 Dictionary.register(tab_pane);
531 content_pane.add(tab_pane, BorderLayout.CENTER);
532 // Drive a sessionReady event to update all controls to reflect current collection status.
533 collectionChanged(Gatherer.c_man.ready());
534 }
535 catch (Exception e) {
536 Gatherer.printStackTrace(e);
537 // The GUI failing to build is a app killer
538 e.printStackTrace();
539 System.exit(1);
540 }
541 }
542 /** When called this method ensures that all the things needing saving are saved before Gatherer.exit() is called. This includes a save collection prompt if necessary.
543 */
544 public void exit() {
545 // Tell everyone who cares that they are losing focus
546 if(!Gatherer.c_man.ready() || design_pane.canSave()) {
547 boolean cont = true;
548 if(Gatherer.c_man.ready() && !Gatherer.c_man.saved()) {
549 cont = showSaveCollectionBox(false, true);
550 }
551 else {
552 // Deal to help
553 if(help != null) {
554 help.destroy();
555 help = null;
556 }
557 Gatherer.self.exit();
558 }
559 }
560 }
561 /** Retrieve the filter, or if one already exists, spawn a linked copy. */
562 public Filter getFilter(DragTree tree) {
563 Filter filter = (Filter) filters.get(tree.getModel());
564 if (filter == null) {
565 filter = new Filter(tree, null);
566 filters.put(tree.getModel(), filter);
567 return filter;
568 }
569 return filter.spawn(tree);
570 }
571
572 public Component getSelectedView() {
573 return tab_pane.getSelectedComponent();
574 }
575 /** This method is called when the collection is being built, and is used to disable all controls in all pane which could change the state of the collection.
576 */
577 public void lockCollection(boolean import_stage, boolean lock) {
578 locked = lock;
579 if(import_stage) {
580 int collection_pos = tab_pane.indexOfComponent(gather_pane);
581 int metaedit_pos = tab_pane.indexOfComponent(enrich_pane);
582 int config_pos = tab_pane.indexOfComponent(design_pane);
583 tab_pane.setEnabledAt(collection_pos, !lock);
584 tab_pane.setEnabledAt(metaedit_pos, !lock);
585 tab_pane.setEnabledAt(config_pos, !lock);
586 }
587 else {
588 int config_pos = tab_pane.indexOfComponent(design_pane);
589 tab_pane.setEnabledAt(config_pos, !lock);
590 }
591 }
592
593 public void modeChanged(int mode) {
594 // Set the title
595 String collection_title = null;
596 String collection_name = null;
597 if (Gatherer.c_man.ready()) {
598 Collection collection = Gatherer.c_man.getCollection();
599 collection_title = collection.getTitle();
600 collection_name = collection.getName();
601 collection = null;
602 }
603 setTitle(collection_title, collection_name);
604 collection_title = null;
605 collection_name = null;
606 // Now pass on the message to anyone who cares
607 if(gather_pane != null) {
608 gather_pane.modeChanged(mode);
609 }
610 if(design_pane != null) {
611 design_pane.modeChanged(mode);
612 }
613 if(create_pane != null) {
614 create_pane.modeChanged(mode);
615 }
616 if(enrich_pane != null) {
617 enrich_pane.modeChanged(mode);
618 }
619 }
620
621
622 public void refreshCollectionTree(int refresh_reason)
623 {
624 if (gather_pane != null) {
625 gather_pane.refreshCollectionTree(refresh_reason);
626 }
627 }
628
629
630 public void refreshWorkspaceTree(int refresh_reason)
631 {
632 if (gather_pane != null) {
633 gather_pane.refreshWorkspaceTree(refresh_reason);
634 }
635 }
636
637
638 /** Returns to some "initial" pane (when no collection is loaded) */
639 public void returnToInitialPane()
640 {
641 if (gather_pane != null) {
642 tab_pane.setSelectedComponent(gather_pane);
643 }
644 }
645
646
647 /** Specifies whether a certain tab is enabled or not. */
648 public void setTabEnabled(String rawname, boolean state) {
649 // Retrieve the dictionary based name.
650 String name = Dictionary.get("GUI." + rawname);
651 int index = tab_pane.indexOfTab(name);
652 // Of course we may not have this tab available.
653 if(index != -1) {
654 // Some tabs are also dependant on if a collection is ready
655 Component component = tab_pane.getComponentAt(index);
656 //if(component == preview_pane) {
657 //tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.built());
658 //}
659 //else
660 if(component == enrich_pane || component == design_pane || component == export_pane || component == create_pane) {
661 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
662 }
663 else {
664 tab_pane.setEnabledAt(index, state);
665 }
666 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
667 if(tab_pane.getSelectedIndex() == index && !state) {
668 boolean found = false;
669 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
670 if(tab_pane.isEnabledAt(i)) {
671 tab_pane.setSelectedIndex(i);
672 found = true;
673 }
674 }
675 // If there are no tabs enabled, which should be impossible, then select the first tab
676 if(!found) {
677 tab_pane.setSelectedIndex(0);
678 }
679 }
680 }
681 // If the rawname was mirror then rebuild workspace tree to remove caches.
682 if (rawname.equals("Mirror")) {
683 // gather_pane.refreshWorkspaceTree(WorkspaceTree.FOLDER_SHORTCUTS_CHANGED);
684 }
685 }
686
687 /** Change the string shown in the title bar of the main gui frame. If either value is null, the 'No Collection' string is shown instead.
688 * @param title
689 * @param name
690 */
691 public void setTitle(String title, String name) {
692 // Finally display the collection name in the title bar.
693 StringBuffer title_buffer = new StringBuffer(Utility.PROGRAM_NAME);
694 title_buffer.append(StaticStrings.SPACE_CHARACTER);
695 title_buffer.append(StaticStrings.SPACE_CHARACTER);
696 // Describe the current user mode
697 title_buffer.append(StaticStrings.MODE_STR);
698 title_buffer.append(Gatherer.config.getModeAsString());
699 title_buffer.append(StaticStrings.SPACE_CHARACTER);
700 title_buffer.append(StaticStrings.SPACE_CHARACTER);
701 // Now for the current collection
702 title_buffer.append(StaticStrings.COLLECTION_STR);
703 if (title != null && name != null) {
704 title_buffer.append(title);
705 title_buffer.append(StaticStrings.SPACE_CHARACTER);
706 title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
707 title_buffer.append(name);
708 title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
709 }
710 else {
711 title_buffer.append(Dictionary.get("Collection.No_Collection"));
712 }
713 this.setTitle(title_buffer.toString());
714 title_buffer = null;
715 }
716
717 /** When the edit metadata option is choosen from the menu, this method is called to ensure we only edit the metadata if there is metadata loaded.
718 */
719 public void showEditMetadataBox() {
720 if(Gatherer.c_man.getCollection() != null) {
721 Gatherer.c_man.getCollection().msm.editMDS(null, MetadataEditorManager.NORMAL);
722 }
723 }
724 /** When the load collection option is choosen this method is called to produce the modal file load prompt.
725 */
726 public boolean showLoadCollectionBox() {
727 boolean result = false;
728 // We first try the simple open collection dialog
729 SimpleOpenCollectionDialog dialog = new SimpleOpenCollectionDialog();
730 int user_choice = dialog.display();
731 String filename = null;
732 // The user may choose to go to the advanced 'browse' dialog
733 if(user_choice == SimpleOpenCollectionDialog.OK_OPTION) {
734 filename = dialog.getFileName();
735 }
736 else if(user_choice == SimpleOpenCollectionDialog.BROWSE_OPTION) {
737 File file;
738 if (Gatherer.GS3) {
739 if (Gatherer.config.gsdl3_path != null) {
740 file = new File(Utility.getSitesDir(Gatherer.config.gsdl3_path));
741 } else {
742 file = new File(Utility.BASE_DIR);
743 }
744
745 } else {
746
747 if(Gatherer.config.gsdl_path != null) {
748 file = new File(Utility.getCollectDir(Gatherer.config.gsdl_path));
749 }
750 else {
751 file = new File(Utility.BASE_DIR);
752 }
753 }
754 OpenCollectionDialog chooser = new OpenCollectionDialog(file);
755 file = null;
756 filename = chooser.getFileName();
757 chooser.destroy();
758 chooser = null;
759 }
760 dialog.destroy();
761 dialog = null;
762 // User can cancel action.
763 if(filename != null) {
764 // If there is already a collection open, save and close it.
765 if(Gatherer.c_man.ready()) {
766 showSaveCollectionBox(true, false);
767 // Wait until it is closed.
768 try {
769 synchronized(this) {
770 while(Gatherer.c_man.reallyReady()) {
771 wait(10);
772 }
773 }
774 }
775 catch(Exception error) {
776 Gatherer.println("Exception: " + error);
777 Gatherer.printStackTrace(error);
778 }
779 }
780
781 result = Gatherer.c_man.loadCollection(filename);
782 filename = null;
783 }
784 return result;
785 }
786
787 /** When called this method causes the MetaAuditBox class in CollectionManager to display a nice dialog box which contains all the metadata assigned in the collection.
788 */
789 public void showMetaAuditBox() {
790 wait(true);
791 meta_audit.display();
792 wait(false);
793 }
794 /** This method is used to open the new collection box on the screen.
795 */
796 public void showNewCollectionPrompt() {
797 NewCollectionMetadataPrompt ncm_prompt = null;
798 // Create the collection details prompt from new collection prompt
799 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
800 // If no previous collection was indicated as a model design, then show the metadata selection prompt from new collection prompt
801 if(!ncd_prompt.isCancelled() && (ncd_prompt.getBase() == null)) {
802 ncm_prompt = new NewCollectionMetadataPrompt();
803 }
804 // Create the new collection (if not cancelled) in a new thread.
805 if(!ncd_prompt.isCancelled() && (ncm_prompt == null || !ncm_prompt.isCancelled())) {
806 // If there is already a collection open, save and close it.
807 if(Gatherer.c_man.ready()) {
808 showSaveCollectionBox(true, false);
809 // Wait until it is closed.
810 try {
811 synchronized(this) {
812 while(Gatherer.c_man.reallyReady()) {
813 wait(10);
814 }
815 }
816 }
817 catch(Exception error) {
818 Gatherer.println("Exception: " + error);
819 Gatherer.printStackTrace(error);
820 }
821 }
822
823 // Create new collection.
824 CreationTask task = new CreationTask(ncd_prompt, ncm_prompt);
825 // SwingUtilities.invokeLater(task);
826 task.start();
827 // Close prompt.
828 }
829 // Done
830 ncd_prompt = null;
831 ncm_prompt = null;
832 }
833 private class CreationTask
834 extends Thread {
835 private NewCollectionDetailsPrompt ncd_prompt = null;
836 private NewCollectionMetadataPrompt ncm_prompt = null;
837 public CreationTask(NewCollectionDetailsPrompt ncd_prompt, NewCollectionMetadataPrompt ncm_prompt) {
838 this.ncd_prompt = ncd_prompt;
839 this.ncm_prompt = ncm_prompt;
840 }
841
842 public void run() {
843 ///ystem.err.println("Running CreationTask...");
844 if(ncm_prompt == null) {
845 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Gatherer.config.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), null);
846 }
847 else {
848 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Gatherer.config.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), null, ncm_prompt.getSets());
849 }
850 // Now that the collection specific settings are loaded we can set the 'view extracted metadata' property
851 // do we want to have this in here???
852 //Gatherer.config.set("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC, true);
853 ncd_prompt.dispose();
854 ncd_prompt = null;
855 if(ncm_prompt != null) {
856 ncm_prompt.dispose();
857 ncm_prompt = null;
858 }
859 }
860 }
861
862
863 /** This method is used to open the save collection box/prompt on the screen.
864 * @return A <i>boolean</i> which is <i>true</i> if the collection was saved successfully, <i>false</i> otherwise.
865 */
866 public boolean showSaveCollectionBox(boolean close_after, boolean exit_after) {
867 //SaveCollectionBox save_collection_box = new SaveCollectionBox();
868 //Rectangle bounds = save_collection_box.getBounds();
869 //int result = save_collection_box.getUserOption(Gatherer.c_man.getCollection().getName());
870 //switch(result) {
871 //case SaveCollectionBox.SAVE_YES:
872 Gatherer.c_man.setClosingThread(true);
873 Gatherer.c_man.saveCollection(close_after, exit_after);
874 // Wait until it is closed.
875 try {
876 synchronized(this) {
877 while(Gatherer.c_man.reallyReady()) {
878 wait(10);
879 }
880 }
881 }
882 catch(Exception error) {
883 Gatherer.println("Exception: " + error);
884 Gatherer.printStackTrace(error);
885 }
886
887 Gatherer.c_man.setClosingThread(false);
888
889 //content_pane.paintImmediately(bounds);
890 return true;
891 //case SaveCollectionBox.SAVE_NO:
892 // Close collection.
893 // if(close_after) {
894 // tab_pane.setSelectedComponent(gather_pane);
895 // Gatherer.c_man.closeCollection();
896 // }
897 // if(exit_after) {
898 // Gatherer.self.exit();
899 // }
900 // return true;
901 //default:
902 // return false;
903 //}
904 }
905 /** Any implementation of ChangeListener must include this method so we can be informed when the state of one of the registered objects changes. In this case we are listening to view changes within the tabbed pane.
906 * @param event A ChangeEvent containing information about the event that fired this call.
907 */
908 public void stateChanged(ChangeEvent event) {
909 if(previous_pane != null) {
910 if(previous_pane == create_pane) {
911 create_pane.loseFocus();
912 }
913 else if(previous_pane == design_pane) {
914 design_pane.loseFocus();
915 }
916 }
917 // "View assigned metadata" menu item is disabled by default
918 menu_bar.metadata_view.setCanEnable(false);
919 menu_bar.setMetaAuditSuffix(null);
920
921 menu_bar.tabSelected(tab_pane.getSelectedIndex());
922 int selected_index = tab_pane.getSelectedIndex();
923 if( selected_index == tab_pane.indexOfComponent(gather_pane)) {
924 gather_pane.gainFocus();
925 // "View assigned metadata" menu item is enabled for the "Gather" pane
926 menu_bar.metadata_view.setCanEnable(true);
927 }
928 else if(selected_index == tab_pane.indexOfComponent(enrich_pane)) {
929 enrich_pane.gainFocus();
930 // "View assigned metadata" menu item is enabled for the "Enrich" pane
931 menu_bar.metadata_view.setCanEnable(true);
932 }
933 else if(selected_index == tab_pane.indexOfComponent(design_pane)) {
934 design_pane.gainFocus();
935 }
936 else if(selected_index == tab_pane.indexOfComponent(create_pane)) {
937 create_pane.gainFocus();
938 }
939 else if(selected_index == tab_pane.indexOfComponent(mirror_pane)) {
940 mirror_pane.gainFocus();
941 }
942 //else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(preview_pane)) {
943 //design_pane.saveConfiguration();
944 //preview_pane.gainFocus();
945 //}
946
947 previous_pane = (JPanel) tab_pane.getSelectedComponent();
948 }
949
950 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
951
952 public void wait(boolean waiting) {
953 Component glass_pane = getGlassPane();
954 if(waiting) {
955 // Show wait cursor.
956 glass_pane.addMouseListener(mouse_blocker_listener);
957 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
958 glass_pane.setVisible(true);
959 }
960 else {
961 // Hide wait cursor.
962 glass_pane.setVisible(false);
963 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
964 glass_pane.removeMouseListener(mouse_blocker_listener);
965 }
966 glass_pane = null;
967 }
968
969 public void workflowUpdate(String raw, boolean state) {
970 WorkflowUpdater task = new WorkflowUpdater(raw, state);
971 SwingUtilities.invokeLater(task);
972 task = null;
973 }
974
975 /** Called to determine if we should wait for a thread to finish before continuing. We wait for threads if they are named: GSHELL_BUILD, GSHELL_IMPORT, or GSHELL_NEW.
976 * @return <i>true</i> if we should wait for a thread, <i>false</i> if it is safe to continue.
977 */
978 private boolean waitForThread() {
979 Thread active[] = new Thread[thread_group.activeCount()];
980 int size = thread_group.enumerate(active);
981 for(int i = 0; i < size; i++) {
982 if(active[i].getName().equals(GShell.GSHELL_BUILD) ||
983 active[i].getName().equals(GShell.GSHELL_IMPORT) ||
984 active[i].getName().equals(GShell.GSHELL_NEW)) {
985 return true;
986 }
987 }
988 return false;
989 }
990
991
992 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
993 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
994 */
995 protected void processWindowEvent(WindowEvent event) {
996 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
997 exit();
998 }
999 }
1000 /** Listens to actions upon the menu bar, and if it detects a click over the help menu brings the help window to the front if it has become hidden.
1001 */
1002 private class MenuListenerImpl
1003 implements MenuListener {
1004 /** Called whenever a popup menu is hidden, but we don't care.
1005 * @param e Some <strong>MenuEvent</strong> that we could care less about.
1006 */
1007 public void menuCanceled(MenuEvent e) {
1008 }
1009 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
1010 * @param e Some <strong>MenuEvent</strong> that we could care less about.
1011 */
1012 public void menuDeselected(MenuEvent e) {
1013 }
1014 /** This method, when a menu is first opened, is the only one we respond to by bringing the help window to the front if possible, but only if there is a help window and the help menu is the one opening.
1015 * @param e The <strong>MenuEvent</strong> whose source is checked.
1016 */
1017 public void menuSelected(MenuEvent e) {
1018 if(e.getSource() == menu_bar.help) {
1019 if(menu_bar.help.isSelected()) {
1020 menu_bar.help.doClick(10);
1021 }
1022 }
1023 }
1024 }
1025 private class TabUpdater
1026 implements Runnable {
1027 private boolean ready = false;
1028 //private int browse_pos = -1;
1029 private int mirror_pos = -1;
1030 private int config_pos = -1;
1031 private int create_pos = -1;
1032 private int export_pos = -1;
1033 private int metaedit_pos = -1;
1034 //private int preview_pos = -1;
1035 private JTabbedPane tab_pane = null;
1036 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
1037 this.ready = ready;
1038 this.tab_pane = tab_pane;
1039 //browse_pos = tab_pane.indexOfComponent(browser_pane);
1040 mirror_pos = tab_pane.indexOfComponent(mirror_pane);
1041 metaedit_pos = tab_pane.indexOfComponent(enrich_pane);
1042 config_pos = tab_pane.indexOfComponent(design_pane);
1043 export_pos = tab_pane.indexOfComponent(export_pane);
1044 create_pos = tab_pane.indexOfComponent(create_pane);
1045 //preview_pos = tab_pane.indexOfComponent(preview_pane);
1046 }
1047
1048 public void run() {
1049// if(browse_pos != -1) {
1050// if(ready) {
1051// tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", false));
1052// }
1053// else {
1054// tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", true));
1055// }
1056// }
1057 if(mirror_pos != -1) {
1058 if(ready) {
1059 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", false));
1060 }
1061 else {
1062 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", true));
1063 }
1064 }
1065 if(metaedit_pos != -1) {
1066 tab_pane.setEnabledAt(metaedit_pos, ready && Gatherer.config.get("workflow.enrich", false));
1067 }
1068 if(config_pos != -1) {
1069 tab_pane.setEnabledAt(config_pos, ready && Gatherer.config.get("workflow.design", false) && Gatherer.config.getMode() > Configuration.ASSISTANT_MODE);
1070 }
1071 if(export_pos != -1) {
1072 tab_pane.setEnabledAt(export_pos, ready && Gatherer.config.get("workflow.export", false));
1073 }
1074 if(create_pos != -1) {
1075 tab_pane.setEnabledAt(create_pos, ready && Gatherer.config.get("workflow.create", false));
1076 }
1077// if(preview_pos != -1) {
1078// tab_pane.setEnabledAt(preview_pos, Gatherer.c_man != null && Gatherer.c_man.built() && Gatherer.config.get("workflow.preview", false));
1079// }
1080 }
1081 public void setReady(boolean ready) {
1082 this.ready = ready;
1083 }
1084 }
1085
1086 private class WorkflowUpdater
1087 implements Runnable {
1088 private boolean state;
1089 private String raw;
1090 public WorkflowUpdater(String raw, boolean state) {
1091 this.raw = raw;
1092 this.state = state;
1093 }
1094 public void run() {
1095 setTabEnabled(raw, state);
1096 }
1097 }
1098}
1099
1100
Note: See TracBrowser for help on using the repository browser.