Xcos solvers : Sundials explicit Runge-Kutta 4(5) implem and interface
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / actions / dialog / SetupDialog.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - DIGITEO - Clement DAVID
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.actions.dialog;
14
15 import java.awt.Component;
16 import java.awt.GridBagConstraints;
17 import java.awt.GridBagLayout;
18 import java.awt.Image;
19 import java.awt.Insets;
20 import java.awt.event.ActionEvent;
21 import java.awt.event.ActionListener;
22 import java.beans.PropertyVetoException;
23 import java.math.BigDecimal;
24 import java.text.DecimalFormat;
25 import java.text.DecimalFormatSymbols;
26 import java.util.logging.Logger;
27
28 import javax.swing.DefaultListCellRenderer;
29 import javax.swing.ImageIcon;
30 import javax.swing.InputVerifier;
31 import javax.swing.JButton;
32 import javax.swing.JComboBox;
33 import javax.swing.JComponent;
34 import javax.swing.JDialog;
35 import javax.swing.JFormattedTextField;
36 import javax.swing.JLabel;
37 import javax.swing.JList;
38 import javax.swing.JSpinner;
39 import javax.swing.SpinnerNumberModel;
40
41 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
42 import org.scilab.modules.xcos.actions.SetupAction;
43 import org.scilab.modules.xcos.graph.ScicosParameters;
44 import org.scilab.modules.xcos.graph.XcosDiagram;
45 import org.scilab.modules.xcos.utils.XcosMessages;
46
47 /**
48  * Dialog associated with the {@link SetupAction}.
49  *
50  * Note that this dialog break the Data Abstraction Coupling metric because of
51  * the numbers of graphical components involved in the GUI creation. For the
52  * same reason (GUI class), constants are not used on this code.
53  */
54 // CSOFF: ClassDataAbstractionCoupling
55 // CSOFF: ClassFanOutComplexity
56 // CSOFF: MagicNumber
57 @SuppressWarnings(value = { "serial" })
58 public class SetupDialog extends JDialog {
59     private static final DecimalFormatSymbols FORMAT_SYMBOL = DecimalFormatSymbols.getInstance();
60     private static final DecimalFormat CURRENT_FORMAT = new DecimalFormat("0.0####E00", FORMAT_SYMBOL);
61     private static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE);
62
63     /**
64      * Validate the user entry and format it.
65      *
66      * Without formatting the entry, bug #7143 appears on jdk6.
67      */
68     private static final InputVerifier VALIDATE_POSITIVE_DOUBLE = new InputVerifier() {
69
70         @Override
71         public boolean verify(javax.swing.JComponent arg0) {
72             boolean ret = false;
73             JFormattedTextField textField = (JFormattedTextField) arg0;
74             try {
75                 BigDecimal value = new BigDecimal(textField.getText());
76                 if (value.compareTo(BigDecimal.ZERO) >= 0 && value.compareTo(MAX_DOUBLE) <= 0) {
77                     ret = true;
78                 }
79
80                 // bug #7143 workaround
81                 textField.setValue(value);
82             } catch (NumberFormatException e) {
83                 return ret;
84             }
85             return ret;
86
87         };
88     };
89
90     /**
91      * Initialize static final fields
92      */
93     static {
94         FORMAT_SYMBOL.setDecimalSeparator('.');
95         CURRENT_FORMAT.setDecimalFormatSymbols(FORMAT_SYMBOL);
96         CURRENT_FORMAT.setParseIntegerOnly(false);
97         CURRENT_FORMAT.setParseBigDecimal(true);
98     }
99
100     private final ScicosParameters parameters;
101     private final XcosDiagram rootGraph;
102
103     private JFormattedTextField integration;
104     private JFormattedTextField rts;
105     private JFormattedTextField integrator;
106     private JFormattedTextField integratorRel;
107     private JFormattedTextField toleranceOnTime;
108     private JFormattedTextField maxIntegrationTime;
109     private JComboBox solver;
110     private JFormattedTextField maxStepSize;
111
112     /**
113      * Instanciate a new dialog.
114      *
115      * @param parent
116      *            the current selected graph component
117      * @param parameters
118      *            the current parameters
119      */
120     public SetupDialog(Component parent, XcosDiagram graph, ScicosParameters parameters) {
121         super();
122
123         this.parameters = parameters;
124
125         ImageIcon scilabIcon = new ImageIcon(ScilabSwingUtilities.findIcon("scilab"));
126         Image imageForIcon = scilabIcon.getImage();
127         setLayout(new GridBagLayout());
128         setIconImage(imageForIcon);
129         setTitle(XcosMessages.SETUP_TITLE);
130         setModal(false);
131         setLocationRelativeTo(parent);
132         rootGraph = graph;
133         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
134         ScilabSwingUtilities.closeOnEscape(this);
135
136         initComponents();
137     }
138
139     /**
140      * Initialize the dialog components.
141      *
142      * As this method perform a complex initialization, It doesn't pass NCSS.
143      */
144     // CSOFF: JavaNCSS
145     private void initComponents() {
146         JLabel integrationLabel = new JLabel(XcosMessages.FINAL_INTEGRATION_TIME);
147         integration = new JFormattedTextField(CURRENT_FORMAT);
148         integration.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
149         integration.setValue(new BigDecimal(parameters.getFinalIntegrationTime()));
150
151         JLabel rtsLabel = new JLabel(XcosMessages.REAL_TIME_SCALING);
152         rts = new JFormattedTextField(CURRENT_FORMAT);
153         rts.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
154         rts.setValue(new BigDecimal(parameters.getRealTimeScaling()));
155
156         JLabel integratorAbsLabel = new JLabel(XcosMessages.INTEGRATOR_ABSOLUTE_TOLERANCE);
157         integrator = new JFormattedTextField(CURRENT_FORMAT);
158         integrator.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
159         integrator.setValue(new BigDecimal(parameters.getIntegratorAbsoluteTolerance()));
160
161         JLabel integratorRelLabel = new JLabel(XcosMessages.INTEGRATOR_RELATIVE_TOLERANCE);
162         integratorRel = new JFormattedTextField(CURRENT_FORMAT);
163         integratorRel.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
164         integratorRel.setValue(new BigDecimal(parameters.getIntegratorRelativeTolerance()));
165
166         JLabel toleranceOnTimeLabel = new JLabel(XcosMessages.TOLERANCE_ON_TIME);
167         toleranceOnTime = new JFormattedTextField(CURRENT_FORMAT);
168         toleranceOnTime.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
169         toleranceOnTime.setValue(new BigDecimal(parameters.getToleranceOnTime()));
170
171         JLabel maxIntegrationTimeLabel = new JLabel(XcosMessages.MAX_INTEGRATION_TIME_INTERVAL);
172         maxIntegrationTime = new JFormattedTextField(CURRENT_FORMAT);
173         maxIntegrationTime.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
174         maxIntegrationTime.setValue(new BigDecimal(parameters.getMaxIntegrationTimeInterval()));
175
176         JLabel solverLabel = new JLabel(XcosMessages.SOLVER_CHOICE);
177         final String[] solvers = new String[] { "LSodar", "Sundials/CVODE - BDF - NEWTON", "Sundials/CVODE - BDF - FUNCTIONAL",
178                                                 "Sundials/CVODE - ADAMS - NEWTON", "Sundials/CVODE - ADAMS - FUNCTIONAL", "DOPRI5 - Dormand-Prince 4(5)", "RK45 - Runge-Kutta 4(5)", "Sundials/IDA"
179                                               };
180         final String[] solversTooltips = new String[] { "Method: dynamic, Nonlinear solver= dynamic", "Method: BDF, Nonlinear solver= NEWTON",
181                 "Method: BDF, Nonlinear solver= FUNCTIONAL", "Method: ADAMS, Nonlinear solver= NEWTON", "Method: ADAMS, Nonlinear solver= FUNCTIONAL",
182                 "Method: Fixed step", "Method: Fixed step", "Sundials/IDA"
183                                                       };
184
185         solver = new JComboBox(solvers);
186         double solverValue = parameters.getSolver();
187         if (solverValue >= 0.0 && solverValue <= solvers.length - 2) {
188             solver.setSelectedIndex((int) solverValue);
189         } else {
190             solver.setSelectedIndex(solvers.length - 1);
191         }
192
193         final class ComboboxToolTipRenderer extends DefaultListCellRenderer {
194             @Override
195             public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
196                 JComponent comp = (JComponent) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
197
198                 if (-1 < index && null != value && null != solversTooltips) {
199                     list.setToolTipText(solversTooltips[index]);
200                 }
201                 return comp;
202             }
203         }
204         solver.setRenderer(new ComboboxToolTipRenderer());
205
206         JLabel maxStepSizeLabel = new JLabel(XcosMessages.MAXIMUN_STEP_SIZE);
207         maxStepSize = new JFormattedTextField(CURRENT_FORMAT);
208         maxStepSize.setInputVerifier(VALIDATE_POSITIVE_DOUBLE);
209         maxStepSize.setValue(new BigDecimal(parameters.getMaximumStepSize()));
210
211         JButton cancelButton = new JButton(XcosMessages.CANCEL);
212         JButton okButton = new JButton(XcosMessages.OK);
213         JButton defaultButton = new JButton(XcosMessages.DEFAULT);
214         JButton setContextButton = new JButton(XcosMessages.SET_CONTEXT);
215         okButton.setPreferredSize(cancelButton.getPreferredSize());
216
217         GridBagConstraints gbc = new GridBagConstraints();
218
219         gbc.gridx = 0;
220         gbc.gridy = 0;
221         gbc.gridheight = 1;
222         gbc.gridwidth = 1;
223         gbc.insets = new Insets(0, 10, 0, 0);
224
225         gbc.gridx = 0;
226         gbc.gridy = 4;
227         gbc.gridheight = 1;
228         gbc.gridwidth = 1;
229         gbc.fill = GridBagConstraints.NONE;
230         gbc.insets = new Insets(0, 10, 0, 0);
231
232         add(integrationLabel, gbc);
233
234         gbc.gridy = 5;
235         add(rtsLabel, gbc);
236
237         gbc.gridy = 6;
238         add(integratorAbsLabel, gbc);
239
240         gbc.gridy = 7;
241         add(integratorRelLabel, gbc);
242
243         gbc.gridy = 8;
244         add(toleranceOnTimeLabel, gbc);
245
246         gbc.gridy = 9;
247         add(maxIntegrationTimeLabel, gbc);
248
249         gbc.gridy = 10;
250         add(solverLabel, gbc);
251
252         gbc.gridy = 11;
253         add(maxStepSizeLabel, gbc);
254
255         gbc.gridy = 12;
256         add(setContextButton, gbc);
257
258         gbc.gridx = 1;
259         gbc.gridy = 4;
260         gbc.gridwidth = GridBagConstraints.REMAINDER;
261         gbc.fill = GridBagConstraints.HORIZONTAL;
262         gbc.insets = new Insets(5, 10, 0, 10);
263         add(integration, gbc);
264
265         gbc.gridy = 5;
266         add(rts, gbc);
267
268         gbc.gridy = 6;
269         add(integrator, gbc);
270
271         gbc.gridy = 7;
272         add(integratorRel, gbc);
273
274         gbc.gridy = 8;
275         add(toleranceOnTime, gbc);
276
277         gbc.gridy = 9;
278         add(maxIntegrationTime, gbc);
279
280         gbc.gridy = 10;
281         add(solver, gbc);
282
283         gbc.gridy = 11;
284         add(maxStepSize, gbc);
285
286         gbc.gridx = 1;
287         gbc.gridy = 14;
288         gbc.gridheight = 1;
289         gbc.gridwidth = 1;
290         gbc.weightx = 1.;
291         gbc.fill = GridBagConstraints.NONE;
292         gbc.insets = new Insets(5, 0, 10, 5);
293         add(okButton, gbc);
294
295         gbc.gridx = 2;
296         gbc.weightx = 0.;
297         gbc.insets = new Insets(5, 0, 10, 10);
298         add(cancelButton, gbc);
299
300         gbc.gridx = 3;
301         gbc.weightx = 0.;
302         gbc.insets = new Insets(5, 0, 10, 10);
303         add(defaultButton, gbc);
304
305         installActionListeners(cancelButton, okButton, defaultButton, setContextButton);
306     }
307
308     // CSON: JavaNCSS
309
310     /**
311      * Install the action listeners on the buttons
312      *
313      * @param cancelButton
314      *            the cancel button (Cancel)
315      * @param okButton
316      *            the OK button (Validate)
317      * @param defaultButton
318      *            the default button (Reset)
319      * @param setContextButton
320      *            the context button (Shortcut to set context)
321      */
322     private void installActionListeners(JButton cancelButton, JButton okButton, JButton defaultButton, JButton setContextButton) {
323         cancelButton.addActionListener(new ActionListener() {
324             @Override
325             public void actionPerformed(ActionEvent e) {
326                 dispose();
327             }
328         });
329
330         defaultButton.addActionListener(new ActionListener() {
331             @Override
332             public void actionPerformed(ActionEvent e) {
333                 integration.setValue(new BigDecimal(ScicosParameters.FINAL_INTEGRATION_TIME));
334                 rts.setValue(new BigDecimal(ScicosParameters.REAL_TIME_SCALING));
335                 integrator.setValue(new BigDecimal(ScicosParameters.INTEGRATOR_ABSOLUTE_TOLERANCE));
336                 integratorRel.setValue(new BigDecimal(ScicosParameters.INTEGRATOR_RELATIVE_TOLERANCE));
337                 toleranceOnTime.setValue(new BigDecimal(ScicosParameters.TOLERANCE_ON_TIME));
338                 maxIntegrationTime.setValue(new BigDecimal(ScicosParameters.MAX_INTEGRATION_TIME_INTERVAL));
339                 solver.setSelectedIndex((int) ScicosParameters.SOLVER);
340                 maxStepSize.setValue(new BigDecimal(ScicosParameters.MAXIMUM_STEP_SIZE));
341             }
342         });
343
344         okButton.addActionListener(new ActionListener() {
345             @Override
346             public void actionPerformed(ActionEvent e) {
347                 if (((JButton) e.getSource()).hasFocus()) {
348                     try {
349                         /*
350                          * FIXME This logic must be deported to a vetoable
351                          * handler
352                          */
353                         int solverSelectedIndex = solver.getSelectedIndex();
354                         if (solverSelectedIndex >= 0.0 && solverSelectedIndex <= solver.getModel().getSize() - 2) {
355                             parameters.setSolver(solverSelectedIndex);
356                         } else {
357                             parameters.setSolver(100.0);
358                         }
359
360                         parameters.setFinalIntegrationTime(((BigDecimal) integration.getValue()).doubleValue());
361                         parameters.setRealTimeScaling(((BigDecimal) rts.getValue()).doubleValue());
362                         parameters.setIntegratorAbsoluteTolerance(((BigDecimal) integrator.getValue()).doubleValue());
363                         parameters.setIntegratorRelativeTolerance(((BigDecimal) integratorRel.getValue()).doubleValue());
364                         parameters.setToleranceOnTime(((BigDecimal) toleranceOnTime.getValue()).doubleValue());
365                         parameters.setMaxIntegrationTimeInterval(((BigDecimal) maxIntegrationTime.getValue()).doubleValue());
366                         parameters.setMaximumStepSize(((BigDecimal) maxStepSize.getValue()).doubleValue());
367
368                         dispose();
369
370                     } catch (PropertyVetoException ex) {
371                         Logger.getLogger(SetupAction.class.getName()).severe(ex.toString());
372                     }
373                 }
374             }
375         });
376
377         setContextButton.addActionListener(new ActionListener() {
378             @Override
379             public void actionPerformed(ActionEvent e) {
380                 final SetContextDialog dialog = new SetContextDialog(SetupDialog.this, rootGraph, parameters);
381
382                 dialog.pack();
383                 dialog.setVisible(true);
384             }
385         });
386     }
387 }
388 // CSON: ClassDataAbstractionCoupling
389 // CSON: ClassFanOutComplexity
390 // CSON: MagicNumber