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