Prefs: add a way to backup preferences file
[scilab.git] / scilab / modules / preferences / src / java / org / scilab / modules / preferences / XConfigManager.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.BorderLayout;
20 import java.awt.Dimension;
21 import java.awt.Font;
22 import java.awt.Frame;
23 import java.awt.Toolkit;
24 import java.awt.event.ComponentAdapter;
25 import java.awt.event.ComponentEvent;
26 import java.awt.event.ComponentListener;
27 import java.awt.event.WindowAdapter;
28 import java.awt.event.WindowEvent;
29 import java.io.File;
30 import java.io.IOException;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34
35 import javax.swing.JDialog;
36
37 import org.w3c.dom.Document;
38 import org.w3c.dom.DocumentFragment;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42
43 import org.scilab.modules.commons.ScilabCommons;
44 import org.scilab.modules.commons.ScilabCommonsUtils;
45 import org.scilab.modules.commons.xml.XConfiguration;
46 import org.scilab.modules.gui.utils.Position;
47 import org.scilab.modules.gui.utils.Size;
48 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
49 import org.scilab.modules.preferences.ScilabPreferences.ToolboxInfos;
50
51 /**
52  * Extended management of the Console configuration file.
53  *
54  * @author Pierre GRADIT
55  * @author Vincent COUVERT
56  */
57 public final class XConfigManager extends XCommonManager {
58
59     /** Exclusive activity flag between all XCommonManager descendants.*/
60     public static boolean active = false;
61
62     /** Scilab configuration file.*/
63     private static final String SCILAB_CONFIG_FILE = System.getenv("SCI") + "/modules/preferences/etc/XConfiguration.xml";
64
65     /** Scilab configuration stylesheet.*/
66     private static final String SCILAB_CONFIG_XSL = System.getenv("SCI") + "/modules/preferences/src/xslt/XConfiguration.xsl";
67
68     /** User configuration file.*/
69     private static final String USER_CONFIG_FILE = ScilabCommons.getSCIHOME() + "/XConfiguration.xml";
70
71     static {
72         //ScilabPreferences.addToolboxInfos("MyToolbox", System.getenv("SCI") + "/contrib/toolbox_skeleton/", System.getenv("SCI") + "/contrib/toolbox_skeleton/etc/toolbox_skeleton_preferences.xml");
73     }
74
75     /**
76      * Constructor blocked, singleton pattern.
77      */
78     private XConfigManager() {
79         throw new UnsupportedOperationException();
80     }
81
82     /** Display dialog and wait for events.
83      *
84      */
85     public static void displayAndWait() {
86         XConfigManager.active = true;
87         XWizardManager.active = false;
88
89         reloadTransformer(SCILAB_CONFIG_XSL);
90
91         // Set up Swing Side
92         dialog = new JDialog(getTopLevel(), "Scilab Preferences", true);
93         topSwing = dialog.getContentPane();
94         topSwing.setLayout(new BorderLayout());
95         // AWT implies to set layout at construction time.
96
97         // Set up DOM Side
98         readUserDocuments();
99         updated = false;
100
101         // Plug in resize
102         //dialog.setResizable(false);
103         dialog.addComponentListener(new ComponentAdapter() {
104             public void componentResized(ComponentEvent e) {
105                 Element element = document.getDocumentElement();
106                 Dimension dimension = dialog.getSize();
107                 int height = XConfigManager.getInt(element, "height", 0);
108                 int width = XConfigManager.getInt(element, "width",  0);
109                 if (Math.abs(((double) height) - dimension.getHeight()) > 0.1 && Math.abs(((double) width) - dimension.getWidth()) > 0.1 ) {
110                     element.setAttribute("height", Integer.toString((int) dimension.getHeight()));
111                     element.setAttribute("width", Integer.toString((int) dimension.getWidth()));
112                 }
113             }
114         });
115
116         dialog.addWindowListener(new WindowAdapter() {
117             @Override
118             public void windowClosing(WindowEvent e) {
119                 cancel();
120             }
121         });
122         ScilabSwingUtilities.closeOnEscape(dialog);
123
124         // Set up correspondence
125         correspondance = new HashMap<Component, XSentinel>();
126
127         // Let the show begin!
128         if (refreshDisplay()) {
129             // Center the dialog on the parent window
130             Frame topWindow = XCommonManager.getTopLevel();
131             int x = topWindow.getX() + (topWindow.getWidth() - dialog.getWidth()) / 2;
132             int y = topWindow.getY() + (topWindow.getHeight() - dialog.getHeight()) / 2;
133             dialog.setLocation(x, y);
134
135             dialog.setVisible(true);
136         }
137     }
138
139     /**
140      * Opens a dialog to setup preferences.
141      */
142     public static void openPreferences() {
143         XConfigManager.displayAndWait();
144     }
145
146     /** Secondary dialog for help.*/
147     private static JDialog help = null;
148
149     /** Read files to modify (and possibly create it).
150      */
151     private static void readUserDocuments() {
152         /*
153          * The default document just contains an empty tag <toolboxes/>
154          * We add a body and the different toolbox entries to have something like
155          * <toolboxes>
156          *   <body/>
157          *   <mytoolbox1><body>...</body></mytoolbox1>
158          *   <mytoolbox2><body>...</body></mytoolbox2>
159          * </toolboxes>
160          */
161
162         document = XConfiguration.getXConfigurationDocument();
163
164         // We remove all the previous tags (should be empty but an error could have occured...)
165         NodeList toolboxes = document.getElementsByTagName("toolboxes");
166         for (int i = 0; i < toolboxes.getLength(); i++) {
167             try {
168                 document.getDocumentElement().removeChild(toolboxes.item(i));
169             } catch (Exception e) {
170                 // Maybe root is not the good parent...
171             }
172         }
173
174         Element tbxs = document.createElement("toolboxes");
175         document.getDocumentElement().appendChild(tbxs);
176
177         // Body (rendered as XConfiguration.xsl example)
178         Element body = document.createElement("body");
179         tbxs.appendChild(body);
180
181         List<ToolboxInfos> infos = ScilabPreferences.getToolboxesInfos();
182         for (ToolboxInfos info: infos) {
183             String filename = new File(info.getPrefFile()).getName();
184             String tbxTag = info.getName().replace(' ', '_');
185             String tbxFile = ScilabCommons.getSCIHOME() + "/" + filename;
186
187             // the copy is made only if needed
188             createUserCopy(info.getPrefFile(), tbxFile);
189
190             // Building document fragment
191             Element token = document.createElement(tbxTag);
192             token.setAttribute("title", info.getName());
193             DocumentFragment fragment = document.createDocumentFragment();
194             Document tbxDocument = readDocument(tbxFile);
195             Node transferred = tbxDocument.getDocumentElement();
196
197             transferred = document.importNode(transferred, true);
198             fragment.appendChild(transferred);
199             token.insertBefore(fragment, null);
200             tbxs.appendChild(token);
201         }
202     }
203
204     private static void WriteUserDocuments() {
205         // Toolboxes files
206         NodeList toolboxes = document.getElementsByTagName("toolboxes");
207         Element tbxs = null;
208         Element emptyTbxs;
209         if (toolboxes != null && toolboxes.getLength() != 0) {
210             tbxs = (Element) toolboxes.item(0);
211             List<ToolboxInfos> infos = ScilabPreferences.getToolboxesInfos();
212             for (ToolboxInfos info: infos) {
213                 String tbxTag = info.getName().replace(' ', '_');
214                 NodeList list = tbxs.getElementsByTagName(tbxTag);
215                 if (list != null && list.getLength() != 0) {
216                     Element mytbx = (Element) list.item(0);
217                     if (mytbx.hasChildNodes()) {
218                         String filename = new File(info.getPrefFile()).getName();
219                         String tbxFile = ScilabCommons.getSCIHOME() + "/" + filename;
220                         XConfiguration.writeDocument(tbxFile, mytbx.getFirstChild());
221                     }
222                 }
223             }
224         }
225
226         if (tbxs != null) {
227             document.getDocumentElement().removeChild(tbxs);
228         }
229
230         XConfiguration.writeDocument(USER_CONFIG_FILE, document);
231
232         if (tbxs != null) {
233             document.getDocumentElement().appendChild(tbxs);
234         }
235     }
236
237     private static void cancel() {
238         dialog.dispose();
239         XCommonManager.invalidateXSL();
240         XConfiguration.invalidate();
241         NodeList toolboxes = document.getElementsByTagName("toolboxes");
242         if (toolboxes != null && toolboxes.getLength() != 0) {
243             Element tbxs = (Element) toolboxes.item(0);
244             document.getDocumentElement().removeChild(tbxs);
245         }
246         updated = false;
247         refreshDisplay();
248     }
249
250     /** Interpret action.
251      *
252      * @param action : to be interpreted.
253      * @param source : component source of the action (only class is needed).
254      * @return whether event was treated or not.
255      */
256     public static boolean xEvent(final Node[] actions, final Component source) {
257         if (generixEvent(actions, source)) {
258             return true;
259         }
260
261         if (actions.length == 0) {
262             return false;
263         }
264
265         Node action = actions[0];
266         String callback = getAttribute(action, "callback");
267         /** help deprecated
268             if (callback.equals("Help")) {
269             // TODO it can be a contextual help.
270             //System.err.println("Help not implemented yet!");
271             if (differential) {
272             System.out.println(": Help.");
273             }
274             return true;
275             }
276         **/
277         if (callback.equals("Save Backup")) {
278             String path = getAttribute(action, "path");
279             writeDocument(ScilabCommonsUtils.getCorrectedPath(path), document);
280
281             return true;
282         }
283
284         if (callback.equals("Restore Backup")) {
285             String path = getAttribute(action, "path");
286             try {
287                 copyFile(new File(ScilabCommonsUtils.getCorrectedPath(path)), new File(USER_CONFIG_FILE));
288             } catch (IOException e) {
289                 System.err.println(e);
290             }
291
292             XConfiguration.invalidate();
293             XConfiguration.addModifiedPath("ALL");
294             reloadTransformer(SCILAB_CONFIG_XSL);
295             document = XConfiguration.createDocument();
296
297             List<ToolboxInfos> infos = ScilabPreferences.getToolboxesInfos();
298             for (ToolboxInfos info : infos) {
299                 String filename = new File(info.getPrefFile()).getName();
300                 String tbxFile = ScilabCommons.getSCIHOME() + "/" + filename;
301                 refreshUserCopy(info.getPrefFile(), tbxFile);
302             }
303             readUserDocuments();
304             updated = false;
305             refreshDisplay();
306
307             return true;
308         }
309
310         if (callback.equals("Ok")) {
311             WriteUserDocuments();
312             dialog.dispose();
313             XCommonManager.invalidateXSL();
314             updated = false;
315             XConfiguration.fireXConfigurationEvent();
316             XConfiguration.invalidate();
317             return true;
318         }
319         if (callback.equals("Apply")) {
320             updated = false;
321             WriteUserDocuments();
322             XConfiguration.fireXConfigurationEvent();
323             return true;
324         }
325         if (callback.equals("Default")) {
326             XConfiguration.invalidate();
327             XConfiguration.addModifiedPath("ALL");
328             reloadTransformer(SCILAB_CONFIG_XSL);
329             document = XConfiguration.createDocument();
330             writeDocument(USER_CONFIG_FILE, document);
331             List<ToolboxInfos> infos = ScilabPreferences.getToolboxesInfos();
332             for (ToolboxInfos info : infos) {
333                 String filename = new File(info.getPrefFile()).getName();
334                 String tbxFile = ScilabCommons.getSCIHOME() + "/" + filename;
335                 refreshUserCopy(info.getPrefFile(), tbxFile);
336             }
337             readUserDocuments();
338             updated = false;
339             refreshDisplay();
340
341             return true;
342         }
343         if (callback.equals("Cancel")) {
344             cancel();
345             return true;
346         }
347         return false;
348     }
349 }