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

Last change on this file since 5659 was 5659, checked in by jmt12, 21 years ago

Fire a loseFocus event to config pane when view changed

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