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

Last change on this file since 5033 was 5033, checked in by jmt12, 21 years ago

Halved log textarea memory use by sharing Document model between both the process and the history text areas. Its not enough though.

  • Property svn:keywords set to Author Date Id Revision
File size: 26.9 KB
Line 
1package org.greenstone.gatherer.gui;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import java.awt.*;
39import java.awt.event.*;
40import java.io.*;
41import java.util.*;
42import javax.swing.*;
43import javax.swing.event.*;
44import org.greenstone.gatherer.Gatherer;
45import org.greenstone.gatherer.cdm.Argument;
46import org.greenstone.gatherer.checklist.CheckList;
47import org.greenstone.gatherer.collection.BuildOptions;
48import org.greenstone.gatherer.collection.Collection;
49import org.greenstone.gatherer.collection.CollectionManager;
50import org.greenstone.gatherer.msm.ElementWrapper;
51import org.greenstone.gatherer.util.Utility;
52//import org.w3c.dom.*;
53/** 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>.
54 * @author John Thompson, Greenstone Digital Library, University of Waikato
55 * @version 2.2
56 */
57final public class OptionsPane
58 extends JPanel {
59 /** 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>). */
60 private BuildOptions build_options = null;
61 /** the log pane - we only create it once now, not each time */
62 private JPanel log_pane = null;
63 /** the list of previous log messages */
64 private JList log_list = null;
65 /** whether that currently showing log is changed or not */
66 private boolean is_log_changed = false;
67 /** the list entry that is currently displayed */
68 private FileEntry displayed_log = null;
69 /** a listener for changes in the log text */
70 private LogChangeListener log_change_listener = null;
71 /** All process messages are written to this log text area. */
72 private JTextArea log_display = null;
73
74 static final public char SUCCESSFUL = 's';
75 static final public char UNSUCCESSFUL = 'u';
76 static final public char CANCELLED = 'c';
77
78 static private int BUILD = 0;
79 static private int IMPORT = 1;
80 static private Dimension LABEL_SIZE = new Dimension(180, 25);
81 static private Dimension LOG_SIZE = new Dimension(610, 360);
82 /** The minimum size of a options pane, to prevent refresh problems around the bottom of shorter panes. */
83 static private Dimension PANE_SIZE = new Dimension(610, 350);
84 static private Dimension ROW_SIZE = new Dimension(610, 25);
85 static private Dimension SPINNER_SIZE = new Dimension(100, 25);
86 static private String DESCRIPTION_SEP = " + ";
87
88
89 /** 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. */
90 public OptionsPane(JTextArea message_log, BuildOptions build_options) {
91 this.log_display = new JTextArea(message_log.getDocument());
92 this.build_options = build_options;
93 this.log_change_listener = new LogChangeListener();
94 //this.target_pane = target_pane;
95 }
96
97 /** creates a new log from the text in log. The new file is named
98 * build_log.<current time>.txt. A new FileEntry is added to teh log list
99 * and made selected. A fresh listener is added to teh document */
100 public void addNewLog(char success) {
101 ///ystem.out.println("add new log");
102
103 // create the file name
104 long time = System.currentTimeMillis();
105 StringBuffer name = new StringBuffer();
106 name.append("build_log.");
107 name.append(time);
108 name.append(success);
109 name.append(".txt");
110 File f = new File(Gatherer.c_man.getCollectionLog()+name.toString());
111 // just in case there is no log directory
112 File parent_file = f.getParentFile();
113 parent_file.mkdirs();
114
115 // save the log text to the file
116 saveLogFile(f);
117 is_log_changed=false;
118 log_display.getDocument().addDocumentListener(log_change_listener);
119
120 // create the file entry and add it to the list at pos 0 - it will always be the newest one created
121 FileEntry fe = new FileEntry(f);
122 ((DefaultListModel)log_list.getModel()).add(0, fe);
123 log_list.setSelectedIndex(0);
124 displayed_log = fe;
125
126 }
127
128 /** This method creates the panel with all the build only options on it.
129 * @return A <strong>JPanel</strong> which can be used to display all the build only options.
130 */
131 public JPanel buildBuild() {
132 JPanel pane = new JPanel();
133 pane.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
134 pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
135 int build_argument_count = build_options.getBuildArgumentCount();
136 pane.setLayout(new GridLayout(build_argument_count, 1, 0, 0));
137 int total_height = PANE_SIZE.height;
138 for(int i = 0; i < build_argument_count; i++) {
139 // Retrieve the argument so we know how to format the control.
140 Argument argument = build_options.getBuildArgument(i);
141 // Now attempt to retrieve any existing value for this argument.
142 boolean enabled = build_options.getBuildValueEnabled(argument.getName());
143 String value = build_options.getBuildValue(argument.getName());
144 ArgumentControl argument_control = new ArgumentControl(BUILD, argument, enabled, value);
145 total_height = total_height - argument_control.getPreferredSize().height;
146 pane.add(argument_control);
147 }
148 if(total_height > 0) {
149 JPanel filler = new JPanel();
150 filler.setPreferredSize(new Dimension(100, total_height));
151 filler.setSize(filler.getPreferredSize());
152 pane.add(filler);
153 }
154 return pane;
155 }
156 /** This method creates the panel with all the import only options on it.
157 * @return A <strong>JPanel</strong> which can be used to display all the import only options.
158 */
159 public JPanel buildImport() {
160 JPanel pane = new JPanel();
161 pane.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
162 pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
163 int import_argument_count = build_options.getImportArgumentCount();
164 pane.setLayout(new GridLayout(import_argument_count, 1, 0, 0));
165 int total_height = PANE_SIZE.height;
166 for(int i = 0; i < import_argument_count; i++) {
167 // Retrieve the argument so we know how to format the control.
168 Argument argument = build_options.getImportArgument(i);
169 // Now attempt to retrieve any existing value for this argument.
170 boolean enabled = build_options.getImportValueEnabled(argument.getName());
171 String value = build_options.getImportValue(argument.getName());
172 ArgumentControl argument_control = new ArgumentControl(IMPORT, argument, enabled, value);
173 total_height = total_height - argument_control.getPreferredSize().height;
174 pane.add(argument_control);
175 }
176 if(total_height > 0) {
177 JPanel filler = new JPanel();
178 filler.setPreferredSize(new Dimension(100, total_height));
179 filler.setSize(filler.getPreferredSize());
180 pane.add(filler);
181 }
182 return pane;
183 }
184 /** This method is used to build a panel based on the message log, which is nothing like any of the other panels.
185 * @return A <strong>JPanel</strong> containing a scrollable text area which represents the shell process message log.
186 */
187 public JPanel buildLog() {
188 // we now save the log pane
189 if (log_pane == null) {
190 log_pane = new JPanel(new BorderLayout());
191
192 // Build a list of the log files available, ordering by last modified. Log files are like build_log.date.txt
193 DefaultListModel contents = new DefaultListModel();
194 File log_directory = new File(Gatherer.c_man.getCollectionLog());
195 File children[] = log_directory.listFiles();
196 for(int i = 0; children != null && i < children.length; i++) {
197 if(children[i].getName().startsWith("build_log")&&children[i].getName().endsWith(".txt") ) {
198 FileEntry entry = new FileEntry(children[i]);
199 // We are about to insert it. But where.
200 boolean found = false;
201 for(int j = 0; j < contents.size(); j++) {
202 FileEntry sibling = (FileEntry) contents.getElementAt(j);
203 int order = entry.compareTo(sibling);
204 if(order > 0) {
205 contents.insertElementAt(entry, j);
206 found = true;
207 break;
208 }
209 }
210 if(!found) {
211 contents.addElement(entry);
212 }
213 }
214 }
215
216 log_list = new JList(contents);
217 log_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
218 log_list.setLayoutOrientation(JList.VERTICAL);
219 log_list.setVisibleRowCount(3);
220 log_list.addListSelectionListener(new LogListListener());
221
222 JScrollPane list_scroller = new JScrollPane(log_list);
223
224 // If log is not empty and we have something in displayed_log - make that element selected
225 if (log_display.getText().length()>0 && displayed_log != null) {
226 int index = contents.indexOf(displayed_log);
227 if (index != -1) {
228 log_list.setSelectedIndex(index);
229 }
230
231 }
232
233 log_pane.add(new JScrollPane(log_display), BorderLayout.CENTER);
234 JLabel log_history_label = new JLabel(get("LogHistory"));
235 JPanel log_history_pane = new JPanel();
236
237 log_history_pane.setLayout(new BorderLayout());
238 log_history_pane.add(log_history_label, BorderLayout.NORTH);
239 log_history_pane.add(list_scroller, BorderLayout.SOUTH);
240
241 log_pane.add(log_history_pane, BorderLayout.SOUTH);
242 }
243 return log_pane;
244 }
245
246 /** This method retrieves a phrase from the dictionary based apon the key.
247 * @param key A <strong>String</strong> used as a reference to the correct phrase.
248 * @return A phrase, matching the key, as a <strong>String</strong>.
249 */
250 private String get(String key) {
251 return get(key, null);
252 }
253 /** This method retrieves a phrase from the dictionary based apon the key and arguments.
254 * @param key A <strong>String</strong> used as a reference to the correct phrase.
255 * @param args A <strong>String[]</strong> whose contents are often substituted into the phrase before it is returned.
256 * @return A phrase, matching the key and constructed using the arguments, as a <strong>String</strong>.
257 * @see org.greenstone.gatherer.Dictionary
258 * @see org.greenstone.gatherer.Gatherer
259 */
260 private String get(String key, String args[]) {
261 if(key.indexOf(".") == -1) {
262 key = "OptionsPane." + key;
263 }
264 return Gatherer.dictionary.get(key, args);
265 }
266 /** Attempts to discover the latest document count.
267 * @return An <strong>int</strong> detailing the number of documents in this collection.
268 */
269 public int getDocumentCount() {
270 if(Gatherer.c_man.ready()) {
271 int count = Gatherer.c_man.getCollection().getDocumentCount();
272 if(count != 0) {
273 return count;
274 }
275 }
276 return 1;
277 }
278
279 /** Loads a new log into the log text - saves the currently showing one,
280 * and loads the new one, adding a fresh listener to the document
281 * Note, we need to remove any listener before making the changes, then
282 * add a listener back in
283 */
284 public void loadSelectedLog(FileEntry fe) {
285 ///ystem.out.println("load selected log");
286 if(displayed_log != null) {
287 if (is_log_changed) {
288 saveLogFile(displayed_log.getFile());
289 } else {
290 log_display.getDocument().removeDocumentListener(log_change_listener);
291 }
292 }
293
294 displayed_log = fe;
295 if (fe != null) {
296 log_display.setText(fe.getFileText());
297 } else {
298 log_display.setText("");
299 }
300 is_log_changed=false;
301 log_display.getDocument().addDocumentListener(log_change_listener);
302
303 }
304
305 /** Neutralizes the log list - saves any unsaved changes to the current log
306 * clears the log text, unselects the log list, and adds a fresh listener
307 * to the log's document
308 * Note, we need to remove any listener before making the changes, then
309 * add a listener back in */
310 public void resetLogList() {
311 ///ystem.out.println("reset log");
312 if (is_log_changed) {
313 saveLogFile(displayed_log.getFile());
314 } else {
315 log_display.getDocument().removeDocumentListener(log_change_listener);
316 }
317 log_display.setText("");
318 displayed_log = null;
319 if (log_list != null) {
320 log_list.clearSelection();
321 }
322 is_log_changed=false;
323 log_display.getDocument().addDocumentListener(log_change_listener);
324
325 }
326
327 /** saves the current text in log to the File specified */
328 public void saveLogFile(File file) {
329
330 try {
331 BufferedWriter out = new BufferedWriter(new FileWriter(file)); // uses the default encoding
332 String log_text = log_display.getText();
333 // set teh return delims to true, then swap them for newLine() (platform dependent) - having return delims set to false seemed to not get empty strings so that empty lines were not preserved.
334 StringTokenizer t = new StringTokenizer(log_text, "\n", true);
335 while (t.hasMoreTokens()) {
336 String token = t.nextToken();
337 if (token.equals("\n")) {
338 out.newLine();
339 } else {
340 out.write(token, 0, token.length());
341 }
342
343 }
344 out.close();
345
346 } catch(Exception e) {
347 System.out.println("Error in saving log file: "+file.toString());
348 e.printStackTrace();
349 }
350
351
352 }
353
354
355 /** Given a panel containing ArgumentControls, update the values associated with them. */
356 public void update(JPanel panel) {
357 if(panel == log_pane) {
358 return;
359 }
360
361 for(int i = 0; i < panel.getComponentCount(); i++) {
362 Component component = panel.getComponent(i);
363 if(component instanceof ArgumentControl) {
364 ((ArgumentControl)component).update();
365 }
366 }
367 }
368
369 private class ArgumentControl
370 extends JPanel {
371 private Argument argument;
372 private int type;
373 private JComponent value_control;
374 private JCheckBox enabled;
375 public ArgumentControl(int type, Argument argument, boolean enable, String value) {
376 super();
377 this.argument = argument;
378 this.type = type;
379 String tooltip = Utility.formatHTMLWidth("<html>" + argument.getDescription() + "</html>", 60);
380 // Because of the dynamic order of component creation/connection/layout, we can't really follow that pattern here.
381 setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
382 setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
383 setLayout(new BorderLayout());
384 setPreferredSize(ROW_SIZE);
385
386 /*
387 JPanel inner_pane = new JPanel();
388 inner_pane.setOpaque(false);
389 */
390
391 // Try to determine what the value_controls value should be.
392 if(value == null) {
393 value = argument.getDefaultValue();
394 }
395 // Create a correct value control based on the argument provided.
396 switch(argument.getType()) {
397 case Argument.ENUM:
398 JComboBox combobox = new JComboBox();
399 combobox.setEnabled(enable);
400 combobox.setToolTipText(tooltip);
401 // Set enabled
402 if(enable) {
403 combobox.setBackground(Color.white);
404 }
405 else {
406 combobox.setBackground(Color.lightGray);
407 }
408 // Build an option model, wrapping each entry of the list table.
409 HashMap arg_list = argument.getOptions();
410 Iterator it = arg_list.keySet().iterator();
411 while(it.hasNext()) {
412 combobox.addItem((String) it.next());
413 }
414 // Connect this up first, so that if a value is selected the tooltip updates accordingly.
415 combobox.addActionListener(new ToolTipUpdater(arg_list));
416 if(value != null) {
417 // Set the selected string. However since they are all strings we had best iterate ourselves.
418 for(int i = 0; i < combobox.getItemCount(); i++) {
419 if(combobox.getItemAt(i).toString().equals(value)) {
420 combobox.setSelectedIndex(i);
421 }
422 }
423 }
424 // Layout
425 add(combobox, BorderLayout.CENTER);
426 // And remember
427 value_control = combobox;
428 break;
429 case Argument.FLAG:
430 // Only need the check box.
431 value_control = null;
432 break;
433 case Argument.INTEGER:
434 // Build a spinner
435 JSpinner spinner = new JSpinner();
436 spinner.setEnabled(enable);
437 spinner.setPreferredSize(SPINNER_SIZE);
438 spinner.setToolTipText(tooltip);
439 // Set enabled
440 JComponent c = spinner.getEditor();
441 if ( c instanceof JSpinner.DefaultEditor ) {
442 JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
443 JFormattedTextField field = editor.getTextField();
444 field.setEditable(enable);
445 if(enable) {
446 field.setBackground(Color.white);
447 }
448 else {
449 field.setBackground(Color.lightGray);
450 }
451 }
452 // If there was an original value, set it.
453 if(value != null) {
454 try {
455 spinner.setValue(new Integer(value));
456 }
457 catch (Exception error) {
458 }
459 }
460 // Layout
461 add(new JLabel(), BorderLayout.CENTER);
462 add(spinner, BorderLayout.EAST);
463 // And remember it
464 value_control = spinner;
465 break;
466 case Argument.STRING:
467 // Use a standard text field
468 JTextField textfield = new JTextField();
469 textfield.setEnabled(enable);
470 textfield.setToolTipText(tooltip);
471 // Set enabled
472 if(enable) {
473 textfield.setBackground(Color.white);
474 }
475 else {
476 textfield.setBackground(Color.lightGray);
477 }
478 // If there was an original value, set it.
479 if(value != null) {
480 textfield.setText(value);
481 }
482 // Layout
483 add(textfield, BorderLayout.CENTER);
484 // And remember it
485 value_control = textfield;
486 break;
487 }
488
489 // If the argument is required, then you don't get a choice of whether it is enabled.
490 if(argument.isRequired()) {
491 JLabel label = new JLabel(argument.getName());
492 label.setOpaque(false);
493 label.setPreferredSize(LABEL_SIZE);
494 label.setToolTipText(tooltip);
495 add(label, BorderLayout.WEST);
496 }
497 else {
498 enabled = new JCheckBox(argument.getName(), enable);
499 enabled.setOpaque(false);
500 enabled.setPreferredSize(LABEL_SIZE);
501 enabled.setToolTipText(tooltip);
502 // Connect
503 enabled.addActionListener(new EnabledListener(value_control));
504 // Layout
505 add(enabled, BorderLayout.WEST);
506 }
507 }
508
509 /** Update the values stored in the collection so as to rememebr the current state of this argument. */
510 public void update() {
511 String name = argument.getName();
512 boolean enable = true;
513 if(enabled != null) {
514 enable = enabled.isSelected();
515 }
516 String value = null;
517 if(value_control == null) {
518 // Flag value, nothing to do.
519 }
520 else if(value_control instanceof JTextField) {
521 value = ((JTextField)value_control).getText();
522 }
523 else if(value_control instanceof JSpinner) {
524 value = ((JSpinner)value_control).getValue().toString();
525 }
526 else if(value_control instanceof JComboBox) {
527 value = (String) ((JComboBox)value_control).getSelectedItem();
528 }
529 // If this argument was a flag, but is now disabled, remove from the build options altogether
530 if(!enable && value == null) {
531 if(type == BUILD) {
532 build_options.removeBuildValue(name);
533 }
534 else {
535 build_options.removeImportValue(name);
536 }
537 }
538 // Otherwise update the argument value
539 else {
540 if(type == BUILD) {
541 build_options.setBuildValue(name, enable, value);
542 }
543 else {
544 build_options.setImportValue(name, enable, value);
545 }
546 }
547 }
548 }
549
550 /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
551 private class EnabledListener
552 implements ActionListener {
553 /** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
554 private JComponent target = null;
555 /** Constructor. */
556 public EnabledListener(JComponent target) {
557 this.target = target;
558 }
559 /** 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.
560 * @param event An <strong>ActionEvent</strong> containing information about the click.
561 */
562 public void actionPerformed(ActionEvent event) {
563 JCheckBox source = (JCheckBox)event.getSource();
564 if(target != null) {
565 if(source.isSelected()) {
566 target.setBackground(Color.white);
567 target.setEnabled(true);
568 }
569 else {
570 target.setBackground(Color.lightGray);
571 target.setEnabled(false);
572 }
573 // Special case of stupid JSpinners who don't let their backgrounds change properly.
574 if(target instanceof JSpinner) {
575 JSpinner spinner = (JSpinner) target;
576 JComponent c = spinner.getEditor();
577 if ( c instanceof JSpinner.DefaultEditor ) {
578 JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
579 JFormattedTextField field = editor.getTextField();
580 field.setEditable(source.isSelected());
581 if(source.isSelected()) {
582 field.setBackground(Color.white);
583 }
584 else {
585 field.setBackground(Color.lightGray);
586 }
587 }
588 }
589 }
590 }
591 }
592
593 /** holds a File which has a particular naming convention
594 * build_log.date.txt
595 * also keeps a Date corresponding to the date in its name*/
596 private class FileEntry {
597
598 private Date date=null;
599 private File file=null;
600 private String display=null;
601 public FileEntry(File f) {
602 this.file=f;
603 this.date = getDateFromFileName();
604 this.display = createDisplayText();
605
606 }
607
608 /** returns 0 if the dates are the same, -ve number if the current FileEntry is earlier than the fe FileEntry ...*/
609 public int compareTo(FileEntry fe) {
610 Date d = fe.getDate();
611 return date.compareTo(d);
612 }
613
614 public Date getDate() {
615 return this.date;
616 }
617 public File getFile() {
618 return this.file;
619 }
620 /** returns the contents of the file */
621 public String getFileText() {
622 if (!this.file.exists()) {
623 return "";
624 }
625 StringBuffer contents = new StringBuffer();
626 try {
627 BufferedReader in = new BufferedReader(new FileReader(this.file));
628 String line;
629
630 while ((line = in.readLine()) != null) {
631 contents.append(line);
632 contents.append("\n");
633 }
634 } catch (FileNotFoundException fnfe) {
635 Gatherer.println("Error: log file not found: "+ this.file.toString());
636 return "";
637 } catch (IOException ioe) {
638 Gatherer.println("Error: exception occurred when trying to read in file "+this.file.toString()+", "+ioe.getMessage());
639
640 }
641
642 return contents.toString();
643 }
644 /** we only want the date out of the file name, not the whole path */
645 public String toString() {
646 return this.display;
647 }
648 /** creates the display text for the list */
649 private String createDisplayText() {
650 StringBuffer d = new StringBuffer();
651 d.append(date.toString());
652 //char success= this.file.getName().charAt(23);
653 String filename = this.file.getName();
654 int index = filename.lastIndexOf(".") - 1;
655 if(index >= 0) {
656 char success = filename.charAt(index);
657 switch (success) {
658 case OptionsPane.SUCCESSFUL:
659 d.append(get("Successful"));
660 break;
661 case OptionsPane.UNSUCCESSFUL:
662 d.append(get("Unsuccessful"));
663 break;
664 case OptionsPane.CANCELLED:
665 d.append(get("Cancelled"));
666 break;
667 }
668 }
669 return d.toString();
670 }
671 /** extracts the date from the file name, which is of the form 'build_log.'<long>[scu]'.txt' */
672 private Date getDateFromFileName() {
673 String name = this.file.getName();
674 // Need to exclude first '.'
675 int first_index = name.indexOf(".") + 1;
676 // Need to exclude state letter before last '.'
677 int last_index = name.lastIndexOf(".") - 1;
678 if(first_index > 0 && last_index > 0 && first_index < last_index) {
679 String date_string = name.substring(first_index, last_index);
680 return new Date(Long.parseLong(date_string));
681 }
682 else {
683 return new Date(); // Current date
684 }
685 }
686
687
688 }
689
690 /** A DocumentListener that listens for changes in the log_display document
691 * if a change is registered, the flag is_log_changed is set to true,
692 * and the listener removes itself from log_display
693 * Because we only want to register user's changes, the listener must be removed before the system makes any changes, and then put back. For example, each time we switchlogs to display, a remove event and an insert event are sent. We dont want to register these as changes to the document, so the listener must be removed before the switch, and added back afterwards */
694 private class LogChangeListener implements DocumentListener {
695
696 public void changedUpdate(DocumentEvent e) {
697 ///ystem.out.println("changed update");
698 registerChange();
699 }
700 public void insertUpdate(DocumentEvent e) {
701 ///ystem.out.println("insert update");
702 registerChange();
703 }
704 public void removeUpdate(DocumentEvent e) {
705 ///ystem.out.println("remove update");
706 registerChange();
707 }
708
709 private void registerChange() {
710 ///ystem.err.println("a change in the doc occurred, removing the listener");
711 is_log_changed = true;
712 log_display.getDocument().removeDocumentListener(this);
713 }
714 }
715
716 /** a ListSelectionListener that triggers the load of a newly selected
717 log */
718 private class LogListListener implements ListSelectionListener {
719
720 public void valueChanged(ListSelectionEvent e) {
721 if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
722 JList source = (JList)e.getSource();
723 FileEntry fe = (FileEntry) source.getSelectedValue();
724 loadSelectedLog(fe);
725 }
726 }
727 }
728
729 /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
730 private class ToolTipUpdater
731 implements ActionListener {
732 private HashMap arg_list;
733 public ToolTipUpdater(HashMap arg_list) {
734 this.arg_list = arg_list;
735 }
736 /** 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.
737 * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
738 */
739 public void actionPerformed(ActionEvent event) {
740 JComboBox source = (JComboBox)event.getSource();
741 String key = (String) source.getSelectedItem();
742 if(arg_list != null) {
743 String description = (String) arg_list.get(key);
744 if(description != null) {
745 description = Utility.formatHTMLWidth(DESCRIPTION_SEP + description, 60);
746 String original = source.getToolTipText();
747 if(original == null) {
748 original = "";
749 }
750 // Remove any existing extra description.
751 if(original.indexOf(DESCRIPTION_SEP) != -1) {
752 original = original.substring(0, original.indexOf(DESCRIPTION_SEP));
753 }
754 source.setToolTipText(original + description);
755 }
756 }
757 }
758 }
759}
Note: See TracBrowser for help on using the repository browser.