Xcos: fix update of empty value for IOBlocks
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / io / ContextUpdate.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - 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.block.io;
14
15 import java.beans.PropertyChangeEvent;
16 import java.beans.PropertyChangeListener;
17 import java.io.File;
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.EnumMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
25 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
26 import org.scilab.modules.types.scilabTypes.ScilabDouble;
27 import org.scilab.modules.types.scilabTypes.ScilabList;
28 import org.scilab.modules.types.scilabTypes.ScilabType;
29 import org.scilab.modules.xcos.block.BasicBlock;
30 import org.scilab.modules.xcos.block.SuperBlock;
31 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
32 import org.scilab.modules.xcos.io.scicos.H5RWHandler;
33 import org.scilab.modules.xcos.port.BasicPort;
34 import org.scilab.modules.xcos.port.command.CommandPort;
35 import org.scilab.modules.xcos.port.control.ControlPort;
36 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
37 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
38 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
39 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
40 import org.scilab.modules.xcos.utils.FileUtils;
41 import org.scilab.modules.xcos.utils.XcosEvent;
42
43 import com.mxgraph.model.mxGraphModel;
44 import com.mxgraph.model.mxICell;
45 import com.mxgraph.model.mxIGraphModel;
46 import com.mxgraph.util.mxEventObject;
47
48 /**
49  * Common class for the SuperBlock I/O blocks (represent ports)
50  */
51 public abstract class ContextUpdate extends BasicBlock {
52
53         private static final long serialVersionUID = 6076826729067963560L;
54
55         /**
56          * Implement a listener which update the value and refresh the view when the
57          * index of the port change.
58          */
59         private static final class IndexChangeAdapter implements PropertyChangeListener {
60                 private static IndexChangeAdapter instance;
61                 
62                 /**
63                  * Default constructor.
64                  */
65                 private IndexChangeAdapter() { }
66                 
67                 /**
68                  * @return the instance
69                  */
70                 public static synchronized IndexChangeAdapter getInstance() {
71                         if (instance == null) {
72                                 instance = new IndexChangeAdapter();
73                         }
74                         return instance;
75                 }
76                 
77                 /**
78                  * Update the value and refresh the graph view.
79                  * 
80                  * @param evt the event
81                  * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
82                  */
83                 @Override
84                 public void propertyChange(PropertyChangeEvent evt) {
85                         ScilabType data = (ScilabType) evt.getNewValue();
86                         ContextUpdate ioBlock = (ContextUpdate) evt.getSource();
87                         
88                         if (!data.isEmpty()) {
89                                 int newIndex = (int) ((ScilabDouble) data).getRealPart()[0][0];
90                                 
91                                 int oldIndex;
92                                 if (evt.getOldValue() instanceof ScilabDouble
93                                                 && !((ScilabDouble) evt.getOldValue()).isEmpty()) {
94                                         oldIndex = (int) ((ScilabDouble) evt.getOldValue()).getRealPart()[0][0];
95                                 } else {
96                                         oldIndex = -1;
97                                 }
98                                 
99                                 ioBlock.setValue(newIndex);
100                                 if (ioBlock.getParentDiagram() != null) {
101                                         ioBlock.getParentDiagram().fireEvent(
102                                                         new mxEventObject(XcosEvent.IO_PORT_VALUE_UPDATED,
103                                                                         "block", ioBlock, "oldIndex", oldIndex,
104                                                                         "newIndex", newIndex));
105                                 }
106                         }
107                 }
108                 
109         }
110         
111         /**
112          * This enum represent all the subclasses of ContextUpdate .
113          * 
114          * It is used to easily loop over a BasicBlock I/O blocks
115          */
116         public enum IOBlocks {
117                 /** Map a control port to an event input block */
118                 EventInBlock(EventInBlock.class, ControlPort.class),
119                 /** Map a command port to an event output block */
120                 EventOutBlock(EventOutBlock.class, CommandPort.class),
121                 /** Map an explicit input port to an explicit input block */
122                 ExplicitInBlock(ExplicitInBlock.class, ExplicitInputPort.class),
123                 /** Map an explicit output port to an explicit output block */
124                 ExplicitOutBlock(ExplicitOutBlock.class, ExplicitOutputPort.class),
125                 /** Map an implicit input port to an implicit input block */
126                 ImplicitInBlock(ImplicitInBlock.class, ImplicitInputPort.class),
127                 /** Map an implicit output port to an implicit output block */
128                 ImplicitOutBlock(ImplicitOutBlock.class, ImplicitOutputPort.class);
129
130                 private final Class< ? extends ContextUpdate> ioBlock;
131                 private final Class< ? extends BasicPort> port;
132
133                 /**
134                  * @param ioBlock
135                  *            input/output block
136                  * @param port
137                  *            the associated port class
138                  */
139                 private IOBlocks(Class< ? extends ContextUpdate> ioBlock,
140                                 Class< ? extends BasicPort> port) {
141                         this.ioBlock = ioBlock;
142                         this.port = port;
143                 }
144                 
145                 /**
146                  * Get all the port of the SuperBlock parent.
147                  * 
148                  * @param parent
149                  *            the parent
150                  * @return the port list mapped by port type
151                  */
152                 public static Map<IOBlocks, List<mxICell>> getAllPorts(SuperBlock parent) {
153                         final EnumMap<IOBlocks, List<mxICell>> ret = new EnumMap<IOBlocks, List<mxICell>>(
154                                         IOBlocks.class);
155
156                         /* Allocation */
157                         for (IOBlocks b : IOBlocks.values()) {
158                                 ret.put(b, new ArrayList<mxICell>());
159                         }
160
161                         /* Loop all over the children */
162                         final int childCount = parent.getChildCount();
163
164                         for (int i = 0; i < childCount; i++) {
165                                 final mxICell child = parent.getChildAt(i);
166
167                                 /* if compatible add it to the list */
168                                 for (IOBlocks b : IOBlocks.values()) {
169                                         if (child.getClass().equals(b.getReferencedPortClass())) {
170                                                 ret.get(b).add(child);
171                                         }
172                                 }
173                         }
174
175                         return ret;
176                 }
177
178                 /**
179                  * Get all the I/O blocks of the SuperBlock parent.
180                  * 
181                  * @param parent
182                  *            the parent
183                  * @return the port list mapped by port type
184                  */
185                 public static Map<IOBlocks, List<mxICell>> getAllBlocks(SuperBlock parent) {
186                         final EnumMap<IOBlocks, List<mxICell>> ret = new EnumMap<IOBlocks, List<mxICell>>(
187                                         IOBlocks.class);
188
189                         final SuperBlockDiagram graph = parent.getChild();
190                         if (graph == null) {
191                                 parent.createChildDiagram();
192                         }
193                         
194                         /* Allocation */
195                         for (IOBlocks b : IOBlocks.values()) {
196                                 ret.put(b, new ArrayList<mxICell>());
197                         }
198
199                         /* Loop all over the children */
200                         final Object defaultParent = graph.getDefaultParent();
201                         final mxIGraphModel defaultModel = graph.getModel();
202                         final Object[] children = mxGraphModel.getChildCells(
203                                         defaultModel, defaultParent, true, false);
204                         
205                         for (int i = 0; i < children.length; i++) {
206                                 final mxICell child = (mxICell) children[i];
207
208                                 /* if compatible add it to the list */
209                                 for (IOBlocks b : IOBlocks.values()) {
210                                         if (child.getClass().equals(b.getReferencedClass())) {
211                                                 ret.get(b).add(child);
212                                         }
213                                 }
214                         }
215
216                         return ret;
217                 }
218
219                 /**
220                  * @return referenced class
221                  */
222                 public Class< ? extends ContextUpdate> getReferencedClass() {
223                         return ioBlock;
224                 }
225
226                 /**
227                  * @return the port referenced class
228                  */
229                 public Class< ? extends BasicPort> getReferencedPortClass() {
230                         return port;
231                 }
232         }
233         
234         /**
235          * Constructor.
236          */
237         public ContextUpdate() {
238                 super();
239                 
240                 getParametersPCS().addPropertyChangeListener("integerParameters",
241                                 IndexChangeAdapter.getInstance());
242         }
243
244         /**
245          * @param label
246          *            block labek
247          */
248         protected ContextUpdate(String label) {
249                 this();
250                 setValue(label);
251         }
252
253         /**
254          * Initialize the block with the default values
255          */
256         @Override
257         protected void setDefaultValues() {
258                 super.setDefaultValues();
259                 setNbZerosCrossing(new ScilabDouble(0));
260                 setNmode(new ScilabDouble(0));
261                 setODState(new ScilabList());
262                 setValue(1);
263         }
264
265         /**
266          * @param context
267          *            new context
268          */
269         public void onContextChange(String[] context) {
270                 // prevent to open twice
271                 if (isLocked()) {
272                         return;
273                 }
274
275                 final File tempOutput;
276                 final File tempInput;
277                 final File tempContext;
278                 try {
279                         tempInput = FileUtils.createTempFile();
280                         tempInput.deleteOnExit();
281
282                         // Write scs_m
283                         tempOutput = exportBlockStruct();
284                         // Write context
285                         tempContext = exportContext(context);
286
287                         String cmd = ScilabInterpreterManagement.buildCall("xcosBlockEval",
288                                         tempOutput.getAbsolutePath(), tempInput.getAbsolutePath(),
289                                         getInterfaceFunctionName().toCharArray(), tempContext.getAbsolutePath());
290
291                         try {
292                                 ScilabInterpreterManagement.synchronousScilabExec(cmd);
293                         } catch (InterpreterException e) {
294                                 e.printStackTrace();
295                         }
296                         BasicBlock modifiedBlock = new H5RWHandler(tempInput).readBlock();
297                         updateBlockSettings(modifiedBlock);
298
299                 } catch (IOException e) {
300                         e.printStackTrace();
301                 }
302         }
303 }