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

Last change on this file since 4675 was 4675, checked in by jmt12, 21 years ago

Sunday's work

  • Property svn:keywords set to Author Date Id Revision
File size: 35.5 KB
Line 
1package org.greenstone.gatherer.gui;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import java.awt.*;
39import java.awt.datatransfer.*;
40import java.awt.event.*;
41import java.io.*;
42import java.lang.*;
43import java.net.*;
44import java.util.*;
45import javax.swing.*;
46import javax.swing.event.*;
47import javax.swing.plaf.*;
48import javax.swing.text.*;
49import org.greenstone.gatherer.Gatherer;
50import org.greenstone.gatherer.collection.Collection;
51import org.greenstone.gatherer.collection.DeleteCollectionPrompt;
52import org.greenstone.gatherer.collection.LoadCollectionBox;
53import org.greenstone.gatherer.collection.SaveCollectionBox;
54import org.greenstone.gatherer.file.FileNode;
55import org.greenstone.gatherer.file.FileOpenActionListener;
56import org.greenstone.gatherer.gui.AboutDialog;
57import org.greenstone.gatherer.gui.BrowsingPane;
58import org.greenstone.gatherer.gui.CollectionPane;
59import org.greenstone.gatherer.gui.CreatePane;
60import org.greenstone.gatherer.gui.Filter;
61import org.greenstone.gatherer.gui.GConfigPane;
62import org.greenstone.gatherer.gui.MenuBar;
63import org.greenstone.gatherer.gui.MetaEditPane;
64import org.greenstone.gatherer.gui.MirrorPane;
65import org.greenstone.gatherer.gui.OpenCollectionDialog;
66import org.greenstone.gatherer.gui.OptionsBox;
67import org.greenstone.gatherer.gui.Preferences;
68import org.greenstone.gatherer.gui.PreviewPane;
69import org.greenstone.gatherer.gui.messages.MessagePane;
70import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
71import org.greenstone.gatherer.gui.tree.DragTree;
72import org.greenstone.gatherer.help.HelpFrame;
73import org.greenstone.gatherer.msm.ElementWrapper;
74import org.greenstone.gatherer.msm.Metadata;
75import org.greenstone.gatherer.sarm.SearchAndReplace;
76import org.greenstone.gatherer.shell.GShell;
77import org.greenstone.gatherer.util.TreeSynchronizer;
78import org.greenstone.gatherer.util.Utility;
79import org.greenstone.gatherer.valuetree.GValueNode;
80/** 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. */
81public class GUIManager
82 extends JFrame
83 implements ActionListener, ChangeListener {
84 /** The browsing pane behaves much like an internet browser, or at least will some day. */
85 public BrowsingPane browser_pane = null;
86 /** The collection pane is more like a file manager where you drag files from one tree to another. */
87 public CollectionPane collection_pane = null;
88 /** The create pane contains scripting options for importing and building collections into libraries. */
89 public CreatePane create_pane = null;
90
91 public FileOpenActionListener foa_listener = new FileOpenActionListener();
92
93 /** The configuration pane allows you to edit the design of the library in terms of the collection configuration file. */
94 public GConfigPane config_pane = null;
95 /** A reference to the currently instantiated help window, if any. */
96 public HelpFrame help = null;
97 /** The menu bar. */
98 public MenuBar menu_bar = null;
99 /** The message pane is optional and contains the log of messages sent. */
100 public MessagePane message_pane = null;
101
102 public MetaAuditFrame meta_audit;
103 /** The metaedit pane is used to assign, edit and remove metadata from files within the collection. */
104 public MetaEditPane metaedit_pane = null;
105 /** The mirror pane contains controls for mirroring interent sites. */
106 public MirrorPane mirror_pane = null;
107 /** The preview pane contains a preview of your build collection. */
108 public PreviewPane preview_pane = null;
109 /** Are certain panes currently locked? */
110 private boolean locked = false;
111 /** The size of the Gatherer window. */
112 private Dimension size = null;
113 /** The filters used to dynamically filter the trees at user request. */
114 private HashMap filters = new HashMap();
115 /** The panel within the window that other components are placed on. */
116 private JPanel content_pane = null;
117 /** The dummy export pane. */
118 private JPanel export_pane = new JPanel();
119 /** The last view pane selected. */
120 private JPanel previous_pane;
121 /** The main tab pane containing the different views, available here to trap view change events. */
122 private JTabbedPane tab_pane = null;
123 /** A reference to any existing search and replace module/dialog. */
124 private SearchAndReplace sar = null;
125 /** A threaded tab changer to try and avoid NPE on exit. */
126 private TabUpdater tab_updater = null;
127 /** 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.
128 * @see org.greenstone.gatherer.Dictionary
129 */
130 private ThreadGroup thread_group = null;
131 /** Ensures that expansion events between like collection trees are synchronized. */
132 private TreeSynchronizer collection_tree_sync = null;
133 /** Ensures that expansion events between like workspace trees are synchronized. */
134 private TreeSynchronizer workspace_tree_sync = null;
135 /**Constructor. Enable window events and arranges all other components.
136 * @param size The intial <strong>Dimension</strong> of the screen.
137 * @param graphic The default <strong>GraphicsConfiguration</strong> for this platform.
138 */
139 public GUIManager(Dimension size) {
140 super();
141 // Initialization
142 this.help = new HelpFrame();
143 this.size = size;
144 this.collection_tree_sync = new TreeSynchronizer();
145 this.meta_audit = new MetaAuditFrame(collection_tree_sync, null);
146 this.workspace_tree_sync = new TreeSynchronizer();
147 // Make the Tool tip hang around for a rediculous amount of time.
148 ToolTipManager.sharedInstance().setDismissDelay(10000);
149 // 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.
150 Thread bob = new Thread();
151 thread_group = bob.getThreadGroup();
152 // Set up some other UI stuff. (fonts handled in Gatherer.main())
153 UIManager.put("FileChooser.lookInLabelText", Gatherer.dictionary.get("SaveCollectionBox.Look_In"));
154 UIManager.put("FileChooser.filesOfTypeLabelText", Gatherer.dictionary.get("SaveCollectionBox.Files_Of_Type"));
155 UIManager.put("FileChooser.fileNameLabelText", Gatherer.dictionary.get("SaveCollectionBox.File_Name"));
156 }
157 /** 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.
158 * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
159 */
160 public void actionPerformed(ActionEvent event) {
161 boolean cont = true;
162 Object esrc = event.getSource();
163 // *************
164 // File Options.
165 // *************
166 if(esrc == menu_bar.file_associations) {
167 Gatherer.assoc_man.edit();
168 }
169 else if(esrc == menu_bar.file_close) {
170 if(!Gatherer.c_man.saved()) {
171 cont = showSaveCollectionBox(true, false);
172 }
173 if(cont) {
174 tab_pane.setSelectedComponent(collection_pane);
175 }
176 }
177 else if(esrc == menu_bar.file_delete) {
178 DeleteCollectionPrompt dcp = new DeleteCollectionPrompt();
179 dcp.display();
180 dcp.destroy();
181 dcp = null;
182 System.gc();
183 }
184 else if(esrc == menu_bar.file_exit) {
185 menu_bar.exit();
186 exit();
187 }
188 else if(esrc == menu_bar.file_new) {
189 showNewCollectionPrompt();
190 }
191 else if(esrc == menu_bar.file_open) {
192 // if(!Gatherer.c_man.saved()) {
193 // cont = showSaveCollectionBox(false, false);
194 // }
195 // if(cont) {
196 //if(!
197 showLoadCollectionBox();
198 //) {
199 //collectionChanged(false);
200 //}
201 // }
202 }
203 else if(esrc == menu_bar.file_options) {
204 new Preferences();
205 }
206 else if(esrc == menu_bar.file_save) {
207 Gatherer.c_man.saveCollection(false, false);
208 }
209 else if(esrc == menu_bar.file_save_as) {
210 String name = JOptionPane.showInputDialog(this, "Enter new collection filename.");
211 if(name != null) {
212 Gatherer.c_man.saveCollectionAs(name);
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 Gatherer.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 Gatherer.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 Gatherer.println(cce.toString());
254 }
255 }
256 else if(esrc == menu_bar.edit_search) {
257 if(sar != null) {
258 sar.dispose();
259 }
260 sar = new SearchAndReplace(false);
261 }
262 else if(esrc == menu_bar.edit_replace) {
263 if(sar != null) {
264 sar.dispose();
265 }
266 sar = new SearchAndReplace(true);
267 }
268 // *************
269 // Tools Options.
270 // *************
271 else if(esrc == menu_bar.tools_size) {
272 FileNode records[] = metaedit_pane.getSelectedNode();
273 if(records != null && records.length > 0) {
274 ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getMetadata(records[0].getFile());
275 if(metadatum.size() >= 4) {
276 Metadata metadata = (Metadata) metadatum.get(0);
277 ElementWrapper ew = metadata.getElement();
278
279 int SIZE = 5000;
280 Object[] array = new Object[SIZE];
281 Runtime.getRuntime().gc();
282 long start = Runtime.getRuntime().freeMemory();
283 for (int i = 0; i < SIZE; i++) {
284 array[i] = ew.copy();
285 }
286 Runtime.getRuntime().gc();
287 long end = Runtime.getRuntime().freeMemory();
288 long difference = (( start - end ) / SIZE);
289 ///ystem.out.println(difference + " bytes used." );
290 }
291 }
292 }
293 // *************
294 // Help Options.
295 // *************
296 else if(esrc == menu_bar.help_about) {
297 new AboutDialog(this);
298 }
299 else if(esrc == menu_bar.help_browse) {
300 help.setView("3.0");
301 }
302 else if(esrc == menu_bar.help_build) {
303 help.setView("8.0");
304 }
305 else if(esrc == menu_bar.help_collect) {
306 help.setView("5.0");
307 }
308 else if(esrc == menu_bar.help_design) {
309 help.setView("7.0");
310 }
311 else if(esrc == menu_bar.help_general) {
312 help.setView("");
313 }
314 else if(esrc == menu_bar.help_metaedit) {
315 help.setView("6.0");
316 }
317 else if(esrc == menu_bar.help_mirror) {
318 help.setView("4.0");
319 }
320 else if(esrc == menu_bar.help_preview) {
321 help.setView("9.0");
322 }
323 // *****************
324 // Metadata Options.
325 // *****************
326 else if(esrc == menu_bar.metadata_add) {
327 Gatherer.c_man.getCollection().msm.importMDS();
328 }
329 else if(esrc == menu_bar.metadata_edit) {
330 showEditMetadataBox();
331 }
332 else if(esrc == menu_bar.metadata_export) {
333 Gatherer.c_man.getCollection().msm.exportMDS();
334 }
335 else if(esrc == menu_bar.metadata_view) {
336 showMetaAuditBox();
337 }
338 else if(esrc == menu_bar.tools_log) {
339 showLogBox();
340 }
341 }
342 /** 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.
343 */
344 public void afterDisplay() {
345 if(Gatherer.config.get("workflow.mirror", true)) {
346 browser_pane.afterDisplay();
347 }
348 metaedit_pane.afterDisplay();
349 }
350 /** 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.
351 * @param ready <i>true</i> if the collection is ready for editing, <i>false</i> otherwise.
352 */
353 public void collectionChanged(final boolean ready) {
354 if(Gatherer.config.get("workflow.mirror", true)) {
355 mirror_pane.collectionChanged(ready);
356 }
357 menu_bar.collectionChanged(ready); // Inform the menu bar that the collections changed.
358 collection_pane.collectionChanged(ready); // Used to update the collection workspace.
359 metaedit_pane.collectionChanged(ready); // Very important that metaedit pane shows current collection and is listening to latest msm.
360 config_pane.collectionChanged(ready); // Also important config pane is listening to latest msm.
361 create_pane.collectionChanged(ready); // Used to indicate a new BuildOptions model should be loaded.
362 preview_pane.collectionChanged(ready); // preview should know when teh coll has changed so it can reload the home page
363 // Force tree model updates.
364 Gatherer.c_man.refreshTrees();
365 if(!locked) {
366 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
367 if(tab_updater == null) {
368 tab_updater = new TabUpdater(tab_pane, ready);
369 }
370 else {
371 tab_updater.setReady(ready);
372 }
373 SwingUtilities.invokeLater(tab_updater);
374 }
375 // Finally display the collection name in the title bar.
376 if(ready) {
377 this.setTitle(Utility.PROGRAM_NAME + ":\"" + Gatherer.c_man.getCollection().getTitle() + "\"");
378 }
379 else {
380 this.setTitle(Utility.PROGRAM_NAME + ": " + get("Collection.No_Collection"));
381 }
382 // Now is a good time to force a garbage collect.
383 ///ystem.err.println("Calling garbage collection.");
384 System.gc();
385 }
386 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
387 */
388 public void display() {
389 content_pane = (JPanel) this.getContentPane();
390 // Enable window-type events to be fired.
391 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
392 // Initialise and layout sub-components, plus other window dressing.
393 try {
394 this.setSize(size);
395 if(Gatherer.c_man.ready()) {
396 this.setTitle(Utility.PROGRAM_NAME + ":\"" + Gatherer.c_man.getCollection().getTitle() + "\"");
397 }
398 else {
399 this.setTitle(Utility.PROGRAM_NAME + ": " + get("Collection.No_Collection"));
400 }
401 // Pretty corner icon
402 this.setIconImage(Utility.getImage("gatherer_small.gif").getImage());
403 // BorderLayout for the main screen. I'll try my best to avoid t
404 // hese in subcomponents as they're space greedy.
405 content_pane.setLayout(new BorderLayout());
406 // Create the menu-bar and stick it up the top.
407 menu_bar = new MenuBar(new MenuListenerImpl());
408 content_pane.add(menu_bar, BorderLayout.NORTH);
409 // Create the tabbed pane and plop it in the center where it will
410 // expand to consume all available space like any good gas would.
411 tab_pane = new JTabbedPane();
412 tab_pane.addChangeListener(this);
413 tab_pane.setFont(Gatherer.config.getFont("general.font", false));
414
415 // May have to play with the order in which tabs are added.
416 if(Gatherer.config.get("workflow.browse", true)) {
417 browser_pane = new BrowsingPane();
418 tab_pane.addTab(get("Browser"), Utility.getImage("browsing.gif"), browser_pane);
419 tab_pane.setEnabledAt(tab_pane.indexOfComponent(browser_pane), Gatherer.config.get("workflow.browse", false));
420 }
421
422 if(Gatherer.config.get("workflow.mirror", true)) {
423 mirror_pane = new MirrorPane(workspace_tree_sync);
424 mirror_pane.display();
425 tab_pane.addTab(get("Mirroring"), Utility.getImage("mirroring.gif"), mirror_pane);
426 tab_pane.setEnabledAt(tab_pane.indexOfComponent(mirror_pane), Gatherer.config.get("workflow.mirror", false));
427 }
428
429 if(Gatherer.config.get("workflow.gather", true)) {
430 collection_pane = new CollectionPane(workspace_tree_sync, collection_tree_sync);
431 collection_pane.display();
432 tab_pane.addTab(get("Collection"), Utility.getImage("collection.gif"), collection_pane);
433 tab_pane.setEnabledAt(tab_pane.indexOfComponent(collection_pane), Gatherer.config.get("workflow.gather", false));
434 }
435
436 if(Gatherer.config.get("workflow.enrich", true)) {
437 metaedit_pane = new MetaEditPane(collection_tree_sync);
438 metaedit_pane.display();
439 tab_pane.addTab(get("MetaEdit"), Utility.getImage("metaedit.gif"), metaedit_pane);
440 tab_pane.setEnabledAt(tab_pane.indexOfComponent(metaedit_pane), false);
441 }
442
443 if(Gatherer.config.get("workflow.design", true)) {
444 config_pane = new GConfigPane();
445 config_pane.display();
446 tab_pane.addTab(get("Build"), Utility.getImage("build.gif"), config_pane);
447 tab_pane.setEnabledAt(tab_pane.indexOfComponent(config_pane), false);
448 }
449
450 if(Gatherer.config.get("workflow.export", true)) {
451 tab_pane.addTab(get("Export"), Utility.getImage("export.gif"), export_pane);
452 tab_pane.setEnabledAt(tab_pane.indexOfComponent(export_pane), false);
453 }
454
455 if(Gatherer.config.get("workflow.create", true)) {
456 create_pane = new CreatePane();
457 create_pane.display();
458 tab_pane.addTab(get("Create"), Utility.getImage("build session.gif"), create_pane);
459 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
460 }
461
462 if(Gatherer.config.get("workflow.preview", true)) {
463 preview_pane = new PreviewPane();
464 preview_pane.display();
465 tab_pane.addTab(get("Preview"), Utility.getImage("final.gif"), preview_pane);
466 tab_pane.setEnabledAt(tab_pane.indexOfComponent(preview_pane), false);
467 }
468
469 // Find the first tab that is enabled and select that.
470 boolean found = false;
471 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
472 if(tab_pane.isEnabledAt(i)) {
473 tab_pane.setSelectedIndex(i);
474 found = true;
475 }
476 }
477
478 content_pane.add(tab_pane, BorderLayout.CENTER);
479 // Drive a sessionReady event to update all controls to reflect current collection status.
480 collectionChanged(Gatherer.c_man.ready());
481 }
482 catch (Exception e) {
483 Gatherer.printStackTrace(e);
484 // The GUI failing to build is a app killer
485 e.printStackTrace();
486 System.exit(1);
487 }
488 }
489 /** 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.
490 */
491 public void exit() {
492 boolean cont = true;
493 if(Gatherer.c_man.ready() && !Gatherer.c_man.saved()) {
494 cont = showSaveCollectionBox(false, true);
495 }
496 else {
497 help.destroy();
498 help = null;
499 Gatherer.self.exit();
500 }
501 }
502 /** Retrieve the filter, or if one already exists, spawn a linked copy. */
503 public Filter getFilter(DragTree tree) {
504 Filter filter = (Filter) filters.get(tree.getModel());
505 if(filter == null) {
506 filter = new Filter(tree, null);
507 filters.put(tree.getModel(), filter);
508 return filter;
509 }
510 return filter.spawn(tree);
511 }
512
513 public Component getSelectedView() {
514 return tab_pane.getSelectedComponent();
515 }
516 /** 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.
517 */
518 public void lockCollection(boolean import_stage, boolean lock) {
519 locked = lock;
520 if(import_stage) {
521 int collection_pos = tab_pane.indexOfComponent(collection_pane);
522 int metaedit_pos = tab_pane.indexOfComponent(metaedit_pane);
523 int config_pos = tab_pane.indexOfComponent(config_pane);
524 tab_pane.setEnabledAt(collection_pos, !lock);
525 tab_pane.setEnabledAt(metaedit_pos, !lock);
526 tab_pane.setEnabledAt(config_pos, !lock);
527 }
528 else {
529 int config_pos = tab_pane.indexOfComponent(config_pane);
530 tab_pane.setEnabledAt(config_pos, !lock);
531 }
532 }
533
534 public void refreshTrees() {
535 collection_pane.refreshTrees();
536 //metaedit_pane.refreshTrees();
537 }
538
539 /** Allows the system to programatically set the selected tab.
540 * @param component The view you wish to make visable in the tab pane as a <strong>Component</strong>.
541 */
542 public void setSelectedView(Component component) {
543 tab_pane.setSelectedComponent(component);
544 }
545
546 /** Specifies whether a certain tab is enabled or not. */
547 public void setTabEnabled(String rawname, boolean state) {
548 // Retrieve the dictionary based name.
549 String name = get(rawname);
550 int index = tab_pane.indexOfTab(name);
551 // Of course we may not have this tab available.
552 if(index != -1) {
553 // Some tabs are also dependant on if a collection is ready
554 Component component = tab_pane.getComponentAt(index);
555 if(component == preview_pane) {
556 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.built());
557 }
558 else if(component == metaedit_pane || component == config_pane || component == export_pane || component == create_pane) {
559 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
560 }
561 else {
562 tab_pane.setEnabledAt(index, state);
563 }
564 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
565 if(tab_pane.getSelectedIndex() == index && !state) {
566 boolean found = false;
567 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
568 if(tab_pane.isEnabledAt(i)) {
569 tab_pane.setSelectedIndex(i);
570 found = true;
571 }
572 }
573 // If there are no tabs enabled, which should be impossible, then select the first tab
574 if(!found) {
575 tab_pane.setSelectedIndex(0);
576 }
577 }
578 }
579 }
580
581 /** When the edit metadata option is choosen from the menu, this method is called to ensure we only edit the metadata if there is metadata loaded.
582 */
583 public void showEditMetadataBox() {
584 if(Gatherer.c_man.getCollection() != null) {
585 Gatherer.c_man.getCollection().msm.editMDS();
586 }
587 }
588 /** When the load collection option is choosen this method is called to produce the modal file load prompt.
589 */
590 public boolean showLoadCollectionBox() {
591 boolean result = false;
592 //LoadCollectionBox load_collection_box = new LoadCollectionBox();
593 File file;
594 if(Gatherer.config.gsdl_path != null) {
595 file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
596 }
597 else {
598 file = new File(Utility.BASE_DIR);
599 }
600 OpenCollectionDialog chooser = new OpenCollectionDialog(file);
601 String filename = chooser.getFileName();
602 // User can cancel action.
603 if(filename != null) {
604 // If there is already a collection open, save and close it.
605 if(Gatherer.c_man.ready()) {
606 showSaveCollectionBox(true, false);
607 // Wait until it is closed.
608 try {
609 synchronized(this) {
610 while(Gatherer.c_man.reallyReady()) {
611 wait(10);
612 }
613 }
614 }
615 catch(Exception error) {
616 Gatherer.println("Exception: " + error);
617 Gatherer.printStackTrace(error);
618 }
619 }
620 result = Gatherer.c_man.loadCollection(filename);
621 }
622 return result;
623 }
624 /** When called this method causes the Log class in Gatherer to display a nice dialog box which contains the log.
625 */
626 public void showLogBox() {
627 Gatherer.log.display();
628 }
629 /** 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.
630 */
631 public void showMetaAuditBox() {
632 wait(true);
633 meta_audit.display();
634 wait(false);
635 }
636 /** This method is used to open the new collection box on the screen.
637 */
638 public void showNewCollectionPrompt() {
639 NewCollectionMetadataPrompt ncm_prompt = null;
640 // Create the collection details prompt from new collection prompt
641 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
642 // If no previous collection was indicated as a model design, then show the metadata selection prompt from new collection prompt
643 if(!ncd_prompt.isCancelled() && (ncd_prompt.getBase() == null)) {
644 ncm_prompt = new NewCollectionMetadataPrompt();
645 }
646 // Create the new collection (if not cancelled) in a new thread.
647 if(!ncd_prompt.isCancelled() && (ncm_prompt == null || !ncm_prompt.isCancelled())) {
648 // If there is already a collection open, save and close it.
649 if(Gatherer.c_man.ready()) {
650 showSaveCollectionBox(true, false);
651 // Wait until it is closed.
652 try {
653 synchronized(this) {
654 while(Gatherer.c_man.reallyReady()) {
655 wait(10);
656 }
657 }
658 }
659 catch(Exception error) {
660 Gatherer.println("Exception: " + error);
661 Gatherer.printStackTrace(error);
662 }
663 }
664
665 // Create new collection.
666 CreationTask task = new CreationTask(ncd_prompt, ncm_prompt);
667 // SwingUtilities.invokeLater(task);
668 task.start();
669 // Close prompt.
670 }
671 // Done
672 ncd_prompt = null;
673 ncm_prompt = null;
674 }
675 private class CreationTask
676 extends Thread {
677 private NewCollectionDetailsPrompt ncd_prompt = null;
678 private NewCollectionMetadataPrompt ncm_prompt = null;
679 public CreationTask(NewCollectionDetailsPrompt ncd_prompt, NewCollectionMetadataPrompt ncm_prompt) {
680 this.ncd_prompt = ncd_prompt;
681 this.ncm_prompt = ncm_prompt;
682 }
683
684 public void run() {
685 // System.err.println("Running CreationTask...");
686 if(ncm_prompt == null) {
687 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), ncd_prompt.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), null);
688 }
689 else {
690 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), ncd_prompt.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), null, ncm_prompt.getSets());
691 }
692 ncd_prompt.dispose();
693 ncd_prompt = null;
694 if(ncm_prompt != null) {
695 ncm_prompt.dispose();
696 ncm_prompt = null;
697 }
698 }
699 }
700
701 /** This method is used to open the options box on the screen.
702 */
703 public void showOptionsBox() {
704 new OptionsBox();
705 }
706 /** This method is used to open the save collection box/prompt on the screen.
707 * @return A <i>boolean</i> which is <i>true</i> if the collection was saved successfully, <i>false</i> otherwise.
708 */
709 public boolean showSaveCollectionBox(boolean close_after, boolean exit_after) {
710 //SaveCollectionBox save_collection_box = new SaveCollectionBox();
711 //Rectangle bounds = save_collection_box.getBounds();
712 //int result = save_collection_box.getUserOption(Gatherer.c_man.getCollection().getName());
713 //switch(result) {
714 //case SaveCollectionBox.SAVE_YES:
715 Gatherer.c_man.saveCollection(close_after, exit_after);
716 // Wait until it is closed.
717 try {
718 synchronized(this) {
719 while(Gatherer.c_man.reallyReady()) {
720 wait(10);
721 }
722 }
723 }
724 catch(Exception error) {
725 Gatherer.println("Exception: " + error);
726 Gatherer.printStackTrace(error);
727 }
728
729 //content_pane.paintImmediately(bounds);
730 return true;
731 //case SaveCollectionBox.SAVE_NO:
732 // Close collection.
733 // if(close_after) {
734 // tab_pane.setSelectedComponent(collection_pane);
735 // Gatherer.c_man.closeCollection();
736 // }
737 // if(exit_after) {
738 // Gatherer.self.exit();
739 // }
740 // return true;
741 //default:
742 // return false;
743 //}
744 }
745 /** 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.
746 * @param event A ChangeEvent containing information about the event that fired this call.
747 */
748 public void stateChanged(ChangeEvent event) {
749 if(previous_pane != null) {
750 if(previous_pane == create_pane) {
751 create_pane.loseFocus();
752 }
753 }
754 // "View assigned metadata" menu item is disabled by default
755 menu_bar.metadata_view.setCanEnable(false);
756 menu_bar.setMetaAuditSuffix(null);
757
758 menu_bar.tabSelected(tab_pane.getSelectedIndex());
759 if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(collection_pane)) {
760 collection_pane.gainFocus();
761 // "View assigned metadata" menu item is enabled for the "Gather" pane
762 menu_bar.metadata_view.setCanEnable(true);
763 }
764 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(metaedit_pane)) {
765 metaedit_pane.gainFocus();
766 // "View assigned metadata" menu item is enabled for the "Enrich" pane
767 menu_bar.metadata_view.setCanEnable(true);
768 }
769 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(config_pane)) {
770 config_pane.gainFocus();
771 }
772 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(create_pane)) {
773 create_pane.gainFocus();
774 }
775 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(preview_pane)) {
776 config_pane.saveConfiguration();
777 preview_pane.gainFocus();
778 }
779
780 previous_pane = (JPanel) tab_pane.getSelectedComponent();
781 }
782
783 public void wait(boolean waiting) {
784 Component glass_pane = getGlassPane();
785 if(waiting) {
786 // Show wait cursor.
787 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
788 glass_pane.setVisible(true);
789 }
790 else {
791 // Hide wait cursor.
792 glass_pane.setVisible(false);
793 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
794 }
795 glass_pane = null;
796 }
797
798 public void workflowUpdate(String raw, boolean state) {
799 WorkflowUpdater task = new WorkflowUpdater(raw, state);
800 SwingUtilities.invokeLater(task);
801 task = null;
802 }
803
804 /** Retrieves a phrase from the Dictionary based on the key.
805 * @param key A <strong>String</strong> uniquely identifying a phrase from the Dictionary.
806 * @return The desired phrase as a <strong>String</strong>.
807 * @see org.greenstone.gatherer.Dictionary
808 */
809 private String get(String key) {
810 return get(key, null);
811 }
812 /** Retrieves a phrase from the Dictionary based on the key and including the arguments.
813 * @param key A <strong>String</strong> uniquely identifying a phrase from the Dictionary.
814 * @param args A <strong>String[]</strong> of arguments available to be inserted into the phrase.
815 * @return The desired phrase as a <strong>String</strong>.
816 * @see org.greenstone.gatherer.Dictionary
817 */
818 private String get(String key, String args[]) {
819 if(key.indexOf('.') == -1) {
820 key = "GUI." + key;
821 }
822 return Gatherer.dictionary.get(key, args);
823 }
824 /** 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.
825 * @return <i>true</i> if we should wait for a thread, <i>false</i> if it is safe to continue.
826 */
827 private boolean waitForThread() {
828 Thread active[] = new Thread[thread_group.activeCount()];
829 int size = thread_group.enumerate(active);
830 for(int i = 0; i < size; i++) {
831 if(active[i].getName().equals(GShell.GSHELL_BUILD) ||
832 active[i].getName().equals(GShell.GSHELL_IMPORT) ||
833 active[i].getName().equals(GShell.GSHELL_NEW)) {
834 return true;
835 }
836 }
837 return false;
838 }
839
840
841 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
842 * @param event A <strong>WindowEvent</strong> containing information about the event that fred this call.
843 */
844 protected void processWindowEvent(WindowEvent event) {
845 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
846 exit();
847 }
848 }
849 /** 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.
850 */
851 private class MenuListenerImpl
852 implements MenuListener {
853 /** Called whenever a popup menu is hidden, but we don't care.
854 * @param e Some <strong>MenuEvent</strong> that we could care less about.
855 */
856 public void menuCanceled(MenuEvent e) {
857 }
858 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
859 * @param e Some <strong>MenuEvent</strong> that we could care less about.
860 */
861 public void menuDeselected(MenuEvent e) {
862 }
863 /** 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.
864 * @param e The <strong>MenuEvent</strong> whose source is checked.
865 */
866 public void menuSelected(MenuEvent e) {
867 if(e.getSource() == menu_bar.help) {
868 if(menu_bar.help.isSelected()) {
869 menu_bar.help.doClick(10);
870 }
871 }
872 }
873 }
874 private class TabUpdater
875 implements Runnable {
876 private boolean ready = false;
877 private int browse_pos = -1;
878 private int mirror_pos = -1;
879 private int config_pos = -1;
880 private int create_pos = -1;
881 private int export_pos = -1;
882 private int metaedit_pos = -1;
883 private int preview_pos = -1;
884 private JTabbedPane tab_pane = null;
885 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
886 this.ready = ready;
887 this.tab_pane = tab_pane;
888 browse_pos = tab_pane.indexOfComponent(browser_pane);
889 mirror_pos = tab_pane.indexOfComponent(mirror_pane);
890 metaedit_pos = tab_pane.indexOfComponent(metaedit_pane);
891 config_pos = tab_pane.indexOfComponent(config_pane);
892 export_pos = tab_pane.indexOfComponent(export_pane);
893 create_pos = tab_pane.indexOfComponent(create_pane);
894 preview_pos = tab_pane.indexOfComponent(preview_pane);
895 }
896 public void run() {
897 if(browse_pos != -1) {
898 if(ready) {
899 tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", false));
900 }
901 else {
902 tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", true));
903 }
904 }
905 if(mirror_pos != -1) {
906 if(ready) {
907 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", false));
908 }
909 else {
910 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", true));
911 }
912 }
913 if(metaedit_pos != -1) {
914 tab_pane.setEnabledAt(metaedit_pos, ready && Gatherer.config.get("workflow.enrich", false));
915 }
916 if(config_pos != -1) {
917 tab_pane.setEnabledAt(config_pos, ready && Gatherer.config.get("workflow.design", false));
918 }
919 if(export_pos != -1) {
920 tab_pane.setEnabledAt(export_pos, ready && Gatherer.config.get("workflow.export", false));
921 }
922 if(create_pos != -1) {
923 tab_pane.setEnabledAt(create_pos, ready && Gatherer.config.get("workflow.create", false));
924 }
925 if(preview_pos != -1) {
926 tab_pane.setEnabledAt(preview_pos, Gatherer.c_man != null && Gatherer.c_man.built() && Gatherer.config.get("workflow.preview", false));
927 }
928 }
929 public void setReady(boolean ready) {
930 this.ready = ready;
931 }
932 }
933
934 private class WorkflowUpdater
935 implements Runnable {
936 private boolean state;
937 private String raw;
938 public WorkflowUpdater(String raw, boolean state) {
939 this.raw = raw;
940 this.state = state;
941 }
942 public void run() {
943 setTabEnabled(raw, state);
944 }
945 }
946}
Note: See TracBrowser for help on using the repository browser.