2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
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
13 package org.scilab.modules.xcos.block;
15 import java.awt.MouseInfo;
16 import java.awt.event.ActionEvent;
17 import java.awt.event.ActionListener;
18 import java.beans.PropertyChangeEvent;
19 import java.beans.PropertyChangeListener;
20 import java.beans.PropertyChangeSupport;
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.Deque;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.LinkedList;
30 import java.util.List;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
36 import org.scilab.modules.action_binding.InterpreterManagement;
37 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
38 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
39 import org.scilab.modules.graph.ScilabGraph;
40 import org.scilab.modules.graph.ScilabGraphUniqueObject;
41 import org.scilab.modules.graph.actions.CopyAction;
42 import org.scilab.modules.graph.actions.CutAction;
43 import org.scilab.modules.graph.actions.DeleteAction;
44 import org.scilab.modules.graph.actions.base.DefaultAction;
45 import org.scilab.modules.graph.utils.ScilabGraphConstants;
46 import org.scilab.modules.graph.utils.StyleMap;
47 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
48 import org.scilab.modules.gui.contextmenu.ContextMenu;
49 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
50 import org.scilab.modules.gui.events.callback.CommonCallBack;
51 import org.scilab.modules.gui.menu.Menu;
52 import org.scilab.modules.gui.menu.ScilabMenu;
53 import org.scilab.modules.gui.menuitem.MenuItem;
54 import org.scilab.modules.gui.menuitem.ScilabMenuItem;
55 import org.scilab.modules.types.ScilabDouble;
56 import org.scilab.modules.types.ScilabList;
57 import org.scilab.modules.types.ScilabString;
58 import org.scilab.modules.types.ScilabType;
59 import org.scilab.modules.xcos.Xcos;
60 import org.scilab.modules.xcos.XcosTab;
61 import org.scilab.modules.xcos.actions.EditFormatAction;
62 import org.scilab.modules.xcos.actions.ShowHideShadowAction;
63 import org.scilab.modules.xcos.block.actions.BlockDocumentationAction;
64 import org.scilab.modules.xcos.block.actions.BlockParametersAction;
65 import org.scilab.modules.xcos.block.actions.BorderColorAction;
66 import org.scilab.modules.xcos.block.actions.FilledColorAction;
67 import org.scilab.modules.xcos.block.actions.FlipAction;
68 import org.scilab.modules.xcos.block.actions.MirrorAction;
69 import org.scilab.modules.xcos.block.actions.RegionToSuperblockAction;
70 import org.scilab.modules.xcos.block.actions.RotateAction;
71 import org.scilab.modules.xcos.block.actions.ViewDetailsAction;
72 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockAction;
73 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionBottom;
74 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionCenter;
75 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionLeft;
76 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionMiddle;
77 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionRight;
78 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionTop;
79 import org.scilab.modules.xcos.graph.PaletteDiagram;
80 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
81 import org.scilab.modules.xcos.graph.XcosDiagram;
82 import org.scilab.modules.xcos.io.scicos.BasicBlockInfo;
83 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
84 import org.scilab.modules.xcos.io.scicos.ScilabDirectHandler;
85 import org.scilab.modules.xcos.port.BasicPort;
86 import org.scilab.modules.xcos.port.command.CommandPort;
87 import org.scilab.modules.xcos.port.control.ControlPort;
88 import org.scilab.modules.xcos.port.input.InputPort;
89 import org.scilab.modules.xcos.port.output.OutputPort;
90 import org.scilab.modules.xcos.utils.BlockPositioning;
91 import org.scilab.modules.xcos.utils.XcosConstants;
92 import org.scilab.modules.xcos.utils.XcosEvent;
93 import org.scilab.modules.xcos.utils.XcosMessages;
95 import com.mxgraph.model.mxGeometry;
96 import com.mxgraph.model.mxICell;
97 import com.mxgraph.model.mxIGraphModel;
98 import com.mxgraph.util.mxConstants;
99 import com.mxgraph.util.mxEventObject;
100 import com.mxgraph.util.mxUtils;
103 * A block on the diagram
105 // CSOFF: ClassDataAbstractionCoupling
106 // CSOFF: ClassFanOutComplexity
107 @SuppressWarnings(value = { "serial" })
108 public class BasicBlock extends ScilabGraphUniqueObject implements Serializable {
110 * Sorted kind of input, useful to sort them by kind
112 private static final Class<?>[] sortedChildrenClass = {InputPort.class, OutputPort.class, ControlPort.class, CommandPort.class, Object.class};
119 * Property name of interfaceFunctionName
121 public static final String INTERFACE_FUNCTION_NAME = "interfaceFunctionName";
123 * Property name of simulationFunctionName
125 public static final String SIMULATION_FUNCTION_NAME = "simulationFunctionName";
127 * Property name of simulationFunctionType
129 public static final String SIMULATION_FUNCTION_TYPE = "simulationFunctionType";
131 * Property name of realParameters
133 public static final String REAL_PARAMETERS = "realParameters";
135 * Property name of integerParameters
137 public static final String INTEGER_PARAMETERS = "integerParameters";
139 * Property name of objectsParameters
141 public static final String OBJECTS_PARAMETERS = "objectsParameters";
143 * Property name of dependsOnU
145 public static final String DEPENDS_ON_U = "dependsOnU";
147 * Property name of dependsOnT
149 public static final String DEPENDS_ON_T = "dependsOnT";
151 * Property name of blockType
153 public static final String BLOCK_TYPE = "blockType";
155 * Property name of ordering
157 public static final String ORDERING = "ordering";
159 * Property name of exprs
161 public static final String EXPRS = "exprs";
163 * Property name of nbZerosCrossing
165 public static final String NB_ZEROS_CROSSING = "nbZerosCrossing";
167 * Property name of nmode
169 public static final String NMODE = "nmode";
171 * Property name of state
173 public static final String STATE = "state";
175 * Property name of dState
177 public static final String D_STATE = "dState";
179 * Property name of oDState
181 public static final String O_D_STATE = "oDState";
183 * Property name of equations
185 public static final String EQUATIONS = "equations";
192 * Default interface function name
194 public static final String DEFAULT_INTERFACE_FUNCTION = "xcos_block";
196 * Default simulation function name
198 public static final String DEFAULT_SIMULATION_FUNCTION = "xcos_simulate";
204 private static final String PARENT_DIAGRAM_WAS_NULL = "Parent diagram was null";
205 private static final double DEFAULT_POSITION_X = 10.0;
206 private static final double DEFAULT_POSITION_Y = 10.0;
207 private static final double DEFAULT_WIDTH = 40.0;
208 private static final double DEFAULT_HEIGHT = 40.0;
210 private static final PropertyChangeListener STYLE_UPDATER = new UpdateStyleFromInterfunction();
211 private static final Logger LOG = Logger.getLogger(BasicBlock.class.getName());
214 * Sort the children list in place.
216 * The sort put inputs then outputs the control then command ports. The
217 * local port order is preserved.The sort is performed in place and do not
222 * the children to sort
224 public static final void sort(List<?> children) {
225 final List<Object> reference = new ArrayList<Object>(children);
227 Collections.sort(children, new Comparator<Object>() {
229 public int compare(Object o1, Object o2) {
230 // diff is the major sorting by kind
231 int diff = compareByChildClass(o1, o2);
233 if (o1 instanceof BasicPort && o2 instanceof BasicPort) {
234 // first sort with the port list index
235 final int diffIndexOf = Integer.signum(reference.indexOf(o1) - reference.indexOf(o2));
236 // then sort with the ordering value
237 final int diffOrdering = Integer.signum(((BasicPort) o1).getOrdering() - ((BasicPort) o2).getOrdering());
238 // then sort with the port position value
239 final mxGeometry o1Geom = ((BasicPort) o1).getGeometry();
240 final mxGeometry o2Geom = ((BasicPort) o2).getGeometry();
241 final int diffPosition = Integer.signum((int) (o2Geom.getX() - o1Geom.getX() - o2Geom.getY() + o1Geom.getY()));
243 // voting is performed with these equivalent 3 selector
244 diff = diff + diffIndexOf + diffOrdering + diffPosition;
253 * Internal method to get a base index to compare with depending on the cell
258 * @return the base index
260 private static final int compareByChildClass(final Object o1, final Object o2) {
264 for (int i = 0; i < sortedChildrenClass.length; i++) {
265 final Class<?> klass = sortedChildrenClass[i];
267 if (klass.isInstance(o1)) {
272 for (int i = 0; i < sortedChildrenClass.length; i++) {
273 final Class<?> klass = sortedChildrenClass[i];
275 if (klass.isInstance(o2)) {
281 final int base = o1Index - o2Index;
282 return base * (Integer.MAX_VALUE / sortedChildrenClass.length);
286 * Manage events for block parameters.
288 * The property name is the field name, is one of:
290 * <li>"interfaceFunctionName"
291 * <li>"simulationFunctionName"
292 * <li>"simulationFunctionType"
294 * <li>"realParameters"
295 * <li>"integerParameters"
296 * <li>"objectsParameters"
297 * <li>"nbZerosCrossing"
309 * you can easily access to then by using property name constants.
311 private PropertyChangeSupport parametersPCS = new PropertyChangeSupport(this);
313 private String interfaceFunctionName = DEFAULT_INTERFACE_FUNCTION;
314 private String simulationFunctionName = DEFAULT_SIMULATION_FUNCTION;
315 private SimulationFunctionType simulationFunctionType = SimulationFunctionType.DEFAULT;
316 private transient XcosDiagram parentDiagram;
319 private boolean isFlipped;
320 private boolean isMirrored;
322 // TODO : Must make this types evolve, but for now keep a strong link to
325 // exprs = [] ; rpar = [] ; ipar = [] ; opar = list()
327 // private List<String> exprs = new ArrayList<String>();
328 private ScilabType exprs;
329 // private List<Double> realParameters = new ArrayList<Double>();
330 private ScilabType realParameters;
331 // private List<Integer> integerParameters = new ArrayList<Integer>();
332 private ScilabType integerParameters;
333 // private List objectsParameters = new ArrayList();
334 private ScilabType objectsParameters;
336 private ScilabType nbZerosCrossing = new ScilabDouble();
338 private ScilabType nmode = new ScilabDouble();
340 private ScilabType state = new ScilabDouble();
341 private ScilabType dState = new ScilabDouble();
342 private ScilabType oDState = new ScilabDouble();
344 private ScilabType equations;
346 private boolean dependsOnU;
347 private boolean dependsOnT;
349 private String blockType = "c";
351 private int ordering;
352 private boolean locked;
355 * Represent a simulation function type compatible with Scilab/Scicos
356 * function type descriptors.
358 public static enum SimulationFunctionType {
359 /** event select; reduced at compilation */
361 /** if then else; reduced at compilation */
363 /** first common block */
365 /** first native block */
367 /** second native block */
369 /** third native block */
371 /** forth native block */
377 /** Modelica {@link #C_OR_FORTRAN} blocks */
381 /** Implicit {@link #TYPE_1} blocks */
383 /** Implicit {@link #C_OR_FORTRAN} blocks */
384 IMPLICIT_C_OR_FORTRAN(10004.0);
386 private double value;
389 * Default constructor
392 * Scilab/Scicos function type descriptor
394 private SimulationFunctionType(double scilabValue) {
399 * Get the Java descriptor from the Scilab descriptor.
402 * Scilab/Scicos function type descriptor
403 * @return The corresponding java descriptor
405 public static SimulationFunctionType convertScilabValue(int scilabValue) {
406 for (SimulationFunctionType iter : SimulationFunctionType.values()) {
407 if (iter.getAsDouble() == scilabValue) {
415 * Get the Scilab Descriptor from the Java Descriptor
417 * @return The corresponding Scilab/Scicos descriptor
419 public double getAsDouble() {
425 * Update the source block when the interfunction change.
427 private static final class UpdateStyleFromInterfunction implements PropertyChangeListener, Serializable {
430 * Default constructor.
432 public UpdateStyleFromInterfunction() {
436 * Update the label on interfunction change.
439 * the property change event.
440 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
443 public void propertyChange(PropertyChangeEvent evt) {
444 final BasicBlock source = (BasicBlock) evt.getSource();
447 * Put the interfunction at the start of the style map to preserve
448 * style modification.
450 * oldStyle="SUPER_f;fillColor=red" newStyle="DSUPER;fillColor=red"
452 * and not newStyle="fillColor=red;DSUPER"
454 final StyleMap style = new StyleMap((String) evt.getNewValue());
455 style.putAll(source.getStyle());
456 style.remove(evt.getOldValue());
458 source.setStyle(style.toString());
464 * Trace the parameters change on the {@link Logger}.
466 * This listener is only installed if the trace is enable.
468 private static final class TraceParametersListener implements PropertyChangeListener, Serializable {
469 private static TraceParametersListener instance;
472 * Default constructor.
474 private TraceParametersListener() {
479 * @return the instance
481 public static TraceParametersListener getInstance() {
482 if (instance == null) {
483 instance = new TraceParametersListener();
493 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
496 public void propertyChange(PropertyChangeEvent evt) {
497 if (LOG.isLoggable(Level.FINEST)) {
498 LOG.finest(evt.getPropertyName() + ": " + evt.getOldValue() + ", " + evt.getNewValue());
504 * Default constructor.
506 public BasicBlock() {
512 if (getStyle().isEmpty() && !getInterfaceFunctionName().isEmpty()) {
513 setStyle(getInterfaceFunctionName());
516 parametersPCS.addPropertyChangeListener(INTERFACE_FUNCTION_NAME, STYLE_UPDATER);
519 * Trace block parameters change if applicable.
521 if (LOG.isLoggable(Level.FINEST)) {
522 parametersPCS.addPropertyChangeListener(TraceParametersListener.getInstance());
530 protected BasicBlock(String label) {
541 protected BasicBlock(String label, String style) {
547 * Initialize the block with the default values
549 protected void setDefaultValues() {
552 setConnectable(false);
553 setGeometry(new mxGeometry(DEFAULT_POSITION_X, DEFAULT_POSITION_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT));
559 * @return parent diagram
561 public XcosDiagram getParentDiagram() {
562 return parentDiagram;
566 * @param parentDiagram
569 public void setParentDiagram(XcosDiagram parentDiagram) {
570 this.parentDiagram = parentDiagram;
574 * @return interface function name
576 public String getInterfaceFunctionName() {
577 return interfaceFunctionName;
581 * @param interfaceFunctionName
582 * interface function name
584 public void setInterfaceFunctionName(String interfaceFunctionName) {
585 if ((this.interfaceFunctionName == null && interfaceFunctionName != null) || !this.interfaceFunctionName.equals(interfaceFunctionName)) {
587 final String oldValue = this.interfaceFunctionName;
588 this.interfaceFunctionName = interfaceFunctionName;
589 parametersPCS.firePropertyChange(INTERFACE_FUNCTION_NAME, oldValue, interfaceFunctionName);
594 * @param simulationFunctionName
595 * sumulation function name
597 public void setSimulationFunctionName(String simulationFunctionName) {
598 if ((this.simulationFunctionName == null && simulationFunctionName != null) || !this.simulationFunctionName.equals(simulationFunctionName)) {
600 final String oldValue = this.simulationFunctionName;
601 this.simulationFunctionName = simulationFunctionName;
602 parametersPCS.firePropertyChange(SIMULATION_FUNCTION_NAME, oldValue, simulationFunctionName);
607 * @return sumulation function name
609 public String getSimulationFunctionName() {
610 return simulationFunctionName;
615 * simulation function type
617 public void setSimulationFunctionType(int scilabValue) {
618 SimulationFunctionType simFunctionType = SimulationFunctionType.convertScilabValue(scilabValue);
619 setSimulationFunctionType(simFunctionType);
623 * @param simulationFunctionType
624 * simulation function type
626 public void setSimulationFunctionType(SimulationFunctionType simulationFunctionType) {
627 if ((this.simulationFunctionType == null && simulationFunctionType != null) || !this.simulationFunctionType.equals(simulationFunctionType)) {
629 final SimulationFunctionType oldValue = this.simulationFunctionType;
630 this.simulationFunctionType = simulationFunctionType;
631 parametersPCS.firePropertyChange(SIMULATION_FUNCTION_TYPE, oldValue, simulationFunctionType);
636 * @return simulation function type
638 public SimulationFunctionType getSimulationFunctionType() {
639 return simulationFunctionType;
643 * @return real parameter ( rpar )
645 public ScilabType getRealParameters() {
646 return realParameters;
650 * @param realParameters
651 * reaL parameter ( rpar )
653 public void setRealParameters(ScilabType realParameters) {
654 if ((this.realParameters == null && realParameters != null) || !this.realParameters.equals(realParameters)) {
656 final ScilabType oldValue = this.realParameters;
657 this.realParameters = realParameters;
658 parametersPCS.firePropertyChange(REAL_PARAMETERS, oldValue, realParameters);
663 * @return integer parameter ( ipar )
665 public ScilabType getIntegerParameters() {
666 return integerParameters;
670 * @param integerParameters
671 * integer parameter ( ipar )
673 public void setIntegerParameters(ScilabType integerParameters) {
674 if ((this.integerParameters == null && integerParameters != null) || !this.integerParameters.equals(integerParameters)) {
676 final ScilabType oldValue = this.integerParameters;
677 this.integerParameters = integerParameters;
678 parametersPCS.firePropertyChange(INTEGER_PARAMETERS, oldValue, integerParameters);
683 * @return object parameter ( opar )
685 public ScilabType getObjectsParameters() {
686 return objectsParameters;
690 * @param objectsParameters
691 * object parameter ( opar )
693 public void setObjectsParameters(ScilabType objectsParameters) {
694 if ((this.objectsParameters == null && objectsParameters != null) || !this.objectsParameters.equals(objectsParameters)) {
696 final ScilabType oldValue = this.objectsParameters;
697 this.objectsParameters = objectsParameters;
698 parametersPCS.firePropertyChange(OBJECTS_PARAMETERS, oldValue, objectsParameters);
706 public void setDependsOnU(boolean dependsOnU) {
707 if (this.dependsOnU != dependsOnU) {
709 final boolean oldValue = this.dependsOnU;
710 this.dependsOnU = dependsOnU;
711 parametersPCS.firePropertyChange(DEPENDS_ON_U, oldValue, dependsOnU);
718 public boolean isDependsOnU() {
726 public void setDependsOnT(boolean dependsOnT) {
727 if (this.dependsOnT != dependsOnT) {
729 final boolean oldValue = this.dependsOnT;
730 this.dependsOnT = dependsOnT;
731 parametersPCS.firePropertyChange(DEPENDS_ON_T, oldValue, dependsOnT);
738 public boolean isDependsOnT() {
746 public void setBlockType(String blockType) {
747 if ((this.blockType == null && blockType != null) || !this.blockType.equals(blockType)) {
749 final String oldValue = this.blockType;
750 this.blockType = blockType;
751 parametersPCS.firePropertyChange(BLOCK_TYPE, oldValue, blockType);
758 public String getBlockType() {
766 public void setOrdering(int ordering) {
767 if (this.ordering != ordering) {
769 final int oldValue = this.ordering;
770 this.ordering = ordering;
771 parametersPCS.firePropertyChange(ORDERING, oldValue, ordering);
776 * @return order value
778 public int getOrdering() {
786 public void setExprs(ScilabType exprs) {
787 if ((this.exprs == null && exprs != null) || !this.exprs.equals(exprs)) {
789 final ScilabType oldValue = this.exprs;
791 parametersPCS.firePropertyChange(EXPRS, oldValue, exprs);
798 public ScilabType getExprs() {
803 * @return the expression as an object array
805 public Object[] getExprsFormat() {
806 // evaluate emptiness
807 if (getExprs() == null || getExprs().isEmpty() || getExprs().getHeight() == 0 || getExprs().getWidth() == 0) {
808 return new String[0];
811 List<String[]> stack = getString(null, getExprs());
814 for (Object[] strings : stack) {
815 len += strings.length;
818 final Object[] array = new Object[len];
820 for (Object[] strings : stack) {
821 System.arraycopy(strings, 0, array, start, strings.length);
822 start += strings.length;
829 * Append the data recursively to the stack
831 * @param currentStack
837 private List<String[]> getString(List<String[]> currentStack, ScilabType data) {
838 final List<String[]> stack;
840 if (currentStack == null) {
841 stack = new LinkedList<String[]>();
843 stack = currentStack;
846 if (data instanceof List) {
848 * Container case (ScilabList, ScilabMList, ScilabTList)
851 @SuppressWarnings("unchecked")
852 final List<ScilabType> list = (List<ScilabType>) data;
854 for (final ScilabType scilabType : list) {
855 getString(stack, scilabType);
857 } else if (data instanceof ScilabString) {
859 * native case (only ScilabString supported)
862 final String[][] scilabData = ((ScilabString) data).getData();
863 final int height = data.getHeight();
864 final int width = data.getWidth();
866 final String[] array = new String[height * width];
867 for (int i = 0; i < height; ++i) {
868 System.arraycopy(scilabData[i], 0, array, i * width, width);
878 * @return zero crossing value
880 public ScilabType getNbZerosCrossing() {
881 return nbZerosCrossing;
885 * @param nbZerosCrossing
886 * zero crossing value
888 public void setNbZerosCrossing(ScilabType nbZerosCrossing) {
889 if ((this.nbZerosCrossing == null && nbZerosCrossing != null) || !this.nbZerosCrossing.equals(nbZerosCrossing)) {
891 final ScilabType oldValue = this.nbZerosCrossing;
892 this.nbZerosCrossing = nbZerosCrossing;
893 parametersPCS.firePropertyChange(NB_ZEROS_CROSSING, oldValue, nbZerosCrossing);
900 public ScilabType getNmode() {
908 public void setNmode(ScilabType nmode) {
909 if ((this.nmode == null && nmode != null) || !this.nmode.equals(nmode)) {
911 final ScilabType oldValue = this.nmode;
913 parametersPCS.firePropertyChange(NMODE, oldValue, nmode);
918 * @return current state
920 public ScilabType getState() {
928 public void setState(ScilabType state) {
929 if ((this.state == null && state != null) || !this.state.equals(state)) {
931 final ScilabType oldValue = this.state;
933 parametersPCS.firePropertyChange(STATE, oldValue, state);
938 * @return current dstate
940 public ScilabType getDState() {
948 public void setDState(ScilabType dState) {
949 if ((this.dState == null && dState != null) || !this.dState.equals(dState)) {
951 final ScilabType oldValue = this.dState;
952 this.dState = dState;
953 parametersPCS.firePropertyChange(D_STATE, oldValue, dState);
958 * @return current ostate
960 public ScilabType getODState() {
968 public void setODState(ScilabType oDState) {
969 if ((this.oDState == null && oDState != null) || !this.oDState.equals(oDState)) {
971 final ScilabType oldValue = this.oDState;
972 this.oDState = oDState;
973 parametersPCS.firePropertyChange(O_D_STATE, oldValue, oDState);
980 public ScilabType getEquations() {
988 public void setEquations(ScilabType equations) {
989 if ((this.equations == null && equations != null) || !this.equations.equals(equations)) {
991 final ScilabType oldValue = this.equations;
992 this.equations = equations;
993 parametersPCS.firePropertyChange(EQUATIONS, oldValue, equations);
998 * @return locked status
1000 public synchronized boolean isLocked() {
1006 * change locked status
1008 public synchronized void setLocked(boolean locked) {
1009 this.locked = locked;
1016 public void removePort(BasicPort port) {
1017 if (port.getEdgeCount() != 0 && getParentDiagram() != null) {
1018 getParentDiagram().removeCells(new Object[] { port.getEdgeAt(0) });
1024 * Add a port on the block.
1026 * This call should only be used when a port reordering operation must be
1030 * The port to be added to the block
1032 public void addPort(BasicPort port) {
1034 port.setOrdering(BasicBlockInfo.getAllTypedPorts(this, false, port.getClass()).size());
1035 BlockPositioning.updateBlockView(this);
1039 * @return command ports initial state
1041 public ScilabDouble getAllCommandPortsInitialStates() {
1042 final List<CommandPort> cmdPorts = BasicBlockInfo.getAllTypedPorts(this, false, CommandPort.class);
1043 if (cmdPorts.isEmpty()) {
1044 return new ScilabDouble();
1047 double[][] data = new double[cmdPorts.size()][1];
1048 for (int i = 0; i < cmdPorts.size(); ++i) {
1049 data[i][0] = cmdPorts.get(i).getInitialState();
1052 return new ScilabDouble(data);
1056 * @return name and type of the simulation function
1058 public ScilabType getSimulationFunctionNameAndType() {
1059 if (getSimulationFunctionType() == SimulationFunctionType.DEFAULT) {
1060 return new ScilabString(getSimulationFunctionName());
1062 ScilabList data = new ScilabList();
1064 data.add(new ScilabString(getSimulationFunctionName()));
1065 data.add(new ScilabDouble(getSimulationFunctionType().getAsDouble()));
1071 * Does the block update and register on the undo manager
1073 * @param modifiedBlock
1076 public void updateBlockSettings(BasicBlock modifiedBlock) {
1077 if (modifiedBlock == null) {
1082 * Update the block settings
1084 updateFields(modifiedBlock);
1087 * Update the children ports
1089 updateChildren(modifiedBlock);
1092 * If the block is in a superblock then update it.
1094 if (getParentDiagram() instanceof SuperBlockDiagram) {
1095 SuperBlock block = ((SuperBlockDiagram) getParentDiagram()).getContainer();
1097 XcosDiagram graph = block.getParentDiagram();
1098 if (graph == null) {
1099 setParentDiagram(Xcos.findParent(block));
1100 graph = block.getParentDiagram();
1101 LOG.finest(PARENT_DIAGRAM_WAS_NULL);
1104 graph.fireEvent(new mxEventObject(XcosEvent.SUPER_BLOCK_UPDATED, XcosConstants.EVENT_BLOCK_UPDATED, block));
1109 * Update the instance field.
1111 * @param modifiedBlock
1112 * the modified instance
1114 private void updateFields(BasicBlock modifiedBlock) {
1115 if (modifiedBlock == null) {
1119 setDependsOnT(modifiedBlock.isDependsOnT());
1120 setDependsOnU(modifiedBlock.isDependsOnU());
1121 setExprs(modifiedBlock.getExprs());
1123 setRealParameters(modifiedBlock.getRealParameters());
1124 setIntegerParameters(modifiedBlock.getIntegerParameters());
1125 setObjectsParameters(modifiedBlock.getObjectsParameters());
1127 setState(modifiedBlock.getState());
1128 setDState(modifiedBlock.getDState());
1129 setODState(modifiedBlock.getODState());
1131 setBlockType(modifiedBlock.getBlockType());
1132 setSimulationFunctionName(modifiedBlock.getSimulationFunctionName());
1133 setSimulationFunctionType(modifiedBlock.getSimulationFunctionType());
1135 setEquations(modifiedBlock.getEquations());
1136 setStyle(modifiedBlock.getStyle());
1140 * Update the children of the block.
1142 * @param modifiedBlock
1143 * the new block instance
1145 private void updateChildren(BasicBlock modifiedBlock) {
1146 if (modifiedBlock == null) {
1150 XcosDiagram graph = getParentDiagram();
1151 if (graph == null) {
1152 setParentDiagram(Xcos.findParent(this));
1153 graph = getParentDiagram();
1154 LOG.finest(PARENT_DIAGRAM_WAS_NULL);
1158 * Checked as port classes only
1160 @SuppressWarnings("unchecked")
1161 Set < Class <? extends mxICell >> types = new HashSet < Class <? extends mxICell >> (Arrays.asList(InputPort.class, OutputPort.class, ControlPort.class,
1162 CommandPort.class));
1164 Map < Class <? extends mxICell > , Deque<mxICell >> annotatedOlds = getTypedChildren(types);
1165 Map < Class <? extends mxICell > , Deque<mxICell >> annotatedNews = modifiedBlock.getTypedChildren(types);
1167 getParentDiagram().getModel().beginUpdate();
1169 for (Class <? extends mxICell > klass : types) {
1170 final Deque<mxICell> olds = annotatedOlds.get(klass);
1171 final Deque<mxICell> news = annotatedNews.get(klass);
1174 while (!olds.isEmpty() && !news.isEmpty()) {
1175 mxICell previous = olds.poll();
1176 mxICell modified = news.poll();
1178 final int previousIndex = children.indexOf(previous);
1181 if (previous.getEdgeCount() != 0) {
1182 final mxICell edge = previous.getEdgeAt(0);
1183 final boolean isOutgoing = previous == edge.getTerminal(true);
1184 previous.removeEdge(edge, isOutgoing);
1185 modified.insertEdge(edge, isOutgoing);
1188 getParentDiagram().removeCells(new Object[] { previous }, false);
1189 getParentDiagram().addCells(new Object[] { modified }, this, previousIndex);
1191 // Clone the geometry to avoid empty geometry on new cells.
1192 getParentDiagram().getModel().setGeometry(modified, (mxGeometry) previous.getGeometry().clone());
1197 if (!olds.isEmpty()) {
1198 getParentDiagram().removeCells(olds.toArray(), true);
1202 if (!news.isEmpty()) {
1203 getParentDiagram().addCells(news.toArray(), this);
1207 getParentDiagram().getModel().endUpdate();
1212 * Format the children as a typed map for the given class set.
1215 * the classes to search for.
1216 * @return a map which linked foreach type the corresponding cell list.
1218 private Map < Class <? extends mxICell > , Deque<mxICell >> getTypedChildren(Set < Class <? extends mxICell >> types) {
1219 Map < Class <? extends mxICell > , Deque<mxICell >> oldPorts = new HashMap < Class <? extends mxICell > , Deque<mxICell >> ();
1221 // Allocate all types set
1222 for (Class <? extends mxICell > type : types) {
1223 oldPorts.put(type, new LinkedList<mxICell>());
1226 if (getChildCount() <= 0) {
1230 // sort children according to the ordering parameter (useful on
1231 // scilab-5.2.x diagrams)
1235 for (Object cell : children) {
1237 Class <? extends Object > klass = cell.getClass();
1238 while (klass != null) {
1239 if (types.contains(klass)) {
1242 klass = klass.getSuperclass();
1245 final Deque<mxICell> current = oldPorts.get(klass);
1246 if (current != null) {
1247 current.add((mxICell) cell);
1255 * Sort the children list in place.
1257 * The sort put inputs then outputs the control then command ports. The
1258 * local port order is preserved.The sort is performed in place and do not
1261 public void sortChildren() {
1262 if (getChildCount() <= 0) {
1271 * parent diagram context
1273 public void openBlockSettings(String[] context) {
1274 final XcosDiagram graph;
1275 if (getParentDiagram() == null) {
1276 setParentDiagram(Xcos.findParent(this));
1277 graph = getParentDiagram();
1278 LOG.finest(PARENT_DIAGRAM_WAS_NULL);
1280 graph = getParentDiagram();
1282 if (graph instanceof PaletteDiagram) {
1286 if (context == null) {
1287 throw new IllegalArgumentException();
1290 // prevent to open twice
1295 // sort children according to the ordering parameter (useful on
1296 // scilab-5.2.x diagrams)
1299 final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
1300 if (handler == null) {
1306 handler.writeBlock(this);
1308 handler.writeContext(context);
1310 final ActionListener action = new ActionListener() {
1312 public void actionPerformed(ActionEvent e) {
1313 LOG.finest("Updating data.");
1315 graph.getView().clear(this, true, true);
1317 // Now read new Block
1318 graph.getModel().beginUpdate();
1320 final BasicBlock modifiedBlock = handler.readBlock();
1321 updateBlockSettings(modifiedBlock);
1323 graph.fireEvent(new mxEventObject(XcosEvent.ADD_PORTS, XcosConstants.EVENT_BLOCK_UPDATED, BasicBlock.this));
1324 } catch (ScicosFormatException ex) {
1325 LOG.severe(ex.toString());
1327 graph.getModel().endUpdate();
1336 ScilabInterpreterManagement.asynchronousScilabExec(action, "blk = xcosBlockInterface", getInterfaceFunctionName().toCharArray(), "set",
1337 ScilabDirectHandler.BLK.toCharArray(), ScilabDirectHandler.CONTEXT.toCharArray());
1338 } catch (InterpreterException e) {
1339 LOG.severe(e.toString());
1347 * @return tooltip text
1349 public String getToolTipText() {
1350 StringBuilder result = new StringBuilder();
1351 result.append(ScilabGraphConstants.HTML_BEGIN);
1352 result.append("Block Name : " + getInterfaceFunctionName() + ScilabGraphConstants.HTML_NEWLINE);
1353 result.append("Simulation : " + getSimulationFunctionName() + ScilabGraphConstants.HTML_NEWLINE);
1355 if (getParentDiagram() instanceof PaletteDiagram) {
1356 if (getIntegerParameters() != null) {
1357 result.append("Integer parameters : " + getIntegerParameters() + ScilabGraphConstants.HTML_NEWLINE);
1360 if (getRealParameters() != null && getRealParameters().getHeight() != 0 && getRealParameters().getWidth() != 0) {
1361 result.append("Real parameters : " + getRealParameters() + ScilabGraphConstants.HTML_NEWLINE);
1364 if (getObjectsParameters() != null) {
1365 result.append("Object parameters : " + getObjectsParameters() + ScilabGraphConstants.HTML_NEWLINE);
1368 result.append("UID : " + getId() + ScilabGraphConstants.HTML_NEWLINE);
1369 final int length = getStyle().length();
1370 result.append("Style : ");
1371 if (length > XcosConstants.MAX_CHAR_IN_STYLE) {
1372 result.append(getStyle().substring(0, XcosConstants.MAX_CHAR_IN_STYLE));
1373 result.append(XcosMessages.DOTS);
1375 result.append(getStyle());
1377 result.append(ScilabGraphConstants.HTML_NEWLINE);
1378 result.append("Flip : " + getFlip() + ScilabGraphConstants.HTML_NEWLINE);
1379 result.append("Mirror : " + getMirror() + ScilabGraphConstants.HTML_NEWLINE);
1380 result.append("Input ports : " + BasicBlockInfo.getAllTypedPorts(this, false, InputPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1381 result.append("Output ports : " + BasicBlockInfo.getAllTypedPorts(this, false, OutputPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1382 result.append("Control ports : " + BasicBlockInfo.getAllTypedPorts(this, false, ControlPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1383 result.append("Command ports : " + BasicBlockInfo.getAllTypedPorts(this, false, CommandPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1386 result.append("x : " + getGeometry().getX() + ScilabGraphConstants.HTML_NEWLINE);
1387 result.append("y : " + getGeometry().getY() + ScilabGraphConstants.HTML_NEWLINE);
1388 result.append("w : " + getGeometry().getWidth() + ScilabGraphConstants.HTML_NEWLINE);
1389 result.append("h : " + getGeometry().getHeight() + ScilabGraphConstants.HTML_NEWLINE);
1390 result.append(ScilabGraphConstants.HTML_END);
1391 return result.toString();
1398 public void openContextMenu(ScilabGraph graph) {
1399 ContextMenu menu = null;
1400 if (getParentDiagram() instanceof PaletteDiagram) {
1401 menu = createPaletteContextMenu(graph);
1403 menu = createContextMenu(graph);
1405 menu.setVisible(true);
1411 * @return context menu
1414 public ContextMenu createPaletteContextMenu(ScilabGraph graph) {
1415 ContextMenu menu = ScilabContextMenu.createContextMenu();
1417 final List<XcosDiagram> allDiagrams = Xcos.getInstance().openedDiagrams();
1419 if (allDiagrams.size() == 0) {
1420 // No diagram opened: should never happen if Xcos opens an empty
1421 // diagram when it is launched
1422 MenuItem addTo = ScilabMenuItem.createMenuItem();
1424 addTo.setText(XcosMessages.ADDTO_NEW_DIAGRAM);
1425 addTo.setCallback(new CommonCallBack(XcosMessages.ADDTO_NEW_DIAGRAM) {
1427 public void callBack() {
1429 XcosDiagram theDiagram = new XcosDiagram();
1430 BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1431 theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1432 mxGeometry geom = BasicBlock.this.getGeometry();
1433 setDefaultPosition(geom);
1434 theDiagram.getModel().setGeometry(block, geom);
1436 XcosTab.get(theDiagram).setVisible(true);
1437 BlockPositioning.updateBlockView(block);
1443 } else if (allDiagrams.size() == 1) {
1444 // A single diagram opened: add to this diagram
1445 MenuItem addTo = ScilabMenuItem.createMenuItem();
1447 addTo.setText(XcosMessages.ADDTO + " " + XcosTab.get(allDiagrams.get(0)).getName());
1448 final XcosDiagram theDiagram = allDiagrams.get(0);
1449 addTo.setCallback(new CommonCallBack(theDiagram.getTitle()) {
1450 private static final long serialVersionUID = -99601763227525686L;
1453 public void callBack() {
1454 BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1455 theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1456 mxGeometry geom = BasicBlock.this.getGeometry();
1457 setDefaultPosition(geom);
1458 theDiagram.getModel().setGeometry(block, geom);
1459 BlockPositioning.updateBlockView(block);
1460 block.setParentDiagram(theDiagram);
1467 // The user has to choose
1468 Menu addTo = ScilabMenu.createMenu();
1470 addTo.setText(XcosMessages.ADDTO);
1472 for (int i = 0; i < allDiagrams.size(); i++) {
1473 MenuItem diagram = ScilabMenuItem.createMenuItem();
1474 final XcosDiagram theDiagram = allDiagrams.get(i);
1475 diagram.setText(XcosTab.get(allDiagrams.get(i)).getName());
1476 diagram.setCallback(new CommonCallBack(theDiagram.getTitle()) {
1477 private static final long serialVersionUID = 3345416658377835057L;
1480 public void callBack() {
1481 BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1482 theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1483 mxGeometry geom = BasicBlock.this.getGeometry();
1484 setDefaultPosition(geom);
1485 theDiagram.getModel().setGeometry(block, geom);
1486 BlockPositioning.updateBlockView(block);
1495 menu.getAsSimpleContextMenu().addSeparator();
1497 MenuItem help = ScilabMenuItem.createMenuItem();
1498 help.setText(XcosMessages.BLOCK_DOCUMENTATION);
1499 help.setCallback(new CommonCallBack(XcosMessages.BLOCK_DOCUMENTATION) {
1500 private static final long serialVersionUID = -1480947262397441951L;
1503 public void callBack() {
1504 InterpreterManagement.requestScilabExec("help " + getInterfaceFunctionName());
1509 menu.setVisible(true);
1511 ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo()
1522 * @return context menu
1525 public ContextMenu createContextMenu(ScilabGraph graph) {
1526 ContextMenu menu = ScilabContextMenu.createContextMenu();
1527 Map < Class <? extends DefaultAction > , Menu > menuList = new HashMap < Class <? extends DefaultAction > , Menu > ();
1529 MenuItem value = BlockParametersAction.createMenu(graph);
1530 menuList.put(BlockParametersAction.class, value);
1533 menu.getAsSimpleContextMenu().addSeparator();
1535 value = CutAction.cutMenu(graph);
1536 menuList.put(CutAction.class, value);
1538 value = CopyAction.copyMenu(graph);
1539 menuList.put(CopyAction.class, value);
1541 value = DeleteAction.createMenu(graph);
1542 menuList.put(DeleteAction.class, value);
1545 menu.getAsSimpleContextMenu().addSeparator();
1547 value = RegionToSuperblockAction.createMenu(graph);
1548 menuList.put(RegionToSuperblockAction.class, value);
1551 menu.getAsSimpleContextMenu().addSeparator();
1553 Menu format = ScilabMenu.createMenu();
1554 format.setText(XcosMessages.FORMAT);
1556 value = RotateAction.createMenu(graph);
1557 menuList.put(RotateAction.class, value);
1559 value = MirrorAction.createMenu(graph);
1560 menuList.put(MirrorAction.class, value);
1562 value = FlipAction.createMenu(graph);
1563 menuList.put(FlipAction.class, value);
1565 value = ShowHideShadowAction.createMenu(graph);
1566 menuList.put(ShowHideShadowAction.class, value);
1569 format.addSeparator();
1571 Menu alignMenu = ScilabMenu.createMenu();
1572 alignMenu.setText(XcosMessages.ALIGN_BLOCKS);
1573 alignMenu.add(AlignBlockActionLeft.createMenu(graph));
1574 alignMenu.add(AlignBlockActionCenter.createMenu(graph));
1575 alignMenu.add(AlignBlockActionRight.createMenu(graph));
1576 alignMenu.addSeparator();
1577 alignMenu.add(AlignBlockActionTop.createMenu(graph));
1578 alignMenu.add(AlignBlockActionMiddle.createMenu(graph));
1579 alignMenu.add(AlignBlockActionBottom.createMenu(graph));
1580 menuList.put(AlignBlockAction.class, alignMenu);
1581 format.add(alignMenu);
1583 format.addSeparator();
1585 if (graph.getSelectionCells().length > 1) {
1586 format.add(BorderColorAction.createMenu(graph));
1587 format.add(FilledColorAction.createMenu(graph));
1589 format.add(EditFormatAction.createMenu(graph));
1592 menu.getAsSimpleContextMenu().addSeparator();
1594 menu.add(ViewDetailsAction.createMenu(graph));
1596 menu.getAsSimpleContextMenu().addSeparator();
1598 menu.add(BlockDocumentationAction.createMenu(graph));
1600 ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo()
1603 customizeMenu(menuList);
1614 public void setFlip(boolean flip) {
1616 if (getParentDiagram() != null) {
1617 final mxIGraphModel model = getParentDiagram().getModel();
1618 mxUtils.setCellStyles(model, new Object[] { this }, ScilabGraphConstants.STYLE_FLIP, Boolean.toString(flip));
1623 * Override this to customize contextual menu
1628 protected void customizeMenu(Map < Class <? extends DefaultAction > , Menu > menuList) {
1629 // To be overridden by sub-classes
1633 * @return mirror value
1635 public boolean getMirror() {
1643 public void setMirror(boolean mirror) {
1644 isMirrored = mirror;
1645 if (getParentDiagram() != null) {
1646 final mxIGraphModel model = getParentDiagram().getModel();
1647 mxUtils.setCellStyles(model, new Object[] { this }, ScilabGraphConstants.STYLE_MIRROR, Boolean.toString(mirror));
1652 * @return flip status
1654 public boolean getFlip() {
1659 * invert flip status
1661 public void toggleFlip() {
1662 BlockPositioning.toggleFlip(this);
1666 * invert mirror value
1668 public void toggleMirror() {
1669 BlockPositioning.toggleMirror(this);
1675 public void toggleAntiClockwiseRotation() {
1676 BlockPositioning.toggleAntiClockwiseRotation(this);
1681 * @return current angle
1683 public int getAngle() {
1691 public void setAngle(int angle) {
1694 if (getParentDiagram() != null) {
1695 mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] { this }, mxConstants.STYLE_ROTATION, Integer.toString(angle));
1700 * Useful when we need to update local properties with mxCell style
1703 public void updateFieldsFromStyle() {
1704 StyleMap map = new StyleMap(getStyle());
1706 if (map.get(mxConstants.STYLE_ROTATION) != null) {
1707 angle = Integer.parseInt(map.get(mxConstants.STYLE_ROTATION));
1712 isFlipped = Boolean.parseBoolean(map.get(ScilabGraphConstants.STYLE_FLIP));
1713 isMirrored = Boolean.parseBoolean(map.get(ScilabGraphConstants.STYLE_MIRROR));
1717 * Set the default block position on the geom
1722 private void setDefaultPosition(mxGeometry geom) {
1723 geom.setX(DEFAULT_POSITION_X);
1724 geom.setY(DEFAULT_POSITION_Y);
1728 * Get the parameters change support.
1730 * The property name for each event is the field name, so one of: -
1731 * "interfaceFunctionName" - "simulationFunctionName" -
1732 * "simulationFunctionType" - "exprs" - "realParameters" -
1733 * "integerParameters" - "objectsParameters" - "nbZerosCrossing" - "nmode" -
1734 * "state" - "dState" - "oDState" - "equations" - "dependsOnU" -
1735 * "dependsOnT" - "blockType" - "ordering"
1737 * @return the associated {@link PropertyChangeSupport} instance
1739 protected PropertyChangeSupport getParametersPCS() {
1740 return parametersPCS;
1744 * Overriden methods from jgraphx
1748 * @return always false
1749 * @see com.mxgraph.model.mxCell#isConnectable()
1752 public boolean isConnectable() {
1757 * Re-associate fields with the new instance.
1759 * @return a new clone instance
1760 * @throws CloneNotSupportedException
1762 * @see com.mxgraph.model.mxCell#clone()
1765 public Object clone() throws CloneNotSupportedException {
1766 BasicBlock clone = (BasicBlock) super.clone();
1768 /* Reinstall the PropertyChangeSupport and all of it listeners */
1769 clone.parametersPCS = new PropertyChangeSupport(clone);
1770 PropertyChangeSupport pcs = getParametersPCS();
1771 for (PropertyChangeListener iter : pcs.getPropertyChangeListeners()) {
1772 clone.parametersPCS.addPropertyChangeListener(iter);
1781 * Sync the specific child {@link EditFormatAction#HASH_IDENTIFIER}
1784 public mxICell insert(mxICell child, int index) {
1786 * Update the id if this is an identifier cell (herited identifier)
1788 if (child.getId().endsWith(XcosDiagram.HASH_IDENTIFIER)) {
1789 child.setId(getId() + XcosDiagram.HASH_IDENTIFIER);
1792 return super.insert(child, index);
1796 public String toString() {
1797 final StringBuilder str = new StringBuilder();
1798 str.append(getInterfaceFunctionName());
1800 for (Object c : children) {
1805 return str.toString();
1808 // CSON: ClassDataAbstractionCoupling
1809 // CSON: ClassFanOutComplexity