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

Last change on this file since 5571 was 5571, checked in by mdewsnip, 21 years ago

More small updates and tooltips added.

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