2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
4 * Copyright (C) 2009 - DIGITEO - Antoine ELIAS
5 * Copyright (C) 2009 - DIGITEO - Clément DAVID
7 * This file must be used under the terms of the CeCILL.
8 * This source file is licensed as described in the file COPYING, which
9 * you should have received as part of this distribution. The terms
10 * are also available at
11 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
15 package org.scilab.modules.xcos.block.actions;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.EnumMap;
22 import java.util.List;
25 import org.scilab.modules.graph.ScilabGraph;
26 import org.scilab.modules.graph.actions.DefaultAction;
27 import org.scilab.modules.gui.menuitem.MenuItem;
28 import org.scilab.modules.hdf5.scilabTypes.ScilabDouble;
29 import org.scilab.modules.hdf5.scilabTypes.ScilabList;
30 import org.scilab.modules.hdf5.scilabTypes.ScilabString;
31 import org.scilab.modules.xcos.XcosUIDObject;
32 import org.scilab.modules.xcos.block.BasicBlock;
33 import org.scilab.modules.xcos.block.ContextUpdate;
34 import org.scilab.modules.xcos.block.ContextUpdate.IOBlocks;
35 import org.scilab.modules.xcos.block.BlockFactory;
36 import org.scilab.modules.xcos.block.EventInBlock;
37 import org.scilab.modules.xcos.block.EventOutBlock;
38 import org.scilab.modules.xcos.block.ExplicitInBlock;
39 import org.scilab.modules.xcos.block.ExplicitOutBlock;
40 import org.scilab.modules.xcos.block.ImplicitInBlock;
41 import org.scilab.modules.xcos.block.ImplicitOutBlock;
42 import org.scilab.modules.xcos.block.SplitBlock;
43 import org.scilab.modules.xcos.block.SuperBlock;
44 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
45 import org.scilab.modules.xcos.graph.XcosDiagram;
46 import org.scilab.modules.xcos.io.BasicBlockInfo;
47 import org.scilab.modules.xcos.io.BlockWriter;
48 import org.scilab.modules.xcos.link.BasicLink;
49 import org.scilab.modules.xcos.link.commandcontrol.CommandControlLink;
50 import org.scilab.modules.xcos.link.explicit.ExplicitLink;
51 import org.scilab.modules.xcos.link.implicit.ImplicitLink;
52 import org.scilab.modules.xcos.port.BasicPort;
53 import org.scilab.modules.xcos.port.command.CommandPort;
54 import org.scilab.modules.xcos.port.control.ControlPort;
55 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
56 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
57 import org.scilab.modules.xcos.port.input.InputPort;
58 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
59 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
60 import org.scilab.modules.xcos.utils.BlockPositioning;
61 import org.scilab.modules.xcos.utils.XcosMessages;
63 import com.mxgraph.model.mxGeometry;
66 public class RegionToSuperblockAction extends DefaultAction {
68 private class BrokenLink {
69 private BasicLink link;
70 private BasicPort edge;
71 private mxGeometry geom;
72 private boolean outGoing;
73 private int portNumber;
75 public BrokenLink(BasicLink link, BasicPort edge, mxGeometry geom, boolean outGoing) {
78 this.outGoing = outGoing;
82 public boolean getOutGoing() {
86 public BasicLink getLink() {
90 public BasicPort getCopiedEdge() {
94 public mxGeometry getGeometry() {
98 public void setPortNumber(int portNumber) {
99 this.portNumber = portNumber;
102 public int getPortNumber() {
107 private RegionToSuperblockAction(ScilabGraph scilabGraph) {
108 super(XcosMessages.REGION_TO_SUPERBLOCK, scilabGraph);
111 public static MenuItem createMenu(ScilabGraph scilabGraph) {
112 return createMenu(XcosMessages.REGION_TO_SUPERBLOCK, null,
113 new RegionToSuperblockAction(scilabGraph), null);
116 public void doAction() {
118 XcosDiagram graph = (XcosDiagram) getGraph(null);
119 graph.info(XcosMessages.GENERATE_SUPERBLOCK);
120 graph.getModel().beginUpdate();
123 * Update selection and return it.
125 List<XcosUIDObject> selectedCells = updateForNotSelectedLinks(graph);
128 * Sort the selected cells to avoid misplacement
130 Collections.sort(selectedCells);
133 * Clone cells and generate a translation matrix between old and new mxCells
135 Object[] cellArrays = getGraph(null).cloneCells(selectedCells.toArray());
136 Collection<Object> cells = Arrays.asList(cellArrays);
137 XcosUIDObject[] typedCells = new XcosUIDObject[cellArrays.length];
138 cells.toArray(typedCells);
139 List<XcosUIDObject> cellsCopy = Arrays.asList(typedCells);
140 Object[] translationMatrix = new Object[cellsCopy.size()];
141 for (int i = 0; i < translationMatrix.length; i++) {
142 translationMatrix[i] = selectedCells.get(i);
145 List<BasicBlock> blocksCopyWithoutSplitBlocks = getBlocks(cellsCopy);
148 * Getting selection rectangle
150 double minX = Double.MAX_VALUE;
151 double minY = Double.MAX_VALUE;
152 double maxX = Double.MIN_VALUE;
153 double maxY = Double.MIN_VALUE;
155 for (BasicBlock current : blocksCopyWithoutSplitBlocks) {
156 minX = Math.min(minX, current.getGeometry().getX());
157 minY = Math.min(minY, current.getGeometry().getY());
158 maxX = Math.max(maxX, current.getGeometry().getX());
159 maxY = Math.max(maxY, current.getGeometry().getY());
163 * Creating the superblock
165 SuperBlock superBlock = (SuperBlock) BlockFactory.createBlock("SUPER_f");
166 superBlock.setStyle("SUPER_f");
167 superBlock.getGeometry().setX((maxX + minX) / 2.0);
168 superBlock.getGeometry().setY((maxY + minY) / 2.0);
173 * Creating the child graph
175 SuperBlockDiagram diagram = new SuperBlockDiagram(superBlock);
177 diagram.getModel().beginUpdate();
178 diagram.addCells(cellsCopy.toArray());
179 diagram.getModel().endUpdate();
182 * Find broken links, to insert input/output blocks And update the child
185 List<BrokenLink> breaks = getBrokenLinks(selectedCells, cellsCopy);
186 List<Integer> maxValues = getMaxBlocksValues(selectedCells);
187 updateChildGraph(diagram, breaks, maxValues);
190 * Delete the selected cells from the parent graph
192 graph.removeCells(graph.getSelectionCells());
195 * Update block with real parameters
197 superBlock.setRealParameters(BlockWriter.convertDiagramToMList(diagram));
198 superBlock.createChildDiagram();
203 graph.getModel().beginUpdate();
204 graph.addCell(superBlock);
205 graph.setSelectionCell(superBlock);
206 graph.getModel().endUpdate();
209 * Calculate angle/mirrored/flipped statistics
214 for (BasicBlock basicBlock : blocksCopyWithoutSplitBlocks) {
215 angle += basicBlock.getAngle();
216 flipped += basicBlock.getFlip()?1:0;
217 mirrored += basicBlock.getMirror()?1:0;
221 * Apply statistics to the superblock
223 int midBlockIndex = blocksCopyWithoutSplitBlocks.size()/2;
224 superBlock.setAngle(BlockPositioning.roundAngle(angle/blocksCopyWithoutSplitBlocks.size()));
225 superBlock.setFlip((flipped > midBlockIndex)?true:false);
226 superBlock.setMirror((mirrored > midBlockIndex)?true:false);
231 superBlock.updateExportedPort();
233 // change source or target of old link
234 createLinks(graph, superBlock, breaks);
235 superBlock.closeBlockSettings();
238 * Update the visible attributes
240 BlockPositioning.updateBlockView(superBlock);
242 graph.getModel().endUpdate();
245 graph.info(XcosMessages.EMPTY_INFO);
249 * Get all the non-SplitBlock blocks in the cellsCopy.
251 private List<BasicBlock> getBlocks(List<XcosUIDObject> cellsCopy) {
252 List<BasicBlock> list = new ArrayList<BasicBlock>(cellsCopy.size());
253 for (XcosUIDObject cell : cellsCopy) {
254 if (cell instanceof BasicBlock) {
255 if (!(cell instanceof SplitBlock)) {
256 list.add((BasicBlock) cell);
264 * Check for missing links or selected ports, to add or exclude them.
266 private List<XcosUIDObject> updateForNotSelectedLinks(XcosDiagram graph) {
268 graph.getModel().beginUpdate();
270 for (int i = 0; i < graph.getSelectionCells().length; i++) {
271 XcosUIDObject current = (XcosUIDObject) graph.getSelectionCells()[i];
272 if (current instanceof BasicBlock) {
273 BasicBlock block = (BasicBlock) current;
274 for (int j = 0; j < block.getChildCount(); j++) {
275 if (block.getChildAt(j) instanceof BasicPort) {
276 BasicPort port = (BasicPort) block.getChildAt(j);
277 if (port.getEdgeCount() > 0) {
278 if (port.getEdgeAt(0) instanceof BasicLink) {
279 BasicLink link = (BasicLink) port.getEdgeAt(0);
280 BasicBlock otherSide = null;
281 if (link.getTarget() == port) {
282 otherSide = (BasicBlock) link.getSource()
285 otherSide = (BasicBlock) link.getTarget()
289 if (isInSelection(graph.getSelectionCells(),
291 graph.addSelectionCell(link);
294 if (otherSide instanceof SplitBlock) {
295 graph.addSelectionCell(otherSide);
296 } // otherSide is a SplitBlock
302 } else if (current instanceof BasicPort) {
303 // remove orphan port and connected link
304 graph.removeSelectionCell(current.getEdgeAt(0));
305 graph.removeSelectionCell(current);
312 graph.getModel().endUpdate();
314 Object[] selectedCells = graph.getSelectionCells();
315 Collection<Object> cells = Arrays.asList(selectedCells);
316 XcosUIDObject[] typedCells = new XcosUIDObject[selectedCells.length];
317 cells.toArray(typedCells);
319 return new ArrayList<XcosUIDObject>(Arrays.asList(typedCells));
323 * Re-link the parent Graph
326 * The parent graph (modified)
328 * The added superblock
332 private void createLinks(XcosDiagram graph, SuperBlock superBlock,
333 List<BrokenLink> breaks) {
334 for (BrokenLink link : breaks) {
335 BasicPort source = null;
336 BasicPort target = null;
338 if (link.getOutGoing()) {
339 target = (BasicPort) link.getLink().getTarget();
341 if (link.getLink() instanceof ExplicitLink) {
342 source = BasicBlockInfo.getAllExplicitOutputPorts(superBlock, false).get(link.getPortNumber() - 1);
343 } else if (link.getLink() instanceof ImplicitLink) {
344 source = BasicBlockInfo.getAllImplicitOutputPorts(superBlock, false).get(link.getPortNumber() - 1);
345 } else if (link.getLink() instanceof CommandControlLink) {
346 source = BasicBlockInfo.getAllCommandPorts(superBlock, false).get(link.getPortNumber() - 1);
349 source = (BasicPort) link.getLink().getSource();
351 if (link.getLink() instanceof ExplicitLink) {
352 target = BasicBlockInfo.getAllExplicitInputPorts(superBlock, false).get(link.getPortNumber() - 1);
353 } else if (link.getLink() instanceof ImplicitLink) {
354 target = BasicBlockInfo.getAllImplicitInputPorts(superBlock, false).get(link.getPortNumber() - 1);
355 } else if (link.getLink() instanceof CommandControlLink) {
356 target = BasicBlockInfo.getAllControlPorts(superBlock, false).get(link.getPortNumber() - 1);
360 BasicLink newLink = BasicLink.createLinkFromPorts(source, target);
361 newLink.setGeometry(link.getLink().getGeometry());
362 newLink.setSource(source);
363 newLink.setTarget(target);
365 graph.getModel().beginUpdate();
366 graph.addCell(newLink);
367 graph.getModel().endUpdate();
369 // this method don't call CELLS_REMOVED between beginUpdate and
371 // this function unlink source and target correctly too
372 graph.getModel().beginUpdate();
373 graph.getModel().remove(link.getLink());
374 graph.getModel().endUpdate();
379 * Add the IN/OUT blocks and links in the child graph
384 * The broken links in the parent graph
386 * The I/O block values previously used in the parent diagram
389 private void updateChildGraph(SuperBlockDiagram diagram,
390 List<BrokenLink> breaks, List<Integer> maxValues) {
393 * Add in/out blocks in SuperBlock (Child Graph)
395 for (BrokenLink link : breaks) {
396 BasicBlock block = null;
398 if (link.getLink() instanceof ExplicitLink) {
399 if (link.getOutGoing()) { // OUT_f
400 block = BlockFactory.createBlock("OUT_f");
401 ExplicitInputPort port = new ExplicitInputPort();
402 port.setDefaultValues();
404 link.setPortNumber(maxValues.get(0) + 1);
405 maxValues.set(0, maxValues.get(0) + 1);
407 block = BlockFactory.createBlock("IN_f");
408 ExplicitOutputPort port = new ExplicitOutputPort();
409 port.setDefaultValues();
411 link.setPortNumber(maxValues.get(1) + 1);
412 maxValues.set(1, maxValues.get(1) + 1);
414 } else if (link.getLink() instanceof ImplicitLink) {
415 if (link.getOutGoing()) { // OUTIMPL_f
416 block = BlockFactory.createBlock("OUTIMPL_f");
417 ImplicitInputPort port = new ImplicitInputPort();
418 port.setDefaultValues();
420 link.setPortNumber(maxValues.get(2) + 1);
421 maxValues.set(2, maxValues.get(2) + 1);
423 block = BlockFactory.createBlock("INIMPL_f");
424 ImplicitOutputPort port = new ImplicitOutputPort();
425 port.setDefaultValues();
427 link.setPortNumber(maxValues.get(3) + 1);
428 maxValues.set(3, maxValues.get(3) + 1);
430 } else if (link.getLink() instanceof CommandControlLink) {
431 if (link.getOutGoing()) { // CLKOUTV_f
432 block = BlockFactory.createBlock("CLKOUTV_f");
433 ControlPort port = new ControlPort();
434 port.setDefaultValues();
436 link.setPortNumber(maxValues.get(4) + 1);
437 maxValues.set(4, maxValues.get(4) + 1);
439 block = BlockFactory.createBlock("CLKINV_f");
440 CommandPort port = new CommandPort();
441 port.setDefaultValues();
443 link.setPortNumber(maxValues.get(5) + 1);
444 maxValues.set(5, maxValues.get(5) + 1);
448 block.setGeometry(link.getGeometry());
449 block.setExprs(new ScilabString(Integer.toString(link
451 block.setRealParameters(new ScilabDouble());
452 block.setIntegerParameters(new ScilabDouble(link.getPortNumber()));
453 block.setObjectsParameters(new ScilabList());
455 diagram.getModel().beginUpdate();
456 diagram.addCells(new Object[] { block });
457 diagram.getModel().endUpdate();
460 * create new link in SuperBlock
462 BasicLink newLink = null;
463 if (link.getOutGoing()) { // old -> new
465 .createLinkFromPorts((BasicPort) link.getLink()
466 .getSource(), (BasicPort) block.getChildAt(0));
467 newLink.setGeometry(link.getLink().getGeometry());
468 newLink.setSource((BasicPort) link.getCopiedEdge());
469 newLink.setTarget((BasicPort) block.getChildAt(0));
470 } else { // new -> old
471 newLink = BasicLink.createLinkFromPorts((BasicPort) block
472 .getChildAt(0), (BasicPort) link.getLink().getTarget());
473 newLink.setGeometry(link.getLink().getGeometry());
474 newLink.setSource((BasicPort) block.getChildAt(0));
475 newLink.setTarget((BasicPort) link.getCopiedEdge());
478 diagram.getModel().beginUpdate();
479 diagram.addCell(newLink);
480 diagram.getModel().endUpdate();
486 * Getting the broken links on the diagram and construct a list of these links
487 * @param objs The selected cells
488 * @param copiedCells The copy of the selected cells
489 * @return all the broken links in the diagram
491 private List<BrokenLink> getBrokenLinks(List<XcosUIDObject> objs, List<XcosUIDObject> copiedCells) {
492 List<BrokenLink> breaks = new ArrayList<BrokenLink>();
494 int objs_length = objs.size();
495 for (int i = 0; i < objs_length; i++) {
496 if (objs.get(i) instanceof BasicBlock) {
497 BasicBlock block = (BasicBlock) objs.get(i);
498 for (int j = 0; j < block.getChildCount(); j++) {
499 BasicPort port = (BasicPort) block.getChildAt(j);
500 if (port.getEdgeCount() != 0) {
501 BasicLink link = (BasicLink) port.getEdgeAt(0);
502 if (block.getChildAt(j) instanceof InputPort
503 || block.getChildAt(j) instanceof ControlPort) {
504 BasicBlock source = (BasicBlock) (link.getSource()
506 if (!objs.contains(source)) {
507 BasicPort copiedPort = (BasicPort) ((BasicBlock)copiedCells.get(i)).getChildAt(j);
508 breaks.add(new BrokenLink(link, copiedPort, source.getGeometry(), false));
510 } else { // OutputPort or CommandPort
511 BasicBlock target = (BasicBlock) (link.getTarget().getParent());
512 if (!objs.contains(target)) {
513 BasicPort copiedPort = (BasicPort) ((BasicBlock)copiedCells.get(i)).getChildAt(j);
514 breaks.add(new BrokenLink(link, copiedPort, target.getGeometry(), true));
525 * Check if an object is in a collection
526 * @param objs collection
527 * @param item the searched item
530 private boolean isInSelection(Object[] objs, Object item) {
531 return Arrays.asList(objs).contains(item);
534 private void printBreakingLink(List<BrokenLink> breaks) {
535 System.err.println("breaks count : " + breaks.size());
537 for (BrokenLink brk : breaks) {
538 System.err.println("Link : " + brk.getLink());
539 System.err.println("OutGoing : " + brk.getOutGoing());
540 System.err.println("Geometry : " + brk.getGeometry());
544 private List<Integer> getMaxBlocksValues(List<XcosUIDObject> blocks) {
545 List<Integer> values = new ArrayList<Integer>();
546 Map<ContextUpdate.IOBlocks, List<BasicBlock>> items = new EnumMap<ContextUpdate.IOBlocks, List<BasicBlock>>(ContextUpdate.IOBlocks.class);
549 for (XcosUIDObject cell : blocks) {
550 if (cell instanceof ContextUpdate) {
551 if (cell instanceof ExplicitOutBlock) {
552 if (!items.containsKey(IOBlocks.ExplicitInBlock)) {
553 items.put(IOBlocks.ExplicitOutBlock, new ArrayList<BasicBlock>());
555 items.get(IOBlocks.ExplicitOutBlock).add((BasicBlock) cell);
556 } else if (cell instanceof ExplicitInBlock) {
557 if (!items.containsKey(IOBlocks.ExplicitInBlock)) {
558 items.put(IOBlocks.ExplicitInBlock, new ArrayList<BasicBlock>());
560 items.get(IOBlocks.ExplicitInBlock).add((BasicBlock) cell);
561 } else if (cell instanceof ImplicitOutBlock) {
562 if (!items.containsKey(IOBlocks.ImplicitOutBlock)) {
563 items.put(IOBlocks.ImplicitOutBlock, new ArrayList<BasicBlock>());
565 items.get(IOBlocks.ImplicitOutBlock).add((BasicBlock) cell);
566 } else if (cell instanceof ImplicitInBlock) {
567 if (!items.containsKey(IOBlocks.ImplicitInBlock)) {
568 items.put(IOBlocks.ImplicitInBlock, new ArrayList<BasicBlock>());
570 items.get(IOBlocks.ImplicitInBlock).add((BasicBlock) cell);
571 } else if (cell instanceof EventOutBlock) {
572 if (!items.containsKey(IOBlocks.EventOutBlock)) {
573 items.put(IOBlocks.EventOutBlock, new ArrayList<BasicBlock>());
575 items.get(IOBlocks.EventOutBlock).add((BasicBlock) cell);
576 } else if (cell instanceof EventInBlock) {
577 if (!items.containsKey(IOBlocks.EventInBlock)) {
578 items.put(IOBlocks.EventInBlock, new ArrayList<BasicBlock>());
580 items.get(IOBlocks.EventInBlock).add((BasicBlock) cell);
585 for (IOBlocks klass : ContextUpdate.IOBlocks.values()) {
586 values.add(getMaxValue(items.get(klass)));
592 private int getMaxValue(List<BasicBlock> blocks) {
594 if (blocks != null) {
595 for (int i = 0; i < blocks.size(); i++) {
596 if (((BasicBlock) blocks.get(i)).getExprs() instanceof ScilabString) {
597 maxValue = Math.max(maxValue, Integer
598 .parseInt(((ScilabString) ((BasicBlock) blocks
599 .get(i)).getExprs()).getData()[0][0]));
603 // System.err.println("maxValue : " + maxValue);