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

Last change on this file since 18589 was 18589, checked in by kjdon, 15 years ago

GLI three modes change: systems mode is no more.

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