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

Last change on this file since 4659 was 4659, checked in by kjdon, 21 years ago

added back in the delete collection functionality

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