Bug 9884 fixed: Add in prefs the possibility to add a default header on new files...
[scilab.git] / scilab / modules / preferences / src / java / org / scilab / modules / preferences / XCommonManager.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2011 - INRIA - Vincent COUVERT
4  * Copyright (C) 2011 -         Pierre GRADIT
5  * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
6  *
7  * This file must be used under the terms of the CeCILL.
8  * This source file is licensed as described in the file COPYING, which
9  * you should have received as part of this distribution.  The terms
10  * are also available at
11  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
12  *
13  */
14
15 package org.scilab.modules.preferences;
16
17 import java.awt.Color;
18 import java.awt.Component;
19 import java.awt.Container;
20 import java.awt.Dimension;
21 import java.awt.Frame;
22 import java.io.File;
23 import java.io.FilenameFilter;
24 import java.io.FileFilter;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.StringReader;
29 import java.net.URI;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Stack;
34 import java.util.StringTokenizer;
35
36 import javax.swing.JDialog;
37 import javax.swing.SwingUtilities;
38 import javax.swing.border.Border;
39 import javax.xml.parsers.DocumentBuilder;
40 import javax.xml.parsers.DocumentBuilderFactory;
41 import javax.xml.parsers.ParserConfigurationException;
42 import javax.xml.transform.OutputKeys;
43 import javax.xml.transform.Source;
44 import javax.xml.transform.Transformer;
45 import javax.xml.transform.TransformerConfigurationException;
46 import javax.xml.transform.TransformerException;
47 import javax.xml.transform.TransformerFactory;
48 import javax.xml.transform.TransformerFactoryConfigurationError;
49 import javax.xml.transform.URIResolver;
50 import javax.xml.transform.dom.DOMResult;
51 import javax.xml.transform.dom.DOMSource;
52 import javax.xml.transform.stream.StreamResult;
53 import javax.xml.transform.stream.StreamSource;
54
55 import org.w3c.dom.Document;
56 import org.w3c.dom.DocumentFragment;
57 import org.w3c.dom.Element;
58 import org.w3c.dom.NamedNodeMap;
59 import org.w3c.dom.Node;
60 import org.w3c.dom.NodeList;
61 import org.xml.sax.InputSource;
62 import org.xml.sax.SAXException;
63
64 import org.scilab.modules.localization.Messages;
65 import org.scilab.modules.commons.OS;
66 import org.scilab.modules.commons.ScilabCommons;
67 import org.scilab.modules.commons.xml.ScilabDocumentBuilderFactory;
68 import org.scilab.modules.commons.xml.ScilabTransformerFactory;
69 import org.scilab.modules.commons.xml.XConfiguration;
70 import org.scilab.modules.gui.console.ScilabConsole;
71
72 /* This class is the common ancestor to both X_manager.
73  */
74 public abstract class XCommonManager {
75
76     /** XConfiguration management verbosity.*/
77     public static final boolean performances = true;
78
79     /** XConfiguration management verbosity.*/
80     public static final boolean differential = true;
81
82     /** Message for read error.*/
83     protected static final String ERROR_READ = "Could not load file: ";
84
85     /** Message for write error.*/
86     protected static final String ERROR_WRITE = "Could not save file: ";
87
88     /** Buffer size.*/
89     protected static final int BUFSIZE = 1024;
90
91     /** Main dialog.*/
92     protected static JDialog dialog;
93
94     /** DOM Document.*/
95     protected static Document document;
96
97     /** DOM Document.*/
98     protected static String documentAddress;
99
100     /** Up-to-date flag.*/
101     protected static boolean  updated = false;
102
103     /** Top level DOM Node.*/
104     protected static Node topDOM;
105
106     /** Top level Swing container.*/
107     protected static Container topSwing;
108
109     /** Container-Sentinel correspondence.*/
110     protected static Map<Component, XSentinel> correspondance;
111
112     /** Last visitor.*/
113     protected static XUpdateVisitor visitor;
114
115     /** Last current time.*/
116     protected static long time = System.currentTimeMillis();
117
118     /**
119      * XSL Transformer factory.
120      */
121     protected static TransformerFactory factory;
122
123     /**
124      * XML Document builder factory.
125      */
126     protected static DocumentBuilderFactory builder = ScilabDocumentBuilderFactory.newInstance();
127
128     /**
129      * XSL Transformer.
130      */
131     protected static Transformer transformer = null;
132
133     private static final String SCI = System.getenv("SCI");
134
135     /** Scilab configuration file.*/
136     private static final String SCILAB_CONFIG_FILE = SCI + "/modules/preferences/etc/XConfiguration.xml";
137
138     private static String XSLCODE;
139
140     static {
141         factory = ScilabTransformerFactory.newInstance();
142         factory.setURIResolver(new URIResolver() {
143             public Source resolve(String href, String base) throws TransformerException {
144                 if (href.startsWith("$SCI")) {
145                     href = href.replace("$SCI", SCI);
146                     base = null;
147                 }
148
149                 try {
150                     File baseDir = null;
151                     if (base != null && !base.isEmpty()) {
152                         baseDir = new File(new URI(base)).getParentFile();
153                     }
154                     File f;
155                     if (baseDir != null) {
156                         f = new File(baseDir, href);
157                     } else {
158                         f = new File(href);
159                     }
160
161                     if (f.exists() && f.canRead()) {
162                         return new StreamSource(f);
163                     }
164                 } catch (Exception e) {
165                     System.out.println(e);
166                 }
167
168                 throw new TransformerException("Cannot find the file " + href + "::" + base);
169             }
170         });
171     }
172
173     /**
174      * Monitor time between calls.
175      */
176     public static void printTimeStamp(final String msg) {
177         long nextTime  = System.currentTimeMillis();
178         long deltaTime = nextTime - time;
179         if (performances) {
180             System.out.println((msg.startsWith("*") ? "" : " |  ") + msg + " in " + deltaTime + " ms.");
181         }
182         time = nextTime;
183     }
184
185     /** Launch swing hierarchy update.
186      *
187      * @return whether XSL return a node or not.
188      */
189     public static boolean refreshDisplay() {
190         topDOM = generateViewDOM().getNode().getFirstChild();//System.out.println(XConfiguration.dumpNode(generateViewDOM().getNode()));
191         if (topDOM == null) {
192             System.err.println("XSL does not give a node!");
193             return false;
194         }
195
196         // Refresh correspondence
197         //    TODO top layout changes
198         visitor = new XUpdateVisitor(correspondance);
199         visitor.visit(topSwing, topDOM);
200         setDimension(dialog, topDOM);
201         dialog.pack();
202
203         return true;
204     }
205
206     /**
207      * Horizontal space between parent and child in String representations.
208      */
209     public static final String INCREMENT = "    ";
210
211     /**
212      * Compute recursive string representation of DOM view tree.
213      * @param node : current node
214      * @param indent : current indentation
215      * @return node representation
216      *
217      */
218     private static String viewDOM(final Node node, final String indent) {
219         String signature = indent;
220         if (node.hasAttributes()) {
221             signature += XSentinel.signature(node, new String[0]);
222         } else {
223             String single = node.getNodeName() + ": " + node.getNodeValue();
224             signature += single.replaceAll("[ \t\n]+", " ");
225         }
226         signature += "\n";
227         NodeList nodelist = node.getChildNodes();
228         for (int i = 0; i < nodelist.getLength(); i++) {
229             Node item  = nodelist.item(i);
230             signature += viewDOM(item, indent + INCREMENT);
231         }
232
233         return signature;
234     }
235
236     /**
237      * Compute top-level string representation of DOM view tree.
238      * @return document representation
239      */
240     protected static String viewDOM() {
241         return viewDOM(topDOM, "");
242     }
243
244     /**
245      * Compute recursive string representation of Swing tree.
246      * @param component : current component
247      * @param indent : current indentation
248      * @return component representation
249      *
250      */
251     private static String swingComposite(final Component component, final String indent) {
252         String signature = indent;
253         signature += component.toString() + "\n";
254         if (component instanceof Container) {
255             Container container = (Container) component;
256             Component [] components = container.getComponents();
257             for (int i = 0; i < components.length; i++) {
258                 Component child = components[i];
259                 signature += swingComposite(child, indent + INCREMENT);
260             }
261         }
262         return signature;
263     }
264
265     /**
266      * Compute top-level string representation of swing composite.
267      * @return Graphical interface representation
268      */
269     protected static String swingComposite() {
270         return swingComposite(topSwing, "");
271     }
272
273     private static List<File> getEtcDir() {
274         List<File> list = new ArrayList<File>();
275         File modulesDir = new File(SCI + "/modules/");
276         File[] modules = modulesDir.listFiles(new FileFilter() {
277             public boolean accept(File f) {
278                 return f.isDirectory();
279             }
280         });
281
282         for (File module : modules) {
283             File etc = new File(module, "/etc/");
284             if (etc.exists() && etc.isDirectory()) {
285                 list.add(etc);
286             }
287         }
288
289         return list;
290     }
291
292     /**
293      * Create a XSL string in using the XConfiguration-*.xsl found in SCI/modules/MODULE_NAME/etc/
294      * @return the buit XSL string.
295      */
296     protected static String createXSLFile() {
297         if (XSLCODE == null) {
298             List<File> etcs = XConfiguration.getEtcDir();
299
300             StringBuilder buffer = new StringBuilder("<?xml version='1.0' encoding='utf-8'?>\n");
301             buffer.append("<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n");
302             buffer.append("<xsl:param name=\"OS\"/>\n");
303             buffer.append("<xsl:import href=\"").append(SCI).append("/modules/preferences/src/xslt/XConfiguration.xsl").append("\"/>\n");
304
305             FilenameFilter filter = new FilenameFilter() {
306                 public boolean accept(File dir, String name) {
307                     return name.endsWith(".xsl") && name.startsWith("XConfiguration");
308                 }
309             };
310
311             // Include standard Scilab xsl files
312             for (File etc : etcs) {
313                 File[] xsls = etc.listFiles(filter);
314                 for (File xsl : xsls) {
315                     try {
316                         buffer.append("<xsl:import href=\"").append(xsl.getCanonicalPath()).append("\"/>\n");
317                     } catch (IOException e) {
318                         buffer.append("<xsl:import href=\"").append(xsl.getAbsolutePath()).append("\"/>\n");
319                     }
320                 }
321             }
322
323             // Include toolboxes xsl files
324             List<ScilabPreferences.ToolboxInfos> infos = ScilabPreferences.getToolboxesInfos();
325             filter = new FilenameFilter() {
326                 public boolean accept(File dir, String name) {
327                     return name.endsWith(".xsl");
328                 }
329             };
330             for (ScilabPreferences.ToolboxInfos i : infos) {
331                 File etc = new File(i.getPrefFile()).getParentFile();
332                 File[] xsls = etc.listFiles(filter);
333                 for (File xsl : xsls) {
334                     try {
335                         buffer.append("<xsl:import href=\"").append(xsl.getCanonicalPath()).append("\"/>\n");
336                     } catch (IOException e) {
337                         buffer.append("<xsl:import href=\"").append(xsl.getAbsolutePath()).append("\"/>\n");
338                     }
339                 }
340             }
341
342             buffer.append("</xsl:stylesheet>");
343
344             XSLCODE = buffer.toString();
345         }
346
347         return XSLCODE;
348     }
349
350     public static void invalidateXSL() {
351         XSLCODE = null;
352     }
353
354     /**
355      * Load XSL as XSL Transformer.
356      */
357     protected static void reloadTransformer(String address) {
358         try {
359             StreamSource source = new StreamSource(new StringReader(createXSLFile()));
360             transformer = factory.newTransformer(source);
361             transformer.setParameter("OS", OS.getVersionName());
362         } catch (TransformerConfigurationException e1) {
363             System.err.println(ERROR_READ + address);
364         } catch (TransformerFactoryConfigurationError e1) {
365             System.err.println(ERROR_READ + address);
366         }
367     }
368
369     /**
370      * Generate view by application of XSL on XConfiguration file.
371      * @return View DOM.
372      */
373     private static DOMResult generateViewDOM() {
374         DOMResult result = new DOMResult();
375         DOMSource source = new DOMSource(document);
376         try {
377             transformer.transform(source, result);
378         } catch (TransformerException e) {
379             // Just highlight clear transformer output.
380             System.out.println("\n");
381         }
382         return result;
383     }
384
385     /**
386      * Identify an element with its context string.
387      * @see XConfiguration.xsl#context
388      * @param context : the context string used to catch the element.
389      * @return the corresponding node
390      */
391     public static Element getElementByContext(final String context) {
392         String[] ids = context.split("/");
393         Element element = document.getDocumentElement();
394         for (int i = 0; i < ids.length; i++) {
395             int index = Integer.parseInt(ids[i]);
396             // get the element with corresponding index (filter text nodes)
397             NodeList childNodes = element.getChildNodes();
398             Node node = null;
399             for (int j = 0; index > 0 && j < childNodes.getLength(); j++) {
400                 node = childNodes.item(j);
401                 if (!node.getNodeName().equals("#text") && !node.getNodeName().equals("#comment")) {
402                     index--;
403                 }
404             }
405             if (index == 0) {
406                 element = (Element) node;
407             } else {
408                 System.err.println("'" + context + "' out of document!");
409                 return null;
410             }
411         }
412         return element;
413     }
414
415     /**
416      * Interpret action.
417      * @param action : to be interpreted.
418      * @param source : component source of the action (only class is needed).
419      * @return if the event is handled here
420      */
421     protected static boolean generixEvent(final Node[] actions, final Component source) {
422         if (actions.length == 0) {
423             return false;
424         }
425
426         Node action = actions[0];
427         // All actions must be of the same kind.
428
429         boolean enable = getAttribute(action, "enable").equals(NAV) || getAttribute(action, "enable").equals("true");
430
431         if (!getAttribute(action, "set").equals(NAV) && enable) {
432             for (int i = 0; i < actions.length; i++) {
433                 action = actions[i];
434                 String context = getAttribute(action, "context");
435                 Element element = getElementByContext(context);
436                 String value = getAttribute(action, "value");
437                 String attribute = getAttribute(action, "set");
438                 if (element != null) {
439                     element.setAttribute(attribute, value);
440                     XConfiguration.addModifiedPath(getNodePath(element));
441                 }
442             }
443             refreshDisplay();
444             updated = true;
445             return true;
446         }
447
448         if (!getAttribute(action, "insert").equals(NAV) && enable) {
449             for (int i = 0; i < actions.length; i++) {
450                 action = actions[i];
451                 String context = getAttribute(action, "context");
452                 Element element = getElementByContext(context);
453                 String insertValue = XCommonManager.getAttribute(action, "insert");
454                 int insert = 0;
455                 try {
456                     insert = Integer.decode(insertValue);
457                 } catch (NumberFormatException e) {
458                     XChooser chooser = (XChooser) source;
459                     insertValue = chooser.choose().toString();
460                     insert = Integer.decode(insertValue) + 1;
461                 }
462                 Node hook = null;
463                 NodeList nodelist = element.getChildNodes();
464                 for (int xi = 0; xi < nodelist.getLength(); xi++) {
465                     Node node = nodelist.item(xi);
466                     if (!node.getNodeName().equals("#text") && !node.getNodeName().equals("#comment")) {
467                         if (insert == 1) {
468                             hook = node;
469                             break;
470                         }
471                         insert --;
472                     }
473                 }
474                 DocumentFragment fragment = document.createDocumentFragment();
475                 while (action.hasChildNodes()) {
476                     Node transferred = action.getFirstChild();
477                     action.removeChild(transferred);
478                     transferred = document.importNode(transferred, true);
479                     fragment.appendChild(transferred);
480                 }
481                 if (element != null) {
482                     element.insertBefore(fragment, hook);
483                 }
484             }
485             refreshDisplay();
486             updated = true;
487
488             return true;
489         }
490
491         if (!getAttribute(action, "delete").equals(NAV) && enable) {
492             for (int i = 0; i < actions.length; i++) {
493                 action = actions[i];
494                 String context = getAttribute(action, "context");
495                 Element element = getElementByContext(context);
496                 String xDelete = XCommonManager.getAttribute(action, "delete");
497                 int delete = 0;
498                 try {
499                     delete = Integer.decode(xDelete);
500                 } catch (NumberFormatException e) {
501                     if (source == null) {
502                         return false;
503                     }
504                     XChooser chooser = (XChooser) source;
505                     xDelete = chooser.choose().toString();
506                     delete = Integer.decode(xDelete);
507                 }
508                 Node deleted = null;
509                 NodeList nodelist = element.getChildNodes();
510                 for (int xi = 0; xi < nodelist.getLength(); xi++) {
511                     Node node = nodelist.item(xi);
512                     if (!node.getNodeName().equals("#text") && !node.getNodeName().equals("#comment")) {
513                         if (delete == 1) {
514                             deleted = node;
515                             break;
516                         }
517                         delete--;
518                     }
519                 }
520                 if (element != null && deleted != null) {
521                     element.removeChild(deleted);
522                 }
523             }
524             refreshDisplay();
525             updated = true;
526
527             return true;
528         }
529
530         if (!getAttribute(action, "choose").equals(NAV) && enable) {
531             if (source == null) {
532                 return false;
533             }
534
535             String context = getAttribute(action, "context");
536             Element element = getElementByContext(context);
537
538             if (source instanceof XChooser) {
539                 XChooser chooser = (XChooser) source;
540                 Object value = chooser.choose();
541                 if (value != null) {
542                     String attribute = getAttribute(action, "choose");
543                     if (element != null) {
544                         if (value instanceof String[]) {
545                             String[] values = (String[]) value;
546                             StringTokenizer toks = new StringTokenizer(attribute, ",");
547                             int n = Math.min(toks.countTokens(), values.length);
548                             for (int i = 0; i < n; i++) {
549                                 String attr = toks.nextToken().trim();
550                                 element.setAttribute(attr, values[i]);
551                             }
552                         } else {
553                             element.setAttribute(attribute, value.toString());
554                         }
555                         XConfiguration.addModifiedPath(getNodePath(element));
556                     }
557                     refreshDisplay();
558                     updated = true;
559                 }
560             } else {
561                 System.err.println("@choose attribute only valid on choosers " + "(SELECT, COLOR, FILE, ENTRY,...)");
562             }
563             return true;
564         }
565
566         if (!getAttribute(action, "choose-child").equals(NAV) && enable) {
567             if (source == null) {
568                 return false;
569             }
570
571             int childNb = Integer.parseInt(getAttribute(action, "choose-child")) - 1;
572             String context = getAttribute(action, "context");
573             Element element = getElementByContext(context);
574             NodeList list = element.getChildNodes();
575             if (element == null || childNb < 0 || childNb >= list.getLength()) {
576                 return false;
577             }
578             Node child = list.item(childNb);
579
580             if (source instanceof XChooser) {
581                 XChooser chooser = (XChooser) source;
582                 Object value = chooser.choose();
583                 if (value != null) {
584                     child.setTextContent(value.toString());
585                     XConfiguration.addModifiedPath(getNodePath(element));
586                     refreshDisplay();
587                     updated = true;
588                 }
589             } else {
590                 System.err.println("@choose-child attribute only valid on choosers " + "(SELECT, COLOR, FILE, ENTRY,...)");
591             }
592
593             return true;
594         }
595
596         return false;
597     }
598
599     public static final String getNodePath(Node node) {
600         StringBuilder buffer = new StringBuilder("/");
601         Stack<String> stack = new Stack<String>();
602         Node n = node;
603
604         while (n != null) {
605             String nname = n.getNodeName();
606             NamedNodeMap attrs = n.getAttributes();
607             if (attrs != null && attrs.getLength() != 0) {
608                 Node attr = attrs.getNamedItem("xconf-uid");
609                 if (attr != null) {
610                     nname += "[@xconf-uid=\"" + attr.getNodeValue() + "\"]";
611                 }
612             }
613             stack.push(nname);
614             n = n.getParentNode();
615         }
616
617         if (stack.size() >= 3) {
618             stack.pop();
619             stack.pop();
620         } else {
621             return null;
622         }
623
624         while (!stack.empty()) {
625             buffer.append("/");
626             buffer.append(stack.pop());
627         }
628
629         return buffer.toString();
630     }
631
632     /**
633      * Sentinel string for attribute consulting.
634      */
635     public static final String NAV = "\"not an value'";
636
637     /**
638      * Attribute consulting with default.
639      * @param node : consulted node
640      * @param name : attribute key
641      * @param value : default value
642      * @return the consulted value
643      */
644     public static String getAttribute(final Node node, final String name, final String value) {
645         String response = getAttribute(node, name);
646         if (response == NAV) {
647             return value;
648         }
649
650         return response;
651     }
652
653     /**
654      * Attribute consulting without default.
655      * @param node : consulted node.
656      * @param name : attribute key.
657      * @return the consulted value (or NAV if attribute key is absent)
658      */
659     public static String getAttribute(final Node node, final String name) {
660         NamedNodeMap attrs = node.getAttributes();
661         if (attrs == null) {
662             return NAV;
663         }
664         Node attr = attrs.getNamedItem(name);
665         if (attr == null) {
666             return NAV;
667         }
668
669         return attr.getNodeValue();
670     }
671
672     /**
673      * Typed attribute consulting with default.
674      * @param node : consulted node.
675      * @param name : attribute key.
676      * @param value : default value.
677      * @return the value.
678      */
679     public static int getInt(final Node node, final String name, final int value) {
680         String response = getAttribute(node, name);
681         if (response.equals(NAV) || response.equals("")) {
682             return value;
683         }
684
685         try {
686             return Integer.parseInt(response);
687         } catch (NumberFormatException e) {
688             return 0;
689         }
690     }
691
692     /**
693      * Typed attribute consulting with default.
694      * @param node : consulted node.
695      * @param name : attribute key.
696      * @param value : default value.
697      * @return the value.
698      */
699     public static double getDouble(final Node node, final String name, final double value) {
700         String response = getAttribute(node, name);
701         if (response.equals(NAV) || response.equals("")) {
702             return value;
703         }
704
705         try {
706             return Double.parseDouble(response);
707         } catch (NumberFormatException e) {
708             return 0;
709         }
710     }
711
712     /**
713      * Typed attribute consulting with default.
714      * @param node : consulted node.
715      * @param name : attribute key.
716      * @param value : default value.
717      * @return the value.
718      */
719     public static boolean getBoolean(final Node node, final String name, final boolean value) {
720         String response = getAttribute(node, name);
721         if (response.equals(NAV) || response.equals("")) {
722             return value;
723         }
724
725         return response.equalsIgnoreCase("true");
726     }
727
728     /**
729      * Manage color representation.
730      * @param source : the color.
731      * @return the string representation.
732      */
733     public static String getColor(final Color source) {
734         if (source == null) {
735             return "#000000";
736         }
737
738         String hexStr = Integer.toHexString(source.getRGB());
739         return "#" + hexStr.substring(2);
740     }
741
742     /**
743      * Manage color representation.
744      * @param source : the string representation.
745      * @return the corresponding color
746      */
747     public static Color getColor(final String source) {
748         return Color.decode(source);
749     }
750
751     /**
752      * Get top level window for correct dialog opening.
753      * @return top-level frame.
754      */
755     public static Frame getTopLevel() {
756         if (ScilabConsole.isExistingConsole()) {
757             Container main = (Container) ScilabConsole.getConsole().getAsSimpleConsole();
758             return (Frame) SwingUtilities.getAncestorOfClass(Frame.class, main);
759         }
760
761         return null;
762     }
763
764     /**
765      * Set a dimension for a component.
766      * @param component : the resized component.
767      * @param peer : the node having the dimension information.
768      */
769     public static void setDimension(final Component component, final Node peer) {
770         int height = XConfigManager.getInt(peer, "height", 0);
771         int width = XConfigManager.getInt(peer, "width",  0);
772         if (height > 0 && width > 0) {
773             component.setPreferredSize(new Dimension(width, height));
774         }
775     }
776
777     /**
778      * Create a copy of Scilab configuration file in the user directory.
779      */
780     public static void createUserCopy(String original, String copy) {
781         File fileConfig = new File(copy);
782         if (!fileConfig.exists()) {
783             refreshUserCopy(original, copy);
784         }
785     }
786
787     /**
788      * Refresh configuration file in the user directory with Scilab defaults.
789      */
790     public static void refreshUserCopy(String original, String copy) {
791         /* Create a local copy of the configuration file */
792         try {
793             copyFile(new File(original), new File(copy));
794         } catch (IOException e) {
795             System.err.println(ERROR_READ + copy);
796         }
797     }
798
799     /**
800      * Copy a file
801      * @param in src file
802      * @param out dest file
803      * @throws FileNotFoundException
804      */
805     protected static void copyFile(final File in, final File out) throws IOException {
806         FileInputStream fis = new FileInputStream(in);
807         FileOutputStream fos = new FileOutputStream(out);
808
809         byte[] buf = new byte[BUFSIZE];
810         int i = 0;
811         try {
812             while ((i = fis.read(buf)) != -1) {
813                 fos.write(buf, 0, i);
814             }
815             fis.close();
816             fos.close();
817         } catch (IOException e) {
818             e.printStackTrace();
819         }
820     }
821
822     /**
823      * Read the file to modify
824      */
825     protected static Document readDocument(final String fileName) {
826         File xml = new File(fileName);
827         DocumentBuilder docBuilder = null;
828
829         try {
830             DocumentBuilderFactory factory = ScilabDocumentBuilderFactory.newInstance();
831             docBuilder = factory.newDocumentBuilder();
832             return docBuilder.parse(xml);
833         } catch (ParserConfigurationException pce) {
834             System.err.println(ERROR_READ + fileName);
835         } catch (SAXException se) {
836             System.err.println(ERROR_READ + fileName);
837         } catch (IOException ioe) {
838             System.err.println(ERROR_READ + fileName);
839         }
840         return null;
841     }
842
843     /**
844      * Save the modifications
845      */
846     protected static void writeDocument(String filename, Node written) {
847         Transformer transformer = null;
848         try {
849             transformer = ScilabTransformerFactory.newInstance().newTransformer();
850         } catch (TransformerConfigurationException e1) {
851             System.err.println(ERROR_WRITE + filename);
852         } catch (TransformerFactoryConfigurationError e1) {
853             System.err.println(ERROR_WRITE + filename);
854         }
855         transformer.setOutputProperty(OutputKeys.INDENT, "yes");
856
857         StreamResult result = new StreamResult(new File(filename));
858         DOMSource source = new DOMSource(written);
859         try {
860             transformer.transform(source, result);
861         } catch (TransformerException e) {
862             System.err.println(ERROR_WRITE + filename);
863         }
864     }
865 }