AC_JAVA_CHECK_VERSION_PACKAGE(NAME, IMPORTS, JAR, MIN_VERSION, CURRENT_VERSION)
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / graph / XcosDiagram.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-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.graph;
14
15 import java.awt.Color;
16 import java.awt.MouseInfo;
17 import java.awt.event.KeyEvent;
18 import java.awt.event.KeyListener;
19 import java.awt.event.MouseEvent;
20 import java.awt.event.MouseListener;
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.io.File;
24 import java.io.FileWriter;
25 import java.io.IOException;
26 import java.rmi.server.UID;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.List;
31 import javax.swing.JFileChooser;
32 import javax.swing.JOptionPane;
33 import javax.swing.SwingUtilities;
34 import javax.xml.parsers.DocumentBuilder;
35 import javax.xml.parsers.DocumentBuilderFactory;
36 import javax.xml.parsers.ParserConfigurationException;
37
38 import org.scilab.modules.graph.ScilabGraph;
39 import org.scilab.modules.graph.actions.PasteAction;
40 import org.scilab.modules.graph.actions.RedoAction;
41 import org.scilab.modules.graph.actions.SelectAllAction;
42 import org.scilab.modules.graph.actions.UndoAction;
43 import org.scilab.modules.graph.actions.ZoomInAction;
44 import org.scilab.modules.graph.actions.ZoomOutAction;
45 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
46 import org.scilab.modules.gui.bridge.filechooser.SwingScilabFileChooser;
47 import org.scilab.modules.gui.checkboxmenuitem.CheckBoxMenuItem;
48 import org.scilab.modules.gui.contextmenu.ContextMenu;
49 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
50 import org.scilab.modules.gui.filechooser.FileChooser;
51 import org.scilab.modules.gui.filechooser.ScilabFileChooser;
52 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
53 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
54 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
55 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
56 import org.scilab.modules.gui.tab.Tab;
57 import org.scilab.modules.gui.utils.SciFileFilter;
58 import org.scilab.modules.gui.utils.UIElementMapper;
59 import org.scilab.modules.gui.window.ScilabWindow;
60 import org.scilab.modules.hdf5.scilabTypes.ScilabMList;
61 import org.scilab.modules.xcos.Xcos;
62 import org.scilab.modules.xcos.XcosTab;
63 import org.scilab.modules.xcos.actions.DiagramBackgroundAction;
64 import org.scilab.modules.xcos.actions.SetContextAction;
65 import org.scilab.modules.xcos.actions.SetupAction;
66 import org.scilab.modules.xcos.actions.XcosDocumentationAction;
67 import org.scilab.modules.xcos.actions.XcosShortCut;
68 import org.scilab.modules.xcos.block.AfficheBlock;
69 import org.scilab.modules.xcos.block.BasicBlock;
70 import org.scilab.modules.xcos.block.BlockFactory;
71 import org.scilab.modules.xcos.block.io.ContextUpdate;
72 import org.scilab.modules.xcos.block.SplitBlock;
73 import org.scilab.modules.xcos.block.SuperBlock;
74 import org.scilab.modules.xcos.block.TextBlock;
75 import org.scilab.modules.xcos.block.BlockFactory.BlockInterFunction;
76 import org.scilab.modules.xcos.block.actions.ShowParentAction;
77 import org.scilab.modules.xcos.io.BlockReader;
78 import org.scilab.modules.xcos.io.BlockWriter;
79 import org.scilab.modules.xcos.io.XcosCodec;
80 import org.scilab.modules.xcos.link.BasicLink;
81 import org.scilab.modules.xcos.link.commandcontrol.CommandControlLink;
82 import org.scilab.modules.xcos.link.explicit.ExplicitLink;
83 import org.scilab.modules.xcos.link.implicit.ImplicitLink;
84 import org.scilab.modules.xcos.port.BasicPort;
85 import org.scilab.modules.xcos.port.PortCheck;
86 import org.scilab.modules.xcos.port.command.CommandPort;
87 import org.scilab.modules.xcos.port.control.ControlPort;
88 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
89 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
90 import org.scilab.modules.xcos.port.input.InputPort;
91 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
92 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
93 import org.scilab.modules.xcos.port.output.OutputPort;
94 import org.scilab.modules.xcos.utils.BlockPositioning;
95 import org.scilab.modules.xcos.utils.ConfigXcosManager;
96 import org.scilab.modules.xcos.utils.XcosDialogs;
97 import org.scilab.modules.xcos.utils.XcosEvent;
98 import org.scilab.modules.xcos.utils.XcosFileType;
99 import org.scilab.modules.xcos.utils.XcosMessages;
100 import org.w3c.dom.Document;
101 import org.xml.sax.SAXException;
102
103 import com.mxgraph.io.mxCodec;
104 import com.mxgraph.model.mxCell;
105 import com.mxgraph.model.mxGeometry;
106 import com.mxgraph.model.mxGraphModel;
107 import com.mxgraph.model.mxICell;
108 import com.mxgraph.model.mxGraphModel.mxChildChange;
109 import com.mxgraph.model.mxGraphModel.mxStyleChange;
110 import com.mxgraph.util.mxEvent;
111 import com.mxgraph.util.mxEventObject;
112 import com.mxgraph.util.mxPoint;
113 import com.mxgraph.util.mxRectangle;
114 import com.mxgraph.util.mxUndoableEdit;
115 import com.mxgraph.util.mxUtils;
116 import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
117 import com.mxgraph.view.mxMultiplicity;
118
119 public class XcosDiagram extends ScilabGraph {
120
121     // Default values : SCI/modules/scicos/macros/scicos_scicos/scicos_params.sci
122     private double finalIntegrationTime = 100000;
123     private double integratorAbsoluteTolerance = 1e-4;
124     private double integratorRelativeTolerance = 1e-6;
125     private double toleranceOnTime = 1e-10;
126     private double maxIntegrationTimeinterval = finalIntegrationTime + 1;
127     private double realTimeScaling = 0;
128     private double solver = 0;
129     private double maximumStepSize = 0;
130     private int debugLevel = 0;
131     private String[] context = new String[]{""};
132     private String version = "scicos4.2";
133     //private Window palette;
134     private Tab viewPort;
135     
136     /*to manage splitLink*/
137     private BasicLink splitLink = null;
138     private BasicPort splitPort = null;
139     private mxPoint dragSplitPos = null;
140     private boolean waitSplitRelease = false;
141     
142     /*to manage path link*/
143     private BasicLink drawLink = null;
144     private boolean waitPathAddEdge = false;
145     private boolean waitPathRelease = false;
146
147     private CheckBoxMenuItem viewPortMenu;
148     private CheckBoxMenuItem gridMenu;
149     private SetContextAction action;
150     
151     protected mxIEventListener undoEnabler = new mxIEventListener()
152     {
153         public void invoke(Object source, mxEventObject evt) {
154                 if (getParentTab() != null) {
155                         ((XcosTab)getParentTab()).setEnabledUndo(true);
156                 }
157         }
158     };
159
160     public Object addEdge(Object edge, Object parent, Object source,
161                 Object target, Integer index) { 
162         
163         // Command -> Control
164         if (source instanceof CommandPort) {
165                 if (target instanceof ControlPort) {
166                         return super.addEdge(new CommandControlLink(), parent, source, target, index);
167                 }
168         }
169
170         // Control -> Command
171         // Switch source and target !
172         if (target instanceof CommandPort) {
173                 if (source instanceof ControlPort) {
174                         return super.addEdge(new CommandControlLink(), parent, target, source, index);
175                 }
176         }
177
178         // ExplicitOutput -> ExplicitInput
179         if (source instanceof ExplicitOutputPort) {
180                 if (target instanceof ExplicitInputPort) {
181                         return super.addEdge(new ExplicitLink(), parent, source, target, index);
182                 }
183         }
184         // ExplicitInput -> ExplicitOutput
185         // Switch source and target !
186         if (target instanceof ExplicitOutputPort) {
187                 if (source instanceof ExplicitInputPort) {
188                         return super.addEdge(new ExplicitLink(), parent, target, source, index);
189                 }
190         }
191
192         // ImplicitOutput -> ImplicitInput
193         if (source instanceof ImplicitOutputPort) {
194                 if (target instanceof ImplicitInputPort) {
195                         return super.addEdge(new ImplicitLink(), parent, source, target, index);
196                 }
197         }
198         // ImplicitInput -> ImplicitOutput
199         // Switch source and target !
200         if (target instanceof ImplicitOutputPort) {
201                 if (source instanceof ImplicitInputPort) {
202                         return super.addEdge(new ImplicitLink(), parent, target, source, index);
203                 }
204         }
205
206         // ImplicitInput -> ImplicitInput
207         if (source instanceof ImplicitInputPort) {
208                 if (target instanceof ImplicitInputPort) {
209                         return super.addEdge(new ImplicitLink(), parent, source, target, index);
210                 }
211         }
212         // ImplicitOutputPort -> ImplicitOutput
213         // Switch source and target !
214         if (target instanceof ImplicitOutputPort) {
215                 if (source instanceof ImplicitOutputPort) {
216                         return super.addEdge(new ImplicitLink(), parent, target, source, index);
217                 }
218         }
219         
220         // ExplicitLink -> ExplicitInputPort
221         if (source instanceof ExplicitLink) {
222                 if (target instanceof ExplicitInputPort) {
223                         return addSplitEdge((BasicLink) source, (BasicPort) target);
224                 }
225         }
226         // ExplicitOutput -> ExpliciLink
227         // Switch source and target !
228         if (target instanceof ExplicitLink) {
229                 if (source instanceof ExplicitInputPort) {
230                         waitSplitRelease = true;
231                         splitLink = (BasicLink) target;
232                         splitPort = (BasicPort) source;
233                         return null;
234                         //return addSplitEdge((BasicLink) target, (BasicPort)source);
235                 }
236         }
237
238         // ImplicitLink -> ImplicitInputPort
239         if (source instanceof ImplicitLink) {
240                 if (target instanceof ImplicitInputPort) {
241                         return addSplitEdge((BasicLink) source, (BasicPort) target);
242                 }
243         }
244         // ImplicitInputPort -> ImplicitLink
245         // Switch source and target !
246         if (target instanceof ImplicitLink) {
247                 if (source instanceof ImplicitInputPort) {
248                         waitSplitRelease = true;
249                         splitLink = (BasicLink) target;
250                         splitPort = (BasicPort) source;
251                         return null;
252                         //return addSplitEdge((BasicLink) target, (BasicPort)source);
253                 }
254         }
255         
256         // ImplicitLink -> ImplicitOutputPort
257         if (source instanceof ImplicitLink) {
258                 if (target instanceof ImplicitOutputPort) {
259                         return addSplitEdge((BasicLink) source, (BasicPort) target);
260                 }
261         }
262         // ImplicitOutputPort -> ImplicitLink
263         // Switch source and target !
264         if (target instanceof ImplicitLink) {
265                 if (source instanceof ImplicitOutputPort) {
266                         waitSplitRelease = true;
267                         splitLink = (BasicLink) target;
268                         splitPort = (BasicPort) source;
269                         return null;
270                         //return addSplitEdge((BasicLink) target, (BasicPort)source);
271                 }
272         }
273
274         // CommandControlLink -> ControlPort
275         if (source instanceof CommandControlLink) {
276                 if (target instanceof ControlPort) {
277                         return addSplitEdge((BasicLink) source, (BasicPort) target);
278                 }
279         }
280         // ControlPort -> CommandControlLink
281         // Switch source and target !
282         if (target instanceof CommandControlLink) {
283                 if (source instanceof ControlPort) {
284                         waitSplitRelease = true;
285                         splitLink = (BasicLink) target;
286                         splitPort = (BasicPort) source;
287                         return null;
288                         //return addSplitEdge((BasicLink) target, (BasicPort)source);
289                 }
290         }
291
292         
293         if(source != null && target == null) {
294                 drawLink = null;
295                 if(source instanceof ExplicitInputPort || source instanceof ExplicitOutputPort) {
296                         drawLink = (BasicLink) super.addEdge(new ExplicitLink(), getDefaultParent(), source, target, index);
297                 } else if(source instanceof ImplicitInputPort || source instanceof ImplicitOutputPort) {
298                         drawLink = (BasicLink) super.addEdge(new ImplicitLink(), getDefaultParent(), source, target, index);
299                 } else if(source instanceof ControlPort || source instanceof CommandPort) {
300                         drawLink = (BasicLink) super.addEdge(new CommandControlLink(), getDefaultParent(), source, target, index);
301                 } else if(source instanceof BasicLink) {
302                         SplitBlock split = (SplitBlock) addSplitEdge((BasicLink)source, (BasicPort)target);
303                         drawLink = (BasicLink) split.getOut2().getEdgeAt(0);
304             }
305
306                 if(drawLink != null) {
307                 waitPathRelease = true;
308             }
309             
310                 info(XcosMessages.DRAW_LINK);
311             return drawLink;
312         }
313         return null;
314     }
315
316     private Object addSplitEdge(BasicLink link, mxICell target) {
317         BasicPort linkSource =  (BasicPort) link.getSource();
318         BasicPort linkTarget =  (BasicPort) link.getTarget();
319
320         getModel().beginUpdate();
321         if (dragSplitPos == null) {
322                 dragSplitPos = new mxPoint();
323
324             //check splitPosition values
325             double srcX = linkSource.getParent().getGeometry().getX() + linkSource.getGeometry().getCenterX();
326             double tgtX = linkTarget.getParent().getGeometry().getX() + linkTarget.getGeometry().getCenterX();
327             double srcY = linkSource.getParent().getGeometry().getY() + linkSource.getGeometry().getCenterY();
328             double tgtY = linkTarget.getParent().getGeometry().getY() + linkTarget.getGeometry().getCenterY();
329
330             double offsetX = (tgtX - srcX) / 2;
331             double offsetY = (tgtY - srcY) / 2;
332             dragSplitPos.setX(srcX + offsetX);
333             dragSplitPos.setY(srcY + offsetY);
334         }
335         
336         SplitBlock splitBlock = (SplitBlock) BlockFactory.createBlock(BlockInterFunction.SPLIT_f);
337         if (target instanceof BasicLink) {
338             splitBlock.setConnection(linkSource, linkTarget, (BasicPort) ((BasicLink)target).getSource());
339         } else {
340                 splitBlock.setConnection(linkSource, linkTarget, (BasicPort) target);
341         }
342         
343         mxGeometry geom = splitBlock.getGeometry();
344         geom.setX(dragSplitPos.getX() - (SplitBlock.DEFAULT_SIZE/2));
345         geom.setY(dragSplitPos.getY() - (SplitBlock.DEFAULT_SIZE/2));
346         addCell(splitBlock);
347         
348         
349         //Update old link
350         
351         //get breaking segment
352         int pos = link.findNearestSegment(dragSplitPos);
353
354         //save points after breaking point
355         mxPoint[] saveStartPoints = link.getPoints(pos, true);
356         mxPoint[] saveEndPoints = link.getPoints(pos, false);
357         
358         
359         //disable events
360         getModel().beginUpdate();
361         getModel().remove(link);
362         getModel().endUpdate();
363
364         BasicLink newLink1 = BasicLink.createLinkFromPorts(linkSource, splitBlock.getIn());
365         newLink1.setGeometry(new mxGeometry(0,0,80,80));
366         newLink1.setSource(linkSource);
367         newLink1.setTarget(splitBlock.getIn());
368
369         //add points after breaking point in the new link
370         if (saveStartPoints != null) {
371                 for (int i = 0; i < saveStartPoints.length; i++) {
372                         newLink1.addPoint(saveStartPoints[i].getX(), saveStartPoints[i].getY());
373                 }
374         }
375         addCell(newLink1);
376         
377         BasicLink newLink2 = BasicLink.createLinkFromPorts(splitBlock.getOut1(), linkTarget);
378         newLink2.setGeometry(new mxGeometry(0,0,80,80));
379         newLink2.setSource(splitBlock.getOut1());
380         newLink2.setTarget(linkTarget);
381         //add points after breaking point in the new link
382         if (saveEndPoints != null) {
383                 for (int i = 0; i < saveEndPoints.length; i++) {
384                         newLink2.addPoint(saveEndPoints[i].getX(), saveEndPoints[i].getY());
385                 }
386         }
387         addCell(newLink2);
388
389         if(target instanceof BasicLink) {
390             //build link inverted ! it will be invert later
391             ((BasicLink)target).setTarget(splitBlock.getOut2());
392             addCell(target);
393         } else {
394             BasicLink newLink3 = BasicLink.createLinkFromPorts(splitBlock.getOut2(), (BasicPort) target);
395             newLink3.setGeometry(new mxGeometry(0,0,80,80));
396             newLink3.setSource(splitBlock.getOut2());
397             newLink3.setTarget((mxCell) target);
398             addCell(newLink3);
399         }
400         
401         dragSplitPos = null;
402         refresh();
403         getModel().endUpdate();
404         
405         return splitBlock;
406     }
407     
408     public XcosDiagram() {
409         super();
410         getModel().addListener(mxEvent.UNDO, undoEnabler);
411         getView().addListener(mxEvent.UNDO, undoEnabler);
412         // The association is inverted there (by the parameter)
413         new XcosShortCut(this);
414         mxCodec codec = new mxCodec();
415
416         try {
417             File uri = new File(System.getenv("SCI"));
418             String xml = mxUtils.readFile(System.getenv("SCI")+ "/modules/xcos/etc/Xcos-style.xml");
419             xml = xml.replaceAll("\\$SCILAB", uri.toURI().toURL().toString());
420             Document document = mxUtils.parse(xml);
421             codec.decode(document.getDocumentElement(), getStylesheet());
422         } catch (IOException e) {
423             e.printStackTrace();
424         }
425
426         getAsComponent().setToolTips(true);
427
428         // Forbid disconnecting cells once it is connected.
429         setCellsDisconnectable(false);
430
431         // Forbid pending edges.
432         //setAllowDanglingEdges(false);
433         setAllowDanglingEdges(true);
434
435         // Cannot connect port to itself.
436         setAllowLoops(false);
437
438         // Override isCellResizable to filter what the user can resize
439         setCellsResizable(true);
440
441         // force auto resize cell
442         setAutoSizeCells(true);
443
444         /* Labels use HTML if not equal to interface function name */
445         setHtmlLabels(true);
446
447         //
448         //setCloneInvalidEdges(false);
449         setCloneInvalidEdges(true);
450
451         // Override isCellEditable to filter what the user can edit
452         setCellsEditable(true);
453         // This enable stop editing cells when pressing Enter.
454         getAsComponent().setEnterStopsCellEditing(false);
455
456         setConnectableEdges(true);
457         getAsComponent().setTolerance(1);
458         
459         getAsComponent().getViewport().setOpaque(false);
460         getAsComponent().setBackground(Color.WHITE);
461
462         setMultiplicities();
463         
464         // Add a listener to track when model is changed
465         getModel().addListener(XcosEvent.CHANGE, new ModelTracker());
466         
467         setGridVisible(true);
468         
469         ((mxCell) getDefaultParent()).setId((new UID()).toString());
470         ((mxCell) getModel().getRoot()).setId((new UID()).toString());
471     }
472
473     /**
474      * Install the multiplicities (use for link checking)
475      */
476     private void setMultiplicities() {
477         mxMultiplicity[] multiplicities = new mxMultiplicity[10];
478
479         
480         // Input data port
481         multiplicities[0] = new PortCheck(ExplicitInputPort.class, Collections
482                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
483                     private static final long serialVersionUID = -4987163442006736665L;
484                     {
485                         add(ExplicitOutputPort.class);
486                         add(ExplicitLink.class);
487                     }
488                 }), XcosMessages.LINK_ERROR_EXPLICIT_IN);
489         multiplicities[1] = new PortCheck(ImplicitInputPort.class, Collections
490                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
491                     private static final long serialVersionUID = 886376532181210926L;
492                     {
493                         add(ImplicitOutputPort.class);
494                         add(ImplicitInputPort.class);
495                         add(ImplicitLink.class);
496                     }
497                 }), XcosMessages.LINK_ERROR_IMPLICIT_IN);
498
499         // Output data port
500         multiplicities[2] = new PortCheck(ExplicitOutputPort.class, Collections
501                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
502                     private static final long serialVersionUID = 4594127972486054821L;
503                     {
504                         add(ExplicitInputPort.class);
505                     }
506                 }), XcosMessages.LINK_ERROR_EXPLICIT_OUT);
507         multiplicities[3] = new PortCheck(ImplicitOutputPort.class, Collections
508                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
509                     private static final long serialVersionUID = -3719677806532507973L;
510                     {
511                         add(ImplicitInputPort.class);
512                         add(ImplicitOutputPort.class);
513                         add(ImplicitLink.class);
514                     }
515                 }), XcosMessages.LINK_ERROR_IMPLICIT_OUT);
516
517         // Control port
518         multiplicities[4] = new PortCheck(ControlPort.class, Collections
519                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
520                     private static final long serialVersionUID = 2941077191386058497L;
521                     {
522                         add(CommandPort.class);
523                         add(CommandControlLink.class);
524                     }
525                 }), XcosMessages.LINK_ERROR_EVENT_IN);
526
527         // Command port
528         multiplicities[5] = new PortCheck(CommandPort.class, Collections
529                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
530                     private static final long serialVersionUID = -3470370027962480362L;
531                     {
532                         add(ControlPort.class);
533                     }
534                 }), XcosMessages.LINK_ERROR_EVENT_OUT);
535
536         // ExplicitLink connections
537         multiplicities[6] = new PortCheck(ExplicitLink.class, Collections
538                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
539                     private static final long serialVersionUID = 7423543162930147373L;
540
541                     {
542                         add(ExplicitInputPort.class);
543                     }
544                 }), XcosMessages.LINK_ERROR_EVENT_OUT);
545
546         // ImplicitLink connections
547         multiplicities[7] = new PortCheck(ImplicitLink.class, Collections
548                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
549                     private static final long serialVersionUID = 7775100011122283282L;
550
551                     {
552                         add(ImplicitInputPort.class);
553                         add(ImplicitOutputPort.class);
554                     }
555                 }), XcosMessages.LINK_ERROR_EVENT_OUT);
556
557         // CommandControlLink connections
558         multiplicities[8] = new PortCheck(CommandControlLink.class, Collections
559                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
560                     private static final long serialVersionUID = 3260421433507192386L;
561
562                     {
563                         add(ControlPort.class);
564                     }
565                 }), XcosMessages.LINK_ERROR_EVENT_OUT);
566
567         // Already connected port
568         multiplicities[9] = new PortCheck(BasicPort.class, Collections
569                 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
570                     private static final long serialVersionUID = 6376349598052836660L;
571
572                     {
573                         add(BasicPort.class);
574                     }
575                 }), XcosMessages.LINK_ERROR_ALREADY_CONNECTED);
576
577         setMultiplicities(multiplicities);
578     }
579
580     /**
581      * Install all needed Listeners.
582      */
583     public void installListeners() {
584
585         // Property change Listener
586         // Will say if a diagram has been modified or not.
587         getAsComponent().addPropertyChangeListener(new PropertyChangeListener() {
588             public void propertyChange(PropertyChangeEvent e) {
589                 if (e.getPropertyName().compareTo("modified") == 0) {
590                     if ((Boolean) e.getOldValue() != (Boolean) e.getNewValue()) {
591                         updateTabTitle();
592                     }
593                 }
594             }
595         });
596
597         // Track when superblock ask a parent refresh.
598         addListener(XcosEvent.SUPER_BLOCK_UPDATED, new SuperBlockUpdateTracker()); 
599
600         // Track when cells are added.
601         addListener(XcosEvent.CELLS_ADDED, new CellAddedTracker(this)); 
602
603         // Track when cells are deleted.
604         addListener(XcosEvent.CELLS_REMOVED, new CellRemovedTracker(this)); 
605                 
606         // Track when resizing a cell.
607         addListener(XcosEvent.CELLS_RESIZED, new CellResizedTracker());
608         
609         // Track when we have to force a Block value
610         addListener(XcosEvent.FORCE_CELL_VALUE_UPDATE, new ForceCellValueUpdate());
611         
612         // Update the blocks view on undo/redo
613         getUndoManager().addListener(mxEvent.UNDO, new UndoUpdateTracker());
614         getUndoManager().addListener(mxEvent.REDO, new UndoUpdateTracker());
615         
616         getAsComponent().getGraphControl().addMouseListener(new XcosMouseListener(this));
617
618         getAsComponent().addKeyListener(new XcosKeyListener(this));
619
620         addListener(XcosEvent.ADD_PORTS, new mxIEventListener() {
621             public void invoke(Object source, mxEventObject evt) {
622                 getModel().beginUpdate();
623                 refresh();
624                 BasicBlock updatedBlock = (BasicBlock) evt.getArgAt(0);
625                 BlockPositioning.updateBlockView(updatedBlock);
626                 getModel().endUpdate();
627             }
628         });     
629         
630     }
631
632     /**
633      * modelTracker
634      * Called when mxEvents.CHANGE occurs on a model
635      */
636     private class ModelTracker implements mxIEventListener {
637         public void invoke(Object source, mxEventObject evt) {
638             List<mxUndoableChange> changes = (List<mxUndoableChange>) evt.getArgAt(0);
639             List<Object> objects = new ArrayList<Object>();
640             getModel().beginUpdate();
641             for (int i = 0; i < changes.size(); ++i) {
642                 if (changes.get(i) instanceof mxChildChange) {
643                     if (((mxChildChange) changes.get(i)).getChild() instanceof SplitBlock) {
644                         continue;
645                     }
646
647                     if (((mxChildChange) changes.get(i)).getChild() instanceof BasicBlock) {
648                         BasicBlock currentCell = (BasicBlock) ((mxChildChange) changes.get(i)).getChild();
649                         objects.add(currentCell);
650                     }
651                 }
652             }
653             if (!objects.isEmpty()) {
654                 Object[] firedCells = new Object[objects.size()];
655                 for (int j = 0;  j < objects.size(); ++j) {
656                     firedCells[j] = objects.get(j);
657                 }
658                 //fireEvent(XcosEvent.FORCE_CELL_RESHAPE, new mxEventObject(new Object[] {firedCells}));
659                 fireEvent(XcosEvent.FORCE_CELL_VALUE_UPDATE, new mxEventObject(new Object[] {firedCells}));
660             }
661             getModel().endUpdate();
662         }
663     }
664     /**
665      * ForceCellValueUpdate
666      * Called when we want a block content to update.
667      */
668     private class ForceCellValueUpdate implements mxIEventListener {
669         public void invoke(Object source, mxEventObject evt) {
670             Object[] cells = (Object[]) evt.getArgs()[0];
671
672             getModel().beginUpdate();
673
674             for (int i = 0; i < cells.length; ++i) {
675                 
676                 Object cell = cells[i];
677                 
678                 if (cell instanceof BasicBlock) {
679                     if (getCellStyle(cell).get("displayedLabel") != null) {
680                         ((mxCell) cell).setValue("<html><body> " + getCellStyle(cell).get("displayedLabel") + " </body></html>");
681                     }
682
683                     mxRectangle preferedSize = getPreferredSizeForCell(cell);
684                     mxGeometry cellSize = ((mxCell) cell).getGeometry();
685
686                     ((mxCell) cell).setGeometry(new mxGeometry(cellSize.getX(), cellSize.getY(),
687                             Math.max(preferedSize.getWidth(), cellSize.getWidth()),
688                             Math.max(preferedSize.getHeight(), cellSize.getHeight())));
689                     cellsResized(new Object[] {cell}, new mxRectangle[]{((mxCell) cell).getGeometry()});
690                 }
691             }
692             getModel().endUpdate();
693             refresh();
694         }
695     }
696     
697     /**
698      *  SuperBlockUpdateTracker
699      *  Called when adding some port in a SuperBlock diagram
700      *  to update current sub-diagram (i.e SuperBlock) representation.
701      */
702     private class SuperBlockUpdateTracker implements mxIEventListener {
703         public void invoke(Object source, mxEventObject evt) {
704             assert evt.getArgs()[0] instanceof SuperBlock;
705             SuperBlock updatedBlock = (SuperBlock) evt.getArgs()[0];
706             updatedBlock.setRealParameters(BlockWriter
707                     .convertDiagramToMList(updatedBlock.getChild()));
708             if (updatedBlock.getParentDiagram() instanceof SuperBlockDiagram) {
709                 SuperBlock parentBlock = ((SuperBlockDiagram) updatedBlock
710                         .getParentDiagram()).getContainer();
711                 parentBlock.getParentDiagram().fireEvent(
712                         XcosEvent.SUPER_BLOCK_UPDATED,
713                         new mxEventObject(new Object[] { parentBlock }));
714             }
715             BlockPositioning.updateBlockView(updatedBlock);
716             refresh();
717         }
718     }
719
720     /**
721      * CellAddedTracker
722      * Called when mxEvents.CELLS_ADDED is fired.
723      */
724     private class CellAddedTracker implements mxIEventListener {
725         private XcosDiagram diagram = null;
726
727         public CellAddedTracker(XcosDiagram diagram) {
728                 this.diagram = diagram;
729         }
730
731         public void invoke(Object source, mxEventObject evt) {
732                 Object[] cells = (Object[]) evt.getArgs()[0];
733                 
734                 diagram.getModel().beginUpdate();
735                 for (int i = 0; i < cells.length; ++i) {
736
737 //                      ((mxCell) cells[i]).setId((new UID()).toString());
738
739                                 if (cells[i] instanceof BasicBlock) {
740                                         // Store all AfficheBlocks in a dedicated HasMap
741                                         if (cells[i] instanceof AfficheBlock) {
742                                                 AfficheBlock affich = (AfficheBlock) cells[i];
743                                                 XcosTab.getAfficheBlocks().put(affich.getHashCode(), affich);
744                                         }
745                                         // Update parent on cell addition
746                                         ((BasicBlock) cells[i]).setParentDiagram(diagram);
747                                 }
748                 }
749                 //fireEvent(XcosEvent.FORCE_CELL_VALUE_UPDATE, new mxEventObject(new Object[] {cells}));
750                 diagram.getModel().endUpdate();
751         }
752     }
753
754     /**
755      * CellRemovedTracker
756      * Called when mxEvents.CELLS_REMOVED is fired.
757      */
758     private class CellRemovedTracker implements mxIEventListener {
759         public CellRemovedTracker(XcosDiagram diagram) {
760         }
761
762         public void invoke(Object source, mxEventObject evt) {
763             Object[] cells = (Object[]) evt.getArgs()[0];
764             for (int i = 0; i < cells.length; i++) {
765                 if (cells[i] instanceof BasicLink) {
766                     BasicLink link = (BasicLink) cells[i];
767                     removeLink(link);
768                     if(waitPathAddEdge) {
769                         cancelDrawLinkAction();
770                     }
771                 }
772             }
773
774         }
775     }
776
777     private void removeLink(BasicLink link) {
778         if(!(link.getSource() instanceof BasicPort)) {
779             return;
780         }
781         
782         if(!(link.getTarget() instanceof BasicPort)) {
783             return;
784         }
785
786         BasicPort portSource = (BasicPort) link.getSource();
787         BasicPort portTarget = (BasicPort) link.getTarget();
788
789         SplitBlock split = null;
790         BasicPort saveSource = null;
791         BasicPort saveTarget = null;
792
793         if (portSource == null) { return; }
794         if (portTarget == null) { return; }
795
796         //remove input link
797         if (portTarget.getParent() instanceof SplitBlock) {
798                 split = (SplitBlock) portTarget.getParent();
799                 
800                 Object[] outLinks = getAllEdges(new Object[] {split.getOut1(), split.getOut2()});
801                 for (int i = 0; i < outLinks.length; i++) {
802                         BasicLink outLink = (BasicLink) outLinks[i];
803                         if (outLink.getTarget().getParent() instanceof SplitBlock) {
804                                 removeCells(new Object[]{outLink});
805                         }
806                 }
807         }
808         
809         //Finally delete split and old associated links
810         if (split != null) {
811                 removeCells(new Object[]{split});
812         }
813
814         //reset variables
815         split = null;
816         saveSource = null;
817         saveTarget = null;
818
819         if (portSource.getParent() instanceof SplitBlock) {
820                 split = (SplitBlock) portSource.getParent();
821
822                 //remove out1, so link between in.source and out2.target
823                 if (split.getOut1() == portSource) {
824                         //save source and target ports 
825                         saveSource = getOppositePort(split.getIn());
826                         saveTarget = getOppositePort(split.getOut2());
827                 } else if (split.getOut2() == portSource) {
828                         //save source and target ports 
829                         saveSource = getOppositePort(split.getIn());
830                         saveTarget = getOppositePort(split.getOut1());
831                 }
832         }
833
834         if (saveSource != null && saveTarget != null) {
835                 //create new link
836                 BasicLink newLink = BasicLink.createLinkFromPorts(saveSource, saveTarget);
837                 newLink.setGeometry(new mxGeometry(0,0,80,80));
838
839                 Object[] saveLinks = getAllEdges(new Object[]{saveSource, saveTarget});
840                 for (int k = 0; k < saveLinks.length; k++) {
841                         mxPoint[] savePts = ((BasicLink) saveLinks[k]).getPoints(0, false);
842                         if (savePts != null) {
843                                 for (int j = 0; j < savePts.length; j++) {
844                                         newLink.addPoint(savePts[j].getX(), savePts[j].getY());
845                                 }
846                         }
847                 }
848
849                 newLink.setSource(saveSource);
850                 newLink.setTarget(saveTarget);
851                 addCell(newLink);
852
853                 //unlink split and delete unlinked links
854         }
855
856         if (split != null) {
857                 split.unlinkAndClean();
858                 removeCells(new Object[]{split});
859         }
860     }
861
862     private BasicPort getOppositePort(BasicPort source) {
863         Object[] objs = getAllEdges(new Object[]{source});
864         if (objs.length == 0 || objs.length > 1) {
865                 return null;
866         }
867         
868         BasicLink link = (BasicLink) objs[0];
869         if (link.getSource() == source) {
870                 return (BasicPort) link.getTarget();
871         } else {
872                 return (BasicPort) link.getSource();
873         }
874     }
875     /**
876      * CellResizedTracker
877      * Called when mxEvents.CELLS_RESIZED is fired. 
878      */
879     private class CellResizedTracker implements mxIEventListener {
880         public void invoke(Object source, mxEventObject evt) {
881             Object[] cells = (Object[]) evt.getArgs()[0];
882             getModel().beginUpdate();
883             for (int i = 0; i < cells.length; ++i) {
884                 if (cells[i] instanceof BasicBlock) {
885                     BlockPositioning.updateBlockView((BasicBlock) cells[i]);
886                 }
887             }
888             getModel().endUpdate();
889         }
890     }
891
892     /**
893      * Update the modified block on undo/redo
894      */
895    private class UndoUpdateTracker implements mxIEventListener {
896         public void invoke(Object source, mxEventObject evt) {
897             List<mxUndoableChange> changes = ((mxUndoableEdit) evt.getArgAt(0)).getChanges();
898             Object[] changedCells = getSelectionCellsForChanges(changes);
899             getModel().beginUpdate();
900             for (Object object : changedCells) {
901                 if (object instanceof BasicBlock) {
902                     BasicBlock current = (BasicBlock) object;
903                     
904                     // When we change the style property we have to update some
905                     // BasiBlock fields
906                     if (changes.get(0) instanceof mxStyleChange) {
907                         current.updateFieldsFromStyle();
908                     }
909                     
910                     // Update the block position
911                     BlockPositioning.updateBlockView(current);
912                 }
913             }
914             getModel().endUpdate();
915             refresh();
916         }
917     };
918     
919     private class XcosKeyListener implements KeyListener{
920
921         public XcosKeyListener(XcosDiagram diagram) {}
922
923         public void keyTyped(KeyEvent e) {}
924
925         public void keyPressed(KeyEvent e) {}   
926
927         public void keyReleased(KeyEvent e) {
928             if(e.getKeyChar() == KeyEvent.VK_ESCAPE) {
929                 if(drawLink != null) {
930                     getModel().remove(drawLink);
931                     cancelDrawLinkAction();
932                 }                   
933             }
934         }
935     }
936     /**
937      * MouseListener inner class
938      */
939     private class XcosMouseListener implements MouseListener {
940         private XcosDiagram diagram = null;
941
942         public XcosMouseListener(XcosDiagram diagram) {
943                 this.diagram = diagram;
944         }
945
946         public void mouseClicked(MouseEvent e) {
947                 Object cell = getAsComponent().getCellAt(e.getX(), e.getY());
948
949                 // Double Click within empty diagram Area
950                 if (e.getClickCount() >= 2 && SwingUtilities.isLeftMouseButton(e) && cell == null) {
951                         TextBlock textBlock = (TextBlock) BlockFactory.createBlock(BlockInterFunction.TEXT_f);
952                         textBlock.getGeometry().setX(e.getX() - textBlock.getGeometry().getWidth() / 2.0);
953                         textBlock.getGeometry().setY(e.getY() - textBlock.getGeometry().getWidth() / 2.0);
954                         addCell(textBlock);
955                         return;
956                 }
957
958                 // Double Click within some component
959                 if (e.getClickCount() >= 2 && SwingUtilities.isLeftMouseButton(e) && cell != null)
960                 {
961                         getModel().beginUpdate();
962                         if (cell instanceof BasicBlock) {
963                                 BasicBlock block = (BasicBlock) cell;
964                                 e.consume();
965                                 block.openBlockSettings(buildEntireContext());
966                         }
967                         if (cell instanceof BasicLink) {
968                                 ((BasicLink) cell).insertPoint(e.getX(), e.getY());
969                         }
970                         getModel().endUpdate();
971                         refresh();
972                 }
973
974                 // Ctrl + Shift + Right Middle Click : for debug !!
975                 if (e.getClickCount() >= 2 && SwingUtilities.isMiddleMouseButton(e)
976                                 && e.isShiftDown() && e.isControlDown())
977                 {
978                         System.err.println("[DEBUG] Click at position : " + e.getX() + " , " + e.getY());
979                         if (cell == null) {
980                                 System.err.println("[DEBUG] Click on diagram");
981                                 System.err.println("Default Parent ID : " + ((mxCell) getDefaultParent()).getId());
982                                 System.err.println("Model root ID : " + ((mxCell) getModel().getRoot()).getId());
983                                 System.err.println("getParentWindow : " + (getParentTab() == null ? null : getParentTab().getParentWindow()));
984                         } else {
985                                 System.err.println("[DEBUG] Click on : " + cell);
986                                 System.err.println("[DEBUG] Style : " + ((mxCell) cell).getStyle());
987                                 System.err.println("[DEBUG] NbEdges : " + ((mxCell) cell).getEdgeCount());
988                                 System.err.println("[DEBUG] NbChildren : " + ((mxCell) cell).getChildCount());
989                                 for (int i = 0; i < ((mxCell) cell).getChildCount(); i++) {
990                                         System.err.println("[DEBUG] Child NbEdges : " + ((mxCell) cell).getChildAt(i).getEdgeCount());
991                                 }
992
993                                 if(cell instanceof BasicLink) {
994                                         System.err.println("[DEBUG] Link Points : " + ((BasicLink) cell).getPointCount());
995                                 }
996                         }
997
998                 }
999
1000                 // Context menu
1001                 if ((e.getClickCount() == 1 && SwingUtilities.isRightMouseButton(e))
1002                                 || e.isPopupTrigger()
1003                                 || XcosMessages.isMacOsPopupTrigger(e)) {
1004
1005                         if (cell == null) {
1006                                 // Display diagram context menu
1007                                 ContextMenu menu = ScilabContextMenu.createContextMenu();
1008
1009                                 menu.add(UndoAction.undoMenu((ScilabGraph) getAsComponent().getGraph()));
1010                                 menu.add(RedoAction.redoMenu((ScilabGraph) getAsComponent().getGraph()));
1011                                 menu.add(PasteAction.pasteMenu((ScilabGraph) getAsComponent().getGraph()));
1012                                 menu.add(SelectAllAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1013                                 /*---*/
1014                                 menu.getAsSimpleContextMenu().addSeparator();
1015                                 /*---*/
1016                                 menu.add(SetContextAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1017                                 menu.add(SetupAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1018
1019                                 if(diagram instanceof SuperBlockDiagram) {
1020                                         /*---*/
1021                                         menu.getAsSimpleContextMenu().addSeparator();
1022                                         /*---*/
1023                                         menu.add(ShowParentAction.createMenu(diagram));
1024                                 }
1025                                 /*---*/
1026                                 menu.getAsSimpleContextMenu().addSeparator();
1027                                 /*---*/
1028                                 menu.add(ZoomInAction.zoominMenu((ScilabGraph) getAsComponent().getGraph()));
1029                                 menu.add(ZoomOutAction.zoomoutMenu((ScilabGraph) getAsComponent().getGraph()));
1030                                 /*---*/
1031                                 menu.getAsSimpleContextMenu().addSeparator();
1032                                 /*---*/
1033                                 menu.add(DiagramBackgroundAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1034                                 /*---*/
1035                                 menu.getAsSimpleContextMenu().addSeparator();
1036                                 /*---*/
1037                                 menu.add(XcosDocumentationAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1038
1039                                 ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y);
1040
1041                                 menu.setVisible(true);
1042
1043                         } else {
1044                                 // Display object context menu
1045                                 if (cell instanceof BasicBlock) {
1046                                         BasicBlock block = (BasicBlock) cell;
1047                                         block.openContextMenu((ScilabGraph) getAsComponent().getGraph());
1048                                 }
1049                                 if (cell instanceof BasicLink) {
1050                                         BasicLink link = (BasicLink) cell;
1051                                         link.openContextMenu((ScilabGraph) getAsComponent().getGraph());
1052                                 }
1053                         }
1054                 }
1055         }
1056
1057         public void mouseEntered(MouseEvent e) {
1058         }
1059
1060         public void mouseExited(MouseEvent e) {
1061         }
1062
1063         public void mousePressed(MouseEvent e) {
1064         }
1065
1066         public void mouseReleased(MouseEvent e) {
1067                 Object cell = getAsComponent().getCellAt(e.getX(), e.getY());
1068
1069                 if(SwingUtilities.isLeftMouseButton(e)) {
1070                         if (waitSplitRelease) {
1071                                 dragSplitPos = new mxPoint(e.getX(), e.getY());
1072                                 waitSplitRelease = false;
1073                                 addSplitEdge(splitLink, splitPort);
1074                         } else if(waitPathRelease){
1075                                 //Tips for ignore first mouse release after drag
1076                                 waitPathRelease = false;
1077                                 waitPathAddEdge = true;
1078
1079                                 if(!e.isControlDown()) {
1080                                         //adjust final point
1081                                         mxGeometry geoPort = drawLink.getSource().getGeometry();
1082                                         mxGeometry geoBlock = drawLink.getSource().getParent().getGeometry();
1083                                         mxPoint lastPoint = new mxPoint(geoBlock.getX() + geoPort.getCenterX(), geoBlock.getY() + geoPort.getCenterY());
1084                                         mxPoint point = getPointPosition(lastPoint, new mxPoint(e.getX(), e.getY()));
1085
1086                                         getModel().beginUpdate();
1087                                         drawLink.getGeometry().setTargetPoint(point);
1088                                         getModel().endUpdate();
1089                                         refresh();
1090                                 }
1091                         } else if(waitPathAddEdge){
1092                                 System.err.println("mouseReleased : waitPathAddEdge");
1093                                 if(drawLink != null) {
1094                                         getModel().beginUpdate();
1095                                         //move end of link and add point at old position
1096                                         mxGeometry geo = drawLink.getGeometry();
1097                                         drawLink.addPoint(geo.getTargetPoint().getX(), geo.getTargetPoint().getY());
1098                                         setSelectionCell(drawLink);
1099
1100                                         if(cell != null) {
1101                                                 mxICell source = drawLink.getSource();
1102
1103                                                 StringBuffer error = checkMultiplicities(drawLink, source, cell);
1104                                                 if(error == null) {
1105                                                         if(cell instanceof BasicLink && cell != drawLink) { //no loop
1106                                                                 //draw link with a SplitBlock
1107                                                                 dragSplitPos = new mxPoint(e.getX(), e.getY());
1108                                                                 addSplitEdge((BasicLink)cell, drawLink);
1109                                                         } else {
1110                                                                 getModel().setTerminal(drawLink, cell, false);
1111                                                         }
1112
1113                                                         //invert source and target if needed
1114                                                         if(checkEdgeDirection(source, cell) == false) {
1115                                                                 getModel().beginUpdate();
1116                                                                 drawLink.invertDirection();
1117                                                                 getModel().endUpdate();
1118                                                         }
1119
1120                                                         //reset info, flags and object
1121                                                         cancelDrawLinkAction();
1122                                                 } else {
1123                                                         if(cell != drawLink) {
1124                                                                 JOptionPane.showMessageDialog(getAsComponent(), error);
1125                                                         }
1126                                                         setSelectionCell(drawLink);
1127                                                 }
1128                                         } else {
1129                                                 if(!e.isControlDown()) {
1130                                                         geo.setTargetPoint(getPointPosition(geo.getTargetPoint(), new mxPoint(e.getX(), e.getY())));
1131                                                 } else {
1132                                                         geo.setTargetPoint(new mxPoint(e.getX(), e.getY()));
1133                                                 }
1134                                         }
1135                                         getModel().endUpdate();
1136                                         refresh();
1137                                 } else {
1138                                         cancelDrawLinkAction();
1139                                 }
1140                         } else {
1141                                 dragSplitPos = null;
1142                         }
1143                 }
1144         }
1145     }
1146
1147     static mxPoint getPointPosition(mxPoint origin, mxPoint click) {
1148         boolean signX = click.getX() > origin.getX();
1149         boolean signY = click.getY() > origin.getY();
1150         double diffX = Math.abs(click.getX() - origin.getX());
1151         double diffY = Math.abs(click.getY() - origin.getY());
1152
1153         if(diffX > diffY) {
1154             if(diffY > (diffX / 2)) { //diagonal
1155                 diffY = diffX;
1156             } else { //orthogonal
1157                 diffY = 0;
1158             }
1159         } else { // < or ==
1160             if(diffX > (diffY / 2)) { //diagonal
1161                 diffX = diffY;
1162             } else { //orthogonal
1163                 diffX = 0;
1164             }
1165         }
1166
1167         //restore signs
1168         if(signX == false) {
1169             diffX = -diffX;
1170         }
1171
1172         if(signY == false) {
1173             diffY = - diffY;
1174         }
1175
1176         return new mxPoint(origin.getX() + diffX, origin.getY() + diffY); 
1177     }
1178     /*
1179      * Manage Group to be CellFoldable i.e with a (-) to reduce
1180      * and a (+) to expand them.
1181      * Only non-Block / non-Port Cell are foldable. 
1182      * 
1183      * (non-Javadoc)
1184      * @see com.mxgraph.view.mxGraph#isCellFoldable(java.lang.Object, boolean)
1185      */
1186     public boolean isCellFoldable(Object cell, boolean collapse) {
1187                 return !(cell instanceof BasicBlock) && super.isCellFoldable(cell, collapse);
1188     }
1189
1190         public boolean isCellClonable(Object cell) {
1191                 return true;
1192         }
1193         
1194         public boolean isCellSelectable(Object cell) {
1195             if(cell instanceof BasicPort) {
1196                 return false;
1197             }
1198             return super.isCellSelectable(cell);
1199         }
1200         
1201         public boolean isCellMovable(Object cell) {
1202                 if (cell instanceof BasicPort) {
1203                         return false;
1204                 }
1205
1206                 boolean movable = false;
1207                 Object[] cells =  this.getSelectionCells();
1208
1209                 //don't move if selection is only links
1210                 for (int i = 0; i < cells.length; i++) {
1211                         if (!(cells[i] instanceof BasicLink)) {
1212                                 movable = true;
1213                                 break;
1214                         }
1215                 }
1216
1217                 return movable && super.isCellMovable(cell);
1218     }
1219
1220     public boolean isCellResizable(Object cell) {
1221         if (cell instanceof SplitBlock) {
1222                 return false;
1223         }
1224         return (cell instanceof BasicBlock) && super.isCellResizable(cell);
1225     }
1226
1227     public boolean isCellDeletable(Object cell) {
1228         if (cell instanceof BasicBlock && ((BasicBlock) cell).isLocked()) {
1229                 return false;
1230         }
1231
1232         return !(cell instanceof BasicPort)     && super.isCellDeletable(cell);
1233     }
1234
1235     public boolean isCellEditable(Object cell) {
1236         return (cell instanceof TextBlock) && super.isCellDeletable(cell);
1237     }
1238
1239     public boolean isCellDisconnectable(Object cell, Object terminal,boolean source) {
1240         return super.isCellDisconnectable(cell, terminal, source);
1241     }
1242     
1243     public boolean isCellConnectable(Object cell)
1244     {
1245         //currently in draw link action
1246         if(waitPathAddEdge) {
1247             if(drawLink != null) {
1248                 StringBuffer error = checkMultiplicities(drawLink, drawLink.getSource(), cell);
1249                 if(error == null) {
1250                     return true;
1251                 }
1252                 return false;
1253             }
1254         }
1255         
1256         if(cell instanceof BasicBlock)  {
1257             return false;
1258         }
1259         
1260         if(cell instanceof BasicPort) {
1261             int sourceOut = mxGraphModel.getDirectedEdgeCount(getModel(), cell, true);
1262             int targetIn = mxGraphModel.getDirectedEdgeCount(getModel(), cell, false);
1263             
1264             if(sourceOut > 0 || targetIn > 0) {
1265                 return false;
1266             }
1267         }
1268         return !(cell instanceof BasicBlock) && super.isCellConnectable(cell);
1269     }
1270
1271     public boolean isAutoSizeCell(Object cell) {
1272         return (cell instanceof AfficheBlock) || super.isAutoSizeCell(cell);
1273     }
1274
1275
1276     public void dumpToHdf5File(String fileName) {
1277         if (fileName == null) {
1278             FileChooser fc = ScilabFileChooser.createFileChooser();
1279             fc.setInitialDirectory(getSavedFile());
1280             fc.setMultipleSelection(false);
1281             fc.displayAndWait();
1282
1283             if (fc.getSelection() == null || fc.getSelection().length == 0 || fc.getSelection()[0].equals("")) {
1284                 return;
1285             }
1286             fileName = fc.getSelection()[0];
1287             System.out.println("Saving to file : {" + fileName + "}");
1288         }
1289
1290         BlockWriter.writeDiagramToFile(fileName, this);
1291     }
1292
1293     public double getFinalIntegrationTime() {
1294         return finalIntegrationTime;
1295     }
1296
1297     public void setFinalIntegrationTime(double finalIntegrationTime) {
1298         this.finalIntegrationTime = finalIntegrationTime;
1299     }
1300
1301     public double getIntegratorAbsoluteTolerance() {
1302         return integratorAbsoluteTolerance;
1303     }
1304
1305     public void setIntegratorAbsoluteTolerance(double integratorAbsoluteTolerance) {
1306         this.integratorAbsoluteTolerance = integratorAbsoluteTolerance;
1307     }
1308
1309     public double getIntegratorRelativeTolerance() {
1310         return integratorRelativeTolerance;
1311     }
1312
1313     public void setIntegratorRelativeTolerance(double integratorRelativeTolerance) {
1314         this.integratorRelativeTolerance = integratorRelativeTolerance;
1315     }
1316
1317     public double getMaximumStepSize() {
1318         return maximumStepSize;
1319     }
1320
1321     public void setMaximumStepSize(double maximumStepSize) {
1322         this.maximumStepSize = maximumStepSize;
1323     }
1324
1325     public double getMaxIntegrationTimeinterval() {
1326         return maxIntegrationTimeinterval;
1327     }
1328
1329     public void setMaxIntegrationTimeinterval(double maxIntegrationTimeinterval) {
1330         this.maxIntegrationTimeinterval = maxIntegrationTimeinterval;
1331     }
1332
1333     public double getRealTimeScaling() {
1334         return realTimeScaling;
1335     }
1336
1337     public void setRealTimeScaling(double realTimeScaling) {
1338         this.realTimeScaling = realTimeScaling;
1339     }
1340
1341     public double getSolver() {
1342         return solver;
1343     }
1344
1345     public void setSolver(double solver) {
1346         this.solver = solver;
1347     }
1348
1349     public double getToleranceOnTime() {
1350         return toleranceOnTime;
1351     }
1352
1353     public void setToleranceOnTime(double toleranceOnTime) {
1354         this.toleranceOnTime = toleranceOnTime;
1355     }
1356
1357     /**
1358      * Set the associated ViewPort
1359      * @param viewPort the Viewport
1360      */
1361     public void setViewPort(Tab viewPort) {
1362         this.viewPort = viewPort;
1363     }
1364
1365     /**
1366      * Get the associated ViewPort
1367      * @return the Viewport
1368      */
1369     public Tab getViewPort() {
1370         return viewPort;
1371     }
1372
1373     /**
1374      * Manage the visibility of the associated viewport
1375      * @param status new status
1376      */
1377     public void setViewPortVisible(boolean status) {
1378         // Hide/Show parent window if the viewport is the only tab
1379         if (viewPort.getParentWindow().getNbDockedObjects() == 1) {
1380             viewPort.getParentWindow().setVisible(status);
1381         }
1382         // Hide/Show viewport tab
1383         viewPort.setVisible(status);
1384
1385         // (Un)Check the corresponding menu
1386         viewPortMenu.setChecked(status);
1387     }
1388
1389     /**
1390      * Set menu used to manage Viewport visibility
1391      * @param menu the menu
1392      */
1393     public void setViewPortMenuItem(CheckBoxMenuItem menu) {
1394         this.viewPortMenu = menu;
1395     }
1396     /**
1397      * Manage the visibility of the grid and the associated menu
1398      * @param status new status
1399      */
1400     public void setGridVisible(boolean status) {
1401         setGridEnabled(status);
1402         getAsComponent().setGridVisible(status);
1403         getAsComponent().repaint();
1404
1405         // (Un)Check the corresponding menu
1406         if(gridMenu != null) {
1407             gridMenu.setChecked(status);
1408         }
1409     }
1410
1411     /**
1412      * Set menu used to manage Grid visibility
1413      * @param menu the menu
1414      */
1415     public void setGridMenuItem(CheckBoxMenuItem menu) {
1416         this.gridMenu = menu;
1417     }
1418
1419     /**
1420      * Close Xcos instance including all tabs
1421      */
1422     public void closeDiagram() {
1423         closeDiagram(false);
1424     }
1425     
1426     /**
1427      * Close Xcos instance including all tabs
1428      */
1429     public void closeDiagram(boolean fromScilab) {
1430
1431         boolean wantToClose = true;
1432
1433         if(canClose() == false) {
1434             setVisible(false);
1435             return;
1436         }
1437         
1438         if (isModified()) {
1439             // The diagram has been modified
1440             // Ask the user want he want to do !
1441             
1442             AnswerOption answer; 
1443             if(fromScilab == true) {
1444                 answer = ScilabModalDialog.show(getParentTab(), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS, 
1445                         IconType.QUESTION_ICON, ButtonType.YES_NO);
1446             } else {
1447                 answer = ScilabModalDialog.show(getParentTab(), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS, 
1448                         IconType.QUESTION_ICON, ButtonType.YES_NO_CANCEL);
1449             }
1450
1451             switch(answer) {
1452             case YES_OPTION :
1453                 // Save the diagram
1454                 if (!saveDiagram()) {
1455                         //if save is canceled, cancel close windows
1456                         wantToClose = false;
1457                 }
1458                 break;
1459             case NO_OPTION :
1460                 break;
1461             case CANCEL_OPTION :
1462                 // The user cancels
1463                 wantToClose = false;
1464                 break;
1465             }
1466         }
1467
1468         if (wantToClose) {
1469             if(getParentTab() != null) {
1470                 ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper.getCorrespondingUIElement(getParentTab().getParentWindowId());
1471                 xcosWindow.removeTab(getParentTab());
1472                 viewPort.close();
1473             }
1474             XcosTab.closeDiagram(this);
1475             setOpened(false);
1476         }
1477     }
1478
1479     public boolean saveDiagram() {
1480         boolean isSuccess = false;
1481         if (getSavedFile() == null) {
1482             isSuccess = saveDiagramAs(null);
1483         } else {
1484             isSuccess = saveDiagramAs(getSavedFile());
1485         }
1486
1487         if (isSuccess) {
1488             setModified(false);
1489         }
1490
1491         return isSuccess;
1492     }
1493
1494     public boolean saveDiagramAs(String fileName) {
1495
1496         boolean isSuccess = false;
1497         info(XcosMessages.SAVING_DIAGRAM);
1498         this.getParentTab().getInfoBar().draw();
1499         if (fileName == null) {
1500             // Choose a filename
1501             SwingScilabFileChooser fc = ((SwingScilabFileChooser) ScilabFileChooser.createFileChooser().getAsSimpleFileChooser());
1502             fc.setTitle(XcosMessages.SAVE_AS);
1503             fc.setUiDialogType(JFileChooser.SAVE_DIALOG);
1504             fc.setMultipleSelection(false);
1505             if (this.getSavedFile() != null) {
1506                 fc.setSelectedFile(new File(this.getSavedFile()));
1507             }
1508
1509             SciFileFilter xcosFilter = new SciFileFilter("*.xcos", null, 0);
1510             SciFileFilter allFilter = new SciFileFilter("*.*", null, 1);
1511             fc.addChoosableFileFilter(xcosFilter);
1512             fc.addChoosableFileFilter(allFilter);
1513             fc.setFileFilter(xcosFilter);
1514
1515             fc.setAcceptAllFileFilterUsed(false);
1516             fc.displayAndWait();
1517
1518             if (fc.getSelection() == null || fc.getSelection().length == 0 || fc.getSelection()[0].equals("")) {
1519                 info(XcosMessages.EMPTY_INFO);
1520                 return isSuccess;
1521             }
1522             fileName = fc.getSelection()[0];
1523         }
1524         /* Extension checks */
1525         File file = new File(fileName);
1526         if(!file.exists()) {
1527             String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
1528
1529             if (extension.equals(fileName)) {
1530                 /* No extension given --> .xcos added */
1531                 fileName += ".xcos";
1532             }
1533         }
1534
1535         XcosCodec codec = new XcosCodec();
1536         String xml = mxUtils.getXml(codec.encode(this));
1537
1538         try {
1539             mxUtils.writeFile(xml, fileName);
1540             isSuccess = true;
1541             resetUndoCounter();
1542         } catch (IOException e1) {
1543             e1.printStackTrace();
1544             isSuccess = false;
1545         }
1546
1547         if (isSuccess) {
1548             this.setSavedFile(fileName);
1549             File theFile = new File(fileName);
1550             setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1551             ConfigXcosManager.saveToRecentOpenedFiles(fileName);
1552             setModified(false);
1553         } else {
1554             XcosDialogs.couldNotSaveFile(this);
1555         }
1556         info(XcosMessages.EMPTY_INFO);
1557         return isSuccess;
1558     }
1559
1560     public void setTitle(String title) {
1561         super.setTitle(title);
1562         updateTabTitle();
1563     }
1564
1565     public void updateTabTitle() {
1566         String tabTitle = !isModified() ? getTitle() : "* " + getTitle();
1567         if (getParentTab() != null) {
1568             getParentTab().setName(tabTitle);
1569             getParentTab().draw();
1570         }
1571     }
1572
1573     public String[] buildEntireContext() {
1574         return getContext();
1575     }
1576     
1577     public void setContext(String[] context) {
1578         this.context = context;
1579         updateCellsContext();
1580     }
1581
1582     public String[] getContext() {
1583         return context;
1584     }
1585
1586         public void updateCellsContext() {
1587                 Object rootParent = getDefaultParent();
1588                 int child_counts = getModel().getChildCount(rootParent);
1589                 for (int i = 0; i < child_counts; ++i) {
1590                         Object obj = getModel().getChildAt(rootParent, i);
1591                         if (obj instanceof ContextUpdate) {
1592                                 String[] context = buildEntireContext();
1593
1594                                 /* Determine if the context is not empty */
1595                                 int nbOfDetectedChar = 0;
1596                                 for (int j = 0; j < context.length; j++) {
1597                                         context[j] = context[j].replaceFirst("\\s", "");
1598                                         nbOfDetectedChar += context[j].length();
1599                                         if (nbOfDetectedChar != 0)
1600                                                 break;
1601                                 }
1602
1603                                 if (nbOfDetectedChar != 0) {
1604                                         ((ContextUpdate) obj).onContextChange(context);
1605                                 }
1606
1607                         } else if (obj instanceof SuperBlock) {
1608                                 SuperBlock superBlock = (SuperBlock) obj;
1609                                 if (superBlock.getChild() != null) {
1610                                         superBlock.getChild().updateCellsContext();
1611                                 }
1612                         }
1613                 }
1614         }
1615
1616     public String getVersion() {
1617         return version;
1618     }
1619     
1620     public int getDebugLevel() {
1621         return debugLevel;
1622     }
1623     
1624     public void setDebugLevel(int debugLevel) {
1625         this.debugLevel = debugLevel;
1626     }
1627
1628     /**
1629      * Open a Diagram :
1630      * If current Diagram is empty, open within it
1631      * else open a new window.
1632      * 
1633      * @param diagramm
1634      */
1635     public void openDiagram(HashMap<String, Object> diagramm) {
1636         if (diagramm != null) {
1637             if (getModel().getChildCount(getDefaultParent()) == 0) {
1638                 loadDiagram(diagramm);
1639             } else {
1640                 XcosDiagram xcosDiagram = Xcos.createANotShownDiagram();
1641                 xcosDiagram.loadDiagram(diagramm);
1642                 setChildrenParentDiagram(xcosDiagram);
1643                 XcosTab.showTabFromDiagram(xcosDiagram);
1644             }
1645         } else {
1646             XcosDialogs.couldNotLoadFile(this);
1647         }
1648     }
1649
1650     /**
1651      * Load a Diagramm structure into current window.
1652      * 
1653      * @param diagramm
1654      */
1655     public void loadDiagram(HashMap<String, Object> diagramm) {
1656         List<BasicBlock> allBlocks = (List<BasicBlock>) diagramm.get("Blocks");
1657         List<TextBlock> allTextBlocks = (List<TextBlock>) diagramm.get("TextBlocks");
1658         HashMap<String, Object> allLinks = (HashMap<String, Object>) diagramm.get("Links");
1659         HashMap<String, Object> properties = (HashMap<String, Object>) diagramm.get("Properties");
1660
1661         setFinalIntegrationTime((Double) properties.get("finalIntegrationTime"));
1662         setIntegratorAbsoluteTolerance((Double) properties.get("integratorAbsoluteTolerance"));
1663         setIntegratorRelativeTolerance((Double) properties.get("integratorRelativeTolerance"));
1664         setToleranceOnTime((Double) properties.get("toleranceOnTime"));
1665         setMaxIntegrationTimeinterval((Double) properties.get("maxIntegrationTimeinterval"));
1666         setRealTimeScaling((Double) properties.get("realTimeScaling"));
1667         setSolver((Double) properties.get("solver"));
1668         setMaximumStepSize((Double) properties.get("maximumStepSize"));
1669         setContext((String[]) properties.get("context"));
1670
1671         List<BasicPort[]> linkPorts = (List<BasicPort[]>) allLinks.get("Ports");
1672         List<double[][]> linkPoints = (List<double[][]>) allLinks.get("Points");
1673
1674         Object[] objs = new Object[allBlocks.size() + linkPorts.size() + allTextBlocks.size()];
1675         getModel().beginUpdate();
1676         for (int i = 0; i < allBlocks.size(); ++i) {
1677                 objs[i] = allBlocks.get(i);
1678         }
1679
1680         for (int i = 0; i < linkPorts.size(); ++i) {
1681             BasicLink link = BasicLink.createLinkFromPorts(linkPorts.get(i)[0], linkPorts.get(i)[1]);
1682             link.setGeometry(new mxGeometry(0,0,80,80));
1683             link.setSource(linkPorts.get(i)[0]);
1684             link.setTarget(linkPorts.get(i)[1]);
1685             double[][] points = linkPoints.get(i);
1686
1687             if (points != null) {
1688                 for (int point = 0; point < points.length; point++) {
1689                     link.addPoint(points[point][0], points[point][1]);
1690                 }
1691             }
1692             objs[i + allBlocks.size()] = link;
1693         }
1694         
1695         for (int i = 0; i < allTextBlocks.size(); ++i) {
1696                 objs[i + allBlocks.size() + linkPorts.size() ] = allTextBlocks.get(i);
1697         }
1698         
1699         addCells(objs);
1700         getModel().endUpdate();
1701
1702         //this.setTitle(fileToLoad);
1703         //this.getParentTab().setName(fileToLoad);
1704
1705         setTitle((String) properties.get("title"));
1706         //getParentTab().setName((String) properties.get("title"));
1707
1708         // Clear all undo events in Undo Manager
1709         getUndoManager().reset();
1710         setModified(false);
1711     }
1712
1713     /**
1714      * Read a diagram from an HDF5 file (ask for creation if the file does not exist) 
1715      * @param diagramFileName file to open
1716      */
1717     public void openDiagramFromFile(String diagramFileName) {
1718         if (XcosTab.focusOnExistingFile(diagramFileName) == false) {
1719             File theFile = new File(diagramFileName);
1720             info(XcosMessages.LOADING_DIAGRAM);
1721             
1722             if (getParentTab() != null)
1723                 ((XcosTab) getParentTab()).setActionsEnabled(false);
1724
1725             if (theFile.exists()) {
1726                 transformAndLoadFile(theFile, false);
1727             } else {
1728                 AnswerOption answer = ScilabModalDialog.show(getParentTab(), String.format(
1729                         XcosMessages.FILE_DOESNT_EXIST, theFile.getAbsolutePath()),
1730                         XcosMessages.XCOS, IconType.QUESTION_ICON,
1731                         ButtonType.YES_NO);
1732
1733                 if (answer == AnswerOption.YES_OPTION) {
1734                     try {
1735                         FileWriter writer = new FileWriter(diagramFileName);
1736                         writer.write("");
1737                         writer.flush();
1738                         writer.close();
1739                         setSavedFile(diagramFileName);
1740                         setTitle(theFile.getName().substring(0,
1741                                 theFile.getName().lastIndexOf('.')));
1742                     } catch (IOException ioexc) {
1743                         JOptionPane.showMessageDialog(this.getAsComponent(), ioexc);
1744                     }
1745                 }
1746             }
1747             info(XcosMessages.EMPTY_INFO);
1748             if (getParentTab() != null)
1749                 ((XcosTab) getParentTab()).setActionsEnabled(true);
1750             this.resetUndoManager();
1751         }
1752     }
1753     
1754
1755     /**
1756      * Load a file with different method depending on it extension 
1757      * @param theFile File to load
1758      */
1759     protected boolean transformAndLoadFile(File theFile, boolean wait) {
1760         final File fileToLoad = theFile;
1761         final XcosFileType filetype = XcosFileType.findFileType(fileToLoad);
1762         boolean result = false;
1763
1764         switch (filetype) {
1765         case COSF:
1766         case COS:
1767             if(wait) {
1768                 File newFile;
1769                 newFile = filetype.exportToHdf5(fileToLoad);
1770                 result = transformAndLoadFile(newFile, wait);
1771             } else {
1772                 Thread transformAction = new Thread() {
1773                     public void run() {
1774                         File newFile;
1775                         newFile = filetype.exportToHdf5(fileToLoad);
1776                         transformAndLoadFile(newFile, false);
1777                     }
1778                 };
1779                 transformAction.start();
1780                 result = true;
1781             }
1782             break;
1783
1784         case XCOS:
1785             Document document = loadXcosDocument(theFile.getAbsolutePath());
1786             if(document == null) {
1787                 XcosDialogs.couldNotLoadFile(this);
1788                 return false;
1789             }
1790
1791             XcosCodec codec = new XcosCodec(document);
1792
1793             if (getModel().getChildCount(getDefaultParent()) == 0) {
1794                 codec.decode(document.getDocumentElement(), this);
1795                 setModified(false);
1796                 setSavedFile(theFile.getAbsolutePath());
1797                 setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1798                 setChildrenParentDiagram();
1799                 generateUID();
1800             } else {
1801                 XcosDiagram xcosDiagram = Xcos.createANotShownDiagram();
1802                 xcosDiagram.info(XcosMessages.LOADING_DIAGRAM);
1803                 codec.decode(document.getDocumentElement(), xcosDiagram);
1804                 xcosDiagram.setModified(false);
1805                 xcosDiagram.setSavedFile(theFile.getAbsolutePath());
1806                 xcosDiagram.setTitle(theFile.getName().substring(0,     theFile.getName().lastIndexOf('.')));
1807                 setChildrenParentDiagram(xcosDiagram);
1808                 XcosTab.showTabFromDiagram(xcosDiagram);
1809                 xcosDiagram.generateUID();
1810                 xcosDiagram.info(XcosMessages.EMPTY_INFO);
1811             }
1812             
1813             result = true;
1814             break;
1815
1816         case HDF5:
1817             openDiagram(BlockReader.readDiagramFromFile(fileToLoad.getAbsolutePath()));
1818             generateUID();
1819             setModified(false);
1820             result = true;
1821             break;
1822
1823         default:
1824             XcosDialogs.couldNotLoadFile(this);
1825             break;
1826         }
1827         return result;
1828     }
1829
1830     static Document loadXcosDocument(String xcosFile) {
1831         DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
1832         DocumentBuilder docBuilder;
1833         try {
1834             docBuilder = docBuilderFactory.newDocumentBuilder();
1835             return docBuilder.parse(xcosFile);
1836         } catch (ParserConfigurationException e) {
1837             return null;
1838         } catch (SAXException e) {
1839             return null;
1840         } catch (IOException e) {
1841             return null;
1842         }
1843     }
1844     
1845     public void generateUID() {
1846         for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1847             if (getModel().getChildAt(getDefaultParent(), i) instanceof BasicBlock) {
1848                 BasicBlock block = (BasicBlock)getModel().getChildAt(getDefaultParent(), i);
1849                 if(block.getRealParameters() instanceof ScilabMList) {
1850                     //we have a hidden SuperBlock, create a real one
1851                     SuperBlock newSP = (SuperBlock)BlockFactory.createBlock("SUPER_f");
1852                     newSP.setRealParameters(block.getRealParameters());
1853                     newSP.createChildDiagram(true);
1854                     newSP.setParentDiagram(this);
1855                     block.setRealParameters(BlockWriter.convertDiagramToMList(newSP.getChild()));
1856                 } else if(block.getId() == null || block.getId().compareTo("") == 0) {
1857                     block.setId();
1858                 }
1859             }
1860         }
1861     }
1862
1863     /**
1864      * Update all the children of the current graph.
1865      */
1866     public void setChildrenParentDiagram() {
1867         setChildrenParentDiagram(this);
1868     }
1869
1870     /**
1871      * For each block in the argument, call its setParentDiagram method
1872      * @param diagram The new parent of the blocks.
1873      */
1874     private void setChildrenParentDiagram(XcosDiagram diagram) {
1875         for (int i = 0; i < diagram.getModel().getChildCount(diagram.getDefaultParent()); i++) {
1876             mxCell cell = (mxCell) diagram.getModel().getChildAt(diagram.getDefaultParent(), i);
1877             if (cell instanceof BasicBlock) {
1878                 BasicBlock block = (BasicBlock) cell;
1879                 block.setParentDiagram(diagram);
1880                 if (block instanceof AfficheBlock) {
1881                     AfficheBlock affich = (AfficheBlock) block;
1882                     XcosTab.getAfficheBlocks().put(affich.getHashCode(), affich);
1883                 }
1884             }
1885         }
1886     }
1887
1888     /**
1889      * Getting the root diagram of a decomposed diagram
1890      * @return Root parent of the whole parent
1891      */
1892     public XcosDiagram getRootDiagram() {
1893         XcosDiagram rootGraph = this;
1894         while (rootGraph instanceof SuperBlockDiagram) {
1895             rootGraph = ((SuperBlockDiagram) rootGraph).getContainer().getParentDiagram();
1896         }
1897         return rootGraph;
1898     }
1899
1900     /**
1901      * Returns the tooltip to be used for the given cell.
1902      */
1903     public String getToolTipForCell(Object cell)
1904     {
1905         if (cell instanceof BasicBlock) {
1906             return ((BasicBlock) cell).getToolTipText();
1907         } else if(cell instanceof BasicPort) {
1908             return ((BasicPort) cell).getToolTipText();
1909         }
1910         return "";
1911     }
1912
1913     /**
1914      * Set any text to an Afficheblock specified by its ID.
1915      * @param blockID ID of the AfficheBlock to be modified.
1916      * @param blockValue Content to be apply to the block.
1917      * @param iRows Number of Row in the blockValue.
1918      * @param iCols Number of Collumns in the blockValue.
1919      */
1920     public static void setBlockTextValue(int blockID, String[] blockValue, int iRows, int iCols) {
1921
1922         AfficheBlock block = XcosTab.getAfficheBlocks().get(blockID);
1923         if (block == null) {
1924             return;
1925         }
1926
1927         String blockResult = "";
1928         for (int i = 0; i < iRows; i++) {
1929             for (int j = 0; j < iCols; j++) {
1930                 if (iCols != 0) {
1931                     blockResult += "  ";
1932                 }
1933                 blockResult += blockValue[j * iRows + i];
1934             }
1935             blockResult += System.getProperty("line.separator");
1936         }
1937
1938         block.setValue(blockResult);
1939         block.getParentDiagram().refresh();
1940     }
1941
1942
1943     /**
1944      * Display the message in info bar.
1945      * @param message Informations
1946      */
1947     public void info(String message) {
1948         final String localMessage = message;
1949         if (getParentTab() != null && getParentTab().getInfoBar() != null) {
1950             getParentTab().getInfoBar().setText(localMessage);
1951         }
1952     }
1953
1954     /**
1955      * Display the message into an error popup
1956      * @param message Error of the message
1957      */
1958     public void error(String message) {
1959         JOptionPane.showMessageDialog(getAsComponent(), message, XcosMessages.XCOS, JOptionPane.ERROR_MESSAGE);
1960     }
1961
1962     /**
1963      * Find the block corresponding to the given uid
1964      * and display a warning message.
1965      * 
1966      * @param uid - A String as UID.
1967      * @param message - The message to display.
1968      */
1969     public void warnCellByUID(String uid, String message) {
1970         for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1971             if (getModel().getChildAt(getDefaultParent(), i) instanceof mxCell) {
1972                 if (((mxCell) getModel().getChildAt(getDefaultParent(), i)).getId().compareTo(uid) == 0) {
1973                     //to put on top, only for new message, no for reset
1974                     if(message.compareTo("") != 0) {
1975                         setVisible(true);
1976                     }
1977
1978                     getAsComponent().setCellWarning(getModel().getChildAt(getDefaultParent(), i), message);
1979                 }
1980             }
1981         }
1982     }
1983
1984     /**
1985      * Set the current diagram in a modified state
1986      * @param modified True or False whether the current diagram must be saved or not. 
1987      */
1988     public void setModified(boolean modified) {
1989         super.setModified(modified);
1990         updateTabTitle();
1991     }
1992
1993     /**
1994      * Revert an action
1995      */
1996     public void undo() {
1997         super.undo();
1998
1999         if (getParentTab() != null) {
2000             if (getUndoManager().canUndo()) {
2001                 ((XcosTab) getParentTab()).setEnabledUndo(true);
2002             } else {
2003                 ((XcosTab) getParentTab()).setEnabledUndo(false);
2004             }
2005             ((XcosTab) getParentTab()).setEnabledRedo(true);
2006         }
2007
2008         updateUndoModifiedState();
2009         /*
2010          * if (undoManager.canRedo()){
2011          * ((Xcos)getParentTab()).setEnabledRedo(true); } else {
2012          * ((Xcos)getParentTab()).setEnabledRedo(false); }
2013          */
2014         
2015         if(waitPathAddEdge) {
2016             if(drawLink != null) {
2017                 getModel().remove(drawLink);
2018             }
2019             cancelDrawLinkAction();
2020         }
2021     }
2022
2023
2024
2025     /**
2026      * Apply the previously reverted action
2027      */
2028     public void redo() {
2029         super.redo();
2030
2031         updateUndoModifiedState();
2032
2033         if (getParentTab() != null) {
2034             if (getUndoManager().canUndo()) {
2035                 ((XcosTab) getParentTab()).setEnabledUndo(true);
2036             } else {
2037                 ((XcosTab) getParentTab()).setEnabledUndo(false);
2038             }
2039             if (getUndoManager().canRedo()) {
2040                 ((XcosTab) getParentTab()).setEnabledRedo(true);
2041             } else {
2042                 ((XcosTab) getParentTab()).setEnabledRedo(false);
2043             }
2044         }
2045     }
2046
2047     /**
2048      * This function will reset the UndoManager in a stable state.
2049      */
2050     public void resetUndoManager() {
2051         getUndoManager().reset();
2052
2053         resetUndoCounter();
2054
2055         if (getParentTab() != null) {
2056             ((XcosTab) getParentTab()).setEnabledRedo(false);
2057             ((XcosTab) getParentTab()).setEnabledUndo(false);
2058         }
2059     }
2060
2061     private void updateUndoModifiedState() {
2062         if (isZeroUndoCounter()) {
2063             setModified(false);
2064         }
2065         else
2066         {
2067             setModified(true);
2068         }
2069     }
2070
2071     public void setContextAction(SetContextAction action) {
2072         this.action = action;
2073     }
2074
2075    public SetContextAction getContextAction() {
2076         return action;
2077     }
2078
2079     public BasicBlock getChildById(String uid) {
2080         BasicBlock returnBlock = null;
2081         for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
2082             if (getModel().getChildAt(getDefaultParent(), i) instanceof BasicBlock) {
2083                 BasicBlock block = (BasicBlock)getModel().getChildAt(getDefaultParent(), i);
2084                 if (block.getId().compareTo(uid) == 0) { //find it
2085                     returnBlock = block;
2086                 } else {
2087                     if(block instanceof SuperBlock) {
2088                         boolean created = false;
2089                         if(((SuperBlock)block).getChild() == null) { 
2090                             //create temporary SuperBlock to find child
2091                             ((SuperBlock)block).createChildDiagram();
2092                             created = true;
2093                         }
2094
2095                         //search in child
2096                         returnBlock = ((SuperBlock)block).getChild().getChildById(uid);
2097
2098                         if(created) { //if temporary, destroy it
2099                             ((SuperBlock)block).getChild().closeDiagram();
2100                         }
2101                     } else if(block.getRealParameters() instanceof ScilabMList) { 
2102                         //we have a hidden SuperBlock, create a real one
2103                         SuperBlock newSP = (SuperBlock)BlockFactory.createBlock("SUPER_f");
2104                         newSP.setParentDiagram(block.getParentDiagram());
2105                         newSP.setRealParameters(block.getRealParameters());
2106                         newSP.createChildDiagram();
2107                         //search in child
2108                         returnBlock = newSP.getChild().getChildById(uid);
2109                         newSP.getChild().closeDiagram();
2110                         newSP = null;
2111                     }
2112                 }
2113             }
2114
2115             if(returnBlock != null) {
2116                 return returnBlock;
2117             }
2118         }
2119         return returnBlock;
2120     }
2121
2122     public boolean isChildVisible() {
2123         for (int i = 0; i < getModel().getChildCount(getDefaultParent()); i++) {
2124             Object child = getModel().getChildAt(getDefaultParent(), i);
2125             if (child instanceof SuperBlock) {
2126                 XcosDiagram diag = ((SuperBlock) child).getChild();
2127                 if (diag != null && diag.isOpened()) {
2128                     // if child or sub child is visible
2129                     if (diag.isChildVisible() || diag.isVisible()) {
2130                         return true;
2131                     }
2132                 }
2133             }
2134         }
2135         return false;
2136     }
2137
2138     public boolean canClose() {
2139         if (isChildVisible() == false) {
2140             return true;
2141         }
2142         return false;
2143     }
2144
2145     public void closeChildren() {
2146         for (int i = 0; i < getModel().getChildCount(getDefaultParent()); i++) {
2147             Object child = getModel().getChildAt(getDefaultParent(), i);
2148             if (child instanceof SuperBlock) {
2149                 SuperBlock diag = (SuperBlock) child;
2150
2151                 if (diag.getChild() != null && diag.getChild().isOpened()) {
2152                     diag.closeBlockSettings();
2153                 }
2154             }
2155         }
2156     }
2157     
2158     private StringBuffer checkMultiplicities(Object edge, Object source, Object target) {
2159         mxMultiplicity multi[] = getMultiplicities();
2160         StringBuffer error = new StringBuffer();
2161         for(mxMultiplicity current : multi) {
2162             if(current instanceof PortCheck) {
2163                 int sourceOut = mxGraphModel.getDirectedEdgeCount(getModel(), source, true);
2164                 int targetIn = mxGraphModel.getDirectedEdgeCount(getModel(), target, false);
2165                 
2166                 String str = ((PortCheck)current).checkDrawLink(this, edge, source, target, sourceOut, targetIn);
2167                 if(str != null) {
2168                     error.append(str);
2169                 }
2170             }
2171         }
2172         
2173         if(error.length() > 0) {
2174             return error;
2175         }
2176         return null;
2177     }
2178
2179     private boolean checkEdgeDirection(Object source, Object target) {
2180         
2181         if(source instanceof InputPort && target instanceof OutputPort) {
2182             Object temp = source;
2183             source = target;
2184             target = temp;
2185             return false;
2186         }
2187
2188         if(source instanceof ControlPort && target instanceof CommandPort) {
2189             Object temp = source;
2190             source = target;
2191             target = temp;
2192             return false;
2193         }
2194
2195         if((source instanceof InputPort || source instanceof ControlPort) &&  target instanceof BasicLink) {
2196             Object temp = source;
2197             source = target;
2198             target = temp;
2199             return false;
2200         }
2201         
2202         
2203         return true;
2204     }
2205     
2206     private void cancelDrawLinkAction() {
2207         waitPathAddEdge = false;
2208         waitPathRelease = false;
2209         drawLink = null;
2210         info(XcosMessages.EMPTY_INFO);
2211     }
2212     
2213 }
2214