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

Last change on this file since 23031 was 23031, checked in by ak19, 14 years ago

More changes to 2. Gatherer.java to allow empty string into config.xml for when the current collect dir is the default collect dir and 2. swapping between user names in applet (no longer loads open collections, because all collections are closed on exiting the applet).

  • Property svn:keywords set to Author Date Id Revision
File size: 34.7 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui;
38
39import java.awt.*;
40import java.awt.datatransfer.*;
41import java.awt.event.*;
42import java.io.File;
43import java.lang.*;
44import java.net.*;
45import java.util.*;
46import javax.swing.*;
47import javax.swing.event.*;
48import javax.swing.filechooser.*;
49import javax.swing.plaf.*;
50import javax.swing.text.*;
51import org.greenstone.gatherer.Configuration;
52import org.greenstone.gatherer.DebugStream;
53import org.greenstone.gatherer.Dictionary;
54import org.greenstone.gatherer.Gatherer;
55import org.greenstone.gatherer.collection.Collection;
56import org.greenstone.gatherer.collection.CollectionManager;
57import org.greenstone.gatherer.file.FileOpenActionListener;
58import org.greenstone.gatherer.file.WorkspaceTree;
59import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
60import org.greenstone.gatherer.gui.tree.DragTree;
61import org.greenstone.gatherer.metadata.MetadataSet;
62import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
63import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
64import org.greenstone.gatherer.util.JarTools;
65import org.greenstone.gatherer.util.StaticStrings;
66import org.greenstone.gatherer.util.Utility;
67
68/** 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. */
69public class GUIManager
70 extends JFrame
71 implements ActionListener, ChangeListener, WindowFocusListener{
72 /** The download pane contains controls for downloading internet sites. */
73 public DownloadPane download_pane = null;
74 /** The gather pane is more like a file manager where you drag files from one tree to another. */
75 public GatherPane gather_pane = null;
76 /** The enrich pane is used to assign, edit and remove metadata from files within the collection. */
77 public EnrichPane enrich_pane = null;
78 /** The design pane allows you to edit the design of the library in terms of the collection configuration file. - the stuff that requires rebuilding */
79 public DesignPane design_pane = null;
80 /** The create pane contains scripting options for importing and building collections into libraries. */
81 public CreatePane create_pane = null;
82 /** The format pane allows you to edit the design of the library in terms of the collection configuration file. - the stuff that doesn't require rebuilding */
83 public FormatPane format_pane = null;
84
85 public FileOpenActionListener foa_listener = new FileOpenActionListener();
86
87
88 /** A reference to the currently instantiated help window, if any. */
89 private HelpFrame help = null;
90 /** The menu bar. */
91 public MenuBar menu_bar = null;
92 public MetaAuditFrame meta_audit;
93 /** Are certain panes currently locked? */
94 private boolean locked = false;
95 /** The size of the Gatherer window. */
96 private Dimension size = null;
97 /** The panel within the window that other components are placed on. */
98 private JPanel content_pane = null;
99 /** The last view pane selected. */
100 private JPanel previous_pane;
101 /** The main tab pane containing the different views, available here to trap view change events. */
102 private JTabbedPane tab_pane = null;
103 /** A threaded tab changer to try and avoid NPE on exit. */
104 private TabUpdater tab_updater = null;
105
106
107
108
109
110 final static String newline = "\n";
111 final static String space = " ";
112
113
114 /**Constructor. Enable window events and arranges all other components.
115 * @param size The intial <strong>Dimension</strong> of the screen.
116 */
117 public GUIManager(Dimension size) {
118 super();
119 this.setComponentOrientation(Dictionary.getOrientation());
120 // Initialization
121 this.help = new HelpFrame();
122 this.size = size;
123
124 this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
125
126 // Add a focus listener to ourselves. Thus if we gain focus when a Modal Dialog should instead have it, we can try to bring the modal dialog to the fore.
127 this.addFocusListener(new GLIGUIFocusListener());
128
129 this.addWindowFocusListener(this);
130
131 // Make the Tool tip hang around for a rediculous amount of time.
132 ToolTipManager.sharedInstance().setDismissDelay(10000);
133
134 // Set up some other UI stuff. (fonts handled in Gatherer.main())
135 UIManager.put("FileChooser.lookInLabelText", Dictionary.get("SaveCollectionBox.Look_In"));
136 UIManager.put("FileChooser.filesOfTypeLabelText", Dictionary.get("SaveCollectionBox.Files_Of_Type"));
137 UIManager.put("FileChooser.fileNameLabelText", Dictionary.get("SaveCollectionBox.File_Name"));
138 }
139
140
141 public void windowGainedFocus(WindowEvent e)
142 {
143 }
144
145
146 public void windowLostFocus(WindowEvent e)
147 {
148 // Save the loaded collection
149 if (Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.getCollection().cdm != null) {
150 Gatherer.c_man.saveCollection();
151 }
152 }
153
154
155 private class GLIGUIFocusListener
156 extends FocusAdapter {
157 public void focusGained(FocusEvent e) {
158 if (ModalDialog.current_modal != null) {
159 ModalDialog.current_modal.makeVisible();
160 ModalDialog.current_modal.toFront();
161 }
162 }
163 }
164
165 /** 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.
166 * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
167 */
168 public void actionPerformed(ActionEvent event) {
169 Object esrc = event.getSource();
170 // *************
171 // File Options.
172 // *************
173 if (esrc == menu_bar.file_associations) {
174 Gatherer.assoc_man.edit();
175 }
176 else if (esrc == menu_bar.file_close) {
177 saveThenCloseCurrentCollection();
178 }
179 else if (esrc == menu_bar.file_delete) {
180 new DeleteCollectionTask().start();
181 }
182 else if (esrc == menu_bar.file_cdimage) {
183 WriteCDImagePrompt wcdip = new WriteCDImagePrompt();
184 wcdip.display();
185 wcdip.destroy();
186 wcdip = null;
187 }
188 else if (esrc == menu_bar.file_exportas) {
189 ExportAsPrompt eap = new ExportAsPrompt();
190 eap.display();
191 eap.destroy();
192 eap = null;
193 }
194 else if (esrc == menu_bar.file_exit) {
195 exit();
196 }
197 else if (esrc == menu_bar.file_new) {
198 new NewCollectionTask().start();
199 }
200 else if (esrc == menu_bar.file_open) {
201 new OpenCollectionTask().start();
202 }
203 else if (esrc == menu_bar.file_options) {
204 new Preferences();
205 }
206 else if (esrc == menu_bar.file_save) {
207 // Very important: make sure metadata values are saved too
208 enrich_pane.stopEditingAndRebuild();
209 // Make sure all the metadata has been saved to file
210 MetadataXMLFileManager.saveMetadataXMLFiles();
211
212 Gatherer.c_man.saveCollection();
213 }
214
215 // *************
216 // Edit Options.
217 // *************
218 else if(esrc == menu_bar.edit_copy) {
219 try {
220 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
221 // Get the component with selected text as a JTextComponent
222 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
223 text.copy();
224 }
225 catch (Exception cce) {
226 // If the component is not a text component ignore the copy command
227 DebugStream.println(cce.toString());
228 }
229 }
230 else if(esrc == menu_bar.edit_cut) {
231 try {
232 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
233 // Get the component with selected text as a JTextComponent
234 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
235 // Cut the text to the clipboard
236 text.cut();
237 }
238 catch (ClassCastException cce) {
239 // If the component is not a text component ignore the cut command
240 DebugStream.println(cce.toString());
241 }
242 }
243 else if(esrc == menu_bar.edit_paste) {
244 try {
245 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
246 // Get the component with selected text as a JTextComponent
247 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
248 // Cut the text to the clipboard
249 text.paste();
250 }
251 catch (ClassCastException cce) {
252 // If the component is not a text component ignore the paste command
253 DebugStream.println(cce.toString());
254 }
255 }
256
257 // *************
258 // Help Options.
259 // *************
260 else if (esrc == menu_bar.help_general) {
261 HelpFrame.setView("introduction");
262 }
263 else if (esrc == menu_bar.help_download) {
264 HelpFrame.setView("themirrorview");
265 }
266 else if (esrc == menu_bar.help_gather) {
267 HelpFrame.setView("collectingfiles");
268 }
269 else if (esrc == menu_bar.help_enrich) {
270 HelpFrame.setView("enrichingacollection");
271 }
272 else if (esrc == menu_bar.help_design) {
273 HelpFrame.setView("designingacollection");
274 }
275 else if (esrc == menu_bar.help_create) {
276 HelpFrame.setView("producingthecollection");
277 }
278 else if (esrc == menu_bar.help_format) {
279 HelpFrame.setView("formattingacollection");
280 }
281 else if (esrc == menu_bar.help_about) {
282 new AboutDialog(this);
283 }
284 }
285
286
287 /** 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.
288 */
289 public void afterDisplay() {
290 if (download_pane != null) {
291 download_pane.afterDisplay();
292 }
293 enrich_pane.afterDisplay();
294 }
295
296
297 public void closeCurrentCollection()
298 {
299 tab_pane.setSelectedComponent(gather_pane);
300 Gatherer.c_man.closeCollection();
301 }
302
303
304 public void saveThenCloseCurrentCollection()
305 {
306 Gatherer.c_man.saveCollection();
307 closeCurrentCollection();
308 }
309
310
311 /** This is called when we're absolutely finished with the GLI. It is *not* called when the applet is suspended.
312 */
313 public void destroy()
314 {
315 // Destroying create pane ensures the latest log has been closed
316 if (create_pane != null) {
317 create_pane.destroy();
318 }
319
320 // Deal to help
321 if (help != null) {
322 help.destroy();
323 help = null;
324 }
325 }
326
327
328 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
329 */
330 public void display() {
331 content_pane = (JPanel) this.getContentPane();
332 content_pane.setComponentOrientation(Dictionary.getOrientation());
333
334 // Enable window-type events to be fired.
335 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
336 // Initialise and layout sub-components, plus other window dressing.
337 try {
338 this.setSize(size);
339
340 // Set the title
341 String collection_title = null;
342 String collection_name = null;
343 if (Gatherer.c_man.ready()) {
344 Collection collection = Gatherer.c_man.getCollection();
345 collection_title = collection.getTitle();
346 collection_name = collection.getGroupQualifiedName(true);
347 collection = null;
348 }
349 setTitle(collection_title, collection_name);
350 collection_title = null;
351 collection_name = null;
352
353 // Pretty corner icon
354 String gsmall_image = "gatherer.png";
355 if (Configuration.fedora_info.isActive()) {
356 gsmall_image = "fli-" + gsmall_image;
357 }
358 if(Gatherer.isGsdlRemote) {
359 gsmall_image = "client-" + gsmall_image;
360 }
361 this.setIconImage(JarTools.getImage(gsmall_image).getImage());
362 // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
363 content_pane.setLayout(new BorderLayout());
364 // Create the menu-bar and stick it up the top.
365 menu_bar = new MenuBar(new MenuListenerImpl());
366 menu_bar.setComponentOrientation(Dictionary.getOrientation());
367
368 //feedback changes
369 //content_pane.add(menu_bar, BorderLayout.NORTH);
370 this.setJMenuBar(menu_bar);
371 // end feedback changes
372
373 // Create the tabbed pane and plop it in the center where it will
374 // expand to consume all available space like any good gas would.
375 tab_pane = new JTabbedPane();
376 tab_pane.setComponentOrientation(Dictionary.getOrientation());
377 tab_pane.addChangeListener(this);
378 tab_pane.setFont(Configuration.getFont("general.font", false));
379
380 if (Configuration.get("workflow.download", true) && Gatherer.isDownloadEnabled) {
381 download_pane = new DownloadPane();
382 // "GUI.Download_Tooltip" is used automatically
383 tab_pane.addTab(Dictionary.get("GUI.Download"), JarTools.getImage("download.gif"), download_pane, Dictionary.get("GUI.Download_Tooltip"));
384 tab_pane.setEnabledAt(tab_pane.indexOfComponent(download_pane), Configuration.get("workflow.download", false));
385 }
386
387 gather_pane = new GatherPane();
388 gather_pane.display();
389 if (Configuration.get("workflow.gather", true)) {
390 // "GUI.Gather_Tooltip" is used automatically
391 tab_pane.addTab(Dictionary.get("GUI.Gather"), JarTools.getImage("gather.gif"), gather_pane, Dictionary.get("GUI.Gather_Tooltip"));
392 tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Configuration.get("workflow.gather", false));
393 }
394
395 enrich_pane = new EnrichPane();
396 enrich_pane.display();
397 if (Configuration.get("workflow.enrich", true)) {
398 // "GUI.Enrich_Tooltip" is used automatically
399 tab_pane.addTab(Dictionary.get("GUI.Enrich"), JarTools.getImage("enrich.gif"), enrich_pane, Dictionary.get("GUI.Enrich_Tooltip"));
400 tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
401 }
402
403 design_pane = new DesignPane();
404 design_pane.display();
405 if (Configuration.get("workflow.design", true)) {
406 // "GUI.Design_Tooltip" is used automatically
407 if (Configuration.fedora_info.isActive()) {
408 tab_pane.addTab("Plugins", JarTools.getImage("design.gif"), design_pane, Dictionary.get("GUI.Design_Tooltip"));
409 }
410 else {
411 tab_pane.addTab(Dictionary.get("GUI.Design"), JarTools.getImage("design.gif"), design_pane, Dictionary.get("GUI.Design_Tooltip"));
412 }
413
414 tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
415 }
416
417 create_pane = new CreatePane();
418 create_pane.setComponentOrientation(Dictionary.getOrientation());
419 create_pane.display();
420 if (Configuration.get("workflow.create", true)) {
421 // "GUI.Create_Tooltip" is used automatically
422 tab_pane.addTab(Dictionary.get("GUI.Create"), JarTools.getImage("create.gif"), create_pane, Dictionary.get("GUI.Create_Tooltip"));
423 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
424 }
425
426 format_pane = new FormatPane();
427 format_pane.setComponentOrientation(Dictionary.getOrientation());
428 format_pane.display();
429 if (Configuration.get("workflow.format", true)) {
430 tab_pane.addTab(Dictionary.get("GUI.Format"), JarTools.getImage("format.gif"), format_pane, Dictionary.get("GUI.Format_Tooltip"));
431 tab_pane.setEnabledAt(tab_pane.indexOfComponent(format_pane), false);
432 }
433
434 // The MetaAuditFrame must be created after the gather/enrich panes but before they get focus
435 meta_audit = new MetaAuditFrame();
436 meta_audit.setComponentOrientation(Dictionary.getOrientation());
437 // Select the collect pane if it is available
438 if (tab_pane.indexOfComponent(gather_pane) != -1) {
439 tab_pane.setSelectedComponent(gather_pane);
440 }
441 // Otherwise find the first tab that is enabled and select that.
442 else {
443 for (int i = 0; i < tab_pane.getTabCount(); i++) {
444 if (tab_pane.isEnabledAt(i)) {
445 tab_pane.setSelectedIndex(i);
446 break;
447 }
448 }
449 }
450
451 content_pane.add(tab_pane, BorderLayout.CENTER);
452
453 // Add an extra progress bar at the bottom of every screen when using a remote Greenstone server
454 if (Gatherer.isGsdlRemote) {
455 JPanel remote_greenstone_server_progress_panel = new JPanel();
456 //remote_greenstone_server_progress_panel.setComponentOrientation(Dictionary.getOrientation());
457 JLabel remote_greenstone_server_progress_label = new JLabel(Dictionary.get("RemoteGreenstoneServer.Progress"));
458 //remote_greenstone_server_progress_label.setComponentOrientation(Dictionary.getOrientation());
459 remote_greenstone_server_progress_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
460 remote_greenstone_server_progress_panel.setLayout(new BorderLayout());
461 remote_greenstone_server_progress_panel.add(remote_greenstone_server_progress_label, BorderLayout.LINE_START);
462 remote_greenstone_server_progress_panel.add(Gatherer.remoteGreenstoneServer.getProgressBar(), BorderLayout.CENTER);
463 content_pane.add(remote_greenstone_server_progress_panel, BorderLayout.SOUTH);
464 }
465
466 // Call refresh to update all controls to reflect current collection status.
467 refresh(-1, Gatherer.c_man.ready());
468 }
469 catch (Exception e) {
470 DebugStream.printStackTrace(e);
471 // The GUI failing to build is an app killer
472 e.printStackTrace();
473 System.exit(1);
474 }
475 }
476
477 public void exit()
478 {
479 exit(0);
480 }
481
482 // some cases we have already saved the collection, but don't want to
483 // override the general.open_collection value here
484 public void exitNoCollectionSave(int exit_status) {
485 // Store the current position and size of the GLI for next time
486 Configuration.setBounds("general.bounds", true, getBounds());
487
488 // Save configuration
489 Configuration.save();
490
491 // Hide the main window
492 setVisible(false);
493
494 // If we're running as an applet we don't quit here (we quit when the browser calls GathererApplet.destroy())
495 if (!Gatherer.isApplet) {
496 Gatherer.exit(exit_status);
497 }
498
499 }
500 /** This method ensures that all the things needing saving are saved before Gatherer.exit() is called.
501 */
502 public void exit(int exit_status)
503 {
504 // If we have a collection open remember it for next time, then save it and close it
505 if (Gatherer.c_man.ready()) {
506 // but we no longer remember open collections for remote GLI, as this causes problems
507 // in applets when other users on a machine want to use an applet and GLI wants to load
508 // a collection left open from a previous session and *requires* the old user to authenticate
509 if(Gatherer.isGsdlRemote) {
510 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
511 true, "");
512 } else {
513 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
514 true, CollectionManager.getLoadedCollectionColFilePath());
515 }
516 saveThenCloseCurrentCollection();
517 }
518 else {
519 // if there was no open collection, then write out the collect dir path for next time
520 // IF this is not the default collect directory and not a remote GLI/applet
521 if(Gatherer.isGsdlRemote || Gatherer.getCollectDirectoryPath().equals(
522 Gatherer.getDefaultGSCollectDirectoryPath(true))) {
523 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
524 true, "");
525 } else {
526 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
527 true, Gatherer.getCollectDirectoryPath());
528 }
529 }
530
531 // Store the current position and size of the GLI for next time
532 Configuration.setBounds("general.bounds", true, getBounds());
533
534 // Save configuration
535 Configuration.save();
536
537 // Hide the main window
538 setVisible(false);
539
540 // If we're running as an applet we don't quit here (we quit when the browser calls GathererApplet.destroy())
541 if (!Gatherer.isApplet) {
542 Gatherer.exit(exit_status);
543 }
544 }
545
546
547 /** 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.
548 */
549 public void lockCollection(boolean import_stage, boolean lock)
550 {
551 locked = lock;
552
553 if (import_stage) {
554 int gather_pos = tab_pane.indexOfComponent(gather_pane);
555 if (gather_pos != -1) {
556 tab_pane.setEnabledAt(gather_pos, !lock);
557 }
558 int enrich_pos = tab_pane.indexOfComponent(enrich_pane);
559 if (enrich_pos != -1) {
560 tab_pane.setEnabledAt(enrich_pos, !lock);
561 }
562 }
563
564 int design_pos = tab_pane.indexOfComponent(design_pane);
565 if (design_pos != -1) {
566 tab_pane.setEnabledAt(design_pos, !lock);
567 }
568 }
569
570
571 public void modeChanged(int mode) {
572 // Set the title
573 String collection_title = null;
574 String collection_name = null;
575 if (Gatherer.c_man.ready()) {
576 Collection collection = Gatherer.c_man.getCollection();
577 collection_title = collection.getTitle();
578 collection_name = collection.getGroupQualifiedName(true);
579 collection = null;
580 }
581 setTitle(collection_title, collection_name);
582 collection_title = null;
583 collection_name = null;
584 // Now pass on the message to anyone who cares
585 if (download_pane != null) {
586 download_pane.modeChanged(mode);
587 }
588 if (gather_pane != null) {
589 gather_pane.modeChanged(mode);
590 }
591 if (enrich_pane != null) {
592 enrich_pane.modeChanged(mode);
593 }
594 if (design_pane != null) {
595 design_pane.modeChanged(mode);
596 }
597 if (create_pane != null) {
598 create_pane.modeChanged(mode);
599 }
600 if (format_pane != null) {
601 format_pane.modeChanged(mode);
602 }
603 }
604
605
606 public void refresh(int refresh_reason, boolean collection_loaded)
607 {
608 // Set the collection information in the title bar
609 if (collection_loaded) {
610 Collection collection = Gatherer.c_man.getCollection();
611 setTitle(collection.getTitle(), collection.getGroupQualifiedName(true));
612 }
613 else {
614 setTitle(null, null);
615 }
616
617 // Update the menu bar
618 menu_bar.refresh(refresh_reason, collection_loaded);
619
620 // Update the loaded panes
621 if (download_pane != null) {
622 download_pane.refresh(refresh_reason, collection_loaded);
623 }
624 if (gather_pane != null) {
625 gather_pane.refresh(refresh_reason, collection_loaded);
626 }
627 if (enrich_pane != null) {
628 enrich_pane.refresh(refresh_reason, collection_loaded);
629 }
630 if (design_pane != null) {
631 design_pane.refresh(refresh_reason, collection_loaded);
632 }
633 if (create_pane != null) {
634 create_pane.refresh(refresh_reason, collection_loaded);
635 }
636 if (format_pane != null) {
637 format_pane.refresh(refresh_reason, collection_loaded);
638 }
639
640 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
641 if (!locked) {
642 if (tab_updater == null) {
643 tab_updater = new TabUpdater(tab_pane, collection_loaded);
644 }
645 else {
646 tab_updater.setReady(collection_loaded);
647 }
648 SwingUtilities.invokeLater(tab_updater);
649 }
650 }
651
652
653 public void refreshCollectionTree(int refresh_reason)
654 {
655 if (gather_pane != null) {
656 gather_pane.refreshCollectionTree(refresh_reason);
657 }
658 }
659
660
661 public void refreshWorkspaceTree(int refresh_reason)
662 {
663 if (gather_pane != null) {
664 gather_pane.refreshWorkspaceTree(refresh_reason);
665 }
666 }
667
668 public void refreshWorkspaceTreeGreenstoneCollections()
669 {
670 refreshWorkspaceTree(WorkspaceTree.LIBRARY_CONTENTS_CHANGED);
671 }
672
673 /** Specifies whether a certain tab is enabled or not. */
674 private void setTabEnabled(String rawname, boolean state) {
675 // Retrieve the dictionary based name.
676 String name = Dictionary.get("GUI." + rawname);
677 int index = tab_pane.indexOfTab(name);
678 // Of course we may not have this tab available.
679 if(index != -1) {
680 // Some tabs are also dependant on if a collection is ready
681 Component component = tab_pane.getComponentAt(index);
682 if(component == enrich_pane || component == design_pane || component == create_pane || component == format_pane) {
683 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
684 }
685 else {
686 tab_pane.setEnabledAt(index, state);
687 }
688 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
689 if(tab_pane.getSelectedIndex() == index && !state) {
690 boolean found = false;
691 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
692 if(tab_pane.isEnabledAt(i)) {
693 tab_pane.setSelectedIndex(i);
694 found = true;
695 }
696 }
697 // If there are no tabs enabled, which should be impossible, then select the first tab
698 if(!found) {
699 tab_pane.setSelectedIndex(0);
700 }
701 }
702 }
703 }
704
705 /** Change the string shown in the title bar of the main gui frame. If either value is null, the 'No Collection' string is shown instead.
706 * @param title
707 * @param name
708 */
709 public void setTitle(String title, String name) {
710
711 // Finally display the collection name in the title bar.
712 StringBuffer title_buffer = new StringBuffer(Configuration.getApplicationTitle());
713 title_buffer.append(StaticStrings.SPACE_CHARACTER);
714 title_buffer.append(Gatherer.PROGRAM_VERSION);
715 title_buffer.append(StaticStrings.SPACE_CHARACTER);
716 title_buffer.append(StaticStrings.SPACE_CHARACTER);
717 // Server version information
718 title_buffer.append(Gatherer.getServerVersionAsString());
719 title_buffer.append(StaticStrings.SPACE_CHARACTER);
720 title_buffer.append(StaticStrings.SPACE_CHARACTER);
721 // Describe the current user mode
722 title_buffer.append(StaticStrings.MODE_STR);
723 title_buffer.append(Configuration.getModeAsString());
724 title_buffer.append(StaticStrings.SPACE_CHARACTER);
725 title_buffer.append(StaticStrings.SPACE_CHARACTER);
726 // Now for the current collection
727 title_buffer.append(StaticStrings.COLLECTION_STR);
728 if (title != null && name != null) {
729 title_buffer.append(title);
730 title_buffer.append(StaticStrings.SPACE_CHARACTER);
731 title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
732 title_buffer.append(name);
733 title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
734 }
735 else {
736 title_buffer.append(Dictionary.get("Collection.No_Collection"));
737 }
738 this.setTitle(title_buffer.toString());
739 title_buffer = null;
740 }
741
742
743 private class OpenCollectionTask
744 extends Thread
745 {
746 public void run()
747 {
748 String collection_file_path = showOpenCollectionDialog();
749
750 // User has selected a collection to open
751 if (collection_file_path != null) {
752 // If there is already a collection open, save and close it
753 if (Gatherer.c_man.ready()) {
754 saveThenCloseCurrentCollection();
755 }
756
757 // Open the selected collection
758 Gatherer.c_man.loadCollection(collection_file_path);
759 }
760 }
761 }
762
763
764 /** When the load collection option is chosen this method is called to produce the modal file load prompt.
765 */
766 private String showOpenCollectionDialog()
767 {
768 OpenCollectionDialog dialog = new OpenCollectionDialog();
769 dialog.setComponentOrientation(Dictionary.getOrientation());
770 if (dialog.display() == OpenCollectionDialog.OK_OPTION) {
771 return dialog.getFileName();
772 }
773
774 // User must have cancelled the action
775 return null;
776 }
777
778
779 /** When called this method causes the MetadataAuditTable to display a nice dialog box which contains all the metadata assigned in the collection.
780 */
781 public void showMetaAuditBox() {
782 wait(true);
783 meta_audit.display();
784 wait(false);
785 }
786
787
788 private class NewCollectionTask
789 extends Thread
790 {
791 public void run()
792 {
793 // Create the collection details prompt from new collection prompt
794 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
795
796 // Create the new collection (if not cancelled) in a new thread.
797 if (!ncd_prompt.isCancelled()) {
798 // If there is already a collection open, save and close it.
799 if (Gatherer.c_man.ready()) {
800 saveThenCloseCurrentCollection();
801 }
802
803 // Create new collection.
804 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), new ArrayList());
805 ncd_prompt.dispose();
806 }
807
808 // Done
809 ncd_prompt = null;
810 }
811 }
812
813
814 private class DeleteCollectionTask
815 extends Thread
816 {
817 public void run()
818 {
819 // The rest is handled by the DeleteCollectionPrompt
820 DeleteCollectionPrompt dc_prompt = new DeleteCollectionPrompt();
821 if (dc_prompt.display()) {
822 //closeCurrentCollection();
823 }
824 dc_prompt.destroy();
825 dc_prompt = null;
826 }
827 }
828
829
830 /** 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.
831 * @param event A ChangeEvent containing information about the event that fired this call.
832 */
833 public void stateChanged(ChangeEvent event)
834 {
835 if (previous_pane != null) {
836 if (previous_pane == gather_pane) {
837 gather_pane.loseFocus();
838 }
839 else if (previous_pane == enrich_pane) {
840 enrich_pane.loseFocus();
841 }
842 else if (previous_pane == design_pane) {
843 design_pane.loseFocus();
844 }
845 else if (previous_pane == create_pane) {
846 create_pane.loseFocus();
847 }
848 else if (previous_pane == format_pane) {
849 format_pane.loseFocus();
850 }
851 }
852
853 menu_bar.tabSelected(tab_pane.getSelectedIndex());
854 int selected_index = tab_pane.getSelectedIndex();
855 if (selected_index == tab_pane.indexOfComponent(download_pane)) {
856 download_pane.gainFocus();
857 }
858 else if (selected_index == tab_pane.indexOfComponent(gather_pane)) {
859 gather_pane.gainFocus();
860 }
861 else if (selected_index == tab_pane.indexOfComponent(enrich_pane)) {
862 enrich_pane.gainFocus();
863 }
864 else if (selected_index == tab_pane.indexOfComponent(design_pane)) {
865 design_pane.gainFocus();
866 }
867 else if (selected_index == tab_pane.indexOfComponent(create_pane)) {
868 create_pane.gainFocus();
869 }
870 else if (selected_index == tab_pane.indexOfComponent(format_pane)) {
871 format_pane.gainFocus();
872 }
873
874 previous_pane = (JPanel) tab_pane.getSelectedComponent();
875
876 }
877
878
879 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
880
881 public void updateUI()
882 {
883 JPanel pane = (JPanel) getContentPane();
884 pane.updateUI();
885 // Also update all of the tabs according to workflow.
886 workflowUpdate("Download", Configuration.get("workflow.download", false));
887 workflowUpdate("Gather", Configuration.get("workflow.gather", false));
888 workflowUpdate("Enrich", Configuration.get("workflow.enrich", false));
889 workflowUpdate("Design", Configuration.get("workflow.design", false));
890 workflowUpdate("Create", Configuration.get("workflow.create", false));
891 workflowUpdate("Format", Configuration.get("workflow.format", false));
892 }
893
894 public void wait(boolean waiting) {
895 Component glass_pane = getGlassPane();
896 if(waiting) {
897 // Show wait cursor.
898 glass_pane.addMouseListener(mouse_blocker_listener);
899 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
900 glass_pane.setVisible(true);
901 }
902 else {
903 // Hide wait cursor.
904 glass_pane.setVisible(false);
905 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
906 glass_pane.removeMouseListener(mouse_blocker_listener);
907 }
908 glass_pane = null;
909 }
910
911 public void workflowUpdate(String raw, boolean state) {
912 WorkflowUpdater task = new WorkflowUpdater(raw, state);
913 SwingUtilities.invokeLater(task);
914 task = null;
915 }
916
917
918 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
919 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
920 */
921 protected void processWindowEvent(WindowEvent event) {
922 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
923 exit();
924 }
925 }
926
927
928 /** 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.
929 */
930 private class MenuListenerImpl
931 implements MenuListener {
932 /** Called whenever a popup menu is hidden, but we don't care.
933 * @param e Some <strong>MenuEvent</strong> that we could care less about.
934 */
935 public void menuCanceled(MenuEvent e) {
936 }
937 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
938 * @param e Some <strong>MenuEvent</strong> that we could care less about.
939 */
940 public void menuDeselected(MenuEvent e) {
941 }
942 /** 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.
943 * @param e The <strong>MenuEvent</strong> whose source is checked.
944 */
945 public void menuSelected(MenuEvent e) {
946 if(e.getSource() == menu_bar.help) {
947 if(menu_bar.help.isSelected()) {
948 menu_bar.help.doClick(10);
949 }
950 }
951 }
952 }
953
954 private class TabUpdater
955 implements Runnable {
956 private boolean ready = false;
957 private int download_pos = -1;
958 private int enrich_pos = -1;
959 private int design_pos = -1;
960 private int create_pos = -1;
961 private int format_pos = -1;
962 private int export_pos = -1;
963 private JTabbedPane tab_pane = null;
964
965 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
966 this.ready = ready;
967 this.tab_pane = tab_pane;
968 download_pos = tab_pane.indexOfComponent(download_pane);
969 enrich_pos = tab_pane.indexOfComponent(enrich_pane);
970 design_pos = tab_pane.indexOfComponent(design_pane);
971 create_pos = tab_pane.indexOfComponent(create_pane);
972 format_pos = tab_pane.indexOfComponent(format_pane);
973 }
974
975 public void run()
976 {
977 if (download_pos != -1) {
978 if (ready) {
979 tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", false));
980 }
981 else {
982 tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", true));
983 }
984 }
985 if (enrich_pos != -1) {
986 tab_pane.setEnabledAt(enrich_pos, ready && Configuration.get("workflow.enrich", false));
987 }
988 if (design_pos != -1) {
989 tab_pane.setEnabledAt(design_pos, ready && Configuration.get("workflow.design", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
990 }
991 if (create_pos != -1) {
992 tab_pane.setEnabledAt(create_pos, ready && Configuration.get("workflow.create", false));
993 }
994 if (format_pos != -1) {
995 tab_pane.setEnabledAt(format_pos, ready && Configuration.get("workflow.format", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
996 }
997 }
998
999 public void setReady(boolean ready) {
1000 this.ready = ready;
1001 }
1002 }
1003
1004 private class WorkflowUpdater
1005 implements Runnable {
1006 private boolean state;
1007 private String raw;
1008 public WorkflowUpdater(String raw, boolean state) {
1009 this.raw = raw;
1010 this.state = state;
1011 }
1012 public void run() {
1013 setTabEnabled(raw, state);
1014 }
1015 }
1016}
Note: See TracBrowser for help on using the repository browser.