* Bug #14659 fixed: number of I/O ports of the superblock was not updated when adding...
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / actions / RegionToSuperblockAction.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - DIGITEO - Clement DAVID
4  * Copyright (C) 2011-2016 - Scilab Enterprises - Clement DAVID
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.xcos.block.actions;
18
19 import java.awt.event.ActionEvent;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.LinkedList;
23 import java.util.Queue;
24 import java.util.TreeSet;
25 import java.util.logging.Logger;
26
27 import org.scilab.modules.graph.ScilabComponent;
28 import org.scilab.modules.graph.ScilabGraph;
29 import org.scilab.modules.graph.actions.base.VertexSelectionDependantAction;
30 import org.scilab.modules.gui.menuitem.MenuItem;
31 import org.scilab.modules.xcos.block.BasicBlock;
32 import org.scilab.modules.xcos.block.SuperBlock;
33 import org.scilab.modules.xcos.block.io.ContextUpdate;
34 import org.scilab.modules.xcos.block.io.ContextUpdate.IOBlocks;
35 import org.scilab.modules.xcos.graph.XcosDiagram;
36 import org.scilab.modules.xcos.link.BasicLink;
37 import org.scilab.modules.xcos.port.BasicPort;
38 import org.scilab.modules.xcos.port.control.ControlPort;
39 import org.scilab.modules.xcos.port.input.InputPort;
40 import org.scilab.modules.xcos.port.output.OutputPort;
41 import org.scilab.modules.xcos.utils.BlockPositioning;
42 import org.scilab.modules.xcos.utils.XcosMessages;
43
44 import com.mxgraph.model.mxGeometry;
45 import com.mxgraph.model.mxGraphModel;
46 import com.mxgraph.model.mxICell;
47 import com.mxgraph.util.mxRectangle;
48 import java.nio.LongBuffer;
49 import java.rmi.server.UID;
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.logging.Level;
55 import static java.util.stream.Collectors.toList;
56 import org.scilab.modules.action_binding.highlevel.ScilabInterpreterManagement;
57 import org.scilab.modules.graph.utils.StyleMap;
58 import org.scilab.modules.types.ScilabString;
59 import org.scilab.modules.xcos.JavaController;
60 import org.scilab.modules.xcos.Kind;
61 import org.scilab.modules.xcos.ObjectProperties;
62 import org.scilab.modules.xcos.VectorOfDouble;
63 import org.scilab.modules.xcos.VectorOfInt;
64 import org.scilab.modules.xcos.VectorOfScicosID;
65 import static org.scilab.modules.xcos.graph.XcosDiagram.EIN;
66 import static org.scilab.modules.xcos.graph.XcosDiagram.EOUT;
67 import static org.scilab.modules.xcos.graph.XcosDiagram.IN;
68 import static org.scilab.modules.xcos.graph.XcosDiagram.OUT;
69 import static org.scilab.modules.xcos.graph.XcosDiagram.UpdateSuperblockPortsTracker.syncPorts;
70 import org.scilab.modules.xcos.graph.model.XcosCell;
71 import org.scilab.modules.xcos.graph.model.XcosCellFactory;
72 import org.scilab.modules.xcos.io.ScilabTypeCoder;
73 import org.scilab.modules.xcos.utils.XcosConstants;
74
75 /**
76  * Move the Selected cells to a new SuperBlock diagram
77  */
78 // CSOFF: ClassFanOutComplexity
79 @SuppressWarnings(value = { "serial" })
80 public class RegionToSuperblockAction extends VertexSelectionDependantAction {
81     /** Name of the action */
82     public static final String NAME = XcosMessages.REGION_TO_SUPERBLOCK;
83     /** Icon name of the action */
84     public static final String SMALL_ICON = "object-group";
85     /** Mnemonic key of the action */
86     public static final int MNEMONIC_KEY = 0;
87     /** Accelerator key for the action */
88     public static final int ACCELERATOR_KEY = 0;
89
90     private static final String INTERFUNCTION_NAME = "SUPER_f";
91
92     /**
93      * Default Constructor
94      *
95      * @param scilabGraph
96      *            the graph
97      */
98     public RegionToSuperblockAction(ScilabGraph scilabGraph) {
99         super(scilabGraph);
100     }
101
102     /**
103      * @param scilabGraph
104      *            graph
105      * @return menu item
106      */
107     public static MenuItem createMenu(ScilabGraph scilabGraph) {
108         return createMenu(scilabGraph, RegionToSuperblockAction.class);
109     }
110
111     /**
112      * Represent a broken link at selection time
113      */
114     private static final class Broken implements Comparable<Broken> {
115         private final mxGraphModel parentModel;
116
117         private final BasicPort source;
118         private final BasicPort target;
119
120         private final BasicLink parentLink;
121         private final boolean containsSource;
122
123         /*
124          * Out of selection port position
125          */
126         private final double x;
127         private final double y;
128
129         /*
130          * lazy allocated fields
131          */
132         private BasicLink childLink;
133         private BasicPort parentPort;
134         private ContextUpdate childBlock;
135
136         /**
137          * Default Constructor
138          *
139          * @param parentGraph
140          *            the parent graph
141          * @param parentModel
142          *            the parent model
143          * @param source
144          *            the source
145          * @param target
146          *            the target
147          * @param link
148          *            the link
149          * @param containsSource
150          *            is the source in selection
151          */
152         public Broken(XcosDiagram parentGraph, mxGraphModel parentModel, BasicPort source, BasicPort target, BasicLink link, boolean containsSource) {
153             super();
154             this.parentModel = parentModel;
155
156             this.source = source;
157             this.target = target;
158             this.parentLink = link;
159             this.containsSource = containsSource;
160
161             final BasicPort terminal;
162             if (containsSource) {
163                 terminal = target;
164             } else {
165                 terminal = source;
166             }
167
168             /*
169              * Update position
170              */
171             final mxGeometry pos = parentModel.getGeometry(terminal);
172             final mxGeometry parent = parentModel.getGeometry(parentModel.getParent(terminal));
173             if (pos != null && parent != null) {
174                 this.x = parentGraph.snap(pos.getX() + parent.getX() - (pos.getHeight() / 2));
175                 this.y = parentGraph.snap(pos.getY() + parent.getY() - (pos.getWidth() / 2));
176             } else {
177                 this.x = 0.0;
178                 this.y = 0.0;
179             }
180         }
181
182         /**
183          * @return the link on the parent diagram
184          */
185         public BasicLink getParentLink() {
186             return parentLink;
187         }
188
189         /**
190          * @param isSource
191          *            is a source port needed
192          * @return the parent terminal (source or not)
193          */
194         public mxICell getParentTerminal(boolean isSource) {
195             final mxICell ret;
196
197             if (containsSource) {
198                 if (isSource) {
199                     ret = getParentPort();
200                 } else {
201                     ret = target;
202                 }
203             } else {
204                 if (isSource) {
205                     ret = source;
206                 } else {
207                     ret = getParentPort();
208                 }
209             }
210
211             return ret;
212         }
213
214         /**
215          * @param isSource
216          *            is a source port needed
217          * @return the child terminal (source or not)
218          */
219         public mxICell getChildTerminal(boolean isSource) {
220             final mxICell ret;
221
222             if (containsSource) {
223                 if (isSource) {
224                     ret = source;
225                 } else {
226                     ret = getChildBlock().getChildAt(0);
227                 }
228             } else {
229                 if (isSource) {
230                     ret = getChildBlock().getChildAt(0);
231                 } else {
232                     ret = target;
233                 }
234             }
235
236             return ret;
237         }
238
239         /**
240          * @return the terminal in the selection
241          */
242         public BasicPort getTerminal() {
243             if (containsSource) {
244                 return source;
245             } else {
246                 return target;
247             }
248         }
249
250         /**
251          * @return the link on the child diagram
252          */
253         public BasicLink getChildLink() {
254             if (childLink == null) {
255                 childLink = (BasicLink) parentModel.cloneCells(new Object[] { parentLink }, true)[0];
256             }
257             return childLink;
258         }
259
260         /**
261          * @return the port on the parent diagram
262          */
263         public BasicPort getParentPort() {
264             if (parentPort == null) {
265                 JavaController controller = new JavaController();
266                 long uid = controller.createObject(Kind.PORT);
267
268                 try {
269                     if (containsSource) {
270                         parentPort = IOBlocks.getOpposite(target.getClass())
271                                      .getConstructor(JavaController.class, Long.TYPE, Kind.class, Object.class, String.class, String.class)
272                                      .newInstance(controller, uid, Kind.PORT, null, null, new UID().toString());
273                     } else {
274                         parentPort = IOBlocks.getOpposite(source.getClass())
275                                      .getConstructor(JavaController.class, Long.TYPE, Kind.class, Object.class, String.class, String.class)
276                                      .newInstance(controller, uid, Kind.PORT, null, null, new UID().toString());;
277                     }
278                 } catch (ReflectiveOperationException e) {
279                     Logger.getLogger(RegionToSuperblockAction.class.getName()).severe(e.toString());
280                 } catch (IllegalArgumentException ex) {
281                     Logger.getLogger(RegionToSuperblockAction.class.getName()).log(Level.SEVERE, null, ex);
282                 }
283             }
284
285             return parentPort;
286         }
287
288         /**
289          * @return the child block to put on the child diagram
290          */
291         public ContextUpdate getChildBlock() {
292             if (childBlock == null) {
293                 final BasicPort terminal = getTerminal();
294                 childBlock = IOBlocks.createBlock(terminal);
295
296                 /*
297                  * Set the child position
298                  */
299                 mxGeometry geom = childBlock.getGeometry();
300                 geom.setX(x);
301                 geom.setY(y);
302                 childBlock.setGeometry(geom);
303             }
304
305             return childBlock;
306         }
307
308         /**
309          * Set the ordering on the I/O block and port
310
311          * @param ordering
312          *            the ordering to set
313          */
314         public void setOrdering(JavaController controller, int ordering) {
315             // update the child ordering
316             VectorOfInt ipar = new VectorOfInt(1);
317             ipar.set(0, ordering);
318             controller.setObjectProperty(getChildBlock().getUID(), getChildBlock().getKind(), ObjectProperties.IPAR, ipar);
319
320             VectorOfDouble exprs = new ScilabTypeCoder().var2vec(new ScilabString(Integer.toString(ordering)));
321             controller.setObjectProperty(getChildBlock().getUID(), getChildBlock().getKind(), ObjectProperties.EXPRS, exprs);
322         }
323
324         /**
325          * {@inheritDoc}
326          *
327          * This function is used to sort a {@link TreeSet} of {@link Broken}.
328          */
329         @Override
330         public int compareTo(Broken o) {
331             final int xdiff = (int) (x - o.x);
332             final int ydiff = (int) (y - o.y);
333
334             if (xdiff == 0 && ydiff == 0) {
335                 // same position, sort by hashcode
336                 return hashCode() - o.hashCode();
337             } else {
338                 return (ydiff << (Integer.SIZE / 2)) + xdiff;
339             }
340         }
341
342         /**
343          * {@inheritDoc}
344          */
345         @Override
346         public String toString() {
347             final String labelSep = ": ";
348             final String link = " -> ";
349
350             final StringBuilder str = new StringBuilder();
351             if (getParentLink().getChildCount() > 0) {
352                 // append the label
353                 str.append(getParentLink().getChildAt(0).getValue());
354                 str.append(labelSep);
355             }
356
357             str.append(getParentTerminal(true));
358             str.append(link);
359             str.append(getParentTerminal(false));
360
361             str.append('\n');
362
363             if (getChildLink().getChildCount() > 0) {
364                 // append the label
365                 str.append(getChildLink().getChildAt(0).getValue());
366                 str.append(labelSep);
367             }
368
369             str.append(getChildTerminal(true));
370             str.append(link);
371             str.append(getChildTerminal(false));
372
373             return str.toString();
374         }
375     }
376
377     /**
378      * {@inheritDoc}
379      */
380     @Override
381     public void actionPerformed(ActionEvent e) {
382         final XcosDiagram parentGraph = (XcosDiagram) getGraph(e);
383
384         // action disabled when the cell is edited
385         final ScilabComponent comp = ((ScilabComponent) parentGraph.getAsComponent());
386         if (comp.isEditing()) {
387             return;
388         }
389
390         parentGraph.info(XcosMessages.GENERATE_SUPERBLOCK);
391         parentGraph.getModel().beginUpdate();
392         try {
393             final JavaController controller = new JavaController();
394             final SuperBlock superBlock;
395             final Collection<Broken> brokenLinks;
396
397             /*
398              * Allocate superBlock
399              */
400             final Object[] selection = parentGraph.getSelectionCells();
401             List<XcosCell> toBeMoved = Arrays.stream(selection)
402                                        .filter(o -> o instanceof XcosCell)
403                                        .map(o -> (XcosCell) o)
404                                        .collect(toList());
405
406             superBlock = allocateSuperBlock(controller, parentGraph, selection);
407
408             /*
409              * First perform all modification on the parent diagram to handle
410              * well undo/redo operations.
411              */
412             brokenLinks = updateParent(controller, parentGraph, superBlock, toBeMoved);
413
414             /*
415              * Then move some cells to the child diagram
416              */
417             moveToChild(controller, parentGraph, superBlock, brokenLinks, toBeMoved);
418
419             /*
420              * Append the port to the superblock (in case of IN_f / OUT_f selected)
421              */
422             updateIO(controller, parentGraph, superBlock, toBeMoved);
423
424             BlockPositioning.updateBlockView(parentGraph, superBlock);
425         } catch (ScilabInterpreterManagement.InterpreterException ex) {
426             // Scilab seems to be blocked, just consume the exception at this point
427         } finally {
428             parentGraph.getModel().endUpdate();
429             parentGraph.info(XcosMessages.EMPTY_INFO);
430         }
431     }
432
433     /**
434      * Allocate a superBlock
435      *
436      * @param parentGraph
437      *            the base graph
438      * @param selection
439      *            the selected blocks
440      * @return the allocated super block (without specific listeners)
441      */
442     private SuperBlock allocateSuperBlock(final JavaController controller, final XcosDiagram parentGraph, final Object[] selection) throws ScilabInterpreterManagement.InterpreterException {
443         final SuperBlock superBlock = (SuperBlock) XcosCellFactory.createBlock(INTERFUNCTION_NAME);
444
445         /*
446          * Remove the default allocated ports
447          */
448         while (superBlock.getChildCount() > 0) {
449             superBlock.remove(superBlock.getChildCount() - 1);
450         }
451         VectorOfScicosID children = new VectorOfScicosID();
452         controller.setObjectProperty(superBlock.getUID(), superBlock.getKind(), ObjectProperties.CHILDREN, children);
453
454         /*
455          * Place the super block
456          */
457         final mxRectangle dims = parentGraph.getBoundingBoxFromGeometry(selection);
458         final double minX = dims.getX();
459         final double maxX = minX + dims.getWidth();
460
461         final double minY = dims.getY();
462         final double maxY = minY + dims.getHeight();
463
464         mxGeometry geom = superBlock.getGeometry();
465         geom.setX((maxX + minX - geom.getWidth()) / 2.0);
466         geom.setY((maxY + minY - geom.getHeight()) / 2.0);
467         superBlock.setGeometry(geom);
468
469         /*
470          * get statistics to flip and rotate
471          */
472         VectorOfDouble mvcAngle = new VectorOfDouble();
473
474         int angleCounter = 0;
475         int flipCounter = 0;
476         int mirrorCounter = 0;
477         for (Object object : selection) {
478             if (object instanceof BasicBlock) {
479                 final BasicBlock b = (BasicBlock) object;
480
481                 String[] style = new String[1];
482                 controller.getObjectProperty(b.getUID(), Kind.BLOCK, ObjectProperties.STYLE, style);
483                 StyleMap styleMap = new StyleMap(style[0]);
484
485                 final boolean mirrored = Boolean.TRUE.toString().equals(styleMap.get(XcosConstants.STYLE_MIRROR));
486                 final boolean flipped = Boolean.TRUE.toString().equals(styleMap.get(XcosConstants.STYLE_FLIP));
487                 final int intRotation = Double.valueOf(styleMap.getOrDefault(XcosConstants.STYLE_ROTATION, "0")).intValue();
488
489                 angleCounter += intRotation;
490                 if (flipped) {
491                     flipCounter++;
492                 }
493                 if (mirrored) {
494                     mirrorCounter++;
495                 }
496             }
497         }
498
499         /*
500          * apply statistics to flip and rotate
501          */
502         final int halfSize = selection.length / 2;
503         String[] style = new String[1];
504         controller.getObjectProperty(superBlock.getUID(), superBlock.getKind(), ObjectProperties.STYLE, style);
505         StyleMap styleMap = new StyleMap(style[0]);
506
507         styleMap.put(XcosConstants.STYLE_ROTATION, Integer.toString(BlockPositioning.roundAngle(angleCounter / selection.length)));
508         if (flipCounter > halfSize) {
509             styleMap.put(XcosConstants.STYLE_FLIP, Boolean.toString(true));
510         }
511         if (mirrorCounter > halfSize) {
512             styleMap.put(XcosConstants.STYLE_MIRROR, Boolean.toString(true));
513         }
514
515         controller.setObjectProperty(superBlock.getUID(), superBlock.getKind(), ObjectProperties.STYLE, styleMap.toString());
516
517         return superBlock;
518     }
519
520     /**
521      * Create child cells and add them to the parent diagram. All links are also
522      * reconnected
523      *
524      * @param parentGraph
525      *            the parent diagram
526      * @param superBlock
527      *            the superblock
528      * @param inSelectionCells
529      *            the cells in the selection
530      * @return the broken descriptor set
531      */
532     private Collection<Broken> updateParent(final JavaController controller, final XcosDiagram parentGraph, final SuperBlock superBlock, final List<XcosCell> inSelectionCells) {
533         final Collection<Broken> brokenLinks;
534         final mxGraphModel parentModel = (mxGraphModel) parentGraph.getModel();
535
536         parentModel.beginUpdate();
537         try {
538             /*
539              * Add the internal links and fill border links Sort the broken
540              * links by position (to perform a good numbering order) and keep
541              * only one occurrence of a broken link.
542              */
543             brokenLinks = new TreeSet<>();
544             fillLinks(parentGraph, parentModel, inSelectionCells, brokenLinks);
545
546             /*
547              * Disconnect the broken links
548              */
549             for (Broken broken : brokenLinks) {
550                 mxGraphModel.setTerminals(parentModel, broken.getParentLink(), null, null);
551             }
552
553             /*
554              * Add the super block
555              */
556             parentGraph.addCell(superBlock);
557
558             /*
559              * Main broken loop
560              */
561             // ordering access is : IN, OUT, e_IN, e_OUT
562             final int[] ordering = { 0, 0, 0, 0 };
563             for (Broken broken : brokenLinks) {
564
565                 // set the ordering
566                 incrementOrdering(controller, ordering, broken);
567
568                 connectParent(parentGraph, parentModel, superBlock, broken);
569                 connectChild(parentGraph, parentModel, broken);
570
571                 /*
572                  * Update the view
573                  */
574                 BlockPositioning.updateBlockView(parentGraph, broken.getChildBlock());
575             }
576         } finally {
577             parentModel.endUpdate();
578         }
579
580         return brokenLinks;
581     }
582
583     /**
584      * Fill the internalLinks links from a selected block to a selected block
585      * and broken links with a broken object. Also disconnect all the broken
586      * links.
587      *
588      * @param parentGraph
589      *            the graph
590      * @param parentModel
591      *            the model
592      * @param inSelectionCells
593      *            the selected blocks (with fast contains operation)
594      * @param brokenLinks
595      *            the broken links to find.
596      */
597     private void fillLinks(final XcosDiagram parentGraph, final mxGraphModel parentModel, final Collection<XcosCell> inSelectionCells, final Collection<Broken> brokenLinks) {
598         final Queue<Object> loopQueue = new LinkedList<>(inSelectionCells);
599
600         while (!loopQueue.isEmpty()) {
601             final Object cell = loopQueue.remove();
602
603             final int childCount = parentModel.getChildCount(cell);
604             for (int i = 0; i < childCount; i++) {
605                 final Object port = parentModel.getChildAt(cell, i);
606
607                 final int edgeCount = parentModel.getEdgeCount(port);
608                 for (int j = 0; j < edgeCount; j++) {
609                     final Object edge = parentModel.getEdgeAt(port, j);
610
611                     final Object source = parentModel.getTerminal(edge, true);
612                     final Object target = parentModel.getTerminal(edge, false);
613
614                     /*
615                      * Add the links
616                      */
617                     final boolean containsSource = inSelectionCells.contains(parentModel.getParent(source));
618                     final boolean containsTarget = inSelectionCells.contains(parentModel.getParent(target));
619
620                     if (containsSource && containsTarget && edge instanceof XcosCell) {
621                         inSelectionCells.add((XcosCell) edge);
622                         continue;
623                     }
624
625                     /*
626                      * Handle a broken link case
627                      */
628
629                     if (containsSource) {
630                         brokenLinks.add(new Broken(parentGraph, parentModel, (BasicPort) source, (BasicPort) target, (BasicLink) edge, true));
631                         continue;
632                     }
633
634                     if (containsTarget) {
635                         brokenLinks.add(new Broken(parentGraph, parentModel, (BasicPort) source, (BasicPort) target, (BasicLink) edge, false));
636                         continue;
637                     }
638                 }
639             }
640         }
641     }
642
643     /**
644      * Increment and set the ordering to the broken entry.
645      *
646      * @param controller the controller
647      * @param ordering
648      *            4x1 array of ordering
649      * @param broken
650      *            the current broken entry.
651      */
652     // CSOFF: MagicNumber
653     private void incrementOrdering(JavaController controller, final int[] ordering, Broken broken) {
654         if (broken.getTerminal() instanceof InputPort) {
655             broken.setOrdering(controller, ++ordering[0]);
656         } else if (broken.getTerminal() instanceof OutputPort) {
657             broken.setOrdering(controller, ++ordering[1]);
658         } else if (broken.getTerminal() instanceof ControlPort) {
659             broken.setOrdering(controller, ++ordering[2]);
660         } else { // if (broken.getTerminal() instanceof CommandPort)
661             broken.setOrdering(controller, ++ordering[3]);
662         }
663     }
664
665     // CSON: MagicNumber
666
667     /**
668      * Add I/O port and reconnect them
669      *
670      * @param parentGraph
671      *            the parent graph
672      * @param parentModel
673      *            the parent graph model
674      * @param superBlock
675      *            the super block
676      * @param broken
677      *            the broken entry
678      */
679     private void connectParent(final XcosDiagram parentGraph, final mxGraphModel parentModel, final SuperBlock superBlock, Broken broken) {
680         parentGraph.addCell(broken.getParentPort(), superBlock);
681         parentGraph.addCell(broken.getParentLink());
682
683         final mxICell source = broken.getParentTerminal(true);
684         final mxICell target = broken.getParentTerminal(false);
685
686         // then connect the link
687         mxGraphModel.setTerminals(parentModel, broken.getParentLink(), source, target);
688     }
689
690     /**
691      * Add I/O blocks and reconnect them
692      *
693      * @param childGraph
694      *            the child graph
695      * @param childModel
696      *            the child graph model
697      * @param broken
698      *            the broken entry
699      */
700     private void connectChild(final XcosDiagram childGraph, final mxGraphModel childModel, Broken broken) {
701         childGraph.addCell(broken.getChildBlock());
702         childGraph.addCell(broken.getChildLink());
703
704         final mxICell source = broken.getChildTerminal(true);
705         final mxICell target = broken.getChildTerminal(false);
706
707         // then connect the link
708         mxGraphModel.setTerminals(childModel, broken.getChildLink(), source, target);
709     }
710
711     /**
712      * Move the cells to the child graph
713      *
714      * @param parentGraph
715      *            the parent graph
716      * @param superBlock
717      *            the superBlock
718      * @param brokenLinks
719      *            the broken links set
720      * @param inSelectionCells
721      *            the cells in selection
722      * @return the superblock child diagram
723      */
724     private void moveToChild(final JavaController controller, final XcosDiagram parentGraph, final SuperBlock superBlock, final Collection<Broken> brokenLinks, final List<XcosCell> inSelectionCells) {
725         final Collection<XcosCell> cellsToCopy = new ArrayList<>();
726
727         /*
728          * create a collection with all the cells to move
729          */
730         cellsToCopy.addAll(inSelectionCells);
731         for (Broken b : brokenLinks) {
732             cellsToCopy.add(b.getChildBlock());
733             cellsToCopy.add(b.getChildLink());
734         }
735
736         /*
737          * Really move the cells
738          */
739         parentGraph.removeCells(cellsToCopy.toArray(), false);
740
741         VectorOfScicosID children = new VectorOfScicosID(cellsToCopy.size());
742         LongBuffer childrenUIDs = children.asByteBuffer(0, cellsToCopy.size()).asLongBuffer();
743
744         final long parentBlock = superBlock.getUID();
745         final long parentDiagram;
746         if (parentGraph.getKind() == Kind.DIAGRAM) {
747             parentDiagram = parentGraph.getUID();
748         } else {
749             parentDiagram = parentGraph.getRootDiagramUID(controller);
750         }
751
752         cellsToCopy.stream().forEach(c -> {
753             childrenUIDs.put(c.getUID());
754             controller.referenceObject(c.getUID());
755
756             controller.setObjectProperty(c.getUID(), c.getKind(), ObjectProperties.PARENT_BLOCK, parentBlock);
757             controller.setObjectProperty(c.getUID(), c.getKind(), ObjectProperties.PARENT_DIAGRAM, parentDiagram);
758         });
759
760         controller.setObjectProperty(superBlock.getUID(), superBlock.getKind(), ObjectProperties.CHILDREN, children);
761     }
762
763     /**
764      * Update the ports according to the IOBlocks moved
765      * @param controller the shared controller
766      * @param parent the parent diagram
767      * @param superblock the superblock cell
768      * @param toBeMoved the moved blocks
769      */
770     private void updateIO(JavaController controller, XcosDiagram parent, SuperBlock superblock, List<XcosCell> toBeMoved) {
771         Map<Object, Object> context = new HashMap<>();
772         XcosDiagram.UpdateSuperblockPortsTracker.updateContext(context, toBeMoved, controller);
773
774         syncPorts(controller, superblock, ObjectProperties.INPUTS, (List<ContextUpdate>) context.get(IN), parent);
775         syncPorts(controller, superblock, ObjectProperties.OUTPUTS, (List<ContextUpdate>) context.get(OUT), parent);
776         syncPorts(controller, superblock, ObjectProperties.EVENT_INPUTS, (List<ContextUpdate>) context.get(EIN), parent);
777         syncPorts(controller, superblock, ObjectProperties.EVENT_OUTPUTS, (List<ContextUpdate>) context.get(EOUT), parent);
778     }
779 }
780 // CSON: ClassFanOutComplexity