fix wrong delete of user_data in gda
[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  * Copyright (C) 2011-2017 - Scilab Enterprises - Clement DAVID
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.xcos.block;
18
19 import java.awt.MouseInfo;
20 import java.io.Serializable;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Deque;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import org.scilab.modules.action_binding.InterpreterManagement;
33 import org.scilab.modules.graph.ScilabGraph;
34 import org.scilab.modules.graph.actions.CopyAction;
35 import org.scilab.modules.graph.actions.CutAction;
36 import org.scilab.modules.graph.actions.DeleteAction;
37 import org.scilab.modules.graph.actions.base.DefaultAction;
38 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
39 import org.scilab.modules.gui.contextmenu.ContextMenu;
40 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
41 import org.scilab.modules.gui.events.callback.CommonCallBack;
42 import org.scilab.modules.gui.menu.Menu;
43 import org.scilab.modules.gui.menu.ScilabMenu;
44 import org.scilab.modules.gui.menuitem.MenuItem;
45 import org.scilab.modules.gui.menuitem.ScilabMenuItem;
46 import org.scilab.modules.xcos.JavaController;
47 import org.scilab.modules.xcos.Kind;
48 import org.scilab.modules.xcos.ObjectProperties;
49 import org.scilab.modules.xcos.VectorOfDouble;
50 import org.scilab.modules.xcos.VectorOfInt;
51 import org.scilab.modules.xcos.VectorOfScicosID;
52 import org.scilab.modules.xcos.VectorOfString;
53 import org.scilab.modules.xcos.Xcos;
54 import org.scilab.modules.xcos.XcosTab;
55 import org.scilab.modules.xcos.actions.EditFormatAction;
56 import org.scilab.modules.xcos.actions.ShowHideShadowAction;
57 import org.scilab.modules.xcos.block.actions.AutoPositionSplitBlockAction;
58 import org.scilab.modules.xcos.block.actions.BlockDocumentationAction;
59 import org.scilab.modules.xcos.block.actions.BlockParametersAction;
60 import org.scilab.modules.xcos.block.actions.BorderColorAction;
61 import org.scilab.modules.xcos.block.actions.FilledColorAction;
62 import org.scilab.modules.xcos.block.actions.FlipAction;
63 import org.scilab.modules.xcos.block.actions.MirrorAction;
64 import org.scilab.modules.xcos.block.actions.RegionToSuperblockAction;
65 import org.scilab.modules.xcos.block.actions.RotateAction;
66 import org.scilab.modules.xcos.block.actions.ViewDetailsAction;
67 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockAction;
68 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionBottom;
69 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionCenter;
70 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionLeft;
71 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionMiddle;
72 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionRight;
73 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionTop;
74 import org.scilab.modules.xcos.graph.XcosDiagram;
75 import org.scilab.modules.xcos.graph.model.XcosCell;
76 import org.scilab.modules.xcos.port.command.CommandPort;
77 import org.scilab.modules.xcos.port.control.ControlPort;
78 import org.scilab.modules.xcos.port.input.InputPort;
79 import org.scilab.modules.xcos.port.output.OutputPort;
80 import org.scilab.modules.xcos.utils.BlockPositioning;
81 import org.scilab.modules.xcos.utils.XcosMessages;
82
83 import com.mxgraph.model.mxGeometry;
84 import com.mxgraph.model.mxICell;
85
86 /**
87  * A block on the diagram
88  */
89 @SuppressWarnings(value = { "serial" })
90 public class BasicBlock extends XcosCell implements Serializable {
91     /**
92      * Sorted kind of input, useful to sort them by kind
93      */
94     private static final Class<?>[] sortedChildrenClass = { InputPort.class, OutputPort.class, ControlPort.class, CommandPort.class, Object.class };
95
96     /*
97      * Default values
98      */
99
100     /**
101      * Default interface function name
102      */
103     public static final String DEFAULT_INTERFACE_FUNCTION = "xcos_block";
104     /**
105      * Default simulation function name
106      */
107     public static final String DEFAULT_SIMULATION_FUNCTION = "xcos_simulate";
108
109     /*
110      * Local constants
111      */
112
113     protected static final double DEFAULT_POSITION_X = 10.0;
114     protected static final double DEFAULT_POSITION_Y = 10.0;
115     private static final double DEFAULT_WIDTH = 40.0;
116     private static final double DEFAULT_HEIGHT = 40.0;
117
118     /**
119      * Internal method to get a base index to compare with depending on the cell type.
120      *
121      * @param cell
122      *            the cell
123      * @return the base index
124      */
125     private static int compareByChildClass(final Object o1, final Object o2) {
126         int o1Index = 0;
127         int o2Index = 0;
128
129         for (int i = 0; i < sortedChildrenClass.length; i++) {
130             final Class<?> klass = sortedChildrenClass[i];
131
132             if (klass.isInstance(o1)) {
133                 o1Index = i;
134                 break;
135             }
136         }
137         for (int i = 0; i < sortedChildrenClass.length; i++) {
138             final Class<?> klass = sortedChildrenClass[i];
139
140             if (klass.isInstance(o2)) {
141                 o2Index = i;
142                 break;
143             }
144         }
145
146         final int base = o1Index - o2Index;
147         return base * (Integer.MAX_VALUE / sortedChildrenClass.length);
148     }
149
150     private boolean locked;
151
152     /**
153      * Hook used to implement specifix behavior after any parameter update and before re-layouting the block
154      */
155     public void updateBlockView() {
156     }
157
158     /**
159      * Represent a simulation function type compatible with Scilab/Scicos function type descriptors.
160      */
161     public static enum SimulationFunctionType {
162         /** event select; reduced at compilation */
163         ESELECT(-2), /** if then else; reduced at compilation */
164         IFTHENELSE(-1), /** first common block */
165         DEFAULT(0), /** first native block */
166         TYPE_1(1), /** second native block */
167         TYPE_2(2), /** third native block */
168         TYPE_3(3), /** forth native block */
169         C_OR_FORTRAN(4), /** Scilab blocks */
170         SCILAB(5), /** Debug blocks */
171         DEBUG(99), /** dynamic {@link #TYPE_1} Fortran blocks (fortran_block.sci) */
172         DYNAMIC_FORTRAN_1(1001), /** dynamic {@link #TYPE_1} C blocks (c_block.sci) */
173         DYNAMIC_C_1(2001), /** Explicit dynamic {@link #TYPE_4} blocks (CBLOCK.sci) */
174         DYNAMIC_EXPLICIT_4(2004), /** Implicit {@link #TYPE_1} Fortran blocks (DIFF_f.sci) */
175         OLDBLOCKS(10001), /** Implicit {@link #C_OR_FORTRAN} blocks */
176         IMPLICIT_C_OR_FORTRAN(10004), /** Implicit dynamic {@link #TYPE_4} blocks (CBLOCK.sci) */
177         DYNAMIC_IMPLICIT_4(12004), /** Modelica {@link #C_OR_FORTRAN} blocks */
178         MODELICA(30004), /** Magic types */
179         UNKNOWN(5);
180
181         private final int value;
182
183         /**
184          * Default constructor
185          *
186          * @param scilabValue
187          *            Scilab/Scicos function type descriptor
188          */
189         private SimulationFunctionType(int scilabValue) {
190             value = scilabValue;
191         }
192
193         /**
194          * Get the Java descriptor from the Scilab descriptor.
195          *
196          * @param scilabValue
197          *            Scilab/Scicos function type descriptor
198          * @return The corresponding java descriptor
199          */
200         public static SimulationFunctionType convertScilabValue(int scilabValue) {
201             for (SimulationFunctionType iter : SimulationFunctionType.values()) {
202                 if (iter.getValue() == scilabValue) {
203                     return iter;
204                 }
205             }
206             return UNKNOWN;
207         }
208
209         /**
210          * Get the Scilab Descriptor from the Java Descriptor
211          *
212          * @return The corresponding Scilab/Scicos descriptor
213          */
214         public int getValue() {
215             return value;
216         }
217     };
218
219     /**
220      * Constructor that setup some properties and pass all its arguments this its {@link XcosCell} parent.
221      *
222      *
223      * @param controller The shared controller instance
224      * @param uid the uid of the MVC object
225      * @param kind {@link Kind#BLOCK} or {@link Kind#ANNOTATION}
226      * @param value the value of the block
227      * @param geometry the geometry to apply to this JGraphX object
228      * @param style the style to apply to this JGraphX object
229      * @param id the id to apply to this JGraphX object
230      */
231     public BasicBlock(final JavaController controller, long uid, Kind kind, Object value, mxGeometry geometry, String style, String id) {
232         super(controller, uid, kind, value, geometry, style, id);
233
234         /*
235          * Default JGraphX properties for blocks
236          */
237         this.visible = true;
238         this.vertex = true;
239         this.connectable = false;
240     }
241
242     /**
243      * @return locked status
244      */
245     public synchronized boolean isLocked() {
246         return locked;
247     }
248
249     /**
250      * @param locked
251      *            change locked status
252      */
253     public synchronized void setLocked(boolean locked) {
254         this.locked = locked;
255     }
256
257     /**
258      * Does the block update and register on the undo manager
259      * @param controller the shared controller
260      * @param parent the parent diagram or superblock diagram
261      * @param modifiedBlock the new settings
262      */
263     public void updateBlockSettings(JavaController controller, XcosDiagram parent, BasicBlock modifiedBlock) {
264         if (modifiedBlock == null) {
265             return;
266         }
267
268         /*
269          * Update the block settings
270          */
271         updateFields(controller, parent, modifiedBlock);
272
273         /*
274          * Update the children ports
275          */
276         updateChildren(controller, parent, modifiedBlock);
277     }
278
279     /**
280      * Update the instance field and the model values
281      *
282      * @param modifiedBlock
283      *            the modified instance
284      */
285     protected void updateFields(JavaController controller, XcosDiagram parent, BasicBlock modifiedBlock) {
286         if (modifiedBlock == null) {
287             return;
288         }
289
290         // TODO these copies are not managed by undo/redo ; fix that
291
292         int[] integer = new int[1];
293
294         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_FUNCTION_API, integer);
295         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_FUNCTION_API, integer[0]);
296
297         String[] str = new String[1];
298
299         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.INTERFACE_FUNCTION, str);
300         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.INTERFACE_FUNCTION, str[0]);
301
302         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_FUNCTION_NAME, str);
303         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_FUNCTION_NAME, str[0]);
304
305         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_BLOCKTYPE, str);
306         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_BLOCKTYPE, str[0]);
307
308         VectorOfDouble vDouble = new VectorOfDouble();
309
310         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.EXPRS, vDouble);
311         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.EXPRS, vDouble);
312
313         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.STATE, vDouble);
314         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.STATE, vDouble);
315
316         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.DSTATE, vDouble);
317         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.DSTATE, vDouble);
318
319         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.ODSTATE, vDouble);
320         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.ODSTATE, vDouble);
321
322         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.RPAR, vDouble);
323         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.RPAR, vDouble);
324
325         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.OPAR, vDouble);
326         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.OPAR, vDouble);
327
328         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.EQUATIONS, vDouble);
329         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.EQUATIONS, vDouble);
330
331         VectorOfInt vInt = new VectorOfInt();
332
333         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.SIM_DEP_UT, vInt);
334         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.SIM_DEP_UT, vInt);
335
336         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.NZCROSS, vInt);
337         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.NZCROSS, vInt);
338
339         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.NMODE, vInt);
340         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.NMODE, vInt);
341
342         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.IPAR, vInt);
343         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.IPAR, vInt);
344
345         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.COLOR, vInt);
346         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.COLOR, vInt);
347
348         VectorOfString vStr = new VectorOfString();
349
350         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.DIAGRAM_CONTEXT, vStr);
351         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.DIAGRAM_CONTEXT, vStr);
352
353         VectorOfScicosID localChildren = new VectorOfScicosID();
354
355         controller.getObjectProperty(modifiedBlock.getUID(), modifiedBlock.getKind(), ObjectProperties.CHILDREN, localChildren);
356         controller.setObjectProperty(getUID(), getKind(), ObjectProperties.CHILDREN, localChildren);
357
358         /*
359          * JGraphX mapped properties
360          */
361         updateStyle(controller, parent, modifiedBlock);
362         updateValue(controller, parent, modifiedBlock);
363     }
364
365     /**
366      * Update the JGraphX style property accordingly to the block new style
367      *
368      * @param controller shared controller
369      * @param parent the diagram
370      * @param modifiedBlock a block copy containing the new style
371      */
372     protected void updateStyle(JavaController controller, XcosDiagram parent, BasicBlock modifiedBlock) {
373         parent.getModel().setStyle(this, modifiedBlock.getStyle());
374     }
375
376     /**
377      * Update the JGraphX style property accordingly to the block new value
378      *
379      * @param controller shared controller
380      * @param parent the diagram
381      * @param modifiedBlock a block copy containing the new value
382      */
383     protected void updateValue(JavaController controller, XcosDiagram parent, BasicBlock modifiedBlock) {
384         parent.getModel().setValue(this, modifiedBlock.getValue());
385     }
386
387     /**
388      * Update the children of the block.
389      *
390      * @param modifiedBlock
391      *            the new block instance
392      */
393     protected void updateChildren(JavaController controller, XcosDiagram parent, BasicBlock modifiedBlock) {
394         if (modifiedBlock == null) {
395             return;
396         }
397
398         /*
399          * Checked as port classes only
400          */
401         Set < Class <? extends mxICell >> types = new HashSet < > (Arrays.asList(InputPort.class, OutputPort.class, ControlPort.class, CommandPort.class));
402
403         Map < Class <? extends mxICell > , Deque<mxICell >> annotatedOlds = getTypedChildren(types);
404         Map < Class <? extends mxICell > , Deque<mxICell >> annotatedNews = modifiedBlock.getTypedChildren(types);
405
406         parent.getModel().beginUpdate();
407         try {
408             for (Class <? extends mxICell > klass : types) {
409                 final Deque<mxICell> olds = annotatedOlds.get(klass);
410                 final Deque<mxICell> news = annotatedNews.get(klass);
411
412                 // updated ports
413                 while (!olds.isEmpty() && !news.isEmpty()) {
414                     mxICell previous = olds.poll();
415                     mxICell modified = news.poll();
416
417                     final int previousIndex = children.indexOf(previous);
418
419                     // relink
420                     if (previous.getEdgeCount() != 0) {
421                         final mxICell relinked = previous.getEdgeAt(0);
422                         final boolean isOutgoing = previous == relinked.getTerminal(true);
423                         previous.removeEdge(relinked, isOutgoing);
424                         modified.insertEdge(relinked, isOutgoing);
425                     }
426
427                     parent.removeCells(new Object[] { previous }, false);
428                     parent.addCells(new Object[] { modified }, this, previousIndex);
429
430                     // Clone the geometry to avoid empty geometry on new cells.
431                     parent.getModel().setGeometry(modified, (mxGeometry) previous.getGeometry().clone());
432
433                 }
434
435                 // removed ports
436                 if (!olds.isEmpty()) {
437                     parent.removeCells(olds.toArray(), true);
438                 }
439
440                 // added ports
441                 if (!news.isEmpty()) {
442                     parent.addCells(news.toArray(), this);
443                 }
444             }
445         } finally {
446             parent.getModel().endUpdate();
447         }
448     }
449
450     /**
451      * Format the children as a typed map for the given class set.
452      *
453      * @param types
454      *            the classes to search for.
455      * @return a map which linked foreach type the corresponding cell list.
456      */
457     private Map < Class <? extends mxICell > , Deque<mxICell >> getTypedChildren(Set < Class <? extends mxICell >> types) {
458         Map < Class <? extends mxICell > , Deque<mxICell >> oldPorts = new HashMap < > ();
459
460         // Allocate all types set
461         for (Class <? extends mxICell > type : types) {
462             oldPorts.put(type, new LinkedList<>());
463         }
464
465         if (getChildCount() <= 0) {
466             return oldPorts;
467         }
468
469         // children lookup
470         for (Object cell : children) {
471
472             Class <? extends Object > klass = cell.getClass();
473             while (klass != null) {
474                 if (types.contains(klass)) {
475                     break;
476                 }
477                 klass = klass.getSuperclass();
478             }
479
480             final Deque<mxICell> current = oldPorts.get(klass);
481             if (current != null) {
482                 current.add((mxICell) cell);
483             }
484         }
485
486         return oldPorts;
487     }
488
489     /**
490      * Format the children as a typed map index for the given class set.
491      *
492      * @param types
493      *            the classes to search for.
494      * @return a map which linked foreach type the corresponding cell index in the children.
495      */
496     private Map<Class<? extends mxICell>, ArrayList<Integer>> getTypedChildrenIndexes(Set<Class<? extends mxICell>> types) {
497         Map<Class<? extends mxICell>, ArrayList<Integer>> oldPorts = new HashMap<Class<? extends mxICell>, ArrayList<Integer>>();
498
499         // Allocate all types set
500         for (Class<? extends mxICell> type : types) {
501             oldPorts.put(type, new ArrayList<>());
502         }
503
504         if (getChildCount() <= 0) {
505             return oldPorts;
506         }
507
508         // children lookup
509         for (int i = 0; i < children.size(); i++) {
510             final Object cell = children.get(i);
511
512             Class<? extends Object> klass = cell.getClass();
513             while (klass != null) {
514                 if (types.contains(klass)) {
515                     break;
516                 }
517                 klass = klass.getSuperclass();
518             }
519
520             final ArrayList<Integer> current = oldPorts.get(klass);
521             if (current != null) {
522                 current.add(i);
523             }
524         }
525
526         return oldPorts;
527     }
528
529     public ArrayList<Integer> getTypedChildrenIndexes(Class<? extends mxICell> type) {
530         return getTypedChildrenIndexes(Collections.singleton(type)).get(type);
531     }
532
533     public Map<Class<? extends mxICell>, ArrayList<Long>> getTypedChildrenUIDs(Set<Class<? extends mxICell>> types) {
534         Map<Class<? extends mxICell>, ArrayList<Long>> ports = new HashMap<>();
535
536         // Allocate all types set
537         types.stream().forEach(t -> ports.put(t, new ArrayList<>()));
538
539         if (getChildCount() <= 0) {
540             return ports;
541         }
542
543         // children lookup
544         for (int i = 0; i < children.size(); i++) {
545             final Object cell = children.get(i);
546
547             Class<? extends Object> klass = cell.getClass();
548             while (klass != null) {
549                 if (types.contains(klass)) {
550                     break;
551                 }
552                 klass = klass.getSuperclass();
553             }
554
555             final ArrayList<Long> current = ports.get(klass);
556             if (current != null) {
557                 if (cell instanceof XcosCell) {
558                     current.add(((XcosCell) cell).getUID());
559                 } else {
560                     current.add(0l);
561                 }
562             }
563         }
564
565         return ports;
566     }
567
568     public ArrayList<Long> getTypedChildrenUIDs(Class<? extends mxICell> type) {
569         return getTypedChildrenUIDs(Collections.singleton(type)).get(type);
570     }
571
572     /**
573      * @param graph
574      *            parent graph
575      */
576     public void openContextMenu(ScilabGraph graph) {
577         ContextMenu menu = null;
578         // if (getParentDiagram() instanceof PaletteDiagram) {
579         // menu = createPaletteContextMenu(graph);
580         // } else {
581         menu = createContextMenu(graph);
582         // }
583         menu.setVisible(true);
584     }
585
586     /**
587      * @param graph
588      *            parent graph
589      * @return context menu
590      */
591     // CSOFF: JavaNCSS
592     public ContextMenu createPaletteContextMenu(ScilabGraph graph) {
593         ContextMenu menu = ScilabContextMenu.createContextMenu();
594
595         final List<XcosDiagram> allDiagrams = Xcos.getInstance().openedDiagrams();
596
597         if (allDiagrams.size() == 0) {
598             // No diagram opened: should never happen if Xcos opens an empty
599             // diagram when it is launched
600             MenuItem addTo = ScilabMenuItem.createMenuItem();
601
602             addTo.setText(XcosMessages.ADDTO_NEW_DIAGRAM);
603             addTo.setCallback(new CommonCallBack(XcosMessages.ADDTO_NEW_DIAGRAM) {
604                 @Override
605                 public void callBack() {
606                     JavaController controller = new JavaController();
607                     BasicBlock block = null;
608                     try {
609                         block = (BasicBlock) BasicBlock.this.clone();
610                     } catch (CloneNotSupportedException e) {
611                         e.printStackTrace();
612                     }
613
614                     XcosDiagram theDiagram = new XcosDiagram(controller, controller.createObject(Kind.DIAGRAM), Kind.DIAGRAM, "");
615                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
616                     mxGeometry geom = BasicBlock.this.getGeometry();
617                     setDefaultPosition(geom);
618                     theDiagram.getModel().setGeometry(block, geom);
619
620                     XcosTab.get(theDiagram).setVisible(true);
621                     BlockPositioning.updateBlockView(theDiagram, block);
622                 }
623             });
624
625             menu.add(addTo);
626
627         } else if (allDiagrams.size() == 1) {
628             // A single diagram opened: add to this diagram
629             MenuItem addTo = ScilabMenuItem.createMenuItem();
630
631             addTo.setText(XcosMessages.ADDTO + " " + XcosTab.get(allDiagrams.get(0)).getName());
632             final XcosDiagram theDiagram = allDiagrams.get(0);
633             addTo.setCallback(new CommonCallBack(theDiagram.getTitle()) {
634                 private static final long serialVersionUID = -99601763227525686L;
635
636                 @Override
637                 public void callBack() {
638                     BasicBlock block = null;
639                     try {
640                         block = (BasicBlock) BasicBlock.this.clone();
641                     } catch (CloneNotSupportedException e) {
642                         e.printStackTrace();
643                     }
644                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
645                     mxGeometry geom = BasicBlock.this.getGeometry();
646                     setDefaultPosition(geom);
647                     theDiagram.getModel().setGeometry(block, geom);
648                     BlockPositioning.updateBlockView(theDiagram, block);
649                 }
650             });
651
652             menu.add(addTo);
653
654         } else {
655             // The user has to choose
656             Menu addTo = ScilabMenu.createMenu();
657
658             addTo.setText(XcosMessages.ADDTO);
659
660             for (int i = 0; i < allDiagrams.size(); i++) {
661                 MenuItem diagram = ScilabMenuItem.createMenuItem();
662                 final XcosDiagram theDiagram = allDiagrams.get(i);
663                 diagram.setText(XcosTab.get(allDiagrams.get(i)).getName());
664                 diagram.setCallback(new CommonCallBack(theDiagram.getTitle()) {
665                     private static final long serialVersionUID = 3345416658377835057L;
666
667                     @Override
668                     public void callBack() {
669                         BasicBlock block = null;
670                         try {
671                             block = (BasicBlock) BasicBlock.this.clone();
672                         } catch (CloneNotSupportedException e) {
673                             e.printStackTrace();
674                         }
675                         theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
676                         mxGeometry geom = BasicBlock.this.getGeometry();
677                         setDefaultPosition(geom);
678                         theDiagram.getModel().setGeometry(block, geom);
679                         BlockPositioning.updateBlockView(theDiagram, block);
680                     }
681                 });
682                 addTo.add(diagram);
683             }
684
685             menu.add(addTo);
686         }
687
688         menu.getAsSimpleContextMenu().addSeparator();
689
690         MenuItem help = ScilabMenuItem.createMenuItem();
691         help.setText(XcosMessages.BLOCK_DOCUMENTATION);
692         help.setCallback(new CommonCallBack(XcosMessages.BLOCK_DOCUMENTATION) {
693             private static final long serialVersionUID = -1480947262397441951L;
694
695             @Override
696             public void callBack() {
697                 JavaController controller = new JavaController();
698                 String[] interfaceFunctionName = new String[1];
699                 controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, interfaceFunctionName);
700
701                 InterpreterManagement.requestScilabExec("help " + interfaceFunctionName[0]);
702             }
703         });
704         menu.add(help);
705
706         menu.setVisible(true);
707
708         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x,
709                 MouseInfo.getPointerInfo().getLocation().y);
710
711         return menu;
712     }
713
714     // CSON: JavaNCSS
715
716     /**
717      * @param graph
718      *            parent graph
719      * @return context menu
720      */
721     // CSOFF: JavaNCSS
722     public ContextMenu createContextMenu(ScilabGraph graph) {
723         ContextMenu menu = ScilabContextMenu.createContextMenu();
724         Map<Class<? extends DefaultAction>, Menu> menuList = new HashMap<>();
725
726         MenuItem value = BlockParametersAction.createMenu(graph);
727         menuList.put(BlockParametersAction.class, value);
728         menu.add(value);
729         /*--- */
730         menu.getAsSimpleContextMenu().addSeparator();
731         /*--- */
732         value = CutAction.cutMenu(graph);
733         menuList.put(CutAction.class, value);
734         menu.add(value);
735         value = CopyAction.copyMenu(graph);
736         menuList.put(CopyAction.class, value);
737         menu.add(value);
738         value = DeleteAction.createMenu(graph);
739         menuList.put(DeleteAction.class, value);
740         menu.add(value);
741         /*--- */
742         menu.getAsSimpleContextMenu().addSeparator();
743         /*--- */
744         value = RegionToSuperblockAction.createMenu(graph);
745         menuList.put(RegionToSuperblockAction.class, value);
746         menu.add(value);
747         /*--- */
748         menu.getAsSimpleContextMenu().addSeparator();
749         /*--- */
750         Menu format = ScilabMenu.createMenu();
751         format.setText(XcosMessages.FORMAT);
752         menu.add(format);
753         value = RotateAction.createMenu(graph);
754         menuList.put(RotateAction.class, value);
755         format.add(value);
756         value = MirrorAction.createMenu(graph);
757         menuList.put(MirrorAction.class, value);
758         format.add(value);
759         value = FlipAction.createMenu(graph);
760         menuList.put(FlipAction.class, value);
761         format.add(value);
762         value = ShowHideShadowAction.createMenu(graph);
763         menuList.put(ShowHideShadowAction.class, value);
764         format.add(value);
765         /*--- */
766         format.addSeparator();
767         /*--- */
768         Menu alignMenu = ScilabMenu.createMenu();
769         alignMenu.setText(XcosMessages.ALIGN_BLOCKS);
770         alignMenu.add(AlignBlockActionLeft.createMenu(graph));
771         alignMenu.add(AlignBlockActionCenter.createMenu(graph));
772         alignMenu.add(AlignBlockActionRight.createMenu(graph));
773         alignMenu.addSeparator();
774         alignMenu.add(AlignBlockActionTop.createMenu(graph));
775         alignMenu.add(AlignBlockActionMiddle.createMenu(graph));
776         alignMenu.add(AlignBlockActionBottom.createMenu(graph));
777         menuList.put(AlignBlockAction.class, alignMenu);
778         format.add(alignMenu);
779         /*--- */
780         format.addSeparator();
781         /*--- */
782         MenuItem sbapMenuItem = AutoPositionSplitBlockAction.createMenu(graph);
783         sbapMenuItem.setText(XcosMessages.BLOCK_AUTO_POSITION_SPLIT_BLOCK_CONTEXTUAL);
784         sbapMenuItem.setEnabled(false);
785         menuList.put(AutoPositionSplitBlockAction.class, sbapMenuItem);
786         format.add(sbapMenuItem);
787         /*--- */
788         format.addSeparator();
789         /*--- */
790         if (graph.getSelectionCells().length > 1) {
791             format.add(BorderColorAction.createMenu(graph));
792             format.add(FilledColorAction.createMenu(graph));
793         } else {
794             format.add(EditFormatAction.createMenu(graph));
795         }
796         /*--- */
797         menu.getAsSimpleContextMenu().addSeparator();
798         /*--- */
799         menu.add(ViewDetailsAction.createMenu(graph));
800         /*--- */
801         menu.getAsSimpleContextMenu().addSeparator();
802         /*--- */
803         menu.add(BlockDocumentationAction.createMenu(graph));
804
805         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x,
806                 MouseInfo.getPointerInfo().getLocation().y);
807
808         customizeMenu(menuList);
809
810         return menu;
811     }
812
813     /**
814      * Override this to customize contextual menu
815      *
816      * @param menuList
817      *            list of menu
818      */
819     protected void customizeMenu(Map<Class<? extends DefaultAction>, Menu> menuList) {
820         // To be overridden by sub-classes
821     }
822
823     /**
824      * Set the default block position on the geom
825      *
826      * @param geom
827      *            the current geom
828      */
829     private void setDefaultPosition(mxGeometry geom) {
830         geom.setX(DEFAULT_POSITION_X);
831         geom.setY(DEFAULT_POSITION_Y);
832     }
833
834     /*
835      * Overriden methods from jgraphx
836      */
837
838     /**
839      * @return always false
840      * @see com.mxgraph.model.mxCell#isConnectable()
841      */
842     @Override
843     public boolean isConnectable() {
844         return false;
845     }
846
847     /**
848      * {@inheritDoc}
849      *
850      * Sync the specific child {@link EditFormatAction#HASH_IDENTIFIER}
851      */
852     @Override
853     public mxICell insert(mxICell child, int index) {
854         /*
855          * Update the id if this is an identifier cell (herited identifier)
856          */
857         if (child.getId().endsWith(XcosDiagram.HASH_IDENTIFIER)) {
858             child.setId(getId() + XcosDiagram.HASH_IDENTIFIER);
859         }
860
861         return super.insert(child, index);
862     }
863 }