a042550847bb354283de86da786a131e0040535a
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / BasicBlock.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.block;
14
15 import java.awt.MouseInfo;
16 import java.io.Serializable;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.Deque;
22 import java.util.HashMap;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Optional;
27 import java.util.Set;
28
29 import org.scilab.modules.action_binding.InterpreterManagement;
30 import org.scilab.modules.graph.ScilabGraph;
31 import org.scilab.modules.graph.ScilabGraphUniqueObject;
32 import org.scilab.modules.graph.actions.CopyAction;
33 import org.scilab.modules.graph.actions.CutAction;
34 import org.scilab.modules.graph.actions.DeleteAction;
35 import org.scilab.modules.graph.actions.base.DefaultAction;
36 import org.scilab.modules.graph.utils.ScilabGraphConstants;
37 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
38 import org.scilab.modules.gui.contextmenu.ContextMenu;
39 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
40 import org.scilab.modules.gui.events.callback.CommonCallBack;
41 import org.scilab.modules.gui.menu.Menu;
42 import org.scilab.modules.gui.menu.ScilabMenu;
43 import org.scilab.modules.gui.menuitem.MenuItem;
44 import org.scilab.modules.gui.menuitem.ScilabMenuItem;
45 import org.scilab.modules.xcos.JavaController;
46 import org.scilab.modules.xcos.Kind;
47 import org.scilab.modules.xcos.ObjectProperties;
48 import org.scilab.modules.xcos.Xcos;
49 import org.scilab.modules.xcos.XcosTab;
50 import org.scilab.modules.xcos.actions.EditFormatAction;
51 import org.scilab.modules.xcos.actions.ShowHideShadowAction;
52 import org.scilab.modules.xcos.block.actions.BlockDocumentationAction;
53 import org.scilab.modules.xcos.block.actions.BlockParametersAction;
54 import org.scilab.modules.xcos.block.actions.BorderColorAction;
55 import org.scilab.modules.xcos.block.actions.FilledColorAction;
56 import org.scilab.modules.xcos.block.actions.FlipAction;
57 import org.scilab.modules.xcos.block.actions.MirrorAction;
58 import org.scilab.modules.xcos.block.actions.RegionToSuperblockAction;
59 import org.scilab.modules.xcos.block.actions.RotateAction;
60 import org.scilab.modules.xcos.block.actions.ViewDetailsAction;
61 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockAction;
62 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionBottom;
63 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionCenter;
64 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionLeft;
65 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionMiddle;
66 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionRight;
67 import org.scilab.modules.xcos.block.actions.alignement.AlignBlockActionTop;
68 import org.scilab.modules.xcos.graph.XcosDiagram;
69 import org.scilab.modules.xcos.io.scicos.BasicBlockInfo;
70 import org.scilab.modules.xcos.port.BasicPort;
71 import org.scilab.modules.xcos.port.command.CommandPort;
72 import org.scilab.modules.xcos.port.control.ControlPort;
73 import org.scilab.modules.xcos.port.input.InputPort;
74 import org.scilab.modules.xcos.port.output.OutputPort;
75 import org.scilab.modules.xcos.utils.BlockPositioning;
76 import org.scilab.modules.xcos.utils.XcosConstants;
77 import org.scilab.modules.xcos.utils.XcosMessages;
78
79 import com.mxgraph.model.mxGeometry;
80 import com.mxgraph.model.mxICell;
81
82 /**
83  * A block on the diagram
84  */
85 @SuppressWarnings(value = { "serial" })
86 public class BasicBlock extends ScilabGraphUniqueObject implements Serializable {
87     /**
88      * Sorted kind of input, useful to sort them by kind
89      */
90     private static final Class<?>[] sortedChildrenClass = {InputPort.class, OutputPort.class, ControlPort.class, CommandPort.class, Object.class};
91
92     /*
93      * Default values
94      */
95
96     /**
97      * Default interface function name
98      */
99     public static final String DEFAULT_INTERFACE_FUNCTION = "xcos_block";
100     /**
101      * Default simulation function name
102      */
103     public static final String DEFAULT_SIMULATION_FUNCTION = "xcos_simulate";
104
105     /*
106      * Local constants
107      */
108
109     private static final double DEFAULT_POSITION_X = 10.0;
110     private static final double DEFAULT_POSITION_Y = 10.0;
111     private static final double DEFAULT_WIDTH = 40.0;
112     private static final double DEFAULT_HEIGHT = 40.0;
113
114     /**
115      * Sort the children list in place.
116      *
117      * The sort put inputs then outputs the control then command ports. The
118      * local port order is preserved.The sort is performed in place and do not
119      * emit any event.
120      *
121      *
122      * @param children
123      *            the children to sort
124      */
125     public static final void sort(List<?> children) {
126         final List<Object> reference = new ArrayList<Object>(children);
127
128         Collections.sort(children, new Comparator<Object>() {
129             @Override
130             public int compare(Object o1, Object o2) {
131                 // diff is the major sorting by kind
132                 int diff = compareByChildClass(o1, o2);
133                 if (o1 instanceof BasicPort && o2 instanceof BasicPort) {
134                     // first sort with the port list index
135                     final int diffIndexOf = Integer.signum(reference.indexOf(o1) - reference.indexOf(o2));
136                     // then sort with the ordering value
137                     final int diffOrdering = Integer.signum(((BasicPort) o1).getOrdering() - ((BasicPort) o2).getOrdering());
138                     // then sort with the port position value
139                     final mxGeometry o1Geom = ((BasicPort) o1).getGeometry();
140                     final mxGeometry o2Geom = ((BasicPort) o2).getGeometry();
141                     final int diffPosition = Integer.signum((int) (o2Geom.getX() - o1Geom.getX() - o2Geom.getY() + o1Geom.getY()));
142
143                     // voting is performed with these equivalent 3 selector
144                     diff = diff + diffIndexOf + diffOrdering + diffPosition;
145                 }
146
147                 return diff;
148             }
149         });
150     }
151
152     /**
153      * Internal method to get a base index to compare with depending on the cell
154      * type.
155      *
156      * @param cell
157      *            the cell
158      * @return the base index
159      */
160     private static final int compareByChildClass(final Object o1, final Object o2) {
161         int o1Index = 0;
162         int o2Index = 0;
163
164         for (int i = 0; i < sortedChildrenClass.length; i++) {
165             final Class<?> klass = sortedChildrenClass[i];
166
167             if (klass.isInstance(o1)) {
168                 o1Index = i;
169                 break;
170             }
171         }
172         for (int i = 0; i < sortedChildrenClass.length; i++) {
173             final Class<?> klass = sortedChildrenClass[i];
174
175             if (klass.isInstance(o2)) {
176                 o2Index = i;
177                 break;
178             }
179         }
180
181         final int base = o1Index - o2Index;
182         return base * (Integer.MAX_VALUE / sortedChildrenClass.length);
183     }
184
185     private boolean locked;
186     private final long uid;
187
188     /**
189      * Represent a simulation function type compatible with Scilab/Scicos
190      * function type descriptors.
191      */
192     public static enum SimulationFunctionType {
193         /** event select; reduced at compilation */
194         ESELECT(-2.0),
195         /** if then else; reduced at compilation */
196         IFTHENELSE(-1.0),
197         /** first common block */
198         DEFAULT(0.0),
199         /** first native block */
200         TYPE_1(1.0),
201         /** second native block */
202         TYPE_2(2.0),
203         /** third native block */
204         TYPE_3(3.0),
205         /** forth native block */
206         C_OR_FORTRAN(4.0),
207         /** Scilab blocks */
208         SCILAB(5.0),
209         /** Debug blocks */
210         DEBUG(99),
211         /** dynamic {@link #TYPE_1} Fortran blocks (fortran_block.sci) */
212         DYNAMIC_FORTRAN_1(1001.0),
213         /** dynamic {@link #TYPE_1} C blocks (c_block.sci) */
214         DYNAMIC_C_1(2001.0),
215         /** Explicit dynamic {@link #TYPE_4} blocks (CBLOCK.sci) */
216         DYNAMIC_EXPLICIT_4(2004.0),
217         /** Implicit {@link #TYPE_1} Fortran blocks (DIFF_f.sci) */
218         OLDBLOCKS(10001.0),
219         /** Implicit {@link #C_OR_FORTRAN} blocks */
220         IMPLICIT_C_OR_FORTRAN(10004.0),
221         /** Implicit dynamic {@link #TYPE_4} blocks (CBLOCK.sci) */
222         DYNAMIC_IMPLICIT_4(12004.0),
223         /** Modelica {@link #C_OR_FORTRAN} blocks */
224         MODELICA(30004.0),
225         /** Magic types */
226         UNKNOWN(5.0);
227
228         private double value;
229
230         /**
231          * Default constructor
232          *
233          * @param scilabValue
234          *            Scilab/Scicos function type descriptor
235          */
236         private SimulationFunctionType(double scilabValue) {
237             value = scilabValue;
238         }
239
240         /**
241          * Get the Java descriptor from the Scilab descriptor.
242          *
243          * @param scilabValue
244          *            Scilab/Scicos function type descriptor
245          * @return The corresponding java descriptor
246          */
247         public static SimulationFunctionType convertScilabValue(int scilabValue) {
248             for (SimulationFunctionType iter : SimulationFunctionType.values()) {
249                 if (iter.getAsDouble() == scilabValue) {
250                     return iter;
251                 }
252             }
253             return UNKNOWN;
254         }
255
256         /**
257          * Get the Scilab Descriptor from the Java Descriptor
258          *
259          * @return The corresponding Scilab/Scicos descriptor
260          */
261         public double getAsDouble() {
262             return value;
263         }
264     };
265
266     /**
267      * Default constructor.
268      */
269     public BasicBlock(long uid) {
270         super();
271
272         /*
273          * Default parameters for blocks
274          */
275         this.visible = true;
276         this.vertex = true;
277         this.connectable = false;
278         this.geometry = new mxGeometry(DEFAULT_POSITION_X, DEFAULT_POSITION_Y, DEFAULT_WIDTH, DEFAULT_HEIGHT);
279
280         this.uid = uid;
281     }
282
283     /**
284      * @return associated MVC ID
285      */
286     public long getUID() {
287         return uid;
288     }
289
290     /**
291      * @return the parent diagram of this graphical object
292      */
293     public XcosDiagram getParentDiagram() {
294         /*
295          * Retrieve the parent
296          */
297         long[] parentBlock = new long[0];
298         long[] parentDiagram = new long[0];
299         JavaController controller = new JavaController();
300         controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.PARENT_BLOCK, parentBlock);
301         controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.PARENT_DIAGRAM, parentDiagram);
302
303         final long parent;
304         final Kind kind;
305         if (parentBlock[0] == 0l) {
306             parent = parentDiagram[0];
307             kind = Kind.DIAGRAM;
308         } else {
309             parent = parentBlock[0];
310             kind = Kind.BLOCK;
311         }
312
313         /*
314          * Retrieve and create on demand the corresponding Diagram
315          */
316         XcosDiagram diagram;
317         Collection<XcosDiagram> diagrams = Xcos.getInstance().getDiagrams(parentDiagram[0]);
318         Optional<XcosDiagram> optDiagram = diagrams.stream().filter(d -> d.getUId() == parent).findFirst();
319         if (optDiagram.isPresent()) {
320             diagram = optDiagram.get();
321         } else {
322             diagram = new XcosDiagram(parent, kind);
323             Xcos.getInstance().addDiagram(parentDiagram[0], diagram);
324         }
325
326         return diagram;
327     }
328
329     /**
330      * @return locked status
331      */
332     public synchronized boolean isLocked() {
333         return locked;
334     }
335
336     /**
337      * @param locked
338      *            change locked status
339      */
340     public synchronized void setLocked(boolean locked) {
341         this.locked = locked;
342     }
343
344     /**
345      * Update the children of the block.
346      *
347      * @param modifiedBlock
348      *            the new block instance
349      */
350     private void updateChildren(BasicBlock modifiedBlock) {
351         //        if (modifiedBlock == null) {
352         //            return;
353         //        }
354         //
355         //        XcosDiagram graph = getParentDiagram();
356         //        if (graph == null) {
357         //            setParentDiagram(Xcos.findParent(this));
358         //            graph = getParentDiagram();
359         //            LOG.finest(PARENT_DIAGRAM_WAS_NULL);
360         //        }
361         //
362         //        /*
363         //         * Checked as port classes only
364         //         */
365         //        @SuppressWarnings("unchecked")
366         //        Set < Class <? extends mxICell >> types = new HashSet < Class <? extends mxICell >> (Arrays.asList(InputPort.class, OutputPort.class, ControlPort.class,
367         //                CommandPort.class));
368         //
369         //        Map < Class <? extends mxICell > , Deque<mxICell >> annotatedOlds = getTypedChildren(types);
370         //        Map < Class <? extends mxICell > , Deque<mxICell >> annotatedNews = modifiedBlock.getTypedChildren(types);
371         //
372         //        getParentDiagram().getModel().beginUpdate();
373         //        try {
374         //            for (Class <? extends mxICell > klass : types) {
375         //                final Deque<mxICell> olds = annotatedOlds.get(klass);
376         //                final Deque<mxICell> news = annotatedNews.get(klass);
377         //
378         //                // updated ports
379         //                while (!olds.isEmpty() && !news.isEmpty()) {
380         //                    mxICell previous = olds.poll();
381         //                    mxICell modified = news.poll();
382         //
383         //                    final int previousIndex = children.indexOf(previous);
384         //
385         //                    // relink
386         //                    if (previous.getEdgeCount() != 0) {
387         //                        final mxICell edge = previous.getEdgeAt(0);
388         //                        final boolean isOutgoing = previous == edge.getTerminal(true);
389         //                        previous.removeEdge(edge, isOutgoing);
390         //                        modified.insertEdge(edge, isOutgoing);
391         //                    }
392         //
393         //                    getParentDiagram().removeCells(new Object[] { previous }, false);
394         //                    getParentDiagram().addCells(new Object[] { modified }, this, previousIndex);
395         //
396         //                    // Clone the geometry to avoid empty geometry on new cells.
397         //                    getParentDiagram().getModel().setGeometry(modified, (mxGeometry) previous.getGeometry().clone());
398         //
399         //                }
400         //
401         //                // removed ports
402         //                if (!olds.isEmpty()) {
403         //                    getParentDiagram().removeCells(olds.toArray(), true);
404         //                }
405         //
406         //                // added ports
407         //                if (!news.isEmpty()) {
408         //                    getParentDiagram().addCells(news.toArray(), this);
409         //                }
410         //            }
411         //        } finally {
412         //            getParentDiagram().getModel().endUpdate();
413         //        }
414     }
415
416     /**
417      * Format the children as a typed map for the given class set.
418      *
419      * @param types
420      *            the classes to search for.
421      * @return a map which linked foreach type the corresponding cell list.
422      */
423     private Map < Class <? extends mxICell > , Deque<mxICell >> getTypedChildren(Set < Class <? extends mxICell >> types) {
424         Map < Class <? extends mxICell > , Deque<mxICell >> oldPorts = new HashMap < Class <? extends mxICell > , Deque<mxICell >> ();
425
426         // Allocate all types set
427         for (Class <? extends mxICell > type : types) {
428             oldPorts.put(type, new LinkedList<mxICell>());
429         }
430
431         if (getChildCount() <= 0) {
432             return oldPorts;
433         }
434
435         // sort children according to the ordering parameter (useful on
436         // scilab-5.2.x diagrams)
437         sort(children);
438
439         // children lookup
440         for (Object cell : children) {
441
442             Class <? extends Object > klass = cell.getClass();
443             while (klass != null) {
444                 if (types.contains(klass)) {
445                     break;
446                 }
447                 klass = klass.getSuperclass();
448             }
449
450             final Deque<mxICell> current = oldPorts.get(klass);
451             if (current != null) {
452                 current.add((mxICell) cell);
453             }
454         }
455
456         return oldPorts;
457     }
458
459     /**
460      * Sort the children list in place.
461      *
462      * The sort put inputs then outputs the control then command ports. The
463      * local port order is preserved.The sort is performed in place and do not
464      * emit any event.
465      */
466     public void sortChildren() {
467         if (getChildCount() <= 0) {
468             return;
469         }
470
471         sort(children);
472     }
473
474     /**
475      * @param context
476      *            parent diagram context
477      */
478     public void openBlockSettings() {
479         // FIXME: implement something
480         //        final XcosDiagram graph;
481         //        if (getParentDiagram() == null) {
482         //            setParentDiagram(Xcos.findParent(this));
483         //            graph = getParentDiagram();
484         //            LOG.finest(PARENT_DIAGRAM_WAS_NULL);
485         //        } else {
486         //            graph = getParentDiagram();
487         //        }
488         //        if (graph instanceof PaletteDiagram) {
489         //            return;
490         //        }
491         //
492         //        if (context == null) {
493         //            throw new IllegalArgumentException();
494         //        }
495         //
496         //        // prevent to open twice
497         //        if (isLocked()) {
498         //            return;
499         //        }
500         //
501         //        graph.setCellsLocked(true);
502         //        graph.getAsComponent().getGraphControl().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
503         //
504         //        // sort children according to the ordering parameter (useful on
505         //        // scilab-5.2.x diagrams)
506         //        sortChildren();
507         //
508         //        final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
509         //        if (handler == null) {
510         //            return;
511         //        }
512         //
513         //        try {
514         //            // Write scs_m
515         //            handler.writeBlock(this);
516         //            // Write context
517         //            handler.writeContext(context);
518         //
519         //            final ActionListener action = new ActionListener() {
520         //                @Override
521         //                public void actionPerformed(ActionEvent e) {
522         //                    LOG.finest("Updating data.");
523         //
524         //                    graph.getView().clear(this, true, true);
525         //
526         //                    // Now read new Block
527         //                    graph.getModel().beginUpdate();
528         //                    try {
529         //                        final BasicBlock modifiedBlock = handler.readBlock();
530         //                        updateBlockSettings(modifiedBlock);
531         //
532         //                        graph.fireEvent(new mxEventObject(XcosEvent.ADD_PORTS, XcosConstants.EVENT_BLOCK_UPDATED, BasicBlock.this));
533         //                    } catch (ScicosFormatException ex) {
534         //                        LOG.severe(ex.toString());
535         //                    } finally {
536         //                        graph.getModel().endUpdate();
537         //                        setLocked(false);
538         //
539         //                        handler.release();
540         //
541         //                        graph.getAsComponent().getGraphControl().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
542         //                        graph.setCellsLocked(false);
543         //                    }
544         //                }
545         //            };
546         //
547         //            setLocked(true);
548         //            ScilabInterpreterManagement.asynchronousScilabExec(action, "blk = xcosBlockInterface", getInterfaceFunctionName().toCharArray(), "set",
549         //                    ScilabDirectHandler.BLK.toCharArray(), ScilabDirectHandler.CONTEXT.toCharArray());
550         //        } catch (InterpreterException e) {
551         //            LOG.severe(e.toString());
552         //            setLocked(false);
553         //
554         //            handler.release();
555         //
556         //            graph.getAsComponent().getGraphControl().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
557         //            graph.setCellsLocked(false);
558         //        }
559     }
560
561     /**
562      * @return tooltip text
563      */
564     public String getToolTipText() {
565         StringBuilder result = new StringBuilder();
566         result.append(ScilabGraphConstants.HTML_BEGIN);
567
568         JavaController controller = new JavaController();
569
570         String[] interfaceFunctionName = new String[1];
571         controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, interfaceFunctionName);
572         String[] simulationFunctionName = new String[1];
573         controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.SIM_FUNCTION_NAME, simulationFunctionName);
574
575         result.append("Block Name : " + interfaceFunctionName[0] + ScilabGraphConstants.HTML_NEWLINE);
576         result.append("Simulation : " + simulationFunctionName[1] + ScilabGraphConstants.HTML_NEWLINE);
577
578         //        if (getParentDiagram() instanceof PaletteDiagram) {
579         //            if (getIntegerParameters() != null) {
580         //                result.append("Integer parameters : " + getIntegerParameters() + ScilabGraphConstants.HTML_NEWLINE);
581         //            }
582         //
583         //            if (getRealParameters() != null && getRealParameters().getHeight() != 0 && getRealParameters().getWidth() != 0) {
584         //                result.append("Real parameters : " + getRealParameters() + ScilabGraphConstants.HTML_NEWLINE);
585         //            }
586         //
587         //            if (getObjectsParameters() != null) {
588         //                result.append("Object parameters : " + getObjectsParameters() + ScilabGraphConstants.HTML_NEWLINE);
589         //            }
590         //        } else {
591         result.append("UID : " + getId() + ScilabGraphConstants.HTML_NEWLINE);
592         final int length = getStyle().length();
593         result.append("Style : ");
594         if (length > XcosConstants.MAX_CHAR_IN_STYLE) {
595             result.append(getStyle().substring(0, XcosConstants.MAX_CHAR_IN_STYLE));
596             result.append(XcosMessages.DOTS);
597         } else {
598             result.append(getStyle());
599         }
600         result.append(ScilabGraphConstants.HTML_NEWLINE);
601         result.append("Input ports : " + BasicBlockInfo.getAllTypedPorts(this, false, InputPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
602         result.append("Output ports : " + BasicBlockInfo.getAllTypedPorts(this, false, OutputPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
603         result.append("Control ports : " + BasicBlockInfo.getAllTypedPorts(this, false, ControlPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
604         result.append("Command ports : " + BasicBlockInfo.getAllTypedPorts(this, false, CommandPort.class).size() + ScilabGraphConstants.HTML_NEWLINE);
605         //        }
606
607         result.append("x : " + getGeometry().getX() + ScilabGraphConstants.HTML_NEWLINE);
608         result.append("y : " + getGeometry().getY() + ScilabGraphConstants.HTML_NEWLINE);
609         result.append("w : " + getGeometry().getWidth() + ScilabGraphConstants.HTML_NEWLINE);
610         result.append("h : " + getGeometry().getHeight() + ScilabGraphConstants.HTML_NEWLINE);
611         result.append(ScilabGraphConstants.HTML_END);
612         return result.toString();
613     }
614
615     /**
616      * @param graph
617      *            parent graph
618      */
619     public void openContextMenu(ScilabGraph graph) {
620         ContextMenu menu = null;
621         //        if (getParentDiagram() instanceof PaletteDiagram) {
622         //            menu = createPaletteContextMenu(graph);
623         //        } else {
624         menu = createContextMenu(graph);
625         //        }
626         menu.setVisible(true);
627     }
628
629     /**
630      * @param graph
631      *            parent graph
632      * @return context menu
633      */
634     // CSOFF: JavaNCSS
635     public ContextMenu createPaletteContextMenu(ScilabGraph graph) {
636         ContextMenu menu = ScilabContextMenu.createContextMenu();
637
638         final List<XcosDiagram> allDiagrams = Xcos.getInstance().openedDiagrams();
639
640         if (allDiagrams.size() == 0) {
641             // No diagram opened: should never happen if Xcos opens an empty
642             // diagram when it is launched
643             MenuItem addTo = ScilabMenuItem.createMenuItem();
644
645             addTo.setText(XcosMessages.ADDTO_NEW_DIAGRAM);
646             addTo.setCallback(new CommonCallBack(XcosMessages.ADDTO_NEW_DIAGRAM) {
647                 @Override
648                 public void callBack() {
649                     JavaController controller = new JavaController();
650                     XcosDiagram theDiagram = new XcosDiagram(controller.createObject(Kind.DIAGRAM), Kind.DIAGRAM);
651                     BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
652                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
653                     mxGeometry geom = BasicBlock.this.getGeometry();
654                     setDefaultPosition(geom);
655                     theDiagram.getModel().setGeometry(block, geom);
656
657                     XcosTab.get(theDiagram).setVisible(true);
658                     BlockPositioning.updateBlockView(block);
659                 }
660             });
661
662             menu.add(addTo);
663
664         } else if (allDiagrams.size() == 1) {
665             // A single diagram opened: add to this diagram
666             MenuItem addTo = ScilabMenuItem.createMenuItem();
667
668             addTo.setText(XcosMessages.ADDTO + " " + XcosTab.get(allDiagrams.get(0)).getName());
669             final XcosDiagram theDiagram = allDiagrams.get(0);
670             addTo.setCallback(new CommonCallBack(theDiagram.getTitle()) {
671                 private static final long serialVersionUID = -99601763227525686L;
672
673                 @Override
674                 public void callBack() {
675                     BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
676                     theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
677                     mxGeometry geom = BasicBlock.this.getGeometry();
678                     setDefaultPosition(geom);
679                     theDiagram.getModel().setGeometry(block, geom);
680                     BlockPositioning.updateBlockView(block);
681                 }
682             });
683
684             menu.add(addTo);
685
686         } else {
687             // The user has to choose
688             Menu addTo = ScilabMenu.createMenu();
689
690             addTo.setText(XcosMessages.ADDTO);
691
692             for (int i = 0; i < allDiagrams.size(); i++) {
693                 MenuItem diagram = ScilabMenuItem.createMenuItem();
694                 final XcosDiagram theDiagram = allDiagrams.get(i);
695                 diagram.setText(XcosTab.get(allDiagrams.get(i)).getName());
696                 diagram.setCallback(new CommonCallBack(theDiagram.getTitle()) {
697                     private static final long serialVersionUID = 3345416658377835057L;
698
699                     @Override
700                     public void callBack() {
701                         BasicBlock block = (BasicBlock) BlockFactory.createClone(BasicBlock.this);
702                         theDiagram.getModel().add(theDiagram.getDefaultParent(), block, 0);
703                         mxGeometry geom = BasicBlock.this.getGeometry();
704                         setDefaultPosition(geom);
705                         theDiagram.getModel().setGeometry(block, geom);
706                         BlockPositioning.updateBlockView(block);
707                     }
708                 });
709                 addTo.add(diagram);
710             }
711
712             menu.add(addTo);
713         }
714
715         menu.getAsSimpleContextMenu().addSeparator();
716
717         MenuItem help = ScilabMenuItem.createMenuItem();
718         help.setText(XcosMessages.BLOCK_DOCUMENTATION);
719         help.setCallback(new CommonCallBack(XcosMessages.BLOCK_DOCUMENTATION) {
720             private static final long serialVersionUID = -1480947262397441951L;
721
722             @Override
723             public void callBack() {
724                 JavaController controller = new JavaController();
725                 String[] interfaceFunctionName = new String[1];
726                 controller.getObjectProperty(getUID(), Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, interfaceFunctionName);
727
728                 InterpreterManagement.requestScilabExec("help " + interfaceFunctionName[0]);
729             }
730         });
731         menu.add(help);
732
733         menu.setVisible(true);
734
735         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo()
736                 .getLocation().y);
737
738         return menu;
739     }
740
741     // CSON: JavaNCSS
742
743     /**
744      * @param graph
745      *            parent graph
746      * @return context menu
747      */
748     // CSOFF: JavaNCSS
749     public ContextMenu createContextMenu(ScilabGraph graph) {
750         ContextMenu menu = ScilabContextMenu.createContextMenu();
751         Map < Class <? extends DefaultAction > , Menu > menuList = new HashMap < Class <? extends DefaultAction > , Menu > ();
752
753         MenuItem value = BlockParametersAction.createMenu(graph);
754         menuList.put(BlockParametersAction.class, value);
755         menu.add(value);
756         /*--- */
757         menu.getAsSimpleContextMenu().addSeparator();
758         /*--- */
759         value = CutAction.cutMenu(graph);
760         menuList.put(CutAction.class, value);
761         menu.add(value);
762         value = CopyAction.copyMenu(graph);
763         menuList.put(CopyAction.class, value);
764         menu.add(value);
765         value = DeleteAction.createMenu(graph);
766         menuList.put(DeleteAction.class, value);
767         menu.add(value);
768         /*--- */
769         menu.getAsSimpleContextMenu().addSeparator();
770         /*--- */
771         value = RegionToSuperblockAction.createMenu(graph);
772         menuList.put(RegionToSuperblockAction.class, value);
773         menu.add(value);
774         /*--- */
775         menu.getAsSimpleContextMenu().addSeparator();
776         /*--- */
777         Menu format = ScilabMenu.createMenu();
778         format.setText(XcosMessages.FORMAT);
779         menu.add(format);
780         value = RotateAction.createMenu(graph);
781         menuList.put(RotateAction.class, value);
782         format.add(value);
783         value = MirrorAction.createMenu(graph);
784         menuList.put(MirrorAction.class, value);
785         format.add(value);
786         value = FlipAction.createMenu(graph);
787         menuList.put(FlipAction.class, value);
788         format.add(value);
789         value = ShowHideShadowAction.createMenu(graph);
790         menuList.put(ShowHideShadowAction.class, value);
791         format.add(value);
792         /*--- */
793         format.addSeparator();
794         /*--- */
795         Menu alignMenu = ScilabMenu.createMenu();
796         alignMenu.setText(XcosMessages.ALIGN_BLOCKS);
797         alignMenu.add(AlignBlockActionLeft.createMenu(graph));
798         alignMenu.add(AlignBlockActionCenter.createMenu(graph));
799         alignMenu.add(AlignBlockActionRight.createMenu(graph));
800         alignMenu.addSeparator();
801         alignMenu.add(AlignBlockActionTop.createMenu(graph));
802         alignMenu.add(AlignBlockActionMiddle.createMenu(graph));
803         alignMenu.add(AlignBlockActionBottom.createMenu(graph));
804         menuList.put(AlignBlockAction.class, alignMenu);
805         format.add(alignMenu);
806         /*--- */
807         format.addSeparator();
808         /*--- */
809         if (graph.getSelectionCells().length > 1) {
810             format.add(BorderColorAction.createMenu(graph));
811             format.add(FilledColorAction.createMenu(graph));
812         } else {
813             format.add(EditFormatAction.createMenu(graph));
814         }
815         /*--- */
816         menu.getAsSimpleContextMenu().addSeparator();
817         /*--- */
818         menu.add(ViewDetailsAction.createMenu(graph));
819         /*--- */
820         menu.getAsSimpleContextMenu().addSeparator();
821         /*--- */
822         menu.add(BlockDocumentationAction.createMenu(graph));
823
824         ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo()
825                 .getLocation().y);
826
827         customizeMenu(menuList);
828
829         return menu;
830     }
831
832     /**
833      * Override this to customize contextual menu
834      *
835      * @param menuList
836      *            list of menu
837      */
838     protected void customizeMenu(Map < Class <? extends DefaultAction > , Menu > menuList) {
839         // To be overridden by sub-classes
840     }
841
842
843     /**
844      * Set the default block position on the geom
845      *
846      * @param geom
847      *            the current geom
848      */
849     private void setDefaultPosition(mxGeometry geom) {
850         geom.setX(DEFAULT_POSITION_X);
851         geom.setY(DEFAULT_POSITION_Y);
852     }
853
854     /*
855      * Overriden methods from jgraphx
856      */
857
858     /**
859      * @return always false
860      * @see com.mxgraph.model.mxCell#isConnectable()
861      */
862     @Override
863     public boolean isConnectable() {
864         return false;
865     }
866
867     /**
868      * {@inheritDoc}
869      *
870      * Sync the specific child {@link EditFormatAction#HASH_IDENTIFIER}
871      */
872     @Override
873     public mxICell insert(mxICell child, int index) {
874         /*
875          * Update the id if this is an identifier cell (herited identifier)
876          */
877         if (child.getId().endsWith(XcosDiagram.HASH_IDENTIFIER)) {
878             child.setId(getId() + XcosDiagram.HASH_IDENTIFIER);
879         }
880
881         return super.insert(child, index);
882     }
883
884     @Override
885     public String toString() {
886         final StringBuilder str = new StringBuilder();
887
888         JavaController controller = new JavaController();
889
890         String[] interfaceFunction = new String[1];
891         controller.getObjectProperty(uid, Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, interfaceFunction);
892
893         str.append(interfaceFunction[0]);
894         str.append("\n");
895         for (Object c : children) {
896             str.append(c);
897             str.append("\n");
898         }
899
900         return str.toString();
901     }
902 }