d6b9453ffaabcfd7a30b136975b4abf04ff7f6bd
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / codec / BasicPortCodec.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Allan Simon
4  * Copyright (C) 2011-2015 - 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.io.codec;
18
19 import java.util.Map;
20 import java.util.logging.Logger;
21
22 import org.scilab.modules.graph.utils.ScilabGraphConstants;
23 import org.scilab.modules.graph.utils.StyleMap;
24 import org.scilab.modules.xcos.JavaController;
25 import org.scilab.modules.xcos.Kind;
26 import org.scilab.modules.xcos.block.BasicBlock;
27 import org.scilab.modules.xcos.port.BasicPort;
28 import org.scilab.modules.xcos.port.Orientation;
29 import org.scilab.modules.xcos.port.command.CommandPort;
30 import org.scilab.modules.xcos.port.control.ControlPort;
31 import org.scilab.modules.xcos.port.input.ExplicitInputPort;
32 import org.scilab.modules.xcos.port.input.ImplicitInputPort;
33 import org.scilab.modules.xcos.port.output.ExplicitOutputPort;
34 import org.scilab.modules.xcos.port.output.ImplicitOutputPort;
35 import org.w3c.dom.Element;
36 import org.w3c.dom.Node;
37
38 import com.mxgraph.io.mxCodec;
39 import com.mxgraph.io.mxCodecRegistry;
40 import com.mxgraph.io.mxObjectCodec;
41 import com.mxgraph.model.mxCell;
42 import com.mxgraph.model.mxICell;
43 import com.mxgraph.util.mxConstants;
44
45 /**
46  * Codec for any Port.
47  *
48  * This class doesn't pas the Data Abstraction Coupling (DAC) as we perform some
49  * template initialization on the {@link #register()} method.
50  */
51 // CSOFF: ClassDataAbstractionCoupling
52 public class BasicPortCodec extends XcosObjectCodec {
53
54     private static final Logger LOG = Logger.getLogger(BasicPortCodec.class.getName());
55     private static final String DATA_TYPE = "dataType";
56     private static final String[] IGNORED_FIELDS = new String[] { DATA_TYPE, "connectedLinkId" };
57
58     /**
59      * The constructor used on for configuration
60      *
61      * @param template
62      *            Prototypical instance of the object to be encoded/decoded.
63      * @param exclude
64      *            Optional array of fieldnames to be ignored.
65      * @param idrefs
66      *            Optional array of fieldnames to be converted to/from
67      *            references.
68      * @param mapping
69      *            Optional mapping from field- to attributenames.
70      */
71     public BasicPortCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
72         super(template, exclude, idrefs, mapping);
73     }
74
75     /**
76      * Register all the know codecs on the {@link mxCodecRegistry}
77      */
78     public static void register() {
79         JavaController controller = new JavaController();
80
81         XcosObjectCodec explicitOutputPortCodec = new BasicPortCodec(new ExplicitOutputPort(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, null), IGNORED_FIELDS, REFS, null);
82         mxCodecRegistry.register(explicitOutputPortCodec);
83         XcosObjectCodec explicitInputPortCodec = new BasicPortCodec(new ExplicitInputPort(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, null), IGNORED_FIELDS, REFS, null);
84         mxCodecRegistry.register(explicitInputPortCodec);
85         XcosObjectCodec implicitOutputPortCodec = new BasicPortCodec(new ImplicitOutputPort(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, null), IGNORED_FIELDS, REFS, null);
86         mxCodecRegistry.register(implicitOutputPortCodec);
87         XcosObjectCodec implicitInputPortCodec = new BasicPortCodec(new ImplicitInputPort(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, null), IGNORED_FIELDS, REFS, null);
88         mxCodecRegistry.register(implicitInputPortCodec);
89         XcosObjectCodec commandPortCodec = new BasicPortCodec(new CommandPort(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, null), IGNORED_FIELDS, REFS, null);
90         mxCodecRegistry.register(commandPortCodec);
91         XcosObjectCodec controlPortCodec = new BasicPortCodec(new ControlPort(controller, controller.createObject(Kind.PORT), Kind.PORT, null, null, null), IGNORED_FIELDS, REFS, null);
92         mxCodecRegistry.register(controlPortCodec);
93         mxCodecRegistry.register(new mxObjectCodec(Orientation.EAST));
94     }
95
96     /**
97      * Things to do before encoding
98      *
99      * @param enc
100      *            Codec that controls the encoding process.
101      * @param obj
102      *            Object to be encoded.
103      * @param node
104      *            XML node to encode the object into.
105      * @return Returns the object to be encoded by the default encoding.
106      * @see com.mxgraph.io.mxObjectCodec#beforeEncode(com.mxgraph.io.mxCodec,
107      *      java.lang.Object, org.w3c.dom.Node)
108      */
109     @Override
110     public Object beforeEncode(mxCodec enc, Object obj, Node node) {
111         /*
112          * Log some information
113          */
114         final BasicPort b = (BasicPort) obj;
115
116         if (b.getParent() == null) {
117             trace(enc, node, "Invalid parent");
118         }
119
120         for (int i = 0; i < b.getChildCount(); i++) {
121             final mxICell o = b.getChildAt(i);
122
123             // switch instanceof(o)
124             if (o instanceof mxCell) {
125                 // this is a comment
126                 continue;
127             }
128
129             trace(enc, node, "Inconsistent child %s at %d", o, i);
130         }
131
132         switch (b.getEdgeCount()) {
133             case 0:
134                 break;
135             case 1:
136                 final mxCell link = (mxCell) b.getEdgeAt(0);
137                 if (link.getSource() != b && link.getTarget() != b) {
138                     trace(enc, node, "Inconsistent source or target at %s", link);
139                 }
140                 break;
141             default:
142                 trace(enc, node, "Too much links");
143                 break;
144         }
145
146         return super.beforeEncode(enc, obj, node);
147     }
148
149     /**
150      * Apply compatibility pattern to the decoded object
151      *
152      * @param dec
153      *            Codec that controls the decoding process.
154      * @param node
155      *            XML node to decode the object from.
156      * @param obj
157      *            Object decoded.
158      * @return The Object transformed
159      * @see org.scilab.modules.xcos.io.codec.XcosObjectCodec#afterDecode(com.mxgraph.io.mxCodec,
160      *      org.w3c.dom.Node, java.lang.Object)
161      */
162     @Override
163     public Object afterDecode(mxCodec dec, Node node, Object obj) {
164         if (!(obj instanceof BasicPort)) {
165             LOG.severe("Unable to decode " + obj);
166             return obj;
167         }
168         final BasicPort port = (BasicPort) obj;
169         final String attr = ((Element) node).getAttribute(DATA_TYPE);
170
171         // update connectable flag
172         port.setConnectable(true);
173
174         // update style from version to version.
175         StyleMap map = new StyleMap(((Element) node).getAttribute(STYLE));
176         formatStyle(map, (BasicPort) obj);
177         port.setStyle(map.toString());
178
179         return super.afterDecode(dec, node, obj);
180     }
181
182     /**
183      * Format the style value
184      *
185      * @param map
186      *            The style as a map
187      * @param obj
188      *            the associated obj
189      */
190     private void formatStyle(StyleMap map, BasicPort obj) {
191
192         // Append the bloc style if not present.
193         String name = obj.getClass().getSimpleName();
194         if (!map.containsKey(name)) {
195             map.put(name, null);
196         }
197
198         // Replace direction by rotation
199         formatStyle(map);
200
201         // Update the rotation value according to the Orientation
202         updateRotationFromOrientation(map, obj);
203     }
204
205     /**
206      * Update the rotation value when the block has been rotated on 5.2.0
207      * format. Update it according to the Orientation field added 2010/01/08
208      * between 5.2.0 and 5.2.1.
209      *
210      * @param map
211      *            The previous style value
212      * @param obj
213      *            The port we are working on
214      */
215     private void updateRotationFromOrientation(StyleMap map, BasicPort obj) {
216         final Orientation orientation = obj.getOrientation();
217         double rotation = 0;
218         boolean flipped = false;
219         boolean mirrored = false;
220
221         if (map.get(mxConstants.STYLE_ROTATION) != null) {
222             rotation = Double.parseDouble(map.get(mxConstants.STYLE_ROTATION));
223         } else {
224             rotation = 0;
225         }
226
227         /*
228          * Protect against a not set parent
229          */
230         if (obj.getParent() == null || !(obj.getParent() instanceof BasicBlock)) {
231             return;
232         }
233
234         StyleMap parentBlockMap = new StyleMap(obj.getParent().getStyle());
235         flipped = Boolean.parseBoolean(parentBlockMap.get(ScilabGraphConstants.STYLE_FLIP));
236         mirrored = Boolean.parseBoolean(parentBlockMap.get(ScilabGraphConstants.STYLE_MIRROR));
237
238         // Calculate the rotation for this kind of port.
239         rotation = orientation.getAbsoluteAngle(obj.getClass(), flipped, mirrored);
240
241         map.put(mxConstants.STYLE_ROTATION, Double.toString(rotation));
242     }
243 }
244 // CSON: ClassDataAbstractionCoupling