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

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

Replaced all Gatherer.print* with DebugStream.print*.

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