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> </td></tr>
67 * <tr><td>i/b</td><td>-archivedir</td><td>JTextField</td><td> </td></tr>
68 * <tr><td>b</td><td>-builddir</td><td>JTextField</td><td> </td></tr>
69 * <tr><td>i/b</td><td>-debug</td><td>JCheckBox</td><td> </td></tr>
70 * <tr><td>i/b</td><td>-collectdir</td><td>JTextField</td><td> </td></tr>
71 * <tr><td>b</td><td>-create_images</td><td>JCheckBox</td><td> </td></tr>
72 * <tr><td>i</td><td>-groupsize</td><td>JSpinner </td><td> </td></tr>
73 * <tr><td>i</td><td>-gzip</td><td>JCheckBox</td><td> </td></tr>
74 * <tr><td>i</td><td>-importdir</td><td>JTextField</td><td> </td></tr>
75 * <tr><td>b</td><td>-index</td><td>GCheckList</td><td> </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> </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> </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> </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> </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 }