Add loadGui and saveGui help pages.
[scilab.git] / scilab / modules / graphic_objects / src / java / org / scilab / modules / graphic_objects / xmlloader / XmlLoader.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010-2011 - DIGITEO - Manuel JULIACHS
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.graphic_objects.xmlloader;
14
15 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AXES__;
16 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UICONTROL__;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_CHILDREN__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_FIGURE__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_TYPE__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UIMENU__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_TAG__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_CHECKBOX__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_EDIT__;
24 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_FRAME_BORDER__;
25 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_FRAME_BORDER_OUT_BORDER__;
26 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_FRAME_BORDER_IN_BORDER__;
27 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_FRAME_BORDER_TITLE__;
28 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_FRAME__;
29 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_IMAGE__;
30 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_LAYER__;
31 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_LISTBOX__;
32 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_POPUPMENU__;
33 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_PUSHBUTTON__;
34 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_RADIOBUTTON__;
35 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_SLIDER__;
36 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_SPINNER__;
37 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_TAB__;
38 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_TEXT__;
39
40 import java.io.File;
41 import java.io.FileInputStream;
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.util.AbstractMap.SimpleEntry;
45 import java.util.HashMap;
46 import java.util.Map;
47 import java.util.Map.Entry;
48 import java.util.Set;
49 import java.util.Stack;
50
51 import javax.xml.parsers.SAXParser;
52 import javax.xml.parsers.SAXParserFactory;
53
54 import org.scilab.modules.commons.CommonFileUtils;
55 import org.scilab.modules.commons.gui.FindIconHelper;
56 import org.scilab.modules.graphic_objects.ScilabNativeView;
57 import org.scilab.modules.graphic_objects.builder.Builder;
58 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
59 import org.scilab.modules.graphic_objects.graphicModel.GraphicModel;
60 import org.scilab.modules.graphic_objects.graphicObject.GraphicObject.Type;
61 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
62 import org.xml.sax.Attributes;
63 import org.xml.sax.Locator;
64 import org.xml.sax.SAXException;
65 import org.xml.sax.helpers.DefaultHandler;
66
67 public class XmlLoader extends DefaultHandler {
68
69     private String filename = "";
70     private Locator locator;
71     private Integer uid = 0;
72     private String namespace = null;
73     private boolean isWaitingModelName = true;
74     private String myURI = "";
75     private boolean isFirst = false;
76
77     private static HashMap<String, Integer> nameToGO = new HashMap<String, Integer>();
78     private static HashMap<String, HashMap<String, Entry<Integer, Map<String, String>>>> models = new HashMap<String, HashMap<String, Entry<Integer, Map<String, String>>>>();
79     private Stack<Integer> stackGO = new Stack<Integer>();
80     private String currentPath = "";
81
82     private GraphicController controller;
83
84     static {
85         // init map to convert control name to id
86         nameToGO.put("UIScilabWindow", __GO_FIGURE__);
87
88         nameToGO.put("UIPanel", __GO_UI_FRAME__);
89         nameToGO.put("UIFrame", __GO_UI_FRAME__);
90         nameToGO.put("UILayer", __GO_UI_LAYER__);
91         nameToGO.put("UIButton", __GO_UI_PUSHBUTTON__);
92         nameToGO.put("UILabel", __GO_UI_TEXT__);
93         nameToGO.put("UILaTeXLabel", -1);
94         nameToGO.put("UICheckbox", __GO_UI_CHECKBOX__);
95         nameToGO.put("UITextfield", __GO_UI_EDIT__);
96         nameToGO.put("UISplashScreen", __GO_UI_IMAGE__);
97         nameToGO.put("UIList", __GO_UI_LISTBOX__);
98         nameToGO.put("UIComboBox", __GO_UI_POPUPMENU__);
99         nameToGO.put("UIComboColor", __GO_UI_POPUPMENU__);
100         nameToGO.put("UIRadio", __GO_UI_RADIOBUTTON__);
101         nameToGO.put("UISlider", __GO_UI_SLIDER__);
102         nameToGO.put("UITab", __GO_UI_TAB__);
103         nameToGO.put("UIScilabPlot", __GO_AXES__);
104         nameToGO.put("UINumberSpinner", __GO_UI_SPINNER__);
105
106
107         /** sdsdf*/
108         nameToGO.put("UITextarea", -2);
109
110         nameToGO.put("UIMenu", __GO_UIMENU__);
111         nameToGO.put("UIMenuItem", __GO_UIMENU__);
112
113     }
114
115     public XmlLoader(String filename) {
116         controller = GraphicController.getController();
117         this.filename = filename;
118     }
119
120     public int parse() throws SAXException {
121         int ret = 0;
122         if (filename != null && filename.equals("") == false) {
123             ret = parse(filename);
124         }
125
126         // clean model before leave.
127         Set<String> entries = models.keySet();
128         for (String key : entries) {
129             HashMap<String, Entry<Integer, Map<String, String>>> map = models.get(key);
130             Set<String> entries2 = map.keySet();
131             for (String key2 : entries2) {
132                 deleteObject(map.get(key2).getKey());
133             }
134         }
135
136         return ret;
137     }
138
139     public int parse(String filename) throws SAXException {
140         this.filename = filename;
141         File f = new File(filename);
142         if (f.exists()) {
143             //add filename filepath in ScilabSwingUtilities paths
144             if (f.isAbsolute()) {
145                 String filePath = f.getAbsolutePath();
146                 currentPath = filePath.substring(0, filePath.lastIndexOf(File.separator));
147                 FindIconHelper.addThemePath(currentPath);
148             } else {
149                 String initialDirectoryPath = CommonFileUtils.getCWD();
150                 String filePath = "";
151                 Integer index = filename.lastIndexOf(File.separator);
152                 if (index != -1) {
153                     filePath = filename.substring(0, index);
154                 }
155                 currentPath = initialDirectoryPath + File.separator + filePath;
156                 FindIconHelper.addThemePath(currentPath);
157                 FindIconHelper.addThemePath(initialDirectoryPath);
158
159                 f = new File(initialDirectoryPath, filename);
160             }
161         } else {
162             //try to find file in currentPath
163             if (f.isAbsolute()) {
164                 //failed
165                 return 1;
166             }
167
168             f = new File(currentPath + File.separator + filename);
169             if (f.exists() == false) {
170                 return 1;
171             }
172         }
173
174         FileInputStream in = null;
175         try {
176             in = new FileInputStream(f);
177         } catch (FileNotFoundException e1) {
178             e1.printStackTrace();
179             return 1;
180         }
181
182         SAXParser parser;
183         try {
184             SAXParserFactory factory;
185             factory = SAXParserFactory.newInstance();
186             factory.setValidating(false);
187             factory.setNamespaceAware(true);
188             factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
189             parser = factory.newSAXParser();
190         } catch (Exception e) {
191             try {
192                 in.close();
193             } catch (IOException e1) {
194                 e1.printStackTrace();
195                 return 1;
196             }
197             throw new SAXException(String.format("Cannot initialize the XML parser: %s", e.getMessage()));
198         }
199
200         try {
201             parser.parse(in, this);
202         } catch (SAXException e) {
203             if (locator != null) {
204                 throw new SAXException(String.format("Parse error at line %d: %s", locator.getLineNumber(), e.getMessage()));
205             } else {
206                 throw new SAXException(String.format("Parse error: %s", e.getMessage()));
207             }
208         } catch (IOException e) {
209             e.printStackTrace();
210         } finally {
211             try {
212                 in.close();
213             } catch (IOException e) {
214             }
215         }
216
217         return uid;
218     }
219
220     public void characters(char[] ch, int start, int length) throws SAXException {
221         super.characters(ch, start, length);
222     }
223
224     public void endDocument() throws SAXException {
225     }
226
227     public void endElement(String uri, String localName, String qName) throws SAXException {
228
229         if (localName.equals("modele")) {
230             namespace = null;
231             isWaitingModelName = false;
232         }
233
234         if (stackGO.size() != 0) {
235             Integer go = stackGO.pop();
236             if (go == null) {
237                 //nothing to do
238             } else if (stackGO.size() > 0) {
239                 Integer parent = stackGO.peek();
240
241                 controller.setGraphicObjectRelationship(parent, go);
242                 //controller.setProperty(go, __GO_VISIBLE__, true);
243             } else {
244                 uid = go;
245             }
246         }
247     }
248
249     public void setDocumentLocator(Locator locator) {
250         this.locator = locator;
251     }
252
253     public void startDocument() throws SAXException {
254         isFirst = true;
255     }
256
257     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
258         if (localName.equals("interface")) {
259             if (isFirst) {
260                 myURI = attributes.getValue("xmlns");
261                 isFirst = false;
262             }
263         } else if (localName.equals("include")) {
264             String path = attributes.getValue("path");
265             parse(path);
266         } else if (localName.equals("modele")) {
267             namespace = attributes.getValue("namespace");
268             isWaitingModelName = true;
269         } else {
270             Integer uitype = getTypeFromName(localName);
271             Integer go = 0;
272             if (uitype != null) {
273                 if (uitype == __GO_FIGURE__) {
274                     // never create a new figure, clone figure model !
275                     go = GOBuilder.figureBuilder(controller, attributes);
276                 } else if (uitype == __GO_AXES__) {
277                     go = GOBuilder.axesBuilder(controller, attributes);
278                 } else if (uitype == __GO_UIMENU__) {
279                     Integer parent = 0;
280                     if (stackGO.isEmpty() == false) {
281                         parent = stackGO.peek();
282                     }
283
284                     go = GOBuilder.uimenuBuilder(controller, attributes, parent);
285                 } else {
286                     Integer parent = 0;
287                     if (stackGO.isEmpty() == false) {
288                         parent = stackGO.peek();
289                     }
290
291                     go = GOBuilder.uicontrolBuilder(controller, uitype, attributes, parent);
292                 }
293             } else { // namespace or bad name ...
294                 if (myURI.equals(uri)) {
295                     // bad name
296                 } else {
297                     HashMap<String, Entry<Integer, Map<String, String>>> m = models.get(uri);
298                     if (m == null) {
299                         // bad namespace
300                     } else {
301                         Entry<Integer, Map<String, String>> entry = m.get(localName);
302                         go = entry.getKey();
303                         // need to clone object and children
304                         Integer newgo = cloneObject(go);
305                         GOBuilder.uicontrolUpdater(controller, newgo, attributes, stackGO.peek(), entry.getValue());
306                         go = newgo;
307                     }
308                 }
309             }
310
311             // we are in a model
312             // the first child must have field "model-name"
313             if (namespace != null) {
314                 if (isWaitingModelName) {
315                     String name = attributes.getValue("modele-name");
316                     if (name == null) {
317                         // unmaned model ? :s
318                     } else {
319                         if (models.get(namespace) == null) {
320                             models.put(namespace, new HashMap<String, Entry<Integer, Map<String, String>>>());
321                         }
322
323                         // copy attributes to a Map, i do not know why a can use
324                         // attributes ? Oo
325                         Map<String, String> attrib = new HashMap<String, String>();
326                         for (int i = 0; i < attributes.getLength(); i++) {
327                             attrib.put(attributes.getLocalName(i), attributes.getValue(i));
328                         }
329
330                         // add root element in map model
331                         models.get(namespace).put(name, new SimpleEntry<Integer, Map<String, String>>(go, attrib));
332                     }
333                 }
334             }
335
336             stackGO.add(go);
337         }
338     }
339
340     Integer cloneObject(Integer root) {
341         Integer newGo = controller.cloneObject(root);
342         Integer[] children = (Integer[]) controller.getProperty(root, __GO_CHILDREN__);
343         for (int i = children.length - 1; i >= 0 ; i--) {
344             Integer childType = (Integer)controller.getProperty(children[i], __GO_TYPE__);
345             if (childType == __GO_AXES__) {
346                 Integer go = controller.cloneObject(GraphicModel.getAxesModel().getIdentifier());
347                 Builder.createLabel(go, GraphicObjectProperties.__GO_X_AXIS_LABEL__);
348                 Builder.createLabel(go, GraphicObjectProperties.__GO_Y_AXIS_LABEL__);
349                 Builder.createLabel(go, GraphicObjectProperties.__GO_Z_AXIS_LABEL__);
350                 Builder.createLabel(go, GraphicObjectProperties.__GO_TITLE__);
351
352                 controller.setGraphicObjectRelationship(newGo, go);
353                 controller.setProperty(newGo, GraphicObjectProperties.__GO_SELECTED_CHILD__, go);
354                 controller.setProperty(go, GraphicObjectProperties.__GO_TAG__, controller.getProperty(children[i], __GO_TAG__));
355                 ScilabNativeView.ScilabNativeView__setCurrentSubWin(go);
356                 ScilabNativeView.ScilabNativeView__setCurrentObject(go);
357             } else if (childType == __GO_UI_FRAME_BORDER__) {
358                 Integer newChild = cloneObject(children[i]);
359                 controller.setGraphicObjectRelationship(newGo, newChild);
360
361                 Integer rootType = (Integer)controller.getProperty(root, __GO_TYPE__);
362                 if (rootType == __GO_UICONTROL__) {
363                     controller.setProperty(newGo, __GO_UI_FRAME_BORDER__, newChild);
364                 } else { //__GO_UI_FRAME_BORDER__
365                     Integer border = (Integer) controller.getProperty(root, __GO_UI_FRAME_BORDER_TITLE__);
366                     if (border == children[i]) {
367                         controller.setProperty(newGo, __GO_UI_FRAME_BORDER_TITLE__, newChild);
368                     } else {
369                         border = (Integer) controller.getProperty(root, __GO_UI_FRAME_BORDER_OUT_BORDER__);
370                         if (border == children[i]) {
371                             controller.setProperty(newGo, __GO_UI_FRAME_BORDER_OUT_BORDER__, newChild);
372                         } else {
373                             border = (Integer) controller.getProperty(root, __GO_UI_FRAME_BORDER_OUT_BORDER__);
374                             if (border == children[i]) {
375                                 controller.setProperty(newGo, __GO_UI_FRAME_BORDER_OUT_BORDER__, newChild);
376                             }
377                         }
378                     }
379                 }
380             } else {
381                 Integer newChild = cloneObject(children[i]);
382                 controller.setGraphicObjectRelationship(newGo, newChild);
383             }
384         }
385
386         return newGo;
387     }
388
389     private void deleteObject(Integer root) {
390         controller.removeRelationShipAndDelete(root);
391     }
392
393     private Integer getTypeFromName(String localName) {
394         return nameToGO.get(localName);
395     }
396 }