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