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