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

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

changed a print statement to DebugStream

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