1 | package 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 | */
|
---|
38 | import java.awt.*;
|
---|
39 | import java.awt.event.*;
|
---|
40 | import java.io.*;
|
---|
41 | import java.util.*;
|
---|
42 | import javax.swing.*;
|
---|
43 | import javax.swing.event.*;
|
---|
44 | import org.greenstone.gatherer.Gatherer;
|
---|
45 | import org.greenstone.gatherer.cdm.Argument;
|
---|
46 | import org.greenstone.gatherer.checklist.CheckList;
|
---|
47 | import org.greenstone.gatherer.collection.BuildOptions;
|
---|
48 | import org.greenstone.gatherer.collection.Collection;
|
---|
49 | import org.greenstone.gatherer.collection.CollectionManager;
|
---|
50 | import org.greenstone.gatherer.msm.ElementWrapper;
|
---|
51 | import 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 | */
|
---|
57 | final 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 log, BuildOptions build_options) {
|
---|
91 | this.log_display = log;
|
---|
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 | log_pane.add(new JScrollPane(log_display), BorderLayout.CENTER);
|
---|
233 | JLabel log_history_label = new JLabel(get("LogHistory"));
|
---|
234 | JPanel log_history_pane = new JPanel();
|
---|
235 | log_history_pane.setLayout(new BorderLayout());
|
---|
236 | log_history_pane.add(log_history_label, BorderLayout.NORTH);
|
---|
237 | log_history_pane.add(list_scroller, BorderLayout.SOUTH);
|
---|
238 | log_pane.add(log_history_pane, BorderLayout.SOUTH);
|
---|
239 | }
|
---|
240 | return log_pane;
|
---|
241 | }
|
---|
242 |
|
---|
243 | /** This method retrieves a phrase from the dictionary based apon the key.
|
---|
244 | * @param key A <strong>String</strong> used as a reference to the correct phrase.
|
---|
245 | * @return A phrase, matching the key, as a <strong>String</strong>.
|
---|
246 | */
|
---|
247 | private String get(String key) {
|
---|
248 | return get(key, null);
|
---|
249 | }
|
---|
250 | /** This method retrieves a phrase from the dictionary based apon the key and arguments.
|
---|
251 | * @param key A <strong>String</strong> used as a reference to the correct phrase.
|
---|
252 | * @param args A <strong>String[]</strong> whose contents are often substituted into the phrase before it is returned.
|
---|
253 | * @return A phrase, matching the key and constructed using the arguments, as a <strong>String</strong>.
|
---|
254 | * @see org.greenstone.gatherer.Dictionary
|
---|
255 | * @see org.greenstone.gatherer.Gatherer
|
---|
256 | */
|
---|
257 | private String get(String key, String args[]) {
|
---|
258 | if(key.indexOf(".") == -1) {
|
---|
259 | key = "OptionsPane." + key;
|
---|
260 | }
|
---|
261 | return Gatherer.dictionary.get(key, args);
|
---|
262 | }
|
---|
263 | /** Attempts to discover the latest document count.
|
---|
264 | * @return An <strong>int</strong> detailing the number of documents in this collection.
|
---|
265 | */
|
---|
266 | public int getDocumentCount() {
|
---|
267 | if(Gatherer.c_man.ready()) {
|
---|
268 | int count = Gatherer.c_man.getCollection().getDocumentCount();
|
---|
269 | if(count != 0) {
|
---|
270 | return count;
|
---|
271 | }
|
---|
272 | }
|
---|
273 | return 1;
|
---|
274 | }
|
---|
275 |
|
---|
276 | /** Loads a new log into the log text - saves the currently showing one,
|
---|
277 | * and loads the new one, adding a fresh listener to the document
|
---|
278 | * Note, we need to remove any listener before making the changes, then
|
---|
279 | * add a listener back in
|
---|
280 | */
|
---|
281 | public void loadSelectedLog(FileEntry fe) {
|
---|
282 | ///ystem.out.println("load selected log");
|
---|
283 | if (is_log_changed) {
|
---|
284 | saveLogFile(displayed_log.getFile());
|
---|
285 | } else {
|
---|
286 | log_display.getDocument().removeDocumentListener(log_change_listener);
|
---|
287 | }
|
---|
288 |
|
---|
289 | displayed_log = fe;
|
---|
290 | if (fe != null) {
|
---|
291 | log_display.setText(fe.getFileText());
|
---|
292 | } else {
|
---|
293 | log_display.setText("");
|
---|
294 | }
|
---|
295 | is_log_changed=false;
|
---|
296 | log_display.getDocument().addDocumentListener(log_change_listener);
|
---|
297 |
|
---|
298 | }
|
---|
299 |
|
---|
300 | /** Neutralizes the log list - saves any unsaved changes to the current log
|
---|
301 | * clears the log text, unselects the log list, and adds a fresh listener
|
---|
302 | * to the log's document
|
---|
303 | * Note, we need to remove any listener before making the changes, then
|
---|
304 | * add a listener back in */
|
---|
305 | public void resetLogList() {
|
---|
306 | ///ystem.out.println("reset log");
|
---|
307 | if (is_log_changed) {
|
---|
308 | saveLogFile(displayed_log.getFile());
|
---|
309 | } else {
|
---|
310 | log_display.getDocument().removeDocumentListener(log_change_listener);
|
---|
311 | }
|
---|
312 | log_display.setText("");
|
---|
313 | displayed_log = null;
|
---|
314 | if (log_list != null) {
|
---|
315 | log_list.clearSelection();
|
---|
316 | }
|
---|
317 | is_log_changed=false;
|
---|
318 | log_display.getDocument().addDocumentListener(log_change_listener);
|
---|
319 |
|
---|
320 | }
|
---|
321 |
|
---|
322 | /** saves the current text in log to the File specified */
|
---|
323 | public void saveLogFile(File file) {
|
---|
324 |
|
---|
325 | try {
|
---|
326 | BufferedWriter out = new BufferedWriter(new FileWriter(file)); // uses the default encoding
|
---|
327 | String log_text = log_display.getText();
|
---|
328 | // 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.
|
---|
329 | StringTokenizer t = new StringTokenizer(log_text, "\n", true);
|
---|
330 | while (t.hasMoreTokens()) {
|
---|
331 | String token = t.nextToken();
|
---|
332 | if (token.equals("\n")) {
|
---|
333 | out.newLine();
|
---|
334 | } else {
|
---|
335 | out.write(token, 0, token.length());
|
---|
336 | }
|
---|
337 |
|
---|
338 | }
|
---|
339 | out.close();
|
---|
340 |
|
---|
341 | } catch(Exception e) {
|
---|
342 | System.out.println("Error in saving log file: "+file.toString());
|
---|
343 | e.printStackTrace();
|
---|
344 | }
|
---|
345 |
|
---|
346 |
|
---|
347 | }
|
---|
348 |
|
---|
349 |
|
---|
350 | /** Given a panel containing ArgumentControls, update the values associated with them. */
|
---|
351 | public void update(JPanel panel) {
|
---|
352 | if(panel == log_pane) {
|
---|
353 | return;
|
---|
354 | }
|
---|
355 |
|
---|
356 | for(int i = 0; i < panel.getComponentCount(); i++) {
|
---|
357 | Component component = panel.getComponent(i);
|
---|
358 | if(component instanceof ArgumentControl) {
|
---|
359 | ((ArgumentControl)component).update();
|
---|
360 | }
|
---|
361 | }
|
---|
362 | }
|
---|
363 |
|
---|
364 | private class ArgumentControl
|
---|
365 | extends JPanel {
|
---|
366 | private Argument argument;
|
---|
367 | private int type;
|
---|
368 | private JComponent value_control;
|
---|
369 | private JCheckBox enabled;
|
---|
370 | public ArgumentControl(int type, Argument argument, boolean enable, String value) {
|
---|
371 | super();
|
---|
372 | this.argument = argument;
|
---|
373 | this.type = type;
|
---|
374 | String tooltip = Utility.formatHTMLWidth("<html>" + argument.getDescription() + "</html>", 60);
|
---|
375 | // Because of the dynamic order of component creation/connection/layout, we can't really follow that pattern here.
|
---|
376 | setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
|
---|
377 | setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
|
---|
378 | setLayout(new BorderLayout());
|
---|
379 | setPreferredSize(ROW_SIZE);
|
---|
380 |
|
---|
381 | /*
|
---|
382 | JPanel inner_pane = new JPanel();
|
---|
383 | inner_pane.setOpaque(false);
|
---|
384 | */
|
---|
385 |
|
---|
386 | // Try to determine what the value_controls value should be.
|
---|
387 | if(value == null) {
|
---|
388 | value = argument.getDefaultValue();
|
---|
389 | }
|
---|
390 | // Create a correct value control based on the argument provided.
|
---|
391 | switch(argument.getType()) {
|
---|
392 | case Argument.ENUM:
|
---|
393 | JComboBox combobox = new JComboBox();
|
---|
394 | combobox.setEnabled(enable);
|
---|
395 | combobox.setToolTipText(tooltip);
|
---|
396 | // Set enabled
|
---|
397 | if(enable) {
|
---|
398 | combobox.setBackground(Color.white);
|
---|
399 | }
|
---|
400 | else {
|
---|
401 | combobox.setBackground(Color.lightGray);
|
---|
402 | }
|
---|
403 | // Build an option model, wrapping each entry of the list table.
|
---|
404 | HashMap arg_list = argument.getOptions();
|
---|
405 | Iterator it = arg_list.keySet().iterator();
|
---|
406 | while(it.hasNext()) {
|
---|
407 | combobox.addItem((String) it.next());
|
---|
408 | }
|
---|
409 | // Connect this up first, so that if a value is selected the tooltip updates accordingly.
|
---|
410 | combobox.addActionListener(new ToolTipUpdater(arg_list));
|
---|
411 | if(value != null) {
|
---|
412 | // Set the selected string. However since they are all strings we had best iterate ourselves.
|
---|
413 | for(int i = 0; i < combobox.getItemCount(); i++) {
|
---|
414 | if(combobox.getItemAt(i).toString().equals(value)) {
|
---|
415 | combobox.setSelectedIndex(i);
|
---|
416 | }
|
---|
417 | }
|
---|
418 | }
|
---|
419 | // Layout
|
---|
420 | add(combobox, BorderLayout.CENTER);
|
---|
421 | // And remember
|
---|
422 | value_control = combobox;
|
---|
423 | break;
|
---|
424 | case Argument.FLAG:
|
---|
425 | // Only need the check box.
|
---|
426 | value_control = null;
|
---|
427 | break;
|
---|
428 | case Argument.INTEGER:
|
---|
429 | // Build a spinner
|
---|
430 | JSpinner spinner = new JSpinner();
|
---|
431 | spinner.setEnabled(enable);
|
---|
432 | spinner.setPreferredSize(SPINNER_SIZE);
|
---|
433 | spinner.setToolTipText(tooltip);
|
---|
434 | // Set enabled
|
---|
435 | JComponent c = spinner.getEditor();
|
---|
436 | if ( c instanceof JSpinner.DefaultEditor ) {
|
---|
437 | JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
|
---|
438 | JFormattedTextField field = editor.getTextField();
|
---|
439 | field.setEditable(enable);
|
---|
440 | if(enable) {
|
---|
441 | field.setBackground(Color.white);
|
---|
442 | }
|
---|
443 | else {
|
---|
444 | field.setBackground(Color.lightGray);
|
---|
445 | }
|
---|
446 | }
|
---|
447 | // If there was an original value, set it.
|
---|
448 | if(value != null) {
|
---|
449 | try {
|
---|
450 | spinner.setValue(new Integer(value));
|
---|
451 | }
|
---|
452 | catch (Exception error) {
|
---|
453 | }
|
---|
454 | }
|
---|
455 | // Layout
|
---|
456 | add(new JLabel(), BorderLayout.CENTER);
|
---|
457 | add(spinner, BorderLayout.EAST);
|
---|
458 | // And remember it
|
---|
459 | value_control = spinner;
|
---|
460 | break;
|
---|
461 | case Argument.STRING:
|
---|
462 | // Use a standard text field
|
---|
463 | JTextField textfield = new JTextField();
|
---|
464 | textfield.setEnabled(enable);
|
---|
465 | textfield.setToolTipText(tooltip);
|
---|
466 | // Set enabled
|
---|
467 | if(enable) {
|
---|
468 | textfield.setBackground(Color.white);
|
---|
469 | }
|
---|
470 | else {
|
---|
471 | textfield.setBackground(Color.lightGray);
|
---|
472 | }
|
---|
473 | // If there was an original value, set it.
|
---|
474 | if(value != null) {
|
---|
475 | textfield.setText(value);
|
---|
476 | }
|
---|
477 | // Layout
|
---|
478 | add(textfield, BorderLayout.CENTER);
|
---|
479 | // And remember it
|
---|
480 | value_control = textfield;
|
---|
481 | break;
|
---|
482 | }
|
---|
483 |
|
---|
484 | // If the argument is required, then you don't get a choice of whether it is enabled.
|
---|
485 | if(argument.isRequired()) {
|
---|
486 | JLabel label = new JLabel(argument.getName());
|
---|
487 | label.setOpaque(false);
|
---|
488 | label.setPreferredSize(LABEL_SIZE);
|
---|
489 | label.setToolTipText(tooltip);
|
---|
490 | add(label, BorderLayout.WEST);
|
---|
491 | }
|
---|
492 | else {
|
---|
493 | enabled = new JCheckBox(argument.getName(), enable);
|
---|
494 | enabled.setOpaque(false);
|
---|
495 | enabled.setPreferredSize(LABEL_SIZE);
|
---|
496 | enabled.setToolTipText(tooltip);
|
---|
497 | // Connect
|
---|
498 | enabled.addActionListener(new EnabledListener(value_control));
|
---|
499 | // Layout
|
---|
500 | add(enabled, BorderLayout.WEST);
|
---|
501 | }
|
---|
502 | }
|
---|
503 |
|
---|
504 | /** Update the values stored in the collection so as to rememebr the current state of this argument. */
|
---|
505 | public void update() {
|
---|
506 | String name = argument.getName();
|
---|
507 | boolean enable = true;
|
---|
508 | if(enabled != null) {
|
---|
509 | enable = enabled.isSelected();
|
---|
510 | }
|
---|
511 | String value = null;
|
---|
512 | if(value_control == null) {
|
---|
513 | // Flag value, nothing to do.
|
---|
514 | }
|
---|
515 | else if(value_control instanceof JTextField) {
|
---|
516 | value = ((JTextField)value_control).getText();
|
---|
517 | }
|
---|
518 | else if(value_control instanceof JSpinner) {
|
---|
519 | value = ((JSpinner)value_control).getValue().toString();
|
---|
520 | }
|
---|
521 | else if(value_control instanceof JComboBox) {
|
---|
522 | value = (String) ((JComboBox)value_control).getSelectedItem();
|
---|
523 | }
|
---|
524 | // If this argument was a flag, but is now disabled, remove from the build options altogether
|
---|
525 | if(!enable && value == null) {
|
---|
526 | if(type == BUILD) {
|
---|
527 | build_options.removeBuildValue(name);
|
---|
528 | }
|
---|
529 | else {
|
---|
530 | build_options.removeImportValue(name);
|
---|
531 | }
|
---|
532 | }
|
---|
533 | // Otherwise update the argument value
|
---|
534 | else {
|
---|
535 | if(type == BUILD) {
|
---|
536 | build_options.setBuildValue(name, enable, value);
|
---|
537 | }
|
---|
538 | else {
|
---|
539 | build_options.setImportValue(name, enable, value);
|
---|
540 | }
|
---|
541 | }
|
---|
542 | }
|
---|
543 | }
|
---|
544 |
|
---|
545 | /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
|
---|
546 | private class EnabledListener
|
---|
547 | implements ActionListener {
|
---|
548 | /** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
|
---|
549 | private JComponent target = null;
|
---|
550 | /** Constructor. */
|
---|
551 | public EnabledListener(JComponent target) {
|
---|
552 | this.target = target;
|
---|
553 | }
|
---|
554 | /** 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.
|
---|
555 | * @param event An <strong>ActionEvent</strong> containing information about the click.
|
---|
556 | */
|
---|
557 | public void actionPerformed(ActionEvent event) {
|
---|
558 | JCheckBox source = (JCheckBox)event.getSource();
|
---|
559 | if(target != null) {
|
---|
560 | if(source.isSelected()) {
|
---|
561 | target.setBackground(Color.white);
|
---|
562 | target.setEnabled(true);
|
---|
563 | }
|
---|
564 | else {
|
---|
565 | target.setBackground(Color.lightGray);
|
---|
566 | target.setEnabled(false);
|
---|
567 | }
|
---|
568 | // Special case of stupid JSpinners who don't let their backgrounds change properly.
|
---|
569 | if(target instanceof JSpinner) {
|
---|
570 | JSpinner spinner = (JSpinner) target;
|
---|
571 | JComponent c = spinner.getEditor();
|
---|
572 | if ( c instanceof JSpinner.DefaultEditor ) {
|
---|
573 | JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
|
---|
574 | JFormattedTextField field = editor.getTextField();
|
---|
575 | field.setEditable(source.isSelected());
|
---|
576 | if(source.isSelected()) {
|
---|
577 | field.setBackground(Color.white);
|
---|
578 | }
|
---|
579 | else {
|
---|
580 | field.setBackground(Color.lightGray);
|
---|
581 | }
|
---|
582 | }
|
---|
583 | }
|
---|
584 | }
|
---|
585 | }
|
---|
586 | }
|
---|
587 |
|
---|
588 | /** holds a File which has a particular naming convention
|
---|
589 | * build_log.date.txt
|
---|
590 | * also keeps a Date corresponding to the date in its name*/
|
---|
591 | private class FileEntry {
|
---|
592 |
|
---|
593 | private Date date=null;
|
---|
594 | private File file=null;
|
---|
595 | private String display=null;
|
---|
596 | public FileEntry(File f) {
|
---|
597 | this.file=f;
|
---|
598 | this.date = getDateFromFileName();
|
---|
599 | this.display = createDisplayText();
|
---|
600 |
|
---|
601 | }
|
---|
602 |
|
---|
603 | /** returns 0 if the dates are the same, -ve number if the current FileEntry is earlier than the fe FileEntry ...*/
|
---|
604 | public int compareTo(FileEntry fe) {
|
---|
605 | Date d = fe.getDate();
|
---|
606 | return date.compareTo(d);
|
---|
607 | }
|
---|
608 |
|
---|
609 | public Date getDate() {
|
---|
610 | return this.date;
|
---|
611 | }
|
---|
612 | public File getFile() {
|
---|
613 | return this.file;
|
---|
614 | }
|
---|
615 | /** returns the contents of the file */
|
---|
616 | public String getFileText() {
|
---|
617 | if (!this.file.exists()) {
|
---|
618 | return "";
|
---|
619 | }
|
---|
620 | StringBuffer contents = new StringBuffer();
|
---|
621 | try {
|
---|
622 | BufferedReader in = new BufferedReader(new FileReader(this.file));
|
---|
623 | String line;
|
---|
624 |
|
---|
625 | while ((line = in.readLine()) != null) {
|
---|
626 | contents.append(line);
|
---|
627 | contents.append("\n");
|
---|
628 | }
|
---|
629 | } catch (FileNotFoundException fnfe) {
|
---|
630 | Gatherer.println("Error: log file not found: "+ this.file.toString());
|
---|
631 | return "";
|
---|
632 | } catch (IOException ioe) {
|
---|
633 | Gatherer.println("Error: exception occurred when trying to read in file "+this.file.toString()+", "+ioe.getMessage());
|
---|
634 |
|
---|
635 | }
|
---|
636 |
|
---|
637 | return contents.toString();
|
---|
638 | }
|
---|
639 | /** we only want the date out of the file name, not the whole path */
|
---|
640 | public String toString() {
|
---|
641 | return this.display;
|
---|
642 | }
|
---|
643 | /** creates the display text for the list */
|
---|
644 | private String createDisplayText() {
|
---|
645 | StringBuffer d = new StringBuffer();
|
---|
646 | d.append(date.toString());
|
---|
647 | //char success= this.file.getName().charAt(23);
|
---|
648 | String filename = this.file.getName();
|
---|
649 | int index = filename.lastIndexOf(".") - 1;
|
---|
650 | if(index >= 0) {
|
---|
651 | char success = filename.charAt(index);
|
---|
652 | switch (success) {
|
---|
653 | case OptionsPane.SUCCESSFUL:
|
---|
654 | d.append(get("Successful"));
|
---|
655 | break;
|
---|
656 | case OptionsPane.UNSUCCESSFUL:
|
---|
657 | d.append(get("Unsuccessful"));
|
---|
658 | break;
|
---|
659 | case OptionsPane.CANCELLED:
|
---|
660 | d.append(get("Cancelled"));
|
---|
661 | break;
|
---|
662 | }
|
---|
663 | }
|
---|
664 | return d.toString();
|
---|
665 | }
|
---|
666 | /** extracts the date from the file name, which is of the form 'build_log.'<long>[scu]'.txt' */
|
---|
667 | private Date getDateFromFileName() {
|
---|
668 | String name = this.file.getName();
|
---|
669 | // Need to exclude first '.'
|
---|
670 | int first_index = name.indexOf(".") + 1;
|
---|
671 | // Need to exclude state letter before last '.'
|
---|
672 | int last_index = name.lastIndexOf(".") - 1;
|
---|
673 | if(first_index > 0 && last_index > 0 && first_index < last_index) {
|
---|
674 | String date_string = name.substring(first_index, last_index);
|
---|
675 | return new Date(Long.parseLong(date_string));
|
---|
676 | }
|
---|
677 | else {
|
---|
678 | return new Date(); // Current date
|
---|
679 | }
|
---|
680 | }
|
---|
681 |
|
---|
682 |
|
---|
683 | }
|
---|
684 |
|
---|
685 | /** A DocumentListener that listens for changes in the log_display document
|
---|
686 | * if a change is registered, the flag is_log_changed is set to true,
|
---|
687 | * and the listener removes itself from log_display
|
---|
688 | * 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 */
|
---|
689 | private class LogChangeListener implements DocumentListener {
|
---|
690 |
|
---|
691 | public void changedUpdate(DocumentEvent e) {
|
---|
692 | ///ystem.out.println("changed update");
|
---|
693 | registerChange();
|
---|
694 | }
|
---|
695 | public void insertUpdate(DocumentEvent e) {
|
---|
696 | ///ystem.out.println("insert update");
|
---|
697 | registerChange();
|
---|
698 | }
|
---|
699 | public void removeUpdate(DocumentEvent e) {
|
---|
700 | ///ystem.out.println("remove update");
|
---|
701 | registerChange();
|
---|
702 | }
|
---|
703 |
|
---|
704 | private void registerChange() {
|
---|
705 | ///ystem.err.println("a change in the doc occurred, removing the listener");
|
---|
706 | is_log_changed = true;
|
---|
707 | log_display.getDocument().removeDocumentListener(this);
|
---|
708 | }
|
---|
709 | }
|
---|
710 |
|
---|
711 | /** a ListSelectionListener that triggers the load of a newly selected
|
---|
712 | log */
|
---|
713 | private class LogListListener implements ListSelectionListener {
|
---|
714 |
|
---|
715 | public void valueChanged(ListSelectionEvent e) {
|
---|
716 | if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
|
---|
717 | JList source = (JList)e.getSource();
|
---|
718 | FileEntry fe = (FileEntry) source.getSelectedValue();
|
---|
719 | loadSelectedLog(fe);
|
---|
720 | }
|
---|
721 | }
|
---|
722 | }
|
---|
723 |
|
---|
724 | /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
|
---|
725 | private class ToolTipUpdater
|
---|
726 | implements ActionListener {
|
---|
727 | private HashMap arg_list;
|
---|
728 | public ToolTipUpdater(HashMap arg_list) {
|
---|
729 | this.arg_list = arg_list;
|
---|
730 | }
|
---|
731 | /** 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.
|
---|
732 | * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
|
---|
733 | */
|
---|
734 | public void actionPerformed(ActionEvent event) {
|
---|
735 | JComboBox source = (JComboBox)event.getSource();
|
---|
736 | String key = (String) source.getSelectedItem();
|
---|
737 | if(arg_list != null) {
|
---|
738 | String description = (String) arg_list.get(key);
|
---|
739 | if(description != null) {
|
---|
740 | description = Utility.formatHTMLWidth(DESCRIPTION_SEP + description, 60);
|
---|
741 | String original = source.getToolTipText();
|
---|
742 | if(original == null) {
|
---|
743 | original = "";
|
---|
744 | }
|
---|
745 | // Remove any existing extra description.
|
---|
746 | if(original.indexOf(DESCRIPTION_SEP) != -1) {
|
---|
747 | original = original.substring(0, original.indexOf(DESCRIPTION_SEP));
|
---|
748 | }
|
---|
749 | source.setToolTipText(original + description);
|
---|
750 | }
|
---|
751 | }
|
---|
752 | }
|
---|
753 | }
|
---|
754 | }
|
---|