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

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

Renamed GDM* classes to MetadataXMLFile*, for our sanity.

  • Property svn:keywords set to Author Date Id Revision
File size: 39.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.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 public 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 /** 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.
372 * @param ready <i>true</i> if the collection is ready for editing, <i>false</i> otherwise.
373 */
374 public void collectionChanged(final boolean ready) {
375 if(Gatherer.config.get("workflow.mirror", true)) {
376 mirror_pane.collectionChanged(ready);
377 }
378 menu_bar.collectionChanged(ready); // Inform the menu bar that the collections changed.
379 gather_pane.collectionChanged(ready); // Used to update the collection workspace.
380 enrich_pane.collectionChanged(ready); // Very important that metaedit pane shows current collection and is listening to latest msm.
381 design_pane.collectionChanged(ready); // Also important config pane is listening to latest msm.
382 create_pane.collectionChanged(ready); // Used to indicate a new BuildOptions model should be loaded.
383 //preview_pane.collectionChanged(ready); // preview should know when teh coll has changed so it can reload the home page
384
385 if(!locked) {
386 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
387 if(tab_updater == null) {
388 tab_updater = new TabUpdater(tab_pane, ready);
389 }
390 else {
391 tab_updater.setReady(ready);
392 }
393 SwingUtilities.invokeLater(tab_updater);
394 }
395 // Set the title
396 String collection_title = null;
397 String collection_name = null;
398 if (ready) {
399 Collection collection = Gatherer.c_man.getCollection();
400 collection_title = collection.getTitle();
401 collection_name = collection.getName();
402 collection = null;
403 }
404 setTitle(collection_title, collection_name);
405 collection_title = null;
406 collection_name = null;
407 // Now is a good time to force a garbage collect.
408 ///ystem.err.println("Calling garbage collection.");
409 System.gc();
410 }
411
412 public void destroy() {
413 // Destroying create pane ensures the latest log has been closed
414 if(create_pane != null) {
415 create_pane.destroy();
416 }
417 }
418
419 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
420 */
421 public void display() {
422 content_pane = (JPanel) this.getContentPane();
423 // Enable window-type events to be fired.
424 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
425 // Initialise and layout sub-components, plus other window dressing.
426 try {
427 this.setSize(size);
428
429 // Set the title
430 String collection_title = null;
431 String collection_name = null;
432 if (Gatherer.c_man.ready()) {
433 Collection collection = Gatherer.c_man.getCollection();
434 collection_title = collection.getTitle();
435 collection_name = collection.getName();
436 collection = null;
437 }
438 setTitle(collection_title, collection_name);
439 collection_title = null;
440 collection_name = null;
441
442 // Pretty corner icon
443 this.setIconImage(Utility.getImage("gatherer_small.gif").getImage());
444 // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
445 content_pane.setLayout(new BorderLayout());
446 // Create the menu-bar and stick it up the top.
447 menu_bar = new MenuBar(new MenuListenerImpl());
448 content_pane.add(menu_bar, BorderLayout.NORTH);
449 // Create the tabbed pane and plop it in the center where it will
450 // expand to consume all available space like any good gas would.
451 tab_pane = new JTabbedPane();
452 tab_pane.addChangeListener(this);
453 tab_pane.setFont(Gatherer.config.getFont("general.font", false));
454
455// // May have to play with the order in which tabs are added.
456// if(Gatherer.config.get("workflow.browse", true)) {
457// browser_pane = new BrowsingPane();
458// tab_pane.addTab("GUI.Hunt", Utility.getImage("browsing.gif"), browser_pane);
459// tab_pane.setEnabledAt(tab_pane.indexOfComponent(browser_pane), Gatherer.config.get("workflow.browse", false));
460// }
461
462 if(Gatherer.config.get(StaticStrings.WORKFLOW_MIRROR, true)) {
463 mirror_pane = new MirrorPane();
464 tab_pane.addTab("GUI.Mirror", Utility.getImage("mirroring.gif"), mirror_pane);
465 tab_pane.setEnabledAt(tab_pane.indexOfComponent(mirror_pane), Gatherer.config.get(StaticStrings.WORKFLOW_MIRROR, false));
466 }
467
468 gather_pane = new GatherPane(workspace_tree_sync, collection_tree_sync);
469 gather_pane.display();
470 if(Gatherer.config.get("workflow.gather", true)) {
471 tab_pane.addTab("GUI.Gather", Utility.getImage("collection.gif"), gather_pane);
472 tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Gatherer.config.get("workflow.gather", false));
473 }
474
475 enrich_pane = new EnrichPane(collection_tree_sync);
476 enrich_pane.display();
477 if(Gatherer.config.get("workflow.enrich", true)) {
478 tab_pane.addTab("GUI.Enrich", Utility.getImage("metaedit.gif"), enrich_pane);
479 tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
480 }
481
482 design_pane = new DesignPane();
483 design_pane.display();
484 if(Gatherer.config.get("workflow.design", true)) {
485 tab_pane.addTab("GUI.Design", Utility.getImage("build.gif"), design_pane);
486 tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
487 }
488
489 if(Gatherer.config.get("workflow.export", true)) {
490 tab_pane.addTab("GUI.Export", Utility.getImage("export.gif"), export_pane);
491 tab_pane.setEnabledAt(tab_pane.indexOfComponent(export_pane), false);
492 }
493
494 create_pane = new CreatePane();
495 create_pane.display();
496 if(Gatherer.config.get("workflow.create", true)) {
497 tab_pane.addTab("GUI.Create", Utility.getImage("build session.gif"), create_pane);
498 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
499 }
500
501 //preview_pane = new PreviewPane();
502 //preview_pane.display();
503 //if(Gatherer.config.get("workflow.preview", true)) {
504 //tab_pane.addTab("GUI.Preview", Utility.getImage("final.gif"), preview_pane);
505 //tab_pane.setEnabledAt(tab_pane.indexOfComponent(preview_pane), false);
506 //}
507
508 // Select the collect pane if it is available
509 if(Gatherer.config.get("workflow.gather", false)) {
510 tab_pane.setSelectedComponent(gather_pane);
511 }
512 // Otherwise find the first tab that is enabled and select that.
513 else {
514 boolean found = false;
515 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
516 if(tab_pane.isEnabledAt(i)) {
517 tab_pane.setSelectedIndex(i);
518 found = true;
519 }
520 }
521 }
522
523 Dictionary.register(tab_pane);
524 content_pane.add(tab_pane, BorderLayout.CENTER);
525 // Drive a sessionReady event to update all controls to reflect current collection status.
526 collectionChanged(Gatherer.c_man.ready());
527 }
528 catch (Exception e) {
529 Gatherer.printStackTrace(e);
530 // The GUI failing to build is a app killer
531 e.printStackTrace();
532 System.exit(1);
533 }
534 }
535 /** 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.
536 */
537 public void exit() {
538 // Tell everyone who cares that they are losing focus
539 if(!Gatherer.c_man.ready() || design_pane.canSave()) {
540 boolean cont = true;
541 if(Gatherer.c_man.ready() && !Gatherer.c_man.saved()) {
542 cont = showSaveCollectionBox(false, true);
543 }
544 else {
545 // Deal to help
546 if(help != null) {
547 help.destroy();
548 help = null;
549 }
550 Gatherer.self.exit();
551 }
552 }
553 }
554 /** Retrieve the filter, or if one already exists, spawn a linked copy. */
555 public Filter getFilter(DragTree tree) {
556 Filter filter = (Filter) filters.get(tree.getModel());
557 if (filter == null) {
558 filter = new Filter(tree, null);
559 filters.put(tree.getModel(), filter);
560 return filter;
561 }
562 return filter.spawn(tree);
563 }
564
565 public Component getSelectedView() {
566 return tab_pane.getSelectedComponent();
567 }
568 /** 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.
569 */
570 public void lockCollection(boolean import_stage, boolean lock) {
571 locked = lock;
572 if(import_stage) {
573 int collection_pos = tab_pane.indexOfComponent(gather_pane);
574 int metaedit_pos = tab_pane.indexOfComponent(enrich_pane);
575 int config_pos = tab_pane.indexOfComponent(design_pane);
576 tab_pane.setEnabledAt(collection_pos, !lock);
577 tab_pane.setEnabledAt(metaedit_pos, !lock);
578 tab_pane.setEnabledAt(config_pos, !lock);
579 }
580 else {
581 int config_pos = tab_pane.indexOfComponent(design_pane);
582 tab_pane.setEnabledAt(config_pos, !lock);
583 }
584 }
585
586 public void modeChanged(int mode) {
587 // Set the title
588 String collection_title = null;
589 String collection_name = null;
590 if (Gatherer.c_man.ready()) {
591 Collection collection = Gatherer.c_man.getCollection();
592 collection_title = collection.getTitle();
593 collection_name = collection.getName();
594 collection = null;
595 }
596 setTitle(collection_title, collection_name);
597 collection_title = null;
598 collection_name = null;
599 // Now pass on the message to anyone who cares
600 if(gather_pane != null) {
601 gather_pane.modeChanged(mode);
602 }
603 if(design_pane != null) {
604 design_pane.modeChanged(mode);
605 }
606 if(create_pane != null) {
607 create_pane.modeChanged(mode);
608 }
609 if(enrich_pane != null) {
610 enrich_pane.modeChanged(mode);
611 }
612 }
613
614 public void refreshTrees(int refresh_reason)
615 {
616 if (gather_pane != null) {
617 gather_pane.refreshWorkspaceTree(refresh_reason);
618 gather_pane.refreshCollectionTree(refresh_reason);
619 }
620 }
621
622 /** Allows the system to programatically set the selected tab.
623 * @param component The view you wish to make visable in the tab pane as a <strong>Component</strong>.
624 */
625 public void setSelectedView(Component component) {
626 tab_pane.setSelectedComponent(component);
627 }
628
629 /** Specifies whether a certain tab is enabled or not. */
630 public void setTabEnabled(String rawname, boolean state) {
631 // Retrieve the dictionary based name.
632 String name = Dictionary.get("GUI." + rawname);
633 int index = tab_pane.indexOfTab(name);
634 // Of course we may not have this tab available.
635 if(index != -1) {
636 // Some tabs are also dependant on if a collection is ready
637 Component component = tab_pane.getComponentAt(index);
638 //if(component == preview_pane) {
639 //tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.built());
640 //}
641 //else
642 if(component == enrich_pane || component == design_pane || component == export_pane || component == create_pane) {
643 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
644 }
645 else {
646 tab_pane.setEnabledAt(index, state);
647 }
648 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
649 if(tab_pane.getSelectedIndex() == index && !state) {
650 boolean found = false;
651 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
652 if(tab_pane.isEnabledAt(i)) {
653 tab_pane.setSelectedIndex(i);
654 found = true;
655 }
656 }
657 // If there are no tabs enabled, which should be impossible, then select the first tab
658 if(!found) {
659 tab_pane.setSelectedIndex(0);
660 }
661 }
662 }
663 // If the rawname was mirror then rebuild workspace tree to remove caches.
664 if (rawname.equals("Mirror")) {
665 gather_pane.refreshWorkspaceTree(WorkspaceTree.MAPPED_DIRECTORIES_CHANGED);
666 }
667 }
668
669 /** 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.
670 * @param title
671 * @param name
672 */
673 public void setTitle(String title, String name) {
674 // Finally display the collection name in the title bar.
675 StringBuffer title_buffer = new StringBuffer(Utility.PROGRAM_NAME);
676 title_buffer.append(StaticStrings.SPACE_CHARACTER);
677 title_buffer.append(StaticStrings.SPACE_CHARACTER);
678 // Describe the current user mode
679 title_buffer.append(StaticStrings.MODE_STR);
680 title_buffer.append(Gatherer.config.getModeAsString());
681 title_buffer.append(StaticStrings.SPACE_CHARACTER);
682 title_buffer.append(StaticStrings.SPACE_CHARACTER);
683 // Now for the current collection
684 title_buffer.append(StaticStrings.COLLECTION_STR);
685 if (title != null && name != null) {
686 title_buffer.append(title);
687 title_buffer.append(StaticStrings.SPACE_CHARACTER);
688 title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
689 title_buffer.append(name);
690 title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
691 }
692 else {
693 title_buffer.append(Dictionary.get("Collection.No_Collection"));
694 }
695 this.setTitle(title_buffer.toString());
696 title_buffer = null;
697 }
698
699 /** 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.
700 */
701 public void showEditMetadataBox() {
702 if(Gatherer.c_man.getCollection() != null) {
703 Gatherer.c_man.getCollection().msm.editMDS(null, MetadataEditorManager.NORMAL);
704 }
705 }
706 /** When the load collection option is choosen this method is called to produce the modal file load prompt.
707 */
708 public boolean showLoadCollectionBox() {
709 boolean result = false;
710 // We first try the simple open collection dialog
711 SimpleOpenCollectionDialog dialog = new SimpleOpenCollectionDialog();
712 int user_choice = dialog.display();
713 String filename = null;
714 // The user may choose to go to the advanced 'browse' dialog
715 if(user_choice == SimpleOpenCollectionDialog.OK_OPTION) {
716 filename = dialog.getFileName();
717 }
718 else if(user_choice == SimpleOpenCollectionDialog.BROWSE_OPTION) {
719 File file;
720 if(Gatherer.config.gsdl_path != null) {
721 file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
722 }
723 else {
724 file = new File(Utility.BASE_DIR);
725 }
726 OpenCollectionDialog chooser = new OpenCollectionDialog(file);
727 file = null;
728 filename = chooser.getFileName();
729 chooser.destroy();
730 chooser = null;
731 }
732 dialog.destroy();
733 dialog = null;
734 // User can cancel action.
735 if(filename != null) {
736 // If there is already a collection open, save and close it.
737 if(Gatherer.c_man.ready()) {
738 showSaveCollectionBox(true, false);
739 // Wait until it is closed.
740 try {
741 synchronized(this) {
742 while(Gatherer.c_man.reallyReady()) {
743 wait(10);
744 }
745 }
746 }
747 catch(Exception error) {
748 Gatherer.println("Exception: " + error);
749 Gatherer.printStackTrace(error);
750 }
751 }
752 result = Gatherer.c_man.loadCollection(filename);
753 filename = null;
754 }
755 return result;
756 }
757
758 /** 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.
759 */
760 public void showMetaAuditBox() {
761 wait(true);
762 meta_audit.display();
763 wait(false);
764 }
765 /** This method is used to open the new collection box on the screen.
766 */
767 public void showNewCollectionPrompt() {
768 NewCollectionMetadataPrompt ncm_prompt = null;
769 // Create the collection details prompt from new collection prompt
770 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
771 // If no previous collection was indicated as a model design, then show the metadata selection prompt from new collection prompt
772 if(!ncd_prompt.isCancelled() && (ncd_prompt.getBase() == null)) {
773 ncm_prompt = new NewCollectionMetadataPrompt();
774 }
775 // Create the new collection (if not cancelled) in a new thread.
776 if(!ncd_prompt.isCancelled() && (ncm_prompt == null || !ncm_prompt.isCancelled())) {
777 // If there is already a collection open, save and close it.
778 if(Gatherer.c_man.ready()) {
779 showSaveCollectionBox(true, false);
780 // Wait until it is closed.
781 try {
782 synchronized(this) {
783 while(Gatherer.c_man.reallyReady()) {
784 wait(10);
785 }
786 }
787 }
788 catch(Exception error) {
789 Gatherer.println("Exception: " + error);
790 Gatherer.printStackTrace(error);
791 }
792 }
793
794 // Create new collection.
795 CreationTask task = new CreationTask(ncd_prompt, ncm_prompt);
796 // SwingUtilities.invokeLater(task);
797 task.start();
798 // Close prompt.
799 }
800 // Done
801 ncd_prompt = null;
802 ncm_prompt = null;
803 }
804 private class CreationTask
805 extends Thread {
806 private NewCollectionDetailsPrompt ncd_prompt = null;
807 private NewCollectionMetadataPrompt ncm_prompt = null;
808 public CreationTask(NewCollectionDetailsPrompt ncd_prompt, NewCollectionMetadataPrompt ncm_prompt) {
809 this.ncd_prompt = ncd_prompt;
810 this.ncm_prompt = ncm_prompt;
811 }
812
813 public void run() {
814 ///ystem.err.println("Running CreationTask...");
815 if(ncm_prompt == null) {
816 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Gatherer.config.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), null);
817 }
818 else {
819 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Gatherer.config.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), null, ncm_prompt.getSets());
820 }
821 // Now that the collection specific settings are loaded we can set the 'view extracted metadata' property
822 // do we want to have this in here???
823 //Gatherer.config.set("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC, true);
824 ncd_prompt.dispose();
825 ncd_prompt = null;
826 if(ncm_prompt != null) {
827 ncm_prompt.dispose();
828 ncm_prompt = null;
829 }
830 }
831 }
832
833
834 /** This method is used to open the save collection box/prompt on the screen.
835 * @return A <i>boolean</i> which is <i>true</i> if the collection was saved successfully, <i>false</i> otherwise.
836 */
837 public boolean showSaveCollectionBox(boolean close_after, boolean exit_after) {
838 //SaveCollectionBox save_collection_box = new SaveCollectionBox();
839 //Rectangle bounds = save_collection_box.getBounds();
840 //int result = save_collection_box.getUserOption(Gatherer.c_man.getCollection().getName());
841 //switch(result) {
842 //case SaveCollectionBox.SAVE_YES:
843 Gatherer.c_man.setClosingThread(true);
844 Gatherer.c_man.saveCollection(close_after, exit_after);
845 // Wait until it is closed.
846 try {
847 synchronized(this) {
848 while(Gatherer.c_man.reallyReady()) {
849 wait(10);
850 }
851 }
852 }
853 catch(Exception error) {
854 Gatherer.println("Exception: " + error);
855 Gatherer.printStackTrace(error);
856 }
857
858 Gatherer.c_man.setClosingThread(false);
859
860 //content_pane.paintImmediately(bounds);
861 return true;
862 //case SaveCollectionBox.SAVE_NO:
863 // Close collection.
864 // if(close_after) {
865 // tab_pane.setSelectedComponent(gather_pane);
866 // Gatherer.c_man.closeCollection();
867 // }
868 // if(exit_after) {
869 // Gatherer.self.exit();
870 // }
871 // return true;
872 //default:
873 // return false;
874 //}
875 }
876 /** 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.
877 * @param event A ChangeEvent containing information about the event that fired this call.
878 */
879 public void stateChanged(ChangeEvent event) {
880 if(previous_pane != null) {
881 if(previous_pane == create_pane) {
882 create_pane.loseFocus();
883 }
884 else if(previous_pane == design_pane) {
885 design_pane.loseFocus();
886 }
887 }
888 // "View assigned metadata" menu item is disabled by default
889 menu_bar.metadata_view.setCanEnable(false);
890 menu_bar.setMetaAuditSuffix(null);
891
892 menu_bar.tabSelected(tab_pane.getSelectedIndex());
893 int selected_index = tab_pane.getSelectedIndex();
894 if( selected_index == tab_pane.indexOfComponent(gather_pane)) {
895 gather_pane.gainFocus();
896 // "View assigned metadata" menu item is enabled for the "Gather" pane
897 menu_bar.metadata_view.setCanEnable(true);
898 }
899 else if(selected_index == tab_pane.indexOfComponent(enrich_pane)) {
900 enrich_pane.gainFocus();
901 // "View assigned metadata" menu item is enabled for the "Enrich" pane
902 menu_bar.metadata_view.setCanEnable(true);
903 }
904 else if(selected_index == tab_pane.indexOfComponent(design_pane)) {
905 design_pane.gainFocus();
906 }
907 else if(selected_index == tab_pane.indexOfComponent(create_pane)) {
908 create_pane.gainFocus();
909 }
910 else if(selected_index == tab_pane.indexOfComponent(mirror_pane)) {
911 mirror_pane.gainFocus();
912 }
913 //else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(preview_pane)) {
914 //design_pane.saveConfiguration();
915 //preview_pane.gainFocus();
916 //}
917
918 previous_pane = (JPanel) tab_pane.getSelectedComponent();
919 }
920
921 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
922
923 public void wait(boolean waiting) {
924 Component glass_pane = getGlassPane();
925 if(waiting) {
926 // Show wait cursor.
927 glass_pane.addMouseListener(mouse_blocker_listener);
928 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
929 glass_pane.setVisible(true);
930 }
931 else {
932 // Hide wait cursor.
933 glass_pane.setVisible(false);
934 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
935 glass_pane.removeMouseListener(mouse_blocker_listener);
936 }
937 glass_pane = null;
938 }
939
940 public void workflowUpdate(String raw, boolean state) {
941 WorkflowUpdater task = new WorkflowUpdater(raw, state);
942 SwingUtilities.invokeLater(task);
943 task = null;
944 }
945
946 /** 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.
947 * @return <i>true</i> if we should wait for a thread, <i>false</i> if it is safe to continue.
948 */
949 private boolean waitForThread() {
950 Thread active[] = new Thread[thread_group.activeCount()];
951 int size = thread_group.enumerate(active);
952 for(int i = 0; i < size; i++) {
953 if(active[i].getName().equals(GShell.GSHELL_BUILD) ||
954 active[i].getName().equals(GShell.GSHELL_IMPORT) ||
955 active[i].getName().equals(GShell.GSHELL_NEW)) {
956 return true;
957 }
958 }
959 return false;
960 }
961
962
963 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
964 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
965 */
966 protected void processWindowEvent(WindowEvent event) {
967 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
968 exit();
969 }
970 }
971 /** 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.
972 */
973 private class MenuListenerImpl
974 implements MenuListener {
975 /** Called whenever a popup menu is hidden, but we don't care.
976 * @param e Some <strong>MenuEvent</strong> that we could care less about.
977 */
978 public void menuCanceled(MenuEvent e) {
979 }
980 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
981 * @param e Some <strong>MenuEvent</strong> that we could care less about.
982 */
983 public void menuDeselected(MenuEvent e) {
984 }
985 /** 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.
986 * @param e The <strong>MenuEvent</strong> whose source is checked.
987 */
988 public void menuSelected(MenuEvent e) {
989 if(e.getSource() == menu_bar.help) {
990 if(menu_bar.help.isSelected()) {
991 menu_bar.help.doClick(10);
992 }
993 }
994 }
995 }
996 private class TabUpdater
997 implements Runnable {
998 private boolean ready = false;
999 //private int browse_pos = -1;
1000 private int mirror_pos = -1;
1001 private int config_pos = -1;
1002 private int create_pos = -1;
1003 private int export_pos = -1;
1004 private int metaedit_pos = -1;
1005 //private int preview_pos = -1;
1006 private JTabbedPane tab_pane = null;
1007 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
1008 this.ready = ready;
1009 this.tab_pane = tab_pane;
1010 //browse_pos = tab_pane.indexOfComponent(browser_pane);
1011 mirror_pos = tab_pane.indexOfComponent(mirror_pane);
1012 metaedit_pos = tab_pane.indexOfComponent(enrich_pane);
1013 config_pos = tab_pane.indexOfComponent(design_pane);
1014 export_pos = tab_pane.indexOfComponent(export_pane);
1015 create_pos = tab_pane.indexOfComponent(create_pane);
1016 //preview_pos = tab_pane.indexOfComponent(preview_pane);
1017 }
1018
1019 public void run() {
1020// if(browse_pos != -1) {
1021// if(ready) {
1022// tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", false));
1023// }
1024// else {
1025// tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", true));
1026// }
1027// }
1028 if(mirror_pos != -1) {
1029 if(ready) {
1030 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", false));
1031 }
1032 else {
1033 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", true));
1034 }
1035 }
1036 if(metaedit_pos != -1) {
1037 tab_pane.setEnabledAt(metaedit_pos, ready && Gatherer.config.get("workflow.enrich", false));
1038 }
1039 if(config_pos != -1) {
1040 tab_pane.setEnabledAt(config_pos, ready && Gatherer.config.get("workflow.design", false) && Gatherer.config.getMode() > Configuration.ASSISTANT_MODE);
1041 }
1042 if(export_pos != -1) {
1043 tab_pane.setEnabledAt(export_pos, ready && Gatherer.config.get("workflow.export", false));
1044 }
1045 if(create_pos != -1) {
1046 tab_pane.setEnabledAt(create_pos, ready && Gatherer.config.get("workflow.create", false));
1047 }
1048// if(preview_pos != -1) {
1049// tab_pane.setEnabledAt(preview_pos, Gatherer.c_man != null && Gatherer.c_man.built() && Gatherer.config.get("workflow.preview", false));
1050// }
1051 }
1052 public void setReady(boolean ready) {
1053 this.ready = ready;
1054 }
1055 }
1056
1057 private class WorkflowUpdater
1058 implements Runnable {
1059 private boolean state;
1060 private String raw;
1061 public WorkflowUpdater(String raw, boolean state) {
1062 this.raw = raw;
1063 this.state = state;
1064 }
1065 public void run() {
1066 setTabEnabled(raw, state);
1067 }
1068 }
1069}
1070
1071
Note: See TracBrowser for help on using the repository browser.