Xcos: use LABEL for C identifier and DESCRIPTION for textual or HTML content
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / sax / XcosSAXHandler.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2015-2015 - Scilab Enterprises - Clement DAVID
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 package org.scilab.modules.xcos.io.sax;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.EnumMap;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27 import java.util.regex.Pattern;
28
29 import org.scilab.modules.types.ScilabList;
30 import org.scilab.modules.xcos.JavaController;
31 import org.scilab.modules.xcos.Kind;
32 import org.scilab.modules.xcos.ObjectProperties;
33 import org.scilab.modules.xcos.VectorOfScicosID;
34 import org.scilab.modules.xcos.graph.XcosDiagram;
35 import org.scilab.modules.xcos.graph.model.ScicosObjectOwner;
36 import org.scilab.modules.xcos.graph.model.XcosCell;
37 import org.scilab.modules.xcos.io.HandledElement;
38 import org.scilab.modules.xcos.io.HandledElementsCategory;
39 import org.scilab.modules.xcos.utils.Stack;
40 import org.xml.sax.Attributes;
41 import org.xml.sax.SAXException;
42 import org.xml.sax.SAXParseException;
43 import org.xml.sax.helpers.DefaultHandler;
44
45 /**
46  * Implement a diagram SAX handler to decode the document as a stream.
47  */
48 public class XcosSAXHandler extends DefaultHandler {
49     protected static final Logger LOG = Logger.getLogger("org.scilab.modules.xcos.io.sax");
50
51     /*
52      * Utilities classes and methods
53      */
54     protected static class UnresolvedReference {
55         final private ScicosObjectOwner owner;
56         final private ObjectProperties property;
57         final private ObjectProperties associatedProperty;
58         final private int associatedPropertyIndex;
59
60         public UnresolvedReference(ScicosObjectOwner owner, ObjectProperties property, ObjectProperties associatedProperty, int associatedPropertyIndex) {
61             this.owner = owner;
62             this.property = property;
63             this.associatedProperty = associatedProperty;
64             this.associatedPropertyIndex = associatedPropertyIndex;
65         }
66
67         public void resolve(JavaController controller, long v, Kind kind) {
68             controller.setObjectProperty(owner.getUID(), owner.getKind(), property, v);
69
70             if (associatedProperty != null) {
71                 VectorOfScicosID associated = new VectorOfScicosID();
72                 controller.getObjectProperty(v, kind, associatedProperty, associated);
73
74                 associated.resize(Math.max(associated.size(), associatedPropertyIndex + 1));
75                 associated.set(associatedPropertyIndex, owner.getUID());
76
77                 controller.setObjectProperty(v, kind, associatedProperty, associated);
78             }
79         }
80     }
81
82     XcosCell lookupForParentXcosCellElement() {
83         Optional<XcosCell> parentBlock = parents.stream()
84                                          .filter(o -> o instanceof XcosCell)
85                                          .map(o -> (XcosCell) o)
86                                          .findFirst();
87
88         return parentBlock.orElse(null);
89     }
90
91     /*
92      * Instance data, raw shared with the sub-handlers
93      */
94     protected final XcosDiagram root;
95     protected final ScilabList dictionary;
96     protected final JavaController controller;
97     protected final Map<String, HandledElement> elementMap;
98     protected final Pattern validCIdentifier;
99
100     private final Map<HandledElementsCategory, ScilabHandler> handlers;
101
102     /*
103      * Current state of the parser, also raw shared with the sub-handlers
104      */
105
106     /** Contains the decoded parent' node (as an in-depth view of decoded elements) */
107     Stack<Object> parents = new Stack<>();
108     /** Mapping of UID JGraphX strings to an MVC decoded object */
109     Stack<HashMap<String, Long>> allChildren = new Stack<>();
110     /** List of unresolved references that will be resolved at {@link HandledElement#XcosDiagram} or {@link HandledElement#SuperBlockDiagram} ending */
111     HashMap<String, ArrayList<UnresolvedReference>> unresolvedReferences = new HashMap<>();
112
113     public XcosSAXHandler(final XcosDiagram content, final ScilabList dictionary) {
114         this.root = content;
115         this.dictionary = dictionary;
116
117         this.controller = new JavaController();
118         this.elementMap = HandledElement.getMap();
119
120         this.validCIdentifier = Pattern.compile("[a-zA-Z][a-zA-Z0-9_]+");
121
122         // add all the known handler to the map
123         EnumMap<HandledElementsCategory, ScilabHandler> localHandlers = new EnumMap<>(HandledElementsCategory.class);
124         localHandlers.put(HandledElementsCategory.JGRAPHX, new JGraphXHandler(this));
125         localHandlers.put(HandledElementsCategory.BLOCK, new BlockHandler(this));
126         localHandlers.put(HandledElementsCategory.LINK, new LinkHandler(this));
127         localHandlers.put(HandledElementsCategory.PORT, new PortHandler(this));
128         localHandlers.put(HandledElementsCategory.RAW_DATA, new RawDataHandler(this));
129         localHandlers.put(HandledElementsCategory.CUSTOM, new CustomHandler(this));
130
131         this.handlers = Collections.unmodifiableMap(localHandlers);
132     }
133
134     /*
135      * Implemented methods for the reader
136      */
137
138     @Override
139     public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
140         // FOR DEBUG only : printout an XML tree
141         if (LOG.isLoggable(Level.FINEST)) {
142             char[] indent = new char[parents.size()];
143             Arrays.fill(indent, ' ');
144             StringBuilder args = new StringBuilder();
145             if (atts.getValue("id") != null) {
146                 args.append(" id=\"").append(atts.getValue("id")).append("\"");
147             } else if (atts.getValue("as") != null) {
148                 args.append(" as=\"").append(atts.getValue("as")).append("\"");
149             }
150             // System.err.println(new StringBuilder().append(indent).append(localName).append(args).toString());
151             LOG.finest(new StringBuilder().append(indent).append(localName).append(args).toString());
152         }
153
154         HandledElement found = elementMap.get(localName);
155         Object localParent = null;
156
157         if (found != null) {
158             localParent = handlers.get(found.getCategory()).startElement(found, atts);
159         }
160
161         parents.push(localParent);
162     }
163
164     @Override
165     public void endElement(String uri, String localName, String qName) throws SAXException {
166         HandledElement found = elementMap.get(localName);
167
168         if (found != null) {
169             handlers.get(found.getCategory()).endElement(found);
170         }
171
172         parents.pop();
173     }
174
175     /*
176      * Utilities
177      */
178
179     /**
180      * Insert a child into the current sub-diagram
181      *
182      * Manage hierarchy association :
183      * <UL>
184      *   <LI>{@link ObjectProperties#PARENT_BLOCK}
185      *   <LI>{@link ObjectProperties#PARENT_DIAGRAM}
186      *   <LI>{@link ObjectProperties#CHILDREN}
187      * </UL>
188      * @param cell to insert
189      */
190     protected void insertChild(final XcosCell cell) {
191         long parentUID;
192         Kind parentKind;
193
194         final XcosCell parentCell = lookupForParentXcosCellElement();
195         if (Kind.BLOCK.equals(parentCell.getKind())) {
196             parentUID = parentCell.getUID();
197             parentKind = parentCell.getKind();
198
199             controller.setObjectProperty(cell.getUID(), cell.getKind(), ObjectProperties.PARENT_BLOCK, parentUID);
200         } else {
201             parentUID = ((XcosCell) root.getDefaultParent()).getUID();
202             parentKind = Kind.DIAGRAM;
203         }
204         controller.setObjectProperty(cell.getUID(), cell.getKind(), ObjectProperties.PARENT_DIAGRAM, ((XcosCell) root.getDefaultParent()).getUID());
205
206         VectorOfScicosID children = new VectorOfScicosID();
207         controller.getObjectProperty(parentUID, parentKind, ObjectProperties.CHILDREN, children);
208
209         children.add(cell.getUID());
210         controller.referenceObject(cell.getUID());
211
212         controller.setObjectProperty(parentUID, parentKind, ObjectProperties.CHILDREN, children);
213     }
214
215     /*
216      * Implement ErrorHandler methods
217      */
218
219     @Override
220     public void warning(SAXParseException e) throws SAXException {
221         System.err.println("XcosSAXHandler warning: " + e.getSystemId() + " at line " + e.getLineNumber() + " column " + e.getColumnNumber());
222         System.err.println(e.getMessage());
223     }
224
225     @Override
226     public void error(SAXParseException e) throws SAXException {
227         System.err.println("XcosSAXHandler error: " + e.getSystemId() + " at line " + e.getLineNumber() + " column " + e.getColumnNumber());
228         System.err.println(e.getMessage());
229     }
230
231     @Override
232     public void fatalError(SAXParseException e) throws SAXException {
233         System.err.println("XcosSAXHandler fatalError: " + e.getSystemId() + " at line " + e.getLineNumber() + " column " + e.getColumnNumber());
234         System.err.println(e.getMessage());
235     }
236 }