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