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

Last change on this file since 4681 was 4681, checked in by kjdon, 21 years ago

now goes back to the Gather pane if a new collection was loaded successfully

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