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

Last change on this file since 8231 was 8231, checked in by mdewsnip, 20 years ago

Replaced all "Gatherer.config" with "Configuration".

  • Property svn:keywords set to Author Date Id Revision
File size: 37.6 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui;
38
39import java.awt.*;
40import java.awt.datatransfer.*;
41import java.awt.event.*;
42import java.io.File;
43import java.lang.*;
44import java.net.*;
45import java.util.*;
46import javax.swing.*;
47import javax.swing.event.*;
48import javax.swing.filechooser.*;
49import javax.swing.plaf.*;
50import javax.swing.text.*;
51import org.greenstone.gatherer.Configuration;
52import org.greenstone.gatherer.Dictionary;
53import org.greenstone.gatherer.Gatherer;
54import org.greenstone.gatherer.collection.Collection;
55import org.greenstone.gatherer.collection.DeleteCollectionPrompt;
56import org.greenstone.gatherer.collection.ExportCollectionPrompt;
57import org.greenstone.gatherer.collection.SaveCollectionBox;
58import org.greenstone.gatherer.file.FileNode;
59import org.greenstone.gatherer.file.FileOpenActionListener;
60import org.greenstone.gatherer.gui.AboutDialog;
61import org.greenstone.gatherer.gui.GatherPane;
62import org.greenstone.gatherer.gui.CreatePane;
63import org.greenstone.gatherer.gui.Filter;
64import org.greenstone.gatherer.gui.DesignPane;
65import org.greenstone.gatherer.gui.MenuBar;
66import org.greenstone.gatherer.gui.EnrichPane;
67import org.greenstone.gatherer.gui.MirrorPane;
68import org.greenstone.gatherer.gui.OpenCollectionDialog;
69import org.greenstone.gatherer.gui.Preferences;
70import org.greenstone.gatherer.gui.SimpleOpenCollectionDialog;
71import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
72import org.greenstone.gatherer.gui.tree.DragTree;
73import org.greenstone.gatherer.gui.tree.WorkspaceTree;
74import org.greenstone.gatherer.help.HelpFrame;
75import org.greenstone.gatherer.mem.MetadataEditorManager;
76import org.greenstone.gatherer.shell.GShell;
77import org.greenstone.gatherer.util.StaticStrings;
78import org.greenstone.gatherer.util.TreeSynchronizer;
79import org.greenstone.gatherer.util.Utility;
80
81/** 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. */
82public class GUIManager
83 extends JFrame
84 implements ActionListener, ChangeListener {
85 /** The mirror pane contains controls for mirroring internet sites. */
86 public MirrorPane mirror_pane = null;
87 /** The gather pane is more like a file manager where you drag files from one tree to another. */
88 private GatherPane gather_pane = null;
89 /** The enrich pane is used to assign, edit and remove metadata from files within the collection. */
90 public EnrichPane enrich_pane = null;
91 /** The design pane allows you to edit the design of the library in terms of the collection configuration file. */
92 public DesignPane design_pane = null;
93 /** The create pane contains scripting options for importing and building collections into libraries. */
94 public CreatePane create_pane = null;
95
96 public FileOpenActionListener foa_listener = new FileOpenActionListener();
97
98 /** A reference to the currently instantiated help window, if any. */
99 public HelpFrame help = null;
100 /** The menu bar. */
101 public MenuBar menu_bar = null;
102 public MetaAuditFrame meta_audit;
103 /** Are certain panes currently locked? */
104 private boolean locked = false;
105 /** The size of the Gatherer window. */
106 private Dimension size = null;
107 /** The filters used to dynamically filter the trees at user request. */
108 private HashMap filters = new HashMap();
109 /** The panel within the window that other components are placed on. */
110 private JPanel content_pane = null;
111 /** The dummy export pane. */
112 private JPanel export_pane = new JPanel();
113 /** The last view pane selected. */
114 private JPanel previous_pane;
115 /** The main tab pane containing the different views, available here to trap view change events. */
116 private JTabbedPane tab_pane = null;
117 /** A threaded tab changer to try and avoid NPE on exit. */
118 private TabUpdater tab_updater = null;
119 /** 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.
120 * @see org.greenstone.gatherer.Dictionary
121 */
122 private ThreadGroup thread_group = null;
123 /** Ensures that expansion events between like collection trees are synchronized. */
124 private TreeSynchronizer collection_tree_sync = null;
125 /** Ensures that expansion events between like workspace trees are synchronized. */
126 private TreeSynchronizer workspace_tree_sync = null;
127 /**Constructor. Enable window events and arranges all other components.
128 * @param size The intial <strong>Dimension</strong> of the screen.
129 */
130 public GUIManager(Dimension size) {
131 super();
132 // Initialization
133 this.help = new HelpFrame();
134 this.size = size;
135 this.collection_tree_sync = new TreeSynchronizer();
136 this.meta_audit = new MetaAuditFrame(collection_tree_sync, null);
137 this.workspace_tree_sync = new TreeSynchronizer();
138
139 this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
140
141 // Add a focus listener to ourselves. Thus if we gain focus when a Modal Dialog should instead have it, we can try to bring the modal dialog to the fore.
142 this.addFocusListener(new GLIGUIFocusListener());
143
144 // Make the Tool tip hang around for a rediculous amount of time.
145 ToolTipManager.sharedInstance().setDismissDelay(10000);
146 // 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.
147 Thread bob = new Thread();
148 thread_group = bob.getThreadGroup();
149 // Set up some other UI stuff. (fonts handled in Gatherer.main())
150 UIManager.put("FileChooser.lookInLabelText", Dictionary.get("SaveCollectionBox.Look_In"));
151 UIManager.put("FileChooser.filesOfTypeLabelText", Dictionary.get("SaveCollectionBox.Files_Of_Type"));
152 UIManager.put("FileChooser.fileNameLabelText", Dictionary.get("SaveCollectionBox.File_Name"));
153 }
154
155 private class GLIGUIFocusListener
156 extends FocusAdapter {
157 public void focusGained(FocusEvent e) {
158 if(Gatherer.current_modal != null) {
159 Gatherer.current_modal.makeVisible();
160 Gatherer.current_modal.toFront();
161 }
162 }
163 }
164
165 /** 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.
166 * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
167 */
168 public void actionPerformed(ActionEvent event) {
169 Object esrc = event.getSource();
170 // *************
171 // File Options.
172 // *************
173 if(esrc == menu_bar.file_associations) {
174 Gatherer.assoc_man.edit();
175 }
176 else if(esrc == menu_bar.file_close) {
177 boolean cont = showSaveCollectionBox(true, false);
178 if(cont) {
179 tab_pane.setSelectedComponent(gather_pane);
180 }
181 }
182 else if(esrc == menu_bar.file_delete) {
183 DeleteCollectionPrompt dcp = new DeleteCollectionPrompt();
184 if(dcp.display()) {
185 Gatherer.c_man.closeCollection();
186 }
187 dcp.destroy();
188 dcp = null;
189 System.gc();
190 }
191 else if(esrc == menu_bar.file_export) {
192 ExportCollectionPrompt ecp = new ExportCollectionPrompt();
193 ecp.display();
194 ecp.destroy();
195 ecp = null;
196 }
197 else if(esrc == menu_bar.file_exit) {
198 System.err.println("*** menu bar file exit called");
199 exit();
200 }
201 else if(esrc == menu_bar.file_new) {
202 showNewCollectionPrompt();
203 }
204 else if(esrc == menu_bar.file_open) {
205 if (showLoadCollectionBox()) {
206 tab_pane.setSelectedComponent(gather_pane);
207 }
208 }
209 else if(esrc == menu_bar.file_options) {
210 // Just incase the user has edited the GeneralSettings of a collection without losing focus afterwards. Well I'm forever losing foc... ooh shiney.
211 design_pane.loseFocus();
212 // And spawn a new preferences.
213 new Preferences();
214 }
215 else if(esrc == menu_bar.file_save) {
216 Gatherer.c_man.saveCollection(false, false);
217 }
218
219 // *************
220 // Edit Options.
221 // *************
222 else if(esrc == menu_bar.edit_copy) {
223 try {
224 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
225 // Get the component with selected text as a JTextComponent
226 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
227 text.copy();
228 }
229 catch (Exception cce) {
230 // If the component is not a text component ignore the copy command
231 Gatherer.println(cce.toString());
232 }
233 }
234 else if(esrc == menu_bar.edit_cut) {
235 try {
236 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
237 // Get the component with selected text as a JTextComponent
238 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
239 // Cut the text to the clipboard
240 text.cut();
241 }
242 catch (ClassCastException cce) {
243 // If the component is not a text component ignore the cut command
244 Gatherer.println(cce.toString());
245 }
246 }
247 else if(esrc == menu_bar.edit_paste) {
248 try {
249 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
250 // Get the component with selected text as a JTextComponent
251 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
252 // Cut the text to the clipboard
253 text.paste();
254 }
255 catch (ClassCastException cce) {
256 // If the component is not a text component ignore the paste command
257 Gatherer.println(cce.toString());
258 }
259 }
260
261 // *****************
262 // Metadata Options.
263 // *****************
264 else if (esrc == menu_bar.metadata_import) {
265 JFileChooser chooser = new JFileChooser(new File(Utility.METADATA_DIR));
266 MDSFileFilter filter = new MDSFileFilter();
267 chooser.setFileFilter(filter);
268 int returnVal = chooser.showDialog(Gatherer.g_man, Dictionary.get("MSMPrompt.File_Import"));
269 if (returnVal == JFileChooser.APPROVE_OPTION) {
270 Gatherer.c_man.getCollection().msm.importMDS(chooser.getSelectedFile(), true);
271 }
272 }
273 else if(esrc == menu_bar.metadata_edit) {
274 showEditMetadataBox();
275 }
276 else if(esrc == menu_bar.metadata_export) {
277 Gatherer.c_man.getCollection().msm.exportMDS();
278 }
279 else if(esrc == menu_bar.metadata_view) {
280 showMetaAuditBox();
281 }
282
283 // *************
284 // Help Options.
285 // *************
286 else if(esrc == menu_bar.help_about) {
287 new AboutDialog(this);
288 }
289 else if(esrc == menu_bar.help_build) {
290 help.setView("producingthecollection");
291 }
292 else if(esrc == menu_bar.help_collect) {
293 help.setView("collectingfiles");
294 }
295 else if(esrc == menu_bar.help_design) {
296 help.setView("designingacollection");
297 }
298 else if(esrc == menu_bar.help_general) {
299 help.setView("introduction");
300 }
301 else if(esrc == menu_bar.help_metaedit) {
302 help.setView("enrichingacollection");
303 }
304 else if(esrc == menu_bar.help_mirror) {
305 help.setView("downloadingfiles");
306 }
307 else if(esrc == menu_bar.help_preview) {
308 help.setView("previewingthecollection");
309 }
310 }
311
312 /** 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.
313 */
314 public void afterDisplay() {
315 if (mirror_pane != null) {
316 mirror_pane.afterDisplay();
317 }
318 enrich_pane.afterDisplay();
319 }
320 public void closeCurrentCollection() {
321
322 boolean cont = showSaveCollectionBox(true, false);
323
324 if(cont) {
325 tab_pane.setSelectedComponent(gather_pane);
326 }
327
328 }
329 /** 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.
330 * @param ready <i>true</i> if the collection is ready for editing, <i>false</i> otherwise.
331 */
332 public void collectionChanged(final boolean ready) {
333 if(Configuration.get("workflow.mirror", true)) {
334 mirror_pane.collectionChanged(ready);
335 }
336 menu_bar.collectionChanged(ready); // Inform the menu bar that the collections changed.
337 gather_pane.collectionChanged(ready); // Used to update the collection workspace.
338 enrich_pane.collectionChanged(ready); // Very important that metaedit pane shows current collection.
339 design_pane.collectionChanged(ready);
340 create_pane.collectionChanged(ready); // Used to indicate a new BuildOptions model should be loaded.
341
342 if(!locked) {
343 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
344 if(tab_updater == null) {
345 tab_updater = new TabUpdater(tab_pane, ready);
346 }
347 else {
348 tab_updater.setReady(ready);
349 }
350 SwingUtilities.invokeLater(tab_updater);
351 }
352 // Set the title
353 String collection_title = null;
354 String collection_name = null;
355 if (ready) {
356 Collection collection = Gatherer.c_man.getCollection();
357 collection_title = collection.getTitle();
358 collection_name = collection.getName();
359 collection = null;
360 }
361 setTitle(collection_title, collection_name);
362 collection_title = null;
363 collection_name = null;
364 // Now is a good time to force a garbage collect.
365 ///ystem.err.println("Calling garbage collection.");
366 System.gc();
367 }
368
369 public void destroy() {
370 // Destroying create pane ensures the latest log has been closed
371 if(create_pane != null) {
372 create_pane.destroy();
373 }
374 }
375
376 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
377 */
378 public void display() {
379 content_pane = (JPanel) this.getContentPane();
380 // Enable window-type events to be fired.
381 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
382 // Initialise and layout sub-components, plus other window dressing.
383 try {
384 this.setSize(size);
385
386 // Set the title
387 String collection_title = null;
388 String collection_name = null;
389 if (Gatherer.c_man.ready()) {
390 Collection collection = Gatherer.c_man.getCollection();
391 collection_title = collection.getTitle();
392 collection_name = collection.getName();
393 collection = null;
394 }
395 setTitle(collection_title, collection_name);
396 collection_title = null;
397 collection_name = null;
398
399 // Pretty corner icon
400 this.setIconImage(Utility.getImage("gatherer_small.gif").getImage());
401 // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
402 content_pane.setLayout(new BorderLayout());
403 // Create the menu-bar and stick it up the top.
404 menu_bar = new MenuBar(new MenuListenerImpl());
405
406 //feedback changes
407 //content_pane.add(menu_bar, BorderLayout.NORTH);
408 this.setJMenuBar(menu_bar);
409 // end feedback changes
410
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(Configuration.getFont("general.font", false));
416
417 if(Configuration.get(StaticStrings.WORKFLOW_MIRROR, true)) {
418 mirror_pane = new MirrorPane();
419 tab_pane.addTab("GUI.Mirror", Utility.getImage("mirroring.gif"), mirror_pane);
420 tab_pane.setEnabledAt(tab_pane.indexOfComponent(mirror_pane), Configuration.get(StaticStrings.WORKFLOW_MIRROR, false));
421 }
422
423 gather_pane = new GatherPane(workspace_tree_sync, collection_tree_sync);
424 gather_pane.display();
425 if(Configuration.get("workflow.gather", true)) {
426 tab_pane.addTab("GUI.Gather", Utility.getImage("collection.gif"), gather_pane);
427 tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Configuration.get("workflow.gather", false));
428 }
429
430 enrich_pane = new EnrichPane(collection_tree_sync);
431 enrich_pane.display();
432 if(Configuration.get("workflow.enrich", true)) {
433 tab_pane.addTab("GUI.Enrich", Utility.getImage("metaedit.gif"), enrich_pane);
434 tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
435 }
436
437 design_pane = new DesignPane();
438 design_pane.display();
439 if(Configuration.get("workflow.design", true)) {
440 tab_pane.addTab("GUI.Design", Utility.getImage("build.gif"), design_pane);
441 tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
442 }
443
444 if(Configuration.get("workflow.export", true)) {
445 tab_pane.addTab("GUI.Export", Utility.getImage("export.gif"), export_pane);
446 tab_pane.setEnabledAt(tab_pane.indexOfComponent(export_pane), false);
447 }
448
449 create_pane = new CreatePane();
450 create_pane.display();
451 if(Configuration.get("workflow.create", true)) {
452 tab_pane.addTab("GUI.Create", Utility.getImage("build session.gif"), create_pane);
453 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
454 }
455
456 // Select the collect pane if it is available
457 if(Configuration.get("workflow.gather", false)) {
458 tab_pane.setSelectedComponent(gather_pane);
459 }
460 // Otherwise find the first tab that is enabled and select that.
461 else {
462 boolean found = false;
463 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
464 if(tab_pane.isEnabledAt(i)) {
465 tab_pane.setSelectedIndex(i);
466 found = true;
467 }
468 }
469 }
470
471 Dictionary.register(tab_pane);
472 content_pane.add(tab_pane, BorderLayout.CENTER);
473 // Drive a sessionReady event to update all controls to reflect current collection status.
474 collectionChanged(Gatherer.c_man.ready());
475 }
476 catch (Exception e) {
477 Gatherer.printStackTrace(e);
478 // The GUI failing to build is an app killer
479 e.printStackTrace();
480 System.exit(1);
481 }
482 }
483 /** 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.
484 */
485 public void exit() {
486 // Tell everyone who cares that they are losing focus
487 System.err.println("**** GUIManager exit called!");
488
489 if(!Gatherer.c_man.ready() || design_pane.canSave()) {
490
491 if (Gatherer.isGsdlRemote) {
492 // consider saving???
493 System.err.println("**** Hiding GUI panel");
494 hide();
495 }
496 else {
497
498 boolean cont = true;
499 if(Gatherer.c_man.ready() && !Gatherer.c_man.saved()) {
500 System.err.println("***** c_man not saved");
501 cont = showSaveCollectionBox(false, true);
502 }
503 else {
504 // Deal to help
505 if(help != null) {
506 help.destroy();
507 help = null;
508 }
509 System.err.println("**** Calling Gatherer.self.exit");
510 Gatherer.self.exit();
511 }
512 }
513 }
514 }
515 /** Retrieve the filter, or if one already exists, spawn a linked copy. */
516 public Filter getFilter(DragTree tree) {
517 Filter filter = (Filter) filters.get(tree.getModel());
518 if (filter == null) {
519 filter = new Filter(tree, null);
520 filters.put(tree.getModel(), filter);
521 return filter;
522 }
523 return filter.spawn(tree);
524 }
525
526// public Component getSelectedView() {
527// return tab_pane.getSelectedComponent();
528// }
529 /** 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.
530 */
531 public void lockCollection(boolean import_stage, boolean lock) {
532 locked = lock;
533 if(import_stage) {
534 int collection_pos = tab_pane.indexOfComponent(gather_pane);
535 int metaedit_pos = tab_pane.indexOfComponent(enrich_pane);
536 int config_pos = tab_pane.indexOfComponent(design_pane);
537 tab_pane.setEnabledAt(collection_pos, !lock);
538 tab_pane.setEnabledAt(metaedit_pos, !lock);
539 tab_pane.setEnabledAt(config_pos, !lock);
540 }
541 else {
542 int config_pos = tab_pane.indexOfComponent(design_pane);
543 tab_pane.setEnabledAt(config_pos, !lock);
544 }
545 }
546
547 public void modeChanged(int mode) {
548 // Set the title
549 String collection_title = null;
550 String collection_name = null;
551 if (Gatherer.c_man.ready()) {
552 Collection collection = Gatherer.c_man.getCollection();
553 collection_title = collection.getTitle();
554 collection_name = collection.getName();
555 collection = null;
556 }
557 setTitle(collection_title, collection_name);
558 collection_title = null;
559 collection_name = null;
560 // Now pass on the message to anyone who cares
561 if(gather_pane != null) {
562 gather_pane.modeChanged(mode);
563 }
564 if(design_pane != null) {
565 design_pane.modeChanged(mode);
566 }
567 if(create_pane != null) {
568 create_pane.modeChanged(mode);
569 }
570 if(enrich_pane != null) {
571 enrich_pane.modeChanged(mode);
572 }
573 if (mirror_pane != null) {
574 mirror_pane.modeChanged(mode);
575 }
576 }
577
578
579 public void refreshCollectionTree(int refresh_reason)
580 {
581 if (gather_pane != null) {
582 gather_pane.refreshCollectionTree(refresh_reason);
583 }
584 }
585
586
587 public void refreshWorkspaceTree(int refresh_reason)
588 {
589 if (gather_pane != null) {
590 gather_pane.refreshWorkspaceTree(refresh_reason);
591 }
592 }
593
594
595 /** Returns to some "initial" pane (when no collection is loaded) */
596 public void returnToInitialPane()
597 {
598 if (gather_pane != null) {
599 tab_pane.setSelectedComponent(gather_pane);
600 }
601 }
602
603
604 /** Specifies whether a certain tab is enabled or not. */
605 private void setTabEnabled(String rawname, boolean state) {
606 // Retrieve the dictionary based name.
607 String name = Dictionary.get("GUI." + rawname);
608 int index = tab_pane.indexOfTab(name);
609 // Of course we may not have this tab available.
610 if(index != -1) {
611 // Some tabs are also dependant on if a collection is ready
612 Component component = tab_pane.getComponentAt(index);
613 if(component == enrich_pane || component == design_pane || component == export_pane || component == create_pane) {
614 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
615 }
616 else {
617 tab_pane.setEnabledAt(index, state);
618 }
619 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
620 if(tab_pane.getSelectedIndex() == index && !state) {
621 boolean found = false;
622 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
623 if(tab_pane.isEnabledAt(i)) {
624 tab_pane.setSelectedIndex(i);
625 found = true;
626 }
627 }
628 // If there are no tabs enabled, which should be impossible, then select the first tab
629 if(!found) {
630 tab_pane.setSelectedIndex(0);
631 }
632 }
633 }
634 // If the rawname was mirror then rebuild workspace tree to remove caches.
635 if (rawname.equals("Mirror")) {
636 // gather_pane.refreshWorkspaceTree(WorkspaceTree.FOLDER_SHORTCUTS_CHANGED);
637 }
638 }
639
640 /** Change the string shown in the title bar of the main gui frame. If either value is null, the 'No Collection' string is shown instead.
641 * @param title
642 * @param name
643 */
644 public void setTitle(String title, String name) {
645 // Finally display the collection name in the title bar.
646 StringBuffer title_buffer = new StringBuffer(Utility.PROGRAM_NAME);
647 title_buffer.append(StaticStrings.SPACE_CHARACTER);
648 title_buffer.append(StaticStrings.SPACE_CHARACTER);
649 // Describe the current user mode
650 title_buffer.append(StaticStrings.MODE_STR);
651 title_buffer.append(Configuration.getModeAsString());
652 title_buffer.append(StaticStrings.SPACE_CHARACTER);
653 title_buffer.append(StaticStrings.SPACE_CHARACTER);
654 // Now for the current collection
655 title_buffer.append(StaticStrings.COLLECTION_STR);
656 if (title != null && name != null) {
657 title_buffer.append(title);
658 title_buffer.append(StaticStrings.SPACE_CHARACTER);
659 title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
660 title_buffer.append(name);
661 title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
662 }
663 else {
664 title_buffer.append(Dictionary.get("Collection.No_Collection"));
665 }
666 this.setTitle(title_buffer.toString());
667 title_buffer = null;
668 }
669
670 /** 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.
671 */
672 private void showEditMetadataBox() {
673 if(Gatherer.c_man.getCollection() != null) {
674 Gatherer.c_man.getCollection().msm.editMDS(null, MetadataEditorManager.NORMAL);
675 }
676 }
677 /** When the load collection option is choosen this method is called to produce the modal file load prompt.
678 */
679 private boolean showLoadCollectionBox() {
680 boolean result = false;
681 // We first try the simple open collection dialog
682 SimpleOpenCollectionDialog dialog = new SimpleOpenCollectionDialog();
683 int user_choice = dialog.display();
684 String filename = null;
685 // The user may choose to go to the advanced 'browse' dialog
686 if(user_choice == SimpleOpenCollectionDialog.OK_OPTION) {
687 filename = dialog.getFileName();
688 }
689 else if(user_choice == SimpleOpenCollectionDialog.BROWSE_OPTION) {
690 File file;
691 if (Gatherer.GS3) {
692 if (Configuration.gsdl3_path != null) {
693 file = new File(Utility.getSitesDir(Configuration.gsdl3_path));
694 } else {
695 file = new File(Utility.BASE_DIR);
696 }
697
698 } else {
699
700 if(Configuration.gsdl_path != null) {
701 file = new File(Utility.getCollectDir(Configuration.gsdl_path));
702 }
703 else {
704 file = new File(Utility.BASE_DIR);
705 }
706 }
707 OpenCollectionDialog chooser = new OpenCollectionDialog(file);
708 file = null;
709 filename = chooser.getFileName();
710 chooser.destroy();
711 chooser = null;
712 }
713 dialog.destroy();
714 dialog = null;
715 // User can cancel action.
716 if(filename != null) {
717 // If there is already a collection open, save and close it.
718 if(Gatherer.c_man.ready()) {
719 showSaveCollectionBox(true, false);
720 // Wait until it is closed.
721 try {
722 synchronized(this) {
723 while(Gatherer.c_man.reallyReady()) {
724 wait(10);
725 }
726 }
727 }
728 catch(Exception error) {
729 Gatherer.println("Exception: " + error);
730 Gatherer.printStackTrace(error);
731 }
732 }
733
734 result = Gatherer.c_man.loadCollection(filename);
735 filename = null;
736 }
737 return result;
738 }
739
740 /** 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.
741 */
742 public void showMetaAuditBox() {
743 wait(true);
744 meta_audit.display();
745 wait(false);
746 }
747 /** This method is used to open the new collection box on the screen.
748 */
749 private void showNewCollectionPrompt() {
750 NewCollectionMetadataPrompt ncm_prompt = null;
751 // Create the collection details prompt from new collection prompt
752 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
753 // If no previous collection was indicated as a model design, then show the metadata selection prompt from new collection prompt
754 if(!ncd_prompt.isCancelled() && (ncd_prompt.getBase() == null)) {
755 ncm_prompt = new NewCollectionMetadataPrompt();
756 }
757 // Create the new collection (if not cancelled) in a new thread.
758 if(!ncd_prompt.isCancelled() && (ncm_prompt == null || !ncm_prompt.isCancelled())) {
759 // If there is already a collection open, save and close it.
760 if(Gatherer.c_man.ready()) {
761 showSaveCollectionBox(true, false);
762 // Wait until it is closed.
763 try {
764 synchronized(this) {
765 while(Gatherer.c_man.reallyReady()) {
766 wait(10);
767 }
768 }
769 }
770 catch(Exception error) {
771 Gatherer.println("Exception: " + error);
772 Gatherer.printStackTrace(error);
773 }
774 }
775
776 // Create new collection.
777 CreationTask task = new CreationTask(ncd_prompt, ncm_prompt);
778 // SwingUtilities.invokeLater(task);
779 task.start();
780 // Close prompt.
781 }
782 // Done
783 ncd_prompt = null;
784 ncm_prompt = null;
785 }
786 private class CreationTask
787 extends Thread {
788 private NewCollectionDetailsPrompt ncd_prompt = null;
789 private NewCollectionMetadataPrompt ncm_prompt = null;
790 public CreationTask(NewCollectionDetailsPrompt ncd_prompt, NewCollectionMetadataPrompt ncm_prompt) {
791 this.ncd_prompt = ncd_prompt;
792 this.ncm_prompt = ncm_prompt;
793 }
794
795 public void run() {
796 ///ystem.err.println("Running CreationTask...");
797 if(ncm_prompt == null) {
798 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), null);
799 }
800 else {
801 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), null, ncm_prompt.getSets());
802 }
803 // Now that the collection specific settings are loaded we can set the 'view extracted metadata' property
804 // do we want to have this in here???
805 //Configuration.set("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC, true);
806 ncd_prompt.dispose();
807 ncd_prompt = null;
808 if(ncm_prompt != null) {
809 ncm_prompt.dispose();
810 ncm_prompt = null;
811 }
812 }
813 }
814
815
816 /** This method is used to open the save collection box/prompt on the screen.
817 * @return A <i>boolean</i> which is <i>true</i> if the collection was saved successfully, <i>false</i> otherwise.
818 */
819 private boolean showSaveCollectionBox(boolean close_after, boolean exit_after) {
820 //SaveCollectionBox save_collection_box = new SaveCollectionBox();
821 //Rectangle bounds = save_collection_box.getBounds();
822 //int result = save_collection_box.getUserOption(Gatherer.c_man.getCollection().getName());
823 //switch(result) {
824 //case SaveCollectionBox.SAVE_YES:
825 Gatherer.c_man.setClosingThread(true);
826 Gatherer.c_man.saveCollection(close_after, exit_after);
827 // Wait until it is closed.
828 try {
829 synchronized(this) {
830 while(Gatherer.c_man.reallyReady()) {
831 wait(10);
832 }
833 }
834 }
835 catch(Exception error) {
836 Gatherer.println("Exception: " + error);
837 Gatherer.printStackTrace(error);
838 }
839
840 Gatherer.c_man.setClosingThread(false);
841
842 //content_pane.paintImmediately(bounds);
843 return true;
844 //case SaveCollectionBox.SAVE_NO:
845 // Close collection.
846 // if(close_after) {
847 // tab_pane.setSelectedComponent(gather_pane);
848 // Gatherer.c_man.closeCollection();
849 // }
850 // if(exit_after) {
851 // Gatherer.self.exit();
852 // }
853 // return true;
854 //default:
855 // return false;
856 //}
857 }
858 /** 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.
859 * @param event A ChangeEvent containing information about the event that fired this call.
860 */
861 public void stateChanged(ChangeEvent event) {
862 if(previous_pane != null) {
863 if(previous_pane == create_pane) {
864 create_pane.loseFocus();
865 }
866 else if(previous_pane == design_pane) {
867 design_pane.loseFocus();
868 }
869 }
870 // "View assigned metadata" menu item is disabled by default
871 menu_bar.metadata_view.setCanEnable(false);
872 menu_bar.setMetaAuditSuffix(null);
873
874 menu_bar.tabSelected(tab_pane.getSelectedIndex());
875 int selected_index = tab_pane.getSelectedIndex();
876 if( selected_index == tab_pane.indexOfComponent(gather_pane)) {
877 gather_pane.gainFocus();
878 // "View assigned metadata" menu item is enabled for the "Gather" pane
879 menu_bar.metadata_view.setCanEnable(true);
880 }
881 else if(selected_index == tab_pane.indexOfComponent(enrich_pane)) {
882 enrich_pane.gainFocus();
883 // "View assigned metadata" menu item is enabled for the "Enrich" pane
884 menu_bar.metadata_view.setCanEnable(true);
885 }
886 else if(selected_index == tab_pane.indexOfComponent(design_pane)) {
887 design_pane.gainFocus();
888 }
889 else if(selected_index == tab_pane.indexOfComponent(create_pane)) {
890 create_pane.gainFocus();
891 }
892 else if(selected_index == tab_pane.indexOfComponent(mirror_pane)) {
893 mirror_pane.gainFocus();
894 }
895
896 previous_pane = (JPanel) tab_pane.getSelectedComponent();
897 }
898
899 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
900
901 public void wait(boolean waiting) {
902 Component glass_pane = getGlassPane();
903 if(waiting) {
904 // Show wait cursor.
905 glass_pane.addMouseListener(mouse_blocker_listener);
906 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
907 glass_pane.setVisible(true);
908 }
909 else {
910 // Hide wait cursor.
911 glass_pane.setVisible(false);
912 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
913 glass_pane.removeMouseListener(mouse_blocker_listener);
914 }
915 glass_pane = null;
916 }
917
918 public void workflowUpdate(String raw, boolean state) {
919 WorkflowUpdater task = new WorkflowUpdater(raw, state);
920 SwingUtilities.invokeLater(task);
921 task = null;
922 }
923
924 /** 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.
925 * @return <i>true</i> if we should wait for a thread, <i>false</i> if it is safe to continue.
926 */
927 private boolean waitForThread() {
928 Thread active[] = new Thread[thread_group.activeCount()];
929 int size = thread_group.enumerate(active);
930 for(int i = 0; i < size; i++) {
931 if(active[i].getName().equals(GShell.GSHELL_BUILD) ||
932 active[i].getName().equals(GShell.GSHELL_IMPORT) ||
933 active[i].getName().equals(GShell.GSHELL_NEW)) {
934 return true;
935 }
936 }
937 return false;
938 }
939
940
941 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
942 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
943 */
944 protected void processWindowEvent(WindowEvent event) {
945 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
946 System.err.println("***** Processing Window Event ... closing");
947 exit();
948 }
949 }
950
951
952 private class MDSFileFilter
953 extends FileFilter
954 {
955 /** Override this method to return <i>true</i> only if the file extension is .mds.
956 * @param f A possible mds <strong>File</strong>.
957 * @return <i>true</i> if we should show this file, <i>false</i> otherwise.
958 */
959 public boolean accept(File f)
960 {
961 String file_name = f.getName().toLowerCase();
962 if (file_name.endsWith(".mds") || file_name.indexOf(".") == -1) {
963 return true;
964 }
965 return false;
966 }
967
968 /** Retrieve the description for this filter.
969 * @return The description as a <strong>String</strong>.
970 */
971 public String getDescription()
972 {
973 return Dictionary.get("MSMPrompt.File_Filter_Description");
974 }
975 }
976
977
978 /** 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.
979 */
980 private class MenuListenerImpl
981 implements MenuListener {
982 /** Called whenever a popup menu is hidden, but we don't care.
983 * @param e Some <strong>MenuEvent</strong> that we could care less about.
984 */
985 public void menuCanceled(MenuEvent e) {
986 }
987 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
988 * @param e Some <strong>MenuEvent</strong> that we could care less about.
989 */
990 public void menuDeselected(MenuEvent e) {
991 }
992 /** 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.
993 * @param e The <strong>MenuEvent</strong> whose source is checked.
994 */
995 public void menuSelected(MenuEvent e) {
996 if(e.getSource() == menu_bar.help) {
997 if(menu_bar.help.isSelected()) {
998 menu_bar.help.doClick(10);
999 }
1000 }
1001 }
1002 }
1003
1004 private class TabUpdater
1005 implements Runnable {
1006 private boolean ready = false;
1007 private int mirror_pos = -1;
1008 private int enrich_pos = -1;
1009 private int design_pos = -1;
1010 private int create_pos = -1;
1011 private int export_pos = -1;
1012 private JTabbedPane tab_pane = null;
1013
1014 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
1015 this.ready = ready;
1016 this.tab_pane = tab_pane;
1017 mirror_pos = tab_pane.indexOfComponent(mirror_pane);
1018 enrich_pos = tab_pane.indexOfComponent(enrich_pane);
1019 design_pos = tab_pane.indexOfComponent(design_pane);
1020 create_pos = tab_pane.indexOfComponent(create_pane);
1021 export_pos = tab_pane.indexOfComponent(export_pane);
1022 }
1023
1024 public void run()
1025 {
1026 if (mirror_pos != -1) {
1027 if (ready) {
1028 tab_pane.setEnabledAt(mirror_pos, Configuration.get("workflow.mirror", false));
1029 }
1030 else {
1031 tab_pane.setEnabledAt(mirror_pos, Configuration.get("workflow.mirror", true));
1032 }
1033 }
1034 if (enrich_pos != -1) {
1035 tab_pane.setEnabledAt(enrich_pos, ready && Configuration.get("workflow.enrich", false));
1036 }
1037 if (design_pos != -1) {
1038 tab_pane.setEnabledAt(design_pos, ready && Configuration.get("workflow.design", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
1039 }
1040 if (create_pos != -1) {
1041 tab_pane.setEnabledAt(create_pos, ready && Configuration.get("workflow.create", false));
1042 }
1043 if (export_pos != -1) {
1044 tab_pane.setEnabledAt(export_pos, ready && Configuration.get("workflow.export", false));
1045 }
1046 }
1047
1048 public void setReady(boolean ready) {
1049 this.ready = ready;
1050 }
1051 }
1052
1053 private class WorkflowUpdater
1054 implements Runnable {
1055 private boolean state;
1056 private String raw;
1057 public WorkflowUpdater(String raw, boolean state) {
1058 this.raw = raw;
1059 this.state = state;
1060 }
1061 public void run() {
1062 setTabEnabled(raw, state);
1063 }
1064 }
1065}
1066
1067
Note: See TracBrowser for help on using the repository browser.