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

Last change on this file since 7500 was 7500, checked in by mdewsnip, 20 years ago

Removed stuff about the defunct Browse and Preview panes.

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