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