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

Last change on this file since 6389 was 6389, checked in by jmt12, 20 years ago

Introduced the idea of detail modes - these have an effect on several parts of the gui, such as disabling or hiding all regular expression based controls, simplifying the output from perl scripts and (having been given yet another new last minute feature to implement) displays a completely different create pane. Mode is stored in the config.xml and is changable via the Preferences controls

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