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

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

Many more tooltips and improvements to the Dictionary. Still more to come.

  • Property svn:keywords set to Author Date Id Revision
File size: 36.9 KB
Line 
1package org.greenstone.gatherer.gui;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import java.awt.*;
39import java.awt.datatransfer.*;
40import java.awt.event.*;
41import java.io.*;
42import java.lang.*;
43import java.net.*;
44import java.util.*;
45import javax.swing.*;
46import javax.swing.event.*;
47import javax.swing.plaf.*;
48import javax.swing.text.*;
49import org.greenstone.gatherer.Configuration;
50import org.greenstone.gatherer.Dictionary;
51import org.greenstone.gatherer.Gatherer;
52import org.greenstone.gatherer.collection.Collection;
53import org.greenstone.gatherer.collection.DeleteCollectionPrompt;
54import org.greenstone.gatherer.collection.LoadCollectionBox;
55import org.greenstone.gatherer.collection.SaveCollectionBox;
56import org.greenstone.gatherer.file.FileNode;
57import org.greenstone.gatherer.file.FileOpenActionListener;
58import org.greenstone.gatherer.gui.AboutDialog;
59import org.greenstone.gatherer.gui.BrowsingPane;
60import org.greenstone.gatherer.gui.CollectionPane;
61import org.greenstone.gatherer.gui.CreatePane;
62import org.greenstone.gatherer.gui.Filter;
63import org.greenstone.gatherer.gui.GConfigPane;
64import org.greenstone.gatherer.gui.MenuBar;
65import org.greenstone.gatherer.gui.MetaEditPane;
66import org.greenstone.gatherer.gui.MirrorPane;
67import org.greenstone.gatherer.gui.OpenCollectionDialog;
68import org.greenstone.gatherer.gui.OptionsBox;
69import org.greenstone.gatherer.gui.Preferences;
70import org.greenstone.gatherer.gui.PreviewPane;
71import org.greenstone.gatherer.gui.SimpleOpenCollectionDialog;
72import org.greenstone.gatherer.gui.messages.MessagePane;
73import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
74import org.greenstone.gatherer.gui.tree.DragTree;
75import org.greenstone.gatherer.help.HelpFrame;
76import org.greenstone.gatherer.msm.ElementWrapper;
77import org.greenstone.gatherer.msm.Metadata;
78// import org.greenstone.gatherer.sarm.SearchAndReplace;
79import org.greenstone.gatherer.shell.GShell;
80import org.greenstone.gatherer.util.TreeSynchronizer;
81import org.greenstone.gatherer.util.Utility;
82import org.greenstone.gatherer.valuetree.GValueNode;
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 /** The message pane is optional and contains the log of messages sent. */
103 public MessagePane message_pane = null;
104
105 public MetaAuditFrame meta_audit;
106 /** The metaedit pane is used to assign, edit and remove metadata from files within the collection. */
107 public MetaEditPane metaedit_pane = null;
108 /** The mirror pane contains controls for mirroring internet sites. */
109 public MirrorPane mirror_pane = null;
110 /** The preview pane contains a preview of your build collection. */
111 public PreviewPane preview_pane = null;
112 /** Are certain panes currently locked? */
113 private boolean locked = false;
114 /** The size of the Gatherer window. */
115 private Dimension size = null;
116 /** The filters used to dynamically filter the trees at user request. */
117 private HashMap filters = new HashMap();
118 /** The panel within the window that other components are placed on. */
119 private JPanel content_pane = null;
120 /** The dummy export pane. */
121 private JPanel export_pane = new JPanel();
122 /** The last view pane selected. */
123 private JPanel previous_pane;
124 /** The main tab pane containing the different views, available here to trap view change events. */
125 private JTabbedPane tab_pane = null;
126 /** A reference to any existing search and replace module/dialog. */
127 // private SearchAndReplace sar = null;
128 /** A threaded tab changer to try and avoid NPE on exit. */
129 private TabUpdater tab_updater = null;
130 /** 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.
131 * @see org.greenstone.gatherer.Dictionary
132 */
133 private ThreadGroup thread_group = null;
134 /** Ensures that expansion events between like collection trees are synchronized. */
135 private TreeSynchronizer collection_tree_sync = null;
136 /** Ensures that expansion events between like workspace trees are synchronized. */
137 private TreeSynchronizer workspace_tree_sync = null;
138 /**Constructor. Enable window events and arranges all other components.
139 * @param size The intial <strong>Dimension</strong> of the screen.
140 * @param graphic The default <strong>GraphicsConfiguration</strong> for this platform.
141 */
142 public GUIManager(Dimension size) {
143 super();
144 // Initialization
145 this.help = new HelpFrame();
146 this.size = size;
147 this.collection_tree_sync = new TreeSynchronizer();
148 this.meta_audit = new MetaAuditFrame(collection_tree_sync, null);
149 this.workspace_tree_sync = new TreeSynchronizer();
150 // Make the Tool tip hang around for a rediculous amount of time.
151 ToolTipManager.sharedInstance().setDismissDelay(10000);
152 // 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.
153 Thread bob = new Thread();
154 thread_group = bob.getThreadGroup();
155 // Set up some other UI stuff. (fonts handled in Gatherer.main())
156 UIManager.put("FileChooser.lookInLabelText", Gatherer.dictionary.get("SaveCollectionBox.Look_In"));
157 UIManager.put("FileChooser.filesOfTypeLabelText", Gatherer.dictionary.get("SaveCollectionBox.Files_Of_Type"));
158 UIManager.put("FileChooser.fileNameLabelText", Gatherer.dictionary.get("SaveCollectionBox.File_Name"));
159 }
160 /** 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.
161 * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
162 */
163 public void actionPerformed(ActionEvent event) {
164 boolean cont = true;
165 Object esrc = event.getSource();
166 // *************
167 // File Options.
168 // *************
169 if(esrc == menu_bar.file_associations) {
170 Gatherer.assoc_man.edit();
171 }
172 else if(esrc == menu_bar.file_close) {
173 // if(!Gatherer.c_man.saved()) {
174 cont = showSaveCollectionBox(true, false);
175 // }
176 if(cont) {
177 tab_pane.setSelectedComponent(collection_pane);
178 }
179 }
180 else if(esrc == menu_bar.file_delete) {
181 DeleteCollectionPrompt dcp = new DeleteCollectionPrompt();
182 if(dcp.display()) {
183 Gatherer.c_man.closeCollection();
184 }
185 dcp.destroy();
186 dcp = null;
187 System.gc();
188 }
189 else if(esrc == menu_bar.file_exit) {
190 menu_bar.exit();
191 exit();
192 }
193 else if(esrc == menu_bar.file_new) {
194 showNewCollectionPrompt();
195 }
196 else if(esrc == menu_bar.file_open) {
197 if (showLoadCollectionBox()) {
198 tab_pane.setSelectedComponent(collection_pane);
199 }
200 }
201 else if(esrc == menu_bar.file_options) {
202 new Preferences();
203 }
204 else if(esrc == menu_bar.file_save) {
205 Gatherer.c_man.saveCollection(false, false);
206 }
207 else if(esrc == menu_bar.file_save_as) {
208 String name = JOptionPane.showInputDialog(this, "Enter new collection filename.");
209 if(name != null) {
210 Gatherer.c_man.saveCollectionAs(name);
211 }
212 }
213 // *************
214 // Edit Options.
215 // *************
216 else if(esrc == menu_bar.edit_copy) {
217 try {
218 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
219 // Get the component with selected text as a JTextComponent
220 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
221 text.copy();
222 }
223 catch (Exception cce) {
224 // If the component is not a text component ignore the copy command
225 Gatherer.println(cce.toString());
226 }
227 }
228 else if(esrc == menu_bar.edit_cut) {
229 try {
230 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
231 // Get the component with selected text as a JTextComponent
232 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
233 // Cut the text to the clipboard
234 text.cut();
235 }
236 catch (ClassCastException cce) {
237 // If the component is not a text component ignore the cut command
238 Gatherer.println(cce.toString());
239 }
240 }
241 else if(esrc == menu_bar.edit_paste) {
242 try {
243 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
244 // Get the component with selected text as a JTextComponent
245 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
246 // Cut the text to the clipboard
247 text.paste();
248 }
249 catch (ClassCastException cce) {
250 // If the component is not a text component ignore the paste command
251 Gatherer.println(cce.toString());
252 }
253 }
254// else if(esrc == menu_bar.edit_search) {
255// if(sar != null) {
256// sar.dispose();
257// }
258// sar = new SearchAndReplace(false);
259// }
260// else if(esrc == menu_bar.edit_replace) {
261// if(sar != null) {
262// sar.dispose();
263// }
264// sar = new SearchAndReplace(true);
265// }
266 // *************
267 // Tools Options.
268 // *************
269 else if(esrc == menu_bar.tools_size) {
270 FileNode records[] = metaedit_pane.getSelectedNode();
271 if(records != null && records.length > 0) {
272 ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getMetadata(records[0].getFile());
273 if(metadatum.size() >= 4) {
274 Metadata metadata = (Metadata) metadatum.get(0);
275 ElementWrapper ew = metadata.getElement();
276
277 int SIZE = 5000;
278 Object[] array = new Object[SIZE];
279 Runtime.getRuntime().gc();
280 long start = Runtime.getRuntime().freeMemory();
281 for (int i = 0; i < SIZE; i++) {
282 array[i] = ew.copy();
283 }
284 Runtime.getRuntime().gc();
285 long end = Runtime.getRuntime().freeMemory();
286 long difference = (( start - end ) / SIZE);
287 ///ystem.out.println(difference + " bytes used." );
288 }
289 }
290 }
291 // *************
292 // Help Options.
293 // *************
294 else if(esrc == menu_bar.help_about) {
295 new AboutDialog(this);
296 }
297 else if(esrc == menu_bar.help_browse) {
298 help.setView("huntingforfiles");
299 }
300 else if(esrc == menu_bar.help_build) {
301 help.setView("producingthecollection");
302 }
303 else if(esrc == menu_bar.help_collect) {
304 help.setView("collectingfiles");
305 }
306 else if(esrc == menu_bar.help_design) {
307 help.setView("designingacollection");
308 }
309 else if(esrc == menu_bar.help_general) {
310 help.setView("introduction");
311 }
312 else if(esrc == menu_bar.help_metaedit) {
313 help.setView("enrichingacollection");
314 }
315 else if(esrc == menu_bar.help_mirror) {
316 help.setView("downloadingfiles");
317 }
318 else if(esrc == menu_bar.help_preview) {
319 help.setView("previewingthecollection");
320 }
321 // *****************
322 // Metadata Options.
323 // *****************
324 else if(esrc == menu_bar.metadata_add) {
325 Gatherer.c_man.getCollection().msm.importMDS();
326 }
327 else if(esrc == menu_bar.metadata_edit) {
328 showEditMetadataBox();
329 }
330 else if(esrc == menu_bar.metadata_export) {
331 Gatherer.c_man.getCollection().msm.exportMDS();
332 }
333 else if(esrc == menu_bar.metadata_view) {
334 showMetaAuditBox();
335 }
336 else if(esrc == menu_bar.tools_log) {
337 showLogBox();
338 }
339 }
340 /** 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.
341 */
342 public void afterDisplay() {
343 if(Gatherer.config.get("workflow.mirror", true)) {
344 browser_pane.afterDisplay();
345 }
346 metaedit_pane.afterDisplay();
347 }
348 /** 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.
349 * @param ready <i>true</i> if the collection is ready for editing, <i>false</i> otherwise.
350 */
351 public void collectionChanged(final boolean ready) {
352 if(Gatherer.config.get("workflow.mirror", true)) {
353 mirror_pane.collectionChanged(ready);
354 }
355 menu_bar.collectionChanged(ready); // Inform the menu bar that the collections changed.
356 collection_pane.collectionChanged(ready); // Used to update the collection workspace.
357 metaedit_pane.collectionChanged(ready); // Very important that metaedit pane shows current collection and is listening to latest msm.
358 config_pane.collectionChanged(ready); // Also important config pane is listening to latest msm.
359 create_pane.collectionChanged(ready); // Used to indicate a new BuildOptions model should be loaded.
360 preview_pane.collectionChanged(ready); // preview should know when teh coll has changed so it can reload the home page
361 // Force tree model updates.
362 Gatherer.c_man.refreshTrees();
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 + ": " + 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 + ": " + 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 browser_pane = new BrowsingPane();
416 if(Gatherer.config.get("workflow.browse", true)) {
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 mirror_pane = new MirrorPane();
422 if(Gatherer.config.get("workflow.mirror", true)) {
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 help.destroy();
497 help = null;
498 Gatherer.self.exit();
499 }
500 }
501 /** Retrieve the filter, or if one already exists, spawn a linked copy. */
502 public Filter getFilter(DragTree tree) {
503 Filter filter = (Filter) filters.get(tree.getModel());
504 if (filter == null) {
505 filter = new Filter(tree, null);
506 filters.put(tree.getModel(), filter);
507 return filter;
508 }
509 return filter.spawn(tree);
510 }
511
512 public Component getSelectedView() {
513 return tab_pane.getSelectedComponent();
514 }
515 /** 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.
516 */
517 public void lockCollection(boolean import_stage, boolean lock) {
518 locked = lock;
519 if(import_stage) {
520 int collection_pos = tab_pane.indexOfComponent(collection_pane);
521 int metaedit_pos = tab_pane.indexOfComponent(metaedit_pane);
522 int config_pos = tab_pane.indexOfComponent(config_pane);
523 tab_pane.setEnabledAt(collection_pos, !lock);
524 tab_pane.setEnabledAt(metaedit_pos, !lock);
525 tab_pane.setEnabledAt(config_pos, !lock);
526 }
527 else {
528 int config_pos = tab_pane.indexOfComponent(config_pane);
529 tab_pane.setEnabledAt(config_pos, !lock);
530 }
531 }
532
533 public void refreshTrees() {
534 collection_pane.refreshTrees();
535 //metaedit_pane.refreshTrees();
536 }
537
538 /** Allows the system to programatically set the selected tab.
539 * @param component The view you wish to make visable in the tab pane as a <strong>Component</strong>.
540 */
541 public void setSelectedView(Component component) {
542 tab_pane.setSelectedComponent(component);
543 }
544
545 /** Specifies whether a certain tab is enabled or not. */
546 public void setTabEnabled(String rawname, boolean state) {
547 // Retrieve the dictionary based name.
548 String name = get(rawname);
549 int index = tab_pane.indexOfTab(name);
550 // Of course we may not have this tab available.
551 if(index != -1) {
552 // Some tabs are also dependant on if a collection is ready
553 Component component = tab_pane.getComponentAt(index);
554 if(component == preview_pane) {
555 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.built());
556 }
557 else if(component == metaedit_pane || component == config_pane || component == export_pane || component == create_pane) {
558 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
559 }
560 else {
561 tab_pane.setEnabledAt(index, state);
562 }
563 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
564 if(tab_pane.getSelectedIndex() == index && !state) {
565 boolean found = false;
566 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
567 if(tab_pane.isEnabledAt(i)) {
568 tab_pane.setSelectedIndex(i);
569 found = true;
570 }
571 }
572 // If there are no tabs enabled, which should be impossible, then select the first tab
573 if(!found) {
574 tab_pane.setSelectedIndex(0);
575 }
576 }
577 }
578 // If the rawname was mirror then rebuild workspace tree to remove caches.
579 if(rawname.equals("Mirroring")) {
580 collection_pane.refreshWorkspace();
581 }
582 }
583
584 /** 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.
585 */
586 public void showEditMetadataBox() {
587 if(Gatherer.c_man.getCollection() != null) {
588 Gatherer.c_man.getCollection().msm.editMDS();
589 }
590 }
591 /** When the load collection option is choosen this method is called to produce the modal file load prompt.
592 */
593 public boolean showLoadCollectionBox() {
594 boolean result = false;
595 // We first try the simple open collection dialog
596 SimpleOpenCollectionDialog dialog = new SimpleOpenCollectionDialog();
597 int user_choice = dialog.display();
598 String filename = null;
599 // The user may choose to go to the advanced 'browse' dialog
600 if(user_choice == SimpleOpenCollectionDialog.OK_OPTION) {
601 filename = dialog.getFileName();
602 }
603 else if(user_choice == SimpleOpenCollectionDialog.BROWSE_OPTION) {
604 File file;
605 if(Gatherer.config.gsdl_path != null) {
606 file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
607 }
608 else {
609 file = new File(Utility.BASE_DIR);
610 }
611 OpenCollectionDialog chooser = new OpenCollectionDialog(file);
612 file = null;
613 filename = chooser.getFileName();
614 chooser.destroy();
615 chooser = null;
616 }
617 dialog.destroy();
618 dialog = null;
619 // User can cancel action.
620 if(filename != null) {
621 // If there is already a collection open, save and close it.
622 if(Gatherer.c_man.ready()) {
623 showSaveCollectionBox(true, false);
624 // Wait until it is closed.
625 try {
626 synchronized(this) {
627 while(Gatherer.c_man.reallyReady()) {
628 wait(10);
629 }
630 }
631 }
632 catch(Exception error) {
633 Gatherer.println("Exception: " + error);
634 Gatherer.printStackTrace(error);
635 }
636 }
637 result = Gatherer.c_man.loadCollection(filename);
638 filename = null;
639 }
640 return result;
641 }
642 /** When called this method causes the Log class in Gatherer to display a nice dialog box which contains the log.
643 */
644 public void showLogBox() {
645 Gatherer.log.display();
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 /** This method is used to open the options box on the screen.
723 */
724 public void showOptionsBox() {
725 new OptionsBox();
726 }
727 /** This method is used to open the save collection box/prompt on the screen.
728 * @return A <i>boolean</i> which is <i>true</i> if the collection was saved successfully, <i>false</i> otherwise.
729 */
730 public boolean showSaveCollectionBox(boolean close_after, boolean exit_after) {
731 //SaveCollectionBox save_collection_box = new SaveCollectionBox();
732 //Rectangle bounds = save_collection_box.getBounds();
733 //int result = save_collection_box.getUserOption(Gatherer.c_man.getCollection().getName());
734 //switch(result) {
735 //case SaveCollectionBox.SAVE_YES:
736 Gatherer.c_man.saveCollection(close_after, exit_after);
737 // Wait until it is closed.
738 try {
739 synchronized(this) {
740 while(Gatherer.c_man.reallyReady()) {
741 wait(10);
742 }
743 }
744 }
745 catch(Exception error) {
746 Gatherer.println("Exception: " + error);
747 Gatherer.printStackTrace(error);
748 }
749
750 //content_pane.paintImmediately(bounds);
751 return true;
752 //case SaveCollectionBox.SAVE_NO:
753 // Close collection.
754 // if(close_after) {
755 // tab_pane.setSelectedComponent(collection_pane);
756 // Gatherer.c_man.closeCollection();
757 // }
758 // if(exit_after) {
759 // Gatherer.self.exit();
760 // }
761 // return true;
762 //default:
763 // return false;
764 //}
765 }
766 /** 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.
767 * @param event A ChangeEvent containing information about the event that fired this call.
768 */
769 public void stateChanged(ChangeEvent event) {
770 if(previous_pane != null) {
771 if(previous_pane == create_pane) {
772 create_pane.loseFocus();
773 }
774 }
775 // "View assigned metadata" menu item is disabled by default
776 menu_bar.metadata_view.setCanEnable(false);
777 menu_bar.setMetaAuditSuffix(null);
778
779 menu_bar.tabSelected(tab_pane.getSelectedIndex());
780 if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(collection_pane)) {
781 collection_pane.gainFocus();
782 // "View assigned metadata" menu item is enabled for the "Gather" pane
783 menu_bar.metadata_view.setCanEnable(true);
784 }
785 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(metaedit_pane)) {
786 metaedit_pane.gainFocus();
787 // "View assigned metadata" menu item is enabled for the "Enrich" pane
788 menu_bar.metadata_view.setCanEnable(true);
789 }
790 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(config_pane)) {
791 config_pane.gainFocus();
792 }
793 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(create_pane)) {
794 create_pane.gainFocus();
795 }
796 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(preview_pane)) {
797 config_pane.saveConfiguration();
798 preview_pane.gainFocus();
799 }
800
801 previous_pane = (JPanel) tab_pane.getSelectedComponent();
802 }
803
804 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
805
806 public void wait(boolean waiting) {
807 Component glass_pane = getGlassPane();
808 if(waiting) {
809 // Show wait cursor.
810 glass_pane.addMouseListener(mouse_blocker_listener);
811 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
812 glass_pane.setVisible(true);
813 }
814 else {
815 // Hide wait cursor.
816 glass_pane.setVisible(false);
817 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
818 glass_pane.removeMouseListener(mouse_blocker_listener);
819 }
820 glass_pane = null;
821 }
822
823 public void workflowUpdate(String raw, boolean state) {
824 WorkflowUpdater task = new WorkflowUpdater(raw, state);
825 SwingUtilities.invokeLater(task);
826 task = null;
827 }
828
829 /** Retrieves a phrase from the Dictionary based on the key.
830 * @param key A <strong>String</strong> uniquely identifying a phrase from the Dictionary.
831 * @return The desired phrase as a <strong>String</strong>.
832 * @see org.greenstone.gatherer.Dictionary
833 */
834 private String get(String key) {
835 return get(key, null);
836 }
837 /** Retrieves a phrase from the Dictionary based on the key and including the arguments.
838 * @param key A <strong>String</strong> uniquely identifying a phrase from the Dictionary.
839 * @param args A <strong>String[]</strong> of arguments available to be inserted into the phrase.
840 * @return The desired phrase as a <strong>String</strong>.
841 * @see org.greenstone.gatherer.Dictionary
842 */
843 private String get(String key, String args[]) {
844 if(key.indexOf('.') == -1) {
845 key = "GUI." + key;
846 }
847 return Gatherer.dictionary.get(key, args);
848 }
849 /** 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.
850 * @return <i>true</i> if we should wait for a thread, <i>false</i> if it is safe to continue.
851 */
852 private boolean waitForThread() {
853 Thread active[] = new Thread[thread_group.activeCount()];
854 int size = thread_group.enumerate(active);
855 for(int i = 0; i < size; i++) {
856 if(active[i].getName().equals(GShell.GSHELL_BUILD) ||
857 active[i].getName().equals(GShell.GSHELL_IMPORT) ||
858 active[i].getName().equals(GShell.GSHELL_NEW)) {
859 return true;
860 }
861 }
862 return false;
863 }
864
865
866 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
867 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
868 */
869 protected void processWindowEvent(WindowEvent event) {
870 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
871 exit();
872 }
873 }
874 /** 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.
875 */
876 private class MenuListenerImpl
877 implements MenuListener {
878 /** Called whenever a popup menu is hidden, but we don't care.
879 * @param e Some <strong>MenuEvent</strong> that we could care less about.
880 */
881 public void menuCanceled(MenuEvent e) {
882 }
883 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
884 * @param e Some <strong>MenuEvent</strong> that we could care less about.
885 */
886 public void menuDeselected(MenuEvent e) {
887 }
888 /** 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.
889 * @param e The <strong>MenuEvent</strong> whose source is checked.
890 */
891 public void menuSelected(MenuEvent e) {
892 if(e.getSource() == menu_bar.help) {
893 if(menu_bar.help.isSelected()) {
894 menu_bar.help.doClick(10);
895 }
896 }
897 }
898 }
899 private class TabUpdater
900 implements Runnable {
901 private boolean ready = false;
902 private int browse_pos = -1;
903 private int mirror_pos = -1;
904 private int config_pos = -1;
905 private int create_pos = -1;
906 private int export_pos = -1;
907 private int metaedit_pos = -1;
908 private int preview_pos = -1;
909 private JTabbedPane tab_pane = null;
910 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
911 this.ready = ready;
912 this.tab_pane = tab_pane;
913 browse_pos = tab_pane.indexOfComponent(browser_pane);
914 mirror_pos = tab_pane.indexOfComponent(mirror_pane);
915 metaedit_pos = tab_pane.indexOfComponent(metaedit_pane);
916 config_pos = tab_pane.indexOfComponent(config_pane);
917 export_pos = tab_pane.indexOfComponent(export_pane);
918 create_pos = tab_pane.indexOfComponent(create_pane);
919 preview_pos = tab_pane.indexOfComponent(preview_pane);
920 }
921 public void run() {
922 if(browse_pos != -1) {
923 if(ready) {
924 tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", false));
925 }
926 else {
927 tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", true));
928 }
929 }
930 if(mirror_pos != -1) {
931 if(ready) {
932 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", false));
933 }
934 else {
935 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", true));
936 }
937 }
938 if(metaedit_pos != -1) {
939 tab_pane.setEnabledAt(metaedit_pos, ready && Gatherer.config.get("workflow.enrich", false));
940 }
941 if(config_pos != -1) {
942 tab_pane.setEnabledAt(config_pos, ready && Gatherer.config.get("workflow.design", false));
943 }
944 if(export_pos != -1) {
945 tab_pane.setEnabledAt(export_pos, ready && Gatherer.config.get("workflow.export", false));
946 }
947 if(create_pos != -1) {
948 tab_pane.setEnabledAt(create_pos, ready && Gatherer.config.get("workflow.create", false));
949 }
950 if(preview_pos != -1) {
951 tab_pane.setEnabledAt(preview_pos, Gatherer.c_man != null && Gatherer.c_man.built() && Gatherer.config.get("workflow.preview", false));
952 }
953 }
954 public void setReady(boolean ready) {
955 this.ready = ready;
956 }
957 }
958
959 private class WorkflowUpdater
960 implements Runnable {
961 private boolean state;
962 private String raw;
963 public WorkflowUpdater(String raw, boolean state) {
964 this.raw = raw;
965 this.state = state;
966 }
967 public void run() {
968 setTabEnabled(raw, state);
969 }
970 }
971}
Note: See TracBrowser for help on using the repository browser.