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

Last change on this file since 6582 was 6582, checked in by jmt12, 20 years ago

A whole bunch of files right in the middle of being edited because Michael is being awkward and expecting me to commit stuff regular like.

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