Update of the localization files
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / Xcos.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  * Copyright (C) 2010 - DIGITEO - Clement DAVID
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.xcos;
15
16 import static org.scilab.modules.xcos.utils.FileUtils.delete;
17 import static org.scilab.modules.xcos.utils.FileUtils.exists;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.lang.reflect.InvocationTargetException;
22 import java.util.ArrayDeque;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.logging.LogManager;
32
33 import javax.swing.ImageIcon;
34 import javax.swing.SwingUtilities;
35 import javax.swing.SwingWorker;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.scilab.modules.action_binding.InterpreterManagement;
40 import org.scilab.modules.core.Scilab;
41 import org.scilab.modules.graph.utils.ScilabExported;
42 import org.scilab.modules.gui.bridge.tab.SwingScilabTab;
43 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
44 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
45 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
46 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
47 import org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory;
48 import org.scilab.modules.gui.tabfactory.ScilabTabFactory;
49 import org.scilab.modules.gui.utils.ClosingOperationsManager;
50 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
51 import org.scilab.modules.gui.utils.WindowsConfigurationManager;
52 import org.scilab.modules.localization.Messages;
53 import org.scilab.modules.xcos.block.BasicBlock;
54 import org.scilab.modules.xcos.block.SuperBlock;
55 import org.scilab.modules.xcos.configuration.ConfigurationManager;
56 import org.scilab.modules.xcos.configuration.model.DocumentType;
57 import org.scilab.modules.xcos.graph.DiagramComparator;
58 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
59 import org.scilab.modules.xcos.graph.XcosDiagram;
60 import org.scilab.modules.xcos.io.scicos.H5RWHandler;
61 import org.scilab.modules.xcos.palette.PaletteBlockCtrl;
62 import org.scilab.modules.xcos.palette.PaletteManager;
63 import org.scilab.modules.xcos.palette.model.Category;
64 import org.scilab.modules.xcos.palette.model.PaletteBlock;
65 import org.scilab.modules.xcos.palette.model.PreLoaded;
66 import org.scilab.modules.xcos.palette.view.PaletteManagerView;
67 import org.scilab.modules.xcos.utils.FileUtils;
68 import org.scilab.modules.xcos.utils.XcosFileType;
69 import org.scilab.modules.xcos.utils.XcosMessages;
70
71 import com.mxgraph.model.mxGraphModel;
72 import com.mxgraph.util.mxEvent;
73 import com.mxgraph.util.mxEventObject;
74 import com.mxgraph.view.mxStylesheet;
75
76 /**
77  * Xcos entry point class
78  */
79 // CSOFF: ClassFanOutComplexity
80 // CSOFF: ClassDataAbstractionCoupling
81 public final class Xcos {
82     /**
83      * The current Xcos version
84      */
85     public static final String VERSION = "1.0";
86     /**
87      * The current Xcos tradename
88      */
89     public static final String TRADENAME = "Xcos";
90     public static final ImageIcon ICON = new ImageIcon(ScilabSwingUtilities.findIcon("utilities-system-monitor", "256x256"));
91
92     private static final String LOAD_XCOS_LIBS_LOAD_SCICOS = "loadXcosLibs(); loadScicos();";
93
94     /*
95      * Dependencies version
96      */
97     private static final List<String> MXGRAPH_VERSIONS = null;
98     private static final List<String> HDF5_VERSIONS = Arrays.asList(
99         "[1, 8, 4]", "[1, 8, 5]", "[1, 8, 6]", "[1, 8, 7]", "[1, 8, 8]");
100     private static final List<String> BATIK_VERSIONS = Arrays.asList("1.7");
101
102     private static final String UNABLE_TO_LOAD_JGRAPHX = Messages
103         .gettext("Unable to load the jgraphx library.\nExpecting version %s ; Getting version %s .");
104     private static final String UNABLE_TO_LOAD_JHDF5 = Messages
105         .gettext("Unable to load the hdf5-java (jhdf5) library. \nExpecting version %s ; Getting version %s .");
106     private static final String UNABLE_TO_LOAD_HDF5 = Messages
107         .gettext("Unable to load the native HDF5 library.");
108     private static final String UNABLE_TO_LOAD_BATIK = Messages
109         .gettext("Unable to load the Batik library. \nExpecting version %s ; Getting version %s .");
110
111     private static final String CALLED_OUTSIDE_THE_EDT_THREAD = "Called outside the EDT thread.";
112     private static final Log LOG = LogFactory.getLog(Xcos.class);
113
114     /** common shared instance */
115     private static volatile Xcos sharedInstance;
116
117     static {
118         Scilab.registerInitialHook(new Runnable() {
119                 @Override
120                 public void run() {
121                     /* load scicos libraries (macros) */
122                     InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
123                 }
124             });
125     }
126
127     /*
128      * Instance data
129      */
130     private final Map<File, Collection<XcosDiagram>> diagrams;
131     private boolean onDiagramIteration = false;
132
133     /*
134      * Instance handlers
135      */
136     private final PaletteManager palette;
137     private final ConfigurationManager configuration;
138     private final mxStylesheet styleSheet;
139     private final XcosTabFactory factory;
140
141     /**
142      * Construct an Xcos instance.
143      *
144      * There must be only one Xcos instance per Scilab application
145      */
146     private Xcos(final XcosTabFactory factory) {
147         /*
148          * Read the configuration to support dynamic (before Xcos launch)
149          * settings.
150          */
151         try {
152             LogManager.getLogManager().readConfiguration();
153         } catch (final SecurityException e) {
154             LOG.error(e);
155         } catch (final IOException e) {
156             LOG.error(e);
157         }
158
159         /* Check the dependencies at startup time */
160         // checkDependencies();
161
162         /*
163          * Allocate data
164          */
165         diagrams = new HashMap<File, Collection<XcosDiagram>>();
166         // null is used for not saved diagrams
167         addDiagram(null, null);
168
169         /*
170          * get the handlers instance
171          */
172         palette = PaletteManager.getInstance();
173         configuration = ConfigurationManager.getInstance();
174         styleSheet = new mxStylesheet();
175
176         try {
177             FileUtils.decodeStyle(styleSheet);
178         } catch (final IOException e) {
179             LOG.error(e);
180         }
181
182         /*
183          * Register as an AbstractScilabTabFactory
184          */
185         if (factory == null) {
186             this.factory = new XcosTabFactory(false);
187         } else {
188             this.factory = factory;
189         }
190         ScilabTabFactory.getInstance().addTabFactory(this.factory);
191     }
192
193     /**
194      * Check the dependencies and the version dependencies.
195      *
196      * This method use runtime class loading to handle ClassNotFoundException.
197      *
198      * This method catch any exception and rethrow it with a well defined
199      * message. Thus it doesn't pass the IllegalCatch metrics.
200      */
201     // CSOFF: IllegalCatch
202     // CSOFF: MagicNumber
203     private void checkDependencies() {
204         final ClassLoader loader = ClassLoader.getSystemClassLoader();
205
206         /* JGraphx */
207         String mxGraphVersion = "";
208         try {
209             final Class<?> klass = loader.loadClass("com.mxgraph.view.mxGraph");
210             mxGraphVersion = (String) klass.getDeclaredField("VERSION").get(
211                 null);
212
213             if (MXGRAPH_VERSIONS != null
214                 && !MXGRAPH_VERSIONS.contains(mxGraphVersion)) {
215                 throw new Exception();
216             }
217         } catch (final Throwable e) {
218             throw new RuntimeException(String.format(UNABLE_TO_LOAD_JGRAPHX,
219                                                      MXGRAPH_VERSIONS.get(0), mxGraphVersion), e);
220         }
221
222         /* HDF5 */
223         final int[] libVersion = new int[3];
224         try {
225             final Class<?> klass = loader.loadClass("ncsa.hdf.hdf5lib.H5");
226
227             /* hdf5-java */
228             int ret = (Integer) klass.getMethod("H5get_libversion",
229                                                 libVersion.getClass()).invoke(null, libVersion);
230             if (ret < 0) {
231                 throw new Exception();
232             }
233
234             if (!HDF5_VERSIONS.contains(Arrays.toString(libVersion))) {
235                 throw new Exception();
236             }
237
238             /* hdf5 */
239             ret = (Integer) klass.getMethod("H5check_version", int.class,
240                                             int.class, int.class).invoke(null, libVersion[0],
241                                                                          libVersion[1], libVersion[2]);
242             if (ret < 0) {
243                 throw new RuntimeException(UNABLE_TO_LOAD_HDF5);
244             }
245
246         } catch (final Throwable e) {
247             if (!(e instanceof RuntimeException)) {
248                 throw new RuntimeException(String.format(UNABLE_TO_LOAD_JHDF5,
249                                                          HDF5_VERSIONS.get(0), Arrays.toString(libVersion)), e);
250             }
251         }
252
253         /* Batik */
254         String batikVersion = null;
255         try {
256             final Class<?> klass = loader.loadClass("org.apache.batik.Version");
257             batikVersion = klass.getPackage().getImplementationVersion()
258                 .split("\\+")[0];
259
260             if (!BATIK_VERSIONS.contains(batikVersion)) {
261                 throw new Exception();
262             }
263
264         } catch (final Throwable e) {
265             throw new RuntimeException(String.format(UNABLE_TO_LOAD_BATIK,
266                                                      BATIK_VERSIONS.get(0), batikVersion), e);
267         }
268     }
269
270     // CSON: MagicNumber
271     // CSON: IllegalCatch
272
273     /**
274      * @return the per Scilab application, Xcos instance
275      */
276     public static synchronized Xcos getInstance() {
277         return getInstance(null);
278     }
279
280     /**
281      * @param factory
282      *            the tab factory instance or null on creation
283      * @return the per Scilab application, Xcos instance
284      */
285     private static synchronized Xcos getInstance(final XcosTabFactory factory) {
286         if (sharedInstance == null) {
287             sharedInstance = new Xcos(factory);
288
289             /*
290              * Lazy loading of HDF5 libraries to avoid first drag lag.
291              */
292             (new SwingWorker<Void, Void>() {
293
294                 @Override
295                     protected Void doInBackground() throws Exception {
296                     try {
297                         final Category root = PaletteManager.getInstance()
298                             .getRoot();
299
300                         final PaletteBlock b = ((PreLoaded) root.getNode().get(
301                                                     0)).getBlock().get(0);
302                         new PaletteBlockCtrl(b).getTransferable();
303                     } catch (IndexOutOfBoundsException e) {
304                         LOG.debug(e);
305                     } catch (ClassCastException e) {
306                         LOG.debug(e);
307                     }
308                     return null;
309                 }
310             }).execute();
311
312             LOG.trace("Session started");
313         }
314
315         return sharedInstance;
316     }
317
318     /**
319      * Try to quit xcos
320      */
321     public void quit(boolean force) {
322         if (sharedInstance == null) {
323             return;
324         }
325
326     }
327
328     /**
329      * Clear the shared instance.
330      */
331     private static synchronized void clearInstance() {
332         sharedInstance = null;
333         LOG.trace("Session ended");
334     }
335
336     /**
337      * All Opened diagrams
338      *
339      * @return the opened diagrams list
340      */
341     public List<XcosDiagram> openedDiagrams() {
342         final List<XcosDiagram> opened = new ArrayList<XcosDiagram>();
343         for (File f : diagrams.keySet()) {
344             opened.addAll(openedDiagrams(f));
345         }
346
347         return opened;
348     }
349
350     /**
351      * Opened diagrams
352      *
353      * @param f
354      *            the file
355      * @return the opened diagrams list
356      */
357     public List<XcosDiagram> openedDiagrams(File f) {
358         final List<XcosDiagram> opened = new ArrayList<XcosDiagram>();
359         for (XcosDiagram d : diagrams.get(f)) {
360             if (d.isOpened()) {
361                 opened.add(d);
362             }
363         }
364
365         return opened;
366     }
367
368     /**
369      * Check if the in memory file representation is modified
370      *
371      * @param f
372      *            the file
373      * @return is modified
374      */
375     public boolean isModified(File f) {
376         for (XcosDiagram d : diagrams.get(f)) {
377             if (d.isModified()) {
378                 return true;
379             }
380         }
381
382         return false;
383     }
384
385     /**
386      * @return the global shared styleSheet
387      */
388     public mxStylesheet getStyleSheet() {
389         return styleSheet;
390     }
391
392     /**
393      * Open a file from it's filename.
394      *
395      * This method must be called on the EDT thread. For other use, please use
396      * the {@link #xcos(String)} method.
397      *
398      * @param filename
399      *            the file to open. If null an empty diagram is created.
400      */
401     public void open(final File filename) {
402         if (!SwingUtilities.isEventDispatchThread()) {
403             LOG.error(CALLED_OUTSIDE_THE_EDT_THREAD);
404         }
405
406         /*
407          * If it is the first window opened, then open the palette first.
408          */
409         if (filename == null && openedDiagrams().isEmpty()) {
410             PaletteManager.setVisible(true);
411         }
412
413         XcosDiagram diag = null;
414
415         if (filename != null && filename.exists()) {
416             configuration.addToRecentFiles(filename);
417
418             /*
419              * looking for an already opened diagram
420              */
421             final Collection<XcosDiagram> diags = diagrams.get(filename);
422             if (diags != null && !diags.isEmpty()) {
423                 diag = diags.iterator().next();
424             }
425         }
426
427         if (diag == null) {
428
429             /*
430              * Allocate and setup a new diagram
431              */
432             diag = new XcosDiagram();
433             diag.installListeners();
434
435             /*
436              * Create a visible window before loading
437              */
438             if (XcosTab.get(diag) == null) {
439                 XcosTab.restore(diag);
440             }
441
442             /*
443              * Load the file if applicable
444              */
445             if (filename != null) {
446                 diag = diag.openDiagramFromFile(filename);
447             }
448
449             if (diag != null) {
450                 addDiagram(diag.getSavedFile(), diag);
451             }
452         }
453
454         if (diag != null) {
455             diag.updateTabTitle();
456         }
457     }
458
459     /**
460      * Get an unmodifiable view of the diagrams for a specific file
461      *
462      * @param f
463      *            the file
464      * @return the diagram collection
465      */
466     public Collection<XcosDiagram> getDiagrams(final File f) {
467         final Collection<XcosDiagram> diags = diagrams.get(f);
468         if (diags == null) {
469             return null;
470         }
471         return Collections.unmodifiableCollection(diags);
472     }
473
474     /**
475      * Add a diagram to the diagram list for a file. Be sure to set the right
476      * opened status on the diagram before calling this method.
477      *
478      * @param f
479      *            the file
480      * @param diag
481      *            the diag
482      */
483     public void addDiagram(final File f, final XcosDiagram diag) {
484         if (onDiagramIteration) {
485             throw new RuntimeException();
486         }
487
488         /*
489          * Create the collection if it does not exist
490          */
491         Collection<XcosDiagram> diags = diagrams.get(f);
492         if (diags == null) {
493             diags = createDiagramCollection();
494             diagrams.put(f, diags);
495         }
496
497         if (diag != null) {
498             /*
499              * Remove the diagram (and any child)
500              */
501             final Collection<XcosDiagram> toBeMoved = removeChildren(diag);
502
503             /*
504              * Add the diagram to the collection
505              */
506             diags.addAll(toBeMoved);
507         }
508     }
509
510     private Collection<XcosDiagram> removeChildren(XcosDiagram diag) {
511         final Collection<XcosDiagram> removed = new HashSet<XcosDiagram>();
512         removed.add(diag);
513
514         for (Collection<XcosDiagram> it : diagrams.values()) {
515             if (!it.contains(diag)) {
516                 continue;
517             }
518
519             /*
520              * Add all children to the removed collection.
521              */
522             for (XcosDiagram graph : it) {
523                 if (graph instanceof SuperBlockDiagram) {
524                     final XcosDiagram parent = ((SuperBlockDiagram) graph)
525                         .getContainer().getParentDiagram();
526
527                     // As "it" is sorted according to the hierarchy, "removed"
528                     // is also ordered.
529                     if (removed.contains(parent)) {
530                         removed.add(graph);
531                     }
532                 }
533
534             }
535
536             /*
537              * really remove them all
538              */
539             it.removeAll(removed);
540
541         }
542
543         return removed;
544     }
545
546     /**
547      * Create a diagram collections (sorted List)
548      *
549      * @return the diagram collection
550      */
551     public Collection<XcosDiagram> createDiagramCollection() {
552         return new ArrayList<XcosDiagram>() {
553             @Override
554                 public boolean add(XcosDiagram element) {
555                 final boolean status = super.add(element);
556                 DiagramComparator.sort(this);
557                 return status;
558             }
559
560             @Override
561                 public boolean addAll(Collection<? extends XcosDiagram> c) {
562                 final boolean status = super.addAll(c);
563                 DiagramComparator.sort(this);
564                 return status;
565             }
566         };
567     }
568
569     /**
570      * Try to close the graph (popup save dialog)
571      *
572      * @param graph
573      *            the graph to close
574      * @return if we can (or not) close the graph
575      */
576     public boolean canClose(final XcosDiagram graph) {
577         boolean canClose = false;
578         final File f = graph.getSavedFile();
579
580         final boolean wasLastOpened = openedDiagrams(f).size() <= 1;
581         final boolean isModified = isModified(f);
582         if (!(wasLastOpened && isModified)) {
583             canClose = true;
584         }
585
586         if (!canClose) {
587             final AnswerOption ans = ScilabModalDialog.show(XcosTab.get(graph),
588                                                             XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS,
589                                                             IconType.QUESTION_ICON, ButtonType.YES_NO_CANCEL);
590
591             switch (ans) {
592             case YES_OPTION:
593                 canClose = diagrams.get(f).iterator().next().saveDiagram();
594                 break;
595             case NO_OPTION:
596                 canClose = true; // can close
597                 break;
598             default:
599                 canClose = false; // operation canceled
600                 break;
601             }
602         }
603
604         /*
605          * Update configuration before the destroy call to validate the uuid
606          */
607         if (canClose) {
608             configuration.addToRecentTabs(graph);
609             configuration.saveConfig();
610         }
611         return canClose;
612     }
613
614     /**
615      * Close a diagram.
616      *
617      * This method must be called on the EDT thread.
618      *
619      * @param graph
620      *            the diagram to close
621      */
622     public void destroy(XcosDiagram graph) {
623         final File f = graph.getSavedFile();
624         final boolean wasLastOpenedForFile = openedDiagrams(f).size() <= 1;
625
626         if (!onDiagramIteration && wasLastOpenedForFile) {
627             diagrams.remove(f);
628         }
629     }
630
631     /**
632      * @param graph
633      *            the graph to handle
634      * @param list
635      *            the diagram to check
636      * @return diagram name for the "Are your sure ?" dialog
637      */
638     public String askForClosing(final XcosDiagram graph,
639                                 final List<SwingScilabTab> list) {
640         final String msg;
641
642         if (wasLastOpened(list)) {
643             msg = TRADENAME;
644         } else {
645             msg = null;
646         }
647
648         return msg;
649     }
650
651     /**
652      * Does Xcos will close or not ?
653      *
654      * @param list
655      *            the list to be closed
656      * @return true if all files will be close on tabs close.
657      */
658     public boolean wasLastOpened(final List<SwingScilabTab> list) {
659         final HashSet<String> opened = new HashSet<String>();
660         for (XcosDiagram diag : openedDiagrams()) {
661             opened.add(diag.getDiagramTab());
662         }
663
664         final HashSet<String> tabs = new HashSet<String>();
665         for (SwingScilabTab tab : list) {
666             if (tab != null) {
667                 tabs.add(tab.getPersistentId());
668             }
669         }
670
671         opened.removeAll(tabs);
672
673         return opened.isEmpty();
674     }
675
676     /**
677      * Close the current xcos session.
678      *
679      * This method must be called on the EDT thread. For other use, please use
680      * the {@link #closeXcosFromScilab()} method.
681      */
682     public static synchronized void closeSession(final boolean ask) {
683         if (!SwingUtilities.isEventDispatchThread()) {
684             LOG.error(CALLED_OUTSIDE_THE_EDT_THREAD);
685         }
686
687         /* Doesn't instantiate xcos on close operation */
688         if (sharedInstance == null) {
689             return;
690         }
691
692         /*
693          * Try to close all opened files
694          */
695         final Xcos instance = sharedInstance;
696
697         // get all tabs
698         final List<SwingScilabTab> tabs = new ArrayList<SwingScilabTab>();
699         for (final Collection<XcosDiagram> diags : instance.diagrams.values()) {
700             for (final XcosDiagram diag : diags) {
701                 final SwingScilabTab tab = XcosTab.get(diag);
702                 if (tab != null) {
703                     tabs.add(tab);
704                 }
705             }
706         }
707
708         // ask to close
709         final boolean status = ClosingOperationsManager.startClosingOperation(tabs, ask, ask);
710
711         // clear states
712         if (status) {
713             /* reset the shared instance state */
714             instance.diagrams.keySet().clear();
715             instance.addDiagram(null, null);
716
717             /* terminate any remaining simulation */
718             InterpreterManagement.requestScilabExec("haltscicos");
719
720             /* Saving modified data */
721             instance.palette.saveConfig();
722             instance.configuration.saveConfig();
723         }
724     }
725
726     /*
727      * Scilab exported methods.
728      *
729      * All the following methods must use SwingUtilities method to assert that
730      * the operations will be called on the EDT thread.
731      *
732      * @see modules/xcos/src/jni/Xcos.giws.xml
733      *
734      * @see sci_gateway/xcos_gateway.xml
735      *
736      * @see modules/xcos/sci_gateway/cpp/sci_*.cpp
737      */
738
739     /**
740      * Entry popint without filename.
741      *
742      * This method invoke Xcos operation on the EDT thread.
743      */
744     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
745     public static void xcos() {
746         final Xcos instance = getInstance();
747
748         /* load scicos libraries (macros) */
749         InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
750
751         SwingUtilities.invokeLater(new Runnable() {
752             @Override
753             public void run() {
754                 instance.open(null);
755             }
756         });
757     }
758
759     /**
760      * Entry point with filename
761      *
762      * This method invoke Xcos operation on the EDT thread.
763      *
764      * @param fileName
765      *            The filename
766      */
767     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
768     public static void xcos(final String fileName) {
769         final Xcos instance = getInstance();
770         final File filename = new File(fileName);
771
772         /* load scicos libraries (macros) */
773         InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
774
775         SwingUtilities.invokeLater(new Runnable() {
776             @Override
777             public void run() {
778                 instance.open(filename);
779             }
780         });
781     }
782
783     /**
784      * Close the current xcos session from any thread.
785      *
786      * This method invoke Xcos operation on the EDT thread. Please prefer using
787      * {@link #closeSession()} when the caller is on the EDT thread.
788      */
789     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
790     public static void closeXcosFromScilab() {
791         try {
792             SwingUtilities.invokeAndWait(new Runnable() {
793                     @Override
794                     public void run() {
795                         closeSession(false);
796                         clearInstance();
797                     }
798                 });
799         } catch (final InterruptedException e) {
800             LOG.error(e);
801         } catch (final InvocationTargetException e) {
802             Throwable throwable = e;
803             String firstMessage = null;
804             while (throwable != null) {
805                 firstMessage = throwable.getLocalizedMessage();
806                 throwable = throwable.getCause();
807             }
808
809             throw new RuntimeException(firstMessage, e);
810         }
811     }
812
813     /**
814      * Look in each diagram to find the block corresponding to the given uid and
815      * display a warning message.
816      *
817      * This method invoke Xcos operation on the EDT thread.
818      *
819      * @param uid
820      *            A String as UID.
821      * @param message
822      *            The message to display.
823      */
824     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
825     public static void warnCellByUID(final String[] uid, final String message) {
826         try {
827             SwingUtilities.invokeAndWait(new Runnable() {
828                     @Override
829                     public void run() {
830                         final ArrayDeque<String> deque = new ArrayDeque<String>(
831                             Arrays.asList(uid));
832
833                         warnCellByUID(deque, message);
834                     }
835                 });
836         } catch (final InterruptedException e) {
837             LOG.error(e);
838         } catch (final InvocationTargetException e) {
839             Throwable throwable = e;
840             String firstMessage = null;
841             while (throwable != null) {
842                 firstMessage = throwable.getLocalizedMessage();
843                 throwable = throwable.getCause();
844             }
845
846             throw new RuntimeException(firstMessage, e);
847         }
848     }
849
850     private static void warnCellByUID(final ArrayDeque<String> deque, final String message) {
851         String id;
852         BasicBlock block = null;
853         Collection<XcosDiagram> diags = null;
854
855         // specific case with an empty array
856         if (deque.isEmpty()) {
857             return;
858         }
859
860         // first element
861         id = deque.pop();
862         try {
863             getInstance().onDiagramIteration = true;
864
865             for (Collection<XcosDiagram> ds : getInstance().diagrams.values()) {
866                 if (ds.isEmpty()) {
867                     continue;
868                 }
869
870                 final XcosDiagram root = ds.iterator().next();
871
872                 block = (BasicBlock) ((mxGraphModel) root.getModel()).getCell(id);
873                 if (block != null) {
874                     diags = ds;
875                     break;
876                 }
877             }
878         } finally {
879             getInstance().onDiagramIteration = false;
880         }
881
882         // loop to get only the last diagram
883         while (block instanceof SuperBlock && !deque.isEmpty()) {
884             block.getParentDiagram().warnCellByUID(block.getId(), XcosMessages.ERROR_UNABLE_TO_COMPILE_THIS_SUPER_BLOCK);
885
886             final SuperBlock superBlock = (SuperBlock) block;
887             id = deque.pop();
888
889             if (!diags.contains(superBlock.getChild()) || !superBlock.getChild().isOpened()) {
890                 block.openBlockSettings(null);
891             }
892
893             final mxGraphModel model = ((mxGraphModel) superBlock.getChild().getModel());
894             block = (BasicBlock) model.getCell(id);
895         }
896
897         // We are unable to find the block with the right id
898         if (block == null) {
899             return;
900         }
901
902         // finally perform the action on the last block
903         final XcosDiagram parent = findParent(block);
904         parent.warnCellByUID(block.getId(), message);
905
906         SwingUtilities.invokeLater(new Runnable() {
907                 @Override
908                 public void run() {
909                     /*
910                      * Focus on an existing diagram
911                      */
912                     XcosTab.get(parent).setCurrent();
913                 }
914             });
915     }
916
917     /**
918      * This function convert a Xcos diagram to Scilab variable.
919      *
920      * This method invoke Xcos operation on the EDT thread.
921      *
922      * @param xcosFile
923      *            The xcos diagram file
924      * @param h5File
925      *            The target file
926      * @param overwrite
927      *            Does the file will be overwritten ?
928      * @return Not used (compatibility)
929      */
930     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
931     public static int xcosDiagramToHDF5(final String xcosFile,
932                                         final String h5File, final boolean overwrite) {
933         final File file = new File(xcosFile);
934
935         if (exists(h5File)) {
936             if (!overwrite) {
937                 return 1;
938             } else {
939                 delete(h5File);
940             }
941         }
942
943         if (!file.exists()) {
944             return 1;
945         }
946
947         try {
948             SwingUtilities.invokeAndWait(new Runnable() {
949                 @Override
950                 public void run() {
951                     final XcosDiagram diagram = new XcosDiagram();
952
953                     final XcosFileType filetype = XcosFileType.findFileType(xcosFile);
954                     if (filetype != null) {
955                         try {
956                             filetype.load(xcosFile, diagram);
957                             new H5RWHandler(h5File).writeDiagram(diagram);
958                         } catch (Exception e) {
959                             throw new RuntimeException(e);
960                         }
961                     }
962                 }
963             });
964         } catch (final InterruptedException e) {
965             throw new RuntimeException(e);
966         } catch (final InvocationTargetException e) {
967             Throwable throwable = e;
968             String firstMessage = null;
969             while (throwable != null) {
970                 firstMessage = throwable.getLocalizedMessage();
971                 throwable = throwable.getCause();
972             }
973
974             throw new RuntimeException(firstMessage, e);
975         }
976
977         return 0;
978     }
979
980     /**
981      * Open a diagram by uid.
982      *
983      * This method invoke Xcos operation on the EDT thread.
984      *
985      * @param uid
986      *            UID path to a block.
987      */
988     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
989     @Deprecated
990     public static void xcosDiagramOpen(final String[] uid) {
991         throw new UnsupportedOperationException();
992     }
993
994     /**
995      * Close a diagram by uid.
996      *
997      * This method invoke Xcos operation on the EDT thread.
998      *
999      * @param uid
1000      *            The diagram id path
1001      */
1002     @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1003     @Deprecated
1004     public static void xcosDiagramClose(final String[] uid) {
1005         throw new UnsupportedOperationException();
1006     }
1007
1008     /**
1009      * Look for the parent diagram of the cell in the diagram hierarchy.
1010      *
1011      * @param cell
1012      *            the cell to search for
1013      * @return the associated diagram
1014      */
1015     public static XcosDiagram findParent(Object cell) {
1016         final Xcos instance = getInstance();
1017         try {
1018             instance.onDiagramIteration = true;
1019
1020             for (Collection<XcosDiagram> diags : instance.diagrams.values()) {
1021                 for (XcosDiagram diag : diags) {
1022                     if (diag.getModel().contains(cell)) {
1023                         if (cell instanceof BasicBlock) {
1024                             ((BasicBlock) cell).setParentDiagram(diag);
1025                         }
1026                         return diag;
1027                     }
1028                 }
1029             }
1030         } finally {
1031             instance.onDiagramIteration = false;
1032         }
1033
1034         return null;
1035     }
1036
1037     /*
1038      * @see org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory
1039      */
1040     public static class XcosTabFactory extends AbstractScilabTabFactory {
1041
1042         /*
1043          * Cache
1044          */
1045         private DocumentType cachedDocumentType;
1046
1047         /**
1048          * Default constructor
1049          */
1050         public XcosTabFactory() {
1051             this(true);
1052         }
1053
1054         private XcosTabFactory(boolean instanciateXcos) {
1055             if (instanciateXcos) {
1056                 getInstance(this);
1057             }
1058         }
1059
1060         /**
1061          * Create/restore a tab for a given uuid
1062          *
1063          * @param uuid
1064          *            the specific uuid
1065          * @return the tab instance
1066          */
1067         @Override
1068         public synchronized SwingScilabTab getTab(final String uuid) {
1069             if (uuid == null) {
1070                 return null;
1071             }
1072
1073             SwingScilabTab tab = ScilabTabFactory.getInstance().getFromCache(
1074                 uuid);
1075
1076             // Palette manager restore
1077             if (tab == null) {
1078                 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1079                     PaletteManagerView.restore(null, false);
1080                     tab = PaletteManagerView.get();
1081                 }
1082             }
1083
1084             // diagram (tab or viewport) restore
1085             if (tab == null) {
1086                 cache(uuid);
1087                 if (cachedDocumentType == null) {
1088                     return null;
1089                 }
1090
1091                 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1092                 final boolean isViewport = uuid.equals(cachedDocumentType
1093                                                        .getViewport());
1094
1095                 final XcosDiagram graph = getDiagram(isTab, isViewport);
1096                 if (graph != null && isTab) {
1097                     XcosTab.restore(graph, false);
1098                     graph.fireEvent(new mxEventObject(mxEvent.ROOT));
1099                     tab = XcosTab.get(graph);
1100                 } else if (graph != null && isViewport) {
1101                     ViewPortTab.restore(graph, false);
1102                     tab = ViewPortTab.get(graph);
1103
1104                     ClosingOperationsManager.addDependency(
1105                         (SwingScilabTab) XcosTab.get(graph), tab);
1106                     WindowsConfigurationManager.makeDependency(
1107                         graph.getDiagramTab(), tab.getPersistentId());
1108                 } else {
1109                     return null;
1110                 }
1111             }
1112
1113             WindowsConfigurationManager.restorationFinished(tab);
1114             ScilabTabFactory.getInstance().addToCache(tab);
1115
1116             return tab;
1117         }
1118
1119         private XcosDiagram getDiagram(boolean isTab, boolean isViewport) {
1120             XcosDiagram graph = null;
1121             if (isTab) {
1122                 // load a new diagram
1123                 graph = getInstance().configuration
1124                     .loadDiagram(cachedDocumentType);
1125             } else if (isViewport) {
1126                 // get the cached diagram
1127                 final File f = getInstance().configuration
1128                     .getFile(cachedDocumentType);
1129                 final Collection<XcosDiagram> diags = getInstance().diagrams
1130                     .get(f);
1131
1132                 for (XcosDiagram d : diags) {
1133                     final String id = d.getDiagramTab();
1134                     if (id != null && id.equals(cachedDocumentType.getUuid())) {
1135                         graph = d;
1136                         break;
1137                     }
1138                 }
1139             }
1140
1141             return graph;
1142         }
1143
1144         @Override
1145         public synchronized boolean isAValidUUID(String uuid) {
1146             // check the Palette manager view (static uuid)
1147             if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1148                 return true;
1149             }
1150
1151             /*
1152              * Cache and check against cache to ease next getTab(uuid) call
1153              */
1154             cache(uuid);
1155             return cachedDocumentType != null;
1156         }
1157
1158         /**
1159          * Cache the {@link DocumentType} for the specific uuid
1160          *
1161          * @param uuid
1162          *            the uuid
1163          */
1164         private void cache(String uuid) {
1165             /*
1166              * Handle a non null cache
1167              */
1168             if (cachedDocumentType != null) {
1169                 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1170                 final boolean isViewport = uuid.equals(cachedDocumentType
1171                                                        .getViewport());
1172
1173                 if (isTab || isViewport) {
1174                     return;
1175                 } else {
1176                     cachedDocumentType = null;
1177                 }
1178             }
1179
1180             /*
1181              * Invalid cache, look for the right one
1182              */
1183             final ConfigurationManager config = getInstance().configuration;
1184             final List<DocumentType> docs = config.getSettings().getTab();
1185             for (DocumentType d : docs) {
1186                 final boolean isTab = uuid.equals(d.getUuid());
1187                 final boolean isViewport = uuid.equals(d.getViewport());
1188
1189                 if (isTab || isViewport) {
1190                     cachedDocumentType = d;
1191                     break;
1192                 }
1193             }
1194         }
1195
1196         @Override
1197         public String getPackage() {
1198             return TRADENAME;
1199         }
1200
1201         @Override
1202         public String getClassName() {
1203             return XcosTabFactory.class.getName();
1204         }
1205
1206         @Override
1207         public String getApplication() {
1208             return TRADENAME;
1209         }
1210     }
1211 }
1212 // CSON: ClassDataAbstractionCoupling
1213 // CSON: ClassFanOutComplexity