2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
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
13 package org.scilab.modules.xcos.graph;
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;
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;
32 import javax.swing.JFileChooser;
33 import javax.swing.JOptionPane;
34 import javax.swing.SwingUtilities;
35 import javax.xml.parsers.DocumentBuilder;
36 import javax.xml.parsers.DocumentBuilderFactory;
37 import javax.xml.parsers.ParserConfigurationException;
39 import org.scilab.modules.graph.ScilabGraph;
40 import org.scilab.modules.graph.actions.PasteAction;
41 import org.scilab.modules.graph.actions.RedoAction;
42 import org.scilab.modules.graph.actions.SelectAllAction;
43 import org.scilab.modules.graph.actions.UndoAction;
44 import org.scilab.modules.graph.actions.ZoomInAction;
45 import org.scilab.modules.graph.actions.ZoomOutAction;
46 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
47 import org.scilab.modules.gui.bridge.filechooser.SwingScilabFileChooser;
48 import org.scilab.modules.gui.checkboxmenuitem.CheckBoxMenuItem;
49 import org.scilab.modules.gui.contextmenu.ContextMenu;
50 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
51 import org.scilab.modules.gui.filechooser.FileChooser;
52 import org.scilab.modules.gui.filechooser.ScilabFileChooser;
53 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
54 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
55 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
56 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
57 import org.scilab.modules.gui.tab.Tab;
58 import org.scilab.modules.gui.utils.SciFileFilter;
59 import org.scilab.modules.gui.utils.UIElementMapper;
60 import org.scilab.modules.gui.window.ScilabWindow;
61 import org.scilab.modules.hdf5.scilabTypes.ScilabMList;
62 import org.scilab.modules.xcos.Xcos;
63 import org.scilab.modules.xcos.XcosTab;
64 import org.scilab.modules.xcos.actions.DiagramBackgroundAction;
65 import org.scilab.modules.xcos.actions.SetContextAction;
66 import org.scilab.modules.xcos.actions.SetupAction;
67 import org.scilab.modules.xcos.actions.XcosDocumentationAction;
68 import org.scilab.modules.xcos.actions.XcosShortCut;
69 import org.scilab.modules.xcos.block.AfficheBlock;
70 import org.scilab.modules.xcos.block.BasicBlock;
71 import org.scilab.modules.xcos.block.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.actions.ShowParentAction;
76 import org.scilab.modules.xcos.io.BlockReader;
77 import org.scilab.modules.xcos.io.BlockWriter;
78 import org.scilab.modules.xcos.io.XcosCodec;
79 import org.scilab.modules.xcos.link.BasicLink;
80 import org.scilab.modules.xcos.link.commandcontrol.CommandControlLink;
81 import org.scilab.modules.xcos.link.explicit.ExplicitLink;
82 import org.scilab.modules.xcos.link.implicit.ImplicitLink;
83 import org.scilab.modules.xcos.port.BasicPort;
84 import org.scilab.modules.xcos.port.PortCheck;
85 import org.scilab.modules.xcos.port.command.CommandPort;
86 import org.scilab.modules.xcos.port.control.ControlPort;
87 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
88 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
89 import org.scilab.modules.xcos.port.input.InputPort;
90 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
91 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
92 import org.scilab.modules.xcos.port.output.OutputPort;
93 import org.scilab.modules.xcos.utils.BlockPositioning;
94 import org.scilab.modules.xcos.utils.ConfigXcosManager;
95 import org.scilab.modules.xcos.utils.XcosDialogs;
96 import org.scilab.modules.xcos.utils.XcosEvent;
97 import org.scilab.modules.xcos.utils.XcosFileType;
98 import org.scilab.modules.xcos.utils.XcosMessages;
99 import org.w3c.dom.Document;
100 import org.xml.sax.SAXException;
102 import com.mxgraph.io.mxCodec;
103 import com.mxgraph.model.mxCell;
104 import com.mxgraph.model.mxGeometry;
105 import com.mxgraph.model.mxGraphModel;
106 import com.mxgraph.model.mxICell;
107 import com.mxgraph.model.mxGraphModel.mxChildChange;
108 import com.mxgraph.model.mxGraphModel.mxStyleChange;
109 import com.mxgraph.util.mxEvent;
110 import com.mxgraph.util.mxEventObject;
111 import com.mxgraph.util.mxPoint;
112 import com.mxgraph.util.mxRectangle;
113 import com.mxgraph.util.mxUndoableEdit;
114 import com.mxgraph.util.mxUtils;
115 import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
116 import com.mxgraph.view.mxMultiplicity;
118 public class XcosDiagram extends ScilabGraph {
120 // Default values : SCI/modules/scicos/macros/scicos_scicos/scicos_params.sci
121 private double finalIntegrationTime = 100000;
122 private double integratorAbsoluteTolerance = 1e-4;
123 private double integratorRelativeTolerance = 1e-6;
124 private double toleranceOnTime = 1e-10;
125 private double maxIntegrationTimeinterval = finalIntegrationTime + 1;
126 private double realTimeScaling = 0;
127 private double solver = 0;
128 private double maximumStepSize = 0;
129 private int debugLevel = 0;
130 private String[] context = new String[]{""};
131 private String version = "scicos4.2";
132 //private Window palette;
133 private Tab viewPort;
135 /*to manage splitLink*/
136 private BasicLink splitLink = null;
137 private BasicPort splitPort = null;
138 private mxPoint dragSplitPos = null;
139 private boolean waitSplitRelease = false;
141 /*to manage path link*/
142 private BasicLink drawLink = null;
143 private boolean waitPathAddEdge = false;
144 private boolean waitPathRelease = false;
146 private CheckBoxMenuItem viewPortMenu;
147 private CheckBoxMenuItem gridMenu;
148 private SetContextAction action;
150 protected mxIEventListener undoEnabler = new mxIEventListener()
152 public void invoke(Object source, mxEventObject evt) {
153 if (getParentTab() != null) {
154 ((XcosTab)getParentTab()).setEnabledUndo(true);
159 public Object addEdge(Object edge, Object parent, Object source,
160 Object target, Integer index) {
162 // Command -> Control
163 if (source instanceof CommandPort) {
164 if (target instanceof ControlPort) {
165 return super.addEdge(new CommandControlLink(), parent, source, target, index);
169 // Control -> Command
170 // Switch source and target !
171 if (target instanceof CommandPort) {
172 if (source instanceof ControlPort) {
173 return super.addEdge(new CommandControlLink(), parent, target, source, index);
177 // ExplicitOutput -> ExplicitInput
178 if (source instanceof ExplicitOutputPort) {
179 if (target instanceof ExplicitInputPort) {
180 return super.addEdge(new ExplicitLink(), parent, source, target, index);
183 // ExplicitInput -> ExplicitOutput
184 // Switch source and target !
185 if (target instanceof ExplicitOutputPort) {
186 if (source instanceof ExplicitInputPort) {
187 return super.addEdge(new ExplicitLink(), parent, target, source, index);
191 // ImplicitOutput -> ImplicitInput
192 if (source instanceof ImplicitOutputPort) {
193 if (target instanceof ImplicitInputPort) {
194 return super.addEdge(new ImplicitLink(), parent, source, target, index);
197 // ImplicitInput -> ImplicitOutput
198 // Switch source and target !
199 if (target instanceof ImplicitOutputPort) {
200 if (source instanceof ImplicitInputPort) {
201 return super.addEdge(new ImplicitLink(), parent, target, source, index);
205 // ImplicitInput -> ImplicitInput
206 if (source instanceof ImplicitInputPort) {
207 if (target instanceof ImplicitInputPort) {
208 return super.addEdge(new ImplicitLink(), parent, source, target, index);
211 // ImplicitOutputPort -> ImplicitOutput
212 // Switch source and target !
213 if (target instanceof ImplicitOutputPort) {
214 if (source instanceof ImplicitOutputPort) {
215 return super.addEdge(new ImplicitLink(), parent, target, source, index);
219 // ExplicitLink -> ExplicitInputPort
220 if (source instanceof ExplicitLink) {
221 if (target instanceof ExplicitInputPort) {
222 return addSplitEdge((BasicLink) source, (BasicPort) target);
225 // ExplicitOutput -> ExpliciLink
226 // Switch source and target !
227 if (target instanceof ExplicitLink) {
228 if (source instanceof ExplicitInputPort) {
229 waitSplitRelease = true;
230 splitLink = (BasicLink) target;
231 splitPort = (BasicPort) source;
233 //return addSplitEdge((BasicLink) target, (BasicPort)source);
237 // ImplicitLink -> ImplicitInputPort
238 if (source instanceof ImplicitLink) {
239 if (target instanceof ImplicitInputPort) {
240 return addSplitEdge((BasicLink) source, (BasicPort) target);
243 // ImplicitInputPort -> ImplicitLink
244 // Switch source and target !
245 if (target instanceof ImplicitLink) {
246 if (source instanceof ImplicitInputPort) {
247 waitSplitRelease = true;
248 splitLink = (BasicLink) target;
249 splitPort = (BasicPort) source;
251 //return addSplitEdge((BasicLink) target, (BasicPort)source);
255 // ImplicitLink -> ImplicitOutputPort
256 if (source instanceof ImplicitLink) {
257 if (target instanceof ImplicitOutputPort) {
258 return addSplitEdge((BasicLink) source, (BasicPort) target);
261 // ImplicitOutputPort -> ImplicitLink
262 // Switch source and target !
263 if (target instanceof ImplicitLink) {
264 if (source instanceof ImplicitOutputPort) {
265 waitSplitRelease = true;
266 splitLink = (BasicLink) target;
267 splitPort = (BasicPort) source;
269 //return addSplitEdge((BasicLink) target, (BasicPort)source);
273 // CommandControlLink -> ControlPort
274 if (source instanceof CommandControlLink) {
275 if (target instanceof ControlPort) {
276 return addSplitEdge((BasicLink) source, (BasicPort) target);
279 // ControlPort -> CommandControlLink
280 // Switch source and target !
281 if (target instanceof CommandControlLink) {
282 if (source instanceof ControlPort) {
283 waitSplitRelease = true;
284 splitLink = (BasicLink) target;
285 splitPort = (BasicPort) source;
287 //return addSplitEdge((BasicLink) target, (BasicPort)source);
292 if(source != null && target == null) {
294 if(source instanceof ExplicitInputPort || source instanceof ExplicitOutputPort) {
295 drawLink = (BasicLink) super.addEdge(new ExplicitLink(), getDefaultParent(), source, target, index);
296 } else if(source instanceof ImplicitInputPort || source instanceof ImplicitOutputPort) {
297 drawLink = (BasicLink) super.addEdge(new ImplicitLink(), getDefaultParent(), source, target, index);
298 } else if(source instanceof ControlPort || source instanceof CommandPort) {
299 drawLink = (BasicLink) super.addEdge(new CommandControlLink(), getDefaultParent(), source, target, index);
300 } else if(source instanceof BasicLink) {
301 SplitBlock split = (SplitBlock) addSplitEdge((BasicLink)source, (BasicPort)target);
302 drawLink = (BasicLink) split.getOut2().getEdgeAt(0);
304 info(XcosMessages.DRAW_LINK);
305 if(drawLink != null) {
306 waitPathRelease = true;
313 private Object addSplitEdge(BasicLink link, mxICell target) {
314 BasicPort linkSource = (BasicPort) link.getSource();
315 BasicPort linkTarget = (BasicPort) link.getTarget();
317 getModel().beginUpdate();
318 if (dragSplitPos == null) {
319 dragSplitPos = new mxPoint();
321 //check splitPosition values
322 double srcX = linkSource.getParent().getGeometry().getX() + linkSource.getGeometry().getCenterX();
323 double tgtX = linkTarget.getParent().getGeometry().getX() + linkTarget.getGeometry().getCenterX();
324 double srcY = linkSource.getParent().getGeometry().getY() + linkSource.getGeometry().getCenterY();
325 double tgtY = linkTarget.getParent().getGeometry().getY() + linkTarget.getGeometry().getCenterY();
327 double offsetX = (tgtX - srcX) / 2;
328 double offsetY = (tgtY - srcY) / 2;
329 dragSplitPos.setX(srcX + offsetX);
330 dragSplitPos.setY(srcY + offsetY);
333 SplitBlock splitBlock = null;
335 if (target instanceof BasicLink) {
336 splitBlock = new SplitBlock("SPLIT_f", linkSource, linkTarget, (BasicPort) ((BasicLink)target).getSource());
338 splitBlock = new SplitBlock("SPLIT_f", linkSource, linkTarget, (BasicPort) target);
341 splitBlock.setStyle("SPLIT_f");
342 mxGeometry geom = new mxGeometry();
343 geom.setX(dragSplitPos.getX() - 3); //-3 for splitBlock size
344 geom.setY(dragSplitPos.getY() - 3); //-3 for splitBlock size
345 splitBlock.setGeometry(geom);
351 //get breaking segment
352 int pos = link.findNearestSegment(dragSplitPos);
354 //save points after breaking point
355 mxPoint[] saveStartPoints = link.getPoints(pos, true);
356 mxPoint[] saveEndPoints = link.getPoints(pos, false);
360 getModel().beginUpdate();
361 getModel().remove(link);
362 getModel().endUpdate();
364 BasicLink newLink1 = BasicLink.createLinkFromPorts(linkSource, splitBlock.getIn());
365 newLink1.setGeometry(new mxGeometry(0,0,80,80));
366 newLink1.setSource(linkSource);
367 newLink1.setTarget(splitBlock.getIn());
369 //add points after breaking point in the new link
370 if (saveStartPoints != null) {
371 for (int i = 0; i < saveStartPoints.length; i++) {
372 newLink1.addPoint(saveStartPoints[i].getX(), saveStartPoints[i].getY());
377 BasicLink newLink2 = BasicLink.createLinkFromPorts(splitBlock.getOut1(), linkTarget);
378 newLink2.setGeometry(new mxGeometry(0,0,80,80));
379 newLink2.setSource(splitBlock.getOut1());
380 newLink2.setTarget(linkTarget);
381 //add points after breaking point in the new link
382 if (saveEndPoints != null) {
383 for (int i = 0; i < saveEndPoints.length; i++) {
384 newLink2.addPoint(saveEndPoints[i].getX(), saveEndPoints[i].getY());
389 if(target instanceof BasicLink) {
390 //build link inverted ! it will be invert later
391 ((BasicLink)target).setTarget(splitBlock.getOut2());
394 BasicLink newLink3 = BasicLink.createLinkFromPorts(splitBlock.getOut2(), (BasicPort) target);
395 newLink3.setGeometry(new mxGeometry(0,0,80,80));
396 newLink3.setSource(splitBlock.getOut2());
397 newLink3.setTarget((mxCell) target);
403 getModel().endUpdate();
408 public XcosDiagram() {
410 getModel().addListener(mxEvent.UNDO, undoEnabler);
411 getView().addListener(mxEvent.UNDO, undoEnabler);
412 keyboardHandler = new XcosShortCut(this);
413 mxCodec codec = new mxCodec();
416 File uri = new File(System.getenv("SCI"));
417 String xml = mxUtils.readFile(System.getenv("SCI")+ "/modules/xcos/etc/Xcos-style.xml");
418 xml = xml.replaceAll("\\$SCILAB", uri.toURI().toURL().toString());
419 Document document = mxUtils.parse(xml);
420 codec.decode(document.getDocumentElement(), getStylesheet());
421 } catch (IOException e) {
425 getAsComponent().setToolTips(true);
427 // Forbid disconnecting cells once it is connected.
428 setCellsDisconnectable(false);
430 // Forbid pending edges.
431 //setAllowDanglingEdges(false);
432 setAllowDanglingEdges(true);
434 // Cannot connect port to itself.
435 setAllowLoops(false);
437 // Override isCellResizable to filter what the user can resize
438 setCellsResizable(true);
440 // force auto resize cell
441 setAutoSizeCells(true);
443 /* Labels use HTML if not equal to interface function name */
447 //setCloneInvalidEdges(false);
448 setCloneInvalidEdges(true);
450 // Override isCellEditable to filter what the user can edit
451 setCellsEditable(true);
452 // This enable stop editing cells when pressing Enter.
453 getAsComponent().setEnterStopsCellEditing(false);
455 setConnectableEdges(true);
456 getAsComponent().setTolerance(1);
458 getAsComponent().getViewport().setOpaque(false);
459 getAsComponent().setBackground(Color.WHITE);
463 // Add a listener to track when model is changed
464 getModel().addListener(XcosEvent.CHANGE, new ModelTracker());
466 setGridVisible(true);
468 ((mxCell) getDefaultParent()).setId((new UID()).toString());
469 ((mxCell) getModel().getRoot()).setId((new UID()).toString());
473 * Install the multiplicities (use for link checking)
475 private void setMultiplicities() {
476 mxMultiplicity[] multiplicities = new mxMultiplicity[10];
480 multiplicities[0] = new PortCheck(ExplicitInputPort.class, Collections
481 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
482 private static final long serialVersionUID = -4987163442006736665L;
484 add(ExplicitOutputPort.class);
485 add(ExplicitLink.class);
487 }), XcosMessages.LINK_ERROR_EXPLICIT_IN);
488 multiplicities[1] = new PortCheck(ImplicitInputPort.class, Collections
489 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
490 private static final long serialVersionUID = 886376532181210926L;
492 add(ImplicitOutputPort.class);
493 add(ImplicitInputPort.class);
494 add(ImplicitLink.class);
496 }), XcosMessages.LINK_ERROR_IMPLICIT_IN);
499 multiplicities[2] = new PortCheck(ExplicitOutputPort.class, Collections
500 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
501 private static final long serialVersionUID = 4594127972486054821L;
503 add(ExplicitInputPort.class);
505 }), XcosMessages.LINK_ERROR_EXPLICIT_OUT);
506 multiplicities[3] = new PortCheck(ImplicitOutputPort.class, Collections
507 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
508 private static final long serialVersionUID = -3719677806532507973L;
510 add(ImplicitInputPort.class);
511 add(ImplicitOutputPort.class);
512 add(ImplicitLink.class);
514 }), XcosMessages.LINK_ERROR_IMPLICIT_OUT);
517 multiplicities[4] = new PortCheck(ControlPort.class, Collections
518 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
519 private static final long serialVersionUID = 2941077191386058497L;
521 add(CommandPort.class);
522 add(CommandControlLink.class);
524 }), XcosMessages.LINK_ERROR_EVENT_IN);
527 multiplicities[5] = new PortCheck(CommandPort.class, Collections
528 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
529 private static final long serialVersionUID = -3470370027962480362L;
531 add(ControlPort.class);
533 }), XcosMessages.LINK_ERROR_EVENT_OUT);
535 // ExplicitLink connections
536 multiplicities[6] = new PortCheck(ExplicitLink.class, Collections
537 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
538 private static final long serialVersionUID = 7423543162930147373L;
541 add(ExplicitInputPort.class);
543 }), XcosMessages.LINK_ERROR_EVENT_OUT);
545 // ImplicitLink connections
546 multiplicities[7] = new PortCheck(ImplicitLink.class, Collections
547 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
548 private static final long serialVersionUID = 7775100011122283282L;
551 add(ImplicitInputPort.class);
552 add(ImplicitOutputPort.class);
554 }), XcosMessages.LINK_ERROR_EVENT_OUT);
556 // CommandControlLink connections
557 multiplicities[8] = new PortCheck(CommandControlLink.class, Collections
558 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
559 private static final long serialVersionUID = 3260421433507192386L;
562 add(ControlPort.class);
564 }), XcosMessages.LINK_ERROR_EVENT_OUT);
566 // Already connected port
567 multiplicities[9] = new PortCheck(BasicPort.class, Collections
568 .unmodifiableList(new ArrayList<Class<? extends mxCell>>() {
569 private static final long serialVersionUID = 6376349598052836660L;
572 add(BasicPort.class);
574 }), XcosMessages.LINK_ERROR_ALREADY_CONNECTED);
576 setMultiplicities(multiplicities);
580 * Install all needed Listeners.
582 public void installListeners() {
584 // Property change Listener
585 // Will say if a diagram has been modified or not.
586 getAsComponent().addPropertyChangeListener(new PropertyChangeListener() {
587 public void propertyChange(PropertyChangeEvent e) {
588 if (e.getPropertyName().compareTo("modified") == 0) {
589 if ((Boolean) e.getOldValue() != (Boolean) e.getNewValue()) {
596 // Track when superblock ask a parent refresh.
597 addListener(XcosEvent.SUPER_BLOCK_UPDATED, new SuperBlockUpdateTracker());
599 // Track when cells are added.
600 addListener(XcosEvent.CELLS_ADDED, new CellAddedTracker(this));
602 // Track when cells are deleted.
603 addListener(XcosEvent.CELLS_REMOVED, new CellRemovedTracker(this));
605 // Track when resizing a cell.
606 addListener(XcosEvent.CELLS_RESIZED, new CellResizedTracker());
608 // Track when we have to force a Block to reshape
609 addListener(XcosEvent.FORCE_CELL_RESHAPE, new ForceCellReshapeTracker());
611 // Track when we have to force a Block value
612 addListener(XcosEvent.FORCE_CELL_VALUE_UPDATE, new ForceCellValueUpdate());
614 // Update the blocks view on undo/redo
615 undoManager.addListener(mxEvent.UNDO, new UndoUpdateTracker());
616 undoManager.addListener(mxEvent.REDO, new UndoUpdateTracker());
618 getAsComponent().getGraphControl().addMouseListener(new XcosMouseListener(this));
620 getAsComponent().addKeyListener(new XcosKeyListener(this));
622 addListener(XcosEvent.ADD_PORTS, new mxIEventListener() {
623 public void invoke(Object source, mxEventObject evt) {
624 getModel().beginUpdate();
626 BasicBlock updatedBlock = (BasicBlock) evt.getArgAt(0);
627 BlockPositioning.updateBlockView(updatedBlock);
628 getModel().endUpdate();
636 * Called when mxEvents.CHANGE occurs on a model
638 private class ModelTracker implements mxIEventListener {
639 public void invoke(Object source, mxEventObject evt) {
640 List<mxUndoableChange> changes = (List<mxUndoableChange>) evt.getArgAt(0);
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) {
649 if (((mxChildChange) changes.get(i)).getChild() instanceof BasicBlock) {
650 BasicBlock currentCell = (BasicBlock) ((mxChildChange) changes.get(i)).getChild();
651 objects.add(currentCell);
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);
660 //fireEvent(XcosEvent.FORCE_CELL_RESHAPE, new mxEventObject(new Object[] {firedCells}));
661 fireEvent(XcosEvent.FORCE_CELL_VALUE_UPDATE, new mxEventObject(new Object[] {firedCells}));
663 getModel().endUpdate();
667 * ForceCellValueUpdate
668 * Called when we want a block content to update.
670 private class ForceCellValueUpdate implements mxIEventListener {
671 public void invoke(Object source, mxEventObject evt) {
672 Object[] cells = (Object[]) evt.getArgs()[0];
674 getModel().beginUpdate();
676 for (int i = 0; i < cells.length; ++i) {
678 Object cell = cells[i];
680 if (cell instanceof BasicBlock) {
681 if (getCellStyle(cell).get("displayedLabel") != null) {
682 ((mxCell) cell).setValue("<html><body> " + getCellStyle(cell).get("displayedLabel") + " </body></html>");
685 mxRectangle preferedSize = getPreferredSizeForCell(cell);
686 mxGeometry cellSize = ((mxCell) cell).getGeometry();
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()});
694 getModel().endUpdate();
700 * ForceCellReshapeTracker
701 * Called when we want a Block to reshape for it's ports positions.
703 private class ForceCellReshapeTracker implements mxIEventListener {
704 public void invoke(Object source, mxEventObject evt) {
705 Object[] cells = (Object[]) evt.getArgs()[0];
706 getModel().beginUpdate();
707 for (int i = 0; i < cells.length; ++i) {
708 Object cell = cells[i];
709 if (cell instanceof BasicBlock) {
710 BlockPositioning.updateBlockView((BasicBlock) cell);
713 getModel().endUpdate();
718 * SuperBlockUpdateTracker
719 * Called when adding some port in a SuperBlock diagram
720 * to update current sub-diagram (i.e SuperBlock) representation.
722 private class SuperBlockUpdateTracker implements mxIEventListener {
723 public void invoke(Object source, mxEventObject evt) {
724 assert evt.getArgs()[0] instanceof SuperBlock;
725 SuperBlock updatedBlock = (SuperBlock) evt.getArgs()[0];
726 updatedBlock.setRealParameters(BlockWriter
727 .convertDiagramToMList(updatedBlock.getChild()));
728 if (updatedBlock.getParentDiagram() instanceof SuperBlockDiagram) {
729 SuperBlock parentBlock = ((SuperBlockDiagram) updatedBlock
730 .getParentDiagram()).getContainer();
731 parentBlock.getParentDiagram().fireEvent(
732 XcosEvent.SUPER_BLOCK_UPDATED,
733 new mxEventObject(new Object[] { parentBlock }));
735 BlockPositioning.updateBlockView(updatedBlock);
742 * Called when mxEvents.CELLS_ADDED is fired.
744 private class CellAddedTracker implements mxIEventListener {
745 private XcosDiagram diagram = null;
747 public CellAddedTracker(XcosDiagram diagram) {
748 this.diagram = diagram;
751 public void invoke(Object source, mxEventObject evt) {
752 Object[] cells = (Object[]) evt.getArgs()[0];
754 diagram.getModel().beginUpdate();
755 for (int i = 0; i < cells.length; ++i) {
757 // ((mxCell) cells[i]).setId((new UID()).toString());
759 if (cells[i] instanceof BasicBlock) {
760 // Store all AfficheBlocks in a dedicated HasMap
761 if (cells[i] instanceof AfficheBlock) {
762 AfficheBlock affich = (AfficheBlock) cells[i];
763 XcosTab.getAfficheBlocks().put(affich.getHashCode(), affich);
765 // Update parent on cell addition
766 ((BasicBlock) cells[i]).setParentDiagram(diagram);
769 //fireEvent(XcosEvent.FORCE_CELL_VALUE_UPDATE, new mxEventObject(new Object[] {cells}));
770 diagram.getModel().endUpdate();
776 * Called when mxEvents.CELLS_REMOVED is fired.
778 private class CellRemovedTracker implements mxIEventListener {
779 public CellRemovedTracker(XcosDiagram diagram) {
782 public void invoke(Object source, mxEventObject evt) {
783 Object[] cells = (Object[]) evt.getArgs()[0];
784 for (int i = 0; i < cells.length; i++) {
785 if (cells[i] instanceof BasicLink) {
786 BasicLink link = (BasicLink) cells[i];
788 if(waitPathAddEdge) {
789 cancelDrawLinkAction();
797 private void removeLink(BasicLink link) {
798 if(!(link.getSource() instanceof BasicPort)) {
802 if(!(link.getTarget() instanceof BasicPort)) {
806 BasicPort portSource = (BasicPort) link.getSource();
807 BasicPort portTarget = (BasicPort) link.getTarget();
809 SplitBlock split = null;
810 BasicPort saveSource = null;
811 BasicPort saveTarget = null;
813 if (portSource == null) { return; }
814 if (portTarget == null) { return; }
817 if (portTarget.getParent() instanceof SplitBlock) {
818 split = (SplitBlock) portTarget.getParent();
820 Object[] outLinks = getAllEdges(new Object[] {split.getOut1(), split.getOut2()});
821 for (int i = 0; i < outLinks.length; i++) {
822 BasicLink outLink = (BasicLink) outLinks[i];
823 if (outLink.getTarget().getParent() instanceof SplitBlock) {
824 removeCells(new Object[]{outLink});
829 //Finally delete split and old associated links
831 removeCells(new Object[]{split});
839 if (portSource.getParent() instanceof SplitBlock) {
840 split = (SplitBlock) portSource.getParent();
842 //remove out1, so link between in.source and out2.target
843 if (split.getOut1() == portSource) {
844 //save source and target ports
845 saveSource = getOppositePort(split.getIn());
846 saveTarget = getOppositePort(split.getOut2());
847 } else if (split.getOut2() == portSource) {
848 //save source and target ports
849 saveSource = getOppositePort(split.getIn());
850 saveTarget = getOppositePort(split.getOut1());
854 if (saveSource != null && saveTarget != null) {
856 BasicLink newLink = BasicLink.createLinkFromPorts(saveSource, saveTarget);
857 newLink.setGeometry(new mxGeometry(0,0,80,80));
859 Object[] saveLinks = getAllEdges(new Object[]{saveSource, saveTarget});
860 for (int k = 0; k < saveLinks.length; k++) {
861 mxPoint[] savePts = ((BasicLink) saveLinks[k]).getPoints(0, false);
862 if (savePts != null) {
863 for (int j = 0; j < savePts.length; j++) {
864 newLink.addPoint(savePts[j].getX(), savePts[j].getY());
869 newLink.setSource(saveSource);
870 newLink.setTarget(saveTarget);
873 //unlink split and delete unlinked links
877 split.unlinkAndClean();
878 removeCells(new Object[]{split});
882 private BasicPort getOppositePort(BasicPort source) {
883 Object[] objs = getAllEdges(new Object[]{source});
884 if (objs.length == 0 || objs.length > 1) {
888 BasicLink link = (BasicLink) objs[0];
889 if (link.getSource() == source) {
890 return (BasicPort) link.getTarget();
892 return (BasicPort) link.getSource();
897 * Called when mxEvents.CELLS_RESIZED is fired.
899 private class CellResizedTracker implements mxIEventListener {
900 public void invoke(Object source, mxEventObject evt) {
901 Object[] cells = (Object[]) evt.getArgs()[0];
902 getModel().beginUpdate();
903 for (int i = 0; i < cells.length; ++i) {
904 if (cells[i] instanceof BasicBlock) {
905 BlockPositioning.updateBlockView((BasicBlock) cells[i]);
908 getModel().endUpdate();
913 * Update the modified block on undo/redo
915 private class UndoUpdateTracker implements mxIEventListener {
916 public void invoke(Object source, mxEventObject evt) {
917 List<mxUndoableChange> changes = ((mxUndoableEdit) evt.getArgAt(0)).getChanges();
918 Object[] changedCells = getSelectionCellsForChanges(changes);
919 getModel().beginUpdate();
920 for (Object object : changedCells) {
921 if (object instanceof BasicBlock) {
922 BasicBlock current = (BasicBlock) object;
924 // When we change the style property we have to update some
926 if (changes.get(0) instanceof mxStyleChange) {
927 current.updateFieldsFromStyle();
930 // Update the block position
931 BlockPositioning.updateBlockView(current);
934 getModel().endUpdate();
939 private class XcosKeyListener implements KeyListener{
941 public XcosKeyListener(XcosDiagram diagram) {}
943 public void keyTyped(KeyEvent e) {}
945 public void keyPressed(KeyEvent e) {}
947 public void keyReleased(KeyEvent e) {
948 if(e.getKeyChar() == KeyEvent.VK_ESCAPE) {
949 if(drawLink != null) {
950 getModel().remove(drawLink);
951 cancelDrawLinkAction();
957 * MouseListener inner class
959 private class XcosMouseListener implements MouseListener {
960 private XcosDiagram diagram = null;
962 public XcosMouseListener(XcosDiagram diagram) {
963 this.diagram = diagram;
966 public void mouseClicked(MouseEvent e) {
967 Object cell = getAsComponent().getCellAt(e.getX(), e.getY());
969 // Double Click within empty diagram Area
970 if (e.getClickCount() >= 2 && SwingUtilities.isLeftMouseButton(e) && cell == null) {
971 TextBlock textBlock = new TextBlock("Edit me !!!");
972 textBlock.getGeometry().setX(e.getX() - textBlock.getGeometry().getWidth() / 2.0);
973 textBlock.getGeometry().setY(e.getY() - textBlock.getGeometry().getWidth() / 2.0);
978 // Double Click within some component
979 if (e.getClickCount() >= 2 && SwingUtilities.isLeftMouseButton(e) && cell != null)
981 getModel().beginUpdate();
982 if (cell instanceof BasicBlock) {
983 BasicBlock block = (BasicBlock) cell;
985 block.openBlockSettings(buildEntireContext());
987 if (cell instanceof BasicLink) {
988 ((BasicLink) cell).insertPoint(e.getX(), e.getY());
990 getModel().endUpdate();
994 // Ctrl + Shift + Right Middle Click : for debug !!
995 if (e.getClickCount() >= 2 && SwingUtilities.isMiddleMouseButton(e)
996 && e.isShiftDown() && e.isControlDown())
998 System.err.println("[DEBUG] Click at position : " + e.getX() + " , " + e.getY());
1000 System.err.println("[DEBUG] Click on diagram");
1001 System.err.println("Default Parent ID : " + ((mxCell) getDefaultParent()).getId());
1002 System.err.println("Model root ID : " + ((mxCell) getModel().getRoot()).getId());
1003 System.err.println("getParentWindow : " + (getParentTab() == null ? null : getParentTab().getParentWindow()));
1005 System.err.println("[DEBUG] Click on : " + cell);
1006 System.err.println("[DEBUG] Style : " + ((mxCell) cell).getStyle());
1007 System.err.println("[DEBUG] NbEdges : " + ((mxCell) cell).getEdgeCount());
1008 System.err.println("[DEBUG] NbChildren : " + ((mxCell) cell).getChildCount());
1009 for (int i = 0; i < ((mxCell) cell).getChildCount(); i++) {
1010 System.err.println("[DEBUG] Child NbEdges : " + ((mxCell) cell).getChildAt(i).getEdgeCount());
1013 if(cell instanceof BasicLink) {
1014 System.err.println("[DEBUG] Link Points : " + ((BasicLink) cell).getPointCount());
1021 if ((e.getClickCount() == 1 && SwingUtilities.isRightMouseButton(e))
1022 || e.isPopupTrigger()
1023 || XcosMessages.isMacOsPopupTrigger(e)) {
1026 // Display diagram context menu
1027 ContextMenu menu = ScilabContextMenu.createContextMenu();
1029 menu.add(UndoAction.undoMenu((ScilabGraph) getAsComponent().getGraph()));
1030 menu.add(RedoAction.redoMenu((ScilabGraph) getAsComponent().getGraph()));
1031 menu.add(PasteAction.pasteMenu((ScilabGraph) getAsComponent().getGraph()));
1032 menu.add(SelectAllAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1034 menu.getAsSimpleContextMenu().addSeparator();
1036 menu.add(SetContextAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1037 menu.add(SetupAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1039 if(diagram instanceof SuperBlockDiagram) {
1041 menu.getAsSimpleContextMenu().addSeparator();
1043 menu.add(ShowParentAction.createMenu(diagram));
1046 menu.getAsSimpleContextMenu().addSeparator();
1048 menu.add(ZoomInAction.zoominMenu((ScilabGraph) getAsComponent().getGraph()));
1049 menu.add(ZoomOutAction.zoomoutMenu((ScilabGraph) getAsComponent().getGraph()));
1051 menu.getAsSimpleContextMenu().addSeparator();
1053 menu.add(DiagramBackgroundAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1055 menu.getAsSimpleContextMenu().addSeparator();
1057 menu.add(XcosDocumentationAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1059 ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y);
1061 menu.setVisible(true);
1064 // Display object context menu
1065 if (cell instanceof BasicBlock) {
1066 BasicBlock block = (BasicBlock) cell;
1067 block.openContextMenu((ScilabGraph) getAsComponent().getGraph());
1069 if (cell instanceof BasicLink) {
1070 BasicLink link = (BasicLink) cell;
1071 link.openContextMenu((ScilabGraph) getAsComponent().getGraph());
1077 public void mouseEntered(MouseEvent e) {
1080 public void mouseExited(MouseEvent e) {
1083 public void mousePressed(MouseEvent e) {
1086 public void mouseReleased(MouseEvent e) {
1087 Object cell = getAsComponent().getCellAt(e.getX(), e.getY());
1089 if(e.getClickCount() == 1 && SwingUtilities.isLeftMouseButton(e)) {
1090 if (waitSplitRelease) {
1091 dragSplitPos = new mxPoint(e.getX(), e.getY());
1092 waitSplitRelease = false;
1093 addSplitEdge(splitLink, splitPort);
1094 } else if(waitPathRelease){
1095 //Tips for ignore first mouse release after drag
1096 waitPathRelease = false;
1097 waitPathAddEdge = true;
1099 if(!e.isControlDown()) {
1100 //adjust final point
1101 mxGeometry geoPort = drawLink.getSource().getGeometry();
1102 mxGeometry geoBlock = drawLink.getSource().getParent().getGeometry();
1103 mxPoint lastPoint = new mxPoint(geoBlock.getX() + geoPort.getCenterX(), geoBlock.getY() + geoPort.getCenterY());
1104 mxPoint point = getPointPosition(lastPoint, new mxPoint(e.getX(), e.getY()));
1106 getModel().beginUpdate();
1107 drawLink.getGeometry().setTargetPoint(point);
1108 getModel().endUpdate();
1111 } else if(waitPathAddEdge){
1112 if(drawLink != null) {
1113 getModel().beginUpdate();
1114 //move end of link and add point at old position
1115 mxGeometry geo = drawLink.getGeometry();
1116 drawLink.addPoint(geo.getTargetPoint().getX(), geo.getTargetPoint().getY());
1117 setSelectionCell(drawLink);
1120 mxICell source = drawLink.getSource();
1122 StringBuffer error = checkMultiplicities(drawLink, source, cell);
1124 if(cell instanceof BasicLink && cell != drawLink) { //no loop
1125 //draw link with a SplitBlock
1126 dragSplitPos = new mxPoint(e.getX(), e.getY());
1127 addSplitEdge((BasicLink)cell, drawLink);
1129 getModel().setTerminal(drawLink, cell, false);
1132 //invert source and target if needed
1133 if(checkEdgeDirection(source, cell) == false) {
1134 getModel().beginUpdate();
1135 drawLink.invertDirection();
1136 getModel().endUpdate();
1139 //reset info, flags and object
1140 cancelDrawLinkAction();
1142 if(cell != drawLink) {
1143 JOptionPane.showMessageDialog(getAsComponent(), error);
1145 setSelectionCell(drawLink);
1148 if(!e.isControlDown()) {
1149 geo.setTargetPoint(getPointPosition(geo.getTargetPoint(), new mxPoint(e.getX(), e.getY())));
1151 geo.setTargetPoint(new mxPoint(e.getX(), e.getY()));
1154 getModel().endUpdate();
1157 cancelDrawLinkAction();
1160 dragSplitPos = null;
1166 static mxPoint getPointPosition(mxPoint origin, mxPoint click) {
1167 boolean signX = click.getX() > origin.getX();
1168 boolean signY = click.getY() > origin.getY();
1169 double diffX = Math.abs(click.getX() - origin.getX());
1170 double diffY = Math.abs(click.getY() - origin.getY());
1173 if(diffY > (diffX / 2)) { //diagonal
1175 } else { //orthogonal
1179 if(diffX > (diffY / 2)) { //diagonal
1181 } else { //orthogonal
1187 if(signX == false) {
1191 if(signY == false) {
1195 return new mxPoint(origin.getX() + diffX, origin.getY() + diffY);
1198 * Manage Group to be CellFoldable i.e with a (-) to reduce
1199 * and a (+) to expand them.
1200 * Only non-Block / non-Port Cell are foldable.
1203 * @see com.mxgraph.view.mxGraph#isCellFoldable(java.lang.Object, boolean)
1205 public boolean isCellFoldable(Object cell, boolean collapse) {
1206 return !(cell instanceof BasicBlock) && super.isCellFoldable(cell, collapse);
1209 public boolean isCellClonable(Object cell) {
1213 public boolean isCellSelectable(Object cell) {
1214 if(cell instanceof BasicPort) {
1217 return super.isCellSelectable(cell);
1220 public boolean isCellMovable(Object cell) {
1221 if (cell instanceof BasicPort) {
1225 boolean movable = false;
1226 Object[] cells = this.getSelectionCells();
1228 //don't move if selection is only links
1229 for (int i = 0; i < cells.length; i++) {
1230 if (!(cells[i] instanceof BasicLink)) {
1236 return movable && super.isCellMovable(cell);
1239 public boolean isCellResizable(Object cell) {
1240 if (cell instanceof SplitBlock) {
1243 return (cell instanceof BasicBlock) && super.isCellResizable(cell);
1246 public boolean isCellDeletable(Object cell) {
1247 if (cell instanceof BasicBlock && ((BasicBlock) cell).isLocked()) {
1251 return !(cell instanceof BasicPort) && super.isCellDeletable(cell);
1254 public boolean isCellEditable(Object cell) {
1255 return (cell instanceof TextBlock) && super.isCellDeletable(cell);
1258 public boolean isCellDisconnectable(Object cell, Object terminal,boolean source) {
1259 return super.isCellDisconnectable(cell, terminal, source);
1262 public boolean isCellConnectable(Object cell)
1264 //currently in draw link action
1265 if(waitPathAddEdge) {
1266 if(drawLink != null) {
1267 StringBuffer error = checkMultiplicities(drawLink, drawLink.getSource(), cell);
1275 if(cell instanceof BasicBlock) {
1279 if(cell instanceof BasicPort) {
1280 int sourceOut = mxGraphModel.getDirectedEdgeCount(getModel(), cell, true);
1281 int targetIn = mxGraphModel.getDirectedEdgeCount(getModel(), cell, false);
1283 if(sourceOut > 0 || targetIn > 0) {
1287 return !(cell instanceof BasicBlock) && super.isCellConnectable(cell);
1290 public boolean isAutoSizeCell(Object cell) {
1291 return (cell instanceof AfficheBlock) || super.isAutoSizeCell(cell);
1295 public void dumpToHdf5File(String fileName) {
1296 if (fileName == null) {
1297 FileChooser fc = ScilabFileChooser.createFileChooser();
1298 fc.setInitialDirectory(getSavedFile());
1299 fc.setMultipleSelection(false);
1300 fc.displayAndWait();
1302 if (fc.getSelection() == null || fc.getSelection().length == 0 || fc.getSelection()[0].equals("")) {
1305 fileName = fc.getSelection()[0];
1306 System.out.println("Saving to file : {" + fileName + "}");
1309 BlockWriter.writeDiagramToFile(fileName, this);
1312 public double getFinalIntegrationTime() {
1313 return finalIntegrationTime;
1316 public void setFinalIntegrationTime(double finalIntegrationTime) {
1317 this.finalIntegrationTime = finalIntegrationTime;
1320 public double getIntegratorAbsoluteTolerance() {
1321 return integratorAbsoluteTolerance;
1324 public void setIntegratorAbsoluteTolerance(double integratorAbsoluteTolerance) {
1325 this.integratorAbsoluteTolerance = integratorAbsoluteTolerance;
1328 public double getIntegratorRelativeTolerance() {
1329 return integratorRelativeTolerance;
1332 public void setIntegratorRelativeTolerance(double integratorRelativeTolerance) {
1333 this.integratorRelativeTolerance = integratorRelativeTolerance;
1336 public double getMaximumStepSize() {
1337 return maximumStepSize;
1340 public void setMaximumStepSize(double maximumStepSize) {
1341 this.maximumStepSize = maximumStepSize;
1344 public double getMaxIntegrationTimeinterval() {
1345 return maxIntegrationTimeinterval;
1348 public void setMaxIntegrationTimeinterval(double maxIntegrationTimeinterval) {
1349 this.maxIntegrationTimeinterval = maxIntegrationTimeinterval;
1352 public double getRealTimeScaling() {
1353 return realTimeScaling;
1356 public void setRealTimeScaling(double realTimeScaling) {
1357 this.realTimeScaling = realTimeScaling;
1360 public double getSolver() {
1364 public void setSolver(double solver) {
1365 this.solver = solver;
1368 public double getToleranceOnTime() {
1369 return toleranceOnTime;
1372 public void setToleranceOnTime(double toleranceOnTime) {
1373 this.toleranceOnTime = toleranceOnTime;
1377 * Set the associated ViewPort
1378 * @param viewPort the Viewport
1380 public void setViewPort(Tab viewPort) {
1381 this.viewPort = viewPort;
1385 * Get the associated ViewPort
1386 * @return the Viewport
1388 public Tab getViewPort() {
1393 * Manage the visibility of the associated viewport
1394 * @param status new status
1396 public void setViewPortVisible(boolean status) {
1397 // Hide/Show parent window if the viewport is the only tab
1398 if (viewPort.getParentWindow().getNbDockedObjects() == 1) {
1399 viewPort.getParentWindow().setVisible(status);
1401 // Hide/Show viewport tab
1402 viewPort.setVisible(status);
1404 // (Un)Check the corresponding menu
1405 viewPortMenu.setChecked(status);
1409 * Set menu used to manage Viewport visibility
1410 * @param menu the menu
1412 public void setViewPortMenuItem(CheckBoxMenuItem menu) {
1413 this.viewPortMenu = menu;
1416 * Manage the visibility of the grid and the associated menu
1417 * @param status new status
1419 public void setGridVisible(boolean status) {
1420 setGridEnabled(status);
1421 getAsComponent().setGridVisible(status);
1422 getAsComponent().repaint();
1424 // (Un)Check the corresponding menu
1425 if(gridMenu != null) {
1426 gridMenu.setChecked(status);
1431 * Set menu used to manage Grid visibility
1432 * @param menu the menu
1434 public void setGridMenuItem(CheckBoxMenuItem menu) {
1435 this.gridMenu = menu;
1439 * Close Xcos instance including all tabs
1441 public void closeDiagram() {
1442 closeDiagram(false);
1446 * Close Xcos instance including all tabs
1448 public void closeDiagram(boolean fromScilab) {
1450 boolean wantToClose = true;
1452 if(canClose() == false) {
1458 // The diagram has been modified
1459 // Ask the user want he want to do !
1461 AnswerOption answer;
1462 if(fromScilab == true) {
1463 answer = ScilabModalDialog.show(getParentTab(), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS,
1464 IconType.QUESTION_ICON, ButtonType.YES_NO);
1466 answer = ScilabModalDialog.show(getParentTab(), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS,
1467 IconType.QUESTION_ICON, ButtonType.YES_NO_CANCEL);
1473 if (!saveDiagram()) {
1474 //if save is canceled, cancel close windows
1475 wantToClose = false;
1480 case CANCEL_OPTION :
1482 wantToClose = false;
1488 if(getParentTab() != null) {
1489 ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper.getCorrespondingUIElement(getParentTab().getParentWindowId());
1490 xcosWindow.removeTab(getParentTab());
1493 XcosTab.closeDiagram(this);
1498 public boolean saveDiagram() {
1499 boolean isSuccess = false;
1500 if (getSavedFile() == null) {
1501 isSuccess = saveDiagramAs(null);
1503 isSuccess = saveDiagramAs(getSavedFile());
1513 public boolean saveDiagramAs(String fileName) {
1515 boolean isSuccess = false;
1516 info(XcosMessages.SAVING_DIAGRAM);
1517 this.getParentTab().getInfoBar().draw();
1518 if (fileName == null) {
1519 // Choose a filename
1520 SwingScilabFileChooser fc = ((SwingScilabFileChooser) ScilabFileChooser.createFileChooser().getAsSimpleFileChooser());
1521 fc.setTitle(XcosMessages.SAVE_AS);
1522 fc.setUiDialogType(JFileChooser.SAVE_DIALOG);
1523 fc.setMultipleSelection(false);
1524 if (this.getSavedFile() != null) {
1525 fc.setSelectedFile(new File(this.getSavedFile()));
1528 SciFileFilter xcosFilter = new SciFileFilter("*.xcos", null, 0);
1529 SciFileFilter allFilter = new SciFileFilter("*.*", null, 1);
1530 fc.addChoosableFileFilter(xcosFilter);
1531 fc.addChoosableFileFilter(allFilter);
1532 fc.setFileFilter(xcosFilter);
1534 fc.setAcceptAllFileFilterUsed(false);
1535 fc.displayAndWait();
1537 if (fc.getSelection() == null || fc.getSelection().length == 0 || fc.getSelection()[0].equals("")) {
1538 info(XcosMessages.EMPTY_INFO);
1541 fileName = fc.getSelection()[0];
1543 /* Extension checks */
1544 File file = new File(fileName);
1545 if(!file.exists()) {
1546 String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
1548 if (extension.equals(fileName)) {
1549 /* No extension given --> .xcos added */
1550 fileName += ".xcos";
1554 XcosCodec codec = new XcosCodec();
1555 String xml = mxUtils.getXml(codec.encode(this));
1558 mxUtils.writeFile(xml, fileName);
1561 } catch (IOException e1) {
1562 e1.printStackTrace();
1567 this.setSavedFile(fileName);
1568 File theFile = new File(fileName);
1569 setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1570 ConfigXcosManager.saveToRecentOpenedFiles(fileName);
1573 XcosDialogs.couldNotSaveFile(this);
1575 info(XcosMessages.EMPTY_INFO);
1579 public void setTitle(String title) {
1580 super.setTitle(title);
1584 public void updateTabTitle() {
1585 String tabTitle = !isModified() ? getTitle() : "* " + getTitle();
1586 if (getParentTab() != null) {
1587 getParentTab().setName(tabTitle);
1588 getParentTab().draw();
1592 public String[] buildEntireContext() {
1593 return getContext();
1596 public void setContext(String[] context) {
1597 this.context = context;
1598 updateCellsContext();
1601 public String[] getContext() {
1605 public void updateCellsContext() {
1606 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1607 Object obj = getModel().getChildAt(getDefaultParent(), i);
1608 if ( obj instanceof ContextUpdate) {
1609 ((ContextUpdate)obj).onContextChange(buildEntireContext());
1610 } else if (obj instanceof SuperBlock) {
1611 SuperBlock superBlock = (SuperBlock)obj;
1612 if(superBlock.getChild() != null) {
1613 superBlock.getChild().updateCellsContext();
1619 public String getVersion() {
1623 public int getDebugLevel() {
1627 public void setDebugLevel(int debugLevel) {
1628 this.debugLevel = debugLevel;
1633 * If current Diagram is empty, open within it
1634 * else open a new window.
1638 public void openDiagram(HashMap<String, Object> diagramm) {
1639 if (diagramm != null) {
1640 if (getModel().getChildCount(getDefaultParent()) == 0) {
1641 loadDiagram(diagramm);
1643 XcosDiagram xcosDiagram = Xcos.createANotShownDiagram();
1644 xcosDiagram.loadDiagram(diagramm);
1645 setChildrenParentDiagram(xcosDiagram);
1646 XcosTab.showTabFromDiagram(xcosDiagram);
1649 XcosDialogs.couldNotLoadFile(this);
1654 * Load a Diagramm structure into current window.
1658 public void loadDiagram(HashMap<String, Object> diagramm) {
1659 List<BasicBlock> allBlocks = (List<BasicBlock>) diagramm.get("Blocks");
1660 List<TextBlock> allTextBlocks = (List<TextBlock>) diagramm.get("TextBlocks");
1661 HashMap<String, Object> allLinks = (HashMap<String, Object>) diagramm.get("Links");
1662 HashMap<String, Object> properties = (HashMap<String, Object>) diagramm.get("Properties");
1664 setFinalIntegrationTime((Double) properties.get("finalIntegrationTime"));
1665 setIntegratorAbsoluteTolerance((Double) properties.get("integratorAbsoluteTolerance"));
1666 setIntegratorRelativeTolerance((Double) properties.get("integratorRelativeTolerance"));
1667 setToleranceOnTime((Double) properties.get("toleranceOnTime"));
1668 setMaxIntegrationTimeinterval((Double) properties.get("maxIntegrationTimeinterval"));
1669 setRealTimeScaling((Double) properties.get("realTimeScaling"));
1670 setSolver((Double) properties.get("solver"));
1671 setMaximumStepSize((Double) properties.get("maximumStepSize"));
1672 setContext((String[]) properties.get("context"));
1674 List<BasicPort[]> linkPorts = (List<BasicPort[]>) allLinks.get("Ports");
1675 List<double[][]> linkPoints = (List<double[][]>) allLinks.get("Points");
1677 Object[] objs = new Object[allBlocks.size() + linkPorts.size() + allTextBlocks.size()];
1678 getModel().beginUpdate();
1679 for (int i = 0; i < allBlocks.size(); ++i) {
1680 objs[i] = allBlocks.get(i);
1683 for (int i = 0; i < linkPorts.size(); ++i) {
1684 BasicLink link = BasicLink.createLinkFromPorts(linkPorts.get(i)[0], linkPorts.get(i)[1]);
1685 link.setGeometry(new mxGeometry(0,0,80,80));
1686 link.setSource(linkPorts.get(i)[0]);
1687 link.setTarget(linkPorts.get(i)[1]);
1688 double[][] points = linkPoints.get(i);
1690 if (points != null) {
1691 for (int point = 0; point < points.length; point++) {
1692 link.addPoint(points[point][0], points[point][1]);
1695 objs[i + allBlocks.size()] = link;
1698 for (int i = 0; i < allTextBlocks.size(); ++i) {
1699 objs[i + allBlocks.size() + linkPorts.size() ] = allTextBlocks.get(i);
1703 getModel().endUpdate();
1705 //this.setTitle(fileToLoad);
1706 //this.getParentTab().setName(fileToLoad);
1708 setTitle((String) properties.get("title"));
1709 //getParentTab().setName((String) properties.get("title"));
1711 // Clear all undo events in Undo Manager
1712 undoManager.reset();
1717 * Read a diagram from an HDF5 file (ask for creation if the file does not exist)
1718 * @param diagramFileName file to open
1720 public void openDiagramFromFile(String diagramFileName) {
1721 if (XcosTab.focusOnExistingFile(diagramFileName) == false) {
1722 File theFile = new File(diagramFileName);
1723 info(XcosMessages.LOADING_DIAGRAM);
1724 ((XcosTab) getParentTab()).setActionsEnabled(false);
1726 if (theFile.exists()) {
1727 transformAndLoadFile(theFile, false);
1729 AnswerOption answer = ScilabModalDialog.show(getParentTab(), String.format(
1730 XcosMessages.FILE_DOESNT_EXIST, theFile.getAbsolutePath()),
1731 XcosMessages.XCOS, IconType.QUESTION_ICON,
1734 if (answer == AnswerOption.YES_OPTION) {
1736 FileWriter writer = new FileWriter(diagramFileName);
1740 setSavedFile(diagramFileName);
1741 setTitle(theFile.getName().substring(0,
1742 theFile.getName().lastIndexOf('.')));
1743 } catch (IOException ioexc) {
1744 JOptionPane.showMessageDialog(this.getAsComponent(), ioexc);
1748 info(XcosMessages.EMPTY_INFO);
1749 ((XcosTab) getParentTab()).setActionsEnabled(true);
1750 this.resetUndoManager();
1756 * Load a file with different method depending on it extension
1757 * @param theFile File to load
1759 protected boolean transformAndLoadFile(File theFile, boolean wait) {
1760 final File fileToLoad = theFile;
1761 final XcosFileType filetype = XcosFileType.findFileType(fileToLoad);
1762 boolean result = false;
1769 newFile = filetype.exportToHdf5(fileToLoad);
1770 result = transformAndLoadFile(newFile, wait);
1772 Thread transformAction = new Thread() {
1775 newFile = filetype.exportToHdf5(fileToLoad);
1776 transformAndLoadFile(newFile, false);
1779 transformAction.start();
1786 Document document = loadXcosDocument(theFile.getAbsolutePath());
1787 if(document == null) {
1788 XcosDialogs.couldNotLoadFile(this);
1792 XcosCodec codec = new XcosCodec(document);
1794 if (getModel().getChildCount(getDefaultParent()) == 0) {
1795 codec.decode(document.getDocumentElement(), this);
1797 setSavedFile(theFile.getAbsolutePath());
1798 setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1799 setChildrenParentDiagram();
1802 XcosDiagram xcosDiagram = Xcos.createANotShownDiagram();
1803 xcosDiagram.info(XcosMessages.LOADING_DIAGRAM);
1804 codec.decode(document.getDocumentElement(), xcosDiagram);
1805 xcosDiagram.setModified(false);
1806 xcosDiagram.setSavedFile(theFile.getAbsolutePath());
1807 xcosDiagram.setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1808 setChildrenParentDiagram(xcosDiagram);
1809 XcosTab.showTabFromDiagram(xcosDiagram);
1810 xcosDiagram.generateUID();
1817 openDiagram(BlockReader.readDiagramFromFile(fileToLoad.getAbsolutePath()));
1824 XcosDialogs.couldNotLoadFile(this);
1830 static Document loadXcosDocument(String xcosFile) {
1831 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
1832 DocumentBuilder docBuilder;
1834 docBuilder = docBuilderFactory.newDocumentBuilder();
1835 return docBuilder.parse(xcosFile);
1836 } catch (ParserConfigurationException e) {
1838 } catch (SAXException e) {
1840 } catch (IOException e) {
1845 public void generateUID() {
1846 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1847 if (getModel().getChildAt(getDefaultParent(), i) instanceof BasicBlock) {
1848 BasicBlock block = (BasicBlock)getModel().getChildAt(getDefaultParent(), i);
1849 if(block.getRealParameters() instanceof ScilabMList) {
1850 //we have a hidden SuperBlock, create a real one
1851 SuperBlock newSP = (SuperBlock)BasicBlock.createBlock("SUPER_f");
1852 newSP.setRealParameters(block.getRealParameters());
1853 newSP.createChildDiagram(true);
1854 newSP.setParentDiagram(this);
1855 block.setRealParameters(BlockWriter.convertDiagramToMList(newSP.getChild()));
1856 } else if(block.getId() == null || block.getId().compareTo("") == 0) {
1864 * Update all the children of the current graph.
1866 public void setChildrenParentDiagram() {
1867 setChildrenParentDiagram(this);
1871 * For each block in the argument, call its setParentDiagram method
1872 * @param diagram The new parent of the blocks.
1874 private void setChildrenParentDiagram(XcosDiagram diagram) {
1875 for (int i = 0; i < diagram.getModel().getChildCount(diagram.getDefaultParent()); i++) {
1876 mxCell cell = (mxCell) diagram.getModel().getChildAt(diagram.getDefaultParent(), i);
1877 if (cell instanceof BasicBlock) {
1878 BasicBlock block = (BasicBlock) cell;
1879 block.setParentDiagram(diagram);
1880 if (block instanceof AfficheBlock) {
1881 AfficheBlock affich = (AfficheBlock) block;
1882 XcosTab.getAfficheBlocks().put(affich.getHashCode(), affich);
1889 * Getting the root diagram of a decomposed diagram
1890 * @return Root parent of the whole parent
1892 public XcosDiagram getRootDiagram() {
1893 XcosDiagram rootGraph = this;
1894 while (rootGraph instanceof SuperBlockDiagram) {
1895 rootGraph = ((SuperBlockDiagram) rootGraph).getContainer().getParentDiagram();
1901 * Returns the tooltip to be used for the given cell.
1903 public String getToolTipForCell(Object cell)
1905 if (cell instanceof BasicBlock) {
1906 return ((BasicBlock) cell).getToolTipText();
1907 } else if(cell instanceof BasicPort) {
1908 return ((BasicPort) cell).getToolTipText();
1914 * Set any text to an Afficheblock specified by its ID.
1915 * @param blockID ID of the AfficheBlock to be modified.
1916 * @param blockValue Content to be apply to the block.
1917 * @param iRows Number of Row in the blockValue.
1918 * @param iCols Number of Collumns in the blockValue.
1920 public static void setBlockTextValue(int blockID, String[] blockValue, int iRows, int iCols) {
1922 AfficheBlock block = XcosTab.getAfficheBlocks().get(blockID);
1923 if (block == null) {
1927 String blockResult = "";
1928 for (int i = 0; i < iRows; i++) {
1929 for (int j = 0; j < iCols; j++) {
1933 blockResult += blockValue[j * iRows + i];
1935 blockResult += System.getProperty("line.separator");
1938 block.setValue(blockResult);
1939 block.getParentDiagram().refresh();
1944 * Display the message in info bar.
1945 * @param message Informations
1947 public void info(String message) {
1948 final String localMessage = message;
1949 if (getParentTab() != null && getParentTab().getInfoBar() != null) {
1950 getParentTab().getInfoBar().setText(localMessage);
1955 * Display the message into an error popup
1956 * @param message Error of the message
1958 public void error(String message) {
1959 JOptionPane.showMessageDialog(getAsComponent(), message, XcosMessages.XCOS, JOptionPane.ERROR_MESSAGE);
1963 * Find the block corresponding to the given uid
1964 * and display a warning message.
1966 * @param uid - A String as UID.
1967 * @param message - The message to display.
1969 public void warnCellByUID(String uid, String message) {
1970 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1971 if (getModel().getChildAt(getDefaultParent(), i) instanceof mxCell) {
1972 if (((mxCell) getModel().getChildAt(getDefaultParent(), i)).getId().compareTo(uid) == 0) {
1973 //to put on top, only for new message, no for reset
1974 if(message.compareTo("") != 0) {
1978 getAsComponent().setCellWarning(getModel().getChildAt(getDefaultParent(), i), message);
1985 * Set the current diagram in a modified state
1986 * @param modified True or False whether the current diagram must be saved or not.
1988 public void setModified(boolean modified) {
1989 super.setModified(modified);
1996 public void undo() {
1999 if (getParentTab() != null) {
2000 if (undoManager.canUndo()) {
2001 ((XcosTab) getParentTab()).setEnabledUndo(true);
2003 ((XcosTab) getParentTab()).setEnabledUndo(false);
2005 ((XcosTab) getParentTab()).setEnabledRedo(true);
2008 updateUndoModifiedState();
2010 * if (undoManager.canRedo()){
2011 * ((Xcos)getParentTab()).setEnabledRedo(true); } else {
2012 * ((Xcos)getParentTab()).setEnabledRedo(false); }
2015 if(waitPathAddEdge) {
2016 if(drawLink != null) {
2017 getModel().remove(drawLink);
2019 cancelDrawLinkAction();
2026 * Apply the previously reverted action
2028 public void redo() {
2031 updateUndoModifiedState();
2033 if (getParentTab() != null) {
2034 if (undoManager.canUndo()) {
2035 ((XcosTab) getParentTab()).setEnabledUndo(true);
2037 ((XcosTab) getParentTab()).setEnabledUndo(false);
2039 if (undoManager.canRedo()) {
2040 ((XcosTab) getParentTab()).setEnabledRedo(true);
2042 ((XcosTab) getParentTab()).setEnabledRedo(false);
2048 * This function will reset the UndoManager in a stable state.
2050 public void resetUndoManager() {
2051 undoManager.reset();
2055 if (getParentTab() != null) {
2056 ((XcosTab) getParentTab()).setEnabledRedo(false);
2057 ((XcosTab) getParentTab()).setEnabledUndo(false);
2061 private void updateUndoModifiedState() {
2062 if (isZeroUndoCounter()) {
2071 public void setContextAction(SetContextAction action) {
2072 this.action = action;
2075 public SetContextAction getContextAction() {
2079 public BasicBlock getChildById(String uid) {
2080 BasicBlock returnBlock = null;
2081 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
2082 if (getModel().getChildAt(getDefaultParent(), i) instanceof BasicBlock) {
2083 BasicBlock block = (BasicBlock)getModel().getChildAt(getDefaultParent(), i);
2084 if (block.getId().compareTo(uid) == 0) { //find it
2085 returnBlock = block;
2087 if(block instanceof SuperBlock) {
2088 boolean created = false;
2089 if(((SuperBlock)block).getChild() == null) {
2090 //create temporary SuperBlock to find child
2091 ((SuperBlock)block).createChildDiagram();
2096 returnBlock = ((SuperBlock)block).getChild().getChildById(uid);
2098 if(created) { //if temporary, destroy it
2099 ((SuperBlock)block).getChild().closeDiagram();
2101 } else if(block.getRealParameters() instanceof ScilabMList) {
2102 //we have a hidden SuperBlock, create a real one
2103 SuperBlock newSP = (SuperBlock)BasicBlock.createBlock("SUPER_f");
2104 newSP.setParentDiagram(block.getParentDiagram());
2105 newSP.setRealParameters(block.getRealParameters());
2106 newSP.createChildDiagram();
2108 returnBlock = newSP.getChild().getChildById(uid);
2109 newSP.getChild().closeDiagram();
2115 if(returnBlock != null) {
2122 public boolean isChildVisible() {
2123 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); i++) {
2124 Object child = getModel().getChildAt(getDefaultParent(), i);
2125 if (child instanceof SuperBlock) {
2126 XcosDiagram diag = ((SuperBlock) child).getChild();
2127 if (diag != null && diag.isOpened()) {
2128 // if child or sub child is visible
2129 if (diag.isChildVisible() || diag.isVisible()) {
2138 public boolean canClose() {
2139 if (isChildVisible() == false) {
2145 public void closeChildren() {
2146 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); i++) {
2147 Object child = getModel().getChildAt(getDefaultParent(), i);
2148 if (child instanceof SuperBlock) {
2149 SuperBlock diag = (SuperBlock) child;
2151 if (diag.getChild() != null && diag.getChild().isOpened()) {
2152 diag.closeBlockSettings();
2158 private StringBuffer checkMultiplicities(Object edge, Object source, Object target) {
2159 mxMultiplicity multi[] = getMultiplicities();
2160 StringBuffer error = new StringBuffer();
2161 for(mxMultiplicity current : multi) {
2162 if(current instanceof PortCheck) {
2163 int sourceOut = mxGraphModel.getDirectedEdgeCount(getModel(), source, true);
2164 int targetIn = mxGraphModel.getDirectedEdgeCount(getModel(), target, false);
2166 String str = ((PortCheck)current).checkDrawLink(this, edge, source, target, sourceOut, targetIn);
2173 if(error.length() > 0) {
2179 private boolean checkEdgeDirection(Object source, Object target) {
2181 if(source instanceof InputPort && target instanceof OutputPort) {
2182 Object temp = source;
2188 if(source instanceof ControlPort && target instanceof CommandPort) {
2189 Object temp = source;
2195 if((source instanceof InputPort || source instanceof ControlPort) && target instanceof BasicLink) {
2196 Object temp = source;
2206 private void cancelDrawLinkAction() {
2207 waitPathAddEdge = false;
2208 waitPathRelease = false;
2210 info(XcosMessages.EMPTY_INFO);