source: gli/trunk/src/org/greenstone/gatherer/gui/OptionsPane.java@ 14240

Last change on this file since 14240 was 14240, checked in by xiao, 17 years ago

make the option disable_OAI visible in the GLI for Greenstone 3 (modification in method buildBuild()). By default it's hidden in the GLI.

  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 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 java.util.*;
43import javax.swing.*;
44import javax.swing.event.*;
45import javax.swing.text.*;
46import org.greenstone.gatherer.Configuration;
47import org.greenstone.gatherer.DebugStream;
48import org.greenstone.gatherer.Dictionary;
49import org.greenstone.gatherer.Gatherer;
50import org.greenstone.gatherer.cdm.Argument;
51import org.greenstone.gatherer.cdm.ArgumentControl;
52import org.greenstone.gatherer.collection.ScriptOptions;
53import org.greenstone.gatherer.collection.Collection;
54import org.greenstone.gatherer.collection.CollectionManager;
55import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
56import org.greenstone.gatherer.util.AppendLineOnlyFileDocumentOwner;
57import org.greenstone.gatherer.util.StaticStrings;
58
59/** This class serves as the data holder for all subclasses of option panes, such as Import options or All options. It also contains methods for creating each of the option lines as they would appear in the subpane. Futhermore it has a method for considering all the arguments and generating a <strong>String[]</strong> to allow you to pass them to the <strong>GShell</strong>.
60 * @author John Thompson, Greenstone Digital Library, University of Waikato
61 * @version 2.2
62 */
63public class OptionsPane
64 extends JPanel
65 implements AppendLineOnlyFileDocumentOwner, MouseListener {
66
67 static final public char SUCCESSFUL = 's';
68 static final public char UNSUCCESSFUL = 'u';
69 static final public char CANCELLED = 'c';
70 static final public char UNKNOWN = 'x';
71
72 static private int BUILD = 0;
73 static private int IMPORT = 1;
74 static private int MINIMUM_ROWS = 11;
75
76 /** All process messages are written to this log text area. */
77 public JTextArea log_textarea = null;
78
79 private ArrayList current_controls;
80
81 /** The <strong>ScriptOptions</strong> data object contains all the option settings we wish to persist between Gatherer sessions (and thus is stored in <strong>Collection</strong>). */
82 private ScriptOptions build_options = null;
83 private ScriptOptions import_options = null;
84
85 private FileEntry file_entry = null;
86
87 /** the log pane - we only create it once now, not each time */
88 private JPanel log_pane = null;
89 /** the list of previous log messages */
90 private JList log_list = null;
91 private Vector writing_documents;
92
93
94 /** The default constructor creates the few session length options, but either retrieves the rest from the current collection, or creates a default set of options. */
95 public OptionsPane(ScriptOptions import_options, ScriptOptions build_options) {
96 this.build_options = build_options;
97 this.import_options = import_options;
98 this.current_controls = new ArrayList();
99 this.writing_documents = new Vector();
100
101 // Have to do this here, not in display, as the message log view may not have been displayed yet.
102 log_textarea = new JTextArea();
103 log_textarea.setEditable(false);
104 }
105
106 /** This method creates the panel with all the build only options on it.
107 * @param pane a JPanel which already has previous arguments available on it, to allow for lower moes to concatenate all of the arguments together
108 * @return a JPanel which can be used to display all the build only options
109 * @see org.greenstone.gatherer.Configuration#EXPERT_MODE
110 * @see org.greenstone.gatherer.Configuration#getColor
111 * @see org.greenstone.gatherer.Configuration#getMode
112 * @see org.greenstone.gatherer.Gatherer#config
113 * @see org.greenstone.gatherer.cdm.Argument
114 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildArgument
115 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildArgumentCount
116 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildValue
117 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildValueEnabled
118 * @see org.greenstone.gatherer.gui.OptionsPane.MyArgumentControl
119 */
120 public JPanel buildBuild(JPanel pane) {
121 // Reset the arguments
122 if(pane == null) {
123 current_controls.clear();
124 }
125 ArrayList build_arguments = new ArrayList();
126 int current_mode = Configuration.getMode();
127 int total_build_argument_count = build_options.getArgumentCount();
128
129 for(int i = 0; i < total_build_argument_count; i++) {
130 // Retrieve the argument so we know how to format the control.
131 Argument argument = build_options.getArgument(i);
132
133 //A hack to make the disable_OAI option visible in the GLI for Greenstone 3
134 if(argument.getName().equals(StaticStrings.DISABLEOAI_STR) && Gatherer.GS3) {
135 argument.setHiddenGLI(false);
136 }
137 if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
138 // Now attempt to retrieve any existing value for this argument.
139 boolean enabled = build_options.getValueEnabled(argument.getName());
140 String value = build_options.getValue(argument.getName());
141 MyArgumentControl argument_control = new MyArgumentControl(BUILD, argument, enabled, value);
142 build_arguments.add(argument_control);
143 }
144 }
145 current_controls.addAll(build_arguments);
146
147 // Now that we know how many arguments there are we can build the pane to view them on. Modes lower than EXPERT can provide a previous pane on which to add the arguments.
148 if(pane == null || current_mode >= Configuration.EXPERT_MODE) {
149 pane = new JPanel();
150 pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
151 pane.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
152 int argument_count = build_arguments.size();
153 // If in any of the higher detail modes, and assuming we don't want super phat argument controls, we better ensure there is a minimum number of lines in the grid layout
154 if(current_mode >= Configuration.EXPERT_MODE) {
155 if(argument_count < MINIMUM_ROWS) {
156 argument_count = MINIMUM_ROWS;
157 }
158 pane.setLayout(new GridLayout(argument_count, 1, 5, 5));
159 }
160 // Otherwise we're just going to throw them on one after another and chuck it in a scroll pane anyway
161 else {
162 // use GridLayout with 0 rows == as many rows as needed. Unfortunately, rows will
163 // grow fat if space too large, but we don't know how many rows we'll need yet.
164 pane.setLayout(new GridLayout(0, 1, 5, 5));
165 }
166 }
167
168 for(int j = 0; j < build_arguments.size(); j++) {
169 pane.add((JComponent)build_arguments.get(j));
170 }
171 pane.addMouseListener(this);
172 build_arguments = null;
173 return pane;
174 }
175
176 /** This method creates the panel with all the import only options on it.
177 * @param pane a JPanel which already has previous arguments available on it, to allow for lower moes to concatenate all of the arguments together
178 * @return a JPanel which can be used to display all the build only options
179 * @see org.greenstone.gatherer.Configuration#EXPERT_MODE
180 * @see org.greenstone.gatherer.Configuration#getColor
181 * @see org.greenstone.gatherer.Configuration#getMode
182 * @see org.greenstone.gatherer.Gatherer#config
183 * @see org.greenstone.gatherer.cdm.Argument
184 * @see org.greenstone.gatherer.collection.BuildOptions#getImportArgument
185 * @see org.greenstone.gatherer.collection.BuildOptions#getImportArgumentCount
186 * @see org.greenstone.gatherer.collection.BuildOptions#getImportValue
187 * @see org.greenstone.gatherer.collection.BuildOptions#getImportValueEnabled
188 * @see org.greenstone.gatherer.gui.OptionsPane.ArgumentControl
189 */
190 public JPanel buildImport(JPanel pane) {
191 // Reset the arguments
192 if(pane == null) {
193 current_controls.clear();
194 }
195 ArrayList import_arguments = new ArrayList();
196 int current_mode = Configuration.getMode();
197 int total_import_argument_count = import_options.getArgumentCount();
198 for(int i = 0; i < total_import_argument_count; i++) {
199 // Retrieve the argument so we know how to format the control.
200 Argument argument = import_options.getArgument(i);
201 if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
202 // Now attempt to retrieve any existing value for this argument.
203 boolean enabled = import_options.getValueEnabled(argument.getName());
204 String value = import_options.getValue(argument.getName());
205 MyArgumentControl argument_control = new MyArgumentControl(IMPORT, argument, enabled, value);
206 import_arguments.add(argument_control);
207 }
208 }
209 current_controls.addAll(import_arguments);
210 // Now that we know how many arguments there are we can build the pane to view them on. Modes lower than EXPERT can provide a previous pane on which to add the arguments.
211 if(pane == null || current_mode >= Configuration.EXPERT_MODE) {
212 pane = new JPanel();
213 pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
214 pane.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
215 int argument_count = import_arguments.size();
216 // If in any of the higher detail modes, and assuming we don't want super phat argument controls, we better ensure there is a minimum number of lines in the grid layout
217 if(current_mode >= Configuration.EXPERT_MODE) {
218 if(argument_count < MINIMUM_ROWS) {
219 argument_count = MINIMUM_ROWS;
220 }
221 pane.setLayout(new GridLayout(argument_count, 1, 5, 5));
222 }
223 // Otherwise we're just going to throw them on one after another and chuck it in a scroll pane anyway
224 else {
225 // use GridLayout with 0 rows == as many rows as needed. Unfortunately, rows will
226 // grow fat if space too large, but we don't know how many rows we'll need yet.
227 pane.setLayout(new GridLayout(0, 1, 5, 5));
228 }
229 }
230
231 for(int j = 0; j < import_arguments.size(); j++) {
232 pane.add((JComponent)import_arguments.get(j));
233 }
234 pane.addMouseListener(this);
235 import_arguments = null;
236 return pane;
237 }
238
239 /** This method is used to build a panel based on the message log, which is nothing like any of the other panels.
240 * @return A <strong>JPanel</strong> containing a scrollable text area which represents the shell process message log.
241 */
242 public JPanel buildLog() {
243 // we now save the log pane
244 if (log_pane == null) {
245 log_pane = new JPanel(new BorderLayout());
246
247 // Build a list of the log files available, ordering by last modified. Log files are like build_log.date.txt
248 DefaultListModel contents = new DefaultListModel();
249 File log_directory = new File(CollectionManager.getLoadedCollectionLogDirectoryPath());
250 File children[] = log_directory.listFiles();
251 for(int i = 0; children != null && i < children.length; i++) {
252 String filename = children[i].getName();
253 if(filename.startsWith("build_log.") && filename.endsWith(".txt") ) {
254 String datestamp = filename.substring(filename.indexOf(".") + 1, filename.lastIndexOf(".")).toLowerCase();
255 if(datestamp.indexOf("s") == -1 && datestamp.indexOf("u") == -1 && datestamp.indexOf("c") == -1 && datestamp.indexOf("x") == -1) {
256 FileEntry entry = new FileEntry(children[i].getName(), children[i].getAbsolutePath());
257 // We are about to insert it. But where.
258 boolean found = false;
259 for(int j = 0; !found && j < contents.size(); j++) {
260 FileEntry sibling = (FileEntry) contents.getElementAt(j);
261 int order = entry.compareTo(sibling);
262 if(order > 0) {
263 contents.insertElementAt(entry, j);
264 found = true;
265 }
266 }
267 if(!found) {
268 contents.addElement(entry);
269 }
270 }
271 }
272 }
273
274 log_list = new JList(contents);
275 log_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
276 log_list.setLayoutOrientation(JList.VERTICAL);
277 log_list.setPreferredSize(new Dimension(600, 100));
278 log_list.setVisibleRowCount(3);
279 log_list.addListSelectionListener(new LogListListener());
280
281 JLabel log_history_label = new JLabel(Dictionary.get("OptionsPane.LogHistory"));
282 JPanel log_history_pane = new JPanel();
283 log_history_pane.setPreferredSize(new Dimension(600, 100));
284 log_history_pane.setLayout(new BorderLayout());
285 log_history_pane.add(log_history_label, BorderLayout.NORTH);
286 log_history_pane.add(new JScrollPane(log_list), BorderLayout.CENTER);
287
288 log_pane.add(new JScrollPane(log_textarea), BorderLayout.CENTER);
289 log_pane.add(log_history_pane, BorderLayout.SOUTH);
290 }
291 return log_pane;
292 }
293
294 public AppendLineOnlyFileDocument createNewLogDocument() {
295 long time = System.currentTimeMillis();
296 StringBuffer name = new StringBuffer();
297 name.append("build_log.");
298 name.append(time);
299 name.append(".txt");
300 // just in case there is no log directory
301 File file = new File(CollectionManager.getLoadedCollectionLogDirectoryPath() + name.toString());
302 File parent_file = file.getParentFile();
303 parent_file.mkdirs();
304 parent_file = null;
305 // create the file entry and add it to the list at pos 0 - it will always be the newest one created
306 file_entry = new FileEntry(name.toString(), file.getAbsolutePath());
307 ((DefaultListModel)log_list.getModel()).add(0, file_entry);
308 log_list.setSelectedIndex(0);
309 // Finally retrieve and return the document associated with this file entry
310 return file_entry.getDocument();
311 }
312
313
314 /** Attempts to discover the latest document count.
315 * @return An <strong>int</strong> detailing the number of documents in this collection.
316 */
317 public int getDocumentCount() {
318 if(Gatherer.c_man.ready()) {
319 int count = Gatherer.c_man.getCollection().getDocumentCount();
320 if(count != 0) {
321 return count;
322 }
323 }
324 return 1;
325 }
326
327 /** Called by our magic log documents after they have finished writing themselves to file, whereapon it is no longer necessary to hold a reference to them. */
328 public void remove(AppendLineOnlyFileDocument document) {
329 writing_documents.remove(document);
330 }
331
332 public void resetFileEntry() {
333 if(file_entry != null) {
334 file_entry.reset();
335 }
336 }
337
338 /** Given a panel containing ArgumentControls, update the values associated with them. */
339 public void update(JPanel panel) {
340 if(panel == log_pane) {
341 return;
342 }
343
344 for(int i = 0; i < panel.getComponentCount(); i++) {
345 Component component = panel.getComponent(i);
346 if(component instanceof MyArgumentControl) {
347 ((MyArgumentControl)component).update();
348 }
349 }
350 }
351
352 /** Implementation side-effect
353 * @param e a MouseEvent
354 */
355 public void mouseClicked(MouseEvent e) {}
356
357 /** Implementation side-effect
358 * @param e a MouseEvent
359 */
360 public void mouseEntered(MouseEvent e) {}
361
362 /** Implemented to ensure that, by the time the mouse pointer leaves the current build options screen, ang changes to the value the JSpinners have been commited
363 * @param e a MouseEvent
364 */
365 public void mouseExited(MouseEvent e) {
366 // Loop through the controls, and if the current control is a JSpinner, commit its current editing
367 for(int i = 0; i < current_controls.size(); i++) {
368 MyArgumentControl control = (MyArgumentControl) current_controls.get(i);
369 JComponent value_control = control.getValueControl();
370 if(value_control instanceof JSpinner) {
371 try {
372 ((JSpinner)value_control).commitEdit();
373 }
374 catch(Exception exception) {
375 DebugStream.println("Exception in OptionsPane.mouseExited() - unexpected");
376 DebugStream.printStackTrace(exception);
377 }
378 }
379 value_control = null;
380 control = null;
381 }
382 }
383
384 /** Implementation side-effect
385 * @param e a MouseEvent
386 */
387 public void mousePressed(MouseEvent e) {}
388
389 /** Implementation side-effect
390 * @param e a MouseEvent
391 */
392 public void mouseReleased(MouseEvent e) {}
393
394 private class MyArgumentControl
395 extends ArgumentControl {
396 private int type;
397
398 public MyArgumentControl(int type, Argument argument, boolean enable, String value) {
399 super(argument, enable, value);
400 this.type = type;
401 }
402
403 /** Update the values stored in the collection so as to remember the current state of this argument. */
404 public void update() {
405 String name = getArgumentName();
406 boolean enable = isEnabled();
407 String value = getValue();
408 // If this argument was a flag, but is now disabled, remove from the build options altogether
409 if(!enable && value == null) {
410 if(type == BUILD) {
411 build_options.removeValue(name);
412 }
413 else {
414 import_options.removeValue(name);
415 }
416 }
417 // Otherwise update the argument value
418 else {
419 if(type == BUILD) {
420 build_options.setValue(name, enable, value);
421 }
422 else {
423 import_options.setValue(name, enable, value);
424 }
425 }
426 }
427 }
428
429 /** Holds a File which has a particular naming convention build_log.date.txt also keeps a Date corresponding to the date in its name*/
430 private class FileEntry {
431
432 private AppendLineOnlyFileDocument current_document;
433 private Date date;
434 private long last_modified;
435 private String display;
436 private String filename;
437 private String filepath;
438
439 public FileEntry(String filename, String filepath) {
440 this.date = null;
441 this.display = null;
442 this.filename = filename;
443 this.filepath = filepath;
444 this.last_modified = 0L;
445 }
446
447 /** returns 0 if the dates are the same, -ve number if the current FileEntry is earlier than the fe FileEntry ...*/
448 public int compareTo(FileEntry file_entry) {
449 Date our_date = getDate();
450 Date other_date = file_entry.getDate();
451 return our_date.compareTo(other_date);
452 }
453
454 public Date getDate() {
455 if(date == null) {
456 // Need to exclude first '.'
457 int first_index = filename.indexOf(".") + 1;
458 // Need to exclude the last '.'
459 int last_index = filename.lastIndexOf(".");
460 if(first_index > 0 && last_index > 0 && first_index < last_index) {
461 String date_string = filename.substring(first_index, last_index);
462 date = new Date(Long.parseLong(date_string));
463 }
464 else {
465 date = new Date(); // Current date
466 }
467 }
468 return date;
469 }
470
471 public AppendLineOnlyFileDocument getDocument() {
472 if(current_document == null) {
473 current_document = new AppendLineOnlyFileDocument(filepath);
474 }
475 return current_document;
476 }
477
478 public void reset() {
479 display = null;
480 }
481
482 /** we only want the date out of the file name, not the whole path */
483 public String toString() {
484 File file = new File(filename);
485 if(display == null) {
486 last_modified = file.lastModified();
487 StringBuffer d = new StringBuffer();
488 Date date = getDate();
489 d.append(date.toString());
490 char success = UNKNOWN;
491 File the_file = new File(filepath);
492 if(the_file.exists()) {
493 try {
494 FileInputStream in = new FileInputStream(the_file);
495 success = (char) in.read();
496 in.close();
497 in = null;
498 }
499 catch(Exception error) {
500 ///ystem.err.println("Log '" + filepath + "' not found!");
501 ///atherer.printStackTrace(error);
502 }
503 }
504 the_file = null;
505 switch (success) {
506 case SUCCESSFUL:
507 d.append(Dictionary.get("OptionsPane.Successful"));
508 break;
509 case UNSUCCESSFUL:
510 d.append(Dictionary.get("OptionsPane.Unsuccessful"));
511 break;
512 case CANCELLED:
513 d.append(Dictionary.get("OptionsPane.Cancelled"));
514 break;
515 default:
516 d.append(Dictionary.get("OptionsPane.Unknown"));
517 }
518 display = d.toString();
519 }
520 return display;
521 }
522 }
523
524 /** a ListSelectionListener that triggers the load of a newly selected log */
525 private class LogListListener implements ListSelectionListener {
526
527 public void valueChanged(ListSelectionEvent e) {
528 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
529 ///ystem.err.println("Log change detected.");
530 JList source = (JList)e.getSource();
531 file_entry = (FileEntry) source.getSelectedValue();
532 // First we determine if the old log has been completely written to file
533 Document document = log_textarea.getDocument();
534 ///ystem.err.println(" * current document: " + document);
535 ///ystem.err.println(" * new document: " + file_entry.getDocument());
536 // If we are dealing with the same document don't do anything.
537 if(document != file_entry.getDocument()) {
538 if(document instanceof AppendLineOnlyFileDocument) {
539 AppendLineOnlyFileDocument append_line_only_file_document = (AppendLineOnlyFileDocument) document;
540 if(append_line_only_file_document.isStillWriting()) {
541 ///ystem.err.println("Current log is still active... finishing.");
542 writing_documents.add(append_line_only_file_document); // We have to maintain a reference until they are all done.
543 append_line_only_file_document.setOwner(OptionsPane.this);
544 append_line_only_file_document.setExit();
545 }
546 else {
547 ///ystem.err.println("Current log is complete. Nothing to do.");
548 }
549 }
550 // Load the new log
551 log_textarea.setDocument(file_entry.getDocument());
552 }
553 }
554 }
555 }
556
557}
Note: See TracBrowser for help on using the repository browser.