28ae4ae13a5dd198fd5f22fce2faa5e717bc8860
[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  *
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     private 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         parent.getModel().setStyle(this, modifiedBlock.getStyle());
362         parent.getModel().setValue(this, modifiedBlock.getValue());
363     }
364
365     /**
366      * Update the children of the block.
367      *
368      * @param modifiedBlock
369      *            the new block instance
370      */
371     private void updateChildren(JavaController controller, XcosDiagram parent, BasicBlock modifiedBlock) {
372         if (modifiedBlock == null) {
373             return;
374         }
375
376         /*
377          * Checked as port classes only
378          */
379         Set < Class <? extends mxICell >> types = new HashSet < > (Arrays.asList(InputPort.class, OutputPort.class, ControlPort.class, CommandPort.class));
380
381         Map < Class <? extends mxICell > , Deque<mxICell >> annotatedOlds = getTypedChildren(types);
382         Map < Class <? extends mxICell > , Deque<mxICell >> annotatedNews = modifiedBlock.getTypedChildren(types);
383
384         parent.getModel().beginUpdate();
385         try {
386             for (Class <? extends mxICell > klass : types) {
387                 final Deque<mxICell> olds = annotatedOlds.get(klass);
388                 final Deque<mxICell> news = annotatedNews.get(klass);
389
390                 // updated ports
391                 while (!olds.isEmpty() && !news.isEmpty()) {
392                     mxICell previous = olds.poll();
393                     mxICell modified = news.poll();
394
395                     final int previousIndex = children.indexOf(previous);
396
397                     // relink
398                     if (previous.getEdgeCount() != 0) {
399                         final mxICell relinked = previous.getEdgeAt(0);
400                         final boolean isOutgoing = previous == relinked.getTerminal(true);
401                         previous.removeEdge(relinked, isOutgoing);
402                         modified.insertEdge(relinked, isOutgoing);
403                     }
404
405                     parent.removeCells(new Object[] { previous }, false);
406                     parent.addCells(new Object[] { modified }, this, previousIndex);
407
408                     // Clone the geometry to avoid empty geometry on new cells.
409                     parent.getModel().setGeometry(modified, (mxGeometry) previous.getGeometry().clone());
410
411                 }
412
413                 // removed ports
414                 if (!olds.isEmpty()) {
415                     parent.removeCells(olds.toArray(), true);
416                 }
417
418                 // added ports
419                 if (!news.isEmpty()) {
420                     parent.addCells(news.toArray(), this);
421                 }
422             }
423         } finally {
424             parent.getModel().endUpdate();
425         }
426     }
427
428     /**
429      * Format the children as a typed map for the given class set.
430      *
431      * @param types
432      *            the classes to search for.
433      * @return a map which linked foreach type the corresponding cell list.
434      */
435     private Map < Class <? extends mxICell > , Deque<mxICell >> getTypedChildren(Set < Class <? extends mxICell >> types) {
436         Map < Class <? extends mxICell > , Deque<mxICell >> oldPorts = new HashMap < > ();
437
438         // Allocate all types set
439         for (Class <? extends mxICell > type : types) {
440             oldPorts.put(type, new LinkedList<>());
441         }
442
443         if (getChildCount() <= 0) {
444             return oldPorts;
445         }
446
447         // children lookup
448         for (Object cell : children) {
449
450             Class <? extends Object > klass = cell.getClass();
451             while (klass != null) {
452                 if (types.contains(klass)) {
453                     break;
454                 }
455                 klass = klass.getSuperclass();
456             }
457
458             final Deque<mxICell> current = oldPorts.get(klass);
459             if (current != null) {
460                 current.add((mxICell) cell);
461             }
462         }
463
464         return oldPorts;
465     }
466
467     /**
468      * Format the children as a typed map index for the given class set.
469      *
470      * @param types
471      *            the classes to search for.
472      * @return a map which linked foreach type the corresponding cell index in the children.
473      */
474     private Map<Class<? extends mxICell>, ArrayList<Integer>> getTypedChildrenIndexes(Set<Class<? extends mxICell>> types) {
475         Map<Class<? extends mxICell>, ArrayList<Integer>> oldPorts = new HashMap<Class<? extends mxICell>, ArrayList<Integer>>();
476
477         // Allocate all types set
478         for (Class<? extends mxICell> type : types) {
479             oldPorts.put(type, new ArrayList<>());
480         }
481
482         if (getChildCount() <= 0) {
483             return oldPorts;
484         }
485
486         // children lookup
487         for (int i = 0; i < children.size(); i++) {
488             final Object cell = children.get(i);
489
490             Class<? extends Object> klass = cell.getClass();
491             while (klass != null) {
492                 if (types.contains(klass)) {
493                     break;
494                 }
495                 klass = klass.getSuperclass();
496             }
497
498             final ArrayList<Integer> current = oldPorts.get(klass);
499             if (current != null) {
500                 current.add(i);
501             }
502         }
503
504         return oldPorts;
505     }
506
507     public ArrayList<Integer> getTypedChildrenIndexes(Class<? extends mxICell> type) {
508         return getTypedChildrenIndexes(Collections.singleton(type)).get(type);
509     }
510
511     public Map<Class<? extends mxICell>, ArrayList<Long>> getTypedChildrenUIDs(Set<Class<? extends mxICell>> types) {
512         Map<Class<? extends mxICell>, ArrayList<Long>> ports = new HashMap<>();
513
514         // Allocate all types set
515         types.stream().forEach(t -> ports.put(t, new ArrayList<>()));
516
517         if (getChildCount() <= 0) {
518             return ports;
519         }
520
521         // children lookup
522         for (int i = 0; i < children.size(); i++) {
523             final Object cell = children.get(i);
524
525             Class<? extends Object> klass = cell.getClass();
526             while (klass != null) {
527                 if (types.contains(klass)) {
528                     break;
529                 }
530                 klass = klass.getSuperclass();
531             }
532
533             final ArrayList<Long> current = ports.get(klass);
534             if (current != null) {
535                 if (cell instanceof XcosCell) {
536                     current.add(((XcosCell) cell).getUID());
537                 } else {
538                     current.add(0l);
539                 }
540             }
541         }
542
543         return ports;
544     }
545
546     public ArrayList<Long> getTypedChildrenUIDs(Class<? extends mxICell> type) {
547         return getTypedChildrenUIDs(Collections.singleton(type)).get(type);
548     }
549
550     /**
551      * @param graph
552      *            parent graph
553      */
554     public void openContextMenu(ScilabGraph graph) {
555         ContextMenu menu = null;
556         // if (getParentDiagram() instanceof PaletteDiagram) {
557         // menu = createPaletteContextMenu(graph);
558         // } else {
559         menu = createContextMenu(graph);
560         // }
561         menu.setVisible(true);
562     }
563
564     /**
565      * @param graph
566      *            parent graph
567      * @return context menu
568      */
569     // CSOFF: JavaNCSS
570     public ContextMenu createPaletteContextMenu(ScilabGraph graph) {
571         ContextMenu menu = ScilabContextMenu.createContextMenu();
572
573         final List<XcosDiagram> allDiagrams = Xcos.getInstance().openedDiagrams();
574
575         if (allDiagrams.size() == 0) {
576             // No diagram opened: should never happen if Xcos opens an empty
577             // diagram when it is launched
578             MenuItem addTo = ScilabMenuItem.createMenuItem();
579
580             addTo.setText(XcosMessages.ADDTO_NEW_DIAGRAM);
581             addTo.setCallback(new CommonCallBack(XcosMessages.ADDTO_NEW_DIAGRAM) {
582                 @Override
583                 public void callBack() {
584                     JavaController controller = new JavaController();
585                     BasicBlock block = null;
586                     try {
587                         block = (BasicBlock) BasicBlock.this.clone();
588                     } catch (CloneNotSupportedException e) {
589                         e.printStackTrace();
590                     }
591
592                     XcosDiagram theDiagram = new XcosDiagram(controller, controller.createObject(Kind.DIAGRAM), Kind.DIAGRAM, "");
593                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
594                     mxGeometry geom = BasicBlock.this.getGeometry();
595                     setDefaultPosition(geom);
596                     theDiagram.getModel().setGeometry(block, geom);
597
598                     XcosTab.get(theDiagram).setVisible(true);
599                     BlockPositioning.updateBlockView(theDiagram, block);
600                 }
601             });
602
603             menu.add(addTo);
604
605         } else if (allDiagrams.size() == 1) {
606             // A single diagram opened: add to this diagram
607             MenuItem addTo = ScilabMenuItem.createMenuItem();
608
609             addTo.setText(XcosMessages.ADDTO + " " + XcosTab.get(allDiagrams.get(0)).getName());
610             final XcosDiagram theDiagram = allDiagrams.get(0);
611             addTo.setCallback(new CommonCallBack(theDiagram.getTitle()) {
612                 private static final long serialVersionUID = -99601763227525686L;
613
614                 @Override
615                 public void callBack() {
616                     BasicBlock block = null;
617                     try {
618                         block = (BasicBlock) BasicBlock.this.clone();
619                     } catch (CloneNotSupportedException e) {
620                         e.printStackTrace();
621                     }
622                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
623                     mxGeometry geom = BasicBlock.this.getGeometry();
624                     setDefaultPosition(geom);
625                     theDiagram.getModel().setGeometry(block, geom);
626                     BlockPositioning.updateBlockView(theDiagram, block);
627                 }
628             });
629
630             menu.add(addTo);
631
632         } else {
633             // The user has to choose
634             Menu addTo = ScilabMenu.createMenu();
635
636             addTo.setText(XcosMessages.ADDTO);
637
638             for (int i = 0; i < allDiagrams.size(); i++) {
639                 MenuItem diagram = ScilabMenuItem.createMenuItem();
640                 final XcosDiagram theDiagram = allDiagrams.get(i);
641                 diagram.setText(XcosTab.get(allDiagrams.get(i)).getName());
642                 diagram.setCallback(new CommonCallBack(theDiagram.getTitle()) {
643                     private static final long serialVersionUID = 3345416658377835057L;
644
645                     @Override
646                     public void callBack() {
647                         BasicBlock block = null;
648                         try {
649                             block = (BasicBlock) BasicBlock.this.clone();
650                         } catch (CloneNotSupportedException e) {
651                             e.printStackTrace();
652                         }
653                         theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
654                         mxGeometry geom = BasicBlock.this.getGeometry();
655                         setDefaultPosition(geom);
656                         theDiagram.getModel().setGeometry(block, geom);
657                         BlockPositioning.updateBlockView(theDiagram, block);
658                     }
659                 });
660                 addTo.add(diagram);
661             }
662
663             menu.add(addTo);
664         }
665
666         menu.getAsSimpleContextMenu().addSeparator();
667
668         MenuItem help = ScilabMenuItem.createMenuItem();
669         help.setText(XcosMessages.BLOCK_DOCUMENTATION);
670         help.setCallback(new CommonCallBack(XcosMessages.BLOCK_DOCUMENTATION) {
671             private static final long serialVersionUID = -1480947262397441951L;
672
673             @Override
674             public void callBack() {
675                 JavaController controller = new JavaController();
676                 String[] interfaceFunctionName = new String[1];
677                 controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, interfaceFunctionName);
678
679                 InterpreterManagement.requestScilabExec("help " + interfaceFunctionName[0]);
680             }
681         });
682         menu.add(help);
683
684         menu.setVisible(true);
685
686         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x,
687                 MouseInfo.getPointerInfo().getLocation().y);
688
689         return menu;
690     }
691
692     // CSON: JavaNCSS
693
694     /**
695      * @param graph
696      *            parent graph
697      * @return context menu
698      */
699     // CSOFF: JavaNCSS
700     public ContextMenu createContextMenu(ScilabGraph graph) {
701         ContextMenu menu = ScilabContextMenu.createContextMenu();
702         Map<Class<? extends DefaultAction>, Menu> menuList = new HashMap<>();
703
704         MenuItem value = BlockParametersAction.createMenu(graph);
705         menuList.put(BlockParametersAction.class, value);
706         menu.add(value);
707         /*--- */
708         menu.getAsSimpleContextMenu().addSeparator();
709         /*--- */
710         value = CutAction.cutMenu(graph);
711         menuList.put(CutAction.class, value);
712         menu.add(value);
713         value = CopyAction.copyMenu(graph);
714         menuList.put(CopyAction.class, value);
715         menu.add(value);
716         value = DeleteAction.createMenu(graph);
717         menuList.put(DeleteAction.class, value);
718         menu.add(value);
719         /*--- */
720         menu.getAsSimpleContextMenu().addSeparator();
721         /*--- */
722         value = RegionToSuperblockAction.createMenu(graph);
723         menuList.put(RegionToSuperblockAction.class, value);
724         menu.add(value);
725         /*--- */
726         menu.getAsSimpleContextMenu().addSeparator();
727         /*--- */
728         Menu format = ScilabMenu.createMenu();
729         format.setText(XcosMessages.FORMAT);
730         menu.add(format);
731         value = RotateAction.createMenu(graph);
732         menuList.put(RotateAction.class, value);
733         format.add(value);
734         value = MirrorAction.createMenu(graph);
735         menuList.put(MirrorAction.class, value);
736         format.add(value);
737         value = FlipAction.createMenu(graph);
738         menuList.put(FlipAction.class, value);
739         format.add(value);
740         value = ShowHideShadowAction.createMenu(graph);
741         menuList.put(ShowHideShadowAction.class, value);
742         format.add(value);
743         /*--- */
744         format.addSeparator();
745         /*--- */
746         Menu alignMenu = ScilabMenu.createMenu();
747         alignMenu.setText(XcosMessages.ALIGN_BLOCKS);
748         alignMenu.add(AlignBlockActionLeft.createMenu(graph));
749         alignMenu.add(AlignBlockActionCenter.createMenu(graph));
750         alignMenu.add(AlignBlockActionRight.createMenu(graph));
751         alignMenu.addSeparator();
752         alignMenu.add(AlignBlockActionTop.createMenu(graph));
753         alignMenu.add(AlignBlockActionMiddle.createMenu(graph));
754         alignMenu.add(AlignBlockActionBottom.createMenu(graph));
755         menuList.put(AlignBlockAction.class, alignMenu);
756         format.add(alignMenu);
757         /*--- */
758         format.addSeparator();
759         /*--- */
760         MenuItem sbapMenuItem = AutoPositionSplitBlockAction.createMenu(graph);
761         sbapMenuItem.setText(XcosMessages.BLOCK_AUTO_POSITION_SPLIT_BLOCK_CONTEXTUAL);
762         sbapMenuItem.setEnabled(false);
763         menuList.put(AutoPositionSplitBlockAction.class, sbapMenuItem);
764         format.add(sbapMenuItem);
765         /*--- */
766         format.addSeparator();
767         /*--- */
768         if (graph.getSelectionCells().length > 1) {
769             format.add(BorderColorAction.createMenu(graph));
770             format.add(FilledColorAction.createMenu(graph));
771         } else {
772             format.add(EditFormatAction.createMenu(graph));
773         }
774         /*--- */
775         menu.getAsSimpleContextMenu().addSeparator();
776         /*--- */
777         menu.add(ViewDetailsAction.createMenu(graph));
778         /*--- */
779         menu.getAsSimpleContextMenu().addSeparator();
780         /*--- */
781         menu.add(BlockDocumentationAction.createMenu(graph));
782
783         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x,
784                 MouseInfo.getPointerInfo().getLocation().y);
785
786         customizeMenu(menuList);
787
788         return menu;
789     }
790
791     /**
792      * Override this to customize contextual menu
793      *
794      * @param menuList
795      *            list of menu
796      */
797     protected void customizeMenu(Map<Class<? extends DefaultAction>, Menu> menuList) {
798         // To be overridden by sub-classes
799     }
800
801     /**
802      * Set the default block position on the geom
803      *
804      * @param geom
805      *            the current geom
806      */
807     private void setDefaultPosition(mxGeometry geom) {
808         geom.setX(DEFAULT_POSITION_X);
809         geom.setY(DEFAULT_POSITION_Y);
810     }
811
812     /*
813      * Overriden methods from jgraphx
814      */
815
816     /**
817      * @return always false
818      * @see com.mxgraph.model.mxCell#isConnectable()
819      */
820     @Override
821     public boolean isConnectable() {
822         return false;
823     }
824
825     /**
826      * {@inheritDoc}
827      *
828      * Sync the specific child {@link EditFormatAction#HASH_IDENTIFIER}
829      */
830     @Override
831     public mxICell insert(mxICell child, int index) {
832         /*
833          * Update the id if this is an identifier cell (herited identifier)
834          */
835         if (child.getId().endsWith(XcosDiagram.HASH_IDENTIFIER)) {
836             child.setId(getId() + XcosDiagram.HASH_IDENTIFIER);
837         }
838
839         return super.insert(child, index);
840     }
841 }