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