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