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

Last change on this file since 37337 was 37337, checked in by davidb, 14 months ago

Newer version of setSize() introduced to support the new init sequence for webSwing GLI that requires login first before GLI window displayed; Fine-tuning of colours used.

  • Property svn:keywords set to Author Date Id Revision
File size: 51.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.FilenameEncoding;
62import org.greenstone.gatherer.metadata.MetadataSet;
63import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
64import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
65import org.greenstone.gatherer.util.JarTools;
66import org.greenstone.gatherer.util.StaticStrings;
67import org.greenstone.gatherer.util.Utility;
68
69import org.greenstone.gatherer.metadata.MetadataToCSV;
70
71/** 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. */
72public class GUIManager
73 extends JFrame
74 implements ActionListener, ChangeListener, WindowFocusListener{
75 /** The download pane contains controls for downloading internet sites. */
76 public DownloadPane download_pane = null;
77 /** The gather pane is more like a file manager where you drag files from one tree to another. */
78 public GatherPane gather_pane = null;
79 /** The enrich pane is used to assign, edit and remove metadata from files within the collection. */
80 public EnrichPane enrich_pane = null;
81 /** The design pane allows you to edit the design of the library in terms of the collection configuration file. - the stuff that requires rebuilding */
82 public DesignPane design_pane = null;
83 /** The create pane contains scripting options for importing and building collections into libraries. */
84 public CreatePane create_pane = null;
85 /** 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 */
86 public FormatPane format_pane = null;
87
88 public FileOpenActionListener foa_listener = new FileOpenActionListener();
89
90 /** A reference to the currently instantiated help window, if any. */
91 private HelpFrame help = null;
92 /** The menu bar. */
93 public MenuBar menu_bar = null;
94 public MetaAuditFrame meta_audit;
95 /** Are certain panes currently locked? */
96 private boolean locked = false;
97 /** The size of the Gatherer window. */
98 private Dimension size = null;
99 /** The panel within the window that other components are placed on. */
100 private JPanel content_pane = null;
101 /** The last view pane selected. */
102 private JPanel previous_pane;
103 /** The main tab pane containing the different views, available here to trap view change events. */
104 private JTabbedPane tab_pane = null;
105 /** A threaded tab changer to try and avoid NPE on exit. */
106 private TabUpdater tab_updater = null;
107
108 final static String newline = "\n";
109 final static String space = " ";
110
111
112 /**Constructor. Enable window events and arranges all other components.
113 * @param size The intial <strong>Dimension</strong> of the screen.
114 */
115 public GUIManager(Dimension size) {
116 super();
117 this.setComponentOrientation(Dictionary.getOrientation());
118 // Initialization
119 this.help = new HelpFrame();
120 this.size = size;
121
122 this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
123
124 // 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.
125 this.addFocusListener(new GLIGUIFocusListener());
126
127 this.addWindowFocusListener(this);
128
129 // Make the Tool tip hang around for a rediculous amount of time.
130 ToolTipManager.sharedInstance().setDismissDelay(10000);
131
132 // Set up some other UI stuff. (fonts handled in Gatherer.main())
133 UIManager.put("FileChooser.lookInLabelText", Dictionary.get("SaveCollectionBox.Look_In"));
134 UIManager.put("FileChooser.filesOfTypeLabelText", Dictionary.get("SaveCollectionBox.Files_Of_Type"));
135 UIManager.put("FileChooser.fileNameLabelText", Dictionary.get("SaveCollectionBox.File_Name"));
136
137 // JOptionPane options
138 // http://www.java2s.com/Tutorial/Java/0240__Swing/SettingJOptionPanebuttonlabelstoFrench.htm
139 UIManager.put("OptionPane.cancelButtonText", Dictionary.get("General.Cancel"));
140 UIManager.put("OptionPane.noButtonText", Dictionary.get("General.No"));
141 UIManager.put("OptionPane.okButtonText", Dictionary.get("General.OK"));
142 UIManager.put("OptionPane.yesButtonText", Dictionary.get("General.Yes"));
143 }
144
145 public void setSize(Dimension size)
146 {
147 this.size = size;
148 super.setSize(size);
149 }
150
151 public void windowGainedFocus(WindowEvent e)
152 {
153 }
154
155
156 public void windowLostFocus(WindowEvent e)
157 {
158 // Save the loaded collection
159 if (Gatherer.c_man != null && Gatherer.c_man.ready() && Gatherer.c_man.getCollection().cdm != null) {
160 Gatherer.c_man.saveCollection();
161 }
162 }
163
164
165 private class GLIGUIFocusListener
166 extends FocusAdapter {
167 public void focusGained(FocusEvent e) {
168 if (ModalDialog.current_modal != null) {
169 ModalDialog.current_modal.makeVisible();
170 ModalDialog.current_modal.toFront();
171 }
172 }
173 }
174
175 /** 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.
176 * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
177 */
178 public void actionPerformed(ActionEvent event) {
179 Object esrc = event.getSource();
180 // *************
181 // File Options.
182 // *************
183 if (esrc == menu_bar.file_associations) {
184 Gatherer.assoc_man.edit();
185 }
186 else if (esrc == menu_bar.file_close) {
187 saveThenCloseCurrentCollection();
188 }
189 else if (esrc == menu_bar.file_delete) {
190 //new DeleteCollectionTask().start();
191 SwingUtilities.invokeLater(new DeleteCollectionTask());
192 }
193 else if (esrc == menu_bar.file_cdimage) {
194 WriteCDImagePrompt wcdip = new WriteCDImagePrompt();
195 wcdip.display();
196 wcdip.destroy();
197 wcdip = null;
198 }
199 else if (esrc == menu_bar.file_exportas) {
200 ExportAsPrompt eap = new ExportAsPrompt();
201 TestingPreparation.setNamesRecursively(eap);
202 eap.display();
203 eap.destroy();
204 eap = null;
205 }
206 else if (esrc == menu_bar.file_exportmeta || esrc == menu_bar.file_convertmeta) {
207 String currCollName = Gatherer.c_man.getCollection().getName();
208 String collection_directory_path = CollectionManager.getCollectionDirectoryPath(currCollName);
209
210 String importDir = collection_directory_path + "import";
211
212 boolean convertMode = false;
213 String startDir = collection_directory_path;
214 if(esrc == menu_bar.file_convertmeta) {
215 startDir = importDir;
216 convertMode = true;
217 }
218
219 File csvFile = MetadataToCSV.chooseMetaCSVFile(startDir, convertMode, this);
220 if(csvFile != null) {
221 MetadataToCSV toCSV = new MetadataToCSV(collection_directory_path, csvFile);
222
223 boolean success = false;
224 if(esrc == menu_bar.file_convertmeta) {
225 success = toCSV.convertMetaXMLToCSV(csvFile, this);
226 } else {
227 success = toCSV.exportMetaXMLToCSV(csvFile);
228 }
229
230 // refresh coll view if meta.csv was created somewhere inside this coll's import folder
231 // And for remote case, also upload any new meta csv file if created anywhere inside the collection dir
232 // (incl especially its import dir) to the remote server
233 if(success && csvFile.exists() && csvFile.getAbsolutePath().startsWith(collection_directory_path)) {
234 // When the user *converts* metadata to CSV, it's set up to be easiest to create in the import folder
235 // When the user *exports* meta to CSV, it's set up to create this easiest in the collection folder
236
237 // Beware in export case: client-gli can create a metadata CSV file in the collection
238 // folder and this will get successfully uploaded and store into the collect folder
239 // on the remote server. However, when the collection is reopened in client-gli, the
240 // collection that's downloaded will NOT contain such a metadata CSV file (even though it
241 // still exists on the remote server in the collection folder) since the remote server
242 // selectively sends files across when a collection is opened.
243 // Not just anything and everything that exists in the collection folder (or its etc
244 // subfolder) is sent back to the client. There must be a reason why the GS3 server sends
245 // across some files and not others, so I'm not going to change that to incorporate any
246 // *.csv files found anywhere in the server's collection folder.
247 // When someone is using client-GLI it may not anyway make sense for them to save a file
248 // into their collection folder: the coll folder is hidden away in the gli user directory
249 // and even if client-GLI got it transferred back from the server and shows the user that
250 // their metadata.csv file exists locally, they still can't locate it that easily on
251 // their filesystem. It's best for the user to create the exported metadata in an easily
252 // located location on the client file system.
253 if(Gatherer.isGsdlRemote) {
254 Gatherer.remoteGreenstoneServer.uploadFilesIntoCollection(currCollName, new File[] {csvFile}, csvFile.getParentFile());
255 }
256 if(csvFile.getAbsolutePath().startsWith(importDir)) {
257 Gatherer.g_man.refreshCollectionTree(DragTree.COLLECTION_CONTENTS_CHANGED);
258 }
259 }
260 }
261
262 }
263 else if (esrc == menu_bar.file_exit) {
264 exit();
265 }
266 else if (esrc == menu_bar.file_new) {
267 //new NewCollectionTask().start();
268 SwingUtilities.invokeLater(new NewCollectionTask());
269 }
270 else if (esrc == menu_bar.file_open) {
271 //new OpenCollectionTask().start(); // will cause an EDT access violation exception
272 // since the GUI stuff of opening a collection is not done in a Swing thread
273 SwingUtilities.invokeLater(new OpenCollectionTask());
274 }
275 else if (esrc == menu_bar.file_options) {
276 new Preferences();
277 }
278 else if (esrc == menu_bar.file_save) {
279 // Very important: make sure metadata values are saved too
280 enrich_pane.stopEditingAndRebuild();
281 // Make sure all the metadata has been saved to file
282 MetadataXMLFileManager.saveMetadataXMLFiles();
283
284 Gatherer.c_man.saveCollection();
285 }
286
287 // *************
288 // Edit Options.
289 // *************
290 else if(esrc == menu_bar.edit_copy) {
291 try {
292 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
293 // Get the component with selected text as a JTextComponent
294 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
295 text.copy();
296 }
297 catch (Exception cce) {
298 // If the component is not a text component ignore the copy command
299 DebugStream.println(cce.toString());
300 }
301 }
302 else if(esrc == menu_bar.edit_cut) {
303 try {
304 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
305 // Get the component with selected text as a JTextComponent
306 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
307 // Cut the text to the clipboard
308 text.cut();
309 }
310 catch (ClassCastException cce) {
311 // If the component is not a text component ignore the cut command
312 DebugStream.println(cce.toString());
313 }
314 }
315 else if(esrc == menu_bar.edit_paste) {
316 try {
317 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
318 // Get the component with selected text as a JTextComponent
319 JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
320 // Cut the text to the clipboard
321 text.paste();
322 }
323 catch (ClassCastException cce) {
324 // If the component is not a text component ignore the paste command
325 DebugStream.println(cce.toString());
326 }
327 }
328 else if(esrc == menu_bar.edit_config) {
329 if(Gatherer.c_man.getCollection() != null) {
330 // Before we open the current collection's collectionConfig.xml for editing,
331 // need to make sure any presently unsaved edits are saved into collConfig
332 // so they are reflected in this config file when loaded into the editor for editing.
333 // A simple Gatherer.c_man.saveCollection() is not sufficient: it won't save ongoing
334 // edits in the currently selected GLI Pane (where relevant to colcfg)
335
336 // Whenever a user swaps from one GLI pane to another, loseFocus() is called on the pane
337 // and for some GLI Panes, this triggers a collection save, but notably also triggers a
338 // loseFocus() on the pane's editing fields/controls, which saves any ongoing mods in that
339 // pane to the collectionConfiguration file.
340 // - See loseFocus() of BaseConfigPane.java (that only SOME gli Pane's inherit from)
341 // and also apparent in GUIManager.windowLostFocus().
342 // - And for implementations of Control.loseFocus(), see for example via
343 // CollectionManager.loadDesignDetails() -> GeneralManager (for Format > General tab)
344 // which leads to GeneralManager.loseFocus() which gets "Called to store the current
345 // value of the components" - of its Controls. Exactly the behaviour we want!
346
347 // Not all GLI Panes inherit from BaseConfigPane, but then, not all GLI Panes
348 // make changes to the collection Config file; e.g. the Gather pane makes changes to
349 // the file system, Enrich makes changes to metadata.xml files and *.mds metadata sets
350 // files. But Design and Format panes make changes to collectionConfig.xml.
351 // In theory Create pane ought to as well, e.g. can set import options which also exists
352 // as ImportOptions in collectionConfig.xml, but they're not linked (yet) and Create pane
353 // doesn't inherit from BaseConfigPane. CreatePane's loseFocus() also don't call
354 // for the the collection to be saved.
355
356 // What all this means is that when we prepare to open the collectionConfig.xml,
357 // we want a collection save but want also the current state of GLI edits to be saved
358 // into collConfig before we display the collConfig file for editing.
359 // To trigger this behaviour we want to call loseFocus() on the current pane, called
360 // "previous_pane". That method may or may not force a save to collConfig,
361 // depending on whether it is warranted for that pane, but in such cases it will also
362 // cascade the loseFocus() call to the controls in that pane, who will save their current
363 // values into the colcfg in memory before this gets saved to the colCfg.xml file.
364
365 if(previous_pane != null) {
366 doLoseFocus();
367 }
368 //Gatherer.c_man.saveCollection(); //shouldn't have to do this, in theory. See above comment
369
370 ConfigFileEditor configEditor = new ConfigFileEditor();
371 configEditor.setVisible(true);
372 configEditor.setSize(900,700);
373 }
374 }
375
376 // *************
377 // Help Options.
378 // *************
379 else if (esrc == menu_bar.help_general) {
380 HelpFrame.setView("introduction");
381 }
382 else if (esrc == menu_bar.help_download) {
383 HelpFrame.setView("themirrorview");
384 }
385 else if (esrc == menu_bar.help_gather) {
386 HelpFrame.setView("collectingfiles");
387 }
388 else if (esrc == menu_bar.help_enrich) {
389 HelpFrame.setView("enrichingacollection");
390 }
391 else if (esrc == menu_bar.help_design) {
392 HelpFrame.setView("designingacollection");
393 }
394 else if (esrc == menu_bar.help_create) {
395 HelpFrame.setView("producingthecollection");
396 }
397 else if (esrc == menu_bar.help_format) {
398 HelpFrame.setView("formattingacollection");
399 }
400 else if (esrc == menu_bar.help_about) {
401 new AboutDialog(this);
402 }
403 }
404
405
406 /** 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.
407 */
408 public void afterDisplay() {
409 if (download_pane != null) {
410 download_pane.afterDisplay();
411 }
412 enrich_pane.afterDisplay();
413 }
414
415
416 public void closeCurrentCollection()
417 {
418 tab_pane.setSelectedComponent(gather_pane);
419 Gatherer.c_man.closeCollection();
420 FilenameEncoding.closeCollection(); // clear filename-to-encodings map
421 }
422
423
424 public void saveThenCloseCurrentCollection()
425 {
426 Gatherer.c_man.saveCollection();
427 closeCurrentCollection();
428 }
429
430
431 /** This is called when we're absolutely finished with the GLI. It is *not* called when the applet is suspended.
432 */
433 public void destroy()
434 {
435 // Destroying create pane ensures the latest log has been closed
436 if (create_pane != null) {
437 create_pane.destroy();
438 }
439
440 // Deal to help
441 if (help != null) {
442 help.destroy();
443 help = null;
444 }
445 }
446
447
448 /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
449 */
450 public void display() {
451 content_pane = (JPanel) this.getContentPane();
452 content_pane.setComponentOrientation(Dictionary.getOrientation());
453
454 // Enable window-type events to be fired.
455 enableEvents(AWTEvent.WINDOW_EVENT_MASK);
456 // Initialise and layout sub-components, plus other window dressing.
457 try {
458 this.setSize(size);
459
460 // Set the title
461 String collection_title = null;
462 String collection_name = null;
463 if (Gatherer.c_man.ready()) {
464 Collection collection = Gatherer.c_man.getCollection();
465 collection_title = collection.getTitle();
466 collection_name = collection.getGroupQualifiedName(true);
467 collection = null;
468 }
469 setTitle(collection_title, collection_name);
470 collection_title = null;
471 collection_name = null;
472
473 // Pretty corner icon
474 String gsmall_image = "gatherer.png";
475 if (Configuration.fedora_info.isActive()) {
476 gsmall_image = "fli-" + gsmall_image;
477 }
478 if(Gatherer.isGsdlRemote) {
479 gsmall_image = "client-" + gsmall_image;
480 }
481 this.setIconImage(JarTools.getImage(gsmall_image).getImage());
482 // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
483 content_pane.setLayout(new BorderLayout());
484 // Create the menu-bar and stick it up the top.
485 menu_bar = new MenuBar(new MenuListenerImpl());
486 menu_bar.setComponentOrientation(Dictionary.getOrientation());
487
488 //feedback changes
489 //content_pane.add(menu_bar, BorderLayout.NORTH);
490 this.setJMenuBar(menu_bar);
491 // end feedback changes
492
493 // Create the tabbed pane and plop it in the center where it will
494 // expand to consume all available space like any good gas would.
495 tab_pane = new JTabbedPane();
496 tab_pane.setComponentOrientation(Dictionary.getOrientation());
497 tab_pane.addChangeListener(this);
498 tab_pane.setFont(Configuration.getFont("general.font", false));
499
500 if (Configuration.get("workflow.download", true) && Gatherer.isDownloadEnabled) {
501 download_pane = new DownloadPane();
502 // "GUI.Download_Tooltip" is used automatically
503 tab_pane.addTab(Dictionary.get("GUI.Download"), JarTools.getImage("download.gif"), download_pane, Dictionary.get("GUI.Download_Tooltip"));
504 tab_pane.setEnabledAt(tab_pane.indexOfComponent(download_pane), Configuration.get("workflow.download", false));
505 }
506
507 gather_pane = new GatherPane();
508 gather_pane.display();
509 if (Configuration.get("workflow.gather", true)) {
510 // "GUI.Gather_Tooltip" is used automatically
511 tab_pane.addTab(Dictionary.get("GUI.Gather"), JarTools.getImage("gather.gif"), gather_pane, Dictionary.get("GUI.Gather_Tooltip"));
512 tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Configuration.get("workflow.gather", false));
513 }
514
515 enrich_pane = new EnrichPane();
516 enrich_pane.display();
517 if (Configuration.get("workflow.enrich", true)) {
518 // "GUI.Enrich_Tooltip" is used automatically
519 tab_pane.addTab(Dictionary.get("GUI.Enrich"), JarTools.getImage("enrich.gif"), enrich_pane, Dictionary.get("GUI.Enrich_Tooltip"));
520 tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
521 }
522
523 design_pane = new DesignPane();
524 design_pane.display();
525 if (Configuration.get("workflow.design", true)) {
526 // "GUI.Design_Tooltip" is used automatically
527 if (Configuration.fedora_info.isActive()) {
528 tab_pane.addTab("Plugins", JarTools.getImage("design.gif"), design_pane, Dictionary.get("GUI.Design_Tooltip"));
529 }
530 else {
531 tab_pane.addTab(Dictionary.get("GUI.Design"), JarTools.getImage("design.gif"), design_pane, Dictionary.get("GUI.Design_Tooltip"));
532 }
533
534 tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
535 }
536
537 create_pane = new CreatePane();
538 create_pane.setComponentOrientation(Dictionary.getOrientation());
539 create_pane.display();
540 if (Configuration.get("workflow.create", true)) {
541 // "GUI.Create_Tooltip" is used automatically
542 tab_pane.addTab(Dictionary.get("GUI.Create"), JarTools.getImage("create.gif"), create_pane, Dictionary.get("GUI.Create_Tooltip"));
543 tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
544 }
545
546 format_pane = new FormatPane();
547 format_pane.setComponentOrientation(Dictionary.getOrientation());
548 format_pane.display();
549 if (Configuration.get("workflow.format", true)) {
550 tab_pane.addTab(Dictionary.get("GUI.Format"), JarTools.getImage("format.gif"), format_pane, Dictionary.get("GUI.Format_Tooltip"));
551 tab_pane.setEnabledAt(tab_pane.indexOfComponent(format_pane), false);
552 }
553
554 // The MetaAuditFrame must be created after the gather/enrich panes but before they get focus
555 meta_audit = new MetaAuditFrame();
556 meta_audit.setComponentOrientation(Dictionary.getOrientation());
557 // Select the collect pane if it is available
558 if (tab_pane.indexOfComponent(gather_pane) != -1) {
559 tab_pane.setSelectedComponent(gather_pane);
560 }
561 // Otherwise find the first tab that is enabled and select that.
562 else {
563 for (int i = 0; i < tab_pane.getTabCount(); i++) {
564 if (tab_pane.isEnabledAt(i)) {
565 tab_pane.setSelectedIndex(i);
566 break;
567 }
568 }
569 }
570
571 content_pane.add(tab_pane, BorderLayout.CENTER);
572
573 // Add an extra progress bar at the bottom of every screen when using a remote Greenstone server
574 if (Gatherer.isGsdlRemote) {
575 JPanel remote_greenstone_server_progress_panel = new JPanel();
576 //remote_greenstone_server_progress_panel.setComponentOrientation(Dictionary.getOrientation());
577 JLabel remote_greenstone_server_progress_label = new JLabel(Dictionary.get("RemoteGreenstoneServer.Progress"));
578 //remote_greenstone_server_progress_label.setComponentOrientation(Dictionary.getOrientation());
579 remote_greenstone_server_progress_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
580 remote_greenstone_server_progress_panel.setLayout(new BorderLayout());
581 remote_greenstone_server_progress_panel.add(remote_greenstone_server_progress_label, BorderLayout.LINE_START);
582 remote_greenstone_server_progress_panel.add(Gatherer.remoteGreenstoneServer.getProgressBar(), BorderLayout.CENTER);
583 content_pane.add(remote_greenstone_server_progress_panel, BorderLayout.SOUTH);
584 }
585
586 // Call refresh to update all controls to reflect current collection status.
587 refresh(-1, Gatherer.c_man.ready());
588 }
589 catch (Exception e) {
590 DebugStream.printStackTrace(e);
591 // The GUI failing to build is an app killer
592 e.printStackTrace();
593 System.exit(1);
594 }
595 }
596
597 public void exit()
598 {
599 exit(0);
600 }
601
602 // some cases we have already saved the collection, but don't want to
603 // override the general.open_collection value here
604 public void exitNoCollectionSave(int exit_status) {
605 // Store the current position and size of the GLI for next time
606 Configuration.setBounds("general.bounds", true, getBounds());
607
608 // Save configuration
609 Configuration.save();
610
611 // Hide the main window
612 setVisible(false);
613
614 // If we're running as an applet we don't quit here (we quit when the browser calls GathererApplet.destroy())
615 if (!Gatherer.isApplet) {
616 Gatherer.exit(exit_status);
617 }
618
619 }
620 /** This method ensures that all the things needing saving are saved before Gatherer.exit() is called.
621 */
622 public void exit(int exit_status)
623 {
624 boolean collection_open = false;
625 // If we have a collection open remember it for next time, then save it and close it
626 if (Gatherer.c_man.ready()) {
627 // but we no longer remember open collections for remote GLI, as this causes problems
628 // in applets when other users on a machine want to use an applet and GLI wants to load
629 // a collection left open from a previous session and *requires* the old user to authenticate
630 if(Gatherer.isGsdlRemote) {
631 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
632 true, "");
633 } else {
634 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
635 true, CollectionManager.getLoadedCollectionColFilePath());
636 }
637 saveThenCloseCurrentCollection();
638 collection_open = true;
639 }
640 else {
641 // if there was no open collection, then write out the collect dir path for next time
642 // IF this is not the default collect directory and not a remote GLI/applet
643 if(Gatherer.isGsdlRemote || Gatherer.getCollectDirectoryPath().equals(
644 Gatherer.getDefaultGSCollectDirectoryPath(true))) {
645 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
646 true, "");
647 } else {
648 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
649 true, Gatherer.getCollectDirectoryPath());
650 }
651 }
652
653
654 // Basically, if GLI coldir != gsdlsite_colhome, we ask them if they want to save GLI coldir as gsdlsite_colhome
655 // If gsdlsite_colhome = "" (meaning default GS coldir) and GLI is also set to defaultGScoldir, no saving necessary.
656 // We ONLY do this for the local included apache web server, since the issue revolves around gsdlsite.cfg containing
657 // the global collecthome when using the apache web server. This is not an issue for remote GS or server.exe (the latter
658 // has separate config files specifying collecthome for when GLI is running whereas when just the server.exe is running).
659 if(!Gatherer.isGsdlRemote && !Gatherer.isPersistentServer()) {
660
661 String defaultColDir = Gatherer.getDefaultGSCollectDirectoryPath(false); // no filesep at end
662 String gliColDir = Gatherer.getCollectDirectoryPath();
663 String serverColDir = Gatherer.gsdlsite_collecthome;
664
665 boolean showSettingsDlg = true;
666 // if collectdir was changed during GLI session (to something different from what's in gsdlsite), need to ask what to store
667 String gsdlsiteColdir = Gatherer.gsdlsite_collecthome.replace("\"", "");
668 if(gliColDir.equals(gsdlsiteColdir+File.separator)) {
669 showSettingsDlg = false;
670 } else if(gsdlsiteColdir.equals("") // both set to default coldir
671 && gliColDir.equals(defaultColDir+File.separator)) {
672 showSettingsDlg = false;
673 }
674 if(showSettingsDlg) {
675
676 // else we will be showing the Collect Directory Settings Dialog
677 if(gliColDir.endsWith(File.separator)) {
678 gliColDir = gliColDir.substring(0, gliColDir.length()-1);
679 }
680
681 if(serverColDir.equals("")) {
682 serverColDir = defaultColDir;
683 }
684 collectDirSettingsDialog(defaultColDir, serverColDir, gliColDir, collection_open);
685 }
686 }
687
688 // Store the current position and size of the GLI for next time
689 Configuration.setBounds("general.bounds", true, getBounds());
690
691 // Save configuration
692 Configuration.save();
693
694 // Hide the main window
695 setVisible(false);
696
697 // If we're running as an applet we don't quit here (we quit when the browser calls GathererApplet.destroy())
698 if (!Gatherer.isApplet) {
699 Gatherer.exit(exit_status);
700 }
701 }
702
703 public void collectDirSettingsDialog(final String defaultColDir,
704 final String from, final String to, final boolean collection_open)
705 {
706 final JDialog colHomeDialog
707 = new JDialog(this, Dictionary.get("GUI.CollectHome.title"), true); // this = Gatherer.g_man
708 colHomeDialog.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
709
710
711 JRadioButton gliYes = new JRadioButton(Dictionary.get("General.Yes"), true);
712 // the default selection for GLI, collecthome=to
713 JRadioButton serverYes = new JRadioButton(Dictionary.get("General.Yes")); // not selected for the server
714 JRadioButton gliNo = null;
715 JRadioButton gliThirdOption = null;
716 JRadioButton serverNo = null;
717 JRadioButton serverThirdOption = null;
718
719 if(from.equals(defaultColDir)) {
720 gliNo = new JRadioButton(Dictionary.get("GUI.CollectHome.resetToDefault"));
721 serverNo = new JRadioButton(Dictionary.get("GUI.CollectHome.leaveAtDefault"), true);
722 // default selection for server, collecthome=from
723 } else {
724 gliNo = new JRadioButton(Dictionary.get("General.No"));
725 serverNo = new JRadioButton(Dictionary.get("General.No"), true); // default selection for server
726 if(!to.equals(defaultColDir)) { // neither from nor to is the default GS collect dir, so give them that as the third option
727 gliThirdOption = new JRadioButton(Dictionary.get("GUI.CollectHome.reset"));
728 serverThirdOption = new JRadioButton(Dictionary.get("GUI.CollectHome.reset"));
729 }
730 }
731
732 JPanel gliPanel = new JPanel(); // flowlayout by default
733 ButtonGroup gliGroup = new ButtonGroup();
734 JPanel serverPanel = new JPanel(); // flowlayout by default
735 ButtonGroup serverGroup = new ButtonGroup();
736
737 gliGroup.add(gliYes);
738 gliPanel.add(gliYes);
739 serverGroup.add(serverYes);
740 serverPanel.add(serverYes);
741
742 gliGroup.add(gliNo);
743 gliPanel.add(gliNo);
744 serverGroup.add(serverNo);
745 serverPanel.add(serverNo);
746
747 if(gliThirdOption != null) {
748 gliThirdOption = new JRadioButton("Reset to default");
749 serverThirdOption = new JRadioButton("Reset to default");
750
751 gliGroup.add(gliThirdOption);
752 gliPanel.add(gliThirdOption);
753 serverGroup.add(serverThirdOption);
754 serverPanel.add(serverThirdOption);
755 }
756
757 // vars need to be final to use them in the actionlistener below
758 final JRadioButton gli_yes = gliYes;
759 final JRadioButton gli_no = gliNo;
760 final JRadioButton gli_optional = gliThirdOption;
761 final JRadioButton server_yes = serverYes;
762 final JRadioButton server_no = serverNo;
763 final JRadioButton server_optional = serverThirdOption;
764
765 JButton okButton = new JButton(Dictionary.get("General.OK"));
766 okButton.addActionListener(new ActionListener() {
767 public void actionPerformed(ActionEvent e) {
768 // store the option chosen for GLI
769 String gliColDir = to;
770 if(gli_optional != null && gli_optional.isSelected()) {
771 // defaultColDir
772 gliColDir = "";
773 } else if(gli_yes.isSelected()) {
774 gliColDir = to;
775 } else if (gli_no.isSelected()) {
776 gliColDir = from;
777 }
778 if(defaultColDir.equals(gliColDir)) {
779 gliColDir = "";
780 }
781 if(!(collection_open && gli_yes.isSelected())) { // don't overwrite open collections
782 Configuration.setString(
783 "general.open_collection"+Configuration.gliPropertyNameSuffix(),
784 true, gliColDir);
785 }
786
787 // store the option chosen for the server's settings
788 String serverColDir = from;
789 if(server_optional != null && server_optional.isSelected()) {
790 // defaultColDir
791 serverColDir = null;
792 } else if(server_yes.isSelected()) {
793 serverColDir = to;
794 } else if (server_no.isSelected()) {
795 serverColDir = from;
796 }
797 if(serverColDir != null && defaultColDir.equals(serverColDir)) {
798 serverColDir = null;
799 }
800
801 if(serverColDir != null) {
802 serverColDir = serverColDir.replace("\"","");
803 serverColDir = "\""+serverColDir+"\"";
804 }
805
806 Gatherer.gsdlsite_collecthome = Utility.updatePropertyConfigFile(
807 Gatherer.getGsdlSiteConfigFile(), "collecthome", serverColDir);
808
809 colHomeDialog.dispose();
810 }
811 });
812
813 //String[] dirs = {from, to};
814 //JLabel message = new JLabel(Dictionary.get("GUI.CollectHome.message", dirs));
815 JLabel message = new JLabel(Dictionary.get("GUI.CollectHome.message"));
816 JLabel fromDirLine = new JLabel(Dictionary.get("GUI.CollectHome.dir", from));
817 fromDirLine.setBorder(BorderFactory.createEmptyBorder(0,25,0,0)); // padding
818 JLabel toLine = new JLabel(Dictionary.get("GUI.CollectHome.to"));
819 JLabel toDirLine = new JLabel(Dictionary.get("GUI.CollectHome.dir", to));
820 toDirLine.setBorder(BorderFactory.createEmptyBorder(0,25,0,0)); // padding
821 JLabel gliOption = new JLabel(Dictionary.get("GUI.CollectHome.gli"));
822 JLabel serverOption = new JLabel(Dictionary.get("GUI.CollectHome.server"));
823
824 JPanel mainPanel = new JPanel();
825 mainPanel.setLayout(new GridLayout(9, 1));
826 mainPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); // padding
827 mainPanel.add(message);
828 mainPanel.add(fromDirLine);
829 mainPanel.add(toLine);
830 mainPanel.add(toDirLine);
831 mainPanel.add(gliOption);
832 mainPanel.add(gliPanel);
833 mainPanel.add(serverOption);
834 mainPanel.add(serverPanel);
835 mainPanel.add(okButton);
836 Container c = colHomeDialog.getContentPane();
837 c.setLayout(new BorderLayout());
838 c.add(mainPanel, BorderLayout.CENTER);
839 colHomeDialog.getRootPane().setDefaultButton(okButton);
840
841 colHomeDialog.pack();
842 colHomeDialog.setVisible(true);
843 }
844
845
846 /** 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.
847 */
848 public void lockCollection(boolean import_stage, boolean lock)
849 {
850 locked = lock;
851
852 if (import_stage) {
853 int gather_pos = tab_pane.indexOfComponent(gather_pane);
854 if (gather_pos != -1) {
855 tab_pane.setEnabledAt(gather_pos, !lock);
856 }
857 int enrich_pos = tab_pane.indexOfComponent(enrich_pane);
858 if (enrich_pos != -1) {
859 tab_pane.setEnabledAt(enrich_pos, !lock);
860 }
861 }
862
863 int design_pos = tab_pane.indexOfComponent(design_pane);
864 if (design_pos != -1) {
865 tab_pane.setEnabledAt(design_pos, !lock);
866 }
867 }
868
869
870 public void modeChanged(int mode) {
871 // Set the title
872 String collection_title = null;
873 String collection_name = null;
874 if (Gatherer.c_man.ready()) {
875 Collection collection = Gatherer.c_man.getCollection();
876 collection_title = collection.getTitle();
877 collection_name = collection.getGroupQualifiedName(true);
878 collection = null;
879 }
880 setTitle(collection_title, collection_name);
881 collection_title = null;
882 collection_name = null;
883 // Now pass on the message to anyone who cares
884 if (download_pane != null) {
885 download_pane.modeChanged(mode);
886 }
887 if (gather_pane != null) {
888 gather_pane.modeChanged(mode);
889 }
890 if (enrich_pane != null) {
891 enrich_pane.modeChanged(mode);
892 }
893 if (design_pane != null) {
894 design_pane.modeChanged(mode);
895 }
896 if (create_pane != null) {
897 create_pane.modeChanged(mode);
898 }
899 if (format_pane != null) {
900 format_pane.modeChanged(mode);
901 }
902 }
903
904
905 public void refresh(int refresh_reason, boolean collection_loaded)
906 {
907 // Set the collection information in the title bar
908 if (collection_loaded) {
909 Collection collection = Gatherer.c_man.getCollection();
910 setTitle(collection.getTitle(), collection.getGroupQualifiedName(true));
911 }
912 else {
913 setTitle(null, null);
914 }
915
916 // Update the menu bar
917 menu_bar.refresh(refresh_reason, collection_loaded);
918
919 // Update the loaded panes
920 if (download_pane != null) {
921 download_pane.refresh(refresh_reason, collection_loaded);
922 }
923 if (gather_pane != null) {
924 gather_pane.refresh(refresh_reason, collection_loaded);
925 }
926 if (enrich_pane != null) {
927 enrich_pane.refresh(refresh_reason, collection_loaded);
928 }
929 if (design_pane != null) {
930 design_pane.refresh(refresh_reason, collection_loaded);
931 }
932 if (create_pane != null) {
933 create_pane.refresh(refresh_reason, collection_loaded);
934 }
935 if (format_pane != null) {
936 format_pane.refresh(refresh_reason, collection_loaded);
937 }
938
939 // Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
940 if (!locked) {
941 if (tab_updater == null) {
942 tab_updater = new TabUpdater(tab_pane, collection_loaded);
943 }
944 else {
945 tab_updater.setReady(collection_loaded);
946 }
947 SwingUtilities.invokeLater(tab_updater);
948 }
949 }
950
951
952 public void refreshCollectionTree(int refresh_reason)
953 {
954 if (gather_pane != null) {
955 gather_pane.refreshCollectionTree(refresh_reason);
956 }
957 }
958
959
960 public void refreshWorkspaceTree(int refresh_reason)
961 {
962 if (gather_pane != null) {
963 gather_pane.refreshWorkspaceTree(refresh_reason);
964 }
965 }
966
967 public void refreshWorkspaceTreeGreenstoneCollections()
968 {
969 refreshWorkspaceTree(WorkspaceTree.LIBRARY_CONTENTS_CHANGED);
970 }
971
972 /** Specifies whether a certain tab is enabled or not. */
973 private void setTabEnabled(String rawname, boolean state) {
974 // Retrieve the dictionary based name.
975 String name = Dictionary.get("GUI." + rawname);
976 int index = tab_pane.indexOfTab(name);
977 // Of course we may not have this tab available.
978 if(index != -1) {
979 // Some tabs are also dependant on if a collection is ready
980 Component component = tab_pane.getComponentAt(index);
981 if(component == enrich_pane || component == design_pane || component == create_pane || component == format_pane) {
982 tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
983 }
984 else {
985 tab_pane.setEnabledAt(index, state);
986 }
987 // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
988 if(tab_pane.getSelectedIndex() == index && !state) {
989 boolean found = false;
990 for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
991 if(tab_pane.isEnabledAt(i)) {
992 tab_pane.setSelectedIndex(i);
993 found = true;
994 }
995 }
996 // If there are no tabs enabled, which should be impossible, then select the first tab
997 if(!found) {
998 tab_pane.setSelectedIndex(0);
999 }
1000 }
1001 }
1002 }
1003
1004 /** 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.
1005 * @param title
1006 * @param name
1007 */
1008 public void setTitle(String title, String name) {
1009
1010 // Finally display the collection name in the title bar.
1011 StringBuffer title_buffer = new StringBuffer(Configuration.getApplicationTitle());
1012 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1013 title_buffer.append(Gatherer.PROGRAM_VERSION);
1014 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1015 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1016 // Server version information
1017 title_buffer.append(Gatherer.getServerVersionAsString());
1018 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1019 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1020 // Describe the current user mode
1021 title_buffer.append(StaticStrings.MODE_STR);
1022 title_buffer.append(Configuration.getModeAsString());
1023 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1024 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1025 // Now for the current collection
1026 title_buffer.append(StaticStrings.COLLECTION_STR);
1027 if (title != null && name != null) {
1028 title_buffer.append(title);
1029 title_buffer.append(StaticStrings.SPACE_CHARACTER);
1030 title_buffer.append(StaticStrings.LBRACKET_CHARACTER);
1031 title_buffer.append(name);
1032 title_buffer.append(StaticStrings.RBRACKET_CHARACTER);
1033 }
1034 else {
1035 title_buffer.append(Dictionary.get("Collection.No_Collection"));
1036 }
1037 this.setTitle(title_buffer.toString());
1038 title_buffer = null;
1039 }
1040
1041
1042 private class OpenCollectionTask
1043 implements Runnable //extends Thread -> If this extends Thread, it will cause an EDT access
1044 // violation since the GUI stuff in run() is not done in the Swing Event Dispatch Thread/EDT.
1045 {
1046 public void run()
1047 {
1048 String collection_file_path = showOpenCollectionDialog();
1049
1050 // User has selected a collection to open
1051 if (collection_file_path != null) {
1052 // If there is already a collection open, save and close it
1053 if (Gatherer.c_man.ready()) {
1054 saveThenCloseCurrentCollection();
1055 }
1056
1057 // Open the selected collection
1058 Gatherer.c_man.loadCollection(collection_file_path);
1059 }
1060 }
1061 }
1062
1063
1064 /** When the load collection option is chosen this method is called to produce the modal file load prompt.
1065 */
1066 private String showOpenCollectionDialog()
1067 {
1068 OpenCollectionDialog dialog = new OpenCollectionDialog();
1069 TestingPreparation.setNamesRecursively(dialog);
1070
1071 dialog.setComponentOrientation(Dictionary.getOrientation());
1072 if (dialog.display() == OpenCollectionDialog.OK_OPTION) {
1073 return dialog.getFileName();
1074 }
1075
1076 // User must have cancelled the action
1077 return null;
1078 }
1079
1080
1081 /** When called this method causes the MetadataAuditTable to display a nice dialog box which contains all the metadata assigned in the collection.
1082 */
1083 public void showMetaAuditBox() {
1084 wait(true);
1085 meta_audit.display();
1086 wait(false);
1087 }
1088
1089
1090 private class NewCollectionTask
1091 implements Runnable //extends Thread
1092 {
1093 public void run()
1094 {
1095 // Create the collection details prompt from new collection prompt
1096 NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
1097 //TestingPreparation.setNamesRecursively(ncd_prompt);
1098 // 1. names have to be set in NewCollectionDetailsPrompt, as it makes itself visible
1099 // and for testing we have to have run setName() on its components before the dialog goes visible
1100 // 2. For whatever reason, the NewCollectionDetailsPrompt dialog's own name is set
1101 // to "col" and it's not possible to change it at any point before or after
1102 // creating the dialog, and whether from inside or outside the dialog's own class
1103
1104 // Create the new collection (if not cancelled) in a new thread.
1105 if (!ncd_prompt.isCancelled()) {
1106 // If there is already a collection open, save and close it.
1107 if (Gatherer.c_man.ready()) {
1108 saveThenCloseCurrentCollection();
1109 }
1110
1111 // Create new collection.
1112 Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), new ArrayList());
1113 ncd_prompt.dispose();
1114 }
1115
1116 // Done
1117 ncd_prompt = null;
1118 }
1119 }
1120
1121
1122 private class DeleteCollectionTask
1123 implements Runnable //extends Thread
1124 {
1125 public void run()
1126 {
1127 // The rest is handled by the DeleteCollectionPrompt
1128 DeleteCollectionPrompt dc_prompt = new DeleteCollectionPrompt();
1129 TestingPreparation.setNamesRecursively(dc_prompt);
1130 if (dc_prompt.display()) {
1131 //closeCurrentCollection();
1132 }
1133 dc_prompt.destroy();
1134 dc_prompt = null;
1135 }
1136 }
1137
1138 // Want to triger loseFocus() on GLI Panes at will when Menu > Edit > collectionConfig.xml clicked.
1139 // And when done editing, want to trigger doRegainFocs().
1140 // loseFocus() on GLI Panes is not universally inherited from a common base class
1141 // But loseFocus() is important as it forces saves as-is of user entered values in gui fields
1142 // When alling doLoseFocus() on GLI > Edit > collConfig.xml, we force a save of the current state
1143 // of the current pane (called "previous_pane").
1144 // Else a save is only triggered when another GLI Pane is clicked. We can't expect a user to
1145 // remember to click other panes whenever they want to edit the collConfig.xml.
1146 private void doLoseFocus() {
1147 if (previous_pane != null) {
1148 if (previous_pane == gather_pane) {
1149 gather_pane.loseFocus();
1150 }
1151 else if (previous_pane == enrich_pane) {
1152 enrich_pane.loseFocus();
1153 }
1154 else if (previous_pane == design_pane) {
1155 design_pane.loseFocus();
1156 }
1157 else if (previous_pane == create_pane) {
1158 create_pane.loseFocus();
1159 }
1160 else if (previous_pane == format_pane) {
1161 format_pane.loseFocus();
1162 }
1163 }
1164 }
1165 public void doRegainFocus() {
1166 if (previous_pane != null) {
1167 if (previous_pane == gather_pane) {
1168 gather_pane.gainFocus();
1169 }
1170 else if (previous_pane == enrich_pane) {
1171 enrich_pane.gainFocus();
1172 }
1173 else if (previous_pane == design_pane) {
1174 design_pane.gainFocus();
1175 }
1176 else if (previous_pane == create_pane) {
1177 create_pane.gainFocus();
1178 }
1179 else if (previous_pane == format_pane) {
1180 format_pane.gainFocus();
1181 }
1182 }
1183 }
1184
1185 /** 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.
1186 * @param event A ChangeEvent containing information about the event that fired this call.
1187 */
1188 public void stateChanged(ChangeEvent event)
1189 {
1190 if (previous_pane != null) {
1191 if (previous_pane == gather_pane) {
1192 gather_pane.loseFocus();
1193 }
1194 else if (previous_pane == enrich_pane) {
1195 enrich_pane.loseFocus();
1196 }
1197 else if (previous_pane == design_pane) {
1198 design_pane.loseFocus();
1199 }
1200 else if (previous_pane == create_pane) {
1201 create_pane.loseFocus();
1202 }
1203 else if (previous_pane == format_pane) {
1204 format_pane.loseFocus();
1205 }
1206 }
1207
1208 menu_bar.tabSelected(tab_pane.getSelectedIndex());
1209 int selected_index = tab_pane.getSelectedIndex();
1210 if (selected_index == tab_pane.indexOfComponent(download_pane)) {
1211 download_pane.gainFocus();
1212 }
1213 else if (selected_index == tab_pane.indexOfComponent(gather_pane)) {
1214 gather_pane.gainFocus();
1215 }
1216 else if (selected_index == tab_pane.indexOfComponent(enrich_pane)) {
1217 enrich_pane.gainFocus();
1218 }
1219 else if (selected_index == tab_pane.indexOfComponent(design_pane)) {
1220 design_pane.gainFocus();
1221 }
1222 else if (selected_index == tab_pane.indexOfComponent(create_pane)) {
1223 create_pane.gainFocus();
1224 }
1225 else if (selected_index == tab_pane.indexOfComponent(format_pane)) {
1226 format_pane.gainFocus();
1227 }
1228
1229 previous_pane = (JPanel) tab_pane.getSelectedComponent();
1230
1231 }
1232
1233
1234 private MouseListener mouse_blocker_listener = new MouseAdapter() {};
1235
1236 public void updateUI()
1237 {
1238 SwingUtilities.invokeLater(new Runnable() {
1239 public void run() {
1240 JPanel pane = (JPanel) getContentPane();
1241 pane.updateUI();
1242 // Also update all of the tabs according to workflow.
1243 workflowUpdate("Download", Configuration.get("workflow.download", false));
1244 workflowUpdate("Gather", Configuration.get("workflow.gather", false));
1245 workflowUpdate("Enrich", Configuration.get("workflow.enrich", false));
1246 workflowUpdate("Design", Configuration.get("workflow.design", false));
1247 workflowUpdate("Create", Configuration.get("workflow.create", false));
1248 workflowUpdate("Format", Configuration.get("workflow.format", false));
1249 }
1250 });
1251 }
1252
1253 public void wait(boolean waiting) {
1254 Component glass_pane = getGlassPane();
1255 if(waiting) {
1256 // Show wait cursor.
1257 glass_pane.addMouseListener(mouse_blocker_listener);
1258 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1259 glass_pane.setVisible(true);
1260 }
1261 else {
1262 // Hide wait cursor.
1263 glass_pane.setVisible(false);
1264 glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1265 glass_pane.removeMouseListener(mouse_blocker_listener);
1266 }
1267 glass_pane = null;
1268 }
1269
1270 public void workflowUpdate(String raw, boolean state) {
1271 WorkflowUpdater task = new WorkflowUpdater(raw, state);
1272 SwingUtilities.invokeLater(task);
1273 task = null;
1274 }
1275
1276
1277 /**Overridden from JFrame so we can exit safely when window is closed (or destroyed).
1278 * @param event A <strong>WindowEvent</strong> containing information about the event that fired this call.
1279 */
1280 protected void processWindowEvent(WindowEvent event) {
1281 if(event.getID() == WindowEvent.WINDOW_CLOSING) {
1282 exit();
1283 }
1284 }
1285
1286
1287 /** 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.
1288 */
1289 private class MenuListenerImpl
1290 implements MenuListener {
1291 /** Called whenever a popup menu is hidden, but we don't care.
1292 * @param e Some <strong>MenuEvent</strong> that we could care less about.
1293 */
1294 public void menuCanceled(MenuEvent e) {
1295 }
1296 /** Called whenever a menu header (ie button) becomes unselected, but we don't care.
1297 * @param e Some <strong>MenuEvent</strong> that we could care less about.
1298 */
1299 public void menuDeselected(MenuEvent e) {
1300 }
1301 /** 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.
1302 * @param e The <strong>MenuEvent</strong> whose source is checked.
1303 */
1304 public void menuSelected(MenuEvent e) {
1305 if(e.getSource() == menu_bar.help) {
1306 if(menu_bar.help.isSelected()) {
1307 menu_bar.help.doClick(10);
1308 }
1309 }
1310 else if(e.getSource() == menu_bar.edit) { // someone clicked the toplevel Edit menu
1311 // gray out the Edit Config File menu if there's no collection currently open.
1312 if(Gatherer.c_man.getCollection() == null) {
1313 menu_bar.edit_config.setEnabled(false);
1314 }
1315 else { // don't forget to reenable the Edit ConfigXML menu item when applicable
1316 menu_bar.edit_config.setEnabled(true);
1317 }
1318 }
1319
1320 }
1321 }
1322
1323 private class TabUpdater
1324 implements Runnable {
1325 private boolean ready = false;
1326 private int download_pos = -1;
1327 private int enrich_pos = -1;
1328 private int design_pos = -1;
1329 private int create_pos = -1;
1330 private int format_pos = -1;
1331 private int export_pos = -1;
1332 private JTabbedPane tab_pane = null;
1333
1334 public TabUpdater(JTabbedPane tab_pane, boolean ready) {
1335 this.ready = ready;
1336 this.tab_pane = tab_pane;
1337 download_pos = tab_pane.indexOfComponent(download_pane);
1338 enrich_pos = tab_pane.indexOfComponent(enrich_pane);
1339 design_pos = tab_pane.indexOfComponent(design_pane);
1340 create_pos = tab_pane.indexOfComponent(create_pane);
1341 format_pos = tab_pane.indexOfComponent(format_pane);
1342 }
1343
1344 public void run()
1345 {
1346 if (download_pos != -1) {
1347 if (ready) {
1348 tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", false));
1349 }
1350 else {
1351 tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", true));
1352 }
1353 }
1354 if (enrich_pos != -1) {
1355 tab_pane.setEnabledAt(enrich_pos, ready && Configuration.get("workflow.enrich", false));
1356 }
1357 if (design_pos != -1) {
1358 tab_pane.setEnabledAt(design_pos, ready && Configuration.get("workflow.design", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
1359 }
1360 if (create_pos != -1) {
1361 tab_pane.setEnabledAt(create_pos, ready && Configuration.get("workflow.create", false));
1362 }
1363 if (format_pos != -1) {
1364 tab_pane.setEnabledAt(format_pos, ready && Configuration.get("workflow.format", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
1365 }
1366 }
1367
1368 public void setReady(boolean ready) {
1369 this.ready = ready;
1370 }
1371 }
1372
1373 private class WorkflowUpdater
1374 implements Runnable {
1375 private boolean state;
1376 private String raw;
1377 public WorkflowUpdater(String raw, boolean state) {
1378 this.raw = raw;
1379 this.state = state;
1380 }
1381 public void run() {
1382 setTabEnabled(raw, state);
1383 }
1384 }
1385}
Note: See TracBrowser for help on using the repository browser.