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

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

Finally committing the (many) changes to the GLI to use the new metadata code... I hope this doesn't have too many bugs in it and committing it now doesn't stuff anyone up! (Katherine said I could commit it, so blame her if anything goes wrong).

  • Property svn:keywords set to Author Date Id Revision
File size: 29.6 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.metadata.MetadataSetManager;
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 = Configuration.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(Configuration.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 = Configuration.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(Configuration.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 DebugStream.println("Exception in OptionsPane.mouseExited() - unexpected");
366 DebugStream.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(Configuration.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 case Argument.METADATUM:
410 JComboBox combobox = new JComboBox();
411 combobox.setEnabled(enable);
412 combobox.setToolTipText(tooltip);
413 combobox.setBackground(enable ? Color.white : Color.lightGray);
414
415 // Build an option model, wrapping each entry of the list table
416 if (argument.getType() == Argument.ENUM) {
417 HashMap arg_list = argument.getOptions();
418 Iterator it = arg_list.keySet().iterator();
419 while (it.hasNext()) {
420 combobox.addItem((String) it.next());
421 }
422
423 // Connect this so if a value is selected the tooltip updates accordingly
424 combobox.addActionListener(new ToolTipUpdater(arg_list));
425 }
426 if (argument.getType() == Argument.METADATUM) {
427 ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
428 for (int i = 0; i < every_metadata_set_element.size(); i++) {
429 combobox.addItem(every_metadata_set_element.get(i));
430 }
431 }
432
433 if (value != null) {
434 // Set the selected string
435 for (int i = 0; i < combobox.getItemCount(); i++) {
436 if (combobox.getItemAt(i).toString().equals(value)) {
437 combobox.setSelectedIndex(i);
438 }
439 }
440 }
441 // Layout
442 add(combobox, BorderLayout.CENTER);
443 // And remember
444 value_control = combobox;
445 break;
446 case Argument.FLAG:
447 // Only need the check box.
448 value_control = null;
449 break;
450 case Argument.INTEGER:
451 // Build a spinner
452 int initial_value=0;
453 if (value != null) {
454 try {
455 initial_value = Integer.parseInt(value);
456 } catch (Exception exception) {
457 }
458 }
459 if (initial_value < argument.getMinimum()) {
460 initial_value = argument.getMinimum();
461 } else if (initial_value > argument.getMaximum()) {
462 initial_value = argument.getMaximum();
463 }
464 JSpinner spinner = new JSpinner(new SpinnerNumberModel(initial_value, argument.getMinimum(), argument.getMaximum(), 1));
465 spinner.setEnabled(enable);
466 spinner.setPreferredSize(SPINNER_SIZE);
467 spinner.setToolTipText(tooltip);
468 // Set enabled
469 JComponent c = spinner.getEditor();
470 if ( c instanceof JSpinner.DefaultEditor ) {
471 JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
472 JFormattedTextField field = editor.getTextField();
473 field.setEditable(enable);
474 if(enable) {
475 field.setBackground(Color.white);
476 }
477 else {
478 field.setBackground(Color.lightGray);
479 }
480 }
481 // Layout
482 add(new JLabel(), BorderLayout.CENTER);
483 add(spinner, BorderLayout.EAST);
484 // And remember it
485 value_control = spinner;
486 break;
487 case Argument.STRING:
488 // Use a standard text field
489 JTextField textfield = new JTextField();
490 textfield.setEnabled(enable);
491 textfield.setToolTipText(tooltip);
492 // Set enabled
493 if(enable) {
494 textfield.setBackground(Color.white);
495 }
496 else {
497 textfield.setBackground(Color.lightGray);
498 }
499 // If there was an original value, set it.
500 if(value != null) {
501 textfield.setText(value);
502 }
503 // Layout
504 add(textfield, BorderLayout.CENTER);
505 // And remember it
506 value_control = textfield;
507 break;
508 }
509
510 // If the argument is required, then you don't get a choice of whether it is enabled.
511 if(argument.isRequired()) {
512 JLabel label = new JLabel(argument.getName());
513 label.setOpaque(false);
514 label.setPreferredSize(LABEL_SIZE);
515 label.setToolTipText(tooltip);
516 add(label, BorderLayout.WEST);
517 }
518 else {
519 enabled = new JCheckBox(argument.getName(), enable);
520 enabled.setOpaque(false);
521 enabled.setPreferredSize(LABEL_SIZE);
522 enabled.setToolTipText(tooltip);
523 // Connect
524 enabled.addActionListener(new EnabledListener(value_control));
525 // Layout
526 add(enabled, BorderLayout.WEST);
527 }
528 }
529
530 /** Retrieve the control used for storing values.
531 * @return JComponent
532 */
533 public JComponent getValueControl() {
534 return value_control;
535 }
536
537 /** Method to ensure that a certain value is selected, if it exists within that combobox to begin with.
538 * @param combobox the JComboBox whose selection we are trying to preset
539 * @param target The desired value of the selection as a String
540 * @return true if the item was found and selected, false otherwise
541 */
542 public boolean selectValue(JComboBox combobox, String target) {
543 for(int i = 0; i < combobox.getItemCount(); i++) {
544 if(combobox.getItemAt(i).toString().equals(target)) {
545 combobox.setSelectedIndex(i);
546 return true;
547 }
548 }
549 return false;
550 }
551
552 /** Update the values stored in the collection so as to rememebr the current state of this argument. */
553 public void update() {
554 String name = argument.getName();
555 boolean enable = true;
556 if(enabled != null) {
557 enable = enabled.isSelected();
558 }
559 String value = null;
560 if(value_control == null) {
561 // Flag value, nothing to do.
562 }
563 else if(value_control instanceof JTextField) {
564 value = ((JTextField)value_control).getText();
565 }
566 else if(value_control instanceof JSpinner) {
567 value = ((JSpinner)value_control).getValue().toString();
568 }
569 else if(value_control instanceof JComboBox) {
570 value = (((JComboBox)value_control).getSelectedItem()).toString();
571 }
572 // If this argument was a flag, but is now disabled, remove from the build options altogether
573 if(!enable && value == null) {
574 if(type == BUILD) {
575 build_options.removeBuildValue(name);
576 }
577 else {
578 build_options.removeImportValue(name);
579 }
580 }
581 // Otherwise update the argument value
582 else {
583 if(type == BUILD) {
584 build_options.setBuildValue(name, enable, value);
585 }
586 else {
587 build_options.setImportValue(name, enable, value);
588 }
589 }
590 }
591 }
592
593 /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
594 private class EnabledListener
595 implements ActionListener {
596 /** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
597 private JComponent target = null;
598 /** Constructor. */
599 public EnabledListener(JComponent target) {
600 this.target = target;
601 }
602 /** 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.
603 * @param event An <strong>ActionEvent</strong> containing information about the click.
604 */
605 public void actionPerformed(ActionEvent event) {
606 JCheckBox source = (JCheckBox)event.getSource();
607 if(target != null) {
608 if(source.isSelected()) {
609 target.setBackground(Color.white);
610 target.setEnabled(true);
611 }
612 else {
613 target.setBackground(Color.lightGray);
614 target.setEnabled(false);
615 }
616 // Special case of stupid JSpinners who don't let their backgrounds change properly.
617 if(target instanceof JSpinner) {
618 JSpinner spinner = (JSpinner) target;
619 JComponent c = spinner.getEditor();
620 if ( c instanceof JSpinner.DefaultEditor ) {
621 JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
622 JFormattedTextField field = editor.getTextField();
623 field.setEditable(source.isSelected());
624 if(source.isSelected()) {
625 field.setBackground(Color.white);
626 }
627 else {
628 field.setBackground(Color.lightGray);
629 }
630 }
631 }
632 }
633 }
634 }
635
636 /** Holds a File which has a particular naming convention build_log.date.txt also keeps a Date corresponding to the date in its name*/
637 private class FileEntry {
638
639 private AppendLineOnlyFileDocument current_document;
640 private Date date;
641 private long last_modified;
642 private String display;
643 private String filename;
644 private String filepath;
645
646 public FileEntry(String filename, String filepath) {
647 this.date = null;
648 this.display = null;
649 this.filename = filename;
650 this.filepath = filepath;
651 this.last_modified = 0L;
652 }
653
654 /** returns 0 if the dates are the same, -ve number if the current FileEntry is earlier than the fe FileEntry ...*/
655 public int compareTo(FileEntry file_entry) {
656 Date our_date = getDate();
657 Date other_date = file_entry.getDate();
658 return our_date.compareTo(other_date);
659 }
660
661 public Date getDate() {
662 if(date == null) {
663 // Need to exclude first '.'
664 int first_index = filename.indexOf(".") + 1;
665 // Need to exclude the last '.'
666 int last_index = filename.lastIndexOf(".");
667 if(first_index > 0 && last_index > 0 && first_index < last_index) {
668 String date_string = filename.substring(first_index, last_index);
669 date = new Date(Long.parseLong(date_string));
670 }
671 else {
672 date = new Date(); // Current date
673 }
674 }
675 return date;
676 }
677
678 public AppendLineOnlyFileDocument getDocument() {
679 if(current_document == null) {
680 current_document = new AppendLineOnlyFileDocument(filepath);
681 }
682 return current_document;
683 }
684
685 public void reset() {
686 display = null;
687 }
688
689 /** we only want the date out of the file name, not the whole path */
690 public String toString() {
691 File file = new File(filename);
692 if(display == null) {
693 last_modified = file.lastModified();
694 StringBuffer d = new StringBuffer();
695 Date date = getDate();
696 d.append(date.toString());
697 char success = UNKNOWN;
698 File the_file = new File(filepath);
699 if(the_file.exists()) {
700 try {
701 FileInputStream in = new FileInputStream(the_file);
702 success = (char) in.read();
703 in.close();
704 in = null;
705 }
706 catch(Exception error) {
707 ///ystem.err.println("Log '" + filepath + "' not found!");
708 ///atherer.printStackTrace(error);
709 }
710 }
711 the_file = null;
712 switch (success) {
713 case SUCCESSFUL:
714 d.append(Dictionary.get("OptionsPane.Successful"));
715 break;
716 case UNSUCCESSFUL:
717 d.append(Dictionary.get("OptionsPane.Unsuccessful"));
718 break;
719 case CANCELLED:
720 d.append(Dictionary.get("OptionsPane.Cancelled"));
721 break;
722 default:
723 d.append(Dictionary.get("OptionsPane.Unknown"));
724 }
725 display = d.toString();
726 }
727 return display;
728 }
729 }
730
731 /** a ListSelectionListener that triggers the load of a newly selected log */
732 private class LogListListener implements ListSelectionListener {
733
734 public void valueChanged(ListSelectionEvent e) {
735 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
736 ///ystem.err.println("Log change detected.");
737 JList source = (JList)e.getSource();
738 file_entry = (FileEntry) source.getSelectedValue();
739 // First we determine if the old log has been completely written to file
740 Document document = log_textarea.getDocument();
741 ///ystem.err.println(" * current document: " + document);
742 ///ystem.err.println(" * new document: " + file_entry.getDocument());
743 // If we are dealing with the same document don't do anything.
744 if(document != file_entry.getDocument()) {
745 if(document instanceof AppendLineOnlyFileDocument) {
746 AppendLineOnlyFileDocument append_line_only_file_document = (AppendLineOnlyFileDocument) document;
747 if(append_line_only_file_document.isStillWriting()) {
748 ///ystem.err.println("Current log is still active... finishing.");
749 writing_documents.add(append_line_only_file_document); // We have to maintain a reference until they are all done.
750 append_line_only_file_document.setOwner(OptionsPane.this);
751 append_line_only_file_document.setExit();
752 }
753 else {
754 ///ystem.err.println("Current log is complete. Nothing to do.");
755 }
756 }
757 // Load the new log
758 log_textarea.setDocument(file_entry.getDocument());
759 }
760 }
761 }
762 }
763
764 /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
765 private class ToolTipUpdater
766 implements ActionListener {
767 private HashMap arg_list;
768 public ToolTipUpdater(HashMap arg_list) {
769 this.arg_list = arg_list;
770 }
771 /** 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.
772 * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
773 */
774 public void actionPerformed(ActionEvent event) {
775 JComboBox source = (JComboBox)event.getSource();
776 String key = (String) source.getSelectedItem();
777 if(arg_list != null) {
778 String description = (String) arg_list.get(key);
779 if(description != null) {
780 description = Utility.formatHTMLWidth(DESCRIPTION_SEP + description, 60);
781 String original = source.getToolTipText();
782 if(original == null) {
783 original = "";
784 }
785 // Remove any existing extra description.
786 if(original.indexOf(DESCRIPTION_SEP) != -1) {
787 original = original.substring(0, original.indexOf(DESCRIPTION_SEP));
788 }
789 source.setToolTipText(original + description);
790 }
791 }
792 }
793 }
794}
Note: See TracBrowser for help on using the repository browser.