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

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

Changed how a collection name appears. It now displays the collection title, followed by the shorter filename in curved brackets. Also added methods for changing the frame title from outside g_man

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