* Bug #12796 fixed - Mismatch with superblock ports between implicit
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / SuperBlock.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 package org.scilab.modules.xcos.block;
14
15 import java.io.IOException;
16 import java.util.Hashtable;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.logging.Logger;
20
21 import org.scilab.modules.graph.ScilabGraph;
22 import org.scilab.modules.gui.contextmenu.ContextMenu;
23 import org.scilab.modules.gui.menu.Menu;
24 import org.scilab.modules.gui.menu.ScilabMenu;
25 import org.scilab.modules.types.ScilabDouble;
26 import org.scilab.modules.types.ScilabList;
27 import org.scilab.modules.types.ScilabMList;
28 import org.scilab.modules.types.ScilabType;
29 import org.scilab.modules.xcos.Xcos;
30 import org.scilab.modules.xcos.XcosTab;
31 import org.scilab.modules.xcos.block.actions.CodeGenerationAction;
32 import org.scilab.modules.xcos.block.actions.SuperblockMaskCreateAction;
33 import org.scilab.modules.xcos.block.actions.SuperblockMaskCustomizeAction;
34 import org.scilab.modules.xcos.block.actions.SuperblockMaskRemoveAction;
35 import org.scilab.modules.xcos.block.io.ContextUpdate.IOBlocks;
36 import org.scilab.modules.xcos.graph.PaletteDiagram;
37 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
38 import org.scilab.modules.xcos.graph.XcosDiagram;
39 import org.scilab.modules.xcos.graph.swing.GraphComponent;
40 import org.scilab.modules.xcos.io.codec.XcosCodec;
41 import org.scilab.modules.xcos.io.scicos.DiagramElement;
42 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
43 import org.scilab.modules.xcos.port.BasicPort;
44 import org.scilab.modules.xcos.utils.FileUtils;
45 import org.scilab.modules.xcos.utils.XcosConstants;
46 import org.scilab.modules.xcos.utils.XcosEvent;
47 import org.scilab.modules.xcos.utils.XcosMessages;
48 import org.w3c.dom.Node;
49
50 import com.mxgraph.model.mxICell;
51 import com.mxgraph.util.mxEvent;
52 import com.mxgraph.util.mxEventObject;
53
54 /**
55  * A SuperBlock contains an entire diagram on it. Thus it can be easily
56  * customized by the user.
57  *
58  * A SuperBlock can be created from any part of the diagram y selecting blocks
59  * and applying the
60  * {@link org.scilab.modules.xcos.block.actions.RegionToSuperblockAction}.
61  *
62  * It can also appear to users as a normal block by applying a mask on it. In
63  * this case the creator can use any SuperBlock context defined variable on a
64  * prompt to the user.
65  *
66  * @see SuperBlockDiagram
67  * @see SuperblockMaskCreateAction
68  * @see SuperblockMaskCustomizeAction
69  * @see SuperblockMaskRemoveAction
70  */
71 // CSOFF: ClassDataAbstractionCoupling
72 // CSOFF: ClassFanOutComplexity
73 @SuppressWarnings(value = { "serial" })
74 public final class SuperBlock extends BasicBlock {
75     /**
76      * The interfunction name (linked to Xcos-core)
77      */
78     public static final String INTERFUNCTION_NAME = "SUPER_f";
79
80     /**
81      * The simulation name (linked to Xcos-core)
82      */
83     private static final String SIMULATION_NAME = "super";
84     /**
85      * The simulation name on a masked status (linked to Xcos-core)
86      */
87     private static final String MASKED_SIMULATION_NAME = "csuper";
88     /**
89      * The interfunction name on a masked status (linked to Xcos-core)
90      */
91     private static final String MASKED_INTERFUNCTION_NAME = "DSUPER";
92
93     private SuperBlockDiagram child;
94
95     /**
96      * Constructor
97      */
98     public SuperBlock() {
99         super();
100     }
101
102     /**
103      * @param label
104      *            block label
105      */
106     protected SuperBlock(String label) {
107         this();
108         setValue(label);
109     }
110
111     /**
112      * @param masked
113      *            masked super block
114      */
115     protected SuperBlock(boolean masked) {
116         this();
117         if (masked) {
118             mask();
119         }
120     }
121
122     /**
123      * @param label
124      *            block label
125      * @param masked
126      *            masked super block
127      */
128     protected SuperBlock(String label, boolean masked) {
129         this(label);
130         if (masked) {
131             mask();
132         }
133     }
134
135     /**
136      * Initialize the block with the default values
137      */
138     @Override
139     protected void setDefaultValues() {
140         super.setDefaultValues();
141         setInterfaceFunctionName(INTERFUNCTION_NAME);
142         setSimulationFunctionName(SIMULATION_NAME);
143         setRealParameters(new ScilabMList());
144         setIntegerParameters(new ScilabDouble());
145         setObjectsParameters(new ScilabList());
146         setExprs(new ScilabDouble());
147         setBlockType("h");
148         setNbZerosCrossing(new ScilabDouble(0));
149         setNmode(new ScilabDouble(0));
150     }
151
152     @Override
153     public ScilabType getRealParameters() {
154         if (child == null) {
155             return super.getRealParameters();
156         }
157
158         /*
159          * Encode the children as a new rpar.
160          */
161         final ScilabType rpar = new DiagramElement().encode(child);
162         super.setRealParameters(rpar);
163         hasAValidRpar = true;
164
165         return super.getRealParameters();
166     }
167
168     /**
169      * openBlockSettings this method is called when a double click occurred on a
170      * super block
171      *
172      * @param context
173      *            parent diagram context
174      * @see BasicBlock#openBlockSettings(String[])
175      */
176     @Override
177     public void openBlockSettings(String[] context) {
178
179         // prevent to open twice
180         if (isLocked()) {
181             return;
182         }
183
184         /*
185          * Do nothing when something happen on the Palette
186          */
187         if (getParentDiagram() instanceof PaletteDiagram) {
188             return;
189         }
190
191         /*
192          * Specific case when we want to generate code.
193          */
194         if (getChild() == null && getSimulationFunctionType().compareTo(SimulationFunctionType.DEFAULT) != 0) {
195             return;
196         }
197
198         /*
199          * When the block is masked it perform actions like any other blocks.
200          */
201         if (isMasked()) {
202             super.openBlockSettings(context);
203             return;
204         }
205
206         try {
207             // Lock the block because we are really performing actions
208             setLocked(true);
209
210             /*
211              * Compatibility with older diagrams.
212              *
213              * Before Scilab 5.2.2, saved diagrams don't contains XML children
214              * but use a pseudo scs_m structure instead.
215              *
216              * In this case child was null and we need to reconstruct child
217              * diagram from scs_m.
218              */
219             if (getChild() == null || getChild().getChildVertices(getChild().getDefaultParent()).length == 0) {
220                 child = null;
221                 createChildDiagram();
222             } else {
223                 // reassociate (useful on clone and load operation)
224                 getChild().setContainer(this);
225                 getChild().setComponent(new GraphComponent(getChild()));
226
227                 getChild().initComponent();
228                 getChild().installStylesheet();
229
230                 getChild().installListeners();
231                 getChild().installSuperBlockListeners();
232             }
233
234             /*
235              * Construct the view or set it visible.
236              */
237             if (XcosTab.get(getChild()) == null) {
238                 XcosTab.restore(getChild());
239             } else {
240                 XcosTab.get(getChild()).setCurrent();
241             }
242
243             getChild().setModifiedNonRecursively(false);
244
245             getChild().getAsComponent().validateGraph();
246             getChild().fireEvent(new mxEventObject(mxEvent.ROOT));
247             getChild().getView().invalidate();
248
249             /*
250              * Update the cells from the context values.
251              */
252             getChild().updateCellsContext();
253         } finally {
254             setLocked(false);
255         }
256     }
257
258     /**
259      * @param graph
260      *            parent diagram
261      */
262     @Override
263     public void openContextMenu(ScilabGraph graph) {
264         ContextMenu menu = null;
265
266         if (getParentDiagram() instanceof PaletteDiagram) {
267             menu = createPaletteContextMenu(graph);
268         } else {
269             menu = createContextMenu(graph);
270             menu.getAsSimpleContextMenu().addSeparator();
271             menu.add(CodeGenerationAction.createMenu(graph));
272
273             Menu maskMenu = ScilabMenu.createMenu();
274             maskMenu.setText(XcosMessages.SUPERBLOCK_MASK);
275
276             if (isMasked()) {
277                 maskMenu.add(SuperblockMaskRemoveAction.createMenu(graph));
278                 menu.add(maskMenu);
279             } else {
280                 maskMenu.add(SuperblockMaskCreateAction.createMenu(graph));
281             }
282             maskMenu.add(SuperblockMaskCustomizeAction.createMenu(graph));
283             menu.add(maskMenu);
284
285         }
286         menu.setVisible(true);
287     }
288
289     /**
290      * @return status
291      */
292     public boolean createChildDiagram() {
293         return createChildDiagram(false);
294     }
295
296     /**
297      * @param generatedUID
298      *            does we need to generated a new unique ID
299      * @return status
300      */
301     public boolean createChildDiagram(boolean generatedUID) {
302         if (child == null) {
303             final ScilabType rpar = getRealParameters();
304
305             final DiagramElement element = new DiagramElement();
306             if (!element.canDecode(rpar)) {
307                 return false;
308             }
309
310             child = new SuperBlockDiagram(this);
311             child.installListeners();
312
313             try {
314                 element.decode(rpar, child, false);
315             } catch (ScicosFormatException e) {
316                 Logger.getLogger(SuperBlock.class.getName()).severe(e.toString());
317                 return false;
318             }
319
320             child.installSuperBlockListeners();
321
322             final XcosDiagram parent = Xcos.findParent(this);
323             if (parent != null) {
324                 Xcos.getInstance().addDiagram(parent.getSavedFile(), child);
325             }
326         } else {
327             return false;
328         }
329
330         return true;
331     }
332
333     /**
334      * @return diagram
335      */
336     public SuperBlockDiagram getChild() {
337         return child;
338     }
339
340     /**
341      * @param child
342      *            update diagram
343      */
344     public void setChild(SuperBlockDiagram child) {
345         this.child = child;
346     }
347
348     /**
349      * Function that insert one port on the concerned superblock
350      * and gives it the right order.
351      * 
352      * @param order
353      * @param basicblock
354      */
355     private void insertOnePort(int order, BasicBlock basicblock) {
356         try {
357             for (IOBlocks b : IOBlocks.values()) {
358                 if (basicblock.getClass().equals(b.getReferencedClass())) {
359                     BasicPort port;
360                     port = b.getReferencedPortClass().newInstance();
361                     port.setOrdering(order);
362                     insert(port);
363                 }
364             }
365         } catch (InstantiationException e) {
366             Logger.getLogger(SuperBlock.class.getName()).severe(e.toString());
367         } catch (IllegalAccessException e) {
368             Logger.getLogger(SuperBlock.class.getName()).severe(e.toString());
369         } catch (Exception e)
370         {
371             Logger.getLogger(SuperBlock.class.getName()).severe(e.toString());
372         }
373     }
374
375     /**
376      * Function that remove one port on the concerned superblock
377      * 
378      * @param order
379      * @param basicport
380      * @param basicblock
381      * @return
382      */
383     private boolean removeOnePort(int order, BasicPort basicport, BasicBlock basicblock) {
384         boolean port_deleted = false;
385
386         for (IOBlocks b : IOBlocks.values()) {
387             if (basicport.getClass().equals(b.getReferencedPortClass())) {
388                 if (!basicblock.getClass().equals(b.getReferencedClass())) {
389                     // delete the port
390                     removePort(basicport);
391                     port_deleted = true;
392                 }
393             }
394         }
395
396         return port_deleted;
397     }
398
399     /**
400      * 
401      * @param basicport
402      */
403     private void removeOnePort(BasicPort basicport) {
404         // delete the port
405         removePort(basicport);
406     }
407
408     /**
409      * Function that returns a hashtable of IOBlocks contained in the superdiagram
410      * depending on their direction.
411      * 
412      * @param blockMap
413      *            a map of blocks
414      * @return the hashtable
415      */
416     private Hashtable<String, List<? extends mxICell>> extractContextBlocks() {
417         // get a map of all the IOBlocks of the superdiagram
418         final Map<IOBlocks, List<BasicBlock>> blocksMap = IOBlocks.getAllBlocks(this);
419
420         // create a map of all the blocks of the superdiagram depending on their type
421         Hashtable<String, List<? extends mxICell>> context_block = new Hashtable<String, List<? extends mxICell>> ();
422
423         if (!context_block.containsKey(XcosDiagram.IN)) {
424             List<BasicBlock> cell_list = blocksMap.get(IOBlocks.ExplicitInBlock);
425             cell_list.addAll(blocksMap.get(IOBlocks.ImplicitInBlock));
426             context_block.put(XcosDiagram.IN, cell_list);
427         }
428         if (!context_block.containsKey(XcosDiagram.OUT)) {
429             List<BasicBlock> cell_list = blocksMap.get(IOBlocks.ExplicitOutBlock);
430             cell_list.addAll(blocksMap.get(IOBlocks.ImplicitOutBlock));
431             context_block.put(XcosDiagram.OUT, cell_list);
432         }
433         if (!context_block.containsKey(XcosDiagram.EIN)) {
434             List<BasicBlock> cell_list = blocksMap.get(IOBlocks.EventInBlock);
435             context_block.put(XcosDiagram.EIN, cell_list);
436         }
437         if (!context_block.containsKey(XcosDiagram.EOUT)) {
438             List<BasicBlock> cell_list = blocksMap.get(IOBlocks.EventOutBlock);
439             context_block.put(XcosDiagram.EOUT, cell_list);
440         }
441
442         return context_block;
443     }
444
445     /**
446      * Function that returns a hashtable of the superblock ports
447      * depending on their direction.
448      * 
449      * @param portsMap
450      *            a map of ports
451      * @return the hashtable
452      */
453     private Hashtable<String, List<? extends mxICell>> extractContextPorts() {
454         // get a map of all the ports of the superblock
455         final Map<IOBlocks, List<mxICell>> portsMap = IOBlocks.getAllPorts(this);
456
457         // create a map of all the ports of the superblock depending on their type
458         Hashtable<String, List<? extends mxICell>> context_port = new Hashtable<String, List<? extends mxICell>> ();
459
460         if (!context_port.containsKey(XcosDiagram.IN)) {
461             List<mxICell> cell_list = portsMap.get(IOBlocks.ExplicitInBlock);
462             cell_list.addAll(portsMap.get(IOBlocks.ImplicitInBlock));
463             context_port.put(XcosDiagram.IN, cell_list);
464         }
465         if (!context_port.containsKey(XcosDiagram.OUT)) {
466             List<mxICell> cell_list = portsMap.get(IOBlocks.ExplicitOutBlock);
467             cell_list.addAll(portsMap.get(IOBlocks.ImplicitOutBlock));
468             context_port.put(XcosDiagram.OUT, cell_list);
469         }
470         if (!context_port.containsKey(XcosDiagram.EIN)) {
471             List<mxICell> cell_list = portsMap.get(IOBlocks.EventInBlock);
472             context_port.put(XcosDiagram.EIN, cell_list);
473         }
474         if (!context_port.containsKey(XcosDiagram.EOUT)) {
475             List<mxICell> cell_list = portsMap.get(IOBlocks.EventOutBlock);
476             context_port.put(XcosDiagram.EOUT, cell_list);
477         }
478
479         return context_port;
480     }
481
482     /**
483      * Function that add a port to a superblock. The function should be called only when
484      * the number of superdiagram blocks is higher than the superblock port number.
485      * 
486      * @param key
487      *         direction of the block ports
488      * @param context_block
489      *         the list of blocks
490      * @param context_port
491      *         the list of ports
492      */
493     private void addPorts(String key, Hashtable<String, List<? extends mxICell>> context_block, Map<String, List<? extends mxICell>> context_port)
494     {
495         // iterate on the superdiagram blocks
496         for (mxICell cell : context_block.get(key)) {
497             if (cell instanceof BasicBlock) {
498                 BasicBlock basicblock = (BasicBlock) cell;
499                 int order = (int) ((ScilabDouble) basicblock.getIntegerParameters()).getRealPart()[0][0];
500
501                 // get the new added block if found
502                 List<? extends mxICell> port_list = context_port.get(key);
503                 boolean port_found = false;
504                 for (mxICell port : port_list) {
505                     if (port instanceof BasicPort) {
506                         BasicPort basicport = (BasicPort) port;
507                         if (order == basicport.getOrdering()) {
508                             port_found = true;
509                             break;
510                         }
511                     }
512                 }
513
514                 if (port_found == false) {
515                     // add the port on the superblock
516                     insertOnePort(order, basicblock);
517                 }
518             }
519         }
520     }
521
522     /**
523      * Function that remove a port to a superblock. The function should be called only when
524      * the number of superdiagram blocks is less than the superblock port number.
525      * 
526      * @param key
527      *         direction of the block ports
528      * @param context_block
529      *         the list of blocks
530      * @param context_port
531      *         the list of ports
532      */
533     private void removePorts(String key, Hashtable<String, List<? extends mxICell>> context_block, Map<String, List<? extends mxICell>> context_port) {
534         // iterate on the superblock ports
535         for (mxICell cell : context_port.get(key)) {
536             if (cell instanceof BasicPort) {
537                 BasicPort basicport = (BasicPort) cell;
538                 int order = basicport.getOrdering();
539
540                 // get the port to remove
541                 List<? extends mxICell> block_list = context_block.get(key);
542                 boolean block_found = false;
543                 for (mxICell block : block_list) {
544                     if (block instanceof BasicBlock) {
545                         BasicBlock basicblock = (BasicBlock) block;
546                         int block_order = (int) ((ScilabDouble) basicblock.getIntegerParameters()).getRealPart()[0][0];
547                         if (order == block_order)
548                         {
549                             block_found = true;
550                             break;
551                         }
552                     }
553                 }
554
555                 if (block_found == false) {
556                     // delete the port
557                     removeOnePort(basicport);
558                 }
559             }
560         }
561     }
562
563     /**
564      * Function that remove dead ports from the superblock. A dead port is a port which has not
565      * a corresponding superdiagram IOBlock
566      * 
567      * @param key
568      *         direction of the block ports
569      * @param context_block
570      *         the list of blocks
571      * @param context_port
572      *         the list of ports
573      */
574     private void removeDeadPorts(String key, Hashtable<String, List<? extends mxICell>> context_block, Map<String, List<? extends mxICell>> context_port) {
575         // first remove dead ports
576         for (mxICell cell : context_port.get(key)) {
577             if (cell instanceof BasicPort) {
578                 BasicPort basicport = (BasicPort) cell;
579                 int order = basicport.getOrdering();
580
581                 // get the port to remove
582                 List<? extends mxICell> block_list = context_block.get(key);
583                 boolean block_found = false;
584                 for (mxICell block : block_list) {
585                     if (block instanceof BasicBlock) {
586                         BasicBlock basicblock = (BasicBlock) block;
587                         int block_order = (int) ((ScilabDouble) basicblock.getIntegerParameters()).getRealPart()[0][0];
588                         if (order == block_order) {
589                             block_found = true;
590                             break;
591                         }
592                     }
593                 }
594
595                 if (block_found == false) {
596                     // delete the port
597                     removeOnePort(basicport);
598                 }
599             }
600         }
601     }
602
603     /**
604      * Function that replace a port of a superblock
605      * if its numbering has changed
606      * 
607      * @param key
608      *          direction of the block ports
609      * @param context_block
610      *          the list of blocks
611      * @param context_port
612      *          the list of ports
613      */
614     private void replacePort(String key, Hashtable<String, List<? extends mxICell>> context_block, Map<String, List<? extends mxICell>> context_port) {
615         // iterate on the superdiagram blocks
616         for (mxICell cell : context_block.get(key)) {
617             if (cell instanceof BasicBlock) {
618                 BasicBlock basicblock = (BasicBlock) cell;
619                 int order = (int) ((ScilabDouble) basicblock.getIntegerParameters()).getRealPart()[0][0];
620
621                 // verify superblock port coherence
622                 List<? extends mxICell> port_list = context_port.get(key);
623                 BasicPort basicport = null;
624                 boolean port_found = false;
625                 for (mxICell port : port_list) {
626                     if (port instanceof BasicPort) {
627                         basicport = (BasicPort) port;
628                         if (order == basicport.getOrdering()) {
629                             port_found = true;
630                             break;
631                         }
632                     }
633                 }
634
635                 if (port_found == true) {
636                     boolean port_deleted = false;
637                     port_deleted = removeOnePort(order, basicport, basicblock);
638
639                     // add the port on the superblock if deleted
640                     if (port_deleted == true) {
641                         insertOnePort(order, basicblock);
642                     }
643                 } else {
644                     insertOnePort(order, basicblock);
645                 }
646             }
647         }
648     }
649
650     /**
651      * Function that updates super block ports in parent diagram
652      */
653     public void updateExportedPort() {
654         if (child == null) {
655             return;
656         }
657         if (getParentDiagram() == null) {
658             setParentDiagram(Xcos.findParent(this));
659         }
660
661         // extracting blocks from the superdiagram
662         Hashtable<String, List<? extends mxICell>> context_block = extractContextBlocks();
663         // extracting ports from the superblock
664         Hashtable<String, List<? extends mxICell>> context_port = extractContextPorts();
665
666         for (String key : context_block.keySet()) {
667             if (context_block.get(key).size() > context_port.get(key).size()) {
668                 // adding ports of the superblock
669                 addPorts(key, context_block, context_port);
670             } else if (context_block.get(key).size() < context_port.get(key).size()) {
671                 // removing ports of the superblock
672                 removePorts(key, context_block, context_port);
673             } else {
674                 // reordering ports of the superblock
675                 removeDeadPorts(key, context_block, context_port);
676                 replacePort(key, context_block, context_port);
677             }
678         }
679
680         getParentDiagram().fireEvent(new mxEventObject(XcosEvent.SUPER_BLOCK_UPDATED, XcosConstants.EVENT_BLOCK_UPDATED, this));
681     }
682
683     /**
684      * Mask the SuperBlock
685      */
686     public void mask() {
687         setInterfaceFunctionName(MASKED_INTERFUNCTION_NAME);
688         setSimulationFunctionName(MASKED_SIMULATION_NAME);
689         setIntegerParameters(new ScilabDouble(1));
690     }
691
692     /**
693      * Unmask the SuperBlock
694      */
695     public void unmask() {
696         setInterfaceFunctionName(INTERFUNCTION_NAME);
697         setSimulationFunctionName(SIMULATION_NAME);
698         setIntegerParameters(new ScilabDouble());
699     }
700
701     /**
702      * @return True is the SuperBlock is masked, false otherwise
703      */
704     public boolean isMasked() {
705         return getInterfaceFunctionName().compareTo(INTERFUNCTION_NAME) != 0;
706     }
707
708     /**
709      * Customize the parent diagram on name change
710      *
711      * @param value
712      *            the new name
713      * @see com.mxgraph.model.mxCell#setValue(java.lang.Object)
714      */
715     @Override
716     public void setValue(Object value) {
717         super.setValue(value);
718
719         if (value == null) {
720             return;
721         }
722
723         if (getChild() != null) {
724             getChild().setTitle(FileUtils.toValidCIdentifier(value.toString()));
725             setRealParameters(new DiagramElement().encode(getChild()));
726         }
727     }
728
729     /**
730      * Clone the child safely.
731      *
732      * @return a new clone instance
733      * @throws CloneNotSupportedException
734      *             never
735      * @see org.scilab.modules.xcos.block.BasicBlock#clone()
736      */
737     @Override
738     public Object clone() throws CloneNotSupportedException {
739         SuperBlock clone = (SuperBlock) super.clone();
740
741         // clone the diagram
742         if (child != null) {
743             clone.child = (SuperBlockDiagram) child.clone();
744             clone.child.setContainer(clone);
745         }
746
747         return clone;
748
749     }
750
751     /*
752      * Serializable custom implementation need to handle any copy / DnD case.
753      */
754
755     /**
756      * Encode the block as xml
757      *
758      * @param out
759      *            the output stream
760      * @throws IOException
761      *             on error
762      */
763     private void writeObject(java.io.ObjectOutputStream out) throws IOException {
764         out.writeObject(new XcosCodec().encode(this));
765     }
766
767     /**
768      * Decode the block as xml
769      *
770      * @param in
771      *            the input stream
772      * @throws IOException
773      *             on error
774      * @throws ClassNotFoundException
775      *             on error
776      */
777     private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
778         new XcosCodec().decode((Node) in.readObject(), this);
779
780         /*
781          * Specific post serialization things
782          */
783         if (this.child == null) {
784             this.child = new SuperBlockDiagram(this);
785             this.child.installListeners();
786         } else {
787             this.child.setContainer(this);
788         }
789         this.child.installSuperBlockListeners();
790     }
791 }
792 // CSON: ClassDataAbstractionCoupling
793 // CSON: ClassFanOutComplexity