dc3b915f1f6ba42998c422b5bf0806ec569cbef6
[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      * Save the tab properties
579      * @param tab the tab
580      * @param nullWin if true, the winuuid will be set to 0 (the tab is not docked)
581      */
582     public static void saveTabProperties(SwingScilabTab tab, boolean nullWin) {
583         readDocument();
584         ScilabTabFactory factory = ScilabTabFactory.getInstance();
585         String uuid = tab.getPersistentId();
586         Element root = doc.getDocumentElement();
587
588         String app = factory.getApplication(uuid);
589         if (app.isEmpty()) {
590             return;
591         }
592
593         String winuuid;
594         if (nullWin) {
595             winuuid = NULLUUID;
596         } else {
597             winuuid = tab.getParentWindowUUID();
598         }
599
600         Dimension dim = tab.getSize();
601
602         createNode(root, app, new Object[]{"winuuid", winuuid,
603                                            "uuid", uuid,
604                                            "load", factory.getPackage(uuid),
605                                            "factory", factory.getClassName(uuid),
606                                            "width", (int) dim.getWidth(),
607                                            "height", (int) dim.getHeight()});
608         writeDocument();
609     }
610
611     /**
612      * Clean the document in removing the useless tags
613      */
614     public static void clean() {
615         readDocument();
616         Element root = doc.getDocumentElement();
617         NodeList list = root.getElementsByTagName("Window");
618         int len = getNodeListLength(list);
619         for (int i = 0; i < len; i++) {
620             if (list.item(i) instanceof Element) {
621                 String uuid = ((Element) list.item(i)).getAttribute("uuid");
622                 List<Element> elements = ScilabXMLUtilities.getElementsWithAttributeEquals(root, "winuuid", uuid);
623                 if (elements == null || elements.size() == 0) {
624                     root.removeChild(list.item(i));
625                     removeWin(uuid);
626                 }
627             }
628         }
629         writeDocument();
630     }
631
632     /**
633      * Make a dependency between two tabs
634      * @param parentUUID the parent tab uuid
635      * @param childUUID the child tab uuid
636      */
637     public static final void makeDependency(String parentUUID, String childUUID) {
638         readDocument();
639         Element e = getElementWithUUID(doc.getDocumentElement(), childUUID);
640         if (e != null) {
641             e.setAttribute("depends", parentUUID);
642         }
643         writeDocument();
644     }
645
646     /**
647      * Remove a dependency with the parent tab
648      * @param childUUID the child tab uuid
649      */
650     public static void removeDependency(String childUUID) {
651         readDocument();
652         Element e = getElementWithUUID(doc.getDocumentElement(), childUUID);
653         if (e != null) {
654             e.removeAttribute("depends");
655         }
656         writeDocument();
657     }
658
659     /**
660      * Restore an application by its name
661      * @param name the application name
662      * @return true if the operation succeded
663      */
664     public static boolean restoreUUID(String uuid) {
665         readDocument();
666         Element elem = getElementWithUUID(uuid);
667         if (elem == null) {
668             return false;
669         }
670
671         startRestoration(uuid);
672
673         return true;
674     }
675
676     /**
677      * Get the uuids of an application
678      * @param name the application anem
679      * @return the corresponding uuids
680      */
681     public static String[] getApplicationUUIDs(String name) {
682         readDocument();
683         NodeList list = doc.getDocumentElement().getElementsByTagName(name);
684         String[] uuids = new String[getNodeListLength(list)];
685         for (int i = 0; i < uuids.length; i++) {
686             if (list.item(i) instanceof Element) {
687                 Element elem = (Element) list.item(i);
688                 uuids[i] = elem.getAttribute("uuid");
689             }
690         }
691
692         return uuids;
693     }
694
695     /**
696      * Get the length of a NodeList (this is a workaround for a f... java bug)
697      */
698     private static final int getNodeListLength(NodeList list) {
699         int length = 0;
700         try {
701             length = list.getLength();
702         } catch (NullPointerException e) { }
703
704         return length;
705     }
706
707
708     /**
709      * Inner interface used to have something to execute when the restoration is finished
710      */
711     public interface EndedRestoration {
712
713         /**
714          * Stuff to do when the restoration is ended
715          */
716         public void finish();
717     }
718 }