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

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

Replaced System.err.println with Gatherer.println

  • Property svn:keywords set to Author Date Id Revision
File size: 35.4 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 (showLoadCollectionBox()) {
193 tab_pane.setSelectedComponent(collection_pane);
194 }
195 }
196 else if(esrc == menu_bar.file_options) {
197 new Preferences();
198 }
199 else if(esrc == menu_bar.file_save) {
200 Gatherer.c_man.saveCollection(false, false);
201 }
202 else if(esrc == menu_bar.file_save_as) {
203 String name = JOptionPane.showInputDialog(this, "Enter new collection filename.");
204 if(name != null) {
205 Gatherer.c_man.saveCollectionAs(name);
206 }
207 }
208 // *************
209 // Edit Options.
210 // *************
211 else if(esrc == menu_bar.edit_copy) {
212 try {
213 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
214 // Get the component with selected text as a JTextComponent
215 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
216 text.copy();
217 }
218 catch (Exception cce) {
219 // If the component is not a text component ignore the copy command
220 Gatherer.println(cce.toString());
221 }
222 }
223 else if(esrc == menu_bar.edit_cut) {
224 try {
225 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
226 // Get the component with selected text as a JTextComponent
227 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
228 // Cut the text to the clipboard
229 text.cut();
230 }
231 catch (ClassCastException cce) {
232 // If the component is not a text component ignore the cut command
233 Gatherer.println(cce.toString());
234 }
235 }
236 else if(esrc == menu_bar.edit_paste) {
237 try {
238 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
239 // Get the component with selected text as a JTextComponent
240 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
241 // Cut the text to the clipboard
242 text.paste();
243 }
244 catch (ClassCastException cce) {
245 // If the component is not a text component ignore the paste command
246 Gatherer.println(cce.toString());
247 }
248 }
249 else if(esrc == menu_bar.edit_search) {
250 if(sar != null) {
251 sar.dispose();
252 }
253 sar = new SearchAndReplace(false);
254 }
255 else if(esrc == menu_bar.edit_replace) {
256 if(sar != null) {
257 sar.dispose();
258 }
259 sar = new SearchAndReplace(true);
260 }
261 // *************
262 // Tools Options.
263 // *************
264 else if(esrc == menu_bar.tools_size) {
265 FileNode records[] = metaedit_pane.getSelectedNode();
266 if(records != null && records.length > 0) {
267 ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getMetadata(records[0].getFile());
268 if(metadatum.size() >= 4) {
269 Metadata metadata = (Metadata) metadatum.get(0);
270 ElementWrapper ew = metadata.getElement();
271
272 int SIZE = 5000;
273 Object[] array = new Object[SIZE];
274 Runtime.getRuntime().gc();
275 long start = Runtime.getRuntime().freeMemory();
276 for (int i = 0; i < SIZE; i++) {
277 array[i] = ew.copy();
278 }
279 Runtime.getRuntime().gc();
280 long end = Runtime.getRuntime().freeMemory();
281 long difference = (( start - end ) / SIZE);
282 ///ystem.out.println(difference + " bytes used." );
283 }
284 }
285 }
286 // *************
287 // Help Options.
288 // *************
289 else if(esrc == menu_bar.help_about) {
290 new AboutDialog(this);
291 }
292 else if(esrc == menu_bar.help_browse) {
293 help.setView("3.0");
294 }
295 else if(esrc == menu_bar.help_build) {
296 help.setView("8.0");
297 }
298 else if(esrc == menu_bar.help_collect) {
299 help.setView("5.0");
300 }
301 else if(esrc == menu_bar.help_design) {
302 help.setView("7.0");
303 }
304 else if(esrc == menu_bar.help_general) {
305 help.setView("");
306 }
307 else if(esrc == menu_bar.help_metaedit) {
308 help.setView("6.0");
309 }
310 else if(esrc == menu_bar.help_mirror) {
311 help.setView("4.0");
312 }
313 else if(esrc == menu_bar.help_preview) {
314 help.setView("9.0");
315 }
316 // *****************
317 // Metadata Options.
318 // *****************
319 else if(esrc == menu_bar.metadata_add) {
320 Gatherer.c_man.getCollection().msm.importMDS();
321 }
322 else if(esrc == menu_bar.metadata_edit) {
323 showEditMetadataBox();
324 }
325 else if(esrc == menu_bar.metadata_export) {
326 Gatherer.c_man.getCollection().msm.exportMDS();
327 }
328 else if(esrc == menu_bar.metadata_view) {
329 showMetaAuditBox();
330 }
331 else if(esrc == menu_bar.tools_log) {
332 showLogBox();
333 }
334 }
335 /** 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.
336 */
337 public void afterDisplay() {
338 if(Gatherer.config.get("workflow.mirror", true)) {
339 browser_pane.afterDisplay();
340 }
341 metaedit_pane.afterDisplay();
342 }
343 /** 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.
344 * @param ready <i>true</i> if the collection is ready for editing, <i>false</i> otherwise.
345 */
346 public void collectionChanged(final boolean ready) {
347 if(Gatherer.config.get("workflow.mirror", true)) {
348 mirror_pane.collectionChanged(ready);
349 }
350 menu_bar.collectionChanged(ready); // Inform the menu bar that the collections changed.
351 collection_pane.collectionChanged(ready); // Used to update the collection workspace.
352 metaedit_pane.collectionChanged(ready); // Very important that metaedit pane shows current collection and is listening to latest msm.
353 config_pane.collectionChanged(ready); // Also important config pane is listening to latest msm.
354 create_pane.collectionChanged(ready); // Used to indicate a new BuildOptions model should be loaded.
355 preview_pane.collectionChanged(ready); // preview should know when teh coll has changed so it can reload the home page
356 // Force tree model updates.
357 Gatherer.c_man.refreshTrees();
358 if(!locked) {
359 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
360 if(tab_updater == null) {
361 tab_updater = new TabUpdater(tab_pane, ready);
362 }
363 else {
364 tab_updater.setReady(ready);
365 }
366 SwingUtilities.invokeLater(tab_updater);
367 }
368 // Finally display the collection name in the title bar.
369 if(ready) {
370 this.setTitle(Utility.PROGRAM_NAME + ":\"" + Gatherer.c_man.getCollection().getTitle() + "\"");
371 }
372 else {
373 this.setTitle(Utility.PROGRAM_NAME + ": " + get("Collection.No_Collection"));
374 }
375 // Now is a good time to force a garbage collect.
376 ///ystem.err.println("Calling garbage collection.");
377 System.gc();
378 }
379 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
380 */
381 public void display() {
382 content_pane = (JPanel) this.getContentPane();
383 // Enable window-type events to be fired.
384 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
385 // Initialise and layout sub-components, plus other window dressing.
386 try {
387 this.setSize(size);
388 if(Gatherer.c_man.ready()) {
389 this.setTitle(Utility.PROGRAM_NAME + ":\"" + Gatherer.c_man.getCollection().getTitle() + "\"");
390 }
391 else {
392 this.setTitle(Utility.PROGRAM_NAME + ": " + get("Collection.No_Collection"));
393 }
394 // Pretty corner icon
395 this.setIconImage(Utility.getImage("gatherer_small.gif").getImage());
396 // BorderLayout for the main screen. I'll try my best to avoid t
397 // hese in subcomponents as they're space greedy.
398 content_pane.setLayout(new BorderLayout());
399 // Create the menu-bar and stick it up the top.
400 menu_bar = new MenuBar(new MenuListenerImpl());
401 content_pane.add(menu_bar, BorderLayout.NORTH);
402 // Create the tabbed pane and plop it in the center where it will
403 // expand to consume all available space like any good gas would.
404 tab_pane = new JTabbedPane();
405 tab_pane.addChangeListener(this);
406 tab_pane.setFont(Gatherer.config.getFont("general.font", false));
407
408 // May have to play with the order in which tabs are added.
409 if(Gatherer.config.get("workflow.browse", true)) {
410 browser_pane = new BrowsingPane();
411 tab_pane.addTab(get("Browser"), Utility.getImage("browsing.gif"), browser_pane);
412 tab_pane.setEnabledAt(tab_pane.indexOfComponent(browser_pane), Gatherer.config.get("workflow.browse", false));
413 }
414
415 if(Gatherer.config.get("workflow.mirror", true)) {
416 mirror_pane = new MirrorPane(workspace_tree_sync);
417 mirror_pane.display();
418 tab_pane.addTab(get("Mirroring"), Utility.getImage("mirroring.gif"), mirror_pane);
419 tab_pane.setEnabledAt(tab_pane.indexOfComponent(mirror_pane), Gatherer.config.get("workflow.mirror", false));
420 }
421
422 if(Gatherer.config.get("workflow.gather", true)) {
423 collection_pane = new CollectionPane(workspace_tree_sync, collection_tree_sync);
424 collection_pane.display();
425 tab_pane.addTab(get("Collection"), Utility.getImage("collection.gif"), collection_pane);
426 tab_pane.setEnabledAt(tab_pane.indexOfComponent(collection_pane), Gatherer.config.get("workflow.gather", false));
427 }
428
429 if(Gatherer.config.get("workflow.enrich", true)) {
430 metaedit_pane = new MetaEditPane(collection_tree_sync);
431 metaedit_pane.display();
432 tab_pane.addTab(get("MetaEdit"), Utility.getImage("metaedit.gif"), metaedit_pane);
433 tab_pane.setEnabledAt(tab_pane.indexOfComponent(metaedit_pane), false);
434 }
435
436 if(Gatherer.config.get("workflow.design", true)) {
437 config_pane = new GConfigPane();
438 config_pane.display();
439 tab_pane.addTab(get("Build"), Utility.getImage("build.gif"), config_pane);
440 tab_pane.setEnabledAt(tab_pane.indexOfComponent(config_pane), false);
441 }
442
443 if(Gatherer.config.get("workflow.export", true)) {
444 tab_pane.addTab(get("Export"), Utility.getImage("export.gif"), export_pane);
445 tab_pane.setEnabledAt(tab_pane.indexOfComponent(export_pane), false);
446 }
447
448 if(Gatherer.config.get("workflow.create", true)) {
449 create_pane = new CreatePane();
450 create_pane.display();
451 tab_pane.addTab(get("Create"), Utility.getImage("build session.gif"), create_pane);
452 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
453 }
454
455 if(Gatherer.config.get("workflow.preview", true)) {
456 preview_pane = new PreviewPane();
457 preview_pane.display();
458 tab_pane.addTab(get("Preview"), Utility.getImage("final.gif"), preview_pane);
459 tab_pane.setEnabledAt(tab_pane.indexOfComponent(preview_pane), false);
460 }
461
462 // Find the first tab that is enabled and select that.
463 boolean found = false;
464 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
465 if(tab_pane.isEnabledAt(i)) {
466 tab_pane.setSelectedIndex(i);
467 found = true;
468 }
469 }
470
471 content_pane.add(tab_pane, BorderLayout.CENTER);
472 // Drive a sessionReady event to update all controls to reflect current collection status.
473 collectionChanged(Gatherer.c_man.ready());
474 }
475 catch (Exception e) {
476 Gatherer.printStackTrace(e);
477 // The GUI failing to build is a app killer
478 e.printStackTrace();
479 System.exit(1);
480 }
481 }
482 /** 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.
483 */
484 public void exit() {
485 boolean cont = true;
486 if(Gatherer.c_man.ready() && !Gatherer.c_man.saved()) {
487 cont = showSaveCollectionBox(false, true);
488 }
489 else {
490 help.destroy();
491 help = null;
492 Gatherer.self.exit();
493 }
494 }
495 /** Retrieve the filter, or if one already exists, spawn a linked copy. */
496 public Filter getFilter(DragTree tree) {
497 Filter filter = (Filter) filters.get(tree.getModel());
498 if(filter == null) {
499 filter = new Filter(tree, null);
500 filters.put(tree.getModel(), filter);
501 return filter;
502 }
503 return filter.spawn(tree);
504 }
505
506 public Component getSelectedView() {
507 return tab_pane.getSelectedComponent();
508 }
509 /** 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.
510 */
511 public void lockCollection(boolean import_stage, boolean lock) {
512 locked = lock;
513 if(import_stage) {
514 int collection_pos = tab_pane.indexOfComponent(collection_pane);
515 int metaedit_pos = tab_pane.indexOfComponent(metaedit_pane);
516 int config_pos = tab_pane.indexOfComponent(config_pane);
517 tab_pane.setEnabledAt(collection_pos, !lock);
518 tab_pane.setEnabledAt(metaedit_pos, !lock);
519 tab_pane.setEnabledAt(config_pos, !lock);
520 }
521 else {
522 int config_pos = tab_pane.indexOfComponent(config_pane);
523 tab_pane.setEnabledAt(config_pos, !lock);
524 }
525 }
526
527 public void refreshTrees() {
528 collection_pane.refreshTrees();
529 //metaedit_pane.refreshTrees();
530 }
531
532 /** Allows the system to programatically set the selected tab.
533 * @param component The view you wish to make visable in the tab pane as a <strong>Component</strong>.
534 */
535 public void setSelectedView(Component component) {
536 tab_pane.setSelectedComponent(component);
537 }
538
539 /** Specifies whether a certain tab is enabled or not. */
540 public void setTabEnabled(String rawname, boolean state) {
541 // Retrieve the dictionary based name.
542 String name = get(rawname);
543 int index = tab_pane.indexOfTab(name);
544 // Of course we may not have this tab available.
545 if(index != -1) {
546 // Some tabs are also dependant on if a collection is ready
547 Component component = tab_pane.getComponentAt(index);
548 if(component == preview_pane) {
549 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.built());
550 }
551 else if(component == metaedit_pane || component == config_pane || component == export_pane || component == create_pane) {
552 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
553 }
554 else {
555 tab_pane.setEnabledAt(index, state);
556 }
557 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
558 if(tab_pane.getSelectedIndex() == index && !state) {
559 boolean found = false;
560 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
561 if(tab_pane.isEnabledAt(i)) {
562 tab_pane.setSelectedIndex(i);
563 found = true;
564 }
565 }
566 // If there are no tabs enabled, which should be impossible, then select the first tab
567 if(!found) {
568 tab_pane.setSelectedIndex(0);
569 }
570 }
571 }
572 }
573
574 /** 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.
575 */
576 public void showEditMetadataBox() {
577 if(Gatherer.c_man.getCollection() != null) {
578 Gatherer.c_man.getCollection().msm.editMDS();
579 }
580 }
581 /** When the load collection option is choosen this method is called to produce the modal file load prompt.
582 */
583 public boolean showLoadCollectionBox() {
584 boolean result = false;
585 //LoadCollectionBox load_collection_box = new LoadCollectionBox();
586 File file;
587 if(Gatherer.config.gsdl_path != null) {
588 file = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
589 }
590 else {
591 file = new File(Utility.BASE_DIR);
592 }
593 OpenCollectionDialog chooser = new OpenCollectionDialog(file);
594 String filename = chooser.getFileName();
595 // User can cancel action.
596 if(filename != null) {
597 // If there is already a collection open, save and close it.
598 if(Gatherer.c_man.ready()) {
599 showSaveCollectionBox(true, false);
600 // Wait until it is closed.
601 try {
602 synchronized(this) {
603 while(Gatherer.c_man.reallyReady()) {
604 wait(10);
605 }
606 }
607 }
608 catch(Exception error) {
609 Gatherer.println("Exception: " + error);
610 Gatherer.printStackTrace(error);
611 }
612 }
613 result = Gatherer.c_man.loadCollection(filename);
614 }
615 return result;
616 }
617 /** When called this method causes the Log class in Gatherer to display a nice dialog box which contains the log.
618 */
619 public void showLogBox() {
620 Gatherer.log.display();
621 }
622 /** 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.
623 */
624 public void showMetaAuditBox() {
625 wait(true);
626 meta_audit.display();
627 wait(false);
628 }
629 /** This method is used to open the new collection box on the screen.
630 */
631 public void showNewCollectionPrompt() {
632 NewCollectionMetadataPrompt ncm_prompt = null;
633 // Create the collection details prompt from new collection prompt
634 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
635 // If no previous collection was indicated as a model design, then show the metadata selection prompt from new collection prompt
636 if(!ncd_prompt.isCancelled() && (ncd_prompt.getBase() == null)) {
637 ncm_prompt = new NewCollectionMetadataPrompt();
638 }
639 // Create the new collection (if not cancelled) in a new thread.
640 if(!ncd_prompt.isCancelled() && (ncm_prompt == null || !ncm_prompt.isCancelled())) {
641 // If there is already a collection open, save and close it.
642 if(Gatherer.c_man.ready()) {
643 showSaveCollectionBox(true, false);
644 // Wait until it is closed.
645 try {
646 synchronized(this) {
647 while(Gatherer.c_man.reallyReady()) {
648 wait(10);
649 }
650 }
651 }
652 catch(Exception error) {
653 Gatherer.println("Exception: " + error);
654 Gatherer.printStackTrace(error);
655 }
656 }
657
658 // Create new collection.
659 CreationTask task = new CreationTask(ncd_prompt, ncm_prompt);
660 // SwingUtilities.invokeLater(task);
661 task.start();
662 // Close prompt.
663 }
664 // Done
665 ncd_prompt = null;
666 ncm_prompt = null;
667 }
668 private class CreationTask
669 extends Thread {
670 private NewCollectionDetailsPrompt ncd_prompt = null;
671 private NewCollectionMetadataPrompt ncm_prompt = null;
672 public CreationTask(NewCollectionDetailsPrompt ncd_prompt, NewCollectionMetadataPrompt ncm_prompt) {
673 this.ncd_prompt = ncd_prompt;
674 this.ncm_prompt = ncm_prompt;
675 }
676
677 public void run() {
678 ///ystem.err.println("Running CreationTask...");
679 if(ncm_prompt == null) {
680 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), ncd_prompt.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), null);
681 }
682 else {
683 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), ncd_prompt.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), null, ncm_prompt.getSets());
684 }
685 ncd_prompt.dispose();
686 ncd_prompt = null;
687 if(ncm_prompt != null) {
688 ncm_prompt.dispose();
689 ncm_prompt = null;
690 }
691 }
692 }
693
694 /** This method is used to open the options box on the screen.
695 */
696 public void showOptionsBox() {
697 new OptionsBox();
698 }
699 /** This method is used to open the save collection box/prompt on the screen.
700 * @return A <i>boolean</i> which is <i>true</i> if the collection was saved successfully, <i>false</i> otherwise.
701 */
702 public boolean showSaveCollectionBox(boolean close_after, boolean exit_after) {
703 //SaveCollectionBox save_collection_box = new SaveCollectionBox();
704 //Rectangle bounds = save_collection_box.getBounds();
705 //int result = save_collection_box.getUserOption(Gatherer.c_man.getCollection().getName());
706 //switch(result) {
707 //case SaveCollectionBox.SAVE_YES:
708 Gatherer.c_man.saveCollection(close_after, exit_after);
709 // Wait until it is closed.
710 try {
711 synchronized(this) {
712 while(Gatherer.c_man.reallyReady()) {
713 wait(10);
714 }
715 }
716 }
717 catch(Exception error) {
718 Gatherer.println("Exception: " + error);
719 Gatherer.printStackTrace(error);
720 }
721
722 //content_pane.paintImmediately(bounds);
723 return true;
724 //case SaveCollectionBox.SAVE_NO:
725 // Close collection.
726 // if(close_after) {
727 // tab_pane.setSelectedComponent(collection_pane);
728 // Gatherer.c_man.closeCollection();
729 // }
730 // if(exit_after) {
731 // Gatherer.self.exit();
732 // }
733 // return true;
734 //default:
735 // return false;
736 //}
737 }
738 /** 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.
739 * @param event A ChangeEvent containing information about the event that fired this call.
740 */
741 public void stateChanged(ChangeEvent event) {
742 if(previous_pane != null) {
743 if(previous_pane == create_pane) {
744 create_pane.loseFocus();
745 }
746 }
747 // "View assigned metadata" menu item is disabled by default
748 menu_bar.metadata_view.setCanEnable(false);
749 menu_bar.setMetaAuditSuffix(null);
750
751 menu_bar.tabSelected(tab_pane.getSelectedIndex());
752 if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(collection_pane)) {
753 collection_pane.gainFocus();
754 // "View assigned metadata" menu item is enabled for the "Gather" pane
755 menu_bar.metadata_view.setCanEnable(true);
756 }
757 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(metaedit_pane)) {
758 metaedit_pane.gainFocus();
759 // "View assigned metadata" menu item is enabled for the "Enrich" pane
760 menu_bar.metadata_view.setCanEnable(true);
761 }
762 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(config_pane)) {
763 config_pane.gainFocus();
764 }
765 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(create_pane)) {
766 create_pane.gainFocus();
767 }
768 else if(tab_pane.getSelectedIndex() == tab_pane.indexOfComponent(preview_pane)) {
769 config_pane.saveConfiguration();
770 preview_pane.gainFocus();
771 }
772
773 previous_pane = (JPanel) tab_pane.getSelectedComponent();
774 }
775
776 public void wait(boolean waiting) {
777 Component glass_pane = getGlassPane();
778 if(waiting) {
779 // Show wait cursor.
780 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
781 glass_pane.setVisible(true);
782 }
783 else {
784 // Hide wait cursor.
785 glass_pane.setVisible(false);
786 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
787 }
788 glass_pane = null;
789 }
790
791 public void workflowUpdate(String raw, boolean state) {
792 WorkflowUpdater task = new WorkflowUpdater(raw, state);
793 SwingUtilities.invokeLater(task);
794 task = null;
795 }
796
797 /** Retrieves a phrase from the Dictionary based on the key.
798 * @param key A <strong>String</strong> uniquely identifying a phrase from the Dictionary.
799 * @return The desired phrase as a <strong>String</strong>.
800 * @see org.greenstone.gatherer.Dictionary
801 */
802 private String get(String key) {
803 return get(key, null);
804 }
805 /** Retrieves a phrase from the Dictionary based on the key and including the arguments.
806 * @param key A <strong>String</strong> uniquely identifying a phrase from the Dictionary.
807 * @param args A <strong>String[]</strong> of arguments available to be inserted into the phrase.
808 * @return The desired phrase as a <strong>String</strong>.
809 * @see org.greenstone.gatherer.Dictionary
810 */
811 private String get(String key, String args[]) {
812 if(key.indexOf('.') == -1) {
813 key = "GUI." + key;
814 }
815 return Gatherer.dictionary.get(key, args);
816 }
817 /** 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.
818 * @return <i>true</i> if we should wait for a thread, <i>false</i> if it is safe to continue.
819 */
820 private boolean waitForThread() {
821 Thread active[] = new Thread[thread_group.activeCount()];
822 int size = thread_group.enumerate(active);
823 for(int i = 0; i < size; i++) {
824 if(active[i].getName().equals(GShell.GSHELL_BUILD) ||
825 active[i].getName().equals(GShell.GSHELL_IMPORT) ||
826 active[i].getName().equals(GShell.GSHELL_NEW)) {
827 return true;
828 }
829 }
830 return false;
831 }
832
833
834 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
835 * @param event A <strong>WindowEvent</strong> containing information about the event that fred this call.
836 */
837 protected void processWindowEvent(WindowEvent event) {
838 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
839 exit();
840 }
841 }
842 /** 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.
843 */
844 private class MenuListenerImpl
845 implements MenuListener {
846 /** Called whenever a popup menu is hidden, but we don't care.
847 * @param e Some <strong>MenuEvent</strong> that we could care less about.
848 */
849 public void menuCanceled(MenuEvent e) {
850 }
851 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
852 * @param e Some <strong>MenuEvent</strong> that we could care less about.
853 */
854 public void menuDeselected(MenuEvent e) {
855 }
856 /** 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.
857 * @param e The <strong>MenuEvent</strong> whose source is checked.
858 */
859 public void menuSelected(MenuEvent e) {
860 if(e.getSource() == menu_bar.help) {
861 if(menu_bar.help.isSelected()) {
862 menu_bar.help.doClick(10);
863 }
864 }
865 }
866 }
867 private class TabUpdater
868 implements Runnable {
869 private boolean ready = false;
870 private int browse_pos = -1;
871 private int mirror_pos = -1;
872 private int config_pos = -1;
873 private int create_pos = -1;
874 private int export_pos = -1;
875 private int metaedit_pos = -1;
876 private int preview_pos = -1;
877 private JTabbedPane tab_pane = null;
878 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
879 this.ready = ready;
880 this.tab_pane = tab_pane;
881 browse_pos = tab_pane.indexOfComponent(browser_pane);
882 mirror_pos = tab_pane.indexOfComponent(mirror_pane);
883 metaedit_pos = tab_pane.indexOfComponent(metaedit_pane);
884 config_pos = tab_pane.indexOfComponent(config_pane);
885 export_pos = tab_pane.indexOfComponent(export_pane);
886 create_pos = tab_pane.indexOfComponent(create_pane);
887 preview_pos = tab_pane.indexOfComponent(preview_pane);
888 }
889 public void run() {
890 if(browse_pos != -1) {
891 if(ready) {
892 tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", false));
893 }
894 else {
895 tab_pane.setEnabledAt(browse_pos, Gatherer.config.get("workflow.browse", true));
896 }
897 }
898 if(mirror_pos != -1) {
899 if(ready) {
900 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", false));
901 }
902 else {
903 tab_pane.setEnabledAt(mirror_pos, Gatherer.config.get("workflow.mirror", true));
904 }
905 }
906 if(metaedit_pos != -1) {
907 tab_pane.setEnabledAt(metaedit_pos, ready && Gatherer.config.get("workflow.enrich", false));
908 }
909 if(config_pos != -1) {
910 tab_pane.setEnabledAt(config_pos, ready && Gatherer.config.get("workflow.design", false));
911 }
912 if(export_pos != -1) {
913 tab_pane.setEnabledAt(export_pos, ready && Gatherer.config.get("workflow.export", false));
914 }
915 if(create_pos != -1) {
916 tab_pane.setEnabledAt(create_pos, ready && Gatherer.config.get("workflow.create", false));
917 }
918 if(preview_pos != -1) {
919 tab_pane.setEnabledAt(preview_pos, Gatherer.c_man != null && Gatherer.c_man.built() && Gatherer.config.get("workflow.preview", false));
920 }
921 }
922 public void setReady(boolean ready) {
923 this.ready = ready;
924 }
925 }
926
927 private class WorkflowUpdater
928 implements Runnable {
929 private boolean state;
930 private String raw;
931 public WorkflowUpdater(String raw, boolean state) {
932 this.raw = raw;
933 this.state = state;
934 }
935 public void run() {
936 setTabEnabled(raw, state);
937 }
938 }
939}
Note: See TracBrowser for help on using the repository browser.