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