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

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

It does cause serious problems, so I'm changing it back

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