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

Last change on this file since 15621 was 15621, checked in by ak19, 16 years ago

BuildButtonListener implements DocumentListener now so that it it keeps the display log refreshed upon DocumentEvents fired when new lines have finally been added (no more funny squares in the log)

  • Property svn:keywords set to Author Date Id Revision
File size: 37.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.GShell;
56import org.greenstone.gatherer.shell.GShellEvent;
57import org.greenstone.gatherer.shell.GShellListener;
58import org.greenstone.gatherer.shell.GShellProgressMonitor;
59import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
60import org.greenstone.gatherer.util.StaticStrings;
61import org.greenstone.gatherer.util.Utility;
62
63
64/** 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>
65 * @author John Thompson, Greenstone Digital Library, University of Waikato
66 * @version 2.3
67 */
68public class CreatePane
69 extends JPanel
70 implements GShellListener {
71
72 static private Dimension ARGUMENT_SIZE = new Dimension(800,90);
73 /** The threshold for when the simple view is replaced by the complex one. */
74 static private final int THRESHOLD = Configuration.EXPERT_MODE;
75 /** An identifier for the control panel within the card layout. */
76 static private String CONTROL = "Control";
77 /** An identifier for the progress panel within the card layout. */
78 static private String PROGRESS = "Progress";
79 /** An identifier for the simple panel within the card layout. */
80 static private String SIMPLE = "Simple";
81
82 /** Determines the current view that should be shown for this pane. */
83 public boolean processing = false;
84 /** The options pane generates all the various option sheet configuations. */
85 public OptionsPane options_pane = null;
86 private AppendLineOnlyFileDocument document;
87 /** A card layout is used to store the separate configuration and progress panes. */
88 private CardLayout card_layout = null;
89 /** Stores a reference to the current collection. */
90 private Collection previous_collection = null;
91 /** This monitor tracks the build processes progress. */
92 private GShellProgressMonitor build_monitor = null;
93 /** This monitor tracks the import processes progress. */
94 private GShellProgressMonitor import_monitor = null;
95 /** The button for begining the building processes. */
96 private JButton build_button = null;
97 /** The button for stopping the building processes. */
98 private JButton cancel_button = null;
99 /** The button for viewing the collection. */
100 private JButton preview_button = null;
101 private JButton simple_build_button;
102 private JButton simple_cancel_button;
103 private JButton simple_preview_button;
104 /** The radio buttons for chnaging the build type (incremental/full) */
105 private JRadioButton full_build_radio_button;
106 private JRadioButton incremental_build_radio_button;
107 private JRadioButton sfull_build_radio_button;
108 private JRadioButton sincremental_build_radio_button;
109 /** The label displaying the number of documents in this collection. */
110 private JLabel document_count = null;
111 /** The label alongside the build progress bar gets some special treatment so... */
112 private JLabel progress_build_label = null;
113 /** The label alongside the import progress bar gets some special treatment so... */
114 private JLabel progress_import_label = null;
115 private JPanel bar_area;
116 /** The panel on which buttons are rendered on higher detail modes. */
117 private JPanel button_pane;
118 /** The pane which contains the controls for configuration. */
119 private JPanel control_pane = null;
120 /** The pane which has the card layout as its manager. */
121 private JPanel main_pane = null;
122 /** The pane which contains the progress information. */
123 private JPanel progress_pane = null;
124 /** The pane on the right-hand side - shows the requested options view */
125 private JPanel right = null;
126 /** The simple panel on which all of the available arguments are rendered. */
127 private JPanel sargument_configuration_panel;
128 /** The panel on which buttons are rendered on lower details modes. */
129 private JPanel sbutton_panel;
130 /** A simplified version for lower detail modes containing both the control and progress panes smooshed together. */
131 private JSplitPane simple_panel;
132 /** The lower part of the panel which is global so the log pane can be added and removed from it */
133 private JPanel slower_panel;
134 /** The inner panel of the simple pane which is global so that the bar_area can be added and removed from it. */
135 private JPanel sinner_panel;
136 /** The scrolling pane for the log. */
137 private JScrollPane log_scroll;
138 /** The scrolling pane the simple arguments are rendered within. */
139 private JScrollPane sargument_configuration_scroll;
140 /** 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 */
141 private JScrollPane scroll_pane;
142 /** The message log for the entire session. */
143 private JTextArea log_textarea;
144 /** A tree used to display the currently available option views. */
145 private OptionTree tree = null;
146 /** An array used to pass arguments with dictionary calls. */
147 private String args[] = null;
148 /** The homepage address of the current collection */
149 public String homepage = null;
150
151
152 /** The constructor creates important helper classes, and initializes all the components.
153 * @see org.greenstone.gatherer.collection.CollectionManager
154 * @see org.greenstone.gatherer.gui.BuildOptions
155 * @see org.greenstone.gatherer.gui.CreatePane.BuildButtonListener
156 * @see org.greenstone.gatherer.gui.CreatePane.CancelButtonListener
157 * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
158 * @see org.greenstone.gatherer.gui.OptionsPane
159 * @see org.greenstone.gatherer.shell.GBuildProgressMonitor
160 * @see org.greenstone.gatherer.shell.GImportProgressMonitor
161 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
162 */
163 public CreatePane() {
164 log_textarea = new JTextArea();
165 log_scroll = new JScrollPane(log_textarea);
166
167 // Create components
168 card_layout = new CardLayout();
169 // Control Pane
170 control_pane = new JPanel();
171 tree = new OptionTree();
172 button_pane = new JPanel();
173
174 // Progress Pane
175 progress_pane = new JPanel(); // One owner of the bar component
176 bar_area = new JPanel(); // This component will be shared about
177
178 progress_import_label = new JLabel(Dictionary.get("CreatePane.Import_Progress"));
179
180 import_monitor = new GImportProgressMonitor();
181 Gatherer.c_man.registerImportMonitor(import_monitor);
182
183 progress_build_label = new JLabel(Dictionary.get("CreatePane.Build_Progress"));
184
185 build_monitor = new GBuildProgressMonitor(import_monitor.getSharedProgress());
186 Gatherer.c_man.registerBuildMonitor(build_monitor);
187
188 // And the simple panel
189 slower_panel = new JPanel();
190 sbutton_panel = new JPanel();
191 sinner_panel = new JPanel();
192
193 //Radio buttons
194 incremental_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Minimal_Build"));
195 incremental_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Minimal_Build_Tooltip"));
196 full_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Full_Build"));
197 full_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Full_Build_Tooltip"));
198 sincremental_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Minimal_Build"));
199 sincremental_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Minimal_Build_Tooltip"));
200 sfull_build_radio_button = new JRadioButton(Dictionary.get("CreatePane.Full_Build"));
201 sfull_build_radio_button.setToolTipText(Dictionary.get("CreatePane.Full_Build_Tooltip"));
202
203
204 // Buttons
205 BuildButtonListener bbl = new BuildButtonListener();
206 CancelButtonListener cbl = new CancelButtonListener();
207
208 build_button = new GLIButton(Dictionary.get("CreatePane.Build_Collection"), Dictionary.get("CreatePane.Build_Collection_Tooltip"));
209 build_button.addActionListener(bbl);
210
211 cancel_button = new GLIButton(Dictionary.get("CreatePane.Cancel_Build"), Dictionary.get("CreatePane.Cancel_Build_Tooltip"));
212 cancel_button.addActionListener(cbl);
213 cancel_button.setEnabled(false);
214
215 preview_button = new PreviewButton(Dictionary.get("CreatePane.Preview_Collection"), Dictionary.get("CreatePane.Preview_Collection_Tooltip"));
216 //preview_button.addActionListener(pbl);
217 if(Gatherer.c_man != null) {
218 preview_button.setEnabled(Gatherer.c_man.built());
219 }
220 else {
221 preview_button.setEnabled(false);
222 }
223
224 simple_build_button = new GLIButton(Dictionary.get("CreatePane.Build_Collection"), Dictionary.get("CreatePane.Build_Collection_Tooltip"));
225 simple_build_button.addActionListener(bbl);
226
227 simple_cancel_button = new GLIButton(Dictionary.get("CreatePane.Cancel_Build"), Dictionary.get("CreatePane.Cancel_Build_Tooltip"));
228 simple_cancel_button.addActionListener(cbl);
229 simple_cancel_button.setEnabled(false);
230
231 simple_preview_button = new PreviewButton(Dictionary.get("CreatePane.Preview_Collection"), Dictionary.get("CreatePane.Preview_Collection_Tooltip"));
232 //simple_preview_button.addActionListener(pbl);
233 if(Gatherer.c_man != null) {
234 simple_preview_button.setEnabled(Gatherer.c_man.built());
235 }
236 else {
237 simple_preview_button.setEnabled(false);
238 }
239
240 bbl = null;
241 cbl = null;
242 //pbl = null;
243 }
244
245
246 public void destroy() {
247 if(document != null) {
248 document.destroy();
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 int current_mode = Configuration.getMode();
259
260 //Complete/incremental build options panel
261 //For some reason I need to create seperate objects for each mode. Is there a better way??
262 ButtonGroup build_type_group = new ButtonGroup();
263 build_type_group.add(incremental_build_radio_button);
264 full_build_radio_button.setSelected(true);
265 build_type_group.add(full_build_radio_button);
266 ButtonGroup sbuild_type_group = new ButtonGroup();
267 sbuild_type_group.add(sincremental_build_radio_button);
268 sfull_build_radio_button.setSelected(true);
269 sbuild_type_group.add(sfull_build_radio_button);
270 JPanel build_type_pane = new JPanel(new GridLayout(2,1));
271 build_type_pane.add(full_build_radio_button);
272 build_type_pane.add(incremental_build_radio_button);
273 JPanel sbuild_type_pane = new JPanel(new GridLayout(2,1));
274 sbuild_type_pane.add(sfull_build_radio_button);
275 sbuild_type_pane.add(sincremental_build_radio_button);
276
277
278
279 // Build control_pane
280 JPanel left = new JPanel();
281 left.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
282 left.setLayout(new BorderLayout());
283 left.add(tree, BorderLayout.CENTER);
284 left.add(build_type_pane, BorderLayout.SOUTH);
285 //left.add(full_build_radio_button, BorderLayout.SOUTH);
286
287 right = new JPanel();
288 right.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
289 right.setLayout(new BorderLayout());
290
291 JPanel options_area = new JPanel();
292 options_area.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createTitledBorder(Dictionary.get("CreatePane.Options_Title"))));
293 options_area.setLayout(new BorderLayout());
294 options_area.add(left, BorderLayout.WEST);
295 options_area.add(right, BorderLayout.CENTER);
296
297 button_pane = new JPanel();
298 button_pane.setBorder(BorderFactory.createEmptyBorder(5,10,10,10));
299 button_pane.setLayout(new GridLayout(1,4));
300 button_pane.add(build_button);
301 button_pane.add(cancel_button);
302 button_pane.add(preview_button);
303
304 control_pane.setLayout(new BorderLayout());
305 control_pane.add(options_area, BorderLayout.CENTER);
306 control_pane.add(button_pane, BorderLayout.SOUTH);
307
308 // Build progress_pane
309 JPanel labels_pane = new JPanel();
310 labels_pane.setLayout(new GridLayout(2,1,0,5));
311 labels_pane.add(progress_import_label);
312 labels_pane.add(progress_build_label);
313
314 JPanel monitors_pane = new JPanel();
315 monitors_pane.setLayout(new GridLayout(2,1,0,5));
316 monitors_pane.add(import_monitor.getProgress());
317 monitors_pane.add(build_monitor.getProgress());
318
319 bar_area.setBorder(BorderFactory.createEmptyBorder(10,10,5,10));
320 bar_area.setLayout(new BorderLayout(5,5));
321 bar_area.add(labels_pane, BorderLayout.WEST);
322 bar_area.add(monitors_pane, BorderLayout.CENTER);
323
324 progress_pane.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
325 progress_pane.setLayout(new BorderLayout());
326 progress_pane.add(bar_area, BorderLayout.NORTH);
327 if(current_mode >= THRESHOLD) {
328 progress_pane.add(log_scroll, BorderLayout.CENTER);
329 }
330
331 // Simple panel
332 sbutton_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
333 sbutton_panel.setLayout(new GridLayout(1,3));
334 sbutton_panel.add(simple_build_button);
335 sbutton_panel.add(simple_cancel_button);
336 sbutton_panel.add(simple_preview_button);
337
338 JPanel simple_bar_area = new JPanel(new GridLayout(2,1));
339 simple_bar_area.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
340 simple_bar_area.add(import_monitor.getSharedProgress());
341 simple_bar_area.add(sbutton_panel);
342
343 sinner_panel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
344 sinner_panel.setLayout(new BorderLayout());
345 sinner_panel.add(sbuild_type_pane, BorderLayout.WEST);
346 //sinner_panel.add(full_build_radio_button, BorderLayout.WEST);
347 sinner_panel.add(simple_bar_area, BorderLayout.CENTER);
348
349 if(options_pane != null) {
350 sargument_configuration_panel = options_pane.buildImport(null);
351 sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
352 }
353 else {
354 sargument_configuration_panel = new JPanel();
355 }
356 sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
357 sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
358
359 slower_panel.setLayout(new BorderLayout());
360 slower_panel.add(sinner_panel, BorderLayout.NORTH);
361 if(current_mode < THRESHOLD) {
362 slower_panel.add(log_scroll, BorderLayout.CENTER);
363 }
364
365 simple_panel = new JSplitPane(JSplitPane.VERTICAL_SPLIT, sargument_configuration_scroll, slower_panel);
366 // Main pane
367 main_pane = new JPanel(card_layout);
368 if(current_mode < THRESHOLD) { // Simple mode - add first
369 main_pane.add(simple_panel, SIMPLE);
370 }
371 main_pane.add(control_pane, CONTROL);
372 main_pane.add(progress_pane, PROGRESS);
373 if(current_mode >= THRESHOLD) { // Expert mode - add last
374 main_pane.add(simple_panel, SIMPLE);
375 }
376
377 this.setLayout(new BorderLayout());
378 this.add(main_pane, BorderLayout.CENTER);
379 }
380
381 /** 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.
382 * @see org.greenstone.gatherer.Gatherer
383 * @see org.greenstone.gatherer.collection.CollectionManager
384 * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
385 */
386 public void gainFocus() {
387 if(Configuration.getMode() < THRESHOLD) {
388 card_layout.show(main_pane, SIMPLE);
389 }
390 else if(!processing) {
391 // Move the buttons to control
392 control_pane.add(button_pane, BorderLayout.SOUTH);
393 card_layout.show(main_pane, CONTROL);
394 }
395 else {
396 // Move the buttons to progress
397 progress_pane.add(button_pane, BorderLayout.SOUTH);
398 card_layout.show(main_pane, PROGRESS);
399 }
400 // Refresh the set of controls.
401 TreePath path = tree.getSelectionPath();
402 tree.clearSelection();
403 tree.setSelectionPath(path);
404
405 //Disable the full/incremental buttons if the collection has not been built.
406 if(Gatherer.c_man.built()) {
407 full_build_radio_button.setEnabled(true);
408 incremental_build_radio_button.setEnabled(true);
409 sfull_build_radio_button.setEnabled(true);
410 sincremental_build_radio_button.setEnabled(true);
411 }
412 else {
413 full_build_radio_button.setEnabled(false);
414 incremental_build_radio_button.setEnabled(false);
415 sfull_build_radio_button.setEnabled(false);
416 sincremental_build_radio_button.setEnabled(false);
417 }
418 }
419
420 /** We are informed when this view pane loses focus so we can update build options. */
421 public void loseFocus() {
422 tree.valueChanged(null);
423 }
424
425 /**
426 * Check to see if doing an incremental build is chosen.
427 * If not, the full rebuild option must be chosen.
428 * @return boolean - true if the collection should be rebuilt incrementally.
429 */
430 public boolean isIncremental() {
431 boolean incremental = false;
432
433 //This is horrible. What if the mode is changed, and different options are chosen on different modes??
434 if(Gatherer.c_man.built()) {
435 if(Configuration.getMode() >= THRESHOLD) {
436 incremental = incremental_build_radio_button.isSelected();
437 }
438 else {
439 incremental = sincremental_build_radio_button.isSelected();
440 }
441 }
442 else {
443 incremental = false; //The collection has not yet been built
444 }
445 return incremental;
446 }
447
448 /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
449 * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
450 */
451 public synchronized void message(GShellEvent event) {
452 // Ignore the messages from RecPlug (used for progress bars)
453 if (event.getMessage().startsWith("import.pl> RecPlug - ")) {
454 return;
455 }
456 document.appendLine(event.getMessage());
457 log_textarea.setCaretPosition(document.getLengthToNearestLine());
458 }
459
460 /** Called when the detail mode has changed which in turn may cause several import/build configuration arguments to be available/hidden
461 * @param mode the new mode as an int
462 */
463 public void modeChanged(int mode) {
464 // If we are below the complexity threshold ensure the simple controls are being shown
465 if(Configuration.getMode() < THRESHOLD) {
466 // Update the arguments
467 simple_panel.remove(sargument_configuration_scroll);
468 if(options_pane != null) {
469 sargument_configuration_panel = options_pane.buildImport(null);
470 sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
471 }
472 else {
473 sargument_configuration_panel = new JPanel();
474 }
475 sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
476 sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
477 simple_panel.setTopComponent(sargument_configuration_scroll);
478 // Remove the shared components from the expert panels
479 progress_pane.remove(log_scroll);
480 // And add to simple one
481 slower_panel.add(log_scroll, BorderLayout.CENTER);
482 // And bring the card to the front
483 card_layout.show(main_pane, SIMPLE);
484 }
485 // And if we are above the threshold change to the complex controls
486 else {
487 // Remove the shared components from the simple panel
488 slower_panel.remove(log_scroll);
489 // And add then to the expert ones
490 progress_pane.add(log_scroll, BorderLayout.CENTER);
491 // And bring the appropriate card to the front
492 if(!processing) {
493 control_pane.add(button_pane, BorderLayout.SOUTH);
494 card_layout.show(main_pane, CONTROL);
495 }
496 else {
497 progress_pane.add(button_pane, BorderLayout.SOUTH);
498 card_layout.show(main_pane, PROGRESS);
499 }
500 }
501 tree.valueChanged(null); // Ensure tree argument panels are rebuilt
502 }
503
504 /** 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.
505 * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
506 */
507 public synchronized void processBegun(GShellEvent event) {
508 // We don't care. We'll get a more acurate start from the progress monitors.
509 }
510 /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
511 * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
512 */
513 public synchronized void processComplete(GShellEvent event) {
514 DebugStream.println("In CreatePane::processComplete(" + event.getType() + ")...");
515 if(event.getStatus() == GShell.OK) {
516 if(event.getType() == GShell.BUILD) {
517 processing = false;
518 build_button.setEnabled(true);
519 cancel_button.setEnabled(false);
520 //preview_button.setEnabled(true);
521 simple_build_button.setEnabled(true);
522 simple_cancel_button.setEnabled(false);
523 //simple_preview_button.setEnabled(true);
524 int status = event.getStatus();
525 document.setSpecialCharacter(OptionsPane.SUCCESSFUL);
526 options_pane.resetFileEntry();
527 build_monitor.reset();
528 import_monitor.reset();
529 if(Configuration.getMode() >= THRESHOLD) {
530 control_pane.add(button_pane, BorderLayout.SOUTH);
531 card_layout.show(main_pane, CONTROL);
532 }
533 }
534 // Otherwise its completed import but still got build to go
535 }
536 else {
537 processing = false;
538 cancel_button.setEnabled(false);
539 build_button.setEnabled(true);
540 // The build may have failed, but a previous index may still be in place
541 //preview_button.setEnabled(Gatherer.c_man.built());
542
543 simple_build_button.setEnabled(true);
544 simple_cancel_button.setEnabled(false);
545 //simple_preview_button.setEnabled(Gatherer.c_man.built());
546 if(event.getStatus() == GShell.CANCELLED) {
547 document.setSpecialCharacter(OptionsPane.CANCELLED);
548 }
549 else {
550 document.setSpecialCharacter(OptionsPane.UNSUCCESSFUL);
551 }
552 options_pane.resetFileEntry();
553 if(Configuration.getMode() >= THRESHOLD) {
554 control_pane.add(button_pane, BorderLayout.SOUTH);
555 card_layout.show(main_pane, CONTROL);
556 }
557 }
558 }
559
560
561 /** This method is invoked at any time there has been a significant change in the collection, such as saving, loading or creating.
562 * @param ready A <strong>boolean</strong> indicating if a collection is currently available.
563 * @see org.greenstone.gatherer.Gatherer
564 * @see org.greenstone.gatherer.collection.CollectionManager
565 * @see org.greenstone.gatherer.gui.BuildOptions
566 * @see org.greenstone.gatherer.gui.OptionsPane
567 */
568 public void refresh(int refresh_reason, boolean ready)
569 {
570 if (Gatherer.c_man == null || !ready) {
571 return;
572 }
573 Collection current_collection = Gatherer.c_man.getCollection();
574 if (current_collection != previous_collection && !Gatherer.c_man.isImporting()) {
575 this.options_pane = new OptionsPane(current_collection.import_options, current_collection.build_options);
576 if (previous_collection != null) {
577 // clear the log
578 Document log_document = log_textarea.getDocument();
579 if (log_document instanceof AppendLineOnlyFileDocument) {
580 ((AppendLineOnlyFileDocument) log_document).destroy();
581 }
582 }
583 previous_collection = current_collection;
584
585 }
586 // If we are in simple mode, we have to rebuild the simple arguments list
587 if(Configuration.getMode() < THRESHOLD) {
588 simple_panel.remove(sargument_configuration_scroll);
589 sargument_configuration_panel = options_pane.buildImport(null);
590 sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
591 sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
592 sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
593 simple_panel.setTopComponent(sargument_configuration_scroll);
594 }
595 tree.valueChanged(null);
596
597 // Validate the preview button
598 if (Gatherer.c_man.built() && Configuration.library_url != null) {
599 preview_button.setEnabled(true);
600 simple_preview_button.setEnabled(true);
601 }
602 else {
603 preview_button.setEnabled(false);
604 simple_preview_button.setEnabled(false);
605 }
606 }
607
608 /** This class serves as the listener for actions on the build button. It also ensures
609 * that the log displayed is refreshed whenever the building progress display updates. */
610 private class BuildButtonListener
611 implements ActionListener, DocumentListener {
612 /**
613 * This method checks to see what needs to be done for a build, and starts the process off.
614 * A complete build proccess is started by {@link CollectionManager.importCollection()}, which then imports and builds the collection.
615 * However, this doesn't always happen, as sometimes an incremental build will do :-)
616 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
617 * @see org.greenstone.gatherer.Gatherer
618 * @see org.greenstone.gatherer.collection.CollectionManager
619 * @see org.greenstone.gatherer.gui.BuildOptions
620 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
621 */
622 public void actionPerformed(ActionEvent event) {
623 Collection collection = Gatherer.c_man.getCollection();
624 String collection_name = collection.getName();
625 if(!collection.getMetadataChanged() && !collection.getFilesChanged() && isIncremental()) {
626 //Only design options have changes, and we want to be smart in the way we handle them.
627 int rebuildTypeRequired = CollectionDesignManager.getRebuildTypeRequired();
628 if (rebuildTypeRequired == CollectionDesignManager.BUILDCOL) {
629 // Just run the buildcol command.
630 DebugStream.println("Just want to run buildcol.pl");
631 prepareForBuild();
632 Gatherer.c_man.buildCollection(isIncremental());
633 }
634 else if (rebuildTypeRequired == CollectionDesignManager.ALL) {
635 // Do both import and buildcol
636 DebugStream.println("Want to do a complete build");
637 prepareForBuild();
638 Gatherer.c_man.importCollection(); //This starts the building process.
639 }
640 else {
641 //Nothing at all needs doing.
642 //This is bad HCI. Maybe should disable the build button in this situation?
643 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CreatePane.Minimal_Build_Not_Required"));
644 }
645 }
646 else {
647 //Do a complete build.
648 prepareForBuild();
649 Gatherer.c_man.importCollection(); //This starts the building process.
650 }
651 //Re-setting the rebuildTypeRequired is handled by CollectionManager.processComplete(GShellEvent)
652 }
653
654 /**
655 * This does some stuff that is needed before a collection can be built.
656 * For example, buttons are enabled/disabled, and certain flags are set.
657 * This is called from {@link actionPerformed(ActionEvent)}
658 */
659 private void prepareForBuild() {
660 // First we force the build options to be updated if we haven't already.
661 tree.valueChanged(null);
662
663 // Remember that for lower thresholds the above doesn't work, so try this instead
664 if(Configuration.getMode() < THRESHOLD) {
665 options_pane.update(sargument_configuration_panel);
666 }
667
668 // Now go about building.
669 build_button.setEnabled(false);
670 cancel_button.setEnabled(true);
671 preview_button.setEnabled(false);
672
673 simple_build_button.setEnabled(false);
674 simple_cancel_button.setEnabled(true);
675 simple_preview_button.setEnabled(false);
676
677 document = options_pane.createNewLogDocument();
678 log_textarea.setDocument(document);
679 // Add a document listener to listen to DocumentEvents emitted by the custom document.
680 // It prevents the blocks that appear in the log textarea that look like they need a refresh
681 document.addDocumentListener(this);
682 options_pane.log_textarea.setDocument(document);
683 // Change the view.
684 processing = true;
685 if(Configuration.getMode() >= THRESHOLD) {
686 progress_pane.add(button_pane, BorderLayout.SOUTH);
687 card_layout.show(main_pane, PROGRESS);
688 }
689 // Reset the stop flag in all the process monitors, just incase.
690 ((GBuildProgressMonitor)build_monitor).reset();
691 import_monitor.setStop(false);
692 }
693
694
695 // Called whenever the custom Document object has been updated (it then fires a DocumentEvent, handled here)
696 public void changedUpdate(DocumentEvent e) { refreshLog(); }
697 public void insertUpdate(DocumentEvent e) { refreshLog(); }
698 public void removeUpdate(DocumentEvent e) { refreshLog(); }
699 public void refreshLog() { CreatePane.this.log_textarea.repaint(); }
700 }
701
702 /** This class serves as the listener for actions on the cancel button. */
703 private class CancelButtonListener
704 implements ActionListener {
705 /** 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.
706 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
707 * @see org.greenstone.gatherer.Gatherer
708 * @see org.greenstone.gatherer.collection.CollectionManager
709 * @see org.greenstone.gatherer.gui.BuildOptions
710 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
711 */
712 public void actionPerformed(ActionEvent event) {
713 build_button.setEnabled(false);
714 cancel_button.setEnabled(false);
715 preview_button.setEnabled(false);
716
717 simple_build_button.setEnabled(false);
718 simple_cancel_button.setEnabled(false);
719 simple_preview_button.setEnabled(false);
720
721 processing = false;
722 document.setSpecialCharacter(OptionsPane.CANCELLED);
723 if(Configuration.getMode() >= THRESHOLD) {
724 control_pane.add(button_pane, BorderLayout.SOUTH);
725 card_layout.show(main_pane, CONTROL);
726 }
727 // Set the stop flag in all the process monitor.
728 import_monitor.setStop(true);
729 import_monitor.reset();
730 build_monitor.setStop(true);
731 build_monitor.reset();
732
733 // Remove the collection lock.
734 //Gatherer.g_man.lockCollection(false, false);
735 }
736 }
737
738
739 /** 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. */
740 private class OptionTree
741 extends JTree
742 implements TreeSelectionListener {
743 /** The model behind the tree. */
744 private DefaultTreeModel model = null;
745 /** The previous options view displayed, which is sometimes needed to refresh properly. */
746 private JPanel previous_pane = null;
747 /** The node corresponding to the building options view. */
748 private OptionTreeNode building = null;
749 /** The node corresponding to the importing options view. */
750 private OptionTreeNode importing = null;
751 /** The node corresponding to the log view. */
752 private OptionTreeNode log = null;
753 /** The root node of the options tree, which has no associated options view. */
754 private OptionTreeNode options = null;
755 /** Constructor.
756 * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
757 */
758 public OptionTree() {
759 super();
760
761 ToolTipManager.sharedInstance().registerComponent(this);
762 addTreeSelectionListener(this);
763 getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
764 setCellRenderer(new ToolTipTreeCellRenderer());
765 setRootVisible(false);
766 setToggleClickCount(1);
767
768 // Create tree.
769 building = new OptionTreeNode(Dictionary.get("CreatePane.Build"));
770 building.setToolTipText(Dictionary.get("CreatePane.Build_Tooltip"));
771 importing = new OptionTreeNode(Dictionary.get("CreatePane.Import"));
772 importing.setToolTipText(Dictionary.get("CreatePane.Import_Tooltip"));
773 log = new OptionTreeNode(Dictionary.get("CreatePane.Log"));
774 log.setToolTipText(Dictionary.get("CreatePane.Log_Tooltip"));
775 options = new OptionTreeNode(Dictionary.get("CreatePane.Options"));
776
777 model = new DefaultTreeModel(options);
778 setModel(model);
779 model.insertNodeInto(importing, options, 0);
780 model.insertNodeInto(building, options, 1);
781 model.insertNodeInto(log, options, 2);
782 // Expand the root node
783 expandPath(new TreePath(options));
784 }
785 /** 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.
786 * @param event A <Strong>TreeSelectionEvent</strong> which contains all the information garnered when the event occured.
787 * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
788 */
789 public void valueChanged(TreeSelectionEvent event) {
790 TreePath path = null;
791 OptionTreeNode node = null;
792 //if(event != null) {
793 //path = event.getPath();
794 path = getSelectionPath();
795 if(path != null) {
796 node = (OptionTreeNode)path.getLastPathComponent();
797 }
798 //}
799 if(previous_pane != null) {
800 //target_pane.remove(previous_pane);
801 options_pane.update(previous_pane);
802 if(scroll_pane != null) {
803 right.remove(scroll_pane);
804 }
805 else {
806 right.remove(previous_pane);
807 }
808 previous_pane = null;
809 scroll_pane = null;
810 }
811 if(node != null && node.equals(building)) {
812 previous_pane = options_pane.buildBuild(null);
813 scroll_pane = new JScrollPane(previous_pane);
814 right.add(scroll_pane, BorderLayout.CENTER);
815 //target_pane.add(previous_pane, BorderLayout.CENTER);
816 }
817 else if(node != null && node.equals(importing)) {
818 previous_pane = options_pane.buildImport(null);
819 scroll_pane = new JScrollPane(previous_pane);
820 right.add(scroll_pane, BorderLayout.CENTER);
821 //target_pane.add(previous_pane, BorderLayout.CENTER);
822 }
823 else {
824 if (options_pane != null) {
825 previous_pane = options_pane.buildLog();
826 right.add(previous_pane, BorderLayout.CENTER);
827 right.updateUI(); // we need to repaint the log pane, cos it hasn't changed since last time
828 ///ystem.err.println("I've added the log back to the right pane again.");
829 //target_pane.add(previous_pane, BorderLayout.CENTER);
830 }
831 }
832 //scroll_pane.setViewportView(previous_pane);
833 //previous_pane.validate();
834 right.validate();
835 //System.err.println("Current pane size: " + previous_pane.getSize());
836 //System.err.println("While its preferred size is: " + previous_pane.getPreferredSize());
837 }
838 }
839
840 /** The <strong>OptionTree</strong> is built from these nodes, each of which has several methods used in creating the option panes.
841 */
842 private class OptionTreeNode
843 extends DefaultMutableTreeNode
844 implements Comparable {
845 /** The text label given to this node in the tree. */
846 private String title = null;
847 /** a tool tip to be used for this node in the tree */
848 private String tool_tip = null;
849 /** Constructor.
850 * @param title The <strong>String</strong> which serves as this nodes title.
851 */
852 public OptionTreeNode(String title) {
853 super();
854 this.title = title;
855 }
856
857 /** This method compares two nodes for ordering.
858 * @param obj The <strong>Object</strong> to compare to.
859 * @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.
860 */
861 public int compareTo(Object obj) {
862 return title.compareTo(obj.toString());
863 }
864
865 /** This method checks if two nodes are equivalent.
866 * @param obj The <strong>Object</strong> to be tested against.
867 * @return A <strong>boolean</strong> which is <i>true</i> if the objects are equal, <i>false</i> otherwise.
868 */
869 public boolean equals(Object obj) {
870 if(compareTo(obj) == 0) {
871 return true;
872 }
873 return false;
874 }
875
876 /** get the tool tip */
877 public String getToolTipText() {
878 return tool_tip;
879 }
880
881 /** set the tool tip */
882 public void setToolTipText(String tip) {
883 tool_tip = tip;
884 }
885
886 /** Method to translate this node into a textual representation.
887 * @return A <strong>String</strong> which in this case is the title.
888 */
889 public String toString() {
890 return title;
891 }
892 }
893
894 // Adds tooltips to the tree nodes
895 private class ToolTipTreeCellRenderer
896 extends DefaultTreeCellRenderer {
897
898 public Component getTreeCellRendererComponent(JTree tree,
899 Object value,
900 boolean sel,
901 boolean expanded,
902 boolean leaf,
903 int row,
904 boolean hasFocus) {
905
906 super.getTreeCellRendererComponent(tree, value, sel,
907 expanded, leaf, row,
908 hasFocus);
909 if (value instanceof OptionTreeNode) {
910 String tip = ((OptionTreeNode) value).getToolTipText();
911 if (tip != null) {
912 setToolTipText(tip);
913 }
914 }
915 return this;
916 }
917 }
918}
Note: See TracBrowser for help on using the repository browser.