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

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

Moved some stuff out of Configuration.updateUI into GUIManager because it depends on the Gatherer.class. More to come.

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