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;
31 import javax.swing.JFileChooser;
32 import javax.swing.JOptionPane;
33 import javax.swing.SwingUtilities;
34 import javax.xml.parsers.DocumentBuilder;
35 import javax.xml.parsers.DocumentBuilderFactory;
36 import javax.xml.parsers.ParserConfigurationException;
38 import org.scilab.modules.graph.ScilabGraph;
39 import org.scilab.modules.graph.actions.PasteAction;
40 import org.scilab.modules.graph.actions.RedoAction;
41 import org.scilab.modules.graph.actions.SelectAllAction;
42 import org.scilab.modules.graph.actions.UndoAction;
43 import org.scilab.modules.graph.actions.ZoomInAction;
44 import org.scilab.modules.graph.actions.ZoomOutAction;
45 import org.scilab.modules.gui.bridge.contextmenu.SwingScilabContextMenu;
46 import org.scilab.modules.gui.bridge.filechooser.SwingScilabFileChooser;
47 import org.scilab.modules.gui.checkboxmenuitem.CheckBoxMenuItem;
48 import org.scilab.modules.gui.contextmenu.ContextMenu;
49 import org.scilab.modules.gui.contextmenu.ScilabContextMenu;
50 import org.scilab.modules.gui.filechooser.FileChooser;
51 import org.scilab.modules.gui.filechooser.ScilabFileChooser;
52 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
53 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
54 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
55 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
56 import org.scilab.modules.gui.tab.Tab;
57 import org.scilab.modules.gui.utils.SciFileFilter;
58 import org.scilab.modules.gui.utils.UIElementMapper;
59 import org.scilab.modules.gui.window.ScilabWindow;
60 import org.scilab.modules.hdf5.scilabTypes.ScilabMList;
61 import org.scilab.modules.xcos.Xcos;
62 import org.scilab.modules.xcos.XcosTab;
63 import org.scilab.modules.xcos.actions.DiagramBackgroundAction;
64 import org.scilab.modules.xcos.actions.SetContextAction;
65 import org.scilab.modules.xcos.actions.SetupAction;
66 import org.scilab.modules.xcos.actions.XcosDocumentationAction;
67 import org.scilab.modules.xcos.actions.XcosShortCut;
68 import org.scilab.modules.xcos.block.AfficheBlock;
69 import org.scilab.modules.xcos.block.BasicBlock;
70 import org.scilab.modules.xcos.block.BlockFactory;
71 import org.scilab.modules.xcos.block.io.ContextUpdate;
72 import org.scilab.modules.xcos.block.SplitBlock;
73 import org.scilab.modules.xcos.block.SuperBlock;
74 import org.scilab.modules.xcos.block.TextBlock;
75 import org.scilab.modules.xcos.block.BlockFactory.BlockInterFunction;
76 import org.scilab.modules.xcos.block.actions.ShowParentAction;
77 import org.scilab.modules.xcos.io.BlockReader;
78 import org.scilab.modules.xcos.io.BlockWriter;
79 import org.scilab.modules.xcos.io.XcosCodec;
80 import org.scilab.modules.xcos.link.BasicLink;
81 import org.scilab.modules.xcos.link.commandcontrol.CommandControlLink;
82 import org.scilab.modules.xcos.link.explicit.ExplicitLink;
83 import org.scilab.modules.xcos.link.implicit.ImplicitLink;
84 import org.scilab.modules.xcos.port.BasicPort;
85 import org.scilab.modules.xcos.port.PortCheck;
86 import org.scilab.modules.xcos.port.command.CommandPort;
87 import org.scilab.modules.xcos.port.control.ControlPort;
88 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
89 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
90 import org.scilab.modules.xcos.port.input.InputPort;
91 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
92 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
93 import org.scilab.modules.xcos.port.output.OutputPort;
94 import org.scilab.modules.xcos.utils.BlockPositioning;
95 import org.scilab.modules.xcos.utils.ConfigXcosManager;
96 import org.scilab.modules.xcos.utils.XcosDialogs;
97 import org.scilab.modules.xcos.utils.XcosEvent;
98 import org.scilab.modules.xcos.utils.XcosFileType;
99 import org.scilab.modules.xcos.utils.XcosMessages;
100 import org.w3c.dom.Document;
101 import org.xml.sax.SAXException;
103 import com.mxgraph.io.mxCodec;
104 import com.mxgraph.model.mxCell;
105 import com.mxgraph.model.mxGeometry;
106 import com.mxgraph.model.mxGraphModel;
107 import com.mxgraph.model.mxICell;
108 import com.mxgraph.model.mxGraphModel.mxChildChange;
109 import com.mxgraph.model.mxGraphModel.mxStyleChange;
110 import com.mxgraph.util.mxEvent;
111 import com.mxgraph.util.mxEventObject;
112 import com.mxgraph.util.mxPoint;
113 import com.mxgraph.util.mxRectangle;
114 import com.mxgraph.util.mxUndoableEdit;
115 import com.mxgraph.util.mxUtils;
116 import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
117 import com.mxgraph.view.mxMultiplicity;
119 public class XcosDiagram extends ScilabGraph {
121 // Default values : SCI/modules/scicos/macros/scicos_scicos/scicos_params.sci
122 private double finalIntegrationTime = 100000;
123 private double integratorAbsoluteTolerance = 1e-4;
124 private double integratorRelativeTolerance = 1e-6;
125 private double toleranceOnTime = 1e-10;
126 private double maxIntegrationTimeinterval = finalIntegrationTime + 1;
127 private double realTimeScaling = 0;
128 private double solver = 0;
129 private double maximumStepSize = 0;
130 private int debugLevel = 0;
131 private String[] context = new String[]{""};
132 private String version = "scicos4.2";
133 //private Window palette;
134 private Tab viewPort;
136 /*to manage splitLink*/
137 private BasicLink splitLink = null;
138 private BasicPort splitPort = null;
139 private mxPoint dragSplitPos = null;
140 private boolean waitSplitRelease = false;
142 /*to manage path link*/
143 private BasicLink drawLink = null;
144 private boolean waitPathAddEdge = false;
145 private boolean waitPathRelease = false;
147 private CheckBoxMenuItem viewPortMenu;
148 private CheckBoxMenuItem gridMenu;
149 private SetContextAction action;
151 protected mxIEventListener undoEnabler = new mxIEventListener()
153 public void invoke(Object source, mxEventObject evt) {
154 if (getParentTab() != null) {
155 ((XcosTab)getParentTab()).setEnabledUndo(true);
160 public Object addEdge(Object edge, Object parent, Object source,
161 Object target, Integer index) {
163 // Command -> Control
164 if (source instanceof CommandPort) {
165 if (target instanceof ControlPort) {
166 return super.addEdge(new CommandControlLink(), parent, source, target, index);
170 // Control -> Command
171 // Switch source and target !
172 if (target instanceof CommandPort) {
173 if (source instanceof ControlPort) {
174 return super.addEdge(new CommandControlLink(), parent, target, source, index);
178 // ExplicitOutput -> ExplicitInput
179 if (source instanceof ExplicitOutputPort) {
180 if (target instanceof ExplicitInputPort) {
181 return super.addEdge(new ExplicitLink(), parent, source, target, index);
184 // ExplicitInput -> ExplicitOutput
185 // Switch source and target !
186 if (target instanceof ExplicitOutputPort) {
187 if (source instanceof ExplicitInputPort) {
188 return super.addEdge(new ExplicitLink(), parent, target, source, index);
192 // ImplicitOutput -> ImplicitInput
193 if (source instanceof ImplicitOutputPort) {
194 if (target instanceof ImplicitInputPort) {
195 return super.addEdge(new ImplicitLink(), parent, source, target, index);
198 // ImplicitInput -> ImplicitOutput
199 // Switch source and target !
200 if (target instanceof ImplicitOutputPort) {
201 if (source instanceof ImplicitInputPort) {
202 return super.addEdge(new ImplicitLink(), parent, target, source, index);
206 // ImplicitInput -> ImplicitInput
207 if (source instanceof ImplicitInputPort) {
208 if (target instanceof ImplicitInputPort) {
209 return super.addEdge(new ImplicitLink(), parent, source, target, index);
212 // ImplicitOutputPort -> ImplicitOutput
213 // Switch source and target !
214 if (target instanceof ImplicitOutputPort) {
215 if (source instanceof ImplicitOutputPort) {
216 return super.addEdge(new ImplicitLink(), parent, target, source, index);
220 // ExplicitLink -> ExplicitInputPort
221 if (source instanceof ExplicitLink) {
222 if (target instanceof ExplicitInputPort) {
223 return addSplitEdge((BasicLink) source, (BasicPort) target);
226 // ExplicitOutput -> ExpliciLink
227 // Switch source and target !
228 if (target instanceof ExplicitLink) {
229 if (source instanceof ExplicitInputPort) {
230 waitSplitRelease = true;
231 splitLink = (BasicLink) target;
232 splitPort = (BasicPort) source;
234 //return addSplitEdge((BasicLink) target, (BasicPort)source);
238 // ImplicitLink -> ImplicitInputPort
239 if (source instanceof ImplicitLink) {
240 if (target instanceof ImplicitInputPort) {
241 return addSplitEdge((BasicLink) source, (BasicPort) target);
244 // ImplicitInputPort -> ImplicitLink
245 // Switch source and target !
246 if (target instanceof ImplicitLink) {
247 if (source instanceof ImplicitInputPort) {
248 waitSplitRelease = true;
249 splitLink = (BasicLink) target;
250 splitPort = (BasicPort) source;
252 //return addSplitEdge((BasicLink) target, (BasicPort)source);
256 // ImplicitLink -> ImplicitOutputPort
257 if (source instanceof ImplicitLink) {
258 if (target instanceof ImplicitOutputPort) {
259 return addSplitEdge((BasicLink) source, (BasicPort) target);
262 // ImplicitOutputPort -> ImplicitLink
263 // Switch source and target !
264 if (target instanceof ImplicitLink) {
265 if (source instanceof ImplicitOutputPort) {
266 waitSplitRelease = true;
267 splitLink = (BasicLink) target;
268 splitPort = (BasicPort) source;
270 //return addSplitEdge((BasicLink) target, (BasicPort)source);
274 // CommandControlLink -> ControlPort
275 if (source instanceof CommandControlLink) {
276 if (target instanceof ControlPort) {
277 return addSplitEdge((BasicLink) source, (BasicPort) target);
280 // ControlPort -> CommandControlLink
281 // Switch source and target !
282 if (target instanceof CommandControlLink) {
283 if (source instanceof ControlPort) {
284 waitSplitRelease = true;
285 splitLink = (BasicLink) target;
286 splitPort = (BasicPort) source;
288 //return addSplitEdge((BasicLink) target, (BasicPort)source);
293 if(source != null && target == null) {
295 if(source instanceof ExplicitInputPort || source instanceof ExplicitOutputPort) {
296 drawLink = (BasicLink) super.addEdge(new ExplicitLink(), getDefaultParent(), source, target, index);
297 } else if(source instanceof ImplicitInputPort || source instanceof ImplicitOutputPort) {
298 drawLink = (BasicLink) super.addEdge(new ImplicitLink(), getDefaultParent(), source, target, index);
299 } else if(source instanceof ControlPort || source instanceof CommandPort) {
300 drawLink = (BasicLink) super.addEdge(new CommandControlLink(), getDefaultParent(), source, target, index);
301 } else if(source instanceof BasicLink) {
302 SplitBlock split = (SplitBlock) addSplitEdge((BasicLink)source, (BasicPort)target);
303 drawLink = (BasicLink) split.getOut2().getEdgeAt(0);
306 if(drawLink != null) {
307 waitPathRelease = true;
310 info(XcosMessages.DRAW_LINK);
316 private Object addSplitEdge(BasicLink link, mxICell target) {
317 BasicPort linkSource = (BasicPort) link.getSource();
318 BasicPort linkTarget = (BasicPort) link.getTarget();
320 getModel().beginUpdate();
321 if (dragSplitPos == null) {
322 dragSplitPos = new mxPoint();
324 //check splitPosition values
325 double srcX = linkSource.getParent().getGeometry().getX() + linkSource.getGeometry().getCenterX();
326 double tgtX = linkTarget.getParent().getGeometry().getX() + linkTarget.getGeometry().getCenterX();
327 double srcY = linkSource.getParent().getGeometry().getY() + linkSource.getGeometry().getCenterY();
328 double tgtY = linkTarget.getParent().getGeometry().getY() + linkTarget.getGeometry().getCenterY();
330 double offsetX = (tgtX - srcX) / 2;
331 double offsetY = (tgtY - srcY) / 2;
332 dragSplitPos.setX(srcX + offsetX);
333 dragSplitPos.setY(srcY + offsetY);
336 SplitBlock splitBlock = (SplitBlock) BlockFactory.createBlock(BlockInterFunction.SPLIT_f);
337 if (target instanceof BasicLink) {
338 splitBlock.setConnection(linkSource, linkTarget, (BasicPort) ((BasicLink)target).getSource());
340 splitBlock.setConnection(linkSource, linkTarget, (BasicPort) target);
343 mxGeometry geom = splitBlock.getGeometry();
344 geom.setX(dragSplitPos.getX() - (SplitBlock.DEFAULT_SIZE/2));
345 geom.setY(dragSplitPos.getY() - (SplitBlock.DEFAULT_SIZE/2));
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 value
609 addListener(XcosEvent.FORCE_CELL_VALUE_UPDATE, new ForceCellValueUpdate());
611 // Update the blocks view on undo/redo
612 undoManager.addListener(mxEvent.UNDO, new UndoUpdateTracker());
613 undoManager.addListener(mxEvent.REDO, new UndoUpdateTracker());
615 getAsComponent().getGraphControl().addMouseListener(new XcosMouseListener(this));
617 getAsComponent().addKeyListener(new XcosKeyListener(this));
619 addListener(XcosEvent.ADD_PORTS, new mxIEventListener() {
620 public void invoke(Object source, mxEventObject evt) {
621 getModel().beginUpdate();
623 BasicBlock updatedBlock = (BasicBlock) evt.getArgAt(0);
624 BlockPositioning.updateBlockView(updatedBlock);
625 getModel().endUpdate();
633 * Called when mxEvents.CHANGE occurs on a model
635 private class ModelTracker implements mxIEventListener {
636 public void invoke(Object source, mxEventObject evt) {
637 List<mxUndoableChange> changes = (List<mxUndoableChange>) evt.getArgAt(0);
638 List<Object> objects = new ArrayList<Object>();
639 getModel().beginUpdate();
640 for (int i = 0; i < changes.size(); ++i) {
641 if (changes.get(i) instanceof mxChildChange) {
642 if (((mxChildChange) changes.get(i)).getChild() instanceof SplitBlock) {
646 if (((mxChildChange) changes.get(i)).getChild() instanceof BasicBlock) {
647 BasicBlock currentCell = (BasicBlock) ((mxChildChange) changes.get(i)).getChild();
648 objects.add(currentCell);
652 if (!objects.isEmpty()) {
653 Object[] firedCells = new Object[objects.size()];
654 for (int j = 0; j < objects.size(); ++j) {
655 firedCells[j] = objects.get(j);
657 //fireEvent(XcosEvent.FORCE_CELL_RESHAPE, new mxEventObject(new Object[] {firedCells}));
658 fireEvent(XcosEvent.FORCE_CELL_VALUE_UPDATE, new mxEventObject(new Object[] {firedCells}));
660 getModel().endUpdate();
664 * ForceCellValueUpdate
665 * Called when we want a block content to update.
667 private class ForceCellValueUpdate implements mxIEventListener {
668 public void invoke(Object source, mxEventObject evt) {
669 Object[] cells = (Object[]) evt.getArgs()[0];
671 getModel().beginUpdate();
673 for (int i = 0; i < cells.length; ++i) {
675 Object cell = cells[i];
677 if (cell instanceof BasicBlock) {
678 if (getCellStyle(cell).get("displayedLabel") != null) {
679 ((mxCell) cell).setValue("<html><body> " + getCellStyle(cell).get("displayedLabel") + " </body></html>");
682 mxRectangle preferedSize = getPreferredSizeForCell(cell);
683 mxGeometry cellSize = ((mxCell) cell).getGeometry();
685 ((mxCell) cell).setGeometry(new mxGeometry(cellSize.getX(), cellSize.getY(),
686 Math.max(preferedSize.getWidth(), cellSize.getWidth()),
687 Math.max(preferedSize.getHeight(), cellSize.getHeight())));
688 cellsResized(new Object[] {cell}, new mxRectangle[]{((mxCell) cell).getGeometry()});
691 getModel().endUpdate();
697 * SuperBlockUpdateTracker
698 * Called when adding some port in a SuperBlock diagram
699 * to update current sub-diagram (i.e SuperBlock) representation.
701 private class SuperBlockUpdateTracker implements mxIEventListener {
702 public void invoke(Object source, mxEventObject evt) {
703 assert evt.getArgs()[0] instanceof SuperBlock;
704 SuperBlock updatedBlock = (SuperBlock) evt.getArgs()[0];
705 updatedBlock.setRealParameters(BlockWriter
706 .convertDiagramToMList(updatedBlock.getChild()));
707 if (updatedBlock.getParentDiagram() instanceof SuperBlockDiagram) {
708 SuperBlock parentBlock = ((SuperBlockDiagram) updatedBlock
709 .getParentDiagram()).getContainer();
710 parentBlock.getParentDiagram().fireEvent(
711 XcosEvent.SUPER_BLOCK_UPDATED,
712 new mxEventObject(new Object[] { parentBlock }));
714 BlockPositioning.updateBlockView(updatedBlock);
721 * Called when mxEvents.CELLS_ADDED is fired.
723 private class CellAddedTracker implements mxIEventListener {
724 private XcosDiagram diagram = null;
726 public CellAddedTracker(XcosDiagram diagram) {
727 this.diagram = diagram;
730 public void invoke(Object source, mxEventObject evt) {
731 Object[] cells = (Object[]) evt.getArgs()[0];
733 diagram.getModel().beginUpdate();
734 for (int i = 0; i < cells.length; ++i) {
736 // ((mxCell) cells[i]).setId((new UID()).toString());
738 if (cells[i] instanceof BasicBlock) {
739 // Store all AfficheBlocks in a dedicated HasMap
740 if (cells[i] instanceof AfficheBlock) {
741 AfficheBlock affich = (AfficheBlock) cells[i];
742 XcosTab.getAfficheBlocks().put(affich.getHashCode(), affich);
744 // Update parent on cell addition
745 ((BasicBlock) cells[i]).setParentDiagram(diagram);
748 //fireEvent(XcosEvent.FORCE_CELL_VALUE_UPDATE, new mxEventObject(new Object[] {cells}));
749 diagram.getModel().endUpdate();
755 * Called when mxEvents.CELLS_REMOVED is fired.
757 private class CellRemovedTracker implements mxIEventListener {
758 public CellRemovedTracker(XcosDiagram diagram) {
761 public void invoke(Object source, mxEventObject evt) {
762 Object[] cells = (Object[]) evt.getArgs()[0];
763 for (int i = 0; i < cells.length; i++) {
764 if (cells[i] instanceof BasicLink) {
765 BasicLink link = (BasicLink) cells[i];
767 if(waitPathAddEdge) {
768 cancelDrawLinkAction();
776 private void removeLink(BasicLink link) {
777 if(!(link.getSource() instanceof BasicPort)) {
781 if(!(link.getTarget() instanceof BasicPort)) {
785 BasicPort portSource = (BasicPort) link.getSource();
786 BasicPort portTarget = (BasicPort) link.getTarget();
788 SplitBlock split = null;
789 BasicPort saveSource = null;
790 BasicPort saveTarget = null;
792 if (portSource == null) { return; }
793 if (portTarget == null) { return; }
796 if (portTarget.getParent() instanceof SplitBlock) {
797 split = (SplitBlock) portTarget.getParent();
799 Object[] outLinks = getAllEdges(new Object[] {split.getOut1(), split.getOut2()});
800 for (int i = 0; i < outLinks.length; i++) {
801 BasicLink outLink = (BasicLink) outLinks[i];
802 if (outLink.getTarget().getParent() instanceof SplitBlock) {
803 removeCells(new Object[]{outLink});
808 //Finally delete split and old associated links
810 removeCells(new Object[]{split});
818 if (portSource.getParent() instanceof SplitBlock) {
819 split = (SplitBlock) portSource.getParent();
821 //remove out1, so link between in.source and out2.target
822 if (split.getOut1() == portSource) {
823 //save source and target ports
824 saveSource = getOppositePort(split.getIn());
825 saveTarget = getOppositePort(split.getOut2());
826 } else if (split.getOut2() == portSource) {
827 //save source and target ports
828 saveSource = getOppositePort(split.getIn());
829 saveTarget = getOppositePort(split.getOut1());
833 if (saveSource != null && saveTarget != null) {
835 BasicLink newLink = BasicLink.createLinkFromPorts(saveSource, saveTarget);
836 newLink.setGeometry(new mxGeometry(0,0,80,80));
838 Object[] saveLinks = getAllEdges(new Object[]{saveSource, saveTarget});
839 for (int k = 0; k < saveLinks.length; k++) {
840 mxPoint[] savePts = ((BasicLink) saveLinks[k]).getPoints(0, false);
841 if (savePts != null) {
842 for (int j = 0; j < savePts.length; j++) {
843 newLink.addPoint(savePts[j].getX(), savePts[j].getY());
848 newLink.setSource(saveSource);
849 newLink.setTarget(saveTarget);
852 //unlink split and delete unlinked links
856 split.unlinkAndClean();
857 removeCells(new Object[]{split});
861 private BasicPort getOppositePort(BasicPort source) {
862 Object[] objs = getAllEdges(new Object[]{source});
863 if (objs.length == 0 || objs.length > 1) {
867 BasicLink link = (BasicLink) objs[0];
868 if (link.getSource() == source) {
869 return (BasicPort) link.getTarget();
871 return (BasicPort) link.getSource();
876 * Called when mxEvents.CELLS_RESIZED is fired.
878 private class CellResizedTracker implements mxIEventListener {
879 public void invoke(Object source, mxEventObject evt) {
880 Object[] cells = (Object[]) evt.getArgs()[0];
881 getModel().beginUpdate();
882 for (int i = 0; i < cells.length; ++i) {
883 if (cells[i] instanceof BasicBlock) {
884 BlockPositioning.updateBlockView((BasicBlock) cells[i]);
887 getModel().endUpdate();
892 * Update the modified block on undo/redo
894 private class UndoUpdateTracker implements mxIEventListener {
895 public void invoke(Object source, mxEventObject evt) {
896 List<mxUndoableChange> changes = ((mxUndoableEdit) evt.getArgAt(0)).getChanges();
897 Object[] changedCells = getSelectionCellsForChanges(changes);
898 getModel().beginUpdate();
899 for (Object object : changedCells) {
900 if (object instanceof BasicBlock) {
901 BasicBlock current = (BasicBlock) object;
903 // When we change the style property we have to update some
905 if (changes.get(0) instanceof mxStyleChange) {
906 current.updateFieldsFromStyle();
909 // Update the block position
910 BlockPositioning.updateBlockView(current);
913 getModel().endUpdate();
918 private class XcosKeyListener implements KeyListener{
920 public XcosKeyListener(XcosDiagram diagram) {}
922 public void keyTyped(KeyEvent e) {}
924 public void keyPressed(KeyEvent e) {}
926 public void keyReleased(KeyEvent e) {
927 if(e.getKeyChar() == KeyEvent.VK_ESCAPE) {
928 if(drawLink != null) {
929 getModel().remove(drawLink);
930 cancelDrawLinkAction();
936 * MouseListener inner class
938 private class XcosMouseListener implements MouseListener {
939 private XcosDiagram diagram = null;
941 public XcosMouseListener(XcosDiagram diagram) {
942 this.diagram = diagram;
945 public void mouseClicked(MouseEvent e) {
946 Object cell = getAsComponent().getCellAt(e.getX(), e.getY());
948 // Double Click within empty diagram Area
949 if (e.getClickCount() >= 2 && SwingUtilities.isLeftMouseButton(e) && cell == null) {
950 TextBlock textBlock = (TextBlock) BlockFactory.createBlock(BlockInterFunction.TEXT_f);
951 textBlock.getGeometry().setX(e.getX() - textBlock.getGeometry().getWidth() / 2.0);
952 textBlock.getGeometry().setY(e.getY() - textBlock.getGeometry().getWidth() / 2.0);
957 // Double Click within some component
958 if (e.getClickCount() >= 2 && SwingUtilities.isLeftMouseButton(e) && cell != null)
960 getModel().beginUpdate();
961 if (cell instanceof BasicBlock) {
962 BasicBlock block = (BasicBlock) cell;
964 block.openBlockSettings(buildEntireContext());
966 if (cell instanceof BasicLink) {
967 ((BasicLink) cell).insertPoint(e.getX(), e.getY());
969 getModel().endUpdate();
973 // Ctrl + Shift + Right Middle Click : for debug !!
974 if (e.getClickCount() >= 2 && SwingUtilities.isMiddleMouseButton(e)
975 && e.isShiftDown() && e.isControlDown())
977 System.err.println("[DEBUG] Click at position : " + e.getX() + " , " + e.getY());
979 System.err.println("[DEBUG] Click on diagram");
980 System.err.println("Default Parent ID : " + ((mxCell) getDefaultParent()).getId());
981 System.err.println("Model root ID : " + ((mxCell) getModel().getRoot()).getId());
982 System.err.println("getParentWindow : " + (getParentTab() == null ? null : getParentTab().getParentWindow()));
984 System.err.println("[DEBUG] Click on : " + cell);
985 System.err.println("[DEBUG] Style : " + ((mxCell) cell).getStyle());
986 System.err.println("[DEBUG] NbEdges : " + ((mxCell) cell).getEdgeCount());
987 System.err.println("[DEBUG] NbChildren : " + ((mxCell) cell).getChildCount());
988 for (int i = 0; i < ((mxCell) cell).getChildCount(); i++) {
989 System.err.println("[DEBUG] Child NbEdges : " + ((mxCell) cell).getChildAt(i).getEdgeCount());
992 if(cell instanceof BasicLink) {
993 System.err.println("[DEBUG] Link Points : " + ((BasicLink) cell).getPointCount());
1000 if ((e.getClickCount() == 1 && SwingUtilities.isRightMouseButton(e))
1001 || e.isPopupTrigger()
1002 || XcosMessages.isMacOsPopupTrigger(e)) {
1005 // Display diagram context menu
1006 ContextMenu menu = ScilabContextMenu.createContextMenu();
1008 menu.add(UndoAction.undoMenu((ScilabGraph) getAsComponent().getGraph()));
1009 menu.add(RedoAction.redoMenu((ScilabGraph) getAsComponent().getGraph()));
1010 menu.add(PasteAction.pasteMenu((ScilabGraph) getAsComponent().getGraph()));
1011 menu.add(SelectAllAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1013 menu.getAsSimpleContextMenu().addSeparator();
1015 menu.add(SetContextAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1016 menu.add(SetupAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1018 if(diagram instanceof SuperBlockDiagram) {
1020 menu.getAsSimpleContextMenu().addSeparator();
1022 menu.add(ShowParentAction.createMenu(diagram));
1025 menu.getAsSimpleContextMenu().addSeparator();
1027 menu.add(ZoomInAction.zoominMenu((ScilabGraph) getAsComponent().getGraph()));
1028 menu.add(ZoomOutAction.zoomoutMenu((ScilabGraph) getAsComponent().getGraph()));
1030 menu.getAsSimpleContextMenu().addSeparator();
1032 menu.add(DiagramBackgroundAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1034 menu.getAsSimpleContextMenu().addSeparator();
1036 menu.add(XcosDocumentationAction.createMenu((ScilabGraph) getAsComponent().getGraph()));
1038 ((SwingScilabContextMenu) menu.getAsSimpleContextMenu()).setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y);
1040 menu.setVisible(true);
1043 // Display object context menu
1044 if (cell instanceof BasicBlock) {
1045 BasicBlock block = (BasicBlock) cell;
1046 block.openContextMenu((ScilabGraph) getAsComponent().getGraph());
1048 if (cell instanceof BasicLink) {
1049 BasicLink link = (BasicLink) cell;
1050 link.openContextMenu((ScilabGraph) getAsComponent().getGraph());
1056 public void mouseEntered(MouseEvent e) {
1059 public void mouseExited(MouseEvent e) {
1062 public void mousePressed(MouseEvent e) {
1065 public void mouseReleased(MouseEvent e) {
1066 Object cell = getAsComponent().getCellAt(e.getX(), e.getY());
1068 if(SwingUtilities.isLeftMouseButton(e)) {
1069 if (waitSplitRelease) {
1070 dragSplitPos = new mxPoint(e.getX(), e.getY());
1071 waitSplitRelease = false;
1072 addSplitEdge(splitLink, splitPort);
1073 } else if(waitPathRelease){
1074 //Tips for ignore first mouse release after drag
1075 waitPathRelease = false;
1076 waitPathAddEdge = true;
1078 if(!e.isControlDown()) {
1079 //adjust final point
1080 mxGeometry geoPort = drawLink.getSource().getGeometry();
1081 mxGeometry geoBlock = drawLink.getSource().getParent().getGeometry();
1082 mxPoint lastPoint = new mxPoint(geoBlock.getX() + geoPort.getCenterX(), geoBlock.getY() + geoPort.getCenterY());
1083 mxPoint point = getPointPosition(lastPoint, new mxPoint(e.getX(), e.getY()));
1085 getModel().beginUpdate();
1086 drawLink.getGeometry().setTargetPoint(point);
1087 getModel().endUpdate();
1090 } else if(waitPathAddEdge){
1091 System.err.println("mouseReleased : waitPathAddEdge");
1092 if(drawLink != null) {
1093 getModel().beginUpdate();
1094 //move end of link and add point at old position
1095 mxGeometry geo = drawLink.getGeometry();
1096 drawLink.addPoint(geo.getTargetPoint().getX(), geo.getTargetPoint().getY());
1097 setSelectionCell(drawLink);
1100 mxICell source = drawLink.getSource();
1102 StringBuffer error = checkMultiplicities(drawLink, source, cell);
1104 if(cell instanceof BasicLink && cell != drawLink) { //no loop
1105 //draw link with a SplitBlock
1106 dragSplitPos = new mxPoint(e.getX(), e.getY());
1107 addSplitEdge((BasicLink)cell, drawLink);
1109 getModel().setTerminal(drawLink, cell, false);
1112 //invert source and target if needed
1113 if(checkEdgeDirection(source, cell) == false) {
1114 getModel().beginUpdate();
1115 drawLink.invertDirection();
1116 getModel().endUpdate();
1119 //reset info, flags and object
1120 cancelDrawLinkAction();
1122 if(cell != drawLink) {
1123 JOptionPane.showMessageDialog(getAsComponent(), error);
1125 setSelectionCell(drawLink);
1128 if(!e.isControlDown()) {
1129 geo.setTargetPoint(getPointPosition(geo.getTargetPoint(), new mxPoint(e.getX(), e.getY())));
1131 geo.setTargetPoint(new mxPoint(e.getX(), e.getY()));
1134 getModel().endUpdate();
1137 cancelDrawLinkAction();
1140 dragSplitPos = null;
1146 static mxPoint getPointPosition(mxPoint origin, mxPoint click) {
1147 boolean signX = click.getX() > origin.getX();
1148 boolean signY = click.getY() > origin.getY();
1149 double diffX = Math.abs(click.getX() - origin.getX());
1150 double diffY = Math.abs(click.getY() - origin.getY());
1153 if(diffY > (diffX / 2)) { //diagonal
1155 } else { //orthogonal
1159 if(diffX > (diffY / 2)) { //diagonal
1161 } else { //orthogonal
1167 if(signX == false) {
1171 if(signY == false) {
1175 return new mxPoint(origin.getX() + diffX, origin.getY() + diffY);
1178 * Manage Group to be CellFoldable i.e with a (-) to reduce
1179 * and a (+) to expand them.
1180 * Only non-Block / non-Port Cell are foldable.
1183 * @see com.mxgraph.view.mxGraph#isCellFoldable(java.lang.Object, boolean)
1185 public boolean isCellFoldable(Object cell, boolean collapse) {
1186 return !(cell instanceof BasicBlock) && super.isCellFoldable(cell, collapse);
1189 public boolean isCellClonable(Object cell) {
1193 public boolean isCellSelectable(Object cell) {
1194 if(cell instanceof BasicPort) {
1197 return super.isCellSelectable(cell);
1200 public boolean isCellMovable(Object cell) {
1201 if (cell instanceof BasicPort) {
1205 boolean movable = false;
1206 Object[] cells = this.getSelectionCells();
1208 //don't move if selection is only links
1209 for (int i = 0; i < cells.length; i++) {
1210 if (!(cells[i] instanceof BasicLink)) {
1216 return movable && super.isCellMovable(cell);
1219 public boolean isCellResizable(Object cell) {
1220 if (cell instanceof SplitBlock) {
1223 return (cell instanceof BasicBlock) && super.isCellResizable(cell);
1226 public boolean isCellDeletable(Object cell) {
1227 if (cell instanceof BasicBlock && ((BasicBlock) cell).isLocked()) {
1231 return !(cell instanceof BasicPort) && super.isCellDeletable(cell);
1234 public boolean isCellEditable(Object cell) {
1235 return (cell instanceof TextBlock) && super.isCellDeletable(cell);
1238 public boolean isCellDisconnectable(Object cell, Object terminal,boolean source) {
1239 return super.isCellDisconnectable(cell, terminal, source);
1242 public boolean isCellConnectable(Object cell)
1244 //currently in draw link action
1245 if(waitPathAddEdge) {
1246 if(drawLink != null) {
1247 StringBuffer error = checkMultiplicities(drawLink, drawLink.getSource(), cell);
1255 if(cell instanceof BasicBlock) {
1259 if(cell instanceof BasicPort) {
1260 int sourceOut = mxGraphModel.getDirectedEdgeCount(getModel(), cell, true);
1261 int targetIn = mxGraphModel.getDirectedEdgeCount(getModel(), cell, false);
1263 if(sourceOut > 0 || targetIn > 0) {
1267 return !(cell instanceof BasicBlock) && super.isCellConnectable(cell);
1270 public boolean isAutoSizeCell(Object cell) {
1271 return (cell instanceof AfficheBlock) || super.isAutoSizeCell(cell);
1275 public void dumpToHdf5File(String fileName) {
1276 if (fileName == null) {
1277 FileChooser fc = ScilabFileChooser.createFileChooser();
1278 fc.setInitialDirectory(getSavedFile());
1279 fc.setMultipleSelection(false);
1280 fc.displayAndWait();
1282 if (fc.getSelection() == null || fc.getSelection().length == 0 || fc.getSelection()[0].equals("")) {
1285 fileName = fc.getSelection()[0];
1286 System.out.println("Saving to file : {" + fileName + "}");
1289 BlockWriter.writeDiagramToFile(fileName, this);
1292 public double getFinalIntegrationTime() {
1293 return finalIntegrationTime;
1296 public void setFinalIntegrationTime(double finalIntegrationTime) {
1297 this.finalIntegrationTime = finalIntegrationTime;
1300 public double getIntegratorAbsoluteTolerance() {
1301 return integratorAbsoluteTolerance;
1304 public void setIntegratorAbsoluteTolerance(double integratorAbsoluteTolerance) {
1305 this.integratorAbsoluteTolerance = integratorAbsoluteTolerance;
1308 public double getIntegratorRelativeTolerance() {
1309 return integratorRelativeTolerance;
1312 public void setIntegratorRelativeTolerance(double integratorRelativeTolerance) {
1313 this.integratorRelativeTolerance = integratorRelativeTolerance;
1316 public double getMaximumStepSize() {
1317 return maximumStepSize;
1320 public void setMaximumStepSize(double maximumStepSize) {
1321 this.maximumStepSize = maximumStepSize;
1324 public double getMaxIntegrationTimeinterval() {
1325 return maxIntegrationTimeinterval;
1328 public void setMaxIntegrationTimeinterval(double maxIntegrationTimeinterval) {
1329 this.maxIntegrationTimeinterval = maxIntegrationTimeinterval;
1332 public double getRealTimeScaling() {
1333 return realTimeScaling;
1336 public void setRealTimeScaling(double realTimeScaling) {
1337 this.realTimeScaling = realTimeScaling;
1340 public double getSolver() {
1344 public void setSolver(double solver) {
1345 this.solver = solver;
1348 public double getToleranceOnTime() {
1349 return toleranceOnTime;
1352 public void setToleranceOnTime(double toleranceOnTime) {
1353 this.toleranceOnTime = toleranceOnTime;
1357 * Set the associated ViewPort
1358 * @param viewPort the Viewport
1360 public void setViewPort(Tab viewPort) {
1361 this.viewPort = viewPort;
1365 * Get the associated ViewPort
1366 * @return the Viewport
1368 public Tab getViewPort() {
1373 * Manage the visibility of the associated viewport
1374 * @param status new status
1376 public void setViewPortVisible(boolean status) {
1377 // Hide/Show parent window if the viewport is the only tab
1378 if (viewPort.getParentWindow().getNbDockedObjects() == 1) {
1379 viewPort.getParentWindow().setVisible(status);
1381 // Hide/Show viewport tab
1382 viewPort.setVisible(status);
1384 // (Un)Check the corresponding menu
1385 viewPortMenu.setChecked(status);
1389 * Set menu used to manage Viewport visibility
1390 * @param menu the menu
1392 public void setViewPortMenuItem(CheckBoxMenuItem menu) {
1393 this.viewPortMenu = menu;
1396 * Manage the visibility of the grid and the associated menu
1397 * @param status new status
1399 public void setGridVisible(boolean status) {
1400 setGridEnabled(status);
1401 getAsComponent().setGridVisible(status);
1402 getAsComponent().repaint();
1404 // (Un)Check the corresponding menu
1405 if(gridMenu != null) {
1406 gridMenu.setChecked(status);
1411 * Set menu used to manage Grid visibility
1412 * @param menu the menu
1414 public void setGridMenuItem(CheckBoxMenuItem menu) {
1415 this.gridMenu = menu;
1419 * Close Xcos instance including all tabs
1421 public void closeDiagram() {
1422 closeDiagram(false);
1426 * Close Xcos instance including all tabs
1428 public void closeDiagram(boolean fromScilab) {
1430 boolean wantToClose = true;
1432 if(canClose() == false) {
1438 // The diagram has been modified
1439 // Ask the user want he want to do !
1441 AnswerOption answer;
1442 if(fromScilab == true) {
1443 answer = ScilabModalDialog.show(getParentTab(), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS,
1444 IconType.QUESTION_ICON, ButtonType.YES_NO);
1446 answer = ScilabModalDialog.show(getParentTab(), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS,
1447 IconType.QUESTION_ICON, ButtonType.YES_NO_CANCEL);
1453 if (!saveDiagram()) {
1454 //if save is canceled, cancel close windows
1455 wantToClose = false;
1460 case CANCEL_OPTION :
1462 wantToClose = false;
1468 if(getParentTab() != null) {
1469 ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper.getCorrespondingUIElement(getParentTab().getParentWindowId());
1470 xcosWindow.removeTab(getParentTab());
1473 XcosTab.closeDiagram(this);
1478 public boolean saveDiagram() {
1479 boolean isSuccess = false;
1480 if (getSavedFile() == null) {
1481 isSuccess = saveDiagramAs(null);
1483 isSuccess = saveDiagramAs(getSavedFile());
1493 public boolean saveDiagramAs(String fileName) {
1495 boolean isSuccess = false;
1496 info(XcosMessages.SAVING_DIAGRAM);
1497 this.getParentTab().getInfoBar().draw();
1498 if (fileName == null) {
1499 // Choose a filename
1500 SwingScilabFileChooser fc = ((SwingScilabFileChooser) ScilabFileChooser.createFileChooser().getAsSimpleFileChooser());
1501 fc.setTitle(XcosMessages.SAVE_AS);
1502 fc.setUiDialogType(JFileChooser.SAVE_DIALOG);
1503 fc.setMultipleSelection(false);
1504 if (this.getSavedFile() != null) {
1505 fc.setSelectedFile(new File(this.getSavedFile()));
1508 SciFileFilter xcosFilter = new SciFileFilter("*.xcos", null, 0);
1509 SciFileFilter allFilter = new SciFileFilter("*.*", null, 1);
1510 fc.addChoosableFileFilter(xcosFilter);
1511 fc.addChoosableFileFilter(allFilter);
1512 fc.setFileFilter(xcosFilter);
1514 fc.setAcceptAllFileFilterUsed(false);
1515 fc.displayAndWait();
1517 if (fc.getSelection() == null || fc.getSelection().length == 0 || fc.getSelection()[0].equals("")) {
1518 info(XcosMessages.EMPTY_INFO);
1521 fileName = fc.getSelection()[0];
1523 /* Extension checks */
1524 File file = new File(fileName);
1525 if(!file.exists()) {
1526 String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
1528 if (extension.equals(fileName)) {
1529 /* No extension given --> .xcos added */
1530 fileName += ".xcos";
1534 XcosCodec codec = new XcosCodec();
1535 String xml = mxUtils.getXml(codec.encode(this));
1538 mxUtils.writeFile(xml, fileName);
1541 } catch (IOException e1) {
1542 e1.printStackTrace();
1547 this.setSavedFile(fileName);
1548 File theFile = new File(fileName);
1549 setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1550 ConfigXcosManager.saveToRecentOpenedFiles(fileName);
1553 XcosDialogs.couldNotSaveFile(this);
1555 info(XcosMessages.EMPTY_INFO);
1559 public void setTitle(String title) {
1560 super.setTitle(title);
1564 public void updateTabTitle() {
1565 String tabTitle = !isModified() ? getTitle() : "* " + getTitle();
1566 if (getParentTab() != null) {
1567 getParentTab().setName(tabTitle);
1568 getParentTab().draw();
1572 public String[] buildEntireContext() {
1573 return getContext();
1576 public void setContext(String[] context) {
1577 this.context = context;
1578 updateCellsContext();
1581 public String[] getContext() {
1585 public void updateCellsContext() {
1586 Object rootParent = getDefaultParent();
1587 int child_counts = getModel().getChildCount(rootParent);
1588 for (int i = 0; i < child_counts; ++i) {
1589 Object obj = getModel().getChildAt(rootParent, i);
1590 if (obj instanceof ContextUpdate) {
1591 String[] context = buildEntireContext();
1593 /* Determine if the context is not empty */
1594 int nbOfDetectedChar = 0;
1595 for (int j = 0; j < context.length; j++) {
1596 context[j] = context[j].replaceFirst("\\s", "");
1597 nbOfDetectedChar += context[j].length();
1598 if (nbOfDetectedChar != 0)
1602 if (nbOfDetectedChar != 0) {
1603 ((ContextUpdate) obj).onContextChange(context);
1606 } else if (obj instanceof SuperBlock) {
1607 SuperBlock superBlock = (SuperBlock) obj;
1608 if (superBlock.getChild() != null) {
1609 superBlock.getChild().updateCellsContext();
1615 public String getVersion() {
1619 public int getDebugLevel() {
1623 public void setDebugLevel(int debugLevel) {
1624 this.debugLevel = debugLevel;
1629 * If current Diagram is empty, open within it
1630 * else open a new window.
1634 public void openDiagram(HashMap<String, Object> diagramm) {
1635 if (diagramm != null) {
1636 if (getModel().getChildCount(getDefaultParent()) == 0) {
1637 loadDiagram(diagramm);
1639 XcosDiagram xcosDiagram = Xcos.createANotShownDiagram();
1640 xcosDiagram.loadDiagram(diagramm);
1641 setChildrenParentDiagram(xcosDiagram);
1642 XcosTab.showTabFromDiagram(xcosDiagram);
1645 XcosDialogs.couldNotLoadFile(this);
1650 * Load a Diagramm structure into current window.
1654 public void loadDiagram(HashMap<String, Object> diagramm) {
1655 List<BasicBlock> allBlocks = (List<BasicBlock>) diagramm.get("Blocks");
1656 List<TextBlock> allTextBlocks = (List<TextBlock>) diagramm.get("TextBlocks");
1657 HashMap<String, Object> allLinks = (HashMap<String, Object>) diagramm.get("Links");
1658 HashMap<String, Object> properties = (HashMap<String, Object>) diagramm.get("Properties");
1660 setFinalIntegrationTime((Double) properties.get("finalIntegrationTime"));
1661 setIntegratorAbsoluteTolerance((Double) properties.get("integratorAbsoluteTolerance"));
1662 setIntegratorRelativeTolerance((Double) properties.get("integratorRelativeTolerance"));
1663 setToleranceOnTime((Double) properties.get("toleranceOnTime"));
1664 setMaxIntegrationTimeinterval((Double) properties.get("maxIntegrationTimeinterval"));
1665 setRealTimeScaling((Double) properties.get("realTimeScaling"));
1666 setSolver((Double) properties.get("solver"));
1667 setMaximumStepSize((Double) properties.get("maximumStepSize"));
1668 setContext((String[]) properties.get("context"));
1670 List<BasicPort[]> linkPorts = (List<BasicPort[]>) allLinks.get("Ports");
1671 List<double[][]> linkPoints = (List<double[][]>) allLinks.get("Points");
1673 Object[] objs = new Object[allBlocks.size() + linkPorts.size() + allTextBlocks.size()];
1674 getModel().beginUpdate();
1675 for (int i = 0; i < allBlocks.size(); ++i) {
1676 objs[i] = allBlocks.get(i);
1679 for (int i = 0; i < linkPorts.size(); ++i) {
1680 BasicLink link = BasicLink.createLinkFromPorts(linkPorts.get(i)[0], linkPorts.get(i)[1]);
1681 link.setGeometry(new mxGeometry(0,0,80,80));
1682 link.setSource(linkPorts.get(i)[0]);
1683 link.setTarget(linkPorts.get(i)[1]);
1684 double[][] points = linkPoints.get(i);
1686 if (points != null) {
1687 for (int point = 0; point < points.length; point++) {
1688 link.addPoint(points[point][0], points[point][1]);
1691 objs[i + allBlocks.size()] = link;
1694 for (int i = 0; i < allTextBlocks.size(); ++i) {
1695 objs[i + allBlocks.size() + linkPorts.size() ] = allTextBlocks.get(i);
1699 getModel().endUpdate();
1701 //this.setTitle(fileToLoad);
1702 //this.getParentTab().setName(fileToLoad);
1704 setTitle((String) properties.get("title"));
1705 //getParentTab().setName((String) properties.get("title"));
1707 // Clear all undo events in Undo Manager
1708 undoManager.reset();
1713 * Read a diagram from an HDF5 file (ask for creation if the file does not exist)
1714 * @param diagramFileName file to open
1716 public void openDiagramFromFile(String diagramFileName) {
1717 if (XcosTab.focusOnExistingFile(diagramFileName) == false) {
1718 File theFile = new File(diagramFileName);
1719 info(XcosMessages.LOADING_DIAGRAM);
1721 if (getParentTab() != null)
1722 ((XcosTab) getParentTab()).setActionsEnabled(false);
1724 if (theFile.exists()) {
1725 transformAndLoadFile(theFile, false);
1727 AnswerOption answer = ScilabModalDialog.show(getParentTab(), String.format(
1728 XcosMessages.FILE_DOESNT_EXIST, theFile.getAbsolutePath()),
1729 XcosMessages.XCOS, IconType.QUESTION_ICON,
1732 if (answer == AnswerOption.YES_OPTION) {
1734 FileWriter writer = new FileWriter(diagramFileName);
1738 setSavedFile(diagramFileName);
1739 setTitle(theFile.getName().substring(0,
1740 theFile.getName().lastIndexOf('.')));
1741 } catch (IOException ioexc) {
1742 JOptionPane.showMessageDialog(this.getAsComponent(), ioexc);
1746 info(XcosMessages.EMPTY_INFO);
1747 if (getParentTab() != null)
1748 ((XcosTab) getParentTab()).setActionsEnabled(true);
1749 this.resetUndoManager();
1755 * Load a file with different method depending on it extension
1756 * @param theFile File to load
1758 protected boolean transformAndLoadFile(File theFile, boolean wait) {
1759 final File fileToLoad = theFile;
1760 final XcosFileType filetype = XcosFileType.findFileType(fileToLoad);
1761 boolean result = false;
1768 newFile = filetype.exportToHdf5(fileToLoad);
1769 result = transformAndLoadFile(newFile, wait);
1771 Thread transformAction = new Thread() {
1774 newFile = filetype.exportToHdf5(fileToLoad);
1775 transformAndLoadFile(newFile, false);
1778 transformAction.start();
1784 Document document = loadXcosDocument(theFile.getAbsolutePath());
1785 if(document == null) {
1786 XcosDialogs.couldNotLoadFile(this);
1790 XcosCodec codec = new XcosCodec(document);
1792 if (getModel().getChildCount(getDefaultParent()) == 0) {
1793 codec.decode(document.getDocumentElement(), this);
1795 setSavedFile(theFile.getAbsolutePath());
1796 setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1797 setChildrenParentDiagram();
1800 XcosDiagram xcosDiagram = Xcos.createANotShownDiagram();
1801 xcosDiagram.info(XcosMessages.LOADING_DIAGRAM);
1802 codec.decode(document.getDocumentElement(), xcosDiagram);
1803 xcosDiagram.setModified(false);
1804 xcosDiagram.setSavedFile(theFile.getAbsolutePath());
1805 xcosDiagram.setTitle(theFile.getName().substring(0, theFile.getName().lastIndexOf('.')));
1806 setChildrenParentDiagram(xcosDiagram);
1807 XcosTab.showTabFromDiagram(xcosDiagram);
1808 xcosDiagram.generateUID();
1809 xcosDiagram.info(XcosMessages.EMPTY_INFO);
1816 openDiagram(BlockReader.readDiagramFromFile(fileToLoad.getAbsolutePath()));
1823 XcosDialogs.couldNotLoadFile(this);
1829 static Document loadXcosDocument(String xcosFile) {
1830 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
1831 DocumentBuilder docBuilder;
1833 docBuilder = docBuilderFactory.newDocumentBuilder();
1834 return docBuilder.parse(xcosFile);
1835 } catch (ParserConfigurationException e) {
1837 } catch (SAXException e) {
1839 } catch (IOException e) {
1844 public void generateUID() {
1845 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1846 if (getModel().getChildAt(getDefaultParent(), i) instanceof BasicBlock) {
1847 BasicBlock block = (BasicBlock)getModel().getChildAt(getDefaultParent(), i);
1848 if(block.getRealParameters() instanceof ScilabMList) {
1849 //we have a hidden SuperBlock, create a real one
1850 SuperBlock newSP = (SuperBlock)BlockFactory.createBlock("SUPER_f");
1851 newSP.setRealParameters(block.getRealParameters());
1852 newSP.createChildDiagram(true);
1853 newSP.setParentDiagram(this);
1854 block.setRealParameters(BlockWriter.convertDiagramToMList(newSP.getChild()));
1855 } else if(block.getId() == null || block.getId().compareTo("") == 0) {
1863 * Update all the children of the current graph.
1865 public void setChildrenParentDiagram() {
1866 setChildrenParentDiagram(this);
1870 * For each block in the argument, call its setParentDiagram method
1871 * @param diagram The new parent of the blocks.
1873 private void setChildrenParentDiagram(XcosDiagram diagram) {
1874 for (int i = 0; i < diagram.getModel().getChildCount(diagram.getDefaultParent()); i++) {
1875 mxCell cell = (mxCell) diagram.getModel().getChildAt(diagram.getDefaultParent(), i);
1876 if (cell instanceof BasicBlock) {
1877 BasicBlock block = (BasicBlock) cell;
1878 block.setParentDiagram(diagram);
1879 if (block instanceof AfficheBlock) {
1880 AfficheBlock affich = (AfficheBlock) block;
1881 XcosTab.getAfficheBlocks().put(affich.getHashCode(), affich);
1888 * Getting the root diagram of a decomposed diagram
1889 * @return Root parent of the whole parent
1891 public XcosDiagram getRootDiagram() {
1892 XcosDiagram rootGraph = this;
1893 while (rootGraph instanceof SuperBlockDiagram) {
1894 rootGraph = ((SuperBlockDiagram) rootGraph).getContainer().getParentDiagram();
1900 * Returns the tooltip to be used for the given cell.
1902 public String getToolTipForCell(Object cell)
1904 if (cell instanceof BasicBlock) {
1905 return ((BasicBlock) cell).getToolTipText();
1906 } else if(cell instanceof BasicPort) {
1907 return ((BasicPort) cell).getToolTipText();
1913 * Set any text to an Afficheblock specified by its ID.
1914 * @param blockID ID of the AfficheBlock to be modified.
1915 * @param blockValue Content to be apply to the block.
1916 * @param iRows Number of Row in the blockValue.
1917 * @param iCols Number of Collumns in the blockValue.
1919 public static void setBlockTextValue(int blockID, String[] blockValue, int iRows, int iCols) {
1921 AfficheBlock block = XcosTab.getAfficheBlocks().get(blockID);
1922 if (block == null) {
1926 String blockResult = "";
1927 for (int i = 0; i < iRows; i++) {
1928 for (int j = 0; j < iCols; j++) {
1932 blockResult += blockValue[j * iRows + i];
1934 blockResult += System.getProperty("line.separator");
1937 block.setValue(blockResult);
1938 block.getParentDiagram().refresh();
1943 * Display the message in info bar.
1944 * @param message Informations
1946 public void info(String message) {
1947 final String localMessage = message;
1948 if (getParentTab() != null && getParentTab().getInfoBar() != null) {
1949 getParentTab().getInfoBar().setText(localMessage);
1954 * Display the message into an error popup
1955 * @param message Error of the message
1957 public void error(String message) {
1958 JOptionPane.showMessageDialog(getAsComponent(), message, XcosMessages.XCOS, JOptionPane.ERROR_MESSAGE);
1962 * Find the block corresponding to the given uid
1963 * and display a warning message.
1965 * @param uid - A String as UID.
1966 * @param message - The message to display.
1968 public void warnCellByUID(String uid, String message) {
1969 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
1970 if (getModel().getChildAt(getDefaultParent(), i) instanceof mxCell) {
1971 if (((mxCell) getModel().getChildAt(getDefaultParent(), i)).getId().compareTo(uid) == 0) {
1972 //to put on top, only for new message, no for reset
1973 if(message.compareTo("") != 0) {
1977 getAsComponent().setCellWarning(getModel().getChildAt(getDefaultParent(), i), message);
1984 * Set the current diagram in a modified state
1985 * @param modified True or False whether the current diagram must be saved or not.
1987 public void setModified(boolean modified) {
1988 super.setModified(modified);
1995 public void undo() {
1998 if (getParentTab() != null) {
1999 if (undoManager.canUndo()) {
2000 ((XcosTab) getParentTab()).setEnabledUndo(true);
2002 ((XcosTab) getParentTab()).setEnabledUndo(false);
2004 ((XcosTab) getParentTab()).setEnabledRedo(true);
2007 updateUndoModifiedState();
2009 * if (undoManager.canRedo()){
2010 * ((Xcos)getParentTab()).setEnabledRedo(true); } else {
2011 * ((Xcos)getParentTab()).setEnabledRedo(false); }
2014 if(waitPathAddEdge) {
2015 if(drawLink != null) {
2016 getModel().remove(drawLink);
2018 cancelDrawLinkAction();
2025 * Apply the previously reverted action
2027 public void redo() {
2030 updateUndoModifiedState();
2032 if (getParentTab() != null) {
2033 if (undoManager.canUndo()) {
2034 ((XcosTab) getParentTab()).setEnabledUndo(true);
2036 ((XcosTab) getParentTab()).setEnabledUndo(false);
2038 if (undoManager.canRedo()) {
2039 ((XcosTab) getParentTab()).setEnabledRedo(true);
2041 ((XcosTab) getParentTab()).setEnabledRedo(false);
2047 * This function will reset the UndoManager in a stable state.
2049 public void resetUndoManager() {
2050 undoManager.reset();
2054 if (getParentTab() != null) {
2055 ((XcosTab) getParentTab()).setEnabledRedo(false);
2056 ((XcosTab) getParentTab()).setEnabledUndo(false);
2060 private void updateUndoModifiedState() {
2061 if (isZeroUndoCounter()) {
2070 public void setContextAction(SetContextAction action) {
2071 this.action = action;
2074 public SetContextAction getContextAction() {
2078 public BasicBlock getChildById(String uid) {
2079 BasicBlock returnBlock = null;
2080 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); ++i) {
2081 if (getModel().getChildAt(getDefaultParent(), i) instanceof BasicBlock) {
2082 BasicBlock block = (BasicBlock)getModel().getChildAt(getDefaultParent(), i);
2083 if (block.getId().compareTo(uid) == 0) { //find it
2084 returnBlock = block;
2086 if(block instanceof SuperBlock) {
2087 boolean created = false;
2088 if(((SuperBlock)block).getChild() == null) {
2089 //create temporary SuperBlock to find child
2090 ((SuperBlock)block).createChildDiagram();
2095 returnBlock = ((SuperBlock)block).getChild().getChildById(uid);
2097 if(created) { //if temporary, destroy it
2098 ((SuperBlock)block).getChild().closeDiagram();
2100 } else if(block.getRealParameters() instanceof ScilabMList) {
2101 //we have a hidden SuperBlock, create a real one
2102 SuperBlock newSP = (SuperBlock)BlockFactory.createBlock("SUPER_f");
2103 newSP.setParentDiagram(block.getParentDiagram());
2104 newSP.setRealParameters(block.getRealParameters());
2105 newSP.createChildDiagram();
2107 returnBlock = newSP.getChild().getChildById(uid);
2108 newSP.getChild().closeDiagram();
2114 if(returnBlock != null) {
2121 public boolean isChildVisible() {
2122 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); i++) {
2123 Object child = getModel().getChildAt(getDefaultParent(), i);
2124 if (child instanceof SuperBlock) {
2125 XcosDiagram diag = ((SuperBlock) child).getChild();
2126 if (diag != null && diag.isOpened()) {
2127 // if child or sub child is visible
2128 if (diag.isChildVisible() || diag.isVisible()) {
2137 public boolean canClose() {
2138 if (isChildVisible() == false) {
2144 public void closeChildren() {
2145 for (int i = 0; i < getModel().getChildCount(getDefaultParent()); i++) {
2146 Object child = getModel().getChildAt(getDefaultParent(), i);
2147 if (child instanceof SuperBlock) {
2148 SuperBlock diag = (SuperBlock) child;
2150 if (diag.getChild() != null && diag.getChild().isOpened()) {
2151 diag.closeBlockSettings();
2157 private StringBuffer checkMultiplicities(Object edge, Object source, Object target) {
2158 mxMultiplicity multi[] = getMultiplicities();
2159 StringBuffer error = new StringBuffer();
2160 for(mxMultiplicity current : multi) {
2161 if(current instanceof PortCheck) {
2162 int sourceOut = mxGraphModel.getDirectedEdgeCount(getModel(), source, true);
2163 int targetIn = mxGraphModel.getDirectedEdgeCount(getModel(), target, false);
2165 String str = ((PortCheck)current).checkDrawLink(this, edge, source, target, sourceOut, targetIn);
2172 if(error.length() > 0) {
2178 private boolean checkEdgeDirection(Object source, Object target) {
2180 if(source instanceof InputPort && target instanceof OutputPort) {
2181 Object temp = source;
2187 if(source instanceof ControlPort && target instanceof CommandPort) {
2188 Object temp = source;
2194 if((source instanceof InputPort || source instanceof ControlPort) && target instanceof BasicLink) {
2195 Object temp = source;
2205 private void cancelDrawLinkAction() {
2206 waitPathAddEdge = false;
2207 waitPathRelease = false;
2209 info(XcosMessages.EMPTY_INFO);