source: gli/branches/incremental/src/org/greenstone/gatherer/gui/CreatePane.java@ 19401

Last change on this file since 19401 was 19401, checked in by oranfry, 15 years ago

incremental import and build now works from gli, controlled by the minimal and full build buttons

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