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

Last change on this file since 4371 was 4371, checked in by jmt12, 21 years ago

Modified so that an open collection isn't closed if a user selects File->Open then decides to cancel - John

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