2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - DIGITEO - Clement DAVID
4 * Copyright (C) 2011 - Scilab Enterprises - Clement DAVID
6 * Copyright (C) 2012 - 2016 - Scilab Enterprises
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.
17 package org.scilab.modules.xcos.io.scicos;
19 import static java.util.Arrays.asList;
21 import java.util.List;
23 import org.scilab.modules.graph.utils.StyleMap;
24 import org.scilab.modules.types.ScilabBoolean;
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.ScilabString;
29 import org.scilab.modules.types.ScilabTList;
30 import org.scilab.modules.types.ScilabType;
31 import org.scilab.modules.xcos.JavaController;
32 import org.scilab.modules.xcos.ObjectProperties;
33 import org.scilab.modules.xcos.block.BasicBlock;
34 import org.scilab.modules.xcos.graph.XcosDiagram;
35 import org.scilab.modules.xcos.io.ScilabTypeCoder;
36 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongElementException;
37 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongStructureException;
38 import org.scilab.modules.xcos.io.scicos.ScicosFormatException.WrongTypeException;
39 import org.scilab.modules.xcos.utils.BlockPositioning;
41 import com.mxgraph.model.mxCell;
42 import com.mxgraph.util.mxConstants;
43 import org.scilab.modules.xcos.utils.XcosConstants;
46 * Protected class which decode graphic fields of a block.
48 * This class is intentionally package-protected to prevent external use.
50 // CSOFF: ClassDataAbstractionCoupling
51 final class BlockGraphicElement extends BlockPartsElement {
53 * "in_style", "out_style" and style have been added on the 5.3-5.4 dev. cycle they are not checked to be compatible with older versions.
55 protected static final List<String> DATA_FIELD_NAMES = asList("graphics", "orig", "sz", "flip", "theta", "exprs", "pin", "pout", "pein", "peout", "gr_i",
56 "id", "in_implicit", "out_implicit");
57 protected static final List<String> DATA_FIELD_NAMES_FULL = asList("graphics", "orig", "sz", "flip", "theta", "exprs", "pin", "pout", "pein", "peout",
58 "gr_i", "id", "in_implicit", "out_implicit", "in_style", "out_style", "in_label", "out_label", "style");
60 private static final int ORIGIN_INDEX = DATA_FIELD_NAMES_FULL.indexOf("orig");
61 private static final int DIMS_INDEX = DATA_FIELD_NAMES_FULL.indexOf("sz");
62 private static final int FLIP_INDEX = DATA_FIELD_NAMES_FULL.indexOf("flip");
63 private static final int EXPRS_INDEX = DATA_FIELD_NAMES_FULL.indexOf("exprs");
64 private static final int ID_INDEX = DATA_FIELD_NAMES_FULL.indexOf("id");
65 private static final int STYLE_INDEX = DATA_FIELD_NAMES_FULL.indexOf("style");
67 private static final int GRAPHICS_INSTRUCTION_SIZE = 8;
68 private static final double DEFAULT_SIZE_FACTOR = 20.0;
70 /** Mutable field to easily get the data through methods */
71 private ScilabMList data;
73 /** In-progress decoded diagram */
74 private final XcosDiagram diag;
76 /** Size factor use to scale Xcos-Scicos dimensions */
77 private final double sizeFactor;
82 public BlockGraphicElement(final JavaController controller) {
83 this(controller, null);
87 * Default constructor with diagram
92 public BlockGraphicElement(final JavaController controller, final XcosDiagram diag) {
98 * Out of a diagram update, use the DEFAULT_SIZE_FACTOR.
101 sizeFactor = DEFAULT_SIZE_FACTOR;
108 * Default constructor with diagram
115 public BlockGraphicElement(final JavaController controller, final XcosDiagram diag, final double sizeFactor) {
119 this.sizeFactor = sizeFactor;
123 * Decode Scicos element into the block.
125 * This decode method doesn't coverage Port management because we need model information to handle it.
130 * the previously instantiated block.
131 * @return the modified into block.
132 * @throws ScicosFormatException
134 * @see org.scilab.modules.xcos.io.scicos.Element#decode(org.scilab.modules.types.ScilabType, java.lang.Object)
137 public BasicBlock decode(ScilabType element, final BasicBlock into) throws ScicosFormatException {
140 throw new IllegalArgumentException();
142 BasicBlock block = into;
144 data = (ScilabMList) element;
148 block = beforeDecode(element, block);
153 decodeDimension(block);
155 decodeFlipAndRotation(block);
158 controller.setObjectProperty(into.getUID(), into.getKind(), ObjectProperties.EXPRS, new ScilabTypeCoder().var2vec(data.get(EXPRS_INDEX)));
160 if (data.size() > STYLE_INDEX && !isEmptyField(data.get(STYLE_INDEX))) {
161 final ScilabString style = (ScilabString) data.get(STYLE_INDEX);
162 final String s = style.getData()[0][0];
164 if (s != null && !s.isEmpty()) {
169 block = afterDecode(element, block);
175 * Validate the current data.
177 * This method doesn't pass the metrics because it perform many test. Therefore all these tests are trivial and the conditioned action only throw an exception.
179 * @throws ScicosFormatException
180 * when there is a validation error.
182 // CSOFF: CyclomaticComplexity
183 // CSOFF: NPathComplexity
185 private void validate() throws ScicosFormatException {
186 if (!canDecode(data)) {
187 throw new WrongElementException();
192 // we test if the structure as enough field
193 if (data.size() < DATA_FIELD_NAMES.size()) {
194 throw new WrongStructureException(DATA_FIELD_NAMES);
198 * Checking the MList header
201 // Check the first field
202 if (!(data.get(field) instanceof ScilabString)) {
203 throw new WrongTypeException(DATA_FIELD_NAMES, field);
205 final String[] header = ((ScilabString) data.get(field)).getData()[0];
207 // Checking for the field names
208 if (header.length < DATA_FIELD_NAMES.size()) {
209 throw new WrongStructureException(DATA_FIELD_NAMES);
211 for (int i = 0; i < DATA_FIELD_NAMES.size(); i++) {
212 if (!header[i].equals(DATA_FIELD_NAMES.get(i))) {
213 throw new WrongStructureException(DATA_FIELD_NAMES);
221 // orig : must contain the coord of the block
223 if (!(data.get(field) instanceof ScilabDouble)) {
224 throw new WrongTypeException(DATA_FIELD_NAMES, field);
227 // sz : must contains the size of the block
229 if (!(data.get(field) instanceof ScilabDouble)) {
230 throw new WrongTypeException(DATA_FIELD_NAMES, field);
235 if (!(data.get(field) instanceof ScilabBoolean)) {
236 throw new WrongTypeException(DATA_FIELD_NAMES, field);
241 if (!(data.get(field) instanceof ScilabDouble)) {
242 throw new WrongTypeException(DATA_FIELD_NAMES, field);
247 if (!(data.get(field) instanceof ScilabString) && !(data.get(field) instanceof ScilabList) && !(data.get(field) instanceof ScilabTList)
248 && !isEmptyField(data.get(field))) {
249 throw new WrongTypeException(DATA_FIELD_NAMES, field);
254 if (!(data.get(field) instanceof ScilabDouble)) {
255 throw new WrongTypeException(DATA_FIELD_NAMES, field);
260 if (!(data.get(field) instanceof ScilabDouble)) {
261 throw new WrongTypeException(DATA_FIELD_NAMES, field);
266 if (!(data.get(field) instanceof ScilabDouble)) {
267 throw new WrongTypeException(DATA_FIELD_NAMES, field);
272 if (!(data.get(field) instanceof ScilabDouble)) {
273 throw new WrongTypeException(DATA_FIELD_NAMES, field);
277 // !! WARNING !! we do not care about gr_i because there are only
278 // block look related.
283 if (!(data.get(field) instanceof ScilabString)) {
284 throw new WrongTypeException(DATA_FIELD_NAMES, field);
289 if (!(data.get(field) instanceof ScilabString) && !isEmptyField(data.get(field))) {
290 throw new WrongTypeException(DATA_FIELD_NAMES, field);
295 if (!(data.get(field) instanceof ScilabString) && !isEmptyField(data.get(field))) {
296 throw new WrongTypeException(DATA_FIELD_NAMES, field);
299 // field added on the 5.3-5.4 dev. cycle
300 // not checked due to compatibility
306 // CSON: CyclomaticComplexity
307 // CSON: NPathComplexity
311 * Fill the block with the origin parameters
314 * the target instance
316 private void decodeOrigin(final BasicBlock into) {
323 final double[][] real = ((ScilabDouble) data.get(ORIGIN_INDEX)).getRealPart();
325 final double[] vector = real[real.length - 1];
326 y = vector[vector.length - 1];
329 * Apply compatibility patterns
335 * Invert the y-axis value and translate it.
337 y = -y - into.getGeometry().getHeight();
342 into.getGeometry().setX(x);
343 into.getGeometry().setY(y);
347 * Fill the block with the dimension parameters
350 * the target instance
352 private void decodeDimension(final BasicBlock into) {
359 final double[][] real = ((ScilabDouble) data.get(DIMS_INDEX)).getRealPart();
361 final double[] vector = real[real.length - 1];
362 h = vector[vector.length - 1];
365 * When a block has no parent diagram, the size should be updated. On a diagram decode, size is right.
373 into.getGeometry().setWidth(w);
374 into.getGeometry().setHeight(h);
378 * Fill the block with the flip and theta parameters
381 * the target instance
383 private void decodeFlipAndRotation(final BasicBlock into) {
384 String[] interfaceFunction = new String[1];
385 controller.getObjectProperty(into.getUID(), into.getKind(), ObjectProperties.INTERFACE_FUNCTION, interfaceFunction);
387 StyleMap styleMap = new StyleMap(interfaceFunction[0]);
392 if (!((ScilabBoolean) data.get(FLIP_INDEX)).getData()[0][0]) {
393 styleMap.put(XcosConstants.STYLE_FLIP, Boolean.TRUE.toString());
397 * Rotation management
399 double theta = ((ScilabDouble) data.get(FLIP_INDEX + 1)).getRealPart()[0][0];
401 // convert to a valid value
402 theta = BlockPositioning.roundAngle(-theta);
403 styleMap.put(mxConstants.STYLE_ROTATION, Double.toString(theta));
406 controller.setObjectProperty(into.getUID(), into.getKind(), ObjectProperties.STYLE, styleMap.toString());
410 * Preserve the id if applicable
413 * the target instance
415 private void decodeIdCell(final BasicBlock into) {
420 final String[][] id = ((ScilabString) data.get(ID_INDEX)).getData();
421 if (id.length == 0 || id[0].length == 0 || id[0][0].isEmpty()) {
426 * Create the local identifier
428 final mxCell identifier = diag.createCellIdentifier(into);
429 identifier.setValue(id[0][0]);
431 into.insert(identifier);
435 * Check if the element can be decoded.
439 * @return true, if the Scicos types match.
440 * @see org.scilab.modules.xcos.io.scicos.Element#canDecode(org.scilab.modules.types.ScilabType)
443 public boolean canDecode(ScilabType element) {
444 data = (ScilabMList) element;
446 final String type = ((ScilabString) data.get(0)).getData()[0][0];
447 return type.equals(DATA_FIELD_NAMES.get(0));
450 // CSON: ClassDataAbstractionCoupling