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

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

Finally committing the (many) changes to the GLI to use the new metadata code... I hope this doesn't have too many bugs in it and committing it now doesn't stuff anyone up! (Katherine said I could commit it, so blame her if anything goes wrong).

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