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

Last change on this file since 12144 was 12119, checked in by kjdon, 18 years ago

Changed text handling to use Dictionary.get rather than Dictionary.setText or Dictionary.registerBoth etc. also removed mnemonics cos they suck for other languages

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