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

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

Changed the collectionChanged() functions to refresh(), and added an extra parameter for more control over refreshing.

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