Xcos: delay the updateLabel operation after loading
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / scicos / DiagramElement.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - DIGITEO - Clement DAVID
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.io.scicos;
14
15 import static java.util.Arrays.asList;
16
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26
27 import org.scilab.modules.graph.ScilabGraphUniqueObject;
28 import org.scilab.modules.types.ScilabBoolean;
29 import org.scilab.modules.types.ScilabDouble;
30 import org.scilab.modules.types.ScilabList;
31 import org.scilab.modules.types.ScilabMList;
32 import org.scilab.modules.types.ScilabString;
33 import org.scilab.modules.types.ScilabTList;
34 import org.scilab.modules.types.ScilabType;
35 import org.scilab.modules.xcos.block.BasicBlock;
36 import org.scilab.modules.xcos.block.SuperBlock;
37 import org.scilab.modules.xcos.block.TextBlock;
38 import org.scilab.modules.xcos.block.io.ContextUpdate.IOBlocks;
39 import org.scilab.modules.xcos.graph.XcosDiagram;
40 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.VersionMismatchException;
41 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongStructureException;
42 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongTypeException;
43 import org.scilab.modules.xcos.link.BasicLink;
44 import org.scilab.modules.xcos.port.BasicPort;
45 import org.scilab.modules.xcos.utils.BlockPositioning;
46 import org.scilab.modules.xcos.utils.FileUtils;
47 import org.scilab.modules.xcos.utils.XcosMessages;
48
49 import com.mxgraph.model.mxCell;
50 import com.mxgraph.model.mxGeometry;
51 import com.mxgraph.model.mxGraphModel;
52 import com.mxgraph.model.mxGraphModel.Filter;
53 import com.mxgraph.model.mxICell;
54 import com.mxgraph.model.mxIGraphModel;
55 import com.mxgraph.util.mxPoint;
56
57 /**
58  * Perform a diagram transformation between Scicos and Xcos.
59  */
60 // CSOFF: ClassDataAbstractionCoupling
61 // CSOFF: ClassFanOutComplexity
62 public final class DiagramElement extends AbstractElement<XcosDiagram> {
63     protected static final List<String> DATA_FIELD_NAMES = asList("diagram", "props", "objs");
64     protected static final List<String> DATA_FIELD_NAMES_FULL = asList("diagram", "props", "objs", "version", "contrib");
65     private static final List<String> VERSIONS = asList("", "scicos4.2", "scicos4.3", "scicos4.4");
66
67     private static final int OBJS_INDEX = DATA_FIELD_NAMES_FULL.indexOf("objs");
68     private static final int VERSION_INDEX = DATA_FIELD_NAMES_FULL.indexOf("version");
69
70     private static final double H_MARGIN = 40.0;
71     private static final double V_MARGIN = 40.0;
72
73     /** Diagram properties MList header (scs_m.props) */
74     private static final String[] PROPS_FIELDS = { "params", "wpar", "title", "tol", "tf", "context", "void1", "options", "void2", "void3", "doc" };
75
76     /** Index of the title in the props field */
77     private static final int TITLE_INDEX = 2;
78
79     /** Diagram options MList header (scs_m.props.options) */
80     private static final String[] OPTS_FIELDS = { "scsopt", "3D", "Background", "Link", "ID", "Cmap" };
81     /**
82      * Window properties (scs_m.props.wpar).
83      *
84      * This property has no impact among simulation
85      */
86     private static final double[][] WPAR = { { 600, 450, 0, 0, 600, 450 } };
87
88     // The window parameters and diagram options are not used in the simulation
89     // thus we set it to default values.
90     // As the values are scicos dependent we avoid using constant references.
91     // CSOFF: MagicNumber
92     private static final ScilabTList DIAGRAM_OPTIONS = new ScilabTList(OPTS_FIELDS, Arrays.asList(new ScilabList(// 3D
93     Arrays.asList(new ScilabBoolean(true), new ScilabDouble(33))), new ScilabDouble(new double[][] { { 8, 1 } }), // Background
94     new ScilabDouble(new double[][] { { 1, 5 } }), // Link
95     new ScilabList(// ID
96     Arrays.asList(new ScilabDouble(new double[][] { { 5, 1 } }), new ScilabDouble(new double[][] { { 4, 1 } }))), new ScilabDouble(
97     new double[][] { { 0.8, 0.8, 0.8 } }) // Cmap
98                                                                                                  ));
99     // CSON: MagicNumber
100
101     private ScilabMList base;
102
103     private double minimalYaxisValue = Double.POSITIVE_INFINITY;
104     private double minimalXaxisValue = Double.POSITIVE_INFINITY;
105
106     /**
107      * Default constructor
108      */
109     public DiagramElement() {
110     }
111
112     /**
113      * Decode the diagram with version validation.
114      *
115      * @param element
116      *            the diagram Scicos element
117      * @param into
118      *            the Xcos instance, if null, a new instance is returned.
119      * @return the modified into parameters
120      * @throws ScicosFormatException
121      *             when a decoding error occurs
122      * @see org.scilab.modules.xcos.io.scicos.Element#decode(org.scilab.modules.types.ScilabType,
123      *      java.lang.Object)
124      */
125     @Override
126     public XcosDiagram decode(ScilabType element, XcosDiagram into) throws ScicosFormatException {
127         return decode(element, into, true);
128     }
129
130     /**
131      * Decode the diagram
132      *
133      * @param element
134      *            the diagram Scicos element
135      * @param into
136      *            the Xcos instance, if null, a new instance is returned.
137      * @param validate
138      *            true, if the diagram version will be checked. false otherwise.
139      * @return the modified into parameters
140      * @throws ScicosFormatException
141      *             when a decoding error occurs
142      * @see org.scilab.modules.xcos.io.scicos.Element#decode(org.scilab.modules.types.ScilabType,
143      *      java.lang.Object)
144      */
145     public XcosDiagram decode(ScilabType element, XcosDiagram into, boolean validate) throws ScicosFormatException {
146         base = (ScilabMList) element;
147
148         XcosDiagram diag = into;
149         if (diag == null) {
150             diag = new XcosDiagram();
151         }
152
153         diag = beforeDecode(element, diag);
154         diag.getModel().beginUpdate();
155
156         // Validate the base field
157         String wrongVersion = null;
158         try {
159             validate(validate);
160         } catch (VersionMismatchException e) {
161             wrongVersion = e.getWrongVersion();
162         }
163
164         // Fill the diag
165         decodeDiagram(diag, validate);
166
167         diag.getModel().endUpdate();
168         diag = afterDecode(element, diag);
169
170         // Rethrow the version exception after a decode.
171         if (wrongVersion != null) {
172             throw new VersionMismatchException(wrongVersion);
173         }
174
175         return diag;
176     }
177
178     /**
179      * Reassociate the children with the current diagram.
180      *
181      * @param element
182      *            the encoded element
183      * @param into
184      *            the target instance
185      * @return the modified target instance
186      * @see org.scilab.modules.xcos.io.scicos.AbstractElement#afterDecode(org.scilab.modules.types.ScilabType,
187      *      java.lang.Object)
188      */
189     @Override
190     public XcosDiagram afterDecode(ScilabType element, XcosDiagram into) {
191         into.setChildrenParentDiagram();
192
193         return super.afterDecode(element, into);
194     }
195
196     /**
197      * Decode the diagram
198      *
199      * @param diag
200      *            the current diagram
201      * @param validate if true, enable graphic updates ; false disable them
202      * @throws ScicosFormatException
203      *             on decoding error
204      */
205     private void decodeDiagram(XcosDiagram diag, boolean validate) throws ScicosFormatException {
206         // Fill the local parameters
207         // NOTE: the title field is checked on the ScicosParametersElement
208         final String title = ((ScilabString) ((ScilabTList) base.get(1)).get(2)).getData()[0][0];
209         diag.setTitle(title);
210
211         // Fill the diagram attributes
212         ScicosParametersElement params = new ScicosParametersElement();
213         params.decode(base.get(1), diag.getScicosParameters());
214
215         // Decode the objs attributes
216         decodeObjs(diag);
217         // Update the objs properties if applicable
218         updateObjs(diag, validate);
219     }
220
221     /**
222      * Decode the objs list into cells
223      *
224      * @param diag
225      *            the target instance
226      * @throws ScicosFormatException
227      *             on error
228      */
229     private void decodeObjs(final XcosDiagram diag) throws ScicosFormatException {
230         final int nbOfObjs = ((ScilabList) base.get(OBJS_INDEX)).size();
231         final HashMap<Integer, BasicBlock> blocks = new HashMap<Integer, BasicBlock>(nbOfObjs, 1.0f);
232
233         final BlockElement blockElement = new BlockElement(diag);
234         final LinkElement linkElement = new LinkElement(blocks);
235         final LabelElement labelElement = new LabelElement();
236
237         /*
238          * Decode blocks
239          */
240         for (int i = 0; i < nbOfObjs; i++) {
241             final ScilabMList data = (ScilabMList) ((ScilabList) base.get(OBJS_INDEX)).get(i);
242             Object cell = null;
243
244             if (blockElement.canDecode(data)) {
245                 BasicBlock block = blockElement.decode(data, null);
246                 blocks.put(i, block);
247                 cell = block;
248
249                 BlockPositioning.updateBlockView(block);
250
251                 minimalYaxisValue = Math.min(minimalYaxisValue, ((mxCell) cell).getGeometry().getY());
252                 minimalXaxisValue = Math.min(minimalXaxisValue, ((mxCell) cell).getGeometry().getX());
253             } else if (labelElement.canDecode(data)) {
254                 cell = labelElement.decode(data, null);
255
256                 minimalYaxisValue = Math.min(minimalYaxisValue, ((mxCell) cell).getGeometry().getY());
257                 minimalXaxisValue = Math.min(minimalXaxisValue, ((mxCell) cell).getGeometry().getX());
258             }
259
260             if (cell != null) {
261                 diag.addCell(cell);
262             }
263         }
264
265         /*
266          * Decode links
267          */
268         for (int i = 0; i < nbOfObjs; i++) {
269             final ScilabMList data = (ScilabMList) ((ScilabList) base.get(OBJS_INDEX)).get(i);
270             Object cell = null;
271
272             if (linkElement.canDecode(data)) {
273                 BasicLink link = linkElement.decode(data, null);
274                 cell = link;
275
276                 final List<mxPoint> points = ((mxCell) cell).getGeometry().getPoints();
277                 for (final mxPoint p : points) {
278                     minimalYaxisValue = Math.min(minimalYaxisValue, p.getY());
279                     minimalXaxisValue = Math.min(minimalXaxisValue, p.getX());
280                 }
281             }
282
283             if (cell != null) {
284                 diag.addCell(cell);
285             }
286         }
287     }
288
289     /**
290      * Update the diagram object after decode
291      *
292      * @param diag
293      *            the diagram to update
294      * @param validate perform graphic updates, or not
295      */
296     private void updateObjs(final XcosDiagram diag, boolean validate) {
297         final mxGraphModel model = (mxGraphModel) diag.getModel();
298
299         final double minY = -minimalYaxisValue + V_MARGIN;
300         final double minX = -minimalXaxisValue + H_MARGIN;
301         for (final Object cell : model.getCells().values()) {
302             updateMinimalSize(cell, model);
303             translate(cell, model, minX, minY);
304             if (validate) {
305                 updateLabels(cell, model);
306             }
307         }
308     }
309
310     // update the cell size to be at least selectable
311     private static final void updateMinimalSize(final Object cell, final mxIGraphModel model) {
312         if (!(cell instanceof BasicBlock)) {
313             return;
314         }
315
316         final double min = 7.0;
317
318         final mxGeometry geom = model.getGeometry(cell);
319         if (geom == null) {
320             return;
321         }
322
323         final double dx;
324         if (geom.getWidth() < min) {
325             dx = (geom.getWidth() - min) / 2;
326             geom.setWidth(min);
327         } else {
328             dx = 0.0;
329         }
330         final double dy;
331         if (geom.getHeight() < min) {
332             dy = (geom.getHeight() - min) / 2;
333             geom.setHeight(min);
334         } else {
335             dy = 0.0;
336         }
337
338         geom.translate(dx, dy);
339     }
340
341     // Translate the y axis for blocks and links
342     private static final void translate(final Object cell, final mxIGraphModel model, final double minX, final double minY) {
343         if (cell instanceof BasicPort) {
344             return;
345         }
346
347         final mxGeometry geom = model.getGeometry(cell);
348         if (geom != null) {
349             geom.translate(minX, minY);
350         }
351     }
352
353     // update the labels of ports for SuperBlock
354     private static final void updateLabels(final Object cell, final mxIGraphModel model) {
355         if (!(cell instanceof SuperBlock)) {
356             return;
357         }
358         final SuperBlock parent = (SuperBlock) cell;
359
360         // Assume that the children are sorted after decode
361         // blk.sortChildren();
362         final Map<IOBlocks, List<mxICell>> ports = IOBlocks.getAllPorts(parent);
363         final Map<IOBlocks, List<BasicBlock>> blocks = IOBlocks.getAllBlocks(parent);
364
365         for (final IOBlocks io : IOBlocks.values()) {
366             final List<mxICell> port = ports.get(io);
367             final List<BasicBlock> block = blocks.get(io);
368
369             final int len = Math.min(port.size(), block.size());
370             for (int i = 0; i < len; i++) {
371                 final mxICell p = port.get(i);
372                 final mxICell b = block.get(i);
373
374                 // if the I/O block has a port child and a label child,
375                 // update
376                 if (b.getChildCount() > 1) {
377                     final Object value = b.getChildAt(b.getChildCount() - 1).getValue();
378                     p.setValue(value);
379                 }
380             }
381         }
382     }
383
384     /**
385      * Check that the current ScilabType is a valid Diagram.
386      *
387      * This method doesn't pass the metrics because it perform many test.
388      * Therefore all these tests are trivial and the conditioned action only
389      * throw an exception.
390      *
391      * @param checkVersion
392      *            true, when the check validate the version
393      * @throws ScicosFormatException
394      *             When the diagram is not valid
395      */
396     // CSOFF: CyclomaticComplexity
397     // CSOFF: NPathComplexity
398     private void validate(boolean checkVersion) throws ScicosFormatException {
399
400         // Have we enough fields ?
401         if (base.size() < DATA_FIELD_NAMES.size()) {
402             throw new WrongStructureException(DATA_FIELD_NAMES);
403         }
404
405         int field = 0;
406
407         /*
408          * Checking the MList header
409          */
410
411         // Check the first field
412         if (!(base.get(field) instanceof ScilabString)) {
413             throw new WrongTypeException(DATA_FIELD_NAMES, field);
414         }
415         String[] header = ((ScilabString) base.get(field)).getData()[0];
416
417         // Check the number of fields
418         if (header.length < DATA_FIELD_NAMES.size()) {
419             throw new WrongStructureException(DATA_FIELD_NAMES);
420         }
421
422         // Check the first fields values
423         for (int i = 0; i < DATA_FIELD_NAMES.size(); i++) {
424             if (!header[i].equals(DATA_FIELD_NAMES.get(i))) {
425                 throw new WrongStructureException(DATA_FIELD_NAMES);
426             }
427         }
428
429         /*
430          * Checking the data types
431          */
432
433         // the second field must contain list of props
434         field++;
435         if (!(base.get(field) instanceof ScilabTList)) {
436             throw new WrongTypeException(DATA_FIELD_NAMES, field);
437         }
438
439         // the third field must contains lists of blocks and links
440         field++;
441         if (!(base.get(field) instanceof ScilabList)) {
442             throw new WrongTypeException(DATA_FIELD_NAMES, field);
443         }
444
445         // the last field must contain the scicos version used
446         field++;
447
448         // doesn't check version if not present (optional field)
449         if (base.size() <= field) {
450             return;
451         }
452
453         if (!(base.get(field) instanceof ScilabString)) {
454             throw new WrongTypeException(DATA_FIELD_NAMES, field);
455         }
456
457         /*
458          * Check the version if applicable
459          */
460         if (checkVersion) {
461             String scicosVersion = ((ScilabString) base.get(field)).getData()[0][0];
462             if (!VERSIONS.contains(scicosVersion)) {
463                 throw new VersionMismatchException(scicosVersion);
464             }
465         }
466     }
467
468     // CSON: CyclomaticComplexity
469     // CSON: NPathComplexity
470
471     /**
472      * @param element
473      *            the base element
474      * @return true if the header is valid, false otherwise
475      * @see org.scilab.modules.xcos.io.scicos.Element#canDecode(org.scilab.modules.types.ScilabType)
476      */
477     @Override
478     public boolean canDecode(ScilabType element) {
479         if (!(element instanceof ScilabMList)) {
480             return false;
481         }
482
483         base = (ScilabMList) element;
484
485         /*
486          * Checking header
487          */
488         final String type = ((ScilabString) base.get(0)).getData()[0][0];
489         final boolean typeIsValid = type.equals(DATA_FIELD_NAMES.get(0));
490
491         /*
492          * Check the version if applicable
493          */
494         final String scicosVersion;
495         if (base.size() > VERSION_INDEX) {
496             scicosVersion = ((ScilabString) base.get(VERSION_INDEX)).getData()[0][0];
497         } else {
498             scicosVersion = "";
499         }
500         final boolean versionIsValid = VERSIONS.contains(scicosVersion);
501         return typeIsValid && versionIsValid;
502     }
503
504     /**
505      * {@inheritDoc}
506      *
507      * Clear cell warnings before encoding
508      */
509     @Override
510     public ScilabType beforeEncode(XcosDiagram from, ScilabType element) {
511         if (from.getAsComponent() != null) {
512             from.getAsComponent().clearCellOverlays();
513         }
514         return super.beforeEncode(from, element);
515     }
516
517     /**
518      * Encode the instance into the element
519      *
520      * @param from
521      *            the source instance
522      * @param element
523      *            the previously allocated element.
524      * @return the element parameter
525      * @see org.scilab.modules.xcos.io.scicos.Element#encode(java.lang.Object,
526      *      org.scilab.modules.types.ScilabType)
527      */
528     @Override
529     public ScilabType encode(XcosDiagram from, ScilabType element) {
530         base = (ScilabMList) element;
531
532         int field = 0;
533
534         if (base == null) {
535             base = allocateElement();
536         }
537
538         base = (ScilabMList) beforeEncode(from, base);
539
540         field++;
541         fillParams(from, field);
542
543         field++;
544         fillObjs(from, field);
545
546         base = (ScilabMList) afterEncode(from, base);
547
548         return base;
549     }
550
551     /**
552      * Allocate a new element
553      *
554      * @return the new element
555      */
556     private ScilabMList allocateElement() {
557         ScilabMList data = new ScilabMList(DATA_FIELD_NAMES_FULL.toArray(new String[0]));
558         data.add(allocatePropsField()); // props
559         data.add(new ScilabList()); // objs
560         data.add(new ScilabString(VERSIONS.get(0))); // official version
561         data.add(new ScilabList()); // contrib
562         return data;
563     }
564
565     /**
566      * Allocate the props field
567      *
568      * @return the new props field
569      */
570     private ScilabTList allocatePropsField() {
571         ScilabTList data = new ScilabTList(PROPS_FIELDS);
572         data.add(new ScilabDouble(WPAR)); // wpar
573         data.add(new ScilabString("")); // title
574         data.add(new ScilabDouble()); // tol
575         data.add(new ScilabDouble()); // tf
576         data.add(new ScilabDouble()); // context
577         data.add(new ScilabDouble()); // void1
578         data.add(DIAGRAM_OPTIONS); // options
579         data.add(new ScilabDouble()); // void2
580         data.add(new ScilabDouble()); // void3
581         data.add(new ScilabList()); // doc
582
583         return data;
584     }
585
586     /**
587      * Fill the params field
588      *
589      * @param from
590      *            the source instance
591      * @param field
592      *            the params field number
593      */
594     private void fillParams(XcosDiagram from, int field) {
595         ScilabType data;
596         final ScicosParametersElement paramsElement = new ScicosParametersElement();
597         data = base.get(field);
598         data = paramsElement.encode(from.getScicosParameters(), data);
599
600         // set the title as it is need for generating files
601         ((ScilabTList) data).set(TITLE_INDEX, new ScilabString(FileUtils.toValidCIdentifier(from.getTitle())));
602
603         base.set(field, data);
604     }
605
606     /**
607      * Fill the objs field
608      *
609      * @param from
610      *            the source instance
611      * @param field
612      *            the objs field number
613      */
614     private void fillObjs(XcosDiagram from, int field) {
615         final BlockElement blockElement = new BlockElement(from);
616         final LinkElement linkElement = new LinkElement(null);
617         final ScilabList data = (ScilabList) base.get(field);
618
619         final List<BasicBlock> blockList = new ArrayList<BasicBlock>();
620         final List<BasicLink> linkList = new ArrayList<BasicLink>();
621
622         /*
623          * Fill the block and link lists
624          */
625         final Filter filter = new Filter() {
626             @Override
627             public boolean filter(Object current) {
628                 if (current instanceof BasicBlock && !(current instanceof TextBlock)) {
629                     filterBlocks(blockList, linkList, (BasicBlock) current);
630                 } else if (current instanceof BasicLink) {
631                     filterLink(linkList, (BasicLink) current);
632                 }
633
634                 return false;
635             }
636
637             /**
638              * Filter blocks
639              *
640              * @param blockList
641              *            the current block list
642              * @param linkList
643              *            the current link list
644              * @param block
645              *            the block to filter
646              */
647             private void filterBlocks(final List<BasicBlock> blockList, final List<BasicLink> linkList, final BasicBlock block) {
648                 blockList.add(block);
649
650                 //
651                 // Look inside a Block to see if there is no "AutoLink"
652                 // Jgraphx will store this link as block's child
653                 //
654                 for (int j = 0; j < block.getChildCount(); ++j) {
655                     if (block.getChildAt(j) instanceof BasicLink) {
656                         final BasicLink link = (BasicLink) block.getChildAt(j);
657
658                         // do not add the link if not connected
659                         if (link.getSource() != null && link.getTarget() != null) {
660                             linkList.add(link);
661                         }
662                     }
663                 }
664
665             }
666
667             /**
668              * Filter links
669              *
670              * @param linkList
671              *            the current link list
672              * @param link
673              *            the link to filter
674              */
675             private void filterLink(final List<BasicLink> linkList, final BasicLink link) {
676                 // Only add connected links
677                 final mxICell source = link.getSource();
678                 final mxICell target = link.getTarget();
679                 if (source != null && target != null) {
680                     linkList.add(link);
681                 }
682             }
683         };
684         mxGraphModel.filterDescendants(from.getModel(), filter);
685
686         /*
687          * Use a predictable block and links order when debug is enable
688          */
689         if (Logger.getLogger(BlockElement.class.getName()).isLoggable(Level.FINE)) {
690             Collections.sort(blockList);
691             Collections.sort(linkList, new Comparator<BasicLink>() {
692                 @Override
693                 public int compare(BasicLink o1, BasicLink o2) {
694                     return ((ScilabGraphUniqueObject) o1.getSource()).compareTo((ScilabGraphUniqueObject) o2.getSource());
695                 }
696             });
697         }
698
699         /*
700          * Reorder links
701          */
702         for (int i = 0; i < linkList.size(); ++i) {
703             linkList.get(i).setOrdering(i + blockList.size() + 1);
704         }
705
706         /*
707          * Reorder and encode blocks
708          */
709         for (int i = 0; i < blockList.size(); ++i) {
710             blockList.get(i).setOrdering(i + 1);
711
712             data.add(blockElement.encode(blockList.get(i), null));
713         }
714
715         /*
716          * Encode links
717          */
718         for (int i = 0; i < linkList.size(); ++i) {
719             final ScilabType link = linkElement.encode(linkList.get(i), null);
720             if (link != null) {
721                 data.add(link);
722             } else {
723                 data.add(new ScilabMList(new String[] { "Deleted" }));
724                 from.warnCellByUID(linkList.get(i).getId(), XcosMessages.LINK_NOT_CONNECTED);
725             }
726         }
727     }
728 }
729 // CSON: ClassDataAbstractionCoupling
730 // CSON: ClassFanOutComplexity