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

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

Made some annoying debug statements go to DebugStream instead of System.err.

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