Bug 5478 fixed: Scilab could not be started with a non readable/writeable SCIHOME
[scilab.git] / scilab / modules / scinotes / src / java / org / scilab / modules / scinotes / utils / ConfigSciNotesManager.java
1 /*
2  * Scilab (http://www.scilab.org/) - This file is part of Scilab
3  * Copyright (C) 2009 - INRIA - Allan SIMON
4  * Copyright (C) 2010 - Calixte DENIZET
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-en.txt
11  *
12  */
13
14 package org.scilab.modules.scinotes.utils;
15
16 import java.awt.Color;
17 import java.awt.Font;
18 import java.awt.Toolkit;
19 import java.awt.print.Paper;
20
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.nio.charset.Charset;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.Hashtable;
31 import java.util.Properties;
32 import java.util.Enumeration;
33 import java.util.Map;
34 import java.util.UUID;
35
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39 import javax.xml.transform.OutputKeys;
40 import javax.xml.transform.Transformer;
41 import javax.xml.transform.TransformerConfigurationException;
42 import javax.xml.transform.TransformerException;
43 import javax.xml.transform.TransformerFactoryConfigurationError;
44 import javax.xml.transform.dom.DOMSource;
45 import javax.xml.transform.stream.StreamResult;
46
47 import org.scilab.modules.commons.ScilabCommons;
48 import org.scilab.modules.commons.ScilabConstants;
49 import org.scilab.modules.commons.ScilabCommonsUtils;
50 import org.scilab.modules.commons.xml.ScilabXMLUtilities;
51 import org.scilab.modules.commons.xml.ScilabDocumentBuilderFactory;
52 import org.scilab.modules.commons.xml.ScilabTransformerFactory;
53 import org.scilab.modules.gui.utils.Position;
54 import org.scilab.modules.gui.utils.Size;
55
56 import org.scilab.modules.scinotes.ScilabView;
57 import org.scilab.modules.scinotes.ScilabEditorPane;
58 import org.scilab.modules.scinotes.SciNotes;
59 import org.scilab.modules.scinotes.TabManager;
60 import org.scilab.modules.scinotes.MatchingBlockManager;
61
62 import org.w3c.dom.Document;
63 import org.w3c.dom.Element;
64 import org.w3c.dom.Node;
65 import org.w3c.dom.NodeList;
66 import org.w3c.dom.Text;
67 import org.xml.sax.SAXException;
68
69 /**
70  * Configuration class which interacts with the file etc/scinotesConfiguration.xml
71  */
72 public final class ConfigSciNotesManager {
73
74     public static final String RECENTBASEDIR = "recentBaseDir";
75     public static final String BASEDIR = "baseDir";
76     public static final String RECENTFILEPATTERN = "recentFilePattern";
77     public static final String FILEPATTERN = "filePattern";
78     public static final String RECENTWORDPATTERN = "recentWordPattern";
79     public static final String WORDPATTERN = "wordPattern";
80
81     private static final int BUFSIZE = 1024;
82
83     private static final int MARGIN = 20;
84
85     private static final String HORIZONTALWRAP = "HorizontalWrapAllowed";
86     private static final String ERROR_READ = "Could not load file: ";
87     private static final String ERROR_WRITE = "Could not save file: ";
88     private static final String VALUE = "value";
89     private static final String VERSION = "version";
90     private static final String STYLE = "style";
91     private static final String UNDERLINE = "underline";
92     private static final String DEFAULTUNDERLINE = "defaultUnderline";
93     private static final String STROKE = "stroke";
94     private static final String DEFAULTSTROKE = "defaultStroke";
95     private static final String FONT_SIZE = "FontSize";
96     private static final String FONT_STYLE = "FontStyle";
97     private static final String FONT_NAME = "FontName";
98     private static final String DEFAULT = "default";
99     private static final String WIDTH = "width";
100     private static final String HEIGHT = "height";
101     private static final String XCOORD = "x";
102     private static final String YCOORD = "y";
103     private static final String MAINWINPOSITION = "MainWindowPosition";
104     private static final String MAINWINSIZE = "MainWindowSize";
105     private static final String AUTOINDENT = "AutoIndent";
106     private static final String DEFAULTENCONDING = "DefaultEncoding";
107     private static final String LINEHIGHLIGHTER = "LineHighlighter";
108     private static final String HELPONTYPING = "HelpOnTyping";
109     private static final String LINENUMBERING = "LineNumbering";
110     private static final String EDITOR = "SciNotes";
111     private static final String SUPPRESSCOMMENTS = "SuppressComments";
112
113     private static final String FOREGROUNDCOLOR = "ForegroundColor";
114     private static final String BACKGROUNDCOLOR = "BackgroundColor";
115     private static final String ALTERNCOLORS = "AlternColors";
116     private static final String COLOR1 = "color1";
117     private static final String COLOR2 = "color2";
118     private static final String LINECOLOR = "linecolor";
119     private static final String CONTOURCOLOR = "contourcolor";
120     private static final String COLORPREFIX = "#";
121
122     private static final String NAME = "name";
123     private static final String NULL = "null";
124
125     private static final String PROFILE = "Profile";
126
127     private static final String RECENT_SEARCH = "recentSearch";
128     private static final String SEARCH = "search";
129     private static final String RECENT_REPLACE = "recentReplace";
130     private static final String REPLACE = "replace";
131     private static final String RECURSIVE = "recursiveSearch";
132     private static final String LINEBYLINE = "readLineByLine";
133     private static final String FILECASE = "fileCase";
134     private static final String SEARCHINFILES = "searchInFiles";
135
136     private static final String EXPRESSION = "exp";
137     private static final String REGULAR_EXPRESION = "regularExp";
138     private static final String CIRCULAR = "circularSearch";
139     private static final String WORD_WARP = "wordWarp";
140     private static final String WHOLE_WORD = "wholeWord";
141     private static final String CASE_SENSITIVE = "caseSensitive";
142     private static final String STATE_FLAG = "state";
143
144     private static final String SETTING = "Setting";
145     private static final String SCINOTES = "scinotes";
146     private static final String TRUE = "true";
147     private static final String FALSE = "false";
148     private static final String DOCUMENT = "document";
149     private static final String PATH = "path";
150     private static final String RECENT_FILES = "recentFiles";
151     private static final String OPEN_FILES = "openFiles";
152     private static final String RESTOREFILES = "RestoreFiles";
153     private static final String EDITORINST = "editorInstance";
154     private static final String EDITORUUID = "EditorUUID";
155     private static final String PANEINST = "paneInstance";
156     private static final String PANEINST_EX = "paneInstanceExtra";
157
158     private static final String FAVORITE_DIRS = "favoriteDirectories";
159     private static final String DIRECTORY = "Directory";
160
161     private static final String PAPER = "PaperFormat";
162     private static final String MARGINLEFT = "MarginLeft";
163     private static final String MARGINRIGHT = "MarginRight";
164     private static final String MARGINTOP = "MarginTop";
165     private static final String MARGINBOTTOM = "MarginBottom";
166
167     private static final String CODENAVIGATOR = "CodeNavigator";
168
169     private static final String SCI = "SCI";
170     private static final String SCINOTES_CONFIG_FILE = System.getenv(SCI) + "/modules/scinotes/etc/scinotesConfiguration.xml";
171
172     private static final int PLAIN = 0;
173     private static final int BOLD =  1;
174     private static final int ITALIC = 2;
175     private static final int BOLDITALIC = 3;
176
177     private static final int DEFAULT_WIDTH = 650;
178     private static final int DEFAULT_HEIGHT = 550;
179
180     private static final int MAXRECENT = 20;
181
182     private static Document document;
183
184     private static boolean updated;
185     private static boolean mustSave = true;
186
187     private static String USER_SCINOTES_CONFIG_FILE = ScilabConstants.SCIHOME.toString() + "/scinotesConfiguration.xml";
188
189     static {
190         if (ScilabConstants.SCIHOME != null && ScilabConstants.SCIHOME.canRead() && ScilabConstants.SCIHOME.canWrite()) {
191             USER_SCINOTES_CONFIG_FILE = ScilabConstants.SCIHOME.toString() + "/scinotesConfiguration.xml";
192         } else {
193             USER_SCINOTES_CONFIG_FILE = SCINOTES_CONFIG_FILE;
194             mustSave = false;
195         }
196     }
197
198     /**
199      * Constructor
200      */
201     private ConfigSciNotesManager() {
202         throw new UnsupportedOperationException();
203     }
204
205     /**
206      * Create a copy of Scilab configuration file in the user directory
207      */
208     public static void createUserCopy() {
209         if (checkVersion() && mustSave) {
210             /* Create a local copy of the configuration file */
211             ScilabCommonsUtils.copyFile(new File(SCINOTES_CONFIG_FILE), new File(USER_SCINOTES_CONFIG_FILE));
212             document = null;
213             updated = true;
214         }
215     }
216
217     /**
218      * Get the name of the user configuration file
219      * @return the name of the configuration file
220      */
221     public static String getUserConfigFile() {
222         return USER_SCINOTES_CONFIG_FILE;
223     }
224
225     /**
226      * @return true if scinotesConfiguration.xml in etc has a version greater than the version in home
227      */
228     public static boolean checkVersion() {
229         if (updated) {
230             return false;
231         }
232
233         File fileConfig = new File(USER_SCINOTES_CONFIG_FILE);
234
235         if (fileConfig.exists()) {
236             document = null;
237             readDocument(SCINOTES_CONFIG_FILE);
238             Node setting = getNodeChild(null, SETTING);
239             String str = ((Element) setting).getAttribute(VERSION);
240             if (str != null && str.length() != 0) {
241                 float versionEtc = Float.parseFloat(str);
242                 document = null;
243                 readDocument();
244                 setting = getNodeChild(null, SETTING);
245                 str = ((Element) setting).getAttribute(VERSION);
246                 document = null;
247
248                 if (str != null && str.length() != 0) {
249                     float versionHome = Float.parseFloat(str);
250                     return versionEtc != versionHome;
251                 }
252             }
253         }
254
255         return true;
256     }
257
258     /**
259      * @return the paper format saved in previous session
260      */
261     public static Paper getPaperFormat() {
262         readDocument();
263
264         Element root = document.getDocumentElement();
265
266         NodeList profiles = root.getElementsByTagName(PROFILE);
267         Element scinotesProfile = (Element) profiles.item(0);
268
269         NodeList allSizeElements = scinotesProfile.getElementsByTagName(PAPER);
270         Element paper = (Element) allSizeElements.item(0);
271
272         if (paper == null) {
273             return new Paper();
274         }
275
276         Paper p = new Paper();
277         double width = Double.parseDouble(paper.getAttribute(WIDTH));
278         double height = Double.parseDouble(paper.getAttribute(HEIGHT));
279         double marginLeft = Double.parseDouble(paper.getAttribute(MARGINLEFT));
280         double marginRight = Double.parseDouble(paper.getAttribute(MARGINRIGHT));
281         double marginTop = Double.parseDouble(paper.getAttribute(MARGINTOP));
282         double marginBottom = Double.parseDouble(paper.getAttribute(MARGINBOTTOM));
283         p.setSize(width, height);
284         p.setImageableArea(marginLeft, marginTop, width - (marginLeft + marginRight), height - (marginTop + marginBottom));
285
286         return p;
287     }
288
289     /**
290      * Save the paper format
291      * @param p the Paper to save
292      */
293     public static void savePaperFormat(Paper p) {
294         readDocument();
295
296         Element root = document.getDocumentElement();
297
298         NodeList profiles = root.getElementsByTagName(PROFILE);
299         Element scinotesProfile = (Element) profiles.item(0);
300
301         NodeList allSizeElements = scinotesProfile.getElementsByTagName(PAPER);
302         Element paper = (Element) allSizeElements.item(0);
303
304         if (paper == null) {
305             paper = document.createElement(PAPER);
306             scinotesProfile.appendChild((Node) paper);
307         }
308
309         double width = p.getWidth();
310         double height = p.getHeight();
311         double marginLeft = p.getImageableX();
312         double marginRight = width - (marginLeft + p.getImageableWidth());
313         double marginTop = p.getImageableY();
314         double marginBottom = height - (marginTop + p.getImageableHeight());
315
316         paper.setAttribute(WIDTH, Double.toString(width));
317         paper.setAttribute(HEIGHT, Double.toString(height));
318         paper.setAttribute(MARGINLEFT, Double.toString(marginLeft));
319         paper.setAttribute(MARGINRIGHT, Double.toString(marginRight));
320         paper.setAttribute(MARGINTOP, Double.toString(marginTop));
321         paper.setAttribute(MARGINBOTTOM, Double.toString(marginBottom));
322
323         writeDocument();
324     }
325
326     /**
327      * @return the color the altern colors for inner function
328      */
329     public static Color[] getAlternColors() {
330         readDocument();
331
332         Element root = document.getDocumentElement();
333
334         NodeList profiles = root.getElementsByTagName(PROFILE);
335         Element scinotesProfile = (Element) profiles.item(0);
336
337         NodeList allSizeElements = scinotesProfile.getElementsByTagName(ALTERNCOLORS);
338         Element alternColors = (Element) allSizeElements.item(0);
339         Color[] arr = new Color[2];
340
341         Color c;
342         if (NULL.equals(alternColors.getAttribute(COLOR1))) {
343             c = null;
344         } else {
345             c = Color.decode(alternColors.getAttribute(COLOR1));
346         }
347
348         arr[0] = c;
349
350         if (NULL.equals(alternColors.getAttribute(COLOR2))) {
351             c = null;
352         } else {
353             c = Color.decode(alternColors.getAttribute(COLOR2));
354         }
355
356         arr[1] = c;
357         return arr;
358     }
359
360     /**
361      * Get the background Color
362      * @return the background Color
363      */
364     public static Color getSciNotesBackgroundColor() {
365         /* Load file */
366         readDocument();
367
368         Element root = document.getDocumentElement();
369
370         NodeList profiles = root.getElementsByTagName(EDITOR);
371         Element scinotesProfile = (Element) profiles.item(0);
372
373         NodeList allElements = scinotesProfile.getElementsByTagName(BACKGROUNDCOLOR);
374         Element scinotesBackground = (Element) allElements.item(0);
375
376         /*direct create a Color with "#FF00FF" string from the xml */
377         return Color.decode(scinotesBackground.getAttribute(VALUE));
378     }
379
380     /**
381      * Get the foreground Color
382      * @return the foreground Color
383      */
384     public static Color getSciNotesForegroundColor() {
385         /* Load file */
386         readDocument();
387
388         Element root = document.getDocumentElement();
389
390         NodeList profiles = root.getElementsByTagName(EDITOR);
391         Element scinotesProfile = (Element) profiles.item(0);
392
393         NodeList allElements = scinotesProfile.getElementsByTagName(FOREGROUNDCOLOR);
394         Element scinotesForeground = (Element) allElements.item(0);
395
396         /*direct create a Color with "#FF00FF" string from the xml */
397         return Color.decode(scinotesForeground.getAttribute(VALUE));
398     }
399
400     /**
401      * Save SciNotes BackgroundColor
402      * @param color the new Color
403      */
404     public static void saveSciNotesBackground(Color color) {
405
406         /* Load file */
407         readDocument();
408
409         Element root = document.getDocumentElement();
410
411         NodeList profiles = root.getElementsByTagName(EDITOR);
412         Element scinotesProfile = (Element) profiles.item(0);
413
414         NodeList allSizeElements = scinotesProfile.getElementsByTagName(BACKGROUNDCOLOR);
415         Element scinotesBackground = (Element) allSizeElements.item(0);
416
417         String rgb = Integer.toHexString(color.getRGB());
418         scinotesBackground.setAttribute(VALUE, COLORPREFIX + rgb.substring(2, rgb.length()));
419
420         /* Save changes */
421         writeDocument();
422     }
423
424     /**
425      * Save SciNotes foregroundColor
426      * @param color the new Color
427      */
428     public static void saveSciNotesForeground(Color color) {
429         readDocument();
430
431         Element root = document.getDocumentElement();
432
433         NodeList profiles = root.getElementsByTagName(EDITOR);
434         Element scinotesProfile = (Element) profiles.item(0);
435
436         NodeList allSizeElements = scinotesProfile.getElementsByTagName(FOREGROUNDCOLOR);
437         Element scinotesForeground = (Element) allSizeElements.item(0);
438
439         String rgb = Integer.toHexString(color.getRGB());
440         scinotesForeground.setAttribute(VALUE, COLORPREFIX + rgb.substring(2, rgb.length()));
441
442         /* Save changes */
443         writeDocument();
444     }
445
446     /**
447      * Save SciNotes autoIndent or not
448      * @param activated if autoIndent should be used or not
449      */
450     public static void saveSuppressComments(boolean activated) {
451         /* Load file */
452         readDocument();
453
454         Element root = document.getDocumentElement();
455
456         NodeList profiles = root.getElementsByTagName(PROFILE);
457         Element scinotesProfile = (Element) profiles.item(0);
458
459         NodeList allSizeElements = scinotesProfile.getElementsByTagName(SUPPRESSCOMMENTS);
460         Element suppressComments = (Element) allSizeElements.item(0);
461         if (suppressComments == null) {
462             Element sup = document.createElement(SUPPRESSCOMMENTS);
463             sup.setAttribute(VALUE, new Boolean(activated).toString());
464             scinotesProfile.appendChild((Node) sup);
465         } else {
466             suppressComments.setAttribute(VALUE, new Boolean(activated).toString());
467         }
468         /* Save changes */
469         writeDocument();
470     }
471
472     /**
473      * @return a boolean if autoIndent should be used or not
474      */
475     public static boolean getSuppressComments() {
476         /* Load file */
477         readDocument();
478
479         Element root = document.getDocumentElement();
480         NodeList profiles = root.getElementsByTagName(PROFILE);
481         Element scinotesProfile = (Element) profiles.item(0);
482         NodeList allSizeElements = scinotesProfile.getElementsByTagName(SUPPRESSCOMMENTS);
483         Element suppressComments = (Element) allSizeElements.item(0);
484
485         if (suppressComments == null) {
486             return true;
487         } else {
488             return new Boolean(suppressComments.getAttribute(VALUE));
489         }
490     }
491
492     /**
493      * Get all the recent opened files
494      * @return an array of uri
495      */
496     public static List<File> getAllRecentOpenedFiles() {
497         List<File> files = new ArrayList<File>();
498         readDocument();
499         Element root = (Element) document.getDocumentElement().getElementsByTagName(RECENT_FILES).item(0);
500         if (root != null) {
501             NodeList recentFiles = root.getElementsByTagName(DOCUMENT);
502             for (int i = 0; i < recentFiles.getLength(); ++i) {
503                 Element style = (Element) recentFiles.item(i);
504
505                 File temp = new File(style.getAttribute(PATH));
506
507                 if (temp.exists()) {
508                     files.add(temp);
509                 } else {
510                     root.removeChild((Node) style);
511                 }
512             }
513         }
514
515         clean(root);
516         writeDocument();
517
518         return files;
519     }
520
521     /**
522      * Get all the favorite dirs
523      * @return a list of File
524      */
525     public static List<File> getAllFavoriteDirs() {
526         List<File> dirsList = new ArrayList<File>();
527         readDocument();
528         Element root = (Element) document.getDocumentElement().getElementsByTagName(FAVORITE_DIRS).item(0);
529         if (root != null) {
530             NodeList dirs = root.getElementsByTagName(DIRECTORY);
531             for (int i = 0; i < dirs.getLength(); i++) {
532                 Element dir = (Element) dirs.item(i);
533                 File temp = new File(dir.getAttribute(PATH));
534
535                 if (temp.exists()) {
536                     dirsList.add(temp);
537                 } else {
538                     root.removeChild((Node) dir);
539                 }
540             }
541         }
542
543         clean(root);
544         writeDocument();
545
546         return dirsList;
547     }
548
549     /**
550      * Add a path to a favorite directory
551      * @param path the path of the dir
552      */
553     public static void saveFavoriteDirectory(String path) {
554         readDocument();
555
556         Element root = (Element) document.getDocumentElement().getElementsByTagName(FAVORITE_DIRS).item(0);
557         Element newDir =  document.createElement(DIRECTORY);
558         newDir.setAttribute(PATH, path);
559         root.appendChild((Node) newDir);
560
561         clean(root);
562         writeDocument();
563     }
564
565     /**
566      * Remove the last favorite directory
567      */
568     public static void rmLastFavoriteDirectory() {
569         readDocument();
570
571         Element root = (Element) document.getDocumentElement().getElementsByTagName(FAVORITE_DIRS).item(0);
572         NodeList dirs = root.getElementsByTagName(DIRECTORY);
573
574         if (dirs.getLength() != 0) {
575             root.removeChild(dirs.item(dirs.getLength() - 1));
576         }
577
578         clean(root);
579         writeDocument();
580     }
581
582     /**
583      * Add a file to recent Opened Files
584      * @param filePath the path of the files to add
585      */
586     public static void saveToRecentOpenedFiles(String filePath) {
587         readDocument();
588
589         Element root = (Element) document.getDocumentElement().getElementsByTagName(RECENT_FILES).item(0);
590         NodeList recentFiles = root.getElementsByTagName(DOCUMENT);
591         int numberOfFiles = recentFiles.getLength();
592
593         // we remove all the duplicate
594         for (int i = 0; i < recentFiles.getLength();  ++i) {
595             Element style = (Element) recentFiles.item(i);
596             if (filePath.equals(style.getAttribute(PATH))) {
597                 root.removeChild((Node) style);
598                 numberOfFiles--;
599             }
600         }
601
602         // if we have reached the maximun , we remove the oldest files
603         while (recentFiles.getLength() >= MAXRECENT) {
604             root.removeChild(root.getFirstChild());
605         }
606
607         Element newFile =  document.createElement(DOCUMENT);
608         newFile.setAttribute(PATH, filePath);
609         root.appendChild((Node) newFile);
610
611         clean(root);
612         writeDocument();
613     }
614
615     /**
616      * @return true if open files should be restored upon restart.
617      */
618     public static boolean getRestoreOpenedFiles() {
619         readDocument();
620
621         Element root = document.getDocumentElement();
622
623         NodeList profiles = root.getElementsByTagName(PROFILE);
624         Element scinotesProfile = (Element) profiles.item(0);
625
626         NodeList allSizeElements = scinotesProfile.getElementsByTagName(RESTOREFILES);
627         Element restorefiles = (Element) allSizeElements.item(0);
628
629         return TRUE.equals(restorefiles.getAttribute(VALUE));
630     }
631
632     /**
633      * Active/deactive restoration of open files upon restart of scinotes
634      * @param activated active or not
635      */
636     public static void saveRestoreOpenedFiles(boolean activated) {
637         readDocument();
638
639         Element root = document.getDocumentElement();
640
641         NodeList profiles = root.getElementsByTagName(PROFILE);
642         Element scinotesProfile = (Element) profiles.item(0);
643
644         NodeList allSizeElements = scinotesProfile.getElementsByTagName(RESTOREFILES);
645         Element restorefiles = (Element) allSizeElements.item(0);
646         if (restorefiles == null) {
647             Element restoreElement = document.createElement(RESTOREFILES);
648             restorefiles.setAttribute(VALUE, new Boolean(activated).toString());
649             restorefiles.appendChild((Node) restoreElement);
650         } else {
651             restorefiles.setAttribute(VALUE, new Boolean(activated).toString());
652         }
653
654         clean(root);
655         writeDocument();
656     }
657
658     /**
659      * Return a count of the open files that exist. New files, for instance, do not.
660      * @return count
661      */
662     public static int countExistingOpenFiles(UUID uuid) {
663         int count = 0;
664         readDocument();
665         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
666         if (root != null) {
667             NodeList openFiles = root.getElementsByTagName(DOCUMENT);
668             for (int i = 0; i < openFiles.getLength(); ++i) {
669                 Element style = (Element) openFiles.item(i);
670                 if (style.getAttribute(EDITORINST).equals(uuid.toString())) {
671                     File temp = new File(style.getAttribute(PATH));
672                     if (temp.exists()) {
673                         count++;
674                     }
675                 }
676             }
677         }
678         return count;
679     }
680
681     /**
682      * Get the list of open files associated with an editor instance hashcode.
683      * Only files that exist are returned.
684      * @param editorID unique id of an editor instance
685      * @return an array of uri
686      */
687     public static List<File> getOpenFilesByEditor(UUID editorID) {
688         List<File> files = new ArrayList<File>();
689         readDocument();
690         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
691         if (root != null) {
692             NodeList openFiles = root.getElementsByTagName(DOCUMENT);
693
694             /* Loop through the list and return only the files with a matching hash code. */
695             int i = 0;
696             for (; i < openFiles.getLength(); i++) {
697                 Element doc = (Element) openFiles.item(i);
698
699                 if (editorID.equals(UUID.fromString(doc.getAttribute(EDITORINST)))) {
700                     File temp = new File(doc.getAttribute(PATH));
701
702                     /* Check that the file exists and add to file list or else remove the node. */
703                     if (temp.exists() && !files.contains(temp)) {
704                         files.add(temp);
705                     } else {
706                         root.removeChild((Node) doc);
707                         i--;  // Adjust index to account for removed item.
708                     }
709                 }
710             }
711
712             clean(root);
713             writeDocument();
714         }
715         return files;
716     }
717
718     /**
719      * Get a list of unique editor instance identifiers in the list of open files.
720      * @return an array of editor instance identifiers
721      */
722     public static List<UUID> getOpenFilesEditorList() {
723         List<UUID> editorIDlist = new ArrayList<UUID>();
724         readDocument();
725         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
726         if (root != null) {
727             NodeList openFiles = root.getElementsByTagName(DOCUMENT);
728
729             /* Loop through the list and return the list of IDs. */
730             for (int i = 0; i < openFiles.getLength(); ++i) {
731                 Element style = (Element) openFiles.item(i);
732
733                 UUID editorID = UUID.fromString(style.getAttribute(EDITORINST));
734
735                 if (!editorIDlist.contains(editorID)) {
736                     editorIDlist.add(editorID);
737                 }
738             }
739         }
740         return editorIDlist;
741     }
742
743     /**
744      * Add a file to currently open files
745      * @param filePath the path of the files to add
746      * @param editorInstance instance of the editor to associate with the open file
747      * @param sep the pane
748      */
749     public static void saveToOpenFiles(String filePath, SciNotes editorInstance, ScilabEditorPane sep) {
750         saveToOpenFiles(filePath, editorInstance, sep, -1);
751     }
752
753     /**
754      * Add a file to currently open files
755      * @param filePath the path of the files to add
756      * @param editorInstance instance of the editor to associate with the open file
757      * @param sep the pane
758      */
759     public static void saveToOpenFiles(String filePath, SciNotes editorInstance, ScilabEditorPane sep, int pos) {
760         readDocument();
761         removeFromOpenFiles(editorInstance.getUUID(), Arrays.asList(new String[] {filePath}));
762         UUID nil = new UUID(0, 0);
763
764         // Find the element containing the list of open files
765         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
766         // Get the list of open files
767         NodeList openFiles = root.getElementsByTagName(DOCUMENT);
768         int numberOfFiles = openFiles.getLength();
769
770         Node bef = null;
771         if (pos != - 1 && pos < numberOfFiles) {
772             bef = openFiles.item(pos);
773         }
774
775         Element newFile =  document.createElement(DOCUMENT);
776         newFile.setAttribute(PATH, filePath);
777         // Record the editor instance's hash code
778         newFile.setAttribute(EDITORINST, editorInstance.getUUID().toString());
779         //root.appendChild((Node) newFile);
780         // Record the text pane's hash code
781         newFile.setAttribute(PANEINST, sep.getUUID().toString());
782         newFile.setAttribute(PANEINST_EX, nil.toString());
783         if (bef != null) {
784             root.insertBefore((Node) newFile, bef);
785         } else {
786             root.appendChild((Node) newFile);
787         }
788
789         clean(root);
790         writeDocument();
791     }
792
793     /**
794      * Remove a tab with an open file from the list of open files
795      * @param editorInstance instance of the editor
796      * @param sep instance of the editor pane.
797      */
798     public static void removeFromOpenFiles(SciNotes editorInstance, ScilabEditorPane sep) {
799         removeFromOpenFiles(editorInstance.getUUID(), sep.getUUID());
800     }
801
802     /**
803      * Remove from the list of open files all files with a matching editor instance identifer
804      * @param editorID editor instance identifer
805      */
806     public static void removeFromOpenFiles(UUID editorID) {
807         removeFromOpenFiles(editorID, new UUID(0, 0) /* nil UUID */);
808     }
809
810     /**
811      * Remove a tab with an open file from the list of open files
812      * @param editorID editor instance identifer
813      * @param sepID editor pane instance identifer. If a nil UUID is passed,
814      * all files with a matching editor instance identifer are removed.
815      */
816     public static void removeFromOpenFiles(UUID editorID, List<String> toRemove) {
817         readDocument();
818
819         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
820         NodeList openFiles = root.getElementsByTagName(DOCUMENT);
821
822         // Remove item with matching editorID and sepID.
823         for (int i = openFiles.getLength() - 1; i >= 0; i--) {
824             Element doc = (Element) openFiles.item(i);
825             if (editorID.equals(UUID.fromString(doc.getAttribute(EDITORINST)))
826                     && toRemove.contains(doc.getAttribute(PATH))) {
827                 root.removeChild((Node) doc);
828             }
829         }
830
831         clean(root);
832         writeDocument();
833     }
834
835     /**
836      * Remove a tab with an open file from the list of open files
837      * @param editorID editor instance identifer
838      * @param sepID editor pane instance identifer. If a nil UUID is passed,
839      * all files with a matching editor instance identifer are removed.
840      */
841     public static void removeFromOpenFiles(UUID editorID, UUID sepID) {
842         readDocument();
843
844         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
845         NodeList openFiles = root.getElementsByTagName(DOCUMENT);
846
847         // Remove item with matching editorID and sepID.
848         UUID nil = new UUID(0, 0);
849         for (int i = openFiles.getLength() - 1; i >= 0; i--) {
850             Element style = (Element) openFiles.item(i);
851             UUID paneID1 = UUID.fromString(style.getAttribute(PANEINST));
852             UUID paneID2 = UUID.fromString(style.getAttribute(PANEINST_EX));
853
854             if (editorID.equals(UUID.fromString(style.getAttribute(EDITORINST)))
855                     && (sepID.equals(nil) || sepID.equals(paneID1) || sepID.equals(paneID2))) {
856                 root.removeChild((Node) style);
857             }
858         }
859
860         clean(root);
861         writeDocument();
862     }
863
864     /**
865      * Change a filename.
866      * @param newfilePath new pathname of the file
867      * @param editorInstance instance of the editor
868      * @param sep instance of the editor pane
869      */
870     public static void renameOpenFilesItem(String newfilePath, SciNotes editorInstance, ScilabEditorPane sep) {
871         readDocument();
872
873         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
874         Element style = findOpenFileItem(root, editorInstance.getUUID(), sep.getUUID());
875
876         if (style != null) {
877             style.setAttribute(PATH, newfilePath);
878         }
879
880         /* Save changes */
881         writeDocument();
882     }
883
884     /**
885      * Replace a single text pane ID with two pane IDs when a tab split occurs
886      * @param editorInstance instance of the editor
887      * @param old1 old instance of the editor pane
888      * @param new1 first new instance of the tabbed editor pane
889      * @param new2 second new instance of the tabbed editor pane
890      */
891     public static void tabSplitOpenFilesItem(SciNotes editorInstance, ScilabEditorPane old1, ScilabEditorPane new1, ScilabEditorPane new2) {
892         readDocument();
893
894         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
895         Element style = findOpenFileItem(root, editorInstance.getUUID(), old1.getUUID());
896
897         if (style != null) {
898             style.setAttribute(PANEINST, new1.getUUID().toString());
899             style.setAttribute(PANEINST_EX, new2.getUUID().toString());
900         }
901
902         /* Save changes */
903         writeDocument();
904     }
905
906     /**
907      * Replace double pane IDs with a single ID when a tabbed pane is replaced by a single pane.
908      * @param editorInstance instance of the editor
909      * @param old1 one of the old tabbed editor pane
910      * @param new1 new editor pane
911      */
912     public static void removeTabSplitInOpenFilesItem(SciNotes editorInstance, ScilabEditorPane old1, ScilabEditorPane new1) {
913         readDocument();
914
915         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
916         Element style = findOpenFileItem(root, editorInstance.getUUID(), old1.getUUID());
917
918         if (style != null) {
919             UUID nil = new UUID(0, 0);
920             style.setAttribute(PANEINST, new1.getUUID().toString());
921             style.setAttribute(PANEINST_EX, nil.toString());
922         }
923
924         /* Save changes */
925         writeDocument();
926     }
927
928     /**
929      * Find the first element with matching editor and pane identifiers
930      * @param root Document root
931      * @param editorID instance of the editor to find
932      * @param sepID instance of the editor pane to find
933      * @return the corresponding element
934      */
935     public static Element findOpenFileItem(Element root, UUID editorID, UUID sepID) {
936         NodeList openFiles = root.getElementsByTagName(DOCUMENT);
937
938         // Find item with matching editor and pane IDs
939         for (int i = 0; i < openFiles.getLength(); i++) {
940             Element style = (Element) openFiles.item(i);
941             UUID paneID1 = UUID.fromString(style.getAttribute(PANEINST));
942             UUID paneID2 = UUID.fromString(style.getAttribute(PANEINST_EX));
943
944             if (editorID.equals(UUID.fromString(style.getAttribute(EDITORINST)))
945                     && (sepID.equals(paneID1) || sepID.equals(paneID2))) {
946                 return style;
947             }
948         }
949
950         return null;
951     }
952
953     /**
954      * Empty the list of open files. Performed when the editor is opened
955      * and the user opts not to restore the open files.
956      */
957     public static void removeAllOpenFiles() {
958         readDocument();
959
960         Element root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
961         NodeList openFiles = root.getElementsByTagName(DOCUMENT);
962
963         // Remove all
964         for (int i = openFiles.getLength() - 1; i >= 0;  --i) {
965             Element style = (Element) openFiles.item(i);
966             root.removeChild((Node) style);
967         }
968
969         clean(root);
970         writeDocument();
971     }
972
973     /**
974      * Reset the current conf file
975      */
976     public static void resetDocument() {
977         document = null;
978     }
979
980     /**
981      * Read the file to modify
982      */
983     private static void readDocument() {
984         readDocument(USER_SCINOTES_CONFIG_FILE);
985     }
986
987     /**
988      * Read the file to modify
989      */
990     private static void readDocument(String pathConfSci) {
991         File fileConfig = new File(USER_SCINOTES_CONFIG_FILE);
992         if (!fileConfig.exists()) {
993             createUserCopy();
994         }
995         File xml = null;
996         DocumentBuilder docBuilder = null;
997         String factoryName = ScilabDocumentBuilderFactory.useDefaultDocumentBuilderFactoryImpl();
998
999         try {
1000             if (document == null) {
1001                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1002                 docBuilder = factory.newDocumentBuilder();
1003
1004                 // read content of a XML file with DOM
1005                 xml = new File(pathConfSci);
1006                 document = docBuilder.parse(xml);
1007             }
1008         } catch (ParserConfigurationException pce) {
1009             System.err.println(ERROR_READ + pathConfSci);
1010         } catch (SAXException se) {
1011             System.err.println(ERROR_READ + pathConfSci);
1012         } catch (IOException ioe) {
1013             System.err.println(ERROR_READ + pathConfSci);
1014         }
1015
1016         ScilabDocumentBuilderFactory.restoreDocumentBuilderFactoryImpl(factoryName);
1017     }
1018
1019     /**
1020      * Save the modifications
1021      */
1022     private static void writeDocument() {
1023         if (mustSave) {
1024             Transformer transformer = null;
1025             try {
1026                 transformer = ScilabTransformerFactory.newInstance().newTransformer();
1027             } catch (TransformerConfigurationException e1) {
1028                 System.err.println(ERROR_WRITE + USER_SCINOTES_CONFIG_FILE);
1029                 System.err.println(e1);
1030             } catch (TransformerFactoryConfigurationError e1) {
1031                 System.err.println(ERROR_WRITE + USER_SCINOTES_CONFIG_FILE);
1032                 System.err.println(e1);
1033             }
1034
1035             if (transformer != null) {
1036                 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
1037
1038                 StreamResult result = new StreamResult(new File(USER_SCINOTES_CONFIG_FILE));
1039                 DOMSource source = new DOMSource(document);
1040                 try {
1041                     transformer.transform(source, result);
1042                 } catch (TransformerException e) {
1043                     System.err.println(ERROR_WRITE + USER_SCINOTES_CONFIG_FILE);
1044                     System.err.println(e);
1045                 }
1046             }
1047         }
1048     }
1049
1050     /**
1051      *
1052      */
1053     public static void saveCodeNavigatorState(String editorUUID, String navUUID) {
1054         readDocument();
1055
1056         Element root = document.getDocumentElement();
1057         NodeList navs = root.getElementsByTagName(CODENAVIGATOR);
1058         boolean update = false;
1059         for (int i = 0; i < navs.getLength(); i++) {
1060             Element nav = (Element) navs.item(i);
1061             if (nav.getAttribute("uuid").equals(navUUID)) {
1062                 nav.setAttribute("depends", editorUUID);
1063                 update = true;
1064                 break;
1065             }
1066         }
1067
1068         if (!update) {
1069             ScilabXMLUtilities.createNode(document, root, CODENAVIGATOR, new String[] {"uuid", navUUID, "depends", editorUUID});
1070         }
1071
1072         writeDocument();
1073     }
1074
1075     /**
1076      *
1077      */
1078     public static String getCodeNavigatorState(String navUUID) {
1079         readDocument();
1080
1081         Element root = document.getDocumentElement();
1082         NodeList navs = root.getElementsByTagName(CODENAVIGATOR);
1083         for (int i = 0; i < navs.getLength(); i++) {
1084             Element nav = (Element) navs.item(i);
1085             if (nav.getAttribute("uuid").equals(navUUID)) {
1086                 return nav.getAttribute("depends");
1087             }
1088         }
1089         return null;
1090     }
1091
1092     /**
1093      *
1094      */
1095     public static String getCodeNavigatorStateForEditor(String editorUUID) {
1096         readDocument();
1097
1098         Element root = document.getDocumentElement();
1099         NodeList navs = root.getElementsByTagName(CODENAVIGATOR);
1100         for (int i = 0; i < navs.getLength(); i++) {
1101             Element nav = (Element) navs.item(i);
1102             if (nav.getAttribute("depends").equals(editorUUID)) {
1103                 return nav.getAttribute("uuid");
1104             }
1105         }
1106         return null;
1107     }
1108
1109     /**
1110      *
1111      */
1112     public static void saveSearchInFilesState(String editorUUID, String sfUUID) {
1113         readDocument();
1114
1115         Element root = document.getDocumentElement();
1116         NodeList sfs = root.getElementsByTagName(SEARCHINFILES);
1117         boolean update = false;
1118         for (int i = 0; i < sfs.getLength(); i++) {
1119             Element sf = (Element) sfs.item(i);
1120             if (sf.getAttribute("uuid").equals(sfUUID)) {
1121                 sf.setAttribute("depends", editorUUID);
1122                 update = true;
1123                 break;
1124             }
1125         }
1126
1127         if (!update) {
1128             ScilabXMLUtilities.createNode(document, root, SEARCHINFILES, new String[] {"uuid", sfUUID, "depends", editorUUID});
1129         }
1130
1131         writeDocument();
1132     }
1133
1134     /**
1135      *
1136      */
1137     public static String getSearchInFilesState(String sfUUID) {
1138         readDocument();
1139
1140         Element root = document.getDocumentElement();
1141         NodeList sfs = root.getElementsByTagName(SEARCHINFILES);
1142         for (int i = 0; i < sfs.getLength(); i++) {
1143             Element sf = (Element) sfs.item(i);
1144             if (sf.getAttribute("uuid").equals(sfUUID)) {
1145                 return sf.getAttribute("depends");
1146             }
1147         }
1148         return null;
1149     }
1150
1151     /**
1152      *
1153      */
1154     public static String getSearchInFilesStateForEditor(String editorUUID) {
1155         readDocument();
1156
1157         Element root = document.getDocumentElement();
1158         NodeList sfs = root.getElementsByTagName(SEARCHINFILES);
1159         for (int i = 0; i < sfs.getLength(); i++) {
1160             Element sf = (Element) sfs.item(i);
1161             if (sf.getAttribute("depends").equals(editorUUID)) {
1162                 return sf.getAttribute("uuid");
1163             }
1164         }
1165         return null;
1166     }
1167
1168     /**
1169      *
1170      */
1171     public static void saveEditorUUID(String editorUUID) {
1172         readDocument();
1173
1174         Element root = document.getDocumentElement();
1175         NodeList eis = root.getElementsByTagName(EDITORUUID);
1176         for (int i = 0; i < eis.getLength(); i++) {
1177             Element ei = (Element) eis.item(i);
1178             if (ei.getAttribute("uuid").equals(editorUUID)) {
1179                 return;
1180             }
1181         }
1182
1183         ScilabXMLUtilities.createNode(document, root, EDITORUUID, new String[] {"uuid", editorUUID});
1184
1185         writeDocument();
1186     }
1187
1188     /**
1189      *
1190      */
1191     public static void removeEditorUUID(String editorUUID) {
1192         readDocument();
1193
1194         Element root = document.getDocumentElement();
1195         NodeList eis = root.getElementsByTagName(EDITORUUID);
1196         for (int i = 0; i < eis.getLength(); i++) {
1197             Element ei = (Element) eis.item(i);
1198             if (ei.getAttribute("uuid").equals(editorUUID)) {
1199                 root.removeChild(ei);
1200             }
1201         }
1202
1203         root = (Element) document.getDocumentElement().getElementsByTagName(OPEN_FILES).item(0);
1204         if (root != null) {
1205             NodeList openFiles = root.getElementsByTagName(DOCUMENT);
1206             for (int i = 0; i < openFiles.getLength(); ++i) {
1207                 Element of = (Element) openFiles.item(i);
1208                 if (of.getAttribute(EDITORINST).equals(editorUUID)) {
1209                     root.removeChild(of);
1210                 }
1211             }
1212         }
1213
1214         writeDocument();
1215     }
1216
1217     /**
1218      *
1219      */
1220     public static List<String> getEditorsUUID() {
1221         readDocument();
1222
1223         Element root = document.getDocumentElement();
1224         NodeList eis = root.getElementsByTagName(EDITORUUID);
1225         List<String> list = new ArrayList<String>();
1226         for (int i = 0; i < eis.getLength(); i++) {
1227             Element ei = (Element) eis.item(i);
1228             list.add(ei.getAttribute("uuid"));
1229         }
1230
1231         return list;
1232     }
1233
1234     /**
1235      * Add a file to recent Opened Files
1236      * @param exp the path of the files to add
1237      */
1238     public static void saveRecentSearch(String exp) {
1239         Node root = getXcosRoot();
1240         if (root == null || exp == null || exp.compareTo("") == 0) {
1241             return;
1242         }
1243
1244         Node recents = getNodeChild(root, RECENT_SEARCH);
1245         if (recents == null) {
1246             recents = document.createElement(RECENT_SEARCH);
1247             root.appendChild(recents);
1248         }
1249
1250         List<Node> search = getNodeChildren(recents, SEARCH);
1251
1252         while (search.size() >= MAXRECENT) {
1253             removeRecentSearch(((Element) search.get(0)).getAttribute(EXPRESSION));
1254             search = getNodeChildren(recents, SEARCH);
1255         }
1256         //if path already in file no need to add it
1257         for (Node item : search) {
1258             if (exp.compareTo(((Element) item).getAttribute(EXPRESSION)) == 0) {
1259                 return;
1260             }
1261         }
1262
1263         Element newSearch = document.createElement(SEARCH);
1264         newSearch.setAttribute(EXPRESSION, exp);
1265         recents.appendChild((Node) newSearch);
1266
1267         clean(recents);
1268         writeDocument();
1269     }
1270
1271     /**
1272      * @param exp the expression to remove
1273      */
1274     public static void removeRecentSearch(String exp) {
1275         Node root = getXcosRoot();
1276         if (root == null) {
1277             return;
1278         }
1279
1280         Node recent = getNodeChild(root, RECENT_SEARCH);
1281         List<Node> search = getNodeChildren(recent, SEARCH);
1282
1283         // remove node if exists
1284         for (Node file : search) {
1285             if (exp.compareTo(((Element) file).getAttribute(EXPRESSION)) == 0) {
1286                 recent.removeChild(file);
1287                 break;
1288             }
1289         }
1290
1291         clean(recent);
1292         writeDocument();
1293
1294     }
1295
1296     /**
1297      * @return a list of the recent searches
1298      */
1299     public static List<String> getRecentSearch() {
1300         List<String> files = new ArrayList<String>();
1301
1302         Node root = getXcosRoot();
1303         if (root == null) {
1304             return files;
1305         }
1306
1307         Node recent = getNodeChild(root, RECENT_SEARCH);
1308         List<Node> searches = getNodeChildren(recent, SEARCH);
1309         for (Node search : searches) {
1310             String exp = ((Element) search).getAttribute(EXPRESSION);
1311             if (exp != null && exp.compareTo("") != 0) {
1312                 files.add(exp);
1313             }
1314         }
1315
1316         return files;
1317     }
1318
1319     /**
1320      * Add a file to recent Opened Files
1321      * @param exp the path of the files to add
1322      */
1323     public static void saveRecent(String exp, String nodeName, String childNodeName) {
1324         Node root = getXcosRoot();
1325         if (root == null || exp == null || exp.compareTo("") == 0) {
1326             return;
1327         }
1328
1329         Node recents = getNodeChild(root, nodeName);
1330         if (recents == null) {
1331             recents = document.createElement(nodeName);
1332             root.appendChild(recents);
1333         }
1334
1335         List<Node> list = getNodeChildren(recents, childNodeName);
1336
1337         while (list.size() >= MAXRECENT) {
1338             removeRecent(((Element) list.get(0)).getAttribute(EXPRESSION), nodeName, childNodeName);
1339             list = getNodeChildren(recents, childNodeName);
1340         }
1341         //if path already in file no need to add it
1342         for (Node item : list) {
1343             if (exp.compareTo(((Element) item).getAttribute(EXPRESSION)) == 0) {
1344                 return;
1345             }
1346         }
1347
1348         Element newNode = document.createElement(childNodeName);
1349         newNode.setAttribute(EXPRESSION, exp);
1350         recents.appendChild((Node) newNode);
1351
1352         clean(recents);
1353         writeDocument();
1354     }
1355
1356     /**
1357      * @param exp the expression to remove
1358      */
1359     public static void removeRecent(String exp, String nodeName, String childNodeName) {
1360         Node root = getXcosRoot();
1361         if (root == null) {
1362             return;
1363         }
1364
1365         Node recent = getNodeChild(root, nodeName);
1366         List<Node> list = getNodeChildren(recent, childNodeName);
1367
1368         // remove node if exists
1369         for (Node item : list) {
1370             if (exp.compareTo(((Element) item).getAttribute(EXPRESSION)) == 0) {
1371                 recent.removeChild(item);
1372                 break;
1373             }
1374         }
1375
1376         clean(recent);
1377         writeDocument();
1378     }
1379
1380     /**
1381      * @return a list of the recent searches
1382      */
1383     public static List<String> getRecent(String nodeName, String childNodeName) {
1384         List<String> files = new ArrayList<String>();
1385
1386         Node root = getXcosRoot();
1387         if (root == null) {
1388             return files;
1389         }
1390
1391         Node recent = getNodeChild(root, nodeName);
1392         List<Node> list = getNodeChildren(recent, childNodeName);
1393         for (Node node : list) {
1394             String exp = ((Element) node).getAttribute(EXPRESSION);
1395             if (exp != null && exp.compareTo("") != 0) {
1396                 files.add(exp);
1397             }
1398         }
1399
1400         return files;
1401     }
1402
1403
1404     /**
1405      * @param exp the recent expression for a replacement
1406      */
1407     public static void saveRecentReplace(String exp) {
1408         Node root = getXcosRoot();
1409         if (root == null || exp == null || exp.compareTo("") == 0) {
1410             return;
1411         }
1412
1413         Node recent = getNodeChild(root, RECENT_REPLACE);
1414         if (recent == null) {
1415             recent = document.createElement(RECENT_REPLACE);
1416             root.appendChild(recent);
1417         }
1418
1419         List<Node> replace = getNodeChildren(recent, REPLACE);
1420
1421         while (replace.size() >= MAXRECENT) {
1422             removeRecentReplace(((Element) replace.get(0)).getAttribute(EXPRESSION));
1423             replace = getNodeChildren(recent, REPLACE);
1424         }
1425         //if path already in file no need to add it
1426         for (Node item : replace) {
1427             if (exp.compareTo(((Element) item).getAttribute(EXPRESSION)) == 0) {
1428                 return;
1429             }
1430         }
1431
1432         Element newReplace = document.createElement(REPLACE);
1433         newReplace.setAttribute(EXPRESSION, exp);
1434         recent.appendChild((Node) newReplace);
1435
1436         clean(recent);
1437         writeDocument();
1438     }
1439
1440     /**
1441      * @param filePath remove recent replace in the this file
1442      */
1443     public static void removeRecentReplace(String filePath) {
1444
1445         Node root = getXcosRoot();
1446         if (root == null) {
1447             return;
1448         }
1449
1450         Node recent = getNodeChild(root, RECENT_REPLACE);
1451         List<Node> replace = getNodeChildren(recent, REPLACE);
1452
1453         // remove node if exists
1454         for (Node exp : replace) {
1455             if (filePath.compareTo(((Element) exp).getAttribute(EXPRESSION)) == 0) {
1456                 recent.removeChild(exp);
1457                 break;
1458             }
1459
1460         }
1461
1462         clean(recent);
1463         writeDocument();
1464
1465     }
1466
1467     /**
1468      * @return the recent replace
1469      */
1470     public static List<String> getRecentReplace() {
1471         List<String> exps = new ArrayList<String>();
1472
1473         Node root = getXcosRoot();
1474         if (root == null) {
1475             return exps;
1476         }
1477
1478         Node recent = getNodeChild(root, RECENT_REPLACE);
1479         List<Node> replace = getNodeChildren(recent, REPLACE);
1480         for (Node file : replace) {
1481             String exp = ((Element) file).getAttribute(EXPRESSION);
1482             if (exp != null && exp.compareTo("") != 0) {
1483                 exps.add(exp);
1484             }
1485         }
1486
1487         return exps;
1488     }
1489
1490     /**
1491      * @return true for a regexp search
1492      */
1493     public static boolean getRegularExpression() {
1494         return getBooleanAttribute(REGULAR_EXPRESION, STATE_FLAG, false);
1495     }
1496
1497     /**
1498      * @param regualExp for a regexp search
1499      */
1500     public static void saveRegularExpression(boolean regualExp) {
1501         saveBooleanAttribute(REGULAR_EXPRESION, STATE_FLAG, regualExp);
1502     }
1503
1504     /**
1505      * @return true for a wholeWord search
1506      */
1507     public static boolean getWholeWord() {
1508         return getBooleanAttribute(WHOLE_WORD, STATE_FLAG, false);
1509     }
1510
1511     /**
1512      * @param wholeWord for a wholeWord search
1513      */
1514     public static void saveWholeWord(boolean wholeWord) {
1515         saveBooleanAttribute(WHOLE_WORD, STATE_FLAG, wholeWord);
1516     }
1517
1518     /**
1519      * @return true for a recursive search
1520      */
1521     public static boolean getRecursive() {
1522         return getBooleanAttribute(RECURSIVE, STATE_FLAG, true);
1523     }
1524
1525     /**
1526      * @param recursive for a recursive search
1527      */
1528     public static void saveRecursive(boolean recursive) {
1529         saveBooleanAttribute(RECURSIVE, STATE_FLAG, recursive);
1530     }
1531
1532     /**
1533      * @return true for a line by line search
1534      */
1535     public static boolean getLineByLine() {
1536         return getBooleanAttribute(LINEBYLINE, STATE_FLAG, true);
1537     }
1538
1539     /**
1540      * @param lineByLine for a line by line search
1541      */
1542     public static void saveLineByLine(boolean lineByLine) {
1543         saveBooleanAttribute(LINEBYLINE, STATE_FLAG, lineByLine);
1544     }
1545
1546     /**
1547      * @return true for a case sensitive file name
1548      */
1549     public static boolean getFileCase() {
1550         return getBooleanAttribute(FILECASE, STATE_FLAG, false);
1551     }
1552
1553     /**
1554      * @param fileCase for a case sensitive file name
1555      */
1556     public static void saveFileCase(boolean fileCase) {
1557         saveBooleanAttribute(FILECASE, STATE_FLAG, fileCase);
1558     }
1559
1560     /**
1561      * @return true for a circular search
1562      */
1563     public static boolean getCircularSearch() {
1564         return getBooleanAttribute(CIRCULAR, STATE_FLAG, true);
1565     }
1566
1567     /**
1568      * @param circular is true for a circular search
1569      */
1570     public static void saveCircularSearch(boolean circular) {
1571         saveBooleanAttribute(CIRCULAR, STATE_FLAG, circular);
1572     }
1573
1574     /**
1575      * @return true for a case sensitive search
1576      */
1577     public static boolean getCaseSensitive() {
1578         return getBooleanAttribute(CASE_SENSITIVE, STATE_FLAG, false);
1579     }
1580
1581     /**
1582      * @param caseSensitive for a case sensitive search
1583      */
1584     public static void saveCaseSensitive(boolean caseSensitive) {
1585         saveBooleanAttribute(CASE_SENSITIVE, STATE_FLAG, caseSensitive);
1586     }
1587
1588     /**
1589      * getBooleanAttribute
1590      * @param node the node name
1591      * @param attrib the attribute of the node
1592      * @param defaultValue true or false
1593      * @return the found boolean value or defaultValue if not found
1594      */
1595     private static boolean getBooleanAttribute(String node, String attrib, boolean defaultValue) {
1596         boolean flag = false;
1597         Node root = getXcosRoot();
1598         if (root == null) {
1599             return flag;
1600         }
1601         Node recent = getNodeChild(root, node);
1602         if (recent != null) {
1603             String exp = ((Element) recent).getAttribute(attrib);
1604             if (exp.compareTo(TRUE) == 0) {
1605                 flag = true;
1606             }
1607         } else {
1608             return defaultValue;
1609         }
1610         return flag;
1611     }
1612
1613     /**
1614      * saveBooleanAttribute
1615      * @param node the node name
1616      * @param attrib the attribute of the node
1617      * @param state "true" or "false"
1618      */
1619     private static void saveBooleanAttribute(String node, String attrib, boolean state) {
1620         Node root = getXcosRoot();
1621         if (root == null) {
1622             return;
1623         }
1624
1625         Node recent = getNodeChild(root, node);
1626         if (recent == null) {
1627             recent = document.createElement(node);
1628             root.appendChild(recent);
1629         }
1630
1631
1632         ((Element) recent).setAttribute(attrib, new Boolean(state).toString());
1633
1634         root.appendChild(recent);
1635
1636         /* Save changes */
1637         writeDocument();
1638     }
1639
1640     /**
1641      * getNodeChild
1642      * @param par parent
1643      * @param nodeName the name
1644      * @return the node
1645      */
1646     private static Node getNodeChild(Node par, String nodeName) {
1647         Node parent = par;
1648         if (parent == null) {
1649             if (document == null) {
1650                 readDocument();
1651                 if (document == null) {
1652                     return null;
1653                 }
1654             }
1655             parent = document;
1656         }
1657
1658         Node currentNode = parent.getFirstChild();
1659         while (currentNode != null) {
1660             if (currentNode.getNodeName().compareTo(nodeName) == 0) {
1661                 return currentNode;
1662             }
1663             currentNode = currentNode.getNextSibling();
1664         }
1665         return currentNode;
1666     }
1667
1668     /**
1669      * getNodeChildren
1670      * @param par parent
1671      * @param childName the name
1672      * @return a list of nodes
1673      */
1674     private static List<Node> getNodeChildren(Node par, String childName) {
1675         Node parent = par;
1676         List<Node> nodes = new ArrayList<Node>();
1677         if (parent == null) {
1678             if (document == null) {
1679                 readDocument();
1680                 if (document == null) {
1681                     return nodes;
1682                 }
1683             }
1684             parent = document;
1685         }
1686
1687         Node currentNode = parent.getFirstChild();
1688         while (currentNode != null) {
1689             if (currentNode.getNodeName().compareTo(childName) == 0) {
1690                 nodes.add(currentNode);
1691             }
1692             currentNode = currentNode.getNextSibling();
1693         }
1694         return nodes;
1695
1696     }
1697
1698     /**
1699      * @return the root
1700      */
1701     private static Node getXcosRoot() {
1702         if (document == null) {
1703             readDocument();
1704             if (document == null) {
1705                 return null;
1706             }
1707         }
1708
1709         Node setting = getNodeChild(null, SETTING);
1710
1711         if (setting != null) {
1712             List<Node> nodes = getNodeChildren(setting, PROFILE);
1713             for (Node node : nodes) {
1714                 if (((Element) node).getAttribute(NAME).compareTo(SCINOTES) == 0) {
1715                     return node;
1716                 }
1717             }
1718         }
1719         return null;
1720     }
1721
1722     /**
1723      * Remove text at the beginning and at the end
1724      * @param r the element to clean
1725      */
1726     private static void clean(Node r) {
1727         Node n = r.getFirstChild();
1728         if (n != null && n instanceof Text) {
1729             r.removeChild(n);
1730         }
1731         n = r.getLastChild();
1732         if (n != null && n instanceof Text) {
1733             r.removeChild(n);
1734         }
1735     }
1736 }