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

Last change on this file since 7059 was 7059, checked in by kjdon, 20 years ago

made the range bit work for integer args

  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.gui;
38
39import java.awt.*;
40import java.awt.event.*;
41import java.io.*;
42import java.util.*;
43import javax.swing.*;
44import javax.swing.event.*;
45import javax.swing.text.*;
46import org.greenstone.gatherer.Configuration;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.cdm.Argument;
50import org.greenstone.gatherer.checklist.CheckList;
51import org.greenstone.gatherer.collection.BuildOptions;
52import org.greenstone.gatherer.collection.Collection;
53import org.greenstone.gatherer.collection.CollectionManager;
54import org.greenstone.gatherer.msm.ElementWrapper;
55import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
56import org.greenstone.gatherer.util.AppendLineOnlyFileDocumentOwner;
57import org.greenstone.gatherer.util.Utility;
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 static private Dimension LABEL_SIZE = new Dimension(180, 25);
76 static private Dimension ROW_SIZE = new Dimension(610, 30);
77 static private Dimension SPINNER_SIZE = new Dimension(100, 25);
78 static private String DESCRIPTION_SEP = " + ";
79
80 /** All process messages are written to this log text area. */
81 public JTextArea log_textarea = null;
82
83 private ArrayList current_controls;
84
85 /** The <strong>BuildOptions</strong> data object contains all the option settings we wish to persist between Gatherer sessions (and thus is stored in <strong>Collection</strong>). */
86 private BuildOptions build_options = null;
87
88 private FileEntry file_entry = null;
89
90 /** the log pane - we only create it once now, not each time */
91 private JPanel log_pane = null;
92 /** the list of previous log messages */
93 private JList log_list = null;
94 private Vector writing_documents;
95
96
97 /** 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. */
98 public OptionsPane(BuildOptions build_options) {
99 this.build_options = build_options;
100 this.current_controls = new ArrayList();
101 this.writing_documents = new Vector();
102
103 // Have to do this here, not in display, as the message log view may not have been displayed yet.
104 log_textarea = new JTextArea();
105 log_textarea.setEditable(false);
106 }
107
108 /** This method creates the panel with all the build only options on it.
109 * @param pane a JPanel which already has previous arguments available on it, to allow for lower moes to concatenate all of the arguments together
110 * @return a JPanel which can be used to display all the build only options
111 * @see org.greenstone.gatherer.Configuration#EXPERT_MODE
112 * @see org.greenstone.gatherer.Configuration#getColor
113 * @see org.greenstone.gatherer.Configuration#getMode
114 * @see org.greenstone.gatherer.Gatherer#config
115 * @see org.greenstone.gatherer.cdm.Argument
116 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildArgument
117 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildArgumentCount
118 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildValue
119 * @see org.greenstone.gatherer.collection.BuildOptions#getBuildValueEnabled
120 * @see org.greenstone.gatherer.gui.OptionsPane.ArgumentControl
121 */
122 public JPanel buildBuild(JPanel pane) {
123 // Reset the arguments
124 if(pane == null) {
125 current_controls.clear();
126 }
127 ArrayList build_arguments = new ArrayList();
128 int current_mode = Gatherer.config.getMode();
129 int total_build_argument_count = build_options.getBuildArgumentCount();
130 for(int i = 0; i < total_build_argument_count; i++) {
131 // Retrieve the argument so we know how to format the control.
132 Argument argument = build_options.getBuildArgument(i);
133 if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
134 // Now attempt to retrieve any existing value for this argument.
135 boolean enabled = build_options.getBuildValueEnabled(argument.getName());
136 String value = build_options.getBuildValue(argument.getName());
137 ArgumentControl argument_control = new ArgumentControl(BUILD, argument, enabled, value);
138 build_arguments.add(argument_control);
139 }
140 }
141 current_controls.addAll(build_arguments);
142 // 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.
143 if(pane == null || current_mode >= Configuration.EXPERT_MODE) {
144 pane = new JPanel();
145 pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
146 pane.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
147 int argument_count = build_arguments.size();
148 // 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 or lines in the grid layout
149 if(current_mode >= Configuration.EXPERT_MODE) {
150 if(argument_count < MINIMUM_ROWS) {
151 argument_count = MINIMUM_ROWS;
152 }
153 pane.setLayout(new GridLayout(argument_count, 1, 5, 5));
154 }
155 // Otherwise we're just going to throw them on one after another and chuck it in a scroll pane anyway
156 else {
157 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
158 }
159 }
160 for(int j = 0; j < build_arguments.size(); j++) {
161 pane.add((JComponent)build_arguments.get(j));
162 }
163 pane.addMouseListener(this);
164 build_arguments = null;
165 return pane;
166 }
167
168 /** This method creates the panel with all the import only options on it.
169 * @param pane a JPanel which already has previous arguments available on it, to allow for lower moes to concatenate all of the arguments together
170 * @return a JPanel which can be used to display all the build only options
171 * @see org.greenstone.gatherer.Configuration#EXPERT_MODE
172 * @see org.greenstone.gatherer.Configuration#getColor
173 * @see org.greenstone.gatherer.Configuration#getMode
174 * @see org.greenstone.gatherer.Gatherer#config
175 * @see org.greenstone.gatherer.cdm.Argument
176 * @see org.greenstone.gatherer.collection.BuildOptions#getImportArgument
177 * @see org.greenstone.gatherer.collection.BuildOptions#getImportArgumentCount
178 * @see org.greenstone.gatherer.collection.BuildOptions#getImportValue
179 * @see org.greenstone.gatherer.collection.BuildOptions#getImportValueEnabled
180 * @see org.greenstone.gatherer.gui.OptionsPane.ArgumentControl
181 */
182 public JPanel buildImport(JPanel pane) {
183 // Reset the arguments
184 if(pane == null) {
185 current_controls.clear();
186 }
187 ArrayList import_arguments = new ArrayList();
188 int current_mode = Gatherer.config.getMode();
189 int total_import_argument_count = build_options.getImportArgumentCount();
190 for(int i = 0; i < total_import_argument_count; i++) {
191 // Retrieve the argument so we know how to format the control.
192 Argument argument = build_options.getImportArgument(i);
193 if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
194 // Now attempt to retrieve any existing value for this argument.
195 boolean enabled = build_options.getImportValueEnabled(argument.getName());
196 String value = build_options.getImportValue(argument.getName());
197 ArgumentControl argument_control = new ArgumentControl(IMPORT, argument, enabled, value);
198 import_arguments.add(argument_control);
199 }
200 }
201 current_controls.addAll(import_arguments);
202 // 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.
203 if(pane == null || current_mode >= Configuration.EXPERT_MODE) {
204 pane = new JPanel();
205 pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
206 pane.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
207 int argument_count = import_arguments.size();
208 // 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 or lines in the grid layout
209 if(current_mode >= Configuration.EXPERT_MODE) {
210 if(argument_count < MINIMUM_ROWS) {
211 argument_count = MINIMUM_ROWS;
212 }
213 pane.setLayout(new GridLayout(argument_count, 1, 5, 5));
214 }
215 // Otherwise we're just going to throw them on one after another and chuck it in a scroll pane anyway
216 else {
217 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
218 }
219 }
220 for(int j = 0; j < import_arguments.size(); j++) {
221 pane.add((JComponent)import_arguments.get(j));
222 }
223 pane.addMouseListener(this);
224 import_arguments = null;
225 return pane;
226 }
227
228 /** This method is used to build a panel based on the message log, which is nothing like any of the other panels.
229 * @return A <strong>JPanel</strong> containing a scrollable text area which represents the shell process message log.
230 */
231 public JPanel buildLog() {
232 // we now save the log pane
233 if (log_pane == null) {
234 log_pane = new JPanel(new BorderLayout());
235
236 // Build a list of the log files available, ordering by last modified. Log files are like build_log.date.txt
237 DefaultListModel contents = new DefaultListModel();
238 File log_directory = new File(Gatherer.c_man.getCollectionLog());
239 File children[] = log_directory.listFiles();
240 for(int i = 0; children != null && i < children.length; i++) {
241 String filename = children[i].getName();
242 if(filename.startsWith("build_log.") && filename.endsWith(".txt") ) {
243 String datestamp = filename.substring(filename.indexOf(".") + 1, filename.lastIndexOf(".")).toLowerCase();
244 if(datestamp.indexOf("s") == -1 && datestamp.indexOf("u") == -1 && datestamp.indexOf("c") == -1 && datestamp.indexOf("x") == -1) {
245 FileEntry entry = new FileEntry(children[i].getName(), children[i].getAbsolutePath());
246 // We are about to insert it. But where.
247 boolean found = false;
248 for(int j = 0; !found && j < contents.size(); j++) {
249 FileEntry sibling = (FileEntry) contents.getElementAt(j);
250 int order = entry.compareTo(sibling);
251 if(order > 0) {
252 contents.insertElementAt(entry, j);
253 found = true;
254 }
255 }
256 if(!found) {
257 contents.addElement(entry);
258 }
259 }
260 }
261 }
262
263 log_list = new JList(contents);
264 log_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
265 log_list.setLayoutOrientation(JList.VERTICAL);
266 log_list.setPreferredSize(new Dimension(600, 100));
267 log_list.setVisibleRowCount(3);
268 log_list.addListSelectionListener(new LogListListener());
269
270 JLabel log_history_label = new JLabel();
271 Dictionary.registerText(log_history_label, "OptionsPane.LogHistory");
272 JPanel log_history_pane = new JPanel();
273 log_history_pane.setPreferredSize(new Dimension(600, 100));
274 log_history_pane.setLayout(new BorderLayout());
275 log_history_pane.add(log_history_label, BorderLayout.NORTH);
276 log_history_pane.add(new JScrollPane(log_list), BorderLayout.CENTER);
277
278 log_pane.add(new JScrollPane(log_textarea), BorderLayout.CENTER);
279 log_pane.add(log_history_pane, BorderLayout.SOUTH);
280 }
281 return log_pane;
282 }
283
284 public AppendLineOnlyFileDocument createNewLogDocument() {
285 long time = System.currentTimeMillis();
286 StringBuffer name = new StringBuffer();
287 name.append("build_log.");
288 name.append(time);
289 name.append(".txt");
290 // just in case there is no log directory
291 File file = new File(Gatherer.c_man.getCollectionLog() + name.toString());
292 File parent_file = file.getParentFile();
293 parent_file.mkdirs();
294 parent_file = null;
295 // create the file entry and add it to the list at pos 0 - it will always be the newest one created
296 file_entry = new FileEntry(name.toString(), file.getAbsolutePath());
297 ((DefaultListModel)log_list.getModel()).add(0, file_entry);
298 log_list.setSelectedIndex(0);
299 // Finally retrieve and return the document associated with this file entry
300 return file_entry.getDocument();
301 }
302
303
304 /** Attempts to discover the latest document count.
305 * @return An <strong>int</strong> detailing the number of documents in this collection.
306 */
307 public int getDocumentCount() {
308 if(Gatherer.c_man.ready()) {
309 int count = Gatherer.c_man.getCollection().getDocumentCount();
310 if(count != 0) {
311 return count;
312 }
313 }
314 return 1;
315 }
316
317 /** 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. */
318 public void remove(AppendLineOnlyFileDocument document) {
319 writing_documents.remove(document);
320 }
321
322 public void resetFileEntry() {
323 if(file_entry != null) {
324 file_entry.reset();
325 }
326 }
327
328 /** Given a panel containing ArgumentControls, update the values associated with them. */
329 public void update(JPanel panel) {
330 if(panel == log_pane) {
331 return;
332 }
333
334 for(int i = 0; i < panel.getComponentCount(); i++) {
335 Component component = panel.getComponent(i);
336 if(component instanceof ArgumentControl) {
337 ((ArgumentControl)component).update();
338 }
339 }
340 }
341
342 /** Implementation side-effect
343 * @param e a MouseEvent
344 */
345 public void mouseClicked(MouseEvent e) {}
346
347 /** Implementation side-effect
348 * @param e a MouseEvent
349 */
350 public void mouseEntered(MouseEvent e) {}
351
352 /** 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
353 * @param e a MouseEvent
354 */
355 public void mouseExited(MouseEvent e) {
356 // Loop through the controls, and if the current control is a JSpinner, commit its current editing
357 for(int i = 0; i < current_controls.size(); i++) {
358 ArgumentControl control = (ArgumentControl) current_controls.get(i);
359 JComponent value_control = control.getValueControl();
360 if(value_control instanceof JSpinner) {
361 try {
362 ((JSpinner)value_control).commitEdit();
363 }
364 catch(Exception exception) {
365 Gatherer.println("Exception in OptionsPane.mouseExited() - unexpected");
366 Gatherer.printStackTrace(exception);
367 }
368 }
369 value_control = null;
370 control = null;
371 }
372 }
373
374 /** Implementation side-effect
375 * @param e a MouseEvent
376 */
377 public void mousePressed(MouseEvent e) {}
378
379 /** Implementation side-effect
380 * @param e a MouseEvent
381 */
382 public void mouseReleased(MouseEvent e) {}
383
384 private class ArgumentControl
385 extends JPanel {
386 private Argument argument;
387 private int type;
388 private JComponent value_control;
389 private JCheckBox enabled;
390 public ArgumentControl(int type, Argument argument, boolean enable, String value) {
391 super();
392 this.argument = argument;
393 this.type = type;
394 String tooltip = Utility.formatHTMLWidth("<html>" + argument.getDescription() + "</html>", 60);
395 // Because of the dynamic order of component creation/connection/layout, we can't really follow that pattern here.
396 setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
397 setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
398 setLayout(new BorderLayout());
399 setPreferredSize(ROW_SIZE);
400 setMaximumSize(ROW_SIZE);
401
402 // Try to determine what the value_controls value should be.
403 if(value == null) {
404 value = argument.getDefaultValue();
405 }
406 // Create a correct value control based on the argument provided.
407 switch(argument.getType()) {
408 case Argument.ENUM:
409 JComboBox combobox = new JComboBox();
410 combobox.setEnabled(enable);
411 combobox.setToolTipText(tooltip);
412 // Set enabled
413 if(enable) {
414 combobox.setBackground(Color.white);
415 }
416 else {
417 combobox.setBackground(Color.lightGray);
418 }
419 // Build an option model, wrapping each entry of the list table.
420 HashMap arg_list = argument.getOptions();
421 Iterator it = arg_list.keySet().iterator();
422 while(it.hasNext()) {
423 combobox.addItem((String) it.next());
424 }
425 // Connect this up first, so that if a value is selected the tooltip updates accordingly.
426 combobox.addActionListener(new ToolTipUpdater(arg_list));
427 if(value != null) {
428 // Set the selected string. However since they are all strings we had best iterate ourselves.
429 for(int i = 0; i < combobox.getItemCount(); i++) {
430 if(combobox.getItemAt(i).toString().equals(value)) {
431 combobox.setSelectedIndex(i);
432 }
433 }
434 }
435 // Layout
436 add(combobox, BorderLayout.CENTER);
437 // And remember
438 value_control = combobox;
439 break;
440 case Argument.FLAG:
441 // Only need the check box.
442 value_control = null;
443 break;
444 case Argument.INTEGER:
445 // Build a spinner
446 int initial_value=0;
447 if (value != null) {
448 try {
449 initial_value = Integer.parseInt(value);
450 } catch (Exception exception) {
451 }
452 }
453 if (initial_value < argument.getMinimum()) {
454 initial_value = argument.getMinimum();
455 } else if (initial_value > argument.getMaximum()) {
456 initial_value = argument.getMaximum();
457 }
458 JSpinner spinner = new JSpinner(new SpinnerNumberModel(initial_value, argument.getMinimum(), argument.getMaximum(), 1));
459 spinner.setEnabled(enable);
460 spinner.setPreferredSize(SPINNER_SIZE);
461 spinner.setToolTipText(tooltip);
462 // Set enabled
463 JComponent c = spinner.getEditor();
464 if ( c instanceof JSpinner.DefaultEditor ) {
465 JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
466 JFormattedTextField field = editor.getTextField();
467 field.setEditable(enable);
468 if(enable) {
469 field.setBackground(Color.white);
470 }
471 else {
472 field.setBackground(Color.lightGray);
473 }
474 }
475 // Layout
476 add(new JLabel(), BorderLayout.CENTER);
477 add(spinner, BorderLayout.EAST);
478 // And remember it
479 value_control = spinner;
480 break;
481 case Argument.STRING:
482 // Use a standard text field
483 JTextField textfield = new JTextField();
484 textfield.setEnabled(enable);
485 textfield.setToolTipText(tooltip);
486 // Set enabled
487 if(enable) {
488 textfield.setBackground(Color.white);
489 }
490 else {
491 textfield.setBackground(Color.lightGray);
492 }
493 // If there was an original value, set it.
494 if(value != null) {
495 textfield.setText(value);
496 }
497 // Layout
498 add(textfield, BorderLayout.CENTER);
499 // And remember it
500 value_control = textfield;
501 break;
502 case Argument.METADATUM:
503 GComboBox gcombobox = new GComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements(), false);
504 gcombobox.setEnabled(enable);
505 // Now ensure we have the existing value or default value selected if either exist.
506 if(value != null) {
507 boolean found = selectValue(gcombobox, value);
508 // Its possible that this is a custom value and so doesn't exist in the combobox. If so add it and then select it
509 if(!found) {
510 gcombobox.addItem(value);
511 gcombobox.setSelectedItem(value);
512 }
513 }
514 add(gcombobox, BorderLayout.CENTER);
515 value_control = gcombobox;
516 break;
517 }
518
519 // If the argument is required, then you don't get a choice of whether it is enabled.
520 if(argument.isRequired()) {
521 JLabel label = new JLabel(argument.getName());
522 label.setOpaque(false);
523 label.setPreferredSize(LABEL_SIZE);
524 label.setToolTipText(tooltip);
525 add(label, BorderLayout.WEST);
526 }
527 else {
528 enabled = new JCheckBox(argument.getName(), enable);
529 enabled.setOpaque(false);
530 enabled.setPreferredSize(LABEL_SIZE);
531 enabled.setToolTipText(tooltip);
532 // Connect
533 enabled.addActionListener(new EnabledListener(value_control));
534 // Layout
535 add(enabled, BorderLayout.WEST);
536 }
537 }
538
539 /** Retrieve the control used for storing values.
540 * @return JComponent
541 */
542 public JComponent getValueControl() {
543 return value_control;
544 }
545
546 /** Method to ensure that a certain value is selected, if it exists within that combobox to begin with.
547 * @param combobox the JComboBox whose selection we are trying to preset
548 * @param target The desired value of the selection as a String
549 * @return true if the item was found and selected, false otherwise
550 */
551 public boolean selectValue(JComboBox combobox, String target) {
552 for(int i = 0; i < combobox.getItemCount(); i++) {
553 if(combobox.getItemAt(i).toString().equals(target)) {
554 combobox.setSelectedIndex(i);
555 return true;
556 }
557 }
558 return false;
559 }
560
561 /** Update the values stored in the collection so as to rememebr the current state of this argument. */
562 public void update() {
563 String name = argument.getName();
564 boolean enable = true;
565 if(enabled != null) {
566 enable = enabled.isSelected();
567 }
568 String value = null;
569 if(value_control == null) {
570 // Flag value, nothing to do.
571 }
572 else if(value_control instanceof JTextField) {
573 value = ((JTextField)value_control).getText();
574 }
575 else if(value_control instanceof JSpinner) {
576 value = ((JSpinner)value_control).getValue().toString();
577 }
578 else if(value_control instanceof JComboBox) {
579 value = (((JComboBox)value_control).getSelectedItem()).toString();
580 }
581 // If this argument was a flag, but is now disabled, remove from the build options altogether
582 if(!enable && value == null) {
583 if(type == BUILD) {
584 build_options.removeBuildValue(name);
585 }
586 else {
587 build_options.removeImportValue(name);
588 }
589 }
590 // Otherwise update the argument value
591 else {
592 if(type == BUILD) {
593 build_options.setBuildValue(name, enable, value);
594 }
595 else {
596 build_options.setImportValue(name, enable, value);
597 }
598 }
599 }
600 }
601
602 /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
603 private class EnabledListener
604 implements ActionListener {
605 /** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
606 private JComponent target = null;
607 /** Constructor. */
608 public EnabledListener(JComponent target) {
609 this.target = target;
610 }
611 /** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on or registered check box, prompting us to change the state of the other controls as per the users request.
612 * @param event An <strong>ActionEvent</strong> containing information about the click.
613 */
614 public void actionPerformed(ActionEvent event) {
615 JCheckBox source = (JCheckBox)event.getSource();
616 if(target != null) {
617 if(source.isSelected()) {
618 target.setBackground(Color.white);
619 target.setEnabled(true);
620 }
621 else {
622 target.setBackground(Color.lightGray);
623 target.setEnabled(false);
624 }
625 // Special case of stupid JSpinners who don't let their backgrounds change properly.
626 if(target instanceof JSpinner) {
627 JSpinner spinner = (JSpinner) target;
628 JComponent c = spinner.getEditor();
629 if ( c instanceof JSpinner.DefaultEditor ) {
630 JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
631 JFormattedTextField field = editor.getTextField();
632 field.setEditable(source.isSelected());
633 if(source.isSelected()) {
634 field.setBackground(Color.white);
635 }
636 else {
637 field.setBackground(Color.lightGray);
638 }
639 }
640 }
641 }
642 }
643 }
644
645 /** Holds a File which has a particular naming convention build_log.date.txt also keeps a Date corresponding to the date in its name*/
646 private class FileEntry {
647
648 private AppendLineOnlyFileDocument current_document;
649 private Date date;
650 private long last_modified;
651 private String display;
652 private String filename;
653 private String filepath;
654
655 public FileEntry(String filename, String filepath) {
656 this.date = null;
657 this.display = null;
658 this.filename = filename;
659 this.filepath = filepath;
660 this.last_modified = 0L;
661 }
662
663 /** returns 0 if the dates are the same, -ve number if the current FileEntry is earlier than the fe FileEntry ...*/
664 public int compareTo(FileEntry file_entry) {
665 Date our_date = getDate();
666 Date other_date = file_entry.getDate();
667 return our_date.compareTo(other_date);
668 }
669
670 public Date getDate() {
671 if(date == null) {
672 // Need to exclude first '.'
673 int first_index = filename.indexOf(".") + 1;
674 // Need to exclude the last '.'
675 int last_index = filename.lastIndexOf(".");
676 if(first_index > 0 && last_index > 0 && first_index < last_index) {
677 String date_string = filename.substring(first_index, last_index);
678 date = new Date(Long.parseLong(date_string));
679 }
680 else {
681 date = new Date(); // Current date
682 }
683 }
684 return date;
685 }
686
687 public AppendLineOnlyFileDocument getDocument() {
688 if(current_document == null) {
689 current_document = new AppendLineOnlyFileDocument(filepath);
690 }
691 return current_document;
692 }
693
694 public void reset() {
695 display = null;
696 }
697
698 /** we only want the date out of the file name, not the whole path */
699 public String toString() {
700 File file = new File(filename);
701 if(display == null) {
702 last_modified = file.lastModified();
703 StringBuffer d = new StringBuffer();
704 Date date = getDate();
705 d.append(date.toString());
706 char success = UNKNOWN;
707 File the_file = new File(filepath);
708 if(the_file.exists()) {
709 try {
710 FileInputStream in = new FileInputStream(the_file);
711 success = (char) in.read();
712 in.close();
713 in = null;
714 }
715 catch(Exception error) {
716 ///ystem.err.println("Log '" + filepath + "' not found!");
717 ///atherer.printStackTrace(error);
718 }
719 }
720 the_file = null;
721 switch (success) {
722 case SUCCESSFUL:
723 d.append(Dictionary.get("OptionsPane.Successful"));
724 break;
725 case UNSUCCESSFUL:
726 d.append(Dictionary.get("OptionsPane.Unsuccessful"));
727 break;
728 case CANCELLED:
729 d.append(Dictionary.get("OptionsPane.Cancelled"));
730 break;
731 default:
732 d.append(Dictionary.get("OptionsPane.Unknown"));
733 }
734 display = d.toString();
735 }
736 return display;
737 }
738 }
739
740 /** a ListSelectionListener that triggers the load of a newly selected log */
741 private class LogListListener implements ListSelectionListener {
742
743 public void valueChanged(ListSelectionEvent e) {
744 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
745 ///ystem.err.println("Log change detected.");
746 JList source = (JList)e.getSource();
747 file_entry = (FileEntry) source.getSelectedValue();
748 // First we determine if the old log has been completely written to file
749 Document document = log_textarea.getDocument();
750 ///ystem.err.println(" * current document: " + document);
751 ///ystem.err.println(" * new document: " + file_entry.getDocument());
752 // If we are dealing with the same document don't do anything.
753 if(document != file_entry.getDocument()) {
754 if(document instanceof AppendLineOnlyFileDocument) {
755 AppendLineOnlyFileDocument append_line_only_file_document = (AppendLineOnlyFileDocument) document;
756 if(append_line_only_file_document.isStillWriting()) {
757 ///ystem.err.println("Current log is still active... finishing.");
758 writing_documents.add(append_line_only_file_document); // We have to maintain a reference until they are all done.
759 append_line_only_file_document.setOwner(OptionsPane.this);
760 append_line_only_file_document.setExit();
761 }
762 else {
763 ///ystem.err.println("Current log is complete. Nothing to do.");
764 }
765 }
766 // Load the new log
767 log_textarea.setDocument(file_entry.getDocument());
768 }
769 }
770 }
771 }
772
773 /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
774 private class ToolTipUpdater
775 implements ActionListener {
776 private HashMap arg_list;
777 public ToolTipUpdater(HashMap arg_list) {
778 this.arg_list = arg_list;
779 }
780 /** Any implementation of an ActionListener must include this method so that we can be informed when the selection in a combobox has changed and update the tooltip accordingly.
781 * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
782 */
783 public void actionPerformed(ActionEvent event) {
784 JComboBox source = (JComboBox)event.getSource();
785 String key = (String) source.getSelectedItem();
786 if(arg_list != null) {
787 String description = (String) arg_list.get(key);
788 if(description != null) {
789 description = Utility.formatHTMLWidth(DESCRIPTION_SEP + description, 60);
790 String original = source.getToolTipText();
791 if(original == null) {
792 original = "";
793 }
794 // Remove any existing extra description.
795 if(original.indexOf(DESCRIPTION_SEP) != -1) {
796 original = original.substring(0, original.indexOf(DESCRIPTION_SEP));
797 }
798 source.setToolTipText(original + description);
799 }
800 }
801 }
802 }
803}
Note: See TracBrowser for help on using the repository browser.