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