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

Last change on this file since 34263 was 34263, checked in by ak19, 4 years ago

Option in GLI file menu to Export collection meta to CSV (new CSV file or add to existing). Uses apache commons CSV, so had to include the csv subfolder of commons into apache.jar, where all other apache jars used by GLI are bundled into. Updated the gli/lib/README about this.

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