Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/greenstone/gatherer/gui/CreatePane.java


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   */
37  package org.greenstone.gatherer.gui;
38  
39  import java.awt.*;
40  import java.awt.event.*;
41  import java.io.*;
42  import javax.swing.*;
43  import javax.swing.event.*;
44  import javax.swing.text.*;
45  import javax.swing.tree.*;
46  import org.greenstone.gatherer.Dictionary;
47  import org.greenstone.gatherer.Gatherer;
48  import org.greenstone.gatherer.cdm.SearchTypeManager;
49  import org.greenstone.gatherer.collection.BuildOptions;
50  import org.greenstone.gatherer.collection.Collection;
51  import org.greenstone.gatherer.gui.OptionsPane;
52  import org.greenstone.gatherer.shell.GBasicProgressMonitor;
53  import org.greenstone.gatherer.shell.GBuildProgressMonitor;
54  import org.greenstone.gatherer.shell.GImportProgressMonitor;
55  import org.greenstone.gatherer.shell.GShell;
56  import org.greenstone.gatherer.shell.GShellEvent;
57  import org.greenstone.gatherer.shell.GShellListener;
58  import org.greenstone.gatherer.shell.GShellProgressMonitor;
59  import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
60  import org.greenstone.gatherer.util.StaticStrings;
61  
62  /** This class provides a GUI view showing some statistics on your current collection, and options for building it. As the collection is built this initial view is replaced with one showing progress bars and a message log of the creation process. This log can be later accessed via the options tree located in the center of the initial pane. This class is also responsible for creating the GShellProgressMonitors that are then attatched to external shell processes, and calling the methods in the CollectionManager for actually importing and building the collection. <br><BR>
63   * <center><table width=80% border=2 cellspacing=0 cellpadding=2><tr><td align=center colspan=4>
64   * The (i)mport and/or (b)uild options supported:</td></tr>
65   * <tr background=black><font color=white><td>Script</td><td>Associated Argument</td><td>Control</td><td>Comments</td></font></tr>
66   * <tr><td>b</td><td>-allclassifications</td><td>JCheckBox</td><td>&nbsp;</td></tr>
67   * <tr><td>i/b</td><td>-archivedir</td><td>JTextField</td><td>&nbsp;</td></tr>
68   * <tr><td>b</td><td>-builddir</td><td>JTextField</td><td>&nbsp;</td></tr>
69   * <tr><td>i/b</td><td>-debug</td><td>JCheckBox</td><td>&nbsp;</td></tr>
70   * <tr><td>i/b</td><td>-collectdir</td><td>JTextField</td><td>&nbsp;</td></tr>
71   * <tr><td>b</td><td>-create_images</td><td>JCheckBox</td><td>&nbsp;</td></tr>
72   * <tr><td>i</td><td>-groupsize</td><td>JSpinner </td><td>&nbsp;</td></tr>
73   * <tr><td>i</td><td>-gzip</td><td>JCheckBox</td><td>&nbsp;</td></tr>
74   * <tr><td>i</td><td>-importdir</td><td>JTextField</td><td>&nbsp;</td></tr>
75   * <tr><td>b</td><td>-index</td><td>GCheckList</td><td>&nbsp;</td></tr>
76   * <tr><td>i/b</td><td>-keepold</td><td>JCheckBox</td><td>sanity check removeold</td></tr>
77   * <tr><td>i/b</td><td>-maxdocs</td><td>JSpinner</td><td>&nbsp;</td></tr>
78   * <tr><td>b</td><td>-mode</td><td>JComboBox</td><td>"all", "compress_text", "infodb", "build_index"</td></tr>
79   * <tr><td>b</td><td>-no_text</td><td>JCheckBox</td><td>&nbsp;</td></tr>
80   * <tr><td>i</td><td>-OIDtype</td><td>JComboBox</td><td>"hash","incremental"</td></tr>
81   * <tr><td>i/b</td><td>-out</td><td>JTextField</td><td>&nbsp;</td></tr>
82   * <tr><td>i</td><td>-removeold</td><td>JCheckBox</td><td>sanity check keepold</td></tr>
83   * <tr><td>i</td><td>-sortmeta</td><td>JComboBox</td><td>&nbsp;</td></tr>
84   * <tr><td>i/b</td><td>-verbosity</td><td>JSpinner</td><td>1, 3</td></tr>
85   * </table></center>
86   * @author John Thompson, Greenstone Digital Library, University of Waikato
87   * @version 2.3
88   */
89  public class CreatePane
90      extends JPanel
91      implements GShellListener {
92      /** Determines the current view that should be shown for this pane. */
93      public boolean processing = false;
94      /** The options pane generates all the various option sheet configuations. */
95      public OptionsPane options_pane = null;
96      private AppendLineOnlyFileDocument document;
97      /** A card layout is used to store the separate configuration and progress panes. */
98      private CardLayout card_layout = null;
99      /** Stores a reference to the current collection. */
100     private Collection previous_collection = null;
101     /** This monitor tracks the build processes progress. */
102     private GShellProgressMonitor build_monitor = null;
103     /** This monitor tracks the copy processes progress. */
104     private GShellProgressMonitor copy_monitor = null;
105     /** This monitor tracks the import processes progress. */
106     private GShellProgressMonitor import_monitor = null;
107     /** The button for begining the building processes. */
108     private JButton build_button = null;
109     /** The button for stopping the building processes. */
110     private JButton cancel_button = null;
111     /** The button for viewing the collection. */
112     private JButton preview_button = null;
113     /** The label displaying the number of documents in this collection. */
114     private JLabel document_count = null;
115     /** The label alongside the build progress bar gets some special treatment so... */
116     private JLabel progress_build_label = null;
117     /** The label alongside the copy progress bar gets some special treatment so... */
118     private JLabel progress_copy_label = null;
119     /** The label alongside the import progress bar gets some special treatment so... */
120     private JLabel progress_import_label = null;
121     /** The pane which contains the controls for configuration. */
122     private JPanel control_pane = null;
123     /** The pane which has the card layout as its manager. */
124     private JPanel main_pane = null;
125     /** The pane which contains the progress information. */
126     private JPanel progress_pane = null;
127     /** the pane on the right-hand side - shows the requested options view */
128     private JPanel right = null;
129     /** the scrolling pane the righthand side is inside - only used for import and build options. the log and log list are not inside a scrollpane */
130     private JScrollPane scroll_pane;
131     /** The message log for the entire session. */
132     private JTextArea log_textarea;
133     /** A tree used to display the currently available option views. */
134     private OptionTree tree = null;
135     /** An array used to pass arguments with dictionary calls. */
136     private String args[] = null;
137     /** The homepage address of the current collection */
138     private String homepage = null;
139     /** The size of the buttons at the bottom of the screen. */
140     static private Dimension BUTTON_SIZE = new Dimension (256, 50);//(386, 50);
141     /** The size of the labels on the progress pane. */
142     static private Dimension LABEL_SIZE = new Dimension(140, 25);
143     /** An identifier for the control panel within the card layout. */
144     static private String CONTROL = "Control";
145     /** An identifier for the progress panel within the card layout. */
146     static private String PROGRESS      = "Progress";
147 
148     /** The constructor creates important helper classes, and initializes all the components.
149      * @see org.greenstone.gatherer.collection.CollectionManager
150      * @see org.greenstone.gatherer.gui.BuildOptions
151      * @see org.greenstone.gatherer.gui.CreatePane.BuildButtonListener
152      * @see org.greenstone.gatherer.gui.CreatePane.CancelButtonListener
153      * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
154      * @see org.greenstone.gatherer.gui.OptionsPane
155      * @see org.greenstone.gatherer.shell.GBasicProgressMonitor
156      * @see org.greenstone.gatherer.shell.GBuildProgressMonitor
157      * @see org.greenstone.gatherer.shell.GImportProgressMonitor
158      * @see org.greenstone.gatherer.shell.GShellProgressMonitor
159      */
160     public CreatePane() {
161   Collection collection = Gatherer.c_man.getCollection();
162   log_textarea = new JTextArea();
163 
164   // Create components
165   card_layout = new CardLayout();
166   // Control Pane
167   control_pane = new JPanel();
168   tree = new OptionTree();
169 
170   // Progress Pane
171   progress_pane = new JPanel();
172 
173   progress_copy_label = new JLabel();
174   progress_copy_label.setForeground(Color.black);
175   progress_copy_label.setHorizontalAlignment(JLabel.LEFT);
176   progress_copy_label.setPreferredSize(LABEL_SIZE);
177   progress_copy_label.setMinimumSize(LABEL_SIZE);
178   progress_copy_label.setSize(LABEL_SIZE);
179   Dictionary.registerText(progress_copy_label, "CreatePane.Copy_Progress");
180 
181   copy_monitor = new GBasicProgressMonitor();
182   Gatherer.c_man.registerCopyMonitor(copy_monitor);
183 
184   progress_import_label = new JLabel();
185   progress_import_label.setForeground(Color.black);
186   progress_import_label.setHorizontalAlignment(JLabel.LEFT);
187   progress_import_label.setPreferredSize(LABEL_SIZE);
188   progress_import_label.setMinimumSize(LABEL_SIZE);
189   progress_import_label.setSize(LABEL_SIZE);
190   Dictionary.registerText(progress_import_label, "CreatePane.Import_Progress");
191 
192   import_monitor = new GImportProgressMonitor(); //GBasicProgressMonitor();
193   Gatherer.c_man.registerImportMonitor(import_monitor);
194 
195   progress_build_label = new JLabel();
196   progress_build_label.setForeground(Color.black);
197   progress_build_label.setHorizontalAlignment(JLabel.LEFT);
198   progress_build_label.setPreferredSize(LABEL_SIZE);
199   progress_build_label.setMinimumSize(LABEL_SIZE);
200   progress_build_label.setSize(LABEL_SIZE);
201   Dictionary.registerText(progress_build_label, "CreatePane.Build_Progress");
202 
203   build_monitor = new GBuildProgressMonitor((GImportProgressMonitor)import_monitor); //GBasicProgressMonitor();
204   Gatherer.c_man.registerBuildMonitor(build_monitor);
205 
206   // Buttons
207   build_button = new JButton();
208   build_button.addActionListener(new BuildButtonListener());
209   build_button.setPreferredSize(BUTTON_SIZE);
210   Dictionary.registerBoth(build_button, "CreatePane.Build_Collection", "CreatePane.Build_Collection_Tooltip");
211 
212   cancel_button = new JButton();
213   cancel_button.addActionListener(new CancelButtonListener());
214   cancel_button.setEnabled(false);
215   cancel_button.setPreferredSize(BUTTON_SIZE);
216   Dictionary.registerBoth(cancel_button, "CreatePane.Cancel_Build", "CreatePane.Cancel_Build_Tooltip");
217 
218   preview_button = new JButton();
219   preview_button.addActionListener(new PreviewButtonListener());
220   preview_button.setEnabled(false);
221   preview_button.setPreferredSize(BUTTON_SIZE);
222   Dictionary.registerBoth(preview_button, "CreatePane.Preview_Collection", "CreatePane.Preview_Collection_Tooltip");
223     }
224 
225     /** This method is invoked at any time there has been a significant change in the collection, such as saving, loading or creating.
226      * @param ready A <strong>boolean</strong> indicating if a collection is currently available.
227      * @see org.greenstone.gatherer.Gatherer
228      * @see org.greenstone.gatherer.collection.CollectionManager
229      * @see org.greenstone.gatherer.gui.BuildOptions
230      * @see org.greenstone.gatherer.gui.OptionsPane
231      */
232     public void collectionChanged(boolean ready) {
233   ///ystem.err.println("Collection changed... ");
234   if(Gatherer.c_man == null || !ready) {
235       return;
236   }
237   Collection current_collection = Gatherer.c_man.getCollection();
238   if (current_collection != previous_collection) {
239       this.options_pane = new OptionsPane(current_collection.build_options);
240       previous_collection = current_collection;
241   }
242   tree.valueChanged(null);
243   
244   // now do the preview stuff
245   if (!Gatherer.c_man.built() || Gatherer.config.exec_address == null) {
246       preview_button.setEnabled(false);
247   } else {
248       preview_button.setEnabled(true);
249   }
250     }
251     
252     /** This method is called to actually layout the components.
253      * @see org.greenstone.gatherer.Configuration
254      * @see org.greenstone.gatherer.Gatherer
255      */
256     public void display() {
257 
258   // Build control_pane
259   JPanel left = new JPanel();
260   left.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
261   left.setLayout(new BorderLayout());
262   left.add(tree, BorderLayout.CENTER);
263 
264   right = new JPanel();
265   right.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
266   right.setLayout(new BorderLayout());
267 
268   JPanel options_area = new JPanel();
269   options_area.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createTitledBorder(Dictionary.get("CreatePane.Options_Title"))));
270   options_area.setLayout(new BorderLayout());
271   options_area.add(left, BorderLayout.WEST);
272   options_area.add(right, BorderLayout.CENTER);
273 
274   control_pane.setLayout(new BorderLayout());
275   control_pane.add(options_area, BorderLayout.CENTER);
276 
277   // Build progress_pane
278   JPanel copy_pane = new JPanel();
279   copy_pane.setLayout(new BorderLayout());
280   copy_pane.add(progress_copy_label, BorderLayout.WEST);
281   copy_pane.add(copy_monitor.getProgress(), BorderLayout.CENTER);
282 
283   JPanel import_pane = new JPanel();
284   import_pane.setLayout(new BorderLayout());
285   import_pane.add(progress_import_label, BorderLayout.WEST);
286   import_pane.add(import_monitor.getProgress(), BorderLayout.CENTER);
287 
288   JPanel build_pane = new JPanel();
289   build_pane.setLayout(new BorderLayout());
290   build_pane.add(progress_build_label, BorderLayout.WEST);
291   build_pane.add(build_monitor.getProgress(), BorderLayout.CENTER);
292 
293   JPanel bar_area = new JPanel();
294   bar_area.setBorder(BorderFactory.createEmptyBorder(10,10,5,10));
295 
296   bar_area.setLayout(new GridLayout(2,2,10,5));
297   bar_area.add(import_pane);
298   bar_area.add(build_pane);
299 
300   progress_pane.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
301   progress_pane.setLayout(new BorderLayout());
302   progress_pane.add(bar_area, BorderLayout.NORTH);
303   progress_pane.add(new JScrollPane(log_textarea), BorderLayout.CENTER);
304 
305   // Main pane
306   main_pane = new JPanel(card_layout);
307   main_pane.add(control_pane, CONTROL);
308   main_pane.add(progress_pane, PROGRESS);
309 
310   // Buttons
311   JPanel button_pane = new JPanel();
312   button_pane.setBorder(BorderFactory.createEmptyBorder(5,10,10,10));
313   button_pane.setLayout(new GridLayout(1,2));
314   button_pane.add(build_button);
315   button_pane.add(cancel_button);
316   button_pane.add(preview_button);
317 
318   this.setLayout(new BorderLayout());
319   this.add(main_pane, BorderLayout.CENTER);
320   this.add(button_pane, BorderLayout.SOUTH);
321     }
322 
323     /** This method is called whenever the 'Create' tab is selected from the view bar. It allows this view to perform any preactions required prior to display. In this case this entails gathering up to date information about the status of the collection including number of documents etc.
324      * @see org.greenstone.gatherer.Gatherer
325      * @see org.greenstone.gatherer.collection.CollectionManager
326      * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
327      */
328     public void gainFocus() {
329   if(!processing) {
330       card_layout.show(main_pane, CONTROL);
331   }
332   // Refresh the set of controls.
333   TreePath path = tree.getSelectionPath();
334   tree.clearSelection();
335   tree.setSelectionPath(path);
336     }
337 
338     /** Method to acquire the progress monitor associated with builds.
339      * @return The build <strong>GShellProgressMonitor</strong>.
340      */
341     /* private GShellProgressMonitor getBuildProgress() {
342   return build_monitor;
343   } */
344 
345     /** Method to acquire the progress monitor associated with copying.
346      * @return The copying <strong>GShellProgressMonitor</strong>.
347      */
348     /* private GShellProgressMonitor getCopyProgress() {
349   return copy_monitor;
350   } */
351 
352     /** Method to acquire the progress monitor associated with import.
353      * @return The import <strong>GShellProgressMonitor</strong>.
354      */
355     /* private GShellProgressMonitor getImportProgress() {
356   return import_monitor;
357   } */
358 
359     /** We are informed when this view pane loses focus so we can update build options. */
360     public void loseFocus() {
361   tree.valueChanged(null);
362     }
363 
364     /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
365      * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
366      */
367     public synchronized void message(GShellEvent event) {
368   // Ignore the messages from RecPlug with 'show_progress' set (used for progress bars)
369   if (event.getMessage().startsWith("import.pl> RecPlug - ")) {
370       return;
371   }
372   document.appendLine(event.getMessage());
373   log_textarea.setCaretPosition(document.getLengthToNearestLine());
374     }
375 
376     /** All implementation of GShellListener must include this method so the listener can be informed when a GShell begins its task. Implementation side-effect, not actually used.
377      * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
378      */
379     public synchronized void processBegun(GShellEvent event) {
380   // We don't care. We'll get a more acurate start from the progress monitors.
381     }
382     /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
383      * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
384      */
385     public synchronized void processComplete(GShellEvent event) {
386   if(event.getStatus() == GShell.OK) {
387       if(event.getType() == GShell.BUILD) {
388     processing = false;
389     cancel_button.setEnabled(false);
390     build_button.setEnabled(true);
391     preview_button.setEnabled(true);
392     int status = event.getStatus();
393     document.setSpecialCharacter(OptionsPane.SUCCESSFUL);
394     options_pane.resetFileEntry();
395     card_layout.show(main_pane, CONTROL);
396       }
397       // Otherwise its completed import but still got build to go
398   }
399   else {
400       processing = false;
401       cancel_button.setEnabled(false);
402       build_button.setEnabled(true);
403       // The build may have failed, but a previous index may still be in place
404       preview_button.setEnabled(Gatherer.c_man.built());
405       if(event.getStatus() == GShell.CANCELLED) {
406     document.setSpecialCharacter(OptionsPane.CANCELLED);
407       }
408       else {
409     document.setSpecialCharacter(OptionsPane.UNSUCCESSFUL);
410       }
411       options_pane.resetFileEntry();
412       card_layout.show(main_pane, CONTROL);
413   }
414     }
415 
416     private void configureHomeURL() {  
417   // set up the home page for the current collection
418   Collection current_collection = Gatherer.c_man.getCollection();
419   String extra_args = "";
420   SearchTypeManager st_man = current_collection.cdm.searchtype_manager;
421   if (st_man.isMGPPEnabled()) {
422       // we need some more args on the url
423       String search_types = st_man.getSearchTypes();
424       if (search_types.equals("")) {
425     extra_args = "&ct=1&qt=0&qto=3";
426       } else if (search_types.equals("plain")) {
427     extra_args = "&ct=1&qt=0&qto=1";
428       } else if (search_types.equals("form")) {
429     extra_args = "&ct=1&qt=1&qto=2";
430       } else if (search_types.equals("plain,form")) {
431     extra_args = "&ct=1&qt=0&qto=3";
432       } else if (search_types.equals("form,plain")) {
433     extra_args = "&ct=1&qt=1&qto=3";
434       }
435   }
436   // Remember to add unique timestamp
437   homepage = Gatherer.config.exec_address.toString() + "?a=p&p=about&c=" + current_collection.getName()+extra_args + StaticStrings.TIMESTAMP_ARGUMENT + System.currentTimeMillis();
438   
439     }
440     
441 
442     /** This class serves as the listener for actions on the build button. */
443     private class BuildButtonListener
444   implements ActionListener {
445   /** This method causes a call to be made to CollectionManager.importCollection(), which then imports and builds the collection as necessary.
446    * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
447    * @see org.greenstone.gatherer.Gatherer
448    * @see org.greenstone.gatherer.collection.CollectionManager
449    * @see org.greenstone.gatherer.gui.BuildOptions
450    * @see org.greenstone.gatherer.shell.GShellProgressMonitor
451    */
452   public void actionPerformed(ActionEvent event) {
453       // First we force the build options to be updated if we haven't already.
454       tree.valueChanged(null);
455       // Now go about building.
456       build_button.setEnabled(false);
457       cancel_button.setEnabled(true);
458       preview_button.setEnabled(false);
459       // Create a new log document and assign it to the two textareas
460       document = options_pane.createNewLogDocument();
461       log_textarea.setDocument(document);
462       options_pane.log_textarea.setDocument(document);
463       // Change the view.
464       processing = true;
465       card_layout.show(main_pane, PROGRESS);
466       // Reset the stop flag in all the process monitors, just incase.
467       ((GBuildProgressMonitor)build_monitor).reset();
468       copy_monitor.setStop(false);
469       import_monitor.setStop(false);
470       // Set removeold automatically.
471       if(Gatherer.c_man.ready() && Gatherer.c_man.built()) {
472     Gatherer.c_man.getCollection().build_options.setImportValue("removeold", true, null);
473       }
474       // Call CollectionManagers method to build collection.
475       Gatherer.c_man.importCollection();
476   }
477     }
478     /** This class serves as the listener for actions on the cancel button. */
479     private class CancelButtonListener
480   implements ActionListener {
481   /** This method attempts to cancel the current GShell task. It does this by first telling CollectionManager not to carry out any further action. This it turn tells the GShell to break from the current job immediately, without waiting for the processEnded message, and then kills the thread in an attempt to stop the process. The results of such an action are debatable.
482    * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
483    * @see org.greenstone.gatherer.Gatherer
484    * @see org.greenstone.gatherer.collection.CollectionManager
485    * @see org.greenstone.gatherer.gui.BuildOptions
486    * @see org.greenstone.gatherer.shell.GShellProgressMonitor
487    */
488   public void actionPerformed(ActionEvent event) {
489       build_button.setEnabled(true);
490       cancel_button.setEnabled(false);
491       preview_button.setEnabled(false);
492       processing = false;
493       document.setSpecialCharacter(OptionsPane.CANCELLED);
494       card_layout.show(main_pane, CONTROL);
495       // Set the stop flag in all the process monitor.
496       build_monitor.setStop(true);
497       copy_monitor.setStop(true);
498       import_monitor.setStop(true);
499       // Set removeold automatically.
500       Gatherer.c_man.getCollection().build_options.setImportValue("removeold", true, null);
501       // Remove the collection lock.
502       //Gatherer.g_man.lockCollection(false, false);
503   }
504     }
505 
506     private class PreviewButtonListener
507   implements ActionListener {
508   
509   public void actionPerformed(ActionEvent event) {
510       configureHomeURL();
511       Gatherer.self.spawnBrowser(homepage);
512 
513   }
514     }
515     
516     /** The OptionTree is simply a tree structure that has a root node labelled "Options" and then has a child node for each available options screen. These screens are either combinations of the available import and build arguments, or a message log detailing the shell processes progress. */
517     private class OptionTree
518   extends JTree
519   implements TreeSelectionListener {
520   /** The model behind the tree. */
521   private DefaultTreeModel model = null;
522   /** The previous options view displayed, which is sometimes needed to refresh properly. */
523   private JPanel previous_pane = null;
524   /** The node corresponding to the building options view. */
525   private OptionTreeNode building  = null;
526   /** The node corresponding to the importing options view. */
527   private OptionTreeNode importing = null;
528   /** The node corresponding to the log view. */
529   private OptionTreeNode log       = null;
530   /** The root node of the options tree, which has no associated options view. */
531   private OptionTreeNode options   = null;
532   /** Constructor.
533    * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
534    */
535   public OptionTree() {
536       super();
537 
538       ToolTipManager.sharedInstance().registerComponent(this);
539       addTreeSelectionListener(this);
540       getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
541       setCellRenderer(new ToolTipTreeCellRenderer());
542       setRootVisible(false);
543       setToggleClickCount(1);
544 
545       // Create tree.
546       building = new OptionTreeNode(Dictionary.get("CreatePane.Build"));
547       building.setToolTipText(Dictionary.get("CreatePane.Build_Tooltip"));
548       importing = new OptionTreeNode(Dictionary.get("CreatePane.Import"));
549       importing.setToolTipText(Dictionary.get("CreatePane.Import_Tooltip"));
550       log = new OptionTreeNode(Dictionary.get("CreatePane.Log"));
551       log.setToolTipText(Dictionary.get("CreatePane.Log_Tooltip"));
552       options = new OptionTreeNode(Dictionary.get("CreatePane.Options"));
553 
554       model = new DefaultTreeModel(options);
555       setModel(model);
556       model.insertNodeInto(importing, options, 0);
557       model.insertNodeInto(building, options, 1);
558       model.insertNodeInto(log, options, 2);
559       // Expand the root node
560       expandPath(new TreePath(options));
561   }
562   /** Any implementation of TreeSelectionListener must include this method to allow this listener to know when the selection has changed. Here we swap the options view depending on the selected OptionTreeNode.
563    * @param event A <Strong>TreeSelectionEvent</strong> which contains all the information garnered when the event occured.
564    * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
565    */
566   public void valueChanged(TreeSelectionEvent event) {
567       TreePath path = null;
568       OptionTreeNode node = null;
569       //if(event != null) {
570       //path = event.getPath();
571       path = getSelectionPath();
572       if(path != null) {
573     node = (OptionTreeNode)path.getLastPathComponent();
574       }
575         //}
576       if(previous_pane != null) {
577     //target_pane.remove(previous_pane);
578     options_pane.update(previous_pane);
579     if(scroll_pane != null) {
580         right.remove(scroll_pane);
581     }
582     else {
583         right.remove(previous_pane);
584     }
585     previous_pane = null;
586     scroll_pane = null;
587       }
588       if(node != null && node.equals(building)) {
589     previous_pane = options_pane.buildBuild();
590     scroll_pane = new JScrollPane(previous_pane);
591     right.add(scroll_pane, BorderLayout.CENTER);
592     //target_pane.add(previous_pane, BorderLayout.CENTER);
593       }
594       else if(node != null && node.equals(importing)) {
595     previous_pane = options_pane.buildImport();
596     scroll_pane = new JScrollPane(previous_pane);
597     right.add(scroll_pane, BorderLayout.CENTER);
598     //target_pane.add(previous_pane, BorderLayout.CENTER);
599       }
600       else {
601     previous_pane = options_pane.buildLog();
602     right.add(previous_pane, BorderLayout.CENTER);
603     right.updateUI(); // we need to repaint the log pane, cos it hasn't changed since last time
604     ///ystem.err.println("I've added the log back to the right pane again.");
605     //target_pane.add(previous_pane, BorderLayout.CENTER);
606       }
607         //scroll_pane.setViewportView(previous_pane);
608       //previous_pane.validate();
609       right.validate();
610       //System.err.println("Current pane size: " + previous_pane.getSize());
611       //System.err.println("While its preferred size is: " + previous_pane.getPreferredSize());
612   }
613     }
614 
615     /** The <strong>OptionTree</strong> is built from these nodes, each of which has several methods used in creating the option panes.
616      */
617     private class OptionTreeNode
618   extends DefaultMutableTreeNode
619   implements Comparable {
620   /** The text label given to this node in the tree. */
621   private String title = null;
622   /** a tool tip to be used for this node in the tree */
623   private String tool_tip = null;
624   /** Constructor.
625    * @param title The <strong>String</strong> which serves as this nodes title.
626    */
627   public OptionTreeNode(String title) {
628       super();
629       this.title = title;
630   }
631 
632   /** This method compares two nodes for ordering.
633    * @param obj The <strong>Object</strong> to compare to.
634    * @return An <strong>int</strong> of one of the possible values -1, 0 or 1 indicating if this node is less than, equal to or greater than the target node respectively.
635    */
636   public int compareTo(Object obj) {
637       return title.compareTo(obj.toString());
638   }
639 
640   /** This method checks if two nodes are equivalent.
641    * @param obj The <strong>Object</strong> to be tested against.
642    * @return A <strong>boolean</strong> which is <i>true</i> if the objects are equal, <i>false</i> otherwise.
643    */
644   public boolean equals(Object obj) {
645       if(compareTo(obj) == 0) {
646     return true;
647       }
648       return false;
649   }
650 
651   /** get the tool tip */
652   public String getToolTipText() {
653       return tool_tip;
654   }
655 
656   /** set the tool tip */
657   public void setToolTipText(String tip) {
658       tool_tip = tip;
659   }
660   
661   /** Method to translate this node into a textual representation.
662    * @return A <strong>String</strong> which in this case is the title.
663    */
664   public String toString() {
665       return title;
666   }
667     }
668 
669     // Adds tooltips to the tree nodes
670     private class ToolTipTreeCellRenderer
671   extends DefaultTreeCellRenderer {
672 
673   public Component getTreeCellRendererComponent(JTree tree,
674                   Object value,
675                   boolean sel,
676                   boolean expanded,
677                   boolean leaf,
678                   int row,
679                   boolean hasFocus) {
680 
681       super.getTreeCellRendererComponent(tree, value, sel,
682                  expanded, leaf, row,
683                  hasFocus);
684       if (value instanceof OptionTreeNode) {
685     String tip = ((OptionTreeNode) value).getToolTipText();
686     if (tip != null) {
687         setToolTipText(tip);
688     }
689       }
690       return this;
691   }
692     }
693 }