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

Last change on this file since 8231 was 8231, checked in by mdewsnip, 20 years ago

Replaced all "Gatherer.config" with "Configuration".

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