* Bug #13772 fixed - Xcos GUI was not locked while setting parameters.
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / BasicBlock.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
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.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.block;
14
15 import java.awt.Cursor;
16 import java.awt.MouseInfo;
17 import java.awt.event.ActionEvent;
18 import java.awt.event.ActionListener;
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21 import java.beans.PropertyChangeSupport;
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.Deque;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
36
37 import org.scilab.modules.action_binding.InterpreterManagement;
38 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
39 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement.InterpreterException;
40 import org.scilab.modules.graph.ScilabGraph;
41 import org.scilab.modules.graph.ScilabGraphUniqueObject;
42 import org.scilab.modules.graph.actions.CopyAction;
43 import org.scilab.modules.graph.actions.CutAction;
44 import org.scilab.modules.graph.actions.DeleteAction;
45 import org.scilab.modules.graph.actions.base.DefaultAction;
46 import org.scilab.modules.graph.utils.ScilabGraphConstants;
47 import org.scilab.modules.graph.utils.StyleMap;
48 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
49 import org.scilab.modules.gui.contextmenu.ContextMenu;
50 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
51 import org.scilab.modules.gui.events.callback.CommonCallBack;
52 import org.scilab.modules.gui.menu.Menu;
53 import org.scilab.modules.gui.menu.ScilabMenu;
54 import org.scilab.modules.gui.menuitem.MenuItem;
55 import org.scilab.modules.gui.menuitem.ScilabMenuItem;
56 import org.scilab.modules.types.ScilabDouble;
57 import org.scilab.modules.types.ScilabList;
58 import org.scilab.modules.types.ScilabMList;
59 import org.scilab.modules.types.ScilabString;
60 import org.scilab.modules.types.ScilabType;
61 import org.scilab.modules.xcos.Xcos;
62 import org.scilab.modules.xcos.XcosTab;
63 import org.scilab.modules.xcos.actions.EditFormatAction;
64 import org.scilab.modules.xcos.actions.ShowHideShadowAction;
65 import org.scilab.modules.xcos.block.actions.BlockDocumentationAction;
66 import org.scilab.modules.xcos.block.actions.BlockParametersAction;
67 import org.scilab.modules.xcos.block.actions.BorderColorAction;
68 import org.scilab.modules.xcos.block.actions.FilledColorAction;
69 import org.scilab.modules.xcos.block.actions.FlipAction;
70 import org.scilab.modules.xcos.block.actions.MirrorAction;
71 import org.scilab.modules.xcos.block.actions.RegionToSuperblockAction;
72 import org.scilab.modules.xcos.block.actions.RotateAction;
73 import org.scilab.modules.xcos.block.actions.ViewDetailsAction;
74 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockAction;
75 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionBottom;
76 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionCenter;
77 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionLeft;
78 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionMiddle;
79 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionRight;
80 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionTop;
81 import org.scilab.modules.xcos.graph.PaletteDiagram;
82 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
83 import org.scilab.modules.xcos.graph.XcosDiagram;
84 import org.scilab.modules.xcos.io.scicos.BasicBlockInfo;
85 import org.scilab.modules.xcos.io.scicos.DiagramElement;
86 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
87 import org.scilab.modules.xcos.io.scicos.ScilabDirectHandler;
88 import org.scilab.modules.xcos.port.BasicPort;
89 import org.scilab.modules.xcos.port.command.CommandPort;
90 import org.scilab.modules.xcos.port.control.ControlPort;
91 import org.scilab.modules.xcos.port.input.InputPort;
92 import org.scilab.modules.xcos.port.output.OutputPort;
93 import org.scilab.modules.xcos.utils.BlockPositioning;
94 import org.scilab.modules.xcos.utils.XcosConstants;
95 import org.scilab.modules.xcos.utils.XcosEvent;
96 import org.scilab.modules.xcos.utils.XcosMessages;
97
98 import com.mxgraph.model.mxGeometry;
99 import com.mxgraph.model.mxICell;
100 import com.mxgraph.model.mxIGraphModel;
101 import com.mxgraph.util.mxConstants;
102 import com.mxgraph.util.mxEventObject;
103 import com.mxgraph.util.mxUtils;
104
105 /**
106  * A block on the diagram
107  */
108 // CSOFF: ClassDataAbstractionCoupling
109 // CSOFF: ClassFanOutComplexity
110 @SuppressWarnings(value = { "serial" })
111 public class BasicBlock extends ScilabGraphUniqueObject implements Serializable {
112     /**
113      * Sorted kind of input, useful to sort them by kind
114      */
115     private static final Class<?>[] sortedChildrenClass = {InputPort.class, OutputPort.class, ControlPort.class, CommandPort.class, Object.class};
116
117     /*
118      * Property names
119      */
120
121     /**
122      * Property name of interfaceFunctionName
123      */
124     public static final String INTERFACE_FUNCTION_NAME = "interfaceFunctionName";
125     /**
126      * Property name of simulationFunctionName
127      */
128     public static final String SIMULATION_FUNCTION_NAME = "simulationFunctionName";
129     /**
130      * Property name of simulationFunctionType
131      */
132     public static final String SIMULATION_FUNCTION_TYPE = "simulationFunctionType";
133     /**
134      * Property name of realParameters
135      */
136     public static final String REAL_PARAMETERS = "realParameters";
137     /**
138      * Property name of integerParameters
139      */
140     public static final String INTEGER_PARAMETERS = "integerParameters";
141     /**
142      * Property name of objectsParameters
143      */
144     public static final String OBJECTS_PARAMETERS = "objectsParameters";
145     /**
146      * Property name of dependsOnU
147      */
148     public static final String DEPENDS_ON_U = "dependsOnU";
149     /**
150      * Property name of dependsOnT
151      */
152     public static final String DEPENDS_ON_T = "dependsOnT";
153     /**
154      * Property name of blockType
155      */
156     public static final String BLOCK_TYPE = "blockType";
157     /**
158      * Property name of ordering
159      */
160     public static final String ORDERING = "ordering";
161     /**
162      * Property name of exprs
163      */
164     public static final String EXPRS = "exprs";
165     /**
166      * Property name of nbZerosCrossing
167      */
168     public static final String NB_ZEROS_CROSSING = "nbZerosCrossing";
169     /**
170      * Property name of nmode
171      */
172     public static final String NMODE = "nmode";
173     /**
174      * Property name of state
175      */
176     public static final String STATE = "state";
177     /**
178      * Property name of dState
179      */
180     public static final String D_STATE = "dState";
181     /**
182      * Property name of oDState
183      */
184     public static final String O_D_STATE = "oDState";
185     /**
186      * Property name of equations
187      */
188     public static final String EQUATIONS = "equations";
189
190     /*
191      * Default values
192      */
193
194     /**
195      * Default interface function name
196      */
197     public static final String DEFAULT_INTERFACE_FUNCTION = "xcos_block";
198     /**
199      * Default simulation function name
200      */
201     public static final String DEFAULT_SIMULATION_FUNCTION = "xcos_simulate";
202
203     /*
204      * Local constants
205      */
206
207     private static final String PARENT_DIAGRAM_WAS_NULL = "Parent diagram was null";
208     private static final double DEFAULT_POSITION_X = 10.0;
209     private static final double DEFAULT_POSITION_Y = 10.0;
210     private static final double DEFAULT_WIDTH = 40.0;
211     private static final double DEFAULT_HEIGHT = 40.0;
212
213     private static final PropertyChangeListener STYLE_UPDATER = new UpdateStyleFromInterfunction();
214     private static final Logger LOG = Logger.getLogger(BasicBlock.class.getName());
215
216     /**
217      * Sort the children list in place.
218      *
219      * The sort put inputs then outputs the control then command ports. The
220      * local port order is preserved.The sort is performed in place and do not
221      * emit any event.
222      *
223      *
224      * @param children
225      *            the children to sort
226      */
227     public static final void sort(List<?> children) {
228         final List<Object> reference = new ArrayList<Object>(children);
229
230         Collections.sort(children, new Comparator<Object>() {
231             @Override
232             public int compare(Object o1, Object o2) {
233                 // diff is the major sorting by kind
234                 int diff = compareByChildClass(o1, o2);
235
236                 if (o1 instanceof BasicPort && o2 instanceof BasicPort) {
237                     // first sort with the port list index
238                     final int diffIndexOf = Integer.signum(reference.indexOf(o1) - reference.indexOf(o2));
239                     // then sort with the ordering value
240                     final int diffOrdering = Integer.signum(((BasicPort) o1).getOrdering() - ((BasicPort) o2).getOrdering());
241                     // then sort with the port position value
242                     final mxGeometry o1Geom = ((BasicPort) o1).getGeometry();
243                     final mxGeometry o2Geom = ((BasicPort) o2).getGeometry();
244                     final int diffPosition = Integer.signum((int) (o2Geom.getX() - o1Geom.getX() - o2Geom.getY() + o1Geom.getY()));
245
246                     // voting is performed with these equivalent 3 selector
247                     diff = diff + diffIndexOf + diffOrdering + diffPosition;
248                 }
249
250                 return diff;
251             }
252         });
253     }
254
255     /**
256      * Internal method to get a base index to compare with depending on the cell
257      * type.
258      *
259      * @param cell
260      *            the cell
261      * @return the base index
262      */
263     private static final int compareByChildClass(final Object o1, final Object o2) {
264         int o1Index = 0;
265         int o2Index = 0;
266
267         for (int i = 0; i < sortedChildrenClass.length; i++) {
268             final Class<?> klass = sortedChildrenClass[i];
269
270             if (klass.isInstance(o1)) {
271                 o1Index = i;
272                 break;
273             }
274         }
275         for (int i = 0; i < sortedChildrenClass.length; i++) {
276             final Class<?> klass = sortedChildrenClass[i];
277
278             if (klass.isInstance(o2)) {
279                 o2Index = i;
280                 break;
281             }
282         }
283
284         final int base = o1Index - o2Index;
285         return base * (Integer.MAX_VALUE / sortedChildrenClass.length);
286     }
287
288     /**
289      * Manage events for block parameters.
290      *
291      * The property name is the field name, is one of:
292      * <ol>
293      * <li>"interfaceFunctionName"
294      * <li>"simulationFunctionName"
295      * <li>"simulationFunctionType"
296      * <li>"exprs"
297      * <li>"realParameters"
298      * <li>"integerParameters"
299      * <li>"objectsParameters"
300      * <li>"nbZerosCrossing"
301      * <li>"nmode"
302      * <li>"state"
303      * <li>"dState"
304      * <li>"oDState"
305      * <li>"equations"
306      * <li>"dependsOnU"
307      * <li>"dependsOnT"
308      * <li>"blockType"
309      * <li>"ordering"
310      * </ol>
311      *
312      * you can easily access to then by using property name constants.
313      */
314     private PropertyChangeSupport parametersPCS = new PropertyChangeSupport(this);
315
316     private String interfaceFunctionName = DEFAULT_INTERFACE_FUNCTION;
317     private String simulationFunctionName = DEFAULT_SIMULATION_FUNCTION;
318     private SimulationFunctionType simulationFunctionType = SimulationFunctionType.DEFAULT;
319     private transient XcosDiagram parentDiagram;
320
321     private int angle;
322     private boolean isFlipped;
323     private boolean isMirrored;
324
325     // TODO : Must make this types evolve, but for now keep a strong link to
326     // Scilab
327     // !! WARNING !!
328     // exprs = [] ; rpar = [] ; ipar = [] ; opar = list()
329
330     // private List<String> exprs = new ArrayList<String>();
331     private ScilabType exprs;
332     // private List<Double> realParameters = new ArrayList<Double>();
333     private ScilabType realParameters;
334     /**
335      * Update status on the rpar mlist, if true then a re-encode has to be performed on the getter.
336      */
337     protected boolean hasAValidRpar = false;
338     // private List<Integer> integerParameters = new ArrayList<Integer>();
339     private ScilabType integerParameters;
340     // private List objectsParameters = new ArrayList();
341     private ScilabType objectsParameters;
342
343     private ScilabType nbZerosCrossing = new ScilabDouble();
344
345     private ScilabType nmode = new ScilabDouble();
346
347     private ScilabType state = new ScilabDouble();
348     private ScilabType dState = new ScilabDouble();
349     private ScilabType oDState = new ScilabDouble();
350
351     private ScilabType equations;
352
353     private boolean dependsOnU;
354     private boolean dependsOnT;
355
356     private String blockType = "c";
357
358     private int ordering;
359     private boolean locked;
360
361     /**
362      * Represent a simulation function type compatible with Scilab/Scicos
363      * function type descriptors.
364      */
365     public static enum SimulationFunctionType {
366         /** event select; reduced at compilation */
367         ESELECT(-2.0),
368         /** if then else; reduced at compilation */
369         IFTHENELSE(-1.0),
370         /** first common block */
371         DEFAULT(0.0),
372         /** first native block */
373         TYPE_1(1.0),
374         /** second native block */
375         TYPE_2(2.0),
376         /** third native block */
377         TYPE_3(3.0),
378         /** forth native block */
379         C_OR_FORTRAN(4.0),
380         /** Scilab blocks */
381         SCILAB(5.0),
382         /** Debug blocks */
383         DEBUG(99),
384         /** dynamic {@link #TYPE_1} Fortran blocks (fortran_block.sci) */
385         DYNAMIC_FORTRAN_1(1001.0),
386         /** dynamic {@link #TYPE_1} C blocks (c_block.sci) */
387         DYNAMIC_C_1(2001.0),
388         /** Explicit dynamic {@link #TYPE_4} blocks (CBLOCK.sci) */
389         DYNAMIC_EXPLICIT_4(2004.0),
390         /** Implicit {@link #TYPE_1} Fortran blocks (DIFF_f.sci) */
391         OLDBLOCKS(10001.0),
392         /** Implicit {@link #C_OR_FORTRAN} blocks */
393         IMPLICIT_C_OR_FORTRAN(10004.0),
394         /** Implicit dynamic {@link #TYPE_4} blocks (CBLOCK.sci) */
395         DYNAMIC_IMPLICIT_4(12004.0),
396         /** Modelica {@link #C_OR_FORTRAN} blocks */
397         MODELICA(30004.0),
398         /** Magic types */
399         UNKNOWN(5.0);
400
401         private double value;
402
403         /**
404          * Default constructor
405          *
406          * @param scilabValue
407          *            Scilab/Scicos function type descriptor
408          */
409         private SimulationFunctionType(double scilabValue) {
410             value = scilabValue;
411         }
412
413         /**
414          * Get the Java descriptor from the Scilab descriptor.
415          *
416          * @param scilabValue
417          *            Scilab/Scicos function type descriptor
418          * @return The corresponding java descriptor
419          */
420         public static SimulationFunctionType convertScilabValue(int scilabValue) {
421             for (SimulationFunctionType iter : SimulationFunctionType.values()) {
422                 if (iter.getAsDouble() == scilabValue) {
423                     return iter;
424                 }
425             }
426             return UNKNOWN;
427         }
428
429         /**
430          * Get the Scilab Descriptor from the Java Descriptor
431          *
432          * @return The corresponding Scilab/Scicos descriptor
433          */
434         public double getAsDouble() {
435             return value;
436         }
437     };
438
439     /**
440      * Update the source block when the interfunction change.
441      */
442     private static final class UpdateStyleFromInterfunction implements PropertyChangeListener, Serializable {
443
444         /**
445          * Default constructor.
446          */
447         public UpdateStyleFromInterfunction() {
448         }
449
450         /**
451          * Update the label on interfunction change.
452          *
453          * @param evt
454          *            the property change event.
455          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
456          */
457         @Override
458         public void propertyChange(PropertyChangeEvent evt) {
459             final BasicBlock source = (BasicBlock) evt.getSource();
460
461             /*
462              * Put the interfunction at the start of the style map to preserve
463              * style modification.
464              *
465              * oldStyle="SUPER_f;fillColor=red" newStyle="DSUPER;fillColor=red"
466              *
467              * and not newStyle="fillColor=red;DSUPER"
468              */
469             final StyleMap style = new StyleMap((String) evt.getNewValue());
470             style.putAll(source.getStyle());
471             style.remove(evt.getOldValue());
472
473             source.setStyle(style.toString());
474         }
475
476     }
477
478     /**
479      * Trace the parameters change on the {@link Logger}.
480      *
481      * This listener is only installed if the trace is enable.
482      */
483     private static final class TraceParametersListener implements PropertyChangeListener, Serializable {
484         private static TraceParametersListener instance;
485
486         /**
487          * Default constructor.
488          */
489         private TraceParametersListener() {
490             super();
491         }
492
493         /**
494          * @return the instance
495          */
496         public static TraceParametersListener getInstance() {
497             if (instance == null) {
498                 instance = new TraceParametersListener();
499             }
500             return instance;
501         }
502
503         /**
504          * Trace.
505          *
506          * @param evt
507          *            the event
508          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
509          */
510         @Override
511         public void propertyChange(PropertyChangeEvent evt) {
512             if (LOG.isLoggable(Level.FINEST)) {
513                 LOG.finest(evt.getPropertyName() + ": " + evt.getOldValue() + ", " + evt.getNewValue());
514             }
515         }
516     }
517
518     /**
519      * Default constructor.
520      */
521     public BasicBlock() {
522         super();
523         setDefaultValues();
524         setVisible(true);
525         setVertex(true);
526
527         if (getStyle().isEmpty() && !getInterfaceFunctionName().isEmpty()) {
528             setStyle(getInterfaceFunctionName());
529         }
530
531         parametersPCS.addPropertyChangeListener(INTERFACE_FUNCTION_NAME, STYLE_UPDATER);
532
533         /*
534          * Trace block parameters change if applicable.
535          */
536         if (LOG.isLoggable(Level.FINEST)) {
537             parametersPCS.addPropertyChangeListener(TraceParametersListener.getInstance());
538         }
539     }
540
541     /**
542      * @param label
543      *            block label
544      */
545     protected BasicBlock(String label) {
546         this();
547         setDefaultValues();
548     }
549
550     /**
551      * @param label
552      *            block label
553      * @param style
554      *            initial style
555      */
556     protected BasicBlock(String label, String style) {
557         this(label);
558         setStyle(style);
559     }
560
561     /**
562      * Initialize the block with the default values
563      */
564     protected void setDefaultValues() {
565         setVisible(true);
566         setVertex(true);
567         setConnectable(false);
568         setGeometry(new mxGeometry(DEFAULT_POSITION_X, DEFAULT_POSITION_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT));
569         setValue("");
570         setStyle("");
571     }
572
573     /**
574      * @return parent diagram
575      */
576     public XcosDiagram getParentDiagram() {
577         return parentDiagram;
578     }
579
580     /**
581      * @param parentDiagram
582      *            parent diagram
583      */
584     public void setParentDiagram(XcosDiagram parentDiagram) {
585         this.parentDiagram = parentDiagram;
586     }
587
588     /**
589      * @return interface function name
590      */
591     public String getInterfaceFunctionName() {
592         return interfaceFunctionName;
593     }
594
595     /**
596      * @param interfaceFunctionName
597      *            interface function name
598      */
599     public void setInterfaceFunctionName(String interfaceFunctionName) {
600         if ((this.interfaceFunctionName == null && interfaceFunctionName != null) || !this.interfaceFunctionName.equals(interfaceFunctionName)) {
601
602             final String oldValue = this.interfaceFunctionName;
603             this.interfaceFunctionName = interfaceFunctionName;
604             parametersPCS.firePropertyChange(INTERFACE_FUNCTION_NAME, oldValue, interfaceFunctionName);
605         }
606     }
607
608     /**
609      * @param simulationFunctionName
610      *            sumulation function name
611      */
612     public void setSimulationFunctionName(String simulationFunctionName) {
613         if ((this.simulationFunctionName == null && simulationFunctionName != null) || !this.simulationFunctionName.equals(simulationFunctionName)) {
614
615             final String oldValue = this.simulationFunctionName;
616             this.simulationFunctionName = simulationFunctionName;
617             parametersPCS.firePropertyChange(SIMULATION_FUNCTION_NAME, oldValue, simulationFunctionName);
618         }
619     }
620
621     /**
622      * @return sumulation function name
623      */
624     public String getSimulationFunctionName() {
625         return simulationFunctionName;
626     }
627
628     /**
629      * @param scilabValue
630      *            simulation function type
631      */
632     public void setSimulationFunctionType(int scilabValue) {
633         SimulationFunctionType simFunctionType = SimulationFunctionType.convertScilabValue(scilabValue);
634         setSimulationFunctionType(simFunctionType);
635     }
636
637     /**
638      * @param simulationFunctionType
639      *            simulation function type
640      */
641     public void setSimulationFunctionType(SimulationFunctionType simulationFunctionType) {
642         if ((this.simulationFunctionType == null && simulationFunctionType != null) || !this.simulationFunctionType.equals(simulationFunctionType)) {
643
644             final SimulationFunctionType oldValue = this.simulationFunctionType;
645             this.simulationFunctionType = simulationFunctionType;
646             parametersPCS.firePropertyChange(SIMULATION_FUNCTION_TYPE, oldValue, simulationFunctionType);
647         }
648     }
649
650     /**
651      * @return simulation function type
652      */
653     public SimulationFunctionType getSimulationFunctionType() {
654         return simulationFunctionType;
655     }
656
657     /**
658      * @return real parameter ( rpar )
659      */
660     public ScilabType getRealParameters() {
661         if (!hasAValidRpar && realParameters instanceof ScilabMList) {
662             try {
663                 final DiagramElement elem = new DiagramElement();
664                 final XcosDiagram d = elem.decode(realParameters, new XcosDiagram(false));
665                 realParameters = elem.encode(d, null);
666             } catch (ScicosFormatException e) {
667                 // do nothing on error (no assignation)
668             }
669         }
670
671         return realParameters;
672     }
673
674     /**
675      * @param realParameters
676      *            reaL parameter ( rpar )
677      */
678     public void setRealParameters(ScilabType realParameters) {
679         if ((this.realParameters == null && realParameters != null) || !this.realParameters.equals(realParameters)) {
680
681             final ScilabType oldValue = this.realParameters;
682             this.realParameters = realParameters;
683             parametersPCS.firePropertyChange(REAL_PARAMETERS, oldValue, realParameters);
684         }
685     }
686
687     /**
688      * Invalide the rpar, a new child diagram encoding will be performed on
689      * demand.
690      */
691     public void invalidateRpar() {
692         hasAValidRpar = false;
693     }
694
695     /**
696      * @return integer parameter ( ipar )
697      */
698     public ScilabType getIntegerParameters() {
699         return integerParameters;
700     }
701
702     /**
703      * @param integerParameters
704      *            integer parameter ( ipar )
705      */
706     public void setIntegerParameters(ScilabType integerParameters) {
707         if ((this.integerParameters == null && integerParameters != null) || !this.integerParameters.equals(integerParameters)) {
708
709             final ScilabType oldValue = this.integerParameters;
710             this.integerParameters = integerParameters;
711             parametersPCS.firePropertyChange(INTEGER_PARAMETERS, oldValue, integerParameters);
712         }
713     }
714
715     /**
716      * @return object parameter ( opar )
717      */
718     public ScilabType getObjectsParameters() {
719         return objectsParameters;
720     }
721
722     /**
723      * @param objectsParameters
724      *            object parameter ( opar )
725      */
726     public void setObjectsParameters(ScilabType objectsParameters) {
727         if ((this.objectsParameters == null && objectsParameters != null) || !this.objectsParameters.equals(objectsParameters)) {
728
729             final ScilabType oldValue = this.objectsParameters;
730             this.objectsParameters = objectsParameters;
731             parametersPCS.firePropertyChange(OBJECTS_PARAMETERS, oldValue, objectsParameters);
732         }
733     }
734
735     /**
736      * @param dependsOnU
737      *            ?
738      */
739     public void setDependsOnU(boolean dependsOnU) {
740         if (this.dependsOnU != dependsOnU) {
741
742             final boolean oldValue = this.dependsOnU;
743             this.dependsOnU = dependsOnU;
744             parametersPCS.firePropertyChange(DEPENDS_ON_U, oldValue, dependsOnU);
745         }
746     }
747
748     /**
749      * @return ?
750      */
751     public boolean isDependsOnU() {
752         return dependsOnU;
753     }
754
755     /**
756      * @param dependsOnT
757      *            ?
758      */
759     public void setDependsOnT(boolean dependsOnT) {
760         if (this.dependsOnT != dependsOnT) {
761
762             final boolean oldValue = this.dependsOnT;
763             this.dependsOnT = dependsOnT;
764             parametersPCS.firePropertyChange(DEPENDS_ON_T, oldValue, dependsOnT);
765         }
766     }
767
768     /**
769      * @return ?
770      */
771     public boolean isDependsOnT() {
772         return dependsOnT;
773     }
774
775     /**
776      * @param blockType
777      *            block type
778      */
779     public void setBlockType(String blockType) {
780         if ((this.blockType == null && blockType != null) || !this.blockType.equals(blockType)) {
781
782             final String oldValue = this.blockType;
783             this.blockType = blockType;
784             parametersPCS.firePropertyChange(BLOCK_TYPE, oldValue, blockType);
785         }
786     }
787
788     /**
789      * @return block type
790      */
791     public String getBlockType() {
792         return blockType;
793     }
794
795     /**
796      * @param ordering
797      *            order value
798      */
799     public void setOrdering(int ordering) {
800         if (this.ordering != ordering) {
801
802             final int oldValue = this.ordering;
803             this.ordering = ordering;
804             parametersPCS.firePropertyChange(ORDERING, oldValue, ordering);
805         }
806     }
807
808     /**
809      * @return order value
810      */
811     public int getOrdering() {
812         return ordering;
813     }
814
815     /**
816      * @param exprs
817      *            expression
818      */
819     public void setExprs(ScilabType exprs) {
820         if ((this.exprs == null && exprs != null) || !this.exprs.equals(exprs)) {
821
822             final ScilabType oldValue = this.exprs;
823             this.exprs = exprs;
824             parametersPCS.firePropertyChange(EXPRS, oldValue, exprs);
825         }
826     }
827
828     /**
829      * @return expression
830      */
831     public ScilabType getExprs() {
832         return exprs;
833     }
834
835     /**
836      * @return the expression as an object array
837      */
838     public Object[] getExprsFormat() {
839         // evaluate emptiness
840         if (getExprs() == null || getExprs().isEmpty() || getExprs().getHeight() == 0 || getExprs().getWidth() == 0) {
841             return new String[0];
842         }
843
844         List<String[]> stack = getString(null, getExprs());
845
846         int len = 0;
847         for (Object[] strings : stack) {
848             len += strings.length;
849         }
850
851         final Object[] array = new Object[len];
852         int start = 0;
853         for (Object[] strings : stack) {
854             System.arraycopy(strings, 0, array, start, strings.length);
855             start += strings.length;
856         }
857
858         return array;
859     }
860
861     /**
862      * Append the data recursively to the stack
863      *
864      * @param currentStack
865      *            the current stack
866      * @param data
867      *            the data to append
868      * @return the stack
869      */
870     private List<String[]> getString(List<String[]> currentStack, ScilabType data) {
871         final List<String[]> stack;
872
873         if (currentStack == null) {
874             stack = new LinkedList<String[]>();
875         } else {
876             stack = currentStack;
877         }
878
879         if (data instanceof List) {
880             /*
881              * Container case (ScilabList, ScilabMList, ScilabTList)
882              */
883
884             @SuppressWarnings("unchecked")
885             final List<ScilabType> list = (List<ScilabType>) data;
886
887             for (final ScilabType scilabType : list) {
888                 getString(stack, scilabType);
889             }
890         } else if (data instanceof ScilabString) {
891             /*
892              * native case (only ScilabString supported)
893              */
894
895             final String[][] scilabData = ((ScilabString) data).getData();
896             final int height = data.getHeight();
897             final int width = data.getWidth();
898
899             final String[] array = new String[height * width];
900             for (int i = 0; i < height; ++i) {
901                 System.arraycopy(scilabData[i], 0, array, i * width, width);
902             }
903
904             stack.add(array);
905         }
906
907         return stack;
908     }
909
910     /**
911      * @return zero crossing value
912      */
913     public ScilabType getNbZerosCrossing() {
914         return nbZerosCrossing;
915     }
916
917     /**
918      * @param nbZerosCrossing
919      *            zero crossing value
920      */
921     public void setNbZerosCrossing(ScilabType nbZerosCrossing) {
922         if ((this.nbZerosCrossing == null && nbZerosCrossing != null) || !this.nbZerosCrossing.equals(nbZerosCrossing)) {
923
924             final ScilabType oldValue = this.nbZerosCrossing;
925             this.nbZerosCrossing = nbZerosCrossing;
926             parametersPCS.firePropertyChange(NB_ZEROS_CROSSING, oldValue, nbZerosCrossing);
927         }
928     }
929
930     /**
931      * @return nmode
932      */
933     public ScilabType getNmode() {
934         return nmode;
935     }
936
937     /**
938      * @param nmode
939      *            nmode
940      */
941     public void setNmode(ScilabType nmode) {
942         if ((this.nmode == null && nmode != null) || !this.nmode.equals(nmode)) {
943
944             final ScilabType oldValue = this.nmode;
945             this.nmode = nmode;
946             parametersPCS.firePropertyChange(NMODE, oldValue, nmode);
947         }
948     }
949
950     /**
951      * @return current state
952      */
953     public ScilabType getState() {
954         return state;
955     }
956
957     /**
958      * @param state
959      *            new state
960      */
961     public void setState(ScilabType state) {
962         if ((this.state == null && state != null) || !this.state.equals(state)) {
963
964             final ScilabType oldValue = this.state;
965             this.state = state;
966             parametersPCS.firePropertyChange(STATE, oldValue, state);
967         }
968     }
969
970     /**
971      * @return current dstate
972      */
973     public ScilabType getDState() {
974         return dState;
975     }
976
977     /**
978      * @param dState
979      *            new dstate
980      */
981     public void setDState(ScilabType dState) {
982         if ((this.dState == null && dState != null) || !this.dState.equals(dState)) {
983
984             final ScilabType oldValue = this.dState;
985             this.dState = dState;
986             parametersPCS.firePropertyChange(D_STATE, oldValue, dState);
987         }
988     }
989
990     /**
991      * @return current ostate
992      */
993     public ScilabType getODState() {
994         return oDState;
995     }
996
997     /**
998      * @param oDState
999      *            new odstate
1000      */
1001     public void setODState(ScilabType oDState) {
1002         if ((this.oDState == null && oDState != null) || !this.oDState.equals(oDState)) {
1003
1004             final ScilabType oldValue = this.oDState;
1005             this.oDState = oDState;
1006             parametersPCS.firePropertyChange(O_D_STATE, oldValue, oDState);
1007         }
1008     }
1009
1010     /**
1011      * @return equations
1012      */
1013     public ScilabType getEquations() {
1014         return equations;
1015     }
1016
1017     /**
1018      * @param equations
1019      *            equations
1020      */
1021     public void setEquations(ScilabType equations) {
1022         if ((this.equations == null && equations != null) || !this.equations.equals(equations)) {
1023
1024             final ScilabType oldValue = this.equations;
1025             this.equations = equations;
1026             parametersPCS.firePropertyChange(EQUATIONS, oldValue, equations);
1027         }
1028     }
1029
1030     /**
1031      * @return locked status
1032      */
1033     public synchronized boolean isLocked() {
1034         return locked;
1035     }
1036
1037     /**
1038      * @param locked
1039      *            change locked status
1040      */
1041     public synchronized void setLocked(boolean locked) {
1042         this.locked = locked;
1043     }
1044
1045     /**
1046      * @param port
1047      *            to remove
1048      */
1049     public void removePort(BasicPort port) {
1050         if (port.getEdgeCount() != 0 && getParentDiagram() != null) {
1051             getParentDiagram().removeCells(new Object[] { port.getEdgeAt(0) });
1052         }
1053         remove(port);
1054     }
1055
1056     /**
1057      * Add a port on the block.
1058      *
1059      * This call should only be used when a port reordering operation must be
1060      * performed.
1061      *
1062      * @param port
1063      *            The port to be added to the block
1064      */
1065     public void addPort(BasicPort port) {
1066         insert(port);
1067         port.setOrdering(BasicBlockInfo.getAllTypedPorts(this, false, port.getClass()).size());
1068         BlockPositioning.updateBlockView(this);
1069     }
1070
1071     /**
1072      * @return command ports initial state
1073      */
1074     public ScilabDouble getAllCommandPortsInitialStates() {
1075         final List<CommandPort> cmdPorts = BasicBlockInfo.getAllTypedPorts(this, false, CommandPort.class);
1076         if (cmdPorts.isEmpty()) {
1077             return new ScilabDouble();
1078         }
1079
1080         double[][] data = new double[cmdPorts.size()][1];
1081         for (int i = 0; i < cmdPorts.size(); ++i) {
1082             data[i][0] = cmdPorts.get(i).getInitialState();
1083         }
1084
1085         return new ScilabDouble(data);
1086     }
1087
1088     /**
1089      * @return name and type of the simulation function
1090      */
1091     public ScilabType getSimulationFunctionNameAndType() {
1092         if (getSimulationFunctionType() == SimulationFunctionType.DEFAULT) {
1093             return new ScilabString(getSimulationFunctionName());
1094         }
1095         ScilabList data = new ScilabList();
1096
1097         data.add(new ScilabString(getSimulationFunctionName()));
1098         data.add(new ScilabDouble(getSimulationFunctionType().getAsDouble()));
1099
1100         return data;
1101     }
1102
1103     /**
1104      * Does the block update and register on the undo manager
1105      *
1106      * @param modifiedBlock
1107      *            the new settings
1108      */
1109     public void updateBlockSettings(BasicBlock modifiedBlock) {
1110         if (modifiedBlock == null) {
1111             return;
1112         }
1113
1114         /*
1115          * Update the block settings
1116          */
1117         updateFields(modifiedBlock);
1118
1119         /*
1120          * Update the children ports
1121          */
1122         updateChildren(modifiedBlock);
1123
1124         /*
1125          * If the block is in a superblock then update it.
1126          */
1127         if (getParentDiagram() instanceof SuperBlockDiagram) {
1128             SuperBlock block = ((SuperBlockDiagram) getParentDiagram()).getContainer();
1129
1130             XcosDiagram graph = block.getParentDiagram();
1131             if (graph == null) {
1132                 setParentDiagram(Xcos.findParent(block));
1133                 graph = block.getParentDiagram();
1134                 LOG.finest(PARENT_DIAGRAM_WAS_NULL);
1135             }
1136
1137             graph.fireEvent(new mxEventObject(XcosEvent.SUPER_BLOCK_UPDATED, XcosConstants.EVENT_BLOCK_UPDATED, block));
1138         }
1139     }
1140
1141     /**
1142      * Update the instance field.
1143      *
1144      * @param modifiedBlock
1145      *            the modified instance
1146      */
1147     private void updateFields(BasicBlock modifiedBlock) {
1148         if (modifiedBlock == null) {
1149             return;
1150         }
1151
1152         setDependsOnT(modifiedBlock.isDependsOnT());
1153         setDependsOnU(modifiedBlock.isDependsOnU());
1154         setExprs(modifiedBlock.getExprs());
1155
1156         setRealParameters(modifiedBlock.getRealParameters());
1157         setIntegerParameters(modifiedBlock.getIntegerParameters());
1158         setObjectsParameters(modifiedBlock.getObjectsParameters());
1159
1160         setState(modifiedBlock.getState());
1161         setDState(modifiedBlock.getDState());
1162         setODState(modifiedBlock.getODState());
1163
1164         setBlockType(modifiedBlock.getBlockType());
1165         setSimulationFunctionName(modifiedBlock.getSimulationFunctionName());
1166         setSimulationFunctionType(modifiedBlock.getSimulationFunctionType());
1167
1168         setNbZerosCrossing(modifiedBlock.getNbZerosCrossing());
1169         setNmode(modifiedBlock.getNmode());
1170
1171         setEquations(modifiedBlock.getEquations());
1172         setStyle(modifiedBlock.getStyle());
1173     }
1174
1175     /**
1176      * Update the children of the block.
1177      *
1178      * @param modifiedBlock
1179      *            the new block instance
1180      */
1181     private void updateChildren(BasicBlock modifiedBlock) {
1182         if (modifiedBlock == null) {
1183             return;
1184         }
1185
1186         XcosDiagram graph = getParentDiagram();
1187         if (graph == null) {
1188             setParentDiagram(Xcos.findParent(this));
1189             graph = getParentDiagram();
1190             LOG.finest(PARENT_DIAGRAM_WAS_NULL);
1191         }
1192
1193         /*
1194          * Checked as port classes only
1195          */
1196         @SuppressWarnings("unchecked")
1197         Set < Class <? extends mxICell >> types = new HashSet < Class <? extends mxICell >> (Arrays.asList(InputPort.class, OutputPort.class, ControlPort.class,
1198                 CommandPort.class));
1199
1200         Map < Class <? extends mxICell > , Deque<mxICell >> annotatedOlds = getTypedChildren(types);
1201         Map < Class <? extends mxICell > , Deque<mxICell >> annotatedNews = modifiedBlock.getTypedChildren(types);
1202
1203         getParentDiagram().getModel().beginUpdate();
1204         try {
1205             for (Class <? extends mxICell > klass : types) {
1206                 final Deque<mxICell> olds = annotatedOlds.get(klass);
1207                 final Deque<mxICell> news = annotatedNews.get(klass);
1208
1209                 // updated ports
1210                 while (!olds.isEmpty() && !news.isEmpty()) {
1211                     mxICell previous = olds.poll();
1212                     mxICell modified = news.poll();
1213
1214                     final int previousIndex = children.indexOf(previous);
1215
1216                     // relink
1217                     if (previous.getEdgeCount() != 0) {
1218                         final mxICell edge = previous.getEdgeAt(0);
1219                         final boolean isOutgoing = previous == edge.getTerminal(true);
1220                         previous.removeEdge(edge, isOutgoing);
1221                         modified.insertEdge(edge, isOutgoing);
1222                     }
1223
1224                     getParentDiagram().removeCells(new Object[] { previous }, false);
1225                     getParentDiagram().addCells(new Object[] { modified }, this, previousIndex);
1226
1227                     // Clone the geometry to avoid empty geometry on new cells.
1228                     getParentDiagram().getModel().setGeometry(modified, (mxGeometry) previous.getGeometry().clone());
1229
1230                 }
1231
1232                 // removed ports
1233                 if (!olds.isEmpty()) {
1234                     getParentDiagram().removeCells(olds.toArray(), true);
1235                 }
1236
1237                 // added ports
1238                 if (!news.isEmpty()) {
1239                     getParentDiagram().addCells(news.toArray(), this);
1240                 }
1241             }
1242         } finally {
1243             getParentDiagram().getModel().endUpdate();
1244         }
1245     }
1246
1247     /**
1248      * Format the children as a typed map for the given class set.
1249      *
1250      * @param types
1251      *            the classes to search for.
1252      * @return a map which linked foreach type the corresponding cell list.
1253      */
1254     private Map < Class <? extends mxICell > , Deque<mxICell >> getTypedChildren(Set < Class <? extends mxICell >> types) {
1255         Map < Class <? extends mxICell > , Deque<mxICell >> oldPorts = new HashMap < Class <? extends mxICell > , Deque<mxICell >> ();
1256
1257         // Allocate all types set
1258         for (Class <? extends mxICell > type : types) {
1259             oldPorts.put(type, new LinkedList<mxICell>());
1260         }
1261
1262         if (getChildCount() <= 0) {
1263             return oldPorts;
1264         }
1265
1266         // sort children according to the ordering parameter (useful on
1267         // scilab-5.2.x diagrams)
1268         sort(children);
1269
1270         // children lookup
1271         for (Object cell : children) {
1272
1273             Class <? extends Object > klass = cell.getClass();
1274             while (klass != null) {
1275                 if (types.contains(klass)) {
1276                     break;
1277                 }
1278                 klass = klass.getSuperclass();
1279             }
1280
1281             final Deque<mxICell> current = oldPorts.get(klass);
1282             if (current != null) {
1283                 current.add((mxICell) cell);
1284             }
1285         }
1286
1287         return oldPorts;
1288     }
1289
1290     /**
1291      * Sort the children list in place.
1292      *
1293      * The sort put inputs then outputs the control then command ports. The
1294      * local port order is preserved.The sort is performed in place and do not
1295      * emit any event.
1296      */
1297     public void sortChildren() {
1298         if (getChildCount() <= 0) {
1299             return;
1300         }
1301
1302         sort(children);
1303     }
1304
1305     /**
1306      * @param context
1307      *            parent diagram context
1308      */
1309     public void openBlockSettings(String[] context) {
1310         final XcosDiagram graph;
1311         if (getParentDiagram() == null) {
1312             setParentDiagram(Xcos.findParent(this));
1313             graph = getParentDiagram();
1314             LOG.finest(PARENT_DIAGRAM_WAS_NULL);
1315         } else {
1316             graph = getParentDiagram();
1317         }
1318         if (graph instanceof PaletteDiagram) {
1319             return;
1320         }
1321
1322         if (context == null) {
1323             throw new IllegalArgumentException();
1324         }
1325
1326         // prevent to open twice
1327         if (isLocked()) {
1328             return;
1329         }
1330
1331         graph.setCellsLocked(true);
1332         graph.getAsComponent().getGraphControl().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1333
1334         // sort children according to the ordering parameter (useful on
1335         // scilab-5.2.x diagrams)
1336         sortChildren();
1337
1338         final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
1339         if (handler == null) {
1340             return;
1341         }
1342
1343         try {
1344             // Write scs_m
1345             handler.writeBlock(this);
1346             // Write context
1347             handler.writeContext(context);
1348
1349             final ActionListener action = new ActionListener() {
1350                 @Override
1351                 public void actionPerformed(ActionEvent e) {
1352                     LOG.finest("Updating data.");
1353
1354                     graph.getView().clear(this, true, true);
1355
1356                     // Now read new Block
1357                     graph.getModel().beginUpdate();
1358                     try {
1359                         final BasicBlock modifiedBlock = handler.readBlock();
1360                         updateBlockSettings(modifiedBlock);
1361
1362                         graph.fireEvent(new mxEventObject(XcosEvent.ADD_PORTS, XcosConstants.EVENT_BLOCK_UPDATED, BasicBlock.this));
1363                     } catch (ScicosFormatException ex) {
1364                         LOG.severe(ex.toString());
1365                     } finally {
1366                         graph.getModel().endUpdate();
1367                         setLocked(false);
1368
1369                         handler.release();
1370
1371                         graph.getAsComponent().getGraphControl().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1372                         graph.setCellsLocked(false);
1373                     }
1374                 }
1375             };
1376
1377             setLocked(true);
1378             ScilabInterpreterManagement.asynchronousScilabExec(action, "blk = xcosBlockInterface", getInterfaceFunctionName().toCharArray(), "set",
1379                     ScilabDirectHandler.BLK.toCharArray(), ScilabDirectHandler.CONTEXT.toCharArray());
1380         } catch (InterpreterException e) {
1381             LOG.severe(e.toString());
1382             setLocked(false);
1383
1384             handler.release();
1385
1386             graph.getAsComponent().getGraphControl().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
1387             graph.setCellsLocked(false);
1388         }
1389     }
1390
1391     /**
1392      * @return tooltip text
1393      */
1394     public String getToolTipText() {
1395         StringBuilder result = new StringBuilder();
1396         result.append(ScilabGraphConstants.HTML_BEGIN);
1397         result.append("Block Name : " + getInterfaceFunctionName() + ScilabGraphConstants.HTML_NEWLINE);
1398         result.append("Simulation : " + getSimulationFunctionName() + ScilabGraphConstants.HTML_NEWLINE);
1399
1400         if (getParentDiagram() instanceof PaletteDiagram) {
1401             if (getIntegerParameters() != null) {
1402                 result.append("Integer parameters : " + getIntegerParameters() + ScilabGraphConstants.HTML_NEWLINE);
1403             }
1404
1405             if (getRealParameters() != null && getRealParameters().getHeight() != 0 && getRealParameters().getWidth() != 0) {
1406                 result.append("Real parameters : " + getRealParameters() + ScilabGraphConstants.HTML_NEWLINE);
1407             }
1408
1409             if (getObjectsParameters() != null) {
1410                 result.append("Object parameters : " + getObjectsParameters() + ScilabGraphConstants.HTML_NEWLINE);
1411             }
1412         } else {
1413             result.append("UID : " + getId() + ScilabGraphConstants.HTML_NEWLINE);
1414             final int length = getStyle().length();
1415             result.append("Style : ");
1416             if (length > XcosConstants.MAX_CHAR_IN_STYLE) {
1417                 result.append(getStyle().substring(0, XcosConstants.MAX_CHAR_IN_STYLE));
1418                 result.append(XcosMessages.DOTS);
1419             } else {
1420                 result.append(getStyle());
1421             }
1422             result.append(ScilabGraphConstants.HTML_NEWLINE);
1423             result.append("Flip : " + getFlip() + ScilabGraphConstants.HTML_NEWLINE);
1424             result.append("Mirror : " + getMirror() + ScilabGraphConstants.HTML_NEWLINE);
1425             result.append("Input ports : " + BasicBlockInfo.getAllTypedPorts(this, false, InputPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1426             result.append("Output ports : " + BasicBlockInfo.getAllTypedPorts(this, false, OutputPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1427             result.append("Control ports : " + BasicBlockInfo.getAllTypedPorts(this, false, ControlPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1428             result.append("Command ports : " + BasicBlockInfo.getAllTypedPorts(this, false, CommandPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
1429         }
1430
1431         result.append("x : " + getGeometry().getX() + ScilabGraphConstants.HTML_NEWLINE);
1432         result.append("y : " + getGeometry().getY() + ScilabGraphConstants.HTML_NEWLINE);
1433         result.append("w : " + getGeometry().getWidth() + ScilabGraphConstants.HTML_NEWLINE);
1434         result.append("h : " + getGeometry().getHeight() + ScilabGraphConstants.HTML_NEWLINE);
1435         result.append(ScilabGraphConstants.HTML_END);
1436         return result.toString();
1437     }
1438
1439     /**
1440      * @param graph
1441      *            parent graph
1442      */
1443     public void openContextMenu(ScilabGraph graph) {
1444         ContextMenu menu = null;
1445         if (getParentDiagram() instanceof PaletteDiagram) {
1446             menu = createPaletteContextMenu(graph);
1447         } else {
1448             menu = createContextMenu(graph);
1449         }
1450         menu.setVisible(true);
1451     }
1452
1453     /**
1454      * @param graph
1455      *            parent graph
1456      * @return context menu
1457      */
1458     // CSOFF: JavaNCSS
1459     public ContextMenu createPaletteContextMenu(ScilabGraph graph) {
1460         ContextMenu menu = ScilabContextMenu.createContextMenu();
1461
1462         final List<XcosDiagram> allDiagrams = Xcos.getInstance().openedDiagrams();
1463
1464         if (allDiagrams.size() == 0) {
1465             // No diagram opened: should never happen if Xcos opens an empty
1466             // diagram when it is launched
1467             MenuItem addTo = ScilabMenuItem.createMenuItem();
1468
1469             addTo.setText(XcosMessages.ADDTO_NEW_DIAGRAM);
1470             addTo.setCallback(new CommonCallBack(XcosMessages.ADDTO_NEW_DIAGRAM) {
1471                 @Override
1472                 public void callBack() {
1473
1474                     XcosDiagram theDiagram = new XcosDiagram();
1475                     BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1476                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1477                     mxGeometry geom = BasicBlock.this.getGeometry();
1478                     setDefaultPosition(geom);
1479                     theDiagram.getModel().setGeometry(block, geom);
1480
1481                     XcosTab.get(theDiagram).setVisible(true);
1482                     BlockPositioning.updateBlockView(block);
1483                 }
1484             });
1485
1486             menu.add(addTo);
1487
1488         } else if (allDiagrams.size() == 1) {
1489             // A single diagram opened: add to this diagram
1490             MenuItem addTo = ScilabMenuItem.createMenuItem();
1491
1492             addTo.setText(XcosMessages.ADDTO + " " + XcosTab.get(allDiagrams.get(0)).getName());
1493             final XcosDiagram theDiagram = allDiagrams.get(0);
1494             addTo.setCallback(new CommonCallBack(theDiagram.getTitle()) {
1495                 private static final long serialVersionUID = -99601763227525686L;
1496
1497                 @Override
1498                 public void callBack() {
1499                     BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1500                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1501                     mxGeometry geom = BasicBlock.this.getGeometry();
1502                     setDefaultPosition(geom);
1503                     theDiagram.getModel().setGeometry(block, geom);
1504                     BlockPositioning.updateBlockView(block);
1505                     block.setParentDiagram(theDiagram);
1506                 }
1507             });
1508
1509             menu.add(addTo);
1510
1511         } else {
1512             // The user has to choose
1513             Menu addTo = ScilabMenu.createMenu();
1514
1515             addTo.setText(XcosMessages.ADDTO);
1516
1517             for (int i = 0; i < allDiagrams.size(); i++) {
1518                 MenuItem diagram = ScilabMenuItem.createMenuItem();
1519                 final XcosDiagram theDiagram = allDiagrams.get(i);
1520                 diagram.setText(XcosTab.get(allDiagrams.get(i)).getName());
1521                 diagram.setCallback(new CommonCallBack(theDiagram.getTitle()) {
1522                     private static final long serialVersionUID = 3345416658377835057L;
1523
1524                     @Override
1525                     public void callBack() {
1526                         BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
1527                         theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
1528                         mxGeometry geom = BasicBlock.this.getGeometry();
1529                         setDefaultPosition(geom);
1530                         theDiagram.getModel().setGeometry(block, geom);
1531                         BlockPositioning.updateBlockView(block);
1532                     }
1533                 });
1534                 addTo.add(diagram);
1535             }
1536
1537             menu.add(addTo);
1538         }
1539
1540         menu.getAsSimpleContextMenu().addSeparator();
1541
1542         MenuItem help = ScilabMenuItem.createMenuItem();
1543         help.setText(XcosMessages.BLOCK_DOCUMENTATION);
1544         help.setCallback(new CommonCallBack(XcosMessages.BLOCK_DOCUMENTATION) {
1545             private static final long serialVersionUID = -1480947262397441951L;
1546
1547             @Override
1548             public void callBack() {
1549                 InterpreterManagement.requestScilabExec("help " + getInterfaceFunctionName());
1550             }
1551         });
1552         menu.add(help);
1553
1554         menu.setVisible(true);
1555
1556         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo()
1557                 .getLocation().y);
1558
1559         return menu;
1560     }
1561
1562     // CSON: JavaNCSS
1563
1564     /**
1565      * @param graph
1566      *            parent graph
1567      * @return context menu
1568      */
1569     // CSOFF: JavaNCSS
1570     public ContextMenu createContextMenu(ScilabGraph graph) {
1571         ContextMenu menu = ScilabContextMenu.createContextMenu();
1572         Map < Class <? extends DefaultAction > , Menu > menuList = new HashMap < Class <? extends DefaultAction > , Menu > ();
1573
1574         MenuItem value = BlockParametersAction.createMenu(graph);
1575         menuList.put(BlockParametersAction.class, value);
1576         menu.add(value);
1577         /*--- */
1578         menu.getAsSimpleContextMenu().addSeparator();
1579         /*--- */
1580         value = CutAction.cutMenu(graph);
1581         menuList.put(CutAction.class, value);
1582         menu.add(value);
1583         value = CopyAction.copyMenu(graph);
1584         menuList.put(CopyAction.class, value);
1585         menu.add(value);
1586         value = DeleteAction.createMenu(graph);
1587         menuList.put(DeleteAction.class, value);
1588         menu.add(value);
1589         /*--- */
1590         menu.getAsSimpleContextMenu().addSeparator();
1591         /*--- */
1592         value = RegionToSuperblockAction.createMenu(graph);
1593         menuList.put(RegionToSuperblockAction.class, value);
1594         menu.add(value);
1595         /*--- */
1596         menu.getAsSimpleContextMenu().addSeparator();
1597         /*--- */
1598         Menu format = ScilabMenu.createMenu();
1599         format.setText(XcosMessages.FORMAT);
1600         menu.add(format);
1601         value = RotateAction.createMenu(graph);
1602         menuList.put(RotateAction.class, value);
1603         format.add(value);
1604         value = MirrorAction.createMenu(graph);
1605         menuList.put(MirrorAction.class, value);
1606         format.add(value);
1607         value = FlipAction.createMenu(graph);
1608         menuList.put(FlipAction.class, value);
1609         format.add(value);
1610         value = ShowHideShadowAction.createMenu(graph);
1611         menuList.put(ShowHideShadowAction.class, value);
1612         format.add(value);
1613         /*--- */
1614         format.addSeparator();
1615         /*--- */
1616         Menu alignMenu = ScilabMenu.createMenu();
1617         alignMenu.setText(XcosMessages.ALIGN_BLOCKS);
1618         alignMenu.add(AlignBlockActionLeft.createMenu(graph));
1619         alignMenu.add(AlignBlockActionCenter.createMenu(graph));
1620         alignMenu.add(AlignBlockActionRight.createMenu(graph));
1621         alignMenu.addSeparator();
1622         alignMenu.add(AlignBlockActionTop.createMenu(graph));
1623         alignMenu.add(AlignBlockActionMiddle.createMenu(graph));
1624         alignMenu.add(AlignBlockActionBottom.createMenu(graph));
1625         menuList.put(AlignBlockAction.class, alignMenu);
1626         format.add(alignMenu);
1627         /*--- */
1628         format.addSeparator();
1629         /*--- */
1630         if (graph.getSelectionCells().length > 1) {
1631             format.add(BorderColorAction.createMenu(graph));
1632             format.add(FilledColorAction.createMenu(graph));
1633         } else {
1634             format.add(EditFormatAction.createMenu(graph));
1635         }
1636         /*--- */
1637         menu.getAsSimpleContextMenu().addSeparator();
1638         /*--- */
1639         menu.add(ViewDetailsAction.createMenu(graph));
1640         /*--- */
1641         menu.getAsSimpleContextMenu().addSeparator();
1642         /*--- */
1643         menu.add(BlockDocumentationAction.createMenu(graph));
1644
1645         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo()
1646                 .getLocation().y);
1647
1648         customizeMenu(menuList);
1649
1650         return menu;
1651     }
1652
1653     // CSON: JavaNCSS
1654
1655     /**
1656      * @param flip
1657      *            value
1658      */
1659     public void setFlip(boolean flip) {
1660         isFlipped = flip;
1661         if (getParentDiagram() != null) {
1662             final mxIGraphModel model = getParentDiagram().getModel();
1663             mxUtils.setCellStyles(model, new Object[] { this }, ScilabGraphConstants.STYLE_FLIP, Boolean.toString(flip));
1664         }
1665     }
1666
1667     /**
1668      * Override this to customize contextual menu
1669      *
1670      * @param menuList
1671      *            list of menu
1672      */
1673     protected void customizeMenu(Map < Class <? extends DefaultAction > , Menu > menuList) {
1674         // To be overridden by sub-classes
1675     }
1676
1677     /**
1678      * @return mirror value
1679      */
1680     public boolean getMirror() {
1681         return isMirrored;
1682     }
1683
1684     /**
1685      * @param mirror
1686      *            new mirror value
1687      */
1688     public void setMirror(boolean mirror) {
1689         isMirrored = mirror;
1690         if (getParentDiagram() != null) {
1691             final mxIGraphModel model = getParentDiagram().getModel();
1692             mxUtils.setCellStyles(model, new Object[] { this }, ScilabGraphConstants.STYLE_MIRROR, Boolean.toString(mirror));
1693         }
1694     }
1695
1696     /**
1697      * @return flip status
1698      */
1699     public boolean getFlip() {
1700         return isFlipped;
1701     }
1702
1703     /**
1704      * invert flip status
1705      */
1706     public void toggleFlip() {
1707         BlockPositioning.toggleFlip(this);
1708     }
1709
1710     /**
1711      * invert mirror value
1712      */
1713     public void toggleMirror() {
1714         BlockPositioning.toggleMirror(this);
1715     }
1716
1717     /**
1718      *
1719      */
1720     public void toggleAntiClockwiseRotation() {
1721         BlockPositioning.toggleAntiClockwiseRotation(this);
1722
1723     }
1724
1725     /**
1726      * @return current angle
1727      */
1728     public int getAngle() {
1729         return angle;
1730     }
1731
1732     /**
1733      * @param angle
1734      *            new block angle
1735      */
1736     public void setAngle(int angle) {
1737         this.angle = angle;
1738
1739         if (getParentDiagram() != null) {
1740             mxUtils.setCellStyles(getParentDiagram().getModel(), new Object[] { this }, mxConstants.STYLE_ROTATION, Integer.toString(angle));
1741         }
1742     }
1743
1744     /**
1745      * Useful when we need to update local properties with mxCell style
1746      * properties
1747      */
1748     public void updateFieldsFromStyle() {
1749         StyleMap map = new StyleMap(getStyle());
1750
1751         if (map.get(mxConstants.STYLE_ROTATION) != null) {
1752             angle = Integer.parseInt(map.get(mxConstants.STYLE_ROTATION));
1753         } else {
1754             angle = 0;
1755         }
1756
1757         isFlipped = Boolean.parseBoolean(map.get(ScilabGraphConstants.STYLE_FLIP));
1758         isMirrored = Boolean.parseBoolean(map.get(ScilabGraphConstants.STYLE_MIRROR));
1759     }
1760
1761     /**
1762      * Set the default block position on the geom
1763      *
1764      * @param geom
1765      *            the current geom
1766      */
1767     private void setDefaultPosition(mxGeometry geom) {
1768         geom.setX(DEFAULT_POSITION_X);
1769         geom.setY(DEFAULT_POSITION_Y);
1770     }
1771
1772     /**
1773      * Get the parameters change support.
1774      *
1775      * The property name for each event is the field name, so one of: -
1776      * "interfaceFunctionName" - "simulationFunctionName" -
1777      * "simulationFunctionType" - "exprs" - "realParameters" -
1778      * "integerParameters" - "objectsParameters" - "nbZerosCrossing" - "nmode" -
1779      * "state" - "dState" - "oDState" - "equations" - "dependsOnU" -
1780      * "dependsOnT" - "blockType" - "ordering"
1781      *
1782      * @return the associated {@link PropertyChangeSupport} instance
1783      */
1784     protected PropertyChangeSupport getParametersPCS() {
1785         return parametersPCS;
1786     }
1787
1788     /*
1789      * Overriden methods from jgraphx
1790      */
1791
1792     /**
1793      * @return always false
1794      * @see com.mxgraph.model.mxCell#isConnectable()
1795      */
1796     @Override
1797     public boolean isConnectable() {
1798         return false;
1799     }
1800
1801     /**
1802      * Re-associate fields with the new instance.
1803      *
1804      * @return a new clone instance
1805      * @throws CloneNotSupportedException
1806      *             never
1807      * @see com.mxgraph.model.mxCell#clone()
1808      */
1809     @Override
1810     public Object clone() throws CloneNotSupportedException {
1811         BasicBlock clone = (BasicBlock) super.clone();
1812
1813         /* Reinstall the PropertyChangeSupport and all of it listeners */
1814         clone.parametersPCS = new PropertyChangeSupport(clone);
1815         PropertyChangeSupport pcs = getParametersPCS();
1816         for (PropertyChangeListener iter : pcs.getPropertyChangeListeners()) {
1817             clone.parametersPCS.addPropertyChangeListener(iter);
1818         }
1819
1820         return clone;
1821     }
1822
1823     /**
1824      * {@inheritDoc}
1825      *
1826      * Sync the specific child {@link EditFormatAction#HASH_IDENTIFIER}
1827      */
1828     @Override
1829     public mxICell insert(mxICell child, int index) {
1830         /*
1831          * Update the id if this is an identifier cell (herited identifier)
1832          */
1833         if (child.getId().endsWith(XcosDiagram.HASH_IDENTIFIER)) {
1834             child.setId(getId() + XcosDiagram.HASH_IDENTIFIER);
1835         }
1836
1837         return super.insert(child, index);
1838     }
1839
1840     @Override
1841     public String toString() {
1842         final StringBuilder str = new StringBuilder();
1843         str.append(getInterfaceFunctionName());
1844         str.append("\n");
1845         for (Object c : children) {
1846             str.append(c);
1847             str.append("\n");
1848         }
1849
1850         return str.toString();
1851     }
1852 }
1853 // CSON: ClassDataAbstractionCoupling
1854 // CSON: ClassFanOutComplexity