Xcos: fix "Region to Superblock" after cad91838
[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  * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.xcos.block.io;
18
19 import com.mxgraph.model.mxGeometry;
20 import java.beans.PropertyChangeEvent;
21 import java.beans.PropertyChangeListener;
22 import java.io.Serializable;
23 import java.lang.reflect.Constructor;
24 import java.util.ArrayList;
25 import java.util.EnumMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.logging.Logger;
29 import java.util.regex.Pattern;
30
31 import org.scilab.modules.types.ScilabDouble;
32 import org.scilab.modules.types.ScilabString;
33 import org.scilab.modules.types.ScilabType;
34 import org.scilab.modules.xcos.JavaController;
35 import org.scilab.modules.xcos.Kind;
36 import org.scilab.modules.xcos.Xcos;
37 import org.scilab.modules.xcos.XcosView;
38 import org.scilab.modules.xcos.block.BasicBlock;
39 import org.scilab.modules.xcos.block.SuperBlock;
40 import org.scilab.modules.xcos.port.BasicPort;
41 import org.scilab.modules.xcos.port.command.CommandPort;
42 import org.scilab.modules.xcos.port.control.ControlPort;
43 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
44 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
45 import org.scilab.modules.xcos.port.input.InputPort;
46 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
47 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
48 import org.scilab.modules.xcos.port.output.OutputPort;
49
50 import com.mxgraph.model.mxICell;
51 import java.rmi.server.UID;
52 import org.scilab.modules.xcos.ObjectProperties;
53
54 /**
55  * Common class for the SuperBlock I/O blocks (represent ports)
56  */
57 public abstract class ContextUpdate extends BasicBlock {
58
59     private static final Logger LOG_LOCAL = Logger.getLogger(ContextUpdate.class.getName());
60     private static final long serialVersionUID = 6076826729067963560L;
61
62     private static final double DEFAULT_WIDTH = 20.0;
63     private static final double DEFAULT_HEIGHT = 20.0;
64
65     /**
66      * Implement a listener which update the value and refresh the view when the
67      * index of the port change.
68      */
69     @SuppressWarnings(value = { "serial" })
70     private static final class IndexChangeAdapter implements PropertyChangeListener, Serializable {
71         private static IndexChangeAdapter instance;
72
73         /**
74          * Default constructor.
75          */
76         private IndexChangeAdapter() {
77         }
78
79         /**
80          * @return the instance
81          */
82         public static synchronized IndexChangeAdapter getInstance() {
83             if (instance == null) {
84                 instance = new IndexChangeAdapter();
85             }
86             return instance;
87         }
88
89         /**
90          * Update the value and refresh the graph view.
91          *
92          * @param evt
93          *            the event
94          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
95          */
96         @Override
97         public void propertyChange(PropertyChangeEvent evt) {
98             ScilabType data = (ScilabType) evt.getNewValue();
99             ContextUpdate ioBlock = (ContextUpdate) evt.getSource();
100
101             if (!data.isEmpty()) {
102                 int newIndex = (int) ((ScilabDouble) data).getRealPart()[0][0];
103
104                 int oldIndex;
105                 if (evt.getOldValue() instanceof ScilabDouble && !((ScilabDouble) evt.getOldValue()).isEmpty()) {
106                     oldIndex = (int) ((ScilabDouble) evt.getOldValue()).getRealPart()[0][0];
107                 } else {
108                     oldIndex = -1;
109                 }
110
111                 ioBlock.setValue(newIndex);
112             }
113         }
114
115     }
116
117     /**
118      * Implement a listener to update the
119      * {@link ContextUpdate#isContextDependent} flag.
120      *
121      * @SuppressWarnings(value = { "serial" })
122      */
123     private static final class ExprsChangeAdapter implements PropertyChangeListener, Serializable {
124         private static final Pattern INTEGER_PATTERN = Pattern.compile("\\d+");
125
126         private static ExprsChangeAdapter instance;
127
128         /**
129          * Default constructor
130          */
131         public ExprsChangeAdapter() {
132         }
133
134         /**
135          * @return the shared instance
136          */
137         public static ExprsChangeAdapter getInstance() {
138             if (instance == null) {
139                 instance = new ExprsChangeAdapter();
140             }
141             return instance;
142         }
143
144         /**
145          * isContextDependant field
146          *
147          * @param evt
148          *            the event
149          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
150          */
151         @Override
152         public void propertyChange(final PropertyChangeEvent evt) {
153             final ScilabType data = (ScilabType) evt.getNewValue();
154             final ContextUpdate ioBlock = (ContextUpdate) evt.getSource();
155
156             if (!data.isEmpty()) {
157                 final String newIndex = ((ScilabString) data).getData()[0][0];
158
159                 if (!INTEGER_PATTERN.matcher(newIndex).matches()) {
160                     ioBlock.isContextDependent = true;
161                 } else {
162                     ioBlock.isContextDependent = false;
163                 }
164             }
165         }
166     }
167
168     /**
169      * This enum represent all the subclasses of ContextUpdate .
170      *
171      * It is used to easily loop over a BasicBlock I/O blocks
172      */
173     public static enum IOBlocks {
174         /** Map a control port to an event input block */
175         EventInBlock(EventInBlock.class, ControlPort.class, CommandPort.class, ControlPort.class),
176         /** Map a command port to an event output block */
177         EventOutBlock(EventOutBlock.class, CommandPort.class, ControlPort.class, CommandPort.class),
178         /** Map an explicit input port to an explicit input block */
179         ExplicitInBlock(ExplicitInBlock.class, ExplicitInputPort.class, ExplicitOutputPort.class, InputPort.class),
180         /** Map an explicit output port to an explicit output block */
181         ExplicitOutBlock(ExplicitOutBlock.class, ExplicitOutputPort.class, ExplicitInputPort.class, OutputPort.class),
182         /** Map an implicit input port to an implicit input block */
183         ImplicitInBlock(ImplicitInBlock.class, ImplicitInputPort.class, ImplicitOutputPort.class, InputPort.class),
184         /** Map an implicit output port to an implicit output block */
185         ImplicitOutBlock(ImplicitOutBlock.class, ImplicitOutputPort.class, ImplicitInputPort.class, OutputPort.class);
186
187         private final Class<? extends ContextUpdate> ioBlock;
188         private final Class<? extends BasicPort> port;
189         private final Class<? extends BasicPort> opposite;
190         private final Class<? extends BasicPort> assignement;
191
192         /**
193          * @param ioBlock
194          *            input/output block
195          * @param port
196          *            the associated port class
197          * @param opposite
198          *            the opposite port class
199          */
200         private IOBlocks(Class<? extends ContextUpdate> ioBlock, Class<? extends BasicPort> port, Class<? extends BasicPort> opposite,
201         Class<? extends BasicPort> assignement) {
202             this.ioBlock = ioBlock;
203             this.port = port;
204             this.opposite = opposite;
205             this.assignement = assignement;
206         }
207
208         /**
209          * Get all the port of the SuperBlock parent.
210          *
211          * @param parent
212          *            the parent
213          * @return the port list mapped by port type
214          */
215         public static Map<IOBlocks, List<mxICell>> getAllPorts(SuperBlock parent) {
216             final EnumMap<IOBlocks, List<mxICell>> ret = new EnumMap<IOBlocks, List<mxICell>>(IOBlocks.class);
217
218             /* Allocation */
219             for (IOBlocks b : IOBlocks.values()) {
220                 ret.put(b, new ArrayList<mxICell>());
221             }
222
223             /* Loop all over the children */
224             final int childCount = parent.getChildCount();
225
226             for (int i = 0; i < childCount; i++) {
227                 final mxICell child = parent.getChildAt(i);
228
229                 /* if compatible add it to the list */
230                 for (IOBlocks b : IOBlocks.values()) {
231                     if (child.getClass().equals(b.getReferencedPortClass())) {
232                         ret.get(b).add(child);
233                     }
234                 }
235             }
236
237             return ret;
238         }
239
240         /**
241          * Get the ports of the super blocks with kind klass
242          *
243          * @param parent
244          *            the parent {@link SuperBlock}
245          * @param klass
246          *            the filter klass
247          * @return the list of ports
248          */
249         public static List<mxICell> getPorts(SuperBlock parent, Class<? extends ContextUpdate> klass) {
250             List<mxICell> ret = new ArrayList<mxICell>();
251
252             /* Get the corresponding klass */
253             Class<? extends BasicPort> portKlass = null;
254             for (IOBlocks b : IOBlocks.values()) {
255                 if (b.getReferencedClass().equals(klass)) {
256                     portKlass = b.getAssignementCompatiblePortClass();
257                     break;
258                 }
259             }
260
261             /* Loop all over the children */
262             final int childCount = parent.getChildCount();
263
264             for (int i = 0; i < childCount; i++) {
265                 final mxICell child = parent.getChildAt(i);
266
267                 if (portKlass.isInstance(child)) {
268                     ret.add(child);
269                 }
270             }
271
272             return ret;
273         }
274
275         /**
276          * Return the opposite of the port
277          *
278          * @param klass
279          *            the klass
280          * @return the opposite of klass
281          */
282         public static Class<? extends BasicPort> getOpposite(Class<? extends BasicPort> klass) {
283             for (IOBlocks b : IOBlocks.values()) {
284                 if (b.getReferencedPortClass() == klass) {
285                     return b.getOppositeClass();
286                 }
287             }
288             return null;
289         }
290
291         /**
292          * Create a corresponding I/O block
293          *
294          * @param port
295          *            the port used as an output
296          * @return the corresponding block
297          */
298         public static ContextUpdate createBlock(BasicPort port) {
299             for (IOBlocks io : IOBlocks.values()) {
300                 if (io.getReferencedPortClass().isInstance(port)) {
301                     try {
302                         JavaController controller = new JavaController();
303
304                         // create the Input/Output block
305                         Constructor<? extends ContextUpdate> blockCstr = io.getReferencedClass().getConstructor(JavaController.class);
306                         ContextUpdate block = blockCstr.newInstance(controller);
307
308                         // create the single port of the block
309                         Constructor<? extends BasicPort> portCstr = io.getOppositeClass().getConstructor(
310                                     JavaController.class, Long.TYPE, Kind.class, Object.class, String.class, String.class);
311                         BasicPort blockPort = portCstr.newInstance(
312                                                   controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, new UID().toString());
313
314                         // inser the port into the newly created block
315                         block.insert(blockPort);
316
317                         return block;
318                     } catch (ReflectiveOperationException e) {
319                         Logger.getLogger(IOBlocks.class.getName()).severe(e.toString());
320                     }
321                 }
322             }
323
324             return null;
325         }
326
327         /**
328          * @return referenced class
329          */
330         public Class<? extends ContextUpdate> getReferencedClass() {
331             return ioBlock;
332         }
333
334         /**
335          * @return the port referenced class
336          */
337         public Class<? extends BasicPort> getReferencedPortClass() {
338             return port;
339         }
340
341         public Class<? extends BasicPort> getAssignementCompatiblePortClass() {
342             return assignement;
343         }
344
345         /**
346          * @return the port opposite class
347          */
348         public Class<? extends BasicPort> getOppositeClass() {
349             return opposite;
350         }
351     }
352
353     private transient boolean isContextDependent;
354
355     /**
356      * Constructor
357      */
358     public ContextUpdate(JavaController controller, long uid, Kind kind, Object value, mxGeometry geometry, String style, String id) {
359         super(controller, uid, kind, value, geometry, style, id);
360     }
361
362     /**
363      * Constructor used to allocate a new block on the Java side
364      *
365      * The caller should add a port child and setup the simulation function accordingly to the style.
366      * @param controller the controller used to allocate the block
367      * @param blockName the interface function and style applied on the block
368      */
369     protected ContextUpdate(JavaController controller, String blockName) {
370         super(controller, controller.createObject(Kind.BLOCK), Kind.BLOCK, null, new mxGeometry(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT), blockName, new UID().toString());
371
372         controller.setObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, blockName);
373     }
374
375
376
377     /**
378      * @param context
379      *            new context
380      */
381     public void onContextChange(String[] context) {
382         // prevent to open twice
383         if (isLocked()) {
384             return;
385         }
386
387         // do not evaluate context is the block is not context dependent.
388         if (!isContextDependent) {
389             return;
390         }
391
392         LOG_LOCAL.finest("Update the I/O value from the context");
393
394         // final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
395         // if (handler == null) {
396         // return;
397         // }
398         //
399         // try {
400         // // Write scs_m
401         // handler.writeBlock(this);
402         // // Write context
403         // handler.writeContext(context);
404         //
405         // String cmd = ScilabInterpreterManagement.buildCall("blk =
406         // xcosBlockEval", getInterfaceFunctionName().toCharArray(),
407         // ScilabDirectHandler.BLK.toCharArray(),
408         // ScilabDirectHandler.CONTEXT.toCharArray());
409         //
410         // try {
411         // ScilabInterpreterManagement.synchronousScilabExec(cmd);
412         // } catch (InterpreterException e) {
413         // e.printStackTrace();
414         // }
415         // BasicBlock modifiedBlock = handler.readBlock();
416         // updateBlockSettings(modifiedBlock);
417         //
418         // } catch (ScicosFormatException e) {
419         // LOG_LOCAL.severe(e.toString());
420         // } finally {
421         // handler.release();
422         // }
423     }
424 }