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

Last change on this file since 36580 was 36580, checked in by davidb, 20 months ago

Changed to using square brackets for displaying short collection name

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