2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009 - DIGITEO - Clement DAVID
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.1-en.txt
13 package org.scilab.modules.xcos.block.io;
15 import java.beans.PropertyChangeEvent;
16 import java.beans.PropertyChangeListener;
17 import java.io.Serializable;
18 import java.util.ArrayList;
19 import java.util.EnumMap;
20 import java.util.List;
22 import java.util.logging.Logger;
23 import java.util.regex.Pattern;
25 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
26 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
27 import org.scilab.modules.types.ScilabDouble;
28 import org.scilab.modules.types.ScilabList;
29 import org.scilab.modules.types.ScilabString;
30 import org.scilab.modules.types.ScilabType;
31 import org.scilab.modules.xcos.block.BasicBlock;
32 import org.scilab.modules.xcos.block.SuperBlock;
33 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
34 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
35 import org.scilab.modules.xcos.io.scicos.ScilabDirectHandler;
36 import org.scilab.modules.xcos.port.BasicPort;
37 import org.scilab.modules.xcos.port.command.CommandPort;
38 import org.scilab.modules.xcos.port.control.ControlPort;
39 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
40 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
41 import org.scilab.modules.xcos.port.input.InputPort;
42 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
43 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
44 import org.scilab.modules.xcos.port.output.OutputPort;
45 import org.scilab.modules.xcos.utils.XcosEvent;
47 import com.mxgraph.model.mxGraphModel;
48 import com.mxgraph.model.mxICell;
49 import com.mxgraph.model.mxIGraphModel;
50 import com.mxgraph.util.mxEventObject;
53 * Common class for the SuperBlock I/O blocks (represent ports)
55 public abstract class ContextUpdate extends BasicBlock {
57 private static final Logger LOG_LOCAL = Logger.getLogger(ContextUpdate.class.getName());
58 private static final long serialVersionUID = 6076826729067963560L;
60 private static final double DEFAULT_WIDTH = 20.0;
61 private static final double DEFAULT_HEIGHT = 20.0;
64 * Implement a listener which update the value and refresh the view when the
65 * index of the port change.
67 @SuppressWarnings(value = { "serial" })
68 private static final class IndexChangeAdapter implements PropertyChangeListener, Serializable {
69 private static IndexChangeAdapter instance;
72 * Default constructor.
74 private IndexChangeAdapter() {
78 * @return the instance
80 public static synchronized IndexChangeAdapter getInstance() {
81 if (instance == null) {
82 instance = new IndexChangeAdapter();
88 * Update the value and refresh the graph view.
92 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
95 public void propertyChange(PropertyChangeEvent evt) {
96 ScilabType data = (ScilabType) evt.getNewValue();
97 ContextUpdate ioBlock = (ContextUpdate) evt.getSource();
99 if (!data.isEmpty()) {
100 int newIndex = (int) ((ScilabDouble) data).getRealPart()[0][0];
103 if (evt.getOldValue() instanceof ScilabDouble && !((ScilabDouble) evt.getOldValue()).isEmpty()) {
104 oldIndex = (int) ((ScilabDouble) evt.getOldValue()).getRealPart()[0][0];
109 ioBlock.setValue(newIndex);
111 if (ioBlock.getParentDiagram() != null) {
112 ioBlock.getParentDiagram().fireEvent(
113 new mxEventObject(XcosEvent.IO_PORT_VALUE_UPDATED, "block", ioBlock, "oldIndex", oldIndex, "newIndex", newIndex));
121 * Implement a listener to update the
122 * {@link ContextUpdate#isContextDependent} flag.
123 @SuppressWarnings(value = { "serial" })
125 private static final class ExprsChangeAdapter implements PropertyChangeListener, Serializable {
126 private static final Pattern INTEGER_PATTERN = Pattern.compile("\\d+");
128 private static ExprsChangeAdapter instance;
131 * Default constructor
133 public ExprsChangeAdapter() {
137 * @return the shared instance
139 public static ExprsChangeAdapter getInstance() {
140 if (instance == null) {
141 instance = new ExprsChangeAdapter();
147 * isContextDependant field
151 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
154 public void propertyChange(final PropertyChangeEvent evt) {
155 final ScilabType data = (ScilabType) evt.getNewValue();
156 final ContextUpdate ioBlock = (ContextUpdate) evt.getSource();
158 if (!data.isEmpty()) {
159 final String newIndex = ((ScilabString) data).getData()[0][0];
161 if (!INTEGER_PATTERN.matcher(newIndex).matches()) {
162 ioBlock.isContextDependent = true;
164 ioBlock.isContextDependent = false;
171 * This enum represent all the subclasses of ContextUpdate .
173 * It is used to easily loop over a BasicBlock I/O blocks
175 public static enum IOBlocks {
176 /** Map a control port to an event input block */
177 EventInBlock(EventInBlock.class, ControlPort.class, CommandPort.class, ControlPort.class),
178 /** Map a command port to an event output block */
179 EventOutBlock(EventOutBlock.class, CommandPort.class, ControlPort.class, CommandPort.class),
180 /** Map an explicit input port to an explicit input block */
181 ExplicitInBlock(ExplicitInBlock.class, ExplicitInputPort.class, ExplicitOutputPort.class, InputPort.class),
182 /** Map an explicit output port to an explicit output block */
183 ExplicitOutBlock(ExplicitOutBlock.class, ExplicitOutputPort.class, ExplicitInputPort.class, OutputPort.class),
184 /** Map an implicit input port to an implicit input block */
185 ImplicitInBlock(ImplicitInBlock.class, ImplicitInputPort.class, ImplicitOutputPort.class, InputPort.class),
186 /** Map an implicit output port to an implicit output block */
187 ImplicitOutBlock(ImplicitOutBlock.class, ImplicitOutputPort.class, ImplicitInputPort.class, OutputPort.class);
189 private final Class <? extends ContextUpdate > ioBlock;
190 private final Class <? extends BasicPort > port;
191 private final Class <? extends BasicPort > opposite;
192 private final Class <? extends BasicPort > assignement;
198 * the associated port class
200 * the opposite port class
202 private IOBlocks(Class <? extends ContextUpdate > ioBlock, Class <? extends BasicPort > port, Class <? extends BasicPort > opposite,
203 Class <? extends BasicPort > assignement) {
204 this.ioBlock = ioBlock;
206 this.opposite = opposite;
207 this.assignement = assignement;
211 * Get all the port of the SuperBlock parent.
215 * @return the port list mapped by port type
217 public static Map<IOBlocks, List<mxICell>> getAllPorts(SuperBlock parent) {
218 final EnumMap<IOBlocks, List<mxICell>> ret = new EnumMap<IOBlocks, List<mxICell>>(IOBlocks.class);
221 for (IOBlocks b : IOBlocks.values()) {
222 ret.put(b, new ArrayList<mxICell>());
225 /* Loop all over the children */
226 final int childCount = parent.getChildCount();
228 for (int i = 0; i < childCount; i++) {
229 final mxICell child = parent.getChildAt(i);
231 /* if compatible add it to the list */
232 for (IOBlocks b : IOBlocks.values()) {
233 if (child.getClass().equals(b.getReferencedPortClass())) {
234 ret.get(b).add(child);
243 * Get the ports of the super blocks with kind klass
246 * the parent {@link SuperBlock}
249 * @return the list of ports
251 public static List<mxICell> getPorts(SuperBlock parent, Class <? extends ContextUpdate > klass) {
252 List<mxICell> ret = new ArrayList<mxICell>();
254 /* Get the corresponding klass */
255 Class <? extends BasicPort > portKlass = null;
256 for (IOBlocks b : IOBlocks.values()) {
257 if (b.getReferencedClass().equals(klass)) {
258 portKlass = b.getAssignementCompatiblePortClass();
263 /* Loop all over the children */
264 final int childCount = parent.getChildCount();
266 for (int i = 0; i < childCount; i++) {
267 final mxICell child = parent.getChildAt(i);
269 if (portKlass.isInstance(child)) {
278 * Return the opposite of the port
282 * @return the opposite of klass
284 public static Class <? extends BasicPort > getOpposite(Class <? extends BasicPort > klass) {
285 for (IOBlocks b : IOBlocks.values()) {
286 if (b.getReferencedPortClass() == klass) {
287 return b.getOppositeClass();
294 * Get all the I/O blocks of the SuperBlock parent.
298 * @return the port list mapped by port type
300 public static Map<IOBlocks, List<BasicBlock>> getAllBlocks(SuperBlock parent) {
301 final EnumMap<IOBlocks, List<BasicBlock>> ret = new EnumMap<IOBlocks, List<BasicBlock>>(IOBlocks.class);
303 SuperBlockDiagram graph = parent.getChild();
305 parent.createChildDiagram(true);
306 graph = parent.getChild();
310 for (IOBlocks b : IOBlocks.values()) {
311 ret.put(b, new ArrayList<BasicBlock>());
314 /* Loop all over the children */
315 final mxIGraphModel defaultModel = graph.getModel();
316 mxGraphModel.filterDescendants(defaultModel, new mxGraphModel.Filter() {
318 public boolean filter(Object cell) {
319 if (cell instanceof BasicBlock) {
320 final BasicBlock block = (BasicBlock) cell;
321 /* if compatible add it to the list */
322 for (IOBlocks b : IOBlocks.values()) {
323 if (block.getClass().equals(b.getReferencedClass())) {
324 ret.get(b).add(block);
336 * Create a corresponding I/O block
339 * the port used as an output
340 * @return the corresponding block
342 public static ContextUpdate createBlock(BasicPort port) {
343 for (IOBlocks io : IOBlocks.values()) {
344 if (io.getReferencedPortClass().isInstance(port)) {
346 ContextUpdate block = io.getReferencedClass().newInstance();
347 block.addPort(io.getOppositeClass().newInstance());
350 } catch (InstantiationException e) {
351 Logger.getLogger(IOBlocks.class.getName()).severe(e.toString());
352 } catch (IllegalAccessException e) {
353 Logger.getLogger(IOBlocks.class.getName()).severe(e.toString());
362 * @return referenced class
364 public Class <? extends ContextUpdate > getReferencedClass() {
369 * @return the port referenced class
371 public Class <? extends BasicPort > getReferencedPortClass() {
375 public Class <? extends BasicPort > getAssignementCompatiblePortClass() {
380 * @return the port opposite class
382 public Class <? extends BasicPort > getOppositeClass() {
387 private transient boolean isContextDependent;
392 public ContextUpdate() {
395 getParametersPCS().addPropertyChangeListener(INTEGER_PARAMETERS, IndexChangeAdapter.getInstance());
396 getParametersPCS().addPropertyChangeListener(EXPRS, ExprsChangeAdapter.getInstance());
400 * Initialize the block with the default values
403 protected void setDefaultValues() {
404 super.setDefaultValues();
407 * Update the default parameters accordingly to the reference instance
409 getGeometry().setHeight(DEFAULT_HEIGHT);
410 getGeometry().setWidth(DEFAULT_WIDTH);
413 * Fill parameters with non empty values.
415 setNbZerosCrossing(new ScilabDouble(0));
416 setNmode(new ScilabDouble(0));
417 setODState(new ScilabList());
418 setRealParameters(new ScilabDouble());
419 setObjectsParameters(new ScilabDouble());
428 public void onContextChange(String[] context) {
429 // prevent to open twice
434 // do not evaluate context is the block is not context dependent.
435 if (!isContextDependent) {
439 LOG_LOCAL.finest("Update the I/O value from the context");
441 final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
442 if (handler == null) {
448 handler.writeBlock(this);
450 handler.writeContext(context);
452 String cmd = ScilabInterpreterManagement.buildCall("blk = xcosBlockEval", getInterfaceFunctionName().toCharArray(),
453 ScilabDirectHandler.BLK.toCharArray(), ScilabDirectHandler.CONTEXT.toCharArray());
456 ScilabInterpreterManagement.synchronousScilabExec(cmd);
457 } catch (InterpreterException e) {
460 BasicBlock modifiedBlock = handler.readBlock();
461 updateBlockSettings(modifiedBlock);
463 } catch (ScicosFormatException e) {
464 LOG_LOCAL.severe(e.toString());