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

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

Checking canDoScheduling() before trying to do buildSchedule stuff

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