source: main/trunk/gli/src/org/greenstone/gatherer/gui/CreatePane.java@ 34287

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

Belongs with previous commit, had left out one more file that needed committing. Client-GLI was noticeably slow compared to GLI when swapping between format statements or when typing anything into a format statement. The cause was my own mistake from 9 years ago (commit revision 24424) when I didn't know that the CollectionManager.built() operation was an expensive remote call in the case of IsGsdlRemote. This function was being called to determine if the previewbutton should really be available (enabled or disabled) so that the user could not accidentally attempt to preview an unbuilt collection. However, I must not have realised back then that the previewbutton was being set this way at every character added into the Format statements editor, as well as when swapping between one format statement and another. As a result, all of such user action was being severely delayed when isGsdlRemote was true. Fixed this now by adding a function CollectionManager.previewAvailable() that returns the last known result of the built() call. Client-GLI's format pane is now thankfully so much faster, rather than a pain to use.

  • Property svn:keywords set to Author Date Id Revision
File size: 48.8 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.event.*;
41import java.io.*;
42import javax.swing.*;
43import javax.swing.event.*;
44import javax.swing.text.*;
45import javax.swing.tree.*;
46import org.greenstone.gatherer.DebugStream;
47import org.greenstone.gatherer.Configuration;
48import org.greenstone.gatherer.Dictionary;
49import org.greenstone.gatherer.Gatherer;
50import org.greenstone.gatherer.cdm.BuildTypeManager;
51import org.greenstone.gatherer.cdm.CollectionDesignManager;
52import org.greenstone.gatherer.collection.Collection;
53import org.greenstone.gatherer.shell.GBuildProgressMonitor;
54import org.greenstone.gatherer.shell.GImportProgressMonitor;
55import org.greenstone.gatherer.shell.GScheduleProgressMonitor;
56import org.greenstone.gatherer.shell.GShell;
57import org.greenstone.gatherer.shell.GShellEvent;
58import org.greenstone.gatherer.shell.GShellListener;
59import org.greenstone.gatherer.shell.GShellProgressMonitor;
60import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
61import org.greenstone.gatherer.util.StaticStrings;
62import org.greenstone.gatherer.util.Utility;
63
64import org.greenstone.gatherer.collection.CollectionManager;
65import org.greenstone.gatherer.util.GS3ServerThread;
66
67/** 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>
68 * @author John Thompson, Greenstone Digital Library, University of Waikato
69 * @version 2.3
70 */
71public class CreatePane
72 extends JPanel
73 implements GShellListener {
74
75 static private Dimension ARGUMENT_SIZE = new Dimension(800,90);
76 /** The threshold for when the simple view is replaced by the complex one. */
77 static private final int THRESHOLD = Configuration.EXPERT_MODE;
78 /** An identifier for the control panel within the card layout. */
79 static private String CONTROL = "Control";
80 /** An identifier for the progress panel within the card layout. */
81 static private String PROGRESS = "Progress";
82 /** An identifier for the simple panel within the card layout. */
83 static private String SIMPLE = "Simple";
84
85 /** Determines the current view that should be shown for this pane. */
86 public boolean processing = false;
87 /** The options pane generates all the various option sheet configuations. */
88 public OptionsPane options_pane = null;
89 private AppendLineOnlyFileDocument document;
90 /** A card layout is used to store the separate configuration and progress panes. */
91 private CardLayout card_layout = null;
92 /** Stores a reference to the current collection. */
93 private Collection previous_collection = null;
94 /** This monitor tracks the build processes progress. */
95 private GShellProgressMonitor build_monitor = null;
96 /** This monitor tracks the import processes progress. */
97 private GShellProgressMonitor import_monitor = null;
98 /** This monitor tracks the schedule processes progress. */
99 private GShellProgressMonitor schedule_monitor = null;
100 /** The button for begining the building processes. */
101 private JButton build_button = null;
102 /** The button for stopping the building processes. */
103 private JButton cancel_button = null;
104 /** The button for setting up scheduling */
105 private JButton schedule_button = null;
106 /** The button for viewing the collection. */
107 private JButton preview_button = null;
108 private JButton simple_build_button;
109 private JButton simple_cancel_button;
110 private JButton simple_preview_button;
111 /** The radio buttons for chnaging the build type (incremental/full) */
112 private JRadioButton full_build_radio_button;
113 private JRadioButton incremental_build_radio_button;
114 private JRadioButton sfull_build_radio_button;
115 private JRadioButton sincremental_build_radio_button;
116 /** The label displaying the number of documents in this collection. */
117 private JLabel document_count = null;
118 /** The label alongside the build progress bar gets some special treatment so... */
119 private JLabel progress_build_label = null;
120 /** The label alongside the import progress bar gets some special treatment so... */
121 private JLabel progress_import_label = null;
122 private JPanel bar_area;
123 /** The panel on which buttons are rendered on higher detail modes. */
124 private JPanel button_pane;
125 /** The pane which contains the controls for configuration. */
126 private JPanel control_pane = null;
127 /** The pane which has the card layout as its manager. */
128 private JPanel main_pane = null;
129 /** The pane which contains the progress information. */
130 private JPanel progress_pane = null;
131 /** The pane on the right-hand side - shows the requested options view */
132 private JPanel right = null;
133 /** The simple panel on which all of the available arguments are rendered. */
134 private JPanel sargument_configuration_panel;
135 /** The panel on which buttons are rendered on lower details modes. */
136 private JPanel sbutton_panel;
137 /** A simplified version for lower detail modes containing both the control and progress panes smooshed together. */
138 private JSplitPane simple_panel;
139 /** The lower part of the panel which is global so the log pane can be added and removed from it */
140 private JPanel slower_panel;
141 /** The inner panel of the simple pane which is global so that the bar_area can be added and removed from it. */
142 private JPanel sinner_panel;
143 /** The scrolling pane for the log. */
144 private JScrollPane log_scroll;
145 /** The scrolling pane the simple arguments are rendered within. */
146 private JScrollPane sargument_configuration_scroll;
147 /** 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 */
148 private JScrollPane scroll_pane;
149 /** The message log for the entire session. */
150 private JTextArea log_textarea;
151 /** A tree used to display the currently available option views. */
152 private OptionTree tree = null;
153 /** An array used to pass arguments with dictionary calls. */
154 private String args[] = null;
155 /** The homepage address of the current collection */
156 public String homepage = null;
157
158 /** Access to the GShell object that this CreatePane listens to events for.
159 * A handle to the GShell is needed order to interrupt any processes the GShell runs
160 * when the user cancels a build operation.
161 */
162 private GShell shell = null;
163
164 /** The constructor creates important helper classes, and initializes all the components.
165 * @see org.greenstone.gatherer.collection.CollectionManager
166 * @see org.greenstone.gatherer.gui.BuildOptions
167 * @see org.greenstone.gatherer.gui.CreatePane.BuildButtonListener
168 * @see org.greenstone.gatherer.gui.CreatePane.CancelButtonListener
169 * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
170 * @see org.greenstone.gatherer.gui.OptionsPane
171 * @see org.greenstone.gatherer.shell.GBuildProgressMonitor
172 * @see org.greenstone.gatherer.shell.GImportProgressMonitor
173 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
174 */
175 public CreatePane() {
176 this.setComponentOrientation(Dictionary.getOrientation());
177 log_textarea = new JTextArea();
178 log_scroll = new JScrollPane(log_textarea);
179
180 // Create components
181 card_layout = new CardLayout();
182 // Control Pane
183 control_pane = new JPanel();
184 control_pane.setComponentOrientation(Dictionary.getOrientation());
185 tree = new OptionTree();
186 tree.setComponentOrientation(Dictionary.getOrientation());
187 button_pane = new JPanel();
188 button_pane.setComponentOrientation(Dictionary.getOrientation());
189
190 // Progress Pane
191 progress_pane = new JPanel(); // One owner of the bar component
192 progress_pane.setComponentOrientation(Dictionary.getOrientation());
193 bar_area = new JPanel(); // This component will be shared about
194 bar_area.setComponentOrientation(Dictionary.getOrientation());
195
196 progress_import_label = new JLabel(Dictionary.get("CreatePane.Import_Progress"));
197 progress_import_label.setComponentOrientation(Dictionary.getOrientation());
198
199 import_monitor = new GImportProgressMonitor();
200 Gatherer.c_man.registerImportMonitor(import_monitor);
201
202 progress_build_label = new JLabel(Dictionary.get("CreatePane.Build_Progress"));
203 progress_build_label.setComponentOrientation(Dictionary.getOrientation());
204
205 build_monitor = new GBuildProgressMonitor(import_monitor.getSharedProgress());
206 Gatherer.c_man.registerBuildMonitor(build_monitor);
207
208 //We only need a schedule monitor for text output. No use for a progress bar!
209
210 //progress_schedule_label = new JLabel(Dictionary.get("CreatePane.Schedule_Progress"));
211
212 schedule_monitor = new GScheduleProgressMonitor();
213 Gatherer.c_man.registerScheduleMonitor(schedule_monitor);
214
215 // And the simple panel
216 slower_panel = new JPanel();
217 sbutton_panel = new JPanel();
218 sinner_panel = new JPanel();
219
220 slower_panel.setComponentOrientation(Dictionary.getOrientation());
221 sbutton_panel.setComponentOrientation(Dictionary.getOrientation());
222 sinner_panel.setComponentOrientation(Dictionary.getOrientation());
223
224 //Radio buttons
225 incremental_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Minimal_Build"));
226 incremental_build_radio_button.setComponentOrientation(Dictionary.getOrientation());
227 incremental_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Minimal_Build_Tooltip"));
228 full_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Full_Build"));
229 full_build_radio_button.setComponentOrientation(Dictionary.getOrientation());
230 full_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Full_Build_Tooltip"));
231 sincremental_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Minimal_Build"));
232 sincremental_build_radio_button.setComponentOrientation(Dictionary.getOrientation());
233 sincremental_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Minimal_Build_Tooltip"));
234 sfull_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Full_Build"));
235 sfull_build_radio_button.setComponentOrientation(Dictionary.getOrientation());
236 sfull_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Full_Build_Tooltip"));
237
238 //keep them in sync
239 full_build_radio_button.addActionListener(
240 new ActionListener() { public void actionPerformed(ActionEvent e) {
241 sfull_build_radio_button.setSelected( full_build_radio_button.isSelected() );
242 }});
243 sfull_build_radio_button.addActionListener(
244 new ActionListener() { public void actionPerformed(ActionEvent e) {
245 full_build_radio_button.setSelected( sfull_build_radio_button.isSelected() );
246 }});
247 incremental_build_radio_button.addActionListener(
248 new ActionListener() { public void actionPerformed(ActionEvent e) {
249 sincremental_build_radio_button.setSelected( incremental_build_radio_button.isSelected() );
250 }});
251 sincremental_build_radio_button.addActionListener(
252 new ActionListener() { public void actionPerformed(ActionEvent e) {
253 incremental_build_radio_button.setSelected( sincremental_build_radio_button.isSelected() );
254 }});
255
256 // Buttons
257 BuildButtonListener bbl = new BuildButtonListener();
258 CancelButtonListener cbl = new CancelButtonListener();
259
260 build_button = new GLIButton(Dictionary.get("CreatePane.Build_Collection"), Dictionary.get("CreatePane.Build_Collection_Tooltip"));
261 build_button.addActionListener(bbl);
262
263 cancel_button = new GLIButton(Dictionary.get("CreatePane.Cancel_Build"), Dictionary.get("CreatePane.Cancel_Build_Tooltip"));
264 cancel_button.addActionListener(cbl);
265 cancel_button.setEnabled(false);
266
267 preview_button = new PreviewButton(Dictionary.get("CreatePane.Preview_Collection"), Dictionary.get("CreatePane.Preview_Collection_Tooltip"));
268 //preview_button.addActionListener(pbl);
269
270 // c_man.built() is an expensive operation for isGsdlRemote case,
271 // so calculate this once to set both preview and simple_preview buttons in one go
272 boolean been_built = Gatherer.c_man.built();
273
274 if(Gatherer.c_man != null) {
275 preview_button.setEnabled(been_built);
276 }
277 else {
278 preview_button.setEnabled(false);
279 }
280
281 BuildSimpleButtonListener bsbl = new BuildSimpleButtonListener();
282 simple_build_button = new GLIButton(Dictionary.get("CreatePane.Build_Collection"), Dictionary.get("CreatePane.Build_Collection_Tooltip"));
283 simple_build_button.addActionListener(bsbl);
284
285 simple_cancel_button = new GLIButton(Dictionary.get("CreatePane.Cancel_Build"), Dictionary.get("CreatePane.Cancel_Build_Tooltip"));
286 simple_cancel_button.addActionListener(cbl);
287 simple_cancel_button.setEnabled(false);
288
289 simple_preview_button = new PreviewButton(Dictionary.get("CreatePane.Preview_Collection"), Dictionary.get("CreatePane.Preview_Collection_Tooltip"));
290 //simple_preview_button.addActionListener(pbl);
291 if(Gatherer.c_man != null) {
292 simple_preview_button.setEnabled(been_built);
293 }
294 else {
295 simple_preview_button.setEnabled(false);
296 }
297
298 bbl = null;
299 bsbl = null;
300 cbl = null;
301 //pbl = null;
302 }
303
304 public void setGShell(GShell shell) {
305 this.shell = shell;
306 }
307
308 public void destroy() {
309 if(document != null) {
310 document.destroy();
311 }
312 }
313
314 /** This method is called to actually layout the components.
315 * @see org.greenstone.gatherer.Configuration
316 * @see org.greenstone.gatherer.Gatherer
317 */
318 public void display() {
319
320 int current_mode = Configuration.getMode();
321
322 //Complete/incremental build options panel
323 ButtonGroup build_type_group = new ButtonGroup();
324 build_type_group.add(incremental_build_radio_button);
325 build_type_group.add(full_build_radio_button);
326 full_build_radio_button.setSelected(true);
327
328 ButtonGroup sbuild_type_group = new ButtonGroup();
329 sbuild_type_group.add(sincremental_build_radio_button);
330 sbuild_type_group.add(sfull_build_radio_button);
331 sfull_build_radio_button.setSelected(true);
332
333 JPanel build_type_pane = new JPanel(new GridLayout(2,1));
334 build_type_pane.setComponentOrientation(Dictionary.getOrientation());
335 build_type_pane.add(full_build_radio_button);
336 build_type_pane.add(incremental_build_radio_button);
337
338 JPanel sbuild_type_pane = new JPanel(new GridLayout(2,1));
339 sbuild_type_pane.setComponentOrientation(Dictionary.getOrientation());
340 sbuild_type_pane.add(sfull_build_radio_button);
341 sbuild_type_pane.add(sincremental_build_radio_button);
342
343
344 // Build control_pane
345 JPanel left = new JPanel();
346 left.setComponentOrientation(Dictionary.getOrientation());
347 left.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
348 left.setLayout(new BorderLayout());
349 left.add(tree, BorderLayout.CENTER);
350 left.add(build_type_pane, BorderLayout.SOUTH);
351 //left.add(full_build_radio_button, BorderLayout.SOUTH);
352
353 right = new JPanel();
354 right.setComponentOrientation(Dictionary.getOrientation());
355 right.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
356 right.setLayout(new BorderLayout());
357
358 JPanel options_area = new JPanel();
359 options_area.setComponentOrientation(Dictionary.getOrientation());
360 options_area.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createTitledBorder(Dictionary.get("CreatePane.Options_Title"))));
361 options_area.setLayout(new BorderLayout());
362 options_area.add(left, BorderLayout.LINE_START);
363 options_area.add(right, BorderLayout.CENTER);
364
365 button_pane = new JPanel();
366 button_pane.setComponentOrientation(Dictionary.getOrientation());
367 button_pane.setBorder(BorderFactory.createEmptyBorder(5,10,10,10));
368 button_pane.setLayout(new GridLayout(1,4));
369 button_pane.add(build_button);
370 button_pane.add(cancel_button);
371 button_pane.add(preview_button);
372
373 control_pane.setLayout(new BorderLayout());
374 control_pane.add(options_area, BorderLayout.CENTER);
375 control_pane.add(button_pane, BorderLayout.SOUTH);
376
377 // Build progress_pane
378 JPanel labels_pane = new JPanel();
379 labels_pane.setComponentOrientation(Dictionary.getOrientation());
380 labels_pane.setLayout(new GridLayout(2,1,0,5));
381 labels_pane.add(progress_import_label);
382 labels_pane.add(progress_build_label);
383
384 JPanel monitors_pane = new JPanel();
385 monitors_pane.setComponentOrientation(Dictionary.getOrientation());
386 monitors_pane.setLayout(new GridLayout(2,1,0,5));
387 monitors_pane.add(import_monitor.getProgress());
388 monitors_pane.add(build_monitor.getProgress());
389
390 bar_area.setBorder(BorderFactory.createEmptyBorder(10,10,5,10));
391 bar_area.setLayout(new BorderLayout(5,5));
392 bar_area.add(labels_pane, BorderLayout.LINE_START);
393 bar_area.add(monitors_pane, BorderLayout.CENTER);
394
395 progress_pane.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
396 progress_pane.setLayout(new BorderLayout());
397 progress_pane.add(bar_area, BorderLayout.NORTH);
398 if(current_mode >= THRESHOLD) {
399 progress_pane.add(log_scroll, BorderLayout.CENTER);
400 }
401
402 // Simple panel
403 sbutton_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
404 sbutton_panel.setLayout(new GridLayout(1,3));
405 sbutton_panel.add(simple_build_button);
406 sbutton_panel.add(simple_cancel_button);
407 sbutton_panel.add(simple_preview_button);
408
409 JPanel simple_bar_area = new JPanel(new GridLayout(2,1));
410 simple_bar_area.setComponentOrientation(Dictionary.getOrientation());
411 simple_bar_area.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
412 simple_bar_area.add(import_monitor.getSharedProgress());
413 simple_bar_area.add(sbutton_panel);
414
415 sinner_panel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
416 sinner_panel.setLayout(new BorderLayout());
417 sinner_panel.add(sbuild_type_pane, BorderLayout.LINE_START);
418 //sinner_panel.add(full_build_radio_button, BorderLayout.WEST);
419 sinner_panel.add(simple_bar_area, BorderLayout.CENTER);
420
421 if(options_pane != null) {
422 sargument_configuration_panel = options_pane.buildImport(null);
423 sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
424 }
425 else {
426 sargument_configuration_panel = new JPanel();
427 }
428 sargument_configuration_panel.setComponentOrientation(Dictionary.getOrientation());
429 sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
430 sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
431 sargument_configuration_scroll.setComponentOrientation(Dictionary.getOrientation());
432
433 slower_panel.setLayout(new BorderLayout());
434 slower_panel.add(sinner_panel, BorderLayout.NORTH);
435 if(current_mode < THRESHOLD) {
436 slower_panel.add(log_scroll, BorderLayout.CENTER);
437 }
438
439 simple_panel = new JSplitPane(JSplitPane.VERTICAL_SPLIT, sargument_configuration_scroll, slower_panel);
440 simple_panel.setComponentOrientation(Dictionary.getOrientation());
441 // Main pane
442 main_pane = new JPanel(card_layout);
443 main_pane.setComponentOrientation(Dictionary.getOrientation());
444 if(current_mode < THRESHOLD) { // Simple mode - add first
445 main_pane.add(simple_panel, SIMPLE);
446 }
447 main_pane.add(control_pane, CONTROL);
448 main_pane.add(progress_pane, PROGRESS);
449 if(current_mode >= THRESHOLD) { // Expert mode - add last
450 main_pane.add(simple_panel, SIMPLE);
451 }
452
453 this.setLayout(new BorderLayout());
454 this.add(main_pane, BorderLayout.CENTER);
455 }
456
457 /** 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.
458 * @see org.greenstone.gatherer.Gatherer
459 * @see org.greenstone.gatherer.collection.CollectionManager
460 * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
461 */
462 public void gainFocus() {
463 if(Configuration.getMode() < THRESHOLD) {
464 card_layout.show(main_pane, SIMPLE);
465 }
466 else if(!processing) {
467 // Move the buttons to control
468 control_pane.add(button_pane, BorderLayout.SOUTH);
469 card_layout.show(main_pane, CONTROL);
470 }
471 else {
472 // Move the buttons to progress
473 progress_pane.add(button_pane, BorderLayout.SOUTH);
474 card_layout.show(main_pane, PROGRESS);
475 }
476 // Refresh the set of controls.
477 TreePath path = tree.getSelectionPath();
478 tree.clearSelection();
479 tree.setSelectionPath(path);
480
481 }
482
483 /** We are informed when this view pane loses focus so we can update build options. */
484 public void loseFocus() {
485 tree.valueChanged(null);
486 }
487
488 /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
489 * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
490 */
491 public synchronized void message(GShellEvent event) {
492 // Ignore the messages from RecPlug (used for progress bars)
493 if (event.getMessage().startsWith("import.pl> RecPlug - ")) {
494 return;
495 }
496 document.appendLine(event.getMessage());
497 log_textarea.setCaretPosition(document.getLengthToNearestLine());
498 }
499
500 /** Called when the detail mode has changed which in turn may cause several import/build configuration arguments to be available/hidden
501 * @param mode the new mode as an int
502 */
503 public void modeChanged(int mode) {
504 // If we are below the complexity threshold ensure the simple controls are being shown
505 if(Configuration.getMode() < THRESHOLD) {
506 // Update the arguments
507 simple_panel.remove(sargument_configuration_scroll);
508 if(options_pane != null) {
509 sargument_configuration_panel = options_pane.buildImport(null);
510 sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
511 }
512 else {
513 sargument_configuration_panel = new JPanel();
514 }
515 sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
516 sargument_configuration_panel.setComponentOrientation(Dictionary.getOrientation());
517 sargument_configuration_scroll.setComponentOrientation(Dictionary.getOrientation());
518 sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
519 simple_panel.setTopComponent(sargument_configuration_scroll);
520 // Remove the shared components from the expert panels
521 progress_pane.remove(log_scroll);
522 // And add to simple one
523 slower_panel.add(log_scroll, BorderLayout.CENTER);
524 // And bring the card to the front
525 card_layout.show(main_pane, SIMPLE);
526 }
527 // And if we are above the threshold change to the complex controls
528 else {
529 // Remove the shared components from the simple panel
530 slower_panel.remove(log_scroll);
531 // And add then to the expert ones
532 progress_pane.add(log_scroll, BorderLayout.CENTER);
533 // And bring the appropriate card to the front
534 if(!processing) {
535 control_pane.add(button_pane, BorderLayout.SOUTH);
536 card_layout.show(main_pane, CONTROL);
537 }
538 else {
539 progress_pane.add(button_pane, BorderLayout.SOUTH);
540 card_layout.show(main_pane, PROGRESS);
541 }
542 }
543 tree.valueChanged(null); // Ensure tree argument panels are rebuilt
544 }
545
546 /** 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.
547 * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
548 */
549 public synchronized void processBegun(GShellEvent event) {
550 // We don't care. We'll get a more acurate start from the progress monitors.
551 }
552 /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
553 * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
554 */
555 public synchronized void processComplete(GShellEvent event) {
556 DebugStream.println("In CreatePane::processComplete(" + event.getType() + ")...");
557
558 // c_man.built() is an expensive operation in isGsdlRemote case,
559 // so calculate this once now to set both preview and simple_preview buttons in one go
560 boolean been_built = Gatherer.c_man.built();
561
562 if(event.getStatus() == GShell.OK) {
563 if(event.getType() == GShell.SCHEDULE) {
564
565 processing = false;
566 build_button.setEnabled(true);
567 cancel_button.setEnabled(false);
568 //preview_button.setEnabled(true);
569 //only enable preview if the collection has been built.
570 preview_button.setEnabled(been_built);
571 simple_build_button.setEnabled(true);
572 simple_cancel_button.setEnabled(false);
573 simple_preview_button.setEnabled(been_built);
574 int status = event.getStatus();
575 document.setSpecialCharacter(OptionsPane.SCHEDULED);
576 options_pane.resetFileEntry();
577 build_monitor.reset();
578 import_monitor.reset();
579 if(Configuration.getMode() >= THRESHOLD) {
580 control_pane.add(button_pane, BorderLayout.SOUTH);
581 card_layout.show(main_pane, CONTROL);
582 }
583 }
584 else if(event.getType() == GShell.BUILD) {
585 processing = false;
586 build_button.setEnabled(true);
587 cancel_button.setEnabled(false);
588 preview_button.setEnabled(been_built);
589 simple_build_button.setEnabled(true);
590 simple_cancel_button.setEnabled(false);
591 simple_preview_button.setEnabled(been_built);
592 int status = event.getStatus();
593 document.setSpecialCharacter(OptionsPane.SUCCESSFUL);
594 options_pane.resetFileEntry();
595 build_monitor.reset();
596 import_monitor.reset();
597 if(Configuration.getMode() >= THRESHOLD) {
598 control_pane.add(button_pane, BorderLayout.SOUTH);
599 card_layout.show(main_pane, CONTROL);
600 }
601 }
602 // Otherwise its completed import but still got build to go
603 }
604 else {
605 processing = false;
606 cancel_button.setEnabled(false);
607 build_button.setEnabled(true);
608 // The build may have failed, but a previous index may still be in place
609 // In which case, previewing should still be available
610 preview_button.setEnabled(been_built);
611
612 simple_build_button.setEnabled(true);
613 simple_cancel_button.setEnabled(false);
614 simple_preview_button.setEnabled(been_built);
615 if(event.getStatus() == GShell.CANCELLED) {
616 document.setSpecialCharacter(OptionsPane.CANCELLED);
617 }
618 else {
619 document.setSpecialCharacter(OptionsPane.UNSUCCESSFUL);
620 }
621 options_pane.resetFileEntry();
622 if(Configuration.getMode() >= THRESHOLD) {
623 control_pane.add(button_pane, BorderLayout.SOUTH);
624 card_layout.show(main_pane, CONTROL);
625 }
626 }
627 }
628
629
630 /** This method is invoked at any time there has been a significant change in the collection, such as saving, loading or creating.
631 * @param ready A <strong>boolean</strong> indicating if a collection is currently available.
632 * @see org.greenstone.gatherer.Gatherer
633 * @see org.greenstone.gatherer.collection.CollectionManager
634 * @see org.greenstone.gatherer.gui.BuildOptions
635 * @see org.greenstone.gatherer.gui.OptionsPane
636 */
637 public void refresh(int refresh_reason, boolean ready)
638 {
639 if (Gatherer.c_man == null || !ready) {
640 return;
641 }
642 Collection current_collection = Gatherer.c_man.getCollection();
643 if (current_collection != previous_collection && !Gatherer.c_man.isImporting()) {
644 this.options_pane = new OptionsPane(current_collection.import_options, current_collection.build_options, current_collection.schedule_options);
645 if (previous_collection != null) {
646 // clear the log
647 Document log_document = log_textarea.getDocument();
648 if (log_document instanceof AppendLineOnlyFileDocument) {
649 ((AppendLineOnlyFileDocument) log_document).destroy();
650 }
651 }
652 previous_collection = current_collection;
653
654 }
655 // If we are in simple mode, we have to rebuild the simple arguments list
656 if(Configuration.getMode() < THRESHOLD) {
657 simple_panel.remove(sargument_configuration_scroll);
658 sargument_configuration_panel = options_pane.buildImport(null);
659 sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
660 //if(CollectionManager.canDoScheduling()) {
661 //sargument_configuration_panel = options_pane.buildSchedule(sargument_configuration_panel);
662 //}
663 sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
664 sargument_configuration_scroll.setComponentOrientation(Dictionary.getOrientation());
665 sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
666 simple_panel.setTopComponent(sargument_configuration_scroll);
667 }
668 tree.valueChanged(null);
669
670 // Validate the preview button
671 // Calling the expensive built() operation here is justified probably,
672 // as long as refresh() is not called frivolously
673 boolean been_built = Gatherer.c_man.built();
674 if (been_built && Configuration.library_url != null) {
675 preview_button.setEnabled(true);
676 simple_preview_button.setEnabled(true);
677 }
678 else {
679 preview_button.setEnabled(false);
680 simple_preview_button.setEnabled(false);
681 }
682 }
683
684 /** This class serves as the listener for actions on the build button. */
685 private class BuildButtonListener
686 implements ActionListener {
687 /**
688 * This method checks to see what needs to be done for a build, and starts the process off.
689 * A complete build proccess is started by {@link CollectionManager.importCollection()}, which then imports and builds the collection.
690 * However, this doesn't always happen, as sometimes an incremental build will do :-)
691 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
692 * @see org.greenstone.gatherer.Gatherer
693 * @see org.greenstone.gatherer.collection.CollectionManager
694 * @see org.greenstone.gatherer.gui.BuildOptions
695 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
696 */
697 public void actionPerformed(ActionEvent event) {
698 Collection collection = Gatherer.c_man.getCollection();
699 String collection_name = collection.getName();
700
701 //if button is labelled for Building
702 if(event.getActionCommand().equals(Dictionary.get("CreatePane.Build_Collection"))) {
703
704 //set a static variable marking whether this is a "Complete" or "Minimal" build
705 CollectionDesignManager.setCompleteBuild( full_build_radio_button.isSelected() );
706
707 //do the import and build, skipping import if possible
708 /*if( !CollectionDesignManager.isCompleteBuild() &&
709 !collection.getMetadataChanged() && !collection.getFilesChanged() && Gatherer.c_man.imported() &&
710 CollectionDesignManager.getRebuildTypeRequired() <= CollectionDesignManager.BUILDCOL
711 ) {
712 // Just do build (no import)
713 DebugStream.println("Just want to run buildcol.pl");
714 prepareForBuild();
715 Gatherer.c_man.buildCollection();
716 }
717 else {
718 */
719 prepareForBuild();
720
721 // Starting building,
722 // For now, for a GS3 solr collection, we need to stop the GS3 server before building
723 // and restart it after building is complete. Restart is done in CollectionManager.processComplete()
724 if(CollectionManager.isSolrCollection()) {
725 /*GS3ServerThread thread = new GS3ServerThread(Configuration.gsdl3_src_path, "stop");
726 thread.start();*/
727 }
728
729 Gatherer.c_man.importCollection(); //This starts the building process.
730 /*
731 }
732 */
733
734 } else { //button is labelled for setting up scheduling
735
736 //this needs to be called to configure buttons... but no building is done
737 prepareForBuild();
738 Gatherer.c_man.scheduleBuild();
739 }
740 //Re-setting the rebuildTypeRequired is handled by CollectionManager.processComplete(GShellEvent)
741 }
742
743
744 /**
745 * This does some stuff that is needed before a collection can be built.
746 * For example, buttons are enabled/disabled, and certain flags are set.
747 * This is called from {@link actionPerformed(ActionEvent)}
748 */
749 private void prepareForBuild() {
750 // First we force the build options to be updated if we haven't already.
751 tree.valueChanged(null);
752
753 // Remember that for lower thresholds the above doesn't work, so try this instead
754 if(Configuration.getMode() < THRESHOLD) {
755 options_pane.update(sargument_configuration_panel);
756 }
757
758 // Now go about building.
759 build_button.setEnabled(false);
760 cancel_button.setEnabled(true);
761 preview_button.setEnabled(false);
762
763 simple_build_button.setEnabled(false);
764 simple_cancel_button.setEnabled(true);
765 simple_preview_button.setEnabled(false);
766
767 document = options_pane.createNewLogDocument();
768 log_textarea.setDocument(document);
769 options_pane.log_textarea.setDocument(document);
770 // Change the view.
771 processing = true;
772 if(Configuration.getMode() >= THRESHOLD) {
773 progress_pane.add(button_pane, BorderLayout.SOUTH);
774 card_layout.show(main_pane, PROGRESS);
775 }
776 // Reset the stop flag in all the process monitors, just incase.
777 ((GBuildProgressMonitor)build_monitor).reset();
778 import_monitor.setStop(false);
779 }
780 }
781
782 /** I hope this works. Wendy */
783 private class BuildSimpleButtonListener
784 implements ActionListener {
785 /**
786 * This method checks to see what needs to be done for a build, and starts the process off.
787 * A complete build proccess is started by {@link CollectionManager.importCollection()}, which then imports and builds the collection.
788 * However, this doesn't always happen, as sometimes an incremental build will do :-)
789 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
790 * @see org.greenstone.gatherer.Gatherer
791 * @see org.greenstone.gatherer.collection.CollectionManager
792 * @see org.greenstone.gatherer.gui.BuildOptions
793 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
794 */
795 public void actionPerformed(ActionEvent event) {
796 Collection collection = Gatherer.c_man.getCollection();
797 String collection_name = collection.getName();
798
799 //set a static variable marking whether this is a "Complete" or "Minimal" build
800 CollectionDesignManager.setCompleteBuild( full_build_radio_button.isSelected() );
801
802 //do the import and build, skipping import if possible
803 /*if( !CollectionDesignManager.isCompleteBuild() &&
804 !collection.getMetadataChanged() && !collection.getFilesChanged() && Gatherer.c_man.imported() &&
805 CollectionDesignManager.getRebuildTypeRequired() <= CollectionDesignManager.BUILDCOL
806 ) {
807 // Just do build (no import)
808 DebugStream.println("Just want to run buildcol.pl");
809 prepareForBuild();
810 Gatherer.c_man.buildCollection();
811 }
812 else {
813 */
814 prepareForBuild();
815 Gatherer.c_man.importCollection(); //This starts the building process.
816 /*
817 }
818 */
819
820 //Re-setting the rebuildTypeRequired is handled by CollectionManager.processComplete(GShellEvent)
821 }
822
823 /**
824 * This does some stuff that is needed before a collection can be built.
825 * For example, buttons are enabled/disabled, and certain flags are set.
826 * This is called from {@link actionPerformed(ActionEvent)}
827 */
828 private void prepareForBuild() {
829 // First we force the build options to be updated if we haven't already.
830 tree.valueChanged(null);
831
832 // Remember that for lower thresholds the above doesn't work, so try this instead
833 if(Configuration.getMode() < THRESHOLD) {
834 options_pane.update(sargument_configuration_panel);
835 }
836
837 // Now go about building.
838 build_button.setEnabled(false);
839 cancel_button.setEnabled(true);
840 preview_button.setEnabled(false);
841
842 simple_build_button.setEnabled(false);
843 simple_cancel_button.setEnabled(true);
844 simple_preview_button.setEnabled(false);
845
846 document = options_pane.createNewLogDocument();
847 log_textarea.setDocument(document);
848 options_pane.log_textarea.setDocument(document);
849 // Change the view.
850 processing = true;
851 if(Configuration.getMode() >= THRESHOLD) {
852 progress_pane.add(button_pane, BorderLayout.SOUTH);
853 card_layout.show(main_pane, PROGRESS);
854 }
855 // Reset the stop flag in all the process monitors, just incase.
856 ((GBuildProgressMonitor)build_monitor).reset();
857 import_monitor.setStop(false);
858 }
859 }
860
861
862 /** This class serves as the listener for actions on the cancel button. */
863 private class CancelButtonListener
864 implements ActionListener {
865 /** This method attempts to cancel the current GShell task. It does this by first telling CollectionManager not to carry out any further action.
866 * Previously, this would in turn tell 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.
867 * Now, pressing cancel will send an interrupt to the GShell thread, which is the thread in which the external process is run (via the SafeProcess object). Interrupting a running SafeProcess will then interrupt any worker threads and destroy the process, with SafeProcess cleaning up after itself after its worker threads finished cleaning up after themselves. Tested on Linux.
868 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
869 * @see org.greenstone.gatherer.Gatherer
870 * @see org.greenstone.gatherer.collection.CollectionManager
871 * @see org.greenstone.gatherer.gui.BuildOptions
872 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
873 */
874 public void actionPerformed(ActionEvent event) {
875 build_button.setEnabled(false);
876 cancel_button.setEnabled(false);
877 preview_button.setEnabled(false);
878
879 simple_build_button.setEnabled(false);
880 simple_cancel_button.setEnabled(false);
881 simple_preview_button.setEnabled(false);
882
883 processing = false;
884 document.setSpecialCharacter(OptionsPane.CANCELLED);
885 if(Configuration.getMode() >= THRESHOLD) {
886 control_pane.add(button_pane, BorderLayout.SOUTH);
887 card_layout.show(main_pane, CONTROL);
888 }
889 // Set the stop flag in all the process monitor.
890 import_monitor.setStop(true);
891 import_monitor.reset();
892 build_monitor.setStop(true);
893 build_monitor.reset();
894 // Tell the GShell to cleanly stop running its external process
895 if(CreatePane.this.shell != null) {
896 // We can call GShell.cancel() even if the GShell thread is blocking when running a process,
897 // because this CreatePane is running in its own separate GUI thread. This is because the
898 // process blocking call (process.waitFor()) and cancel() are not sequential operations.
899 CreatePane.this.shell.cancel();
900 }
901
902 // Remove the collection lock.
903 //Gatherer.g_man.lockCollection(false, false);
904
905 // Cancelling building:
906 // For now, for a GS3 solr collection, we need to stop the GS3 server before building
907 // and restart it after building is complete. If a cancel is pressed during build
908 // then we also restart the GS3 server
909 if(CollectionManager.isSolrCollection()) {
910 /*GS3ServerThread thread = new GS3ServerThread(Configuration.gsdl3_src_path, "restart");
911 thread.start();*/
912 }
913
914
915 }
916 }
917
918
919 /** 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. */
920 private class OptionTree
921 extends JTree
922 implements TreeSelectionListener {
923 /** The model behind the tree. */
924 private DefaultTreeModel model = null;
925 /** The previous options view displayed, which is sometimes needed to refresh properly. */
926 private JPanel previous_pane = null;
927 /** The node corresponding to the building options view. */
928 private OptionTreeNode building = null;
929 /** The node corresponding to the importing options view. */
930 private OptionTreeNode importing = null;
931 /** The node corresponding to the scheduling options view. */
932 private OptionTreeNode scheduling = null;
933 /** The node corresponding to the log view. */
934 private OptionTreeNode log = null;
935 /** The root node of the options tree, which has no associated options view. */
936 private OptionTreeNode options = null;
937 /** Constructor.
938 * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
939 */
940 public OptionTree() {
941 super();
942 this.setComponentOrientation(Dictionary.getOrientation());
943 ToolTipManager.sharedInstance().registerComponent(this);
944 addTreeSelectionListener(this);
945 getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
946 setCellRenderer(new ToolTipTreeCellRenderer());
947 setRootVisible(false);
948 setToggleClickCount(1);
949
950 // Create tree.
951 building = new OptionTreeNode(Dictionary.get("CreatePane.Build"));
952 building.setToolTipText(Dictionary.get("CreatePane.Build_Tooltip"));
953 importing = new OptionTreeNode(Dictionary.get("CreatePane.Import"));
954 importing.setToolTipText(Dictionary.get("CreatePane.Import_Tooltip"));
955 if (CollectionManager.canDoScheduling()) {
956 scheduling = new OptionTreeNode(Dictionary.get("CreatePane.Schedule"));
957 scheduling.setToolTipText(Dictionary.get("CreatePane.Schedule_Tooltip"));
958
959 }
960 log = new OptionTreeNode(Dictionary.get("CreatePane.Log"));
961 log.setToolTipText(Dictionary.get("CreatePane.Log_Tooltip"));
962 options = new OptionTreeNode(Dictionary.get("CreatePane.Options"));
963
964 model = new DefaultTreeModel(options);
965 setModel(model);
966 model.insertNodeInto(importing, options, 0);
967 model.insertNodeInto(building, options, 1);
968 if (CollectionManager.canDoScheduling()) {
969 model.insertNodeInto(scheduling, options, 2);
970 model.insertNodeInto(log, options, 3);
971 } else {
972 model.insertNodeInto(log, options, 2);
973 }
974 // Expand the root node
975 expandPath(new TreePath(options));
976 }
977 /** 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.
978 * @param event A <Strong>TreeSelectionEvent</strong> which contains all the information garnered when the event occured.
979 * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
980 */
981 public void valueChanged(TreeSelectionEvent event) {
982 TreePath path = null;
983 OptionTreeNode node = null;
984 //if(event != null) {
985 //path = event.getPath();
986 path = getSelectionPath();
987 if(path != null) {
988 node = (OptionTreeNode)path.getLastPathComponent();
989 }
990 //}
991 if(previous_pane != null) {
992 //target_pane.remove(previous_pane);
993 options_pane.update(previous_pane);
994 if(scroll_pane != null) {
995 right.remove(scroll_pane);
996 }
997 else {
998 right.remove(previous_pane);
999 }
1000 previous_pane = null;
1001 scroll_pane = null;
1002 }
1003 if(node != null && node.equals(log)) {
1004 build_button.setActionCommand(Dictionary.get("CreatePane.Build_Collection"));
1005 build_button.setText(Dictionary.get("CreatePane.Build_Collection"));
1006 }
1007 if(node != null && node.equals(building)) {
1008 build_button.setActionCommand(Dictionary.get("CreatePane.Build_Collection"));
1009 build_button.setText(Dictionary.get("CreatePane.Build_Collection"));
1010
1011
1012 previous_pane = options_pane.buildBuild(null);
1013 scroll_pane = new JScrollPane(previous_pane);
1014 right.add(scroll_pane, BorderLayout.CENTER);
1015 //target_pane.add(previous_pane, BorderLayout.CENTER);
1016 }
1017 else if(node != null && node.equals(importing)) {
1018 build_button.setActionCommand(Dictionary.get("CreatePane.Build_Collection"));
1019 build_button.setText(Dictionary.get("CreatePane.Build_Collection"));
1020
1021 previous_pane = options_pane.buildImport(null);
1022 scroll_pane = new JScrollPane(previous_pane);
1023 right.add(scroll_pane, BorderLayout.CENTER);
1024 //target_pane.add(previous_pane, BorderLayout.CENTER);
1025 }
1026 else if(node != null && CollectionManager.canDoScheduling() && node.equals(scheduling)) {
1027 build_button.setActionCommand(Dictionary.get("CreatePane.Schedule_Build"));
1028 build_button.setText(Dictionary.get("CreatePane.Schedule_Build"));
1029
1030 previous_pane = options_pane.buildSchedule(null);
1031 scroll_pane = new JScrollPane(previous_pane);
1032 right.add(scroll_pane, BorderLayout.CENTER);
1033 }
1034 else {
1035 if (options_pane != null) {
1036 previous_pane = options_pane.buildLog();
1037 right.add(previous_pane, BorderLayout.CENTER);
1038 right.updateUI(); // we need to repaint the log pane, cos it hasn't changed since last time
1039 ///ystem.err.println("I've added the log back to the right pane again.");
1040 //target_pane.add(previous_pane, BorderLayout.CENTER);
1041 }
1042 }
1043 //scroll_pane.setViewportView(previous_pane);
1044 //previous_pane.validate();
1045 right.validate();
1046 //System.err.println("Current pane size: " + previous_pane.getSize());
1047 //System.err.println("While its preferred size is: " + previous_pane.getPreferredSize());
1048 }
1049 }
1050
1051 /** The <strong>OptionTree</strong> is built from these nodes, each of which has several methods used in creating the option panes.
1052 */
1053 private class OptionTreeNode
1054 extends DefaultMutableTreeNode
1055 implements Comparable {
1056 /** The text label given to this node in the tree. */
1057 private String title = null;
1058 /** a tool tip to be used for this node in the tree */
1059 private String tool_tip = null;
1060 /** Constructor.
1061 * @param title The <strong>String</strong> which serves as this nodes title.
1062 */
1063 public OptionTreeNode(String title) {
1064 super();
1065 this.title = title;
1066 }
1067
1068 /** This method compares two nodes for ordering.
1069 * @param obj The <strong>Object</strong> to compare to.
1070 * @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.
1071 */
1072 public int compareTo(Object obj) {
1073 return title.compareTo(obj.toString());
1074 }
1075
1076 /** This method checks if two nodes are equivalent.
1077 * @param obj The <strong>Object</strong> to be tested against.
1078 * @return A <strong>boolean</strong> which is <i>true</i> if the objects are equal, <i>false</i> otherwise.
1079 */
1080 public boolean equals(Object obj) {
1081 if(compareTo(obj) == 0) {
1082 return true;
1083 }
1084 return false;
1085 }
1086
1087 /** get the tool tip */
1088 public String getToolTipText() {
1089 return tool_tip;
1090 }
1091
1092 /** set the tool tip */
1093 public void setToolTipText(String tip) {
1094 tool_tip = tip;
1095 }
1096
1097 /** Method to translate this node into a textual representation.
1098 * @return A <strong>String</strong> which in this case is the title.
1099 */
1100 public String toString() {
1101 return title;
1102 }
1103 }
1104
1105 // Adds tooltips to the tree nodes
1106 private class ToolTipTreeCellRenderer
1107 extends DefaultTreeCellRenderer {
1108
1109 public Component getTreeCellRendererComponent(JTree tree,
1110 Object value,
1111 boolean sel,
1112 boolean expanded,
1113 boolean leaf,
1114 int row,
1115 boolean hasFocus) {
1116
1117 super.getTreeCellRendererComponent(tree, value, sel,
1118 expanded, leaf, row,
1119 hasFocus);
1120 if (value instanceof OptionTreeNode) {
1121 String tip = ((OptionTreeNode) value).getToolTipText();
1122 if (tip != null) {
1123 setToolTipText(tip);
1124 }
1125 }
1126 return this;
1127 }
1128 }
1129}
Note: See TracBrowser for help on using the repository browser.