Xcos writers: add the "defaultParent" to the XML
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / io / XcosFileType.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Clement DAVID
4  * Copyright (C) 2011-2014 - Scilab Enterprises - Clement DAVID
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 package org.scilab.modules.xcos.io;
15
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.IOException;
19 import java.net.MalformedURLException;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.EnumSet;
23 import java.util.Iterator;
24 import java.util.Set;
25 import java.util.logging.Logger;
26
27 import javax.swing.filechooser.FileFilter;
28 import javax.swing.filechooser.FileNameExtensionFilter;
29 import javax.xml.parsers.ParserConfigurationException;
30 import javax.xml.stream.XMLOutputFactory;
31 import javax.xml.stream.XMLStreamWriter;
32 import javax.xml.transform.OutputKeys;
33 import javax.xml.transform.Transformer;
34 import javax.xml.transform.TransformerConfigurationException;
35 import javax.xml.transform.TransformerException;
36 import javax.xml.transform.TransformerFactory;
37 import javax.xml.transform.dom.DOMSource;
38 import javax.xml.transform.sax.SAXResult;
39 import javax.xml.transform.stax.StAXSource;
40 import javax.xml.transform.stream.StreamResult;
41 import javax.xml.transform.stream.StreamSource;
42
43 import org.scilab.modules.commons.xml.ScilabTransformerFactory;
44 import org.scilab.modules.commons.xml.ScilabXMLOutputFactory;
45 import org.scilab.modules.types.ScilabList;
46 import org.scilab.modules.xcos.JavaController;
47 import org.scilab.modules.xcos.View;
48 import org.scilab.modules.xcos.Xcos;
49 import org.scilab.modules.xcos.graph.XcosDiagram;
50 import org.scilab.modules.xcos.graph.model.XcosCellFactory;
51 import org.scilab.modules.xcos.io.sax.XcosSAXHandler;
52 import org.scilab.modules.xcos.io.spec.ContentEntry;
53 import org.scilab.modules.xcos.io.spec.XcosPackage;
54 import org.scilab.modules.xcos.io.writer.XcosWriter;
55 import org.scilab.modules.xcos.utils.XcosMessages;
56 import org.w3c.dom.Node;
57 import org.xml.sax.SAXException;
58
59 /**
60  * All the filetype recognized by Xcos.
61  */
62 public enum XcosFileType {
63     /**
64      * Represent the Xcos (a la ODT) format.
65      */
66     ZCOS("zcos", XcosMessages.FILE_ZCOS) {
67         @Override
68         public void load(String file, XcosDiagram into)
69         throws TransformerException, IOException, SAXException,
70             ParserConfigurationException {
71             LOG.entering("XcosFileType.ZCOS", "load");
72
73             View xcosView = JavaController.lookup_view(Xcos.class.getName());
74             try {
75                 JavaController.unregister_view(xcosView);
76
77                 XcosPackage p = new XcosPackage(new File(file));
78                 p.setContent(into);
79                 p.load();
80             } finally {
81                 JavaController.register_view(Xcos.class.getName(), xcosView);
82             }
83
84             LOG.exiting("XcosFileType.ZCOS", "load");
85         }
86
87         @Override
88         public void save(String file, XcosDiagram from) throws Exception {
89             LOG.entering("XcosFileType.ZCOS", "save");
90
91             XcosPackage p = new XcosPackage(new File(file));
92             p.setContent(from);
93             p.store();
94
95             LOG.exiting("XcosFileType.ZCOS", "save");
96         }
97     },
98     /**
99      * Represent the Xcos XML flat format.
100      */
101     XCOS("xcos", XcosMessages.FILE_XCOS) {
102         @Override
103         public void load(String file, XcosDiagram into)
104         throws TransformerException {
105             View xcosView = JavaController.lookup_view(Xcos.class.getName());
106             try {
107                 JavaController.unregister_view(xcosView);
108
109                 final TransformerFactory tranFactory = ScilabTransformerFactory.newInstance();
110                 final Transformer aTransformer = tranFactory.newTransformer();
111
112                 final StreamSource src = new StreamSource(new File(file).toURI().toURL().toString());
113                 final SAXResult result = new SAXResult(new XcosSAXHandler(into, null));
114
115                 LOG.entering("Transformer", "transform");
116                 aTransformer.transform(src, result);
117                 LOG.exiting("Transformer", "transform");
118
119             } catch (TransformerConfigurationException e) {
120                 Logger.getLogger(ContentEntry.class.getName()).severe(e.getMessageAndLocation());
121             } catch (TransformerException e) {
122                 e.printStackTrace();
123                 Logger.getLogger(ContentEntry.class.getName()).severe(e.getMessageAndLocation());
124             } catch (Exception e) {
125                 e.printStackTrace();
126             } finally {
127                 JavaController.register_view(Xcos.class.getName(), xcosView);
128             }
129         }
130
131         @Override
132         public void save(String file, XcosDiagram from) throws Exception {
133             final StreamResult result = new StreamResult(file);
134
135             final XMLOutputFactory factory = ScilabXMLOutputFactory.newInstance();
136             final XMLStreamWriter writer = factory.createXMLStreamWriter(result);
137             try {
138                 LOG.entering("XMLStreamWriter", "write");
139                 new XcosWriter(null, writer).write(from.getUID(), from.getKind());
140                 LOG.exiting("XMLStreamWriter", "write");
141             } finally {
142                 writer.close();
143             }
144         }
145     },
146     /**
147      * Represent the old Scicos text format.
148      */
149     COSF("cosf", XcosMessages.FILE_COSF) {
150         @Override
151         public void load(String file, XcosDiagram into) throws Exception {
152             XcosDiagram diagram = XcosCellFactory.createDiagramFromCOSF(new JavaController(), file);
153             into.addCell(diagram.getDefaultParent(), into.getDefaultParent());
154         }
155
156         @Override
157         public void save(String file, XcosDiagram from) throws Exception {
158             throw new UnsupportedOperationException();
159         }
160     };
161
162     private static final String BEFORE_EXT = " (*.";
163     private static final String AFTER_EXT = ")";
164     private static final Logger LOG = Logger.getLogger(XcosFileType.class
165                                       .getName());
166
167     private String extension;
168     private String description;
169
170     /**
171      * Default constructor
172      *
173      * @param extension
174      *            file extension (without the dot)
175      * @param description
176      *            file description
177      */
178     XcosFileType(String extension, String description) {
179         this.extension = extension;
180         this.description = description + BEFORE_EXT + extension + AFTER_EXT;
181     }
182
183     /**
184      * @return the extension prefixed with a dot
185      */
186     public String getDottedExtension() {
187         return "." + extension;
188     }
189
190     /**
191      * @return the raw extension
192      */
193     public String getExtension() {
194         return extension;
195     }
196
197     /**
198      * @return the mask of this file
199      */
200     public String getFileMask() {
201         return "*." + getExtension();
202     }
203
204     /**
205      * @return the file description
206      */
207     public String getDescription() {
208         return description;
209     }
210
211     /**
212      * Find a filetype by the filename extension
213      *
214      * @param theFile
215      *            Current file
216      * @return The determined filetype
217      */
218     public static XcosFileType findFileType(String theFile) {
219         int dotPos = theFile.lastIndexOf('.');
220         String extension = "";
221         XcosFileType retValue = null;
222
223         if (dotPos > 0 && dotPos <= theFile.length() - 2) {
224             extension = theFile.substring(dotPos + 1);
225         }
226
227         for (XcosFileType currentFileType : XcosFileType.values()) {
228             if (extension.compareToIgnoreCase(currentFileType.extension) == 0) {
229                 retValue = currentFileType;
230                 break;
231             }
232         }
233
234         return retValue;
235     }
236
237     /**
238      * Find a filetype by the filename extension
239      *
240      * @param f
241      *            Current file
242      * @return The determined filetype
243      */
244     public static XcosFileType findFileType(File f) {
245         XcosFileType retValue = findFileType(f.getName());
246
247         /* Validate xml header */
248         if (f.exists() && (retValue == XCOS || retValue == ZCOS)) {
249             retValue = checkHeader(f);
250         }
251
252         return retValue;
253     }
254
255     /**
256      * Find a filetype by a file filter
257      *
258      * @param filter
259      *            Current filter
260      * @return The determined filetype
261      */
262     public static XcosFileType findFileType(FileFilter filter) {
263         final FileFilter[] filters = getSavingFilters();
264
265         int index = 0;
266         for (FileFilter fileFilter : filters) {
267             if (fileFilter.getDescription() == filter.getDescription()) {
268                 break;
269             }
270
271             index++;
272         }
273
274         // the first filter is the "All supported file type", start from -1
275         if (index > 0) {
276             return XcosFileType.values()[index - 1];
277         } else {
278             return null;
279         }
280     }
281
282     /**
283      * Check the Xcos file header
284      *
285      * @param theFile
286      *            the file to check
287      * @return the found file type
288      */
289     private static XcosFileType checkHeader(final File theFile) {
290         XcosFileType retValue = null;
291
292         final byte[] xmlMagic = "<?xml".getBytes();
293         final byte[] readMagic = new byte[xmlMagic.length];
294
295         /*
296          * Check if the file is an xml one
297          */
298         FileInputStream stream = null;
299         try {
300             stream = new FileInputStream(theFile);
301             int length;
302             length = stream.read(readMagic);
303             if (length == xmlMagic.length && Arrays.equals(xmlMagic, readMagic)) {
304                 retValue = XCOS;
305             }
306         } catch (IOException e) {
307             retValue = null;
308         } finally {
309             if (stream != null) {
310                 try {
311                     stream.close();
312                 } catch (IOException e) {
313                     Logger.getLogger(XcosFileType.class.getName()).severe(
314                         e.toString());
315                 }
316             }
317         }
318
319         /*
320          * Check if the file is a valid zip file
321          */
322         if (retValue == null) {
323             try {
324                 new XcosPackage(theFile).checkHeader();
325                 retValue = ZCOS;
326             } catch (IOException e) {
327             } catch (ParserConfigurationException e) {
328             } catch (TransformerException e) {
329             }
330         }
331
332         return retValue;
333     }
334
335     /**
336      * Load a file into an XcosDiagram instance
337      *
338      * @param file
339      *            the file to load
340      * @param into
341      *            the diagram instance to fill
342      * @throws Exception
343      *             in case of problem
344      */
345     public abstract void load(final String file, final XcosDiagram into)
346     throws Exception;
347
348     /**
349      * Save to a file the XcosDiagram instance
350      *
351      * @param file
352      *            the file to save to
353      * @param into
354      *            the diagram instance to save
355      * @throws Exception
356      *             in case of problem
357      */
358     public abstract void save(final String file, final XcosDiagram from)
359     throws Exception;
360
361     /**
362      * @return the file filters which can be used to load a file
363      */
364     public static FileFilter[] getLoadingFilters() {
365         Collection<XcosFileType> used = EnumSet.allOf(XcosFileType.class);
366         Iterator<XcosFileType> it = used.iterator();
367
368         final FileFilter[] filters = new FileFilter[used.size() + 1];
369
370         final String[] extensions = new String[used.size()];
371         final String[] descriptions = new String[used.size()];
372         for (int i = 0; i < extensions.length; i++) {
373             final XcosFileType type = it.next();
374
375             descriptions[i] = type.getDescription();
376             extensions[i] = type.getExtension();
377         }
378
379         /*
380          * One file filter for all valid extensions
381          */
382         filters[0] = new FileNameExtensionFilter(
383             XcosMessages.ALL_SUPPORTED_FORMATS, extensions);
384
385         /*
386          * Then one file filter per enum value.
387          */
388         for (int i = 0; i < descriptions.length; i++) {
389             filters[i + 1] = new FileNameExtensionFilter(descriptions[i],
390                     extensions[i]);
391         }
392
393         return filters;
394     }
395
396     /**
397      * @return the file filters which can be used to save a file
398      */
399     public static FileFilter[] getSavingFilters() {
400         Collection<XcosFileType> used = getAvailableSaveFormats();
401         Iterator<XcosFileType> it = used.iterator();
402
403         final FileFilter[] filters = new FileFilter[used.size() + 1];
404
405         final String[] extensions = new String[used.size()];
406         final String[] descriptions = new String[used.size()];
407         for (int i = 0; i < extensions.length; i++) {
408             final XcosFileType type = it.next();
409
410             descriptions[i] = type.getDescription();
411             extensions[i] = type.getExtension();
412         }
413
414         /*
415          * One file filter for all valid extensions
416          */
417         filters[0] = new FileNameExtensionFilter(
418             XcosMessages.ALL_SUPPORTED_FORMATS, extensions);
419
420         /*
421          * Then one file filter per enum value.
422          */
423         for (int i = 0; i < descriptions.length; i++) {
424             filters[i + 1] = new FileNameExtensionFilter(descriptions[i],
425                     extensions[i]);
426         }
427
428         return filters;
429     }
430
431     /**
432      * @return the possible file format
433      */
434     public static Set<XcosFileType> getAvailableSaveFormats() {
435         final Set<XcosFileType> values = EnumSet.noneOf(XcosFileType.class);
436         values.add(XcosFileType.XCOS);
437         values.add(XcosFileType.ZCOS);
438         return values;
439     }
440 }