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

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

Changed JComboBoxes for GComboBoxes to avoid Mac graphical glitch - however now I can't seem to make them the right colour

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