Desktop: remove a faulty tab entry in the xml
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / utils / WindowsConfigurationManager.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2011 - Calixte DENIZET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.gui.utils;
14
15 import java.awt.Component;
16 import java.awt.Dimension;
17 import java.io.File;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.LinkedHashSet;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.UUID;
26
27 import javax.swing.SwingUtilities;
28
29 import org.w3c.dom.Attr;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Element;
32 import org.w3c.dom.NamedNodeMap;
33 import org.w3c.dom.Node;
34 import org.w3c.dom.NodeList;
35 import org.w3c.dom.Text;
36 import org.xml.sax.SAXException;
37
38 import org.flexdock.docking.Dockable;
39 import org.flexdock.docking.DockingConstants;
40 import org.flexdock.docking.DockingManager;
41 import org.flexdock.docking.activation.ActiveDockableTracker;
42 import org.flexdock.docking.state.LayoutNode;
43 import org.flexdock.perspective.persist.xml.LayoutNodeSerializer;
44 import org.flexdock.perspective.persist.xml.PersistenceConstants;
45
46 import org.scilab.modules.commons.ScilabCommons;
47 import org.scilab.modules.commons.ScilabCommonsUtils;
48 import org.scilab.modules.commons.xml.ScilabXMLUtilities;
49 import org.scilab.modules.gui.bridge.tab.SwingScilabTab;
50 import org.scilab.modules.gui.bridge.window.SwingScilabWindow;
51 import org.scilab.modules.gui.console.ScilabConsole;
52 import org.scilab.modules.gui.tab.Tab;
53 import org.scilab.modules.gui.tabfactory.ScilabTabFactory;
54 import org.scilab.modules.gui.window.ScilabWindow;
55 import org.scilab.modules.gui.window.Window;
56
57 /**
58  *
59  * Save the windows properties.
60  *
61  * @author Calixte DENIZET
62  */
63 public class WindowsConfigurationManager {
64
65     private static final int DEFAULTX = 0;
66     private static final int DEFAULTY = 0;
67     private static final int DEFAULTHEIGHT = 500;
68     private static final int DEFAULTWIDTH = 500;
69
70     private static final String SCI = "SCI";
71     private static final String WINDOWS_CONFIG_FILE = System.getenv(SCI) + "/modules/gui/etc/windowsConfiguration.xml";
72     private static final String USER_WINDOWS_CONFIG_FILE = ScilabCommons.getSCIHOME() + "/windowsConfiguration.xml";
73     private static final String NULLUUID = new UUID(0L, 0L).toString();
74     private static final Map<SwingScilabTab, EndedRestoration> endedRestoration = new HashMap<SwingScilabTab, EndedRestoration>();
75     private static final List<String> alreadyRestoredWindows = new ArrayList<String>();
76     private static final Map<String, Object> defaultWinAttributes = new HashMap<String, Object>();
77     private static final List<String> currentlyRestored = new ArrayList<String>();
78
79     private static boolean oneTry;
80     private static Document doc;
81
82     static {
83         defaultWinAttributes.put("x", new Integer(DEFAULTX));
84         defaultWinAttributes.put("y", new Integer(DEFAULTY));
85         defaultWinAttributes.put("height", new Integer(DEFAULTHEIGHT));
86         defaultWinAttributes.put("width", new Integer(DEFAULTWIDTH));
87         /*java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(new java.awt.event.AWTEventListener() {
88           public void eventDispatched(java.awt.AWTEvent e) {
89           System.out.println(e);
90           }
91           }, java.awt.AWTEvent.FOCUS_EVENT_MASK);*/
92     }
93
94     /**
95      * Create a copy of windows configuration file in the user directory
96      */
97     public static void createUserCopy() {
98         if (isCopyNeeded()) {
99             ScilabCommonsUtils.copyFile(new File(WINDOWS_CONFIG_FILE), new File(USER_WINDOWS_CONFIG_FILE));
100             doc = null;
101         }
102     }
103
104     /**
105      * Read the file to modify
106      */
107     private static void readDocument() {
108         if (doc == null) {
109             createUserCopy();
110             doc = ScilabXMLUtilities.readDocument(USER_WINDOWS_CONFIG_FILE);
111         }
112
113         if (doc == null && !oneTry) {
114             System.err.println("Try to reload the default configuration file: " + WINDOWS_CONFIG_FILE);
115             File f = new File(USER_WINDOWS_CONFIG_FILE);
116             if (f.exists() && f.isFile()) {
117                 f.delete();
118             }
119             oneTry = true;
120             readDocument();
121         } else if (doc == null && oneTry) {
122             System.err.println("Serious problem to copy and parse the configuration file.");
123             System.err.println("Please check if you have the rights to write the file: " + USER_WINDOWS_CONFIG_FILE);
124             System.err.println("If the previous file exists, please check if it is a valid XML");
125             System.err.println("and if yes, please report a bug: http://bugzilla.scilab.org");
126         }
127     }
128
129     /**
130      * Write the document
131      */
132     private static void writeDocument() {
133         ScilabXMLUtilities.writeDocument(doc, USER_WINDOWS_CONFIG_FILE);
134     }
135
136     /**
137      * @return true if a copy is needed
138      */
139     private static final boolean isCopyNeeded() {
140         return !new File(USER_WINDOWS_CONFIG_FILE).exists();
141     }
142
143     /**
144      * Register an EndedRestoration, op.finish() will be executed when the tab restoration will be finished.
145      * @param tab the associated tab
146      * @param ended the closing operation
147      */
148     public static void registerEndedRestoration(SwingScilabTab tab, EndedRestoration ended) {
149         endedRestoration.put(tab, ended);
150     }
151
152     /**
153      * Register an EndedRestoration, op.finish() will be executed when the tab restoration will be finished.
154      * @param tab the associated tab
155      * @param ended the closing operation
156      */
157     public static void registerEndedRestoration(Tab tab, EndedRestoration ended) {
158         registerEndedRestoration((SwingScilabTab) tab.getAsSimpleTab(), ended);
159     }
160
161     /**
162      * Create a new node with parent element
163      * @param parent the parent element
164      * @param nodeName the node name
165      * @param attr an array containing attribute name followed by its value: "attr1", 1, "attr2", true, ...
166      * @return the created element
167      */
168     public static Element createNode(Element parent, String nodeName, Object[] attr) {
169         readDocument();
170         for (int i = 0; i < attr.length; i += 2) {
171             if (attr[i].equals("uuid")) {
172                 removeNode(parent, nodeName, (String) attr[i + 1]);
173             }
174         }
175
176         return ScilabXMLUtilities.createNode(doc, parent, nodeName, attr);
177     }
178
179     /**
180      * Save the window properties
181      * @param window the window
182      */
183     public static void saveWindowProperties(SwingScilabWindow window) {
184         readDocument();
185
186         Element root = doc.getDocumentElement();
187         Element win = createNode(root, "Window", new Object[]{"uuid", window.getUUID(),
188                                                               "x", (int) window.getLocation().getX(),
189                                                               "y", (int) window.getLocation().getY(),
190                                                               "width", (int) window.getSize().getWidth(),
191                                                               "height", (int) window.getSize().getHeight()});
192         LayoutNode layoutNode = window.getDockingPort().exportLayout();
193         LayoutNodeSerializer serializer = new LayoutNodeSerializer();
194         win.appendChild(serializer.serialize(doc, layoutNode));
195
196         for (Dockable dockable : (Set<Dockable>) window.getDockingPort().getDockables()) {
197             saveTabProperties((SwingScilabTab) dockable, false);
198         }
199
200         writeDocument();
201     }
202
203     /**
204      * Restore a window with a given uuid
205      * @param uuid the uuid
206      * @param restoreTab if true the tab is restored too
207      * @return the corresponding window
208      */
209     public static SwingScilabWindow restoreWindow(String uuid, String defaultTabUuid, boolean restoreTab, boolean requestFocus) {
210         readDocument();
211
212         Element root = doc.getDocumentElement();
213         Map<String, Object> attrs = new HashMap<String, Object>();
214         boolean nullUUID = uuid.equals(NULLUUID);
215         Element win = null;
216
217         if (!nullUUID) {
218             win = getElementWithUUID(root, "Window", uuid);
219             if (win == null) {
220                 return null;
221             }
222
223             attrs.put("x", int.class);
224             attrs.put("y", int.class);
225             attrs.put("height", int.class);
226             attrs.put("width", int.class);
227             ScilabXMLUtilities.readNodeAttributes(win, attrs);
228         } else {
229             attrs = defaultWinAttributes;
230         }
231
232         Window w = ScilabWindow.createWindow();
233         UIElementMapper.add(w);
234         final SwingScilabWindow window = (SwingScilabWindow) w.getAsSimpleWindow();
235         if (!nullUUID) {
236             window.setUUID(uuid);
237         } else {
238             window.setUUID(UUID.randomUUID().toString());
239         }
240         window.setLocation(((Integer) attrs.get("x")).intValue(), ((Integer) attrs.get("y")).intValue());
241         window.setSize(((Integer) attrs.get("width")).intValue(), ((Integer) attrs.get("height")).intValue());
242
243         if (restoreTab) {
244             if (win != null) {
245                 LayoutNodeSerializer serializer = new LayoutNodeSerializer();
246                 NodeList children = win.getElementsByTagName(PersistenceConstants.DOCKING_PORT_NODE_ELEMENT_NAME);
247                 LayoutNode layoutNode = (LayoutNode) serializer.deserialize((Element) children.item(0));
248                 window.getDockingPort().importLayout(layoutNode);
249             } else if (defaultTabUuid != null && !defaultTabUuid.isEmpty()) {
250                 SwingScilabTab defaultTab = ScilabTabFactory.getInstance().getTab(defaultTabUuid);
251                 defaultTab.setParentWindowId(window.getElementId());
252                 DockingManager.dock(defaultTab, window.getDockingPort());
253             }
254
255             for (SwingScilabTab tab : (Set<SwingScilabTab>) window.getDockingPort().getDockables()) {
256                 tab.setParentWindowId(window.getElementId());
257             }
258
259             SwingScilabTab[] tabs = new SwingScilabTab[window.getNbDockedObjects()];
260             tabs = ((Set<SwingScilabTab>) window.getDockingPort().getDockables()).toArray(tabs);
261
262             // Be sur that the main tab will have the focus.
263             // Get the elder tab and activate it
264             final SwingScilabTab mainTab = ClosingOperationsManager.getElderTab(new ArrayList(Arrays.asList(tabs)));
265             BarUpdater.updateBars(mainTab.getParentWindowId(), mainTab.getMenuBar(), mainTab.getToolBar(), mainTab.getInfoBar(), mainTab.getName(), mainTab.getWindowIcon());
266
267             if (!ScilabConsole.isExistingConsole() && tabs.length == 1 && tabs[0].getPersistentId().equals(NULLUUID)) {
268                 // null uuid is reserved to the console and in NW mode, there is no console.
269                 return null;
270             }
271
272             for (SwingScilabTab tab : tabs) {
273                 // each tab has now a window so it can be useful for the tab to set an icon window or to center a dialog...
274                 EndedRestoration ended = endedRestoration.get(tab);
275                 if (ended != null) {
276                     ended.finish();
277                     endedRestoration.remove(ended);
278                 }
279             }
280
281             if (tabs.length == 1) {
282                 // we remove undock and close buttons when there is only one View in the DockingPort
283                 SwingScilabTab.removeActions(tabs[0]);
284             } else {
285                 // we add undock and close buttons
286                 for (SwingScilabTab tab : tabs) {
287                     SwingScilabTab.addActions(tab);
288                 }
289             }
290
291             window.setVisible(true);
292
293             // Return only when the window is displayable
294             while (!window.isDisplayable()) {
295                 try {
296                     Thread.sleep(10);
297                 } catch (InterruptedException e) {
298                     System.err.println(e);
299                 }
300             }
301
302             if (requestFocus) {
303                 SwingUtilities.invokeLater(new Runnable() {
304                         public void run() {
305                             final Thread t = new Thread(new Runnable() {
306                                     public void run() {
307                                         while (currentlyRestored.size() != 0) {
308                                             try {
309                                                 Thread.sleep(10);
310                                             } catch (InterruptedException e) { }
311                                         }
312
313                                         // Be sure that te main tab or one of its subcomponent
314                                         // will have the focus on start-up
315                                         Component owner = null;
316                                         while (owner == null && !mainTab.isAncestorOf(owner)) {
317                                             mainTab.requestFocus();
318                                             try {
319                                                 Thread.sleep(100);
320                                             } catch (InterruptedException e) { }
321                                             owner = window.getFocusOwner();
322                                         }
323                                         ActiveDockableTracker.requestDockableActivation(mainTab);
324                                         window.toFront();
325                                     }
326                                 });
327                             t.start();
328                         }
329                     });
330             }
331         }
332
333         return window;
334     }
335
336     /**
337      * Must be called when the restoration is finished
338      * @param tab the tab
339      */
340     public static final void restorationFinished(SwingScilabTab tab) {
341         currentlyRestored.remove(tab.getPersistentId());
342     }
343
344     /**
345      * Remove a window from the already restored windows
346      * @param uuid the win uuid
347      */
348     public static final void removeWin(String uuid) {
349         alreadyRestoredWindows.remove(uuid);
350     }
351
352     /**
353      * Find all the dependencies of the given tab. The returned list contains parent before its children.
354      * @param uuid the tab's uuid
355      * @return a list of the elements with the given uuid
356      */
357     public static final Set<Element> getTabDependencies(String uuid) {
358         Element root = doc.getDocumentElement();
359
360         // Children
361         List<Element> elements = ScilabXMLUtilities.getElementsWithAttributeEquals(root, "depends", uuid);
362
363         Set<Element> list = new LinkedHashSet<Element>();
364         Element el = getElementWithUUID(doc.getDocumentElement(), uuid);
365         if (el != null) {
366             //We add the parent
367             list.add(el);
368             // We add the children and their own children
369             for (Element e : elements) {
370                 list.addAll(getTabDependencies(e.getAttribute("uuid")));
371             }
372         }
373
374         return list;
375     }
376
377     /**
378      * Create all the tabs depending of the tab with the given uuid.
379      * The creation will respect the convention: parent before children.
380      * @param uuid the tab uuid
381      * @return the list of all the uuids to restore
382      */
383     public static final Set<Element> createDescendantTabs(String uuid) {
384         Set<Element> list = getTabDependencies(uuid);
385         Dimension nullDims = new Dimension(0, 0);
386         for (Element e : list) {
387             // All the tabs created in the factory will be cached so when Flexdock will restore the docking
388             // it will use the same tab as created here.
389             ScilabTabFactory factory = ScilabTabFactory.getInstance();
390             factory.addTabFactory(e.getAttribute("load"), e.getAttribute("factory"));
391             currentlyRestored.add(e.getAttribute("uuid"));
392             SwingScilabTab tab = factory.getTab(e.getAttribute("uuid"));
393             if (!e.getAttribute("width").isEmpty() && !e.getAttribute("height").isEmpty()) {
394                 tab.setMinimumSize(nullDims);
395                 tab.setPreferredSize(new Dimension(Integer.parseInt(e.getAttribute("width")), Integer.parseInt(e.getAttribute("width"))));
396             }
397         }
398
399         return list;
400     }
401
402     /**
403      * Useful for the following case: you have 3 tabs, A, B and C, C depends of B, A and C are docked in the same window.
404      * You want to restore A, the window containing A needs to restore C too (and finally B).
405      * There is no direct dependency between A and C but the fact that they're in the same dockport
406      * implies a dependency.
407      * @param elems the elems corresponding to the tabs to restore
408      * @return tabs to restore
409      */
410     private static final Set<Element> createAdjacentTabs(Set<Element> elems) {
411         Element root = doc.getDocumentElement();
412         boolean jobFinished = true;
413         Set<Element> toAdd = new LinkedHashSet<Element>();
414         for (Element e : elems) {
415             String winuuid = e.getAttribute("winuuid");
416             if (!winuuid.isEmpty() && !winuuid.equals(NULLUUID)) {
417                 List<Element> elements = ScilabXMLUtilities.getElementsWithAttributeEquals(root, "winuuid", winuuid);
418                 elements.removeAll(elems);
419                 jobFinished = jobFinished && elements.size() == 0;
420                 toAdd.addAll(elements);
421             }
422         }
423
424         if (jobFinished) {
425             return elems;
426         }
427
428         for (Element ee : toAdd) {
429             elems.addAll(createDescendantTabs(getElderParent(ee).getAttribute("uuid")));
430         }
431
432
433         return createAdjacentTabs(elems);
434     }
435
436     /**
437      * @param e the element
438      * @return the elder parent of this element (elder for the attribute "depends")
439      */
440     private static final Element getElderParent(Element e) {
441         Element root = doc.getDocumentElement();
442         String dep = e.getAttribute("depends");
443         if (!dep.isEmpty()) {
444             return getElderParent(ScilabXMLUtilities.getElementsWithAttributeEquals(root, "uuid", dep).get(0));
445         }
446
447         return e;
448     }
449
450     /**
451      * Starts the restoration of the tab with the given uuid
452      * @param uuid the tab uuid to restore
453      */
454     private static final void startRestoration(String uuid) {
455         Set<Element> list = createDescendantTabs(uuid);
456         list = createAdjacentTabs(list);
457         List<String> wins = new ArrayList<String>();
458         List<String> tabsWithoutWin = new ArrayList<String>();
459         for (Element e : list) {
460             String winuuid = e.getAttribute("winuuid");
461             if (winuuid.equals(NULLUUID) || getElementWithUUID(winuuid) == null || !isDockableIdExisting(winuuid, e.getAttribute("uuid"))) {
462                 tabsWithoutWin.add(e.getAttribute("uuid"));
463             } else if (!wins.contains(winuuid)) {
464                 wins.add(winuuid);
465             }
466         }
467
468         boolean requestFocus = true;
469
470         for (String winuuid : wins) {
471             if (!alreadyRestoredWindows.contains(winuuid)) {
472                 restoreWindow(winuuid, uuid, true, requestFocus);
473                 alreadyRestoredWindows.add(winuuid);
474                 if (requestFocus) {
475                     requestFocus = false;
476                 }
477             }
478         }
479
480         for (String u : tabsWithoutWin) {
481             SwingScilabWindow window = restoreWindow(NULLUUID, u, true, requestFocus);
482             alreadyRestoredWindows.add(window.getUUID());
483             if (requestFocus) {
484                 requestFocus = false;
485             }
486         }
487     }
488
489     /**
490      * Search a node (child of root) with name nodeName and with a given uuid
491      * @param root the root element
492      * @param nodeName the node name
493      * @param uuid the uuid
494      * @return the corresponding element or null if it does not exist
495      */
496     public static final Element getElementWithUUID(Element root, String nodeName, String uuid) {
497         if (uuid == null || uuid.isEmpty()) {
498             return null;
499         }
500         NodeList list = root.getElementsByTagName(nodeName);
501         int length = getNodeListLength(list);
502         for (int i = 0; i < length; i++) {
503             Element elem = (Element) list.item(i);
504             if (elem.getAttribute("uuid").equals(uuid)) {
505                 return elem;
506             }
507         }
508
509         return null;
510     }
511
512     /**
513      * Search a node with a given uuid
514      * @param uuid the uuid
515      * @return the corresponding element or null if it does not exist
516      */
517     public static final Element getElementWithUUID(String uuid) {
518         return getElementWithUUID(doc.getDocumentElement(), uuid);
519     }
520
521     /**
522      * Search a node (child of root) with name nodeName and with a given uuid
523      * @param root the root element
524      * @param uuid the uuid
525      * @return the corresponding element or null if it does not exist
526      */
527     public static final Element getElementWithUUID(Element root, String uuid) {
528         if (uuid == null || uuid.isEmpty()) {
529             return null;
530         }
531         List<Element> list = ScilabXMLUtilities.getElementsWithAttributeEquals(root, "uuid", uuid);
532         if (list.size() != 0) {
533             return list.get(0);
534         }
535
536         return null;
537     }
538
539     /**
540      * Check if there is a window which has a dockableID equals to the given uuid
541      * @param winuuid the uuid of the window
542      * @param uuid the uuid to test
543      * @return true if a dockableId exists
544      */
545     public static final boolean isDockableIdExisting(String winuuid, String uuid) {
546         if (winuuid == null || winuuid.isEmpty() || uuid == null || uuid.isEmpty()) {
547             return false;
548         }
549
550         Element win = getElementWithUUID(winuuid);
551         if (win != null) {
552             List<Element> list = ScilabXMLUtilities.getElementsWithAttributeEquals(win, "dockableId", uuid);
553             if (list.size() != 0) {
554                 return true;
555             }
556         }
557
558         return false;
559     }
560
561     /**
562      * Remove a node with a given uuid
563      * @param parent the parent element
564      * @param nodeName the node name
565      * @param uuid the uuid
566      */
567     private static final void removeNode(Element parent, String nodeName, String uuid) {
568         if (uuid == null || uuid.isEmpty()) {
569             return;
570         }
571         Element e = getElementWithUUID(parent, nodeName, uuid);
572         if (e != null) {
573             parent.removeChild(e);
574         }
575     }
576
577     /**
578      * Remove a node with a given uuid
579      * @param nodeName the node name
580      * @param uuid the uuid
581      */
582     public static final void removeNode(String uuid) {
583         if (uuid == null || uuid.isEmpty()) {
584             return;
585         }
586         Element e = getElementWithUUID(uuid);
587         if (e != null && e.getParentNode() != null) {
588             e.getParentNode().removeChild(e);
589         }
590     }
591
592     /**
593      * Save the tab properties
594      * @param tab the tab
595      * @param nullWin if true, the winuuid will be set to 0 (the tab is not docked)
596      */
597     public static void saveTabProperties(SwingScilabTab tab, boolean nullWin) {
598         readDocument();
599         ScilabTabFactory factory = ScilabTabFactory.getInstance();
600         String uuid = tab.getPersistentId();
601         Element root = doc.getDocumentElement();
602
603         String app = factory.getApplication(uuid);
604         if (app.isEmpty()) {
605             return;
606         }
607
608         String winuuid;
609         if (nullWin) {
610             winuuid = NULLUUID;
611         } else {
612             winuuid = tab.getParentWindowUUID();
613         }
614
615         Dimension dim = tab.getSize();
616
617         createNode(root, app, new Object[]{"winuuid", winuuid,
618                                            "uuid", uuid,
619                                            "load", factory.getPackage(uuid),
620                                            "factory", factory.getClassName(uuid),
621                                            "width", (int) dim.getWidth(),
622                                            "height", (int) dim.getHeight()});
623         writeDocument();
624     }
625
626     /**
627      * Clean the document in removing the useless tags
628      */
629     public static void clean() {
630         readDocument();
631         Element root = doc.getDocumentElement();
632         NodeList list = root.getElementsByTagName("Window");
633         int len = getNodeListLength(list);
634         for (int i = 0; i < len; i++) {
635             if (list.item(i) instanceof Element) {
636                 String uuid = ((Element) list.item(i)).getAttribute("uuid");
637                 List<Element> elements = ScilabXMLUtilities.getElementsWithAttributeEquals(root, "winuuid", uuid);
638                 if (elements == null || elements.size() == 0) {
639                     root.removeChild(list.item(i));
640                     removeWin(uuid);
641                 }
642             }
643         }
644         writeDocument();
645     }
646
647     /**
648      * Make a dependency between two tabs
649      * @param parentUUID the parent tab uuid
650      * @param childUUID the child tab uuid
651      */
652     public static final void makeDependency(String parentUUID, String childUUID) {
653         readDocument();
654         Element e = getElementWithUUID(doc.getDocumentElement(), childUUID);
655         if (e != null) {
656             e.setAttribute("depends", parentUUID);
657         }
658         writeDocument();
659     }
660
661     /**
662      * Remove a dependency with the parent tab
663      * @param childUUID the child tab uuid
664      */
665     public static void removeDependency(String childUUID) {
666         readDocument();
667         Element e = getElementWithUUID(doc.getDocumentElement(), childUUID);
668         if (e != null) {
669             e.removeAttribute("depends");
670         }
671         writeDocument();
672     }
673
674     /**
675      * Restore an application by its name
676      * @param name the application name
677      * @return true if the operation succeded
678      */
679     public static boolean restoreUUID(String uuid) {
680         readDocument();
681         Element elem = getElementWithUUID(uuid);
682         if (elem == null) {
683             return false;
684         }
685
686         startRestoration(uuid);
687
688         return true;
689     }
690
691     /**
692      * Get the uuids of an application
693      * @param name the application anem
694      * @return the corresponding uuids
695      */
696     public static String[] getApplicationUUIDs(String name) {
697         readDocument();
698         NodeList list = doc.getDocumentElement().getElementsByTagName(name);
699         String[] uuids = new String[getNodeListLength(list)];
700         for (int i = 0; i < uuids.length; i++) {
701             if (list.item(i) instanceof Element) {
702                 Element elem = (Element) list.item(i);
703                 uuids[i] = elem.getAttribute("uuid");
704             }
705         }
706
707         return uuids;
708     }
709
710     /**
711      * Get the length of a NodeList (this is a workaround for a f... java bug)
712      */
713     private static final int getNodeListLength(NodeList list) {
714         int length = 0;
715         try {
716             length = list.getLength();
717         } catch (NullPointerException e) { }
718
719         return length;
720     }
721
722
723     /**
724      * Inner interface used to have something to execute when the restoration is finished
725      */
726     public interface EndedRestoration {
727
728         /**
729          * Stuff to do when the restoration is ended
730          */
731         public void finish();
732     }
733 }