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

Last change on this file since 18376 was 18370, checked in by kjdon, 15 years ago

committed code submitted by Amin Hedjazi for making the GLI right to left. I worked on this code on the rtl-gli branch, then merged the branch back to the trunk at revision 18368. The branch code was slightly different in a couple of places where it shouldn't have been. So don't use the branch code next time. Start a new branch.

  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 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("downloadingfiles");
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.getName();
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_small.gif";
355 if (Configuration.fedora_info.isActive()) {
356 gsmall_image = "fli-" + gsmall_image;
357 }
358 this.setIconImage(JarTools.getImage(gsmall_image).getImage());
359 // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
360 content_pane.setLayout(new BorderLayout());
361 // Create the menu-bar and stick it up the top.
362 menu_bar = new MenuBar(new MenuListenerImpl());
363 menu_bar.setComponentOrientation(Dictionary.getOrientation());
364
365 //feedback changes
366 //content_pane.add(menu_bar, BorderLayout.NORTH);
367 this.setJMenuBar(menu_bar);
368 // end feedback changes
369
370 // Create the tabbed pane and plop it in the center where it will
371 // expand to consume all available space like any good gas would.
372 tab_pane = new JTabbedPane();
373 tab_pane.setComponentOrientation(Dictionary.getOrientation());
374 tab_pane.addChangeListener(this);
375 tab_pane.setFont(Configuration.getFont("general.font", false));
376
377 if (Configuration.get("workflow.download", true)) {
378 download_pane = new DownloadPane();
379 // "GUI.Download_Tooltip" is used automatically
380 tab_pane.addTab(Dictionary.get("GUI.Download"), JarTools.getImage("download.gif"), download_pane, Dictionary.get("GUI.Download_Tooltip"));
381 tab_pane.setEnabledAt(tab_pane.indexOfComponent(download_pane), Configuration.get("workflow.download", false));
382 }
383
384 gather_pane = new GatherPane();
385 gather_pane.display();
386 if (Configuration.get("workflow.gather", true)) {
387 // "GUI.Gather_Tooltip" is used automatically
388 tab_pane.addTab(Dictionary.get("GUI.Gather"), JarTools.getImage("gather.gif"), gather_pane, Dictionary.get("GUI.Gather_Tooltip"));
389 tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Configuration.get("workflow.gather", false));
390 }
391
392 enrich_pane = new EnrichPane();
393 enrich_pane.display();
394 if (Configuration.get("workflow.enrich", true)) {
395 // "GUI.Enrich_Tooltip" is used automatically
396 tab_pane.addTab(Dictionary.get("GUI.Enrich"), JarTools.getImage("enrich.gif"), enrich_pane, Dictionary.get("GUI.Enrich_Tooltip"));
397 tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
398 }
399
400 design_pane = new DesignPane();
401 design_pane.display();
402 if (Configuration.get("workflow.design", true)) {
403 // "GUI.Design_Tooltip" is used automatically
404 if (Configuration.fedora_info.isActive()) {
405 tab_pane.addTab("Plugins", JarTools.getImage("design.gif"), design_pane, Dictionary.get("GUI.Design_Tooltip"));
406 }
407 else {
408 tab_pane.addTab(Dictionary.get("GUI.Design"), JarTools.getImage("design.gif"), design_pane, Dictionary.get("GUI.Design_Tooltip"));
409 }
410
411 tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
412 }
413
414 create_pane = new CreatePane();
415 create_pane.setComponentOrientation(Dictionary.getOrientation());
416 create_pane.display();
417 if (Configuration.get("workflow.create", true)) {
418 // "GUI.Create_Tooltip" is used automatically
419 tab_pane.addTab(Dictionary.get("GUI.Create"), JarTools.getImage("create.gif"), create_pane, Dictionary.get("GUI.Create_Tooltip"));
420 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
421 }
422
423 format_pane = new FormatPane();
424 format_pane.setComponentOrientation(Dictionary.getOrientation());
425 format_pane.display();
426 if (Configuration.get("workflow.format", true)) {
427 tab_pane.addTab(Dictionary.get("GUI.Format"), JarTools.getImage("format.gif"), format_pane, Dictionary.get("GUI.Format_Tooltip"));
428 tab_pane.setEnabledAt(tab_pane.indexOfComponent(format_pane), false);
429 }
430
431 // The MetaAuditFrame must be created after the gather/enrich panes but before they get focus
432 meta_audit = new MetaAuditFrame();
433 meta_audit.setComponentOrientation(Dictionary.getOrientation());
434 // Select the collect pane if it is available
435 if (tab_pane.indexOfComponent(gather_pane) != -1) {
436 tab_pane.setSelectedComponent(gather_pane);
437 }
438 // Otherwise find the first tab that is enabled and select that.
439 else {
440 for (int i = 0; i < tab_pane.getTabCount(); i++) {
441 if (tab_pane.isEnabledAt(i)) {
442 tab_pane.setSelectedIndex(i);
443 break;
444 }
445 }
446 }
447
448 content_pane.add(tab_pane, BorderLayout.CENTER);
449
450 // Add an extra progress bar at the bottom of every screen when using a remote Greenstone server
451 if (Gatherer.isGsdlRemote) {
452 JPanel remote_greenstone_server_progress_panel = new JPanel();
453 //remote_greenstone_server_progress_panel.setComponentOrientation(Dictionary.getOrientation());
454 JLabel remote_greenstone_server_progress_label = new JLabel(Dictionary.get("RemoteGreenstoneServer.Progress"));
455 //remote_greenstone_server_progress_label.setComponentOrientation(Dictionary.getOrientation());
456 remote_greenstone_server_progress_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
457 remote_greenstone_server_progress_panel.setLayout(new BorderLayout());
458 remote_greenstone_server_progress_panel.add(remote_greenstone_server_progress_label, BorderLayout.LINE_START);
459 remote_greenstone_server_progress_panel.add(Gatherer.remoteGreenstoneServer.getProgressBar(), BorderLayout.CENTER);
460 content_pane.add(remote_greenstone_server_progress_panel, BorderLayout.SOUTH);
461 }
462
463 // Call refresh to update all controls to reflect current collection status.
464 refresh(-1, Gatherer.c_man.ready());
465 }
466 catch (Exception e) {
467 DebugStream.printStackTrace(e);
468 // The GUI failing to build is an app killer
469 e.printStackTrace();
470 System.exit(1);
471 }
472 }
473
474 public void exit()
475 {
476 exit(0);
477 }
478
479 /** This method ensures that all the things needing saving are saved before Gatherer.exit() is called.
480 */
481 public void exit(int exit_status)
482 {
483 // If we have a collection open remember it for next time, then save it and close it
484 if (Gatherer.c_man.ready()) {
485 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
486 true, CollectionManager.getLoadedCollectionColFilePath());
487 saveThenCloseCurrentCollection();
488 }
489 else {
490 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true, null);
491 }
492
493 // Store the current position and size of the GLI for next time
494 Configuration.setBounds("general.bounds", true, getBounds());
495
496 // Save configuration
497 Configuration.save();
498
499 // Hide the main window
500 setVisible(false);
501
502 // If we're running as an applet we don't quit here (we quit when the browser calls GathererApplet.destroy())
503 if (!Gatherer.isApplet) {
504 Gatherer.exit(exit_status);
505 }
506 }
507
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 {
513 locked = lock;
514
515 if (import_stage) {
516 int gather_pos = tab_pane.indexOfComponent(gather_pane);
517 if (gather_pos != -1) {
518 tab_pane.setEnabledAt(gather_pos, !lock);
519 }
520 int enrich_pos = tab_pane.indexOfComponent(enrich_pane);
521 if (enrich_pos != -1) {
522 tab_pane.setEnabledAt(enrich_pos, !lock);
523 }
524 }
525
526 int design_pos = tab_pane.indexOfComponent(design_pane);
527 if (design_pos != -1) {
528 tab_pane.setEnabledAt(design_pos, !lock);
529 }
530 }
531
532
533 public void modeChanged(int mode) {
534 // Set the title
535 String collection_title = null;
536 String collection_name = null;
537 if (Gatherer.c_man.ready()) {
538 Collection collection = Gatherer.c_man.getCollection();
539 collection_title = collection.getTitle();
540 collection_name = collection.getName();
541 collection = null;
542 }
543 setTitle(collection_title, collection_name);
544 collection_title = null;
545 collection_name = null;
546 // Now pass on the message to anyone who cares
547 if (download_pane != null) {
548 download_pane.modeChanged(mode);
549 }
550 if (gather_pane != null) {
551 gather_pane.modeChanged(mode);
552 }
553 if (enrich_pane != null) {
554 enrich_pane.modeChanged(mode);
555 }
556 if (design_pane != null) {
557 design_pane.modeChanged(mode);
558 }
559 if (create_pane != null) {
560 create_pane.modeChanged(mode);
561 }
562 if (format_pane != null) {
563 format_pane.modeChanged(mode);
564 }
565 }
566
567
568 public void refresh(int refresh_reason, boolean collection_loaded)
569 {
570 // Set the collection information in the title bar
571 if (collection_loaded) {
572 Collection collection = Gatherer.c_man.getCollection();
573 setTitle(collection.getTitle(), collection.getName());
574 }
575 else {
576 setTitle(null, null);
577 }
578
579 // Update the menu bar
580 menu_bar.refresh(refresh_reason, collection_loaded);
581
582 // Update the loaded panes
583 if (download_pane != null) {
584 download_pane.refresh(refresh_reason, collection_loaded);
585 }
586 if (gather_pane != null) {
587 gather_pane.refresh(refresh_reason, collection_loaded);
588 }
589 if (enrich_pane != null) {
590 enrich_pane.refresh(refresh_reason, collection_loaded);
591 }
592 if (design_pane != null) {
593 design_pane.refresh(refresh_reason, collection_loaded);
594 }
595 if (create_pane != null) {
596 create_pane.refresh(refresh_reason, collection_loaded);
597 }
598 if (format_pane != null) {
599 format_pane.refresh(refresh_reason, collection_loaded);
600 }
601
602 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
603 if (!locked) {
604 if (tab_updater == null) {
605 tab_updater = new TabUpdater(tab_pane, collection_loaded);
606 }
607 else {
608 tab_updater.setReady(collection_loaded);
609 }
610 SwingUtilities.invokeLater(tab_updater);
611 }
612 }
613
614
615 public void refreshCollectionTree(int refresh_reason)
616 {
617 if (gather_pane != null) {
618 gather_pane.refreshCollectionTree(refresh_reason);
619 }
620 }
621
622
623 public void refreshWorkspaceTree(int refresh_reason)
624 {
625 if (gather_pane != null) {
626 gather_pane.refreshWorkspaceTree(refresh_reason);
627 }
628 }
629
630
631 /** Specifies whether a certain tab is enabled or not. */
632 private void setTabEnabled(String rawname, boolean state) {
633 // Retrieve the dictionary based name.
634 String name = Dictionary.get("GUI." + rawname);
635 int index = tab_pane.indexOfTab(name);
636 // Of course we may not have this tab available.
637 if(index != -1) {
638 // Some tabs are also dependant on if a collection is ready
639 Component component = tab_pane.getComponentAt(index);
640 if(component == enrich_pane || component == design_pane || component == create_pane || component == format_pane) {
641 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
642 }
643 else {
644 tab_pane.setEnabledAt(index, state);
645 }
646 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
647 if(tab_pane.getSelectedIndex() == index && !state) {
648 boolean found = false;
649 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
650 if(tab_pane.isEnabledAt(i)) {
651 tab_pane.setSelectedIndex(i);
652 found = true;
653 }
654 }
655 // If there are no tabs enabled, which should be impossible, then select the first tab
656 if(!found) {
657 tab_pane.setSelectedIndex(0);
658 }
659 }
660 }
661 }
662
663 /** 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.
664 * @param title
665 * @param name
666 */
667 public void setTitle(String title, String name) {
668 // Finally display the collection name in the title bar.
669 StringBuffer title_buffer = new StringBuffer(Configuration.getApplicationTitle());
670 title_buffer.append(StaticStrings.SPACE_CHARACTER);
671 title_buffer.append(Gatherer.PROGRAM_VERSION);
672 title_buffer.append(StaticStrings.SPACE_CHARACTER);
673 title_buffer.append(StaticStrings.SPACE_CHARACTER);
674 // Server version information
675 title_buffer.append(Gatherer.getServerVersionAsString());
676 title_buffer.append(StaticStrings.SPACE_CHARACTER);
677 title_buffer.append(StaticStrings.SPACE_CHARACTER);
678 // Describe the current user mode
679 title_buffer.append(StaticStrings.MODE_STR);
680 title_buffer.append(Configuration.getModeAsString());
681 title_buffer.append(StaticStrings.SPACE_CHARACTER);
682 title_buffer.append(StaticStrings.SPACE_CHARACTER);
683 // Now for the current collection
684 title_buffer.append(StaticStrings.COLLECTION_STR);
685 if (title != null && name != null) {
686 title_buffer.append(title);
687 title_buffer.append(StaticStrings.SPACE_CHARACTER);
688 title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
689 title_buffer.append(name);
690 title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
691 }
692 else {
693 title_buffer.append(Dictionary.get("Collection.No_Collection"));
694 }
695 this.setTitle(title_buffer.toString());
696 title_buffer = null;
697 }
698
699
700 private class OpenCollectionTask
701 extends Thread
702 {
703 public void run()
704 {
705 String collection_file_path = showOpenCollectionDialog();
706
707 // User has selected a collection to open
708 if (collection_file_path != null) {
709 // If there is already a collection open, save and close it
710 if (Gatherer.c_man.ready()) {
711 saveThenCloseCurrentCollection();
712 }
713
714 // Open the selected collection
715 Gatherer.c_man.loadCollection(collection_file_path);
716 }
717 }
718 }
719
720
721 /** When the load collection option is chosen this method is called to produce the modal file load prompt.
722 */
723 private String showOpenCollectionDialog()
724 {
725 OpenCollectionDialog dialog = new OpenCollectionDialog();
726 dialog.setComponentOrientation(Dictionary.getOrientation());
727 if (dialog.display() == OpenCollectionDialog.OK_OPTION) {
728 return dialog.getFileName();
729 }
730
731 // User must have cancelled the action
732 return null;
733 }
734
735
736 /** When called this method causes the MetadataAuditTable to display a nice dialog box which contains all the metadata assigned in the collection.
737 */
738 public void showMetaAuditBox() {
739 wait(true);
740 meta_audit.display();
741 wait(false);
742 }
743
744
745 private class NewCollectionTask
746 extends Thread
747 {
748 public void run()
749 {
750 // Create the collection details prompt from new collection prompt
751 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
752
753 // Create the new collection (if not cancelled) in a new thread.
754 if (!ncd_prompt.isCancelled()) {
755 // If there is already a collection open, save and close it.
756 if (Gatherer.c_man.ready()) {
757 saveThenCloseCurrentCollection();
758 }
759
760 // Create new collection.
761 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), new ArrayList());
762 ncd_prompt.dispose();
763 }
764
765 // Done
766 ncd_prompt = null;
767 }
768 }
769
770
771 private class DeleteCollectionTask
772 extends Thread
773 {
774 public void run()
775 {
776 // The rest is handled by the DeleteCollectionPrompt
777 DeleteCollectionPrompt dc_prompt = new DeleteCollectionPrompt();
778 if (dc_prompt.display()) {
779 //closeCurrentCollection();
780 }
781 dc_prompt.destroy();
782 dc_prompt = null;
783 }
784 }
785
786
787 /** 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.
788 * @param event A ChangeEvent containing information about the event that fired this call.
789 */
790 public void stateChanged(ChangeEvent event)
791 {
792 if (previous_pane != null) {
793 if (previous_pane == gather_pane) {
794 gather_pane.loseFocus();
795 }
796 else if (previous_pane == enrich_pane) {
797 enrich_pane.loseFocus();
798 }
799 else if (previous_pane == design_pane) {
800 design_pane.loseFocus();
801 }
802 else if (previous_pane == create_pane) {
803 create_pane.loseFocus();
804 }
805 else if (previous_pane == format_pane) {
806 format_pane.loseFocus();
807 }
808 }
809
810 menu_bar.tabSelected(tab_pane.getSelectedIndex());
811 int selected_index = tab_pane.getSelectedIndex();
812 if (selected_index == tab_pane.indexOfComponent(download_pane)) {
813 download_pane.gainFocus();
814 }
815 else if (selected_index == tab_pane.indexOfComponent(gather_pane)) {
816 gather_pane.gainFocus();
817 }
818 else if (selected_index == tab_pane.indexOfComponent(enrich_pane)) {
819 enrich_pane.gainFocus();
820 }
821 else if (selected_index == tab_pane.indexOfComponent(design_pane)) {
822 design_pane.gainFocus();
823 }
824 else if (selected_index == tab_pane.indexOfComponent(create_pane)) {
825 create_pane.gainFocus();
826 }
827 else if (selected_index == tab_pane.indexOfComponent(format_pane)) {
828 format_pane.gainFocus();
829 }
830
831 previous_pane = (JPanel) tab_pane.getSelectedComponent();
832
833 }
834
835
836 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
837
838 public void updateUI()
839 {
840 JPanel pane = (JPanel) getContentPane();
841 pane.updateUI();
842 // Also update all of the tabs according to workflow.
843 workflowUpdate("Download", Configuration.get("workflow.download", false));
844 workflowUpdate("Gather", Configuration.get("workflow.gather", false));
845 workflowUpdate("Enrich", Configuration.get("workflow.enrich", false));
846 workflowUpdate("Design", Configuration.get("workflow.design", false));
847 workflowUpdate("Create", Configuration.get("workflow.create", false));
848 workflowUpdate("Format", Configuration.get("workflow.format", false));
849 }
850
851 public void wait(boolean waiting) {
852 Component glass_pane = getGlassPane();
853 if(waiting) {
854 // Show wait cursor.
855 glass_pane.addMouseListener(mouse_blocker_listener);
856 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
857 glass_pane.setVisible(true);
858 }
859 else {
860 // Hide wait cursor.
861 glass_pane.setVisible(false);
862 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
863 glass_pane.removeMouseListener(mouse_blocker_listener);
864 }
865 glass_pane = null;
866 }
867
868 public void workflowUpdate(String raw, boolean state) {
869 WorkflowUpdater task = new WorkflowUpdater(raw, state);
870 SwingUtilities.invokeLater(task);
871 task = null;
872 }
873
874
875 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
876 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
877 */
878 protected void processWindowEvent(WindowEvent event) {
879 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
880 exit();
881 }
882 }
883
884
885 /** 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.
886 */
887 private class MenuListenerImpl
888 implements MenuListener {
889 /** Called whenever a popup menu is hidden, but we don't care.
890 * @param e Some <strong>MenuEvent</strong> that we could care less about.
891 */
892 public void menuCanceled(MenuEvent e) {
893 }
894 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
895 * @param e Some <strong>MenuEvent</strong> that we could care less about.
896 */
897 public void menuDeselected(MenuEvent e) {
898 }
899 /** 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.
900 * @param e The <strong>MenuEvent</strong> whose source is checked.
901 */
902 public void menuSelected(MenuEvent e) {
903 if(e.getSource() == menu_bar.help) {
904 if(menu_bar.help.isSelected()) {
905 menu_bar.help.doClick(10);
906 }
907 }
908 }
909 }
910
911 private class TabUpdater
912 implements Runnable {
913 private boolean ready = false;
914 private int download_pos = -1;
915 private int enrich_pos = -1;
916 private int design_pos = -1;
917 private int create_pos = -1;
918 private int format_pos = -1;
919 private int export_pos = -1;
920 private JTabbedPane tab_pane = null;
921
922 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
923 this.ready = ready;
924 this.tab_pane = tab_pane;
925 download_pos = tab_pane.indexOfComponent(download_pane);
926 enrich_pos = tab_pane.indexOfComponent(enrich_pane);
927 design_pos = tab_pane.indexOfComponent(design_pane);
928 create_pos = tab_pane.indexOfComponent(create_pane);
929 format_pos = tab_pane.indexOfComponent(format_pane);
930 }
931
932 public void run()
933 {
934 if (download_pos != -1) {
935 if (ready) {
936 tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", false));
937 }
938 else {
939 tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", true));
940 }
941 }
942 if (enrich_pos != -1) {
943 tab_pane.setEnabledAt(enrich_pos, ready && Configuration.get("workflow.enrich", false));
944 }
945 if (design_pos != -1) {
946 tab_pane.setEnabledAt(design_pos, ready && Configuration.get("workflow.design", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
947 }
948 if (create_pos != -1) {
949 tab_pane.setEnabledAt(create_pos, ready && Configuration.get("workflow.create", false));
950 }
951 if (format_pos != -1) {
952 tab_pane.setEnabledAt(format_pos, ready && Configuration.get("workflow.format", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
953 }
954 }
955
956 public void setReady(boolean ready) {
957 this.ready = ready;
958 }
959 }
960
961 private class WorkflowUpdater
962 implements Runnable {
963 private boolean state;
964 private String raw;
965 public WorkflowUpdater(String raw, boolean state) {
966 this.raw = raw;
967 this.state = state;
968 }
969 public void run() {
970 setTabEnabled(raw, state);
971 }
972 }
973}
Note: See TracBrowser for help on using the repository browser.