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

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

Fixed tabbing.

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