Xcos modelica init: fix the XSD Schema
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / modelica / view / MainPanel.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010-2010 - DIGITEO - Clement DAVID <clement.david@scilab.org>
4  * Copyright (C) 2011-2011 - Scilab Enterprises - Clement DAVID
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 package org.scilab.modules.xcos.modelica.view;
15
16 import static org.scilab.modules.xcos.modelica.TerminalAccessor.FIXED;
17 import static org.scilab.modules.xcos.modelica.TerminalAccessor.WEIGHT;
18 import static org.scilab.modules.xcos.modelica.TerminalAccessor.getData;
19
20 import java.awt.GridLayout;
21 import java.awt.event.ItemEvent;
22 import java.awt.event.ItemListener;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.List;
27
28 import javax.swing.BoxLayout;
29 import javax.swing.JPanel;
30 import javax.swing.event.ChangeEvent;
31 import javax.swing.event.ChangeListener;
32 import javax.swing.event.TableModelEvent;
33 import javax.swing.event.TableModelListener;
34 import javax.swing.event.TreeSelectionEvent;
35 import javax.swing.event.TreeSelectionListener;
36 import javax.swing.tree.DefaultMutableTreeNode;
37 import javax.swing.tree.DefaultTreeModel;
38 import javax.swing.tree.MutableTreeNode;
39 import javax.swing.tree.TreeModel;
40 import javax.swing.tree.TreePath;
41
42 import org.scilab.modules.xcos.modelica.ModelStatistics;
43 import org.scilab.modules.xcos.modelica.ModelicaController;
44 import org.scilab.modules.xcos.modelica.ModelicaController.ComputationMethod;
45 import org.scilab.modules.xcos.modelica.ModelicaMessages;
46 import org.scilab.modules.xcos.modelica.TerminalAccessor;
47 import org.scilab.modules.xcos.modelica.TerminalTableModel;
48 import org.scilab.modules.xcos.modelica.listener.FixDerivativesAction;
49 import org.scilab.modules.xcos.modelica.listener.FixStatesAction;
50 import org.scilab.modules.xcos.modelica.listener.SolveAction;
51 import org.scilab.modules.xcos.modelica.listener.StatisticsUpdater;
52 import org.scilab.modules.xcos.modelica.model.Model;
53 import org.scilab.modules.xcos.modelica.model.Struct;
54 import org.scilab.modules.xcos.modelica.model.Terminal;
55
56 /**
57  * The main view of the modelica initialize dialog
58  */
59 // CSOFF: FanOutComplexity
60 // CSOFF: DataAbstractionCoupling
61 @SuppressWarnings(value = { "serial" })
62 public final class MainPanel extends JPanel {
63     private static final int[] EXTENDED_STATUS_LAYOUT_DATA = new int[] { 2, 6 };
64
65     private final ModelicaController controller;
66
67     private javax.swing.JPanel controlBar;
68     private javax.swing.JScrollPane treeScrollPane;
69     private javax.swing.JScrollPane tableScrollPane;
70     private javax.swing.JSplitPane splitPanel;
71     private javax.swing.JTable table;
72     private TerminalTableModel tableModel;
73     private javax.swing.JTree tree;
74     private LabelWithValue equation;
75     private LabelWithValue inputs;
76     private LabelWithValue outputs;
77     private LabelWithValue unknowns;
78     private LabelWithValue reduced;
79     private LabelWithValue diffSt;
80     private LabelWithValue fixedParams;
81     private LabelWithValue relaxedParams;
82     private LabelWithValue fixedVars;
83     private LabelWithValue relaxedVars;
84     private LabelWithValue discretes;
85     private javax.swing.JCheckBox embeddedParametersButton;
86     private javax.swing.JCheckBox generateJacobianButton;
87     private javax.swing.JButton solveButton;
88     private javax.swing.JLabel solver;
89     private javax.swing.JComboBox solverComboBox;
90     private javax.swing.JPanel variableStatusBar;
91     private javax.swing.JPanel extendedStatus;
92     private javax.swing.JPanel globalStatus;
93     private javax.swing.JButton fixStates;
94     private javax.swing.JButton fixDerivatives;
95
96     /**
97      * Default constructor
98      *
99      * @param controller
100      *            the modelica controller
101      */
102     public MainPanel(ModelicaController controller) {
103         this.controller = controller;
104         initComponents();
105         installListeners();
106
107         fireChange();
108     }
109
110     /**
111      * Init the component
112      */
113     private void initComponents() {
114         allocateFields();
115         setLayoutsAndBorders();
116
117         initGlobalStatus();
118         variableStatusBar.add(globalStatus);
119
120         initExtendedStatus();
121         variableStatusBar.add(extendedStatus);
122
123         add(variableStatusBar, java.awt.BorderLayout.PAGE_START);
124
125         tree.setModel(createTreeModel());
126         treeScrollPane.setViewportView(tree);
127         splitPanel.setLeftComponent(treeScrollPane);
128
129         table.setModel(tableModel);
130         table.setAutoCreateRowSorter(true);
131         tableScrollPane.setViewportView(table);
132
133         splitPanel.setRightComponent(tableScrollPane);
134
135         add(splitPanel, java.awt.BorderLayout.CENTER);
136
137         initControlBar();
138         add(controlBar, java.awt.BorderLayout.PAGE_END);
139     }
140
141     /**
142      * Create a tree model associated with the current
143      *
144      * @return the model of a tree
145      */
146     private TreeModel createTreeModel() {
147         final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(
148         controller.getRoot()) {
149             public String toString() {
150                 return ((Model) getUserObject()).getName();
151             };
152         };
153         final TreeModel model = new DefaultTreeModel(rootNode);
154
155         for (Struct struct : controller.getRoot().getElements().getStruct()) {
156             rootNode.add(createNodes(struct));
157         }
158
159         return model;
160     }
161
162     /**
163      * Recursively create the nodes for the data
164      *
165      * @param struct
166      *            the data
167      * @return the parent node
168      */
169     private MutableTreeNode createNodes(Struct struct) {
170         DefaultMutableTreeNode structNode = new DefaultMutableTreeNode(struct) {
171             public String toString() {
172                 return ((Struct) getUserObject()).getName();
173             };
174         };
175
176         for (Object child : struct.getSubnodes().getStructOrTerminal()) {
177             // recursive call
178             if (child instanceof Struct) {
179                 structNode.add(createNodes((Struct) child));
180             }
181         }
182
183         return structNode;
184     }
185
186     /**
187      * @param path
188      *            the current path
189      * @return the terminals associated with the path
190      */
191     private List<Terminal> getTerminals(TreePath path) {
192         final List<Terminal> ret;
193
194         // the root is not a Struct instance and thus return an empty list.
195         if (path.getPathCount() > 1) {
196             ret = new ArrayList<Terminal>();
197             final Struct struct = (Struct) ((DefaultMutableTreeNode) path
198                                             .getLastPathComponent()).getUserObject();
199
200             for (Object child : struct.getSubnodes().getStructOrTerminal()) {
201                 if (child instanceof Terminal) {
202                     ret.add((Terminal) child);
203                 }
204             }
205
206         } else {
207             ret = Collections.emptyList();
208         }
209         return ret;
210     }
211
212     /**
213      * Init the control bar
214      */
215     private void initControlBar() {
216         javax.swing.JPanel control = new javax.swing.JPanel();
217
218         solver.setText(ModelicaMessages.SOLVER + " :");
219         control.add(solver);
220
221         solverComboBox.setModel(new javax.swing.DefaultComboBoxModel(
222                                     ModelicaController.ComputationMethod.values()));
223         solverComboBox
224         .setToolTipText(ModelicaMessages.INITIAL_COMPUTING_METHOD);
225
226         control.add(solverComboBox);
227
228         embeddedParametersButton.setText(ModelicaMessages.PARAMETER_EMBEDDING);
229         embeddedParametersButton
230         .setToolTipText(ModelicaMessages.PARAMETER_EMBEDDING_EXPLAINED);
231         control.add(embeddedParametersButton);
232         generateJacobianButton.setText(ModelicaMessages.GENERATE_JACOBIAN);
233         control.add(generateJacobianButton);
234         solveButton.setAction(new SolveAction(controller));
235         control.add(solveButton);
236         controlBar.add(control);
237     }
238
239     /**
240      *
241      */
242     private void initExtendedStatus() {
243         diffSt.setTitle(ModelicaMessages.DIFF_ST);
244         extendedStatus.add(diffSt);
245         fixedParams.setTitle(ModelicaMessages.FIXED_PARAMS);
246         extendedStatus.add(fixedParams);
247         relaxedParams.setTitle(ModelicaMessages.RELAXED_PARAMS);
248         extendedStatus.add(relaxedParams);
249         fixedVars.setTitle(ModelicaMessages.FIXED_VARIABLES);
250         extendedStatus.add(fixedVars);
251         relaxedVars.setTitle(ModelicaMessages.RELAXED_VARIABLES);
252         extendedStatus.add(relaxedVars);
253         discretes.setTitle(ModelicaMessages.DISCRETES);
254         extendedStatus.add(discretes);
255         inputs.setTitle(ModelicaMessages.INPUTS);
256         extendedStatus.add(inputs);
257         outputs.setTitle(ModelicaMessages.OUTPUTS);
258         extendedStatus.add(outputs);
259     }
260
261     /**
262      *
263      */
264     private void initGlobalStatus() {
265         javax.swing.JPanel globalTop = new javax.swing.JPanel();
266         javax.swing.JPanel globalBottom = new javax.swing.JPanel();
267
268         equation.setTitle(ModelicaMessages.EQUATIONS);
269         globalTop.add(equation);
270         unknowns.setTitle(ModelicaMessages.UNKNOWNS);
271         globalTop.add(unknowns);
272         reduced.setTitle(ModelicaMessages.REDUCED);
273         globalTop.add(reduced);
274
275         globalStatus.add(globalTop);
276
277         fixStates.setAction(new FixStatesAction(controller));
278         globalBottom.add(fixStates);
279         fixDerivatives.setAction(new FixDerivativesAction(controller));
280         globalBottom.add(fixDerivatives);
281
282         globalStatus.add(globalBottom);
283     }
284
285     /**
286      * Setup the layouts
287      */
288     private void setLayoutsAndBorders() {
289         setLayout(new java.awt.BorderLayout());
290
291         globalStatus.setBorder(javax.swing.BorderFactory
292                                .createTitledBorder(ModelicaMessages.GLOBAL));
293         globalStatus
294         .setLayout(new BoxLayout(globalStatus, BoxLayout.PAGE_AXIS));
295
296         extendedStatus.setBorder(javax.swing.BorderFactory
297                                  .createTitledBorder(ModelicaMessages.EXTENDED));
298         extendedStatus.setLayout(new GridLayout(EXTENDED_STATUS_LAYOUT_DATA[0],
299                                                 EXTENDED_STATUS_LAYOUT_DATA[1]));
300
301         splitPanel.setContinuousLayout(true);
302
303         controlBar.setLayout(new BoxLayout(controlBar, BoxLayout.PAGE_AXIS));
304     }
305
306     /**
307      * Allocator for the fields
308      */
309     private void allocateFields() {
310         variableStatusBar = new javax.swing.JPanel();
311         globalStatus = new javax.swing.JPanel();
312         extendedStatus = new javax.swing.JPanel();
313         equation = new LabelWithValue();
314         unknowns = new LabelWithValue();
315         reduced = new LabelWithValue();
316         diffSt = new LabelWithValue();
317         fixedParams = new LabelWithValue();
318         relaxedParams = new LabelWithValue();
319         fixedVars = new LabelWithValue();
320         relaxedVars = new LabelWithValue();
321         discretes = new LabelWithValue();
322         inputs = new LabelWithValue();
323         outputs = new LabelWithValue();
324         splitPanel = new javax.swing.JSplitPane();
325         treeScrollPane = new javax.swing.JScrollPane();
326         tree = new javax.swing.JTree();
327         tableScrollPane = new javax.swing.JScrollPane();
328         table = new javax.swing.JTable();
329         controlBar = new javax.swing.JPanel();
330         solver = new javax.swing.JLabel();
331         solverComboBox = new javax.swing.JComboBox();
332         embeddedParametersButton = new javax.swing.JCheckBox();
333         generateJacobianButton = new javax.swing.JCheckBox();
334         solveButton = new javax.swing.JButton();
335         fixStates = new javax.swing.JButton();
336         fixDerivatives = new javax.swing.JButton();
337         tableModel = new TerminalTableModel();
338     }
339
340     /**
341      * Install the listeners
342      */
343     private void installListeners() {
344         /*
345          * Update table on tree selection change
346          */
347         tree.addTreeSelectionListener(new TreeSelectionListener() {
348             @Override
349             public void valueChanged(TreeSelectionEvent e) {
350                 tableModel.setTerminals(getTerminals(e.getPath()));
351             }
352         });
353
354         /*
355          * On Statistics update, update the labels
356          */
357         final ModelStatistics statistics = controller.getStatistics();
358         statistics.addChangeListener(new ChangeListener() {
359             @Override
360             public void stateChanged(ChangeEvent e) {
361                 final ModelStatistics stats = (ModelStatistics) e.getSource();
362
363                 // set the values
364                 equation.setText(Long.toString(stats.getEquations()));
365                 unknowns.setText(Long.toString(stats.getUnknowns()));
366                 diffSt.setText(Long.toString(stats.getDerivativeStates()));
367                 fixedParams.setText(Long.toString(stats.getFixedParameters()));
368                 relaxedParams.setText(Long.toString(stats
369                                                     .getRelaxedParameters()));
370                 discretes.setText(Long.toString(stats.getDiscreteStates()));
371                 relaxedVars.setText(Long.toString(stats.getRelaxedVariables()));
372                 fixedVars.setText(Long.toString(stats.getFixedVariables()));
373                 inputs.setText(Long.toString(stats.getInputs()));
374                 outputs.setText(Long.toString(stats.getInputs()));
375             }
376         });
377
378         /*
379          * Install the table mode listeners
380          */
381         installTableModelListeners(statistics);
382
383         /*
384          * Update the controller on method change
385          */
386         solverComboBox.addItemListener(new ItemListener() {
387             @Override
388             public void itemStateChanged(ItemEvent e) {
389                 controller.setComputeMethod((ComputationMethod) e.getItem());
390             }
391         });
392
393         /*
394          * The generate jacobian button must be only available on Solver=="Ida"
395          */
396         solverComboBox.addItemListener(new ItemListener() {
397             @Override
398             public void itemStateChanged(ItemEvent e) {
399                 generateJacobianButton.setEnabled(e.getItem() == ModelicaController.ComputationMethod.Ida);
400             }
401         });
402
403         /*
404          * Install checkbox listeners
405          */
406         embeddedParametersButton.addItemListener(new ItemListener() {
407             @Override
408             public void itemStateChanged(ItemEvent e) {
409                 controller.setParameterEmbedded(e.getStateChange() == ItemEvent.SELECTED);
410             }
411         });
412         generateJacobianButton.addItemListener(new ItemListener() {
413             @Override
414             public void itemStateChanged(ItemEvent e) {
415                 controller.setJacobianEnable(e.getStateChange() == ItemEvent.SELECTED);
416             }
417         });
418     }
419
420     /**
421      * Install the listener on the table model
422      *
423      * @param statistics
424      *            the statistics
425      */
426     private void installTableModelListeners(final ModelStatistics statistics) {
427
428         /*
429          * Update the table on a global data change
430          */
431         controller.addChangeListener(new ChangeListener() {
432             @Override
433             public void stateChanged(ChangeEvent e) {
434                 tableModel.fireTableDataChanged();
435             }
436         });
437
438         /*
439          * On table modification, update the Statistics
440          */
441         tableModel.addTableModelListener(new StatisticsUpdater(statistics));
442
443         /*
444          * Update the fixed state
445          */
446         tableModel.addTableModelListener(new TableModelListener() {
447             @Override
448             public void tableChanged(TableModelEvent e) {
449                 if (e instanceof TerminalTableModel.TerminalTableModelEvent
450                         && ((TerminalTableModel.TerminalTableModelEvent) e)
451                         .isAfterCommit()) {
452                     final int rowIndex = e.getFirstRow();
453                     final int columnIndex = e.getColumn();
454
455                     if (TerminalAccessor.values()[columnIndex] == WEIGHT) {
456                         final TerminalTableModel model = (TerminalTableModel) e
457                                                          .getSource();
458                         final Terminal terminal = model.getTerminals().get(
459                                                       rowIndex);
460
461                         if (terminal.getKind().equals("fixed_parameter")
462                                 || terminal.getKind().equals("variable")) {
463                             final double data = (Double) getData(WEIGHT,
464                                                                  terminal);
465                             final boolean isFixed = data >= 1.0;
466
467                             tableModel.setValueAt(isFixed, rowIndex,
468                                                   Arrays.asList(TerminalAccessor.values())
469                                                   .indexOf(FIXED));
470                         }
471
472                     }
473                 }
474             }
475         });
476
477         /*
478          * Set the compilation flag when embedding parameters is invalidated and
479          * a fixed parameter change.
480          */
481         tableModel.addTableModelListener(new TableModelListener() {
482             @Override
483             public void tableChanged(TableModelEvent e) {
484                 if (e instanceof TerminalTableModel.TerminalTableModelEvent
485                         && !embeddedParametersButton.isSelected()) {
486                     final int rowIndex = e.getFirstRow();
487                     final int columnIndex = e.getColumn();
488
489                     if (TerminalAccessor.values()[columnIndex] == TerminalAccessor.WEIGHT) {
490                         final TerminalTableModel model = (TerminalTableModel) e
491                                                          .getSource();
492                         final Terminal terminal = model.getTerminals().get(
493                                                       rowIndex);
494                         final Double weight = TerminalAccessor.getData(
495                                                   TerminalAccessor.WEIGHT, terminal);
496
497                         if (weight.doubleValue() >= 1.0) {
498                             controller.setCompileNeeded(true);
499                         }
500                     }
501                 }
502             }
503         });
504     }
505
506     /**
507      * Fire all update events at the end of the init
508      */
509     private void fireChange() {
510         controller.getStatistics().fireChange();
511         controller.fireChange();
512     }
513 }
514 // CSON: FanOutComplexity
515 // CSON: DataAbstractionCoupling