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