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

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

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