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
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
14 package org.scilab.modules.xcos;
16 import java.awt.Component;
17 import java.awt.GraphicsEnvironment;
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.util.ArrayDeque;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
30 import java.util.logging.LogManager;
31 import java.util.logging.Logger;
33 import javax.swing.Action;
34 import javax.swing.ImageIcon;
35 import javax.swing.SwingUtilities;
37 import org.scilab.modules.action_binding.InterpreterManagement;
38 import org.scilab.modules.commons.xml.XConfiguration;
39 import org.scilab.modules.core.Scilab;
40 import org.scilab.modules.graph.utils.ScilabExported;
41 import org.scilab.modules.gui.bridge.menu.SwingScilabMenu;
42 import org.scilab.modules.gui.bridge.menubar.SwingScilabMenuBar;
43 import org.scilab.modules.gui.bridge.tab.SwingScilabTab;
44 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
45 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
46 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
47 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
48 import org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory;
49 import org.scilab.modules.gui.tabfactory.ScilabTabFactory;
50 import org.scilab.modules.gui.utils.BarUpdater;
51 import org.scilab.modules.gui.utils.ClosingOperationsManager;
52 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
53 import org.scilab.modules.gui.utils.WindowsConfigurationManager;
54 import org.scilab.modules.localization.Messages;
55 import org.scilab.modules.xcos.actions.ExternalAction;
56 import org.scilab.modules.xcos.block.BasicBlock;
57 import org.scilab.modules.xcos.block.SuperBlock;
58 import org.scilab.modules.xcos.configuration.ConfigurationManager;
59 import org.scilab.modules.xcos.configuration.model.DocumentType;
60 import org.scilab.modules.xcos.graph.DiagramComparator;
61 import org.scilab.modules.xcos.graph.SuperBlockDiagram;
62 import org.scilab.modules.xcos.graph.XcosDiagram;
63 import org.scilab.modules.xcos.io.XcosFileType;
64 import org.scilab.modules.xcos.io.scicos.ScicosFormatException;
65 import org.scilab.modules.xcos.io.scicos.ScilabDirectHandler;
66 import org.scilab.modules.xcos.palette.PaletteManager;
67 import org.scilab.modules.xcos.palette.view.PaletteManagerView;
68 import org.scilab.modules.xcos.preferences.XcosConfiguration;
69 import org.scilab.modules.xcos.utils.BlockPositioning;
70 import org.scilab.modules.xcos.utils.FileUtils;
71 import org.scilab.modules.xcos.utils.XcosMessages;
73 import com.mxgraph.model.mxCell;
74 import com.mxgraph.model.mxGraphModel;
75 import com.mxgraph.model.mxICell;
76 import com.mxgraph.util.mxEvent;
77 import com.mxgraph.util.mxEventObject;
78 import com.mxgraph.view.mxStylesheet;
81 * Xcos entry point class
83 // CSOFF: ClassFanOutComplexity
84 // CSOFF: ClassDataAbstractionCoupling
85 public final class Xcos {
87 * The current Xcos version
89 public static final String VERSION = "1.0";
91 * The current Xcos tradename
93 public static final String TRADENAME = "Xcos";
94 public static final ImageIcon ICON = new ImageIcon(ScilabSwingUtilities.findIcon("utilities-system-monitor", "256x256"));
96 private static final String LOAD_XCOS_LIBS_LOAD_SCICOS = "loadXcosLibs(); loadScicos();";
99 * Dependencies version
101 private static final List<String> MXGRAPH_VERSIONS = null;
102 private static final List<String> BATIK_VERSIONS = Arrays.asList("1.7", "1.8pre", "1.8");
104 private static final String IS_HEADLESS = Messages.gettext("a graphical environment is needed.");
105 private static final String UNABLE_TO_LOAD_JGRAPHX = Messages.gettext("Unable to load the jgraphx library.\nExpecting version %s ; Getting version %s .");
106 private static final String UNABLE_TO_LOAD_BATIK = Messages.gettext("Unable to load the Batik library. \nExpecting version %s ; Getting version %s .");
108 private static final String CALLED_OUTSIDE_THE_EDT_THREAD = "Called outside the EDT thread.";
109 private static final Logger LOG = Logger.getLogger(Xcos.class.getSimpleName());
111 /** common shared instance */
112 private static volatile Xcos sharedInstance;
115 Scilab.registerInitialHook(new Runnable() {
118 /* load scicos libraries (macros) */
119 InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
123 XConfiguration.addXConfigurationListener(new XcosConfiguration());
129 private final Map<File, Collection<XcosDiagram>> diagrams;
130 private boolean onDiagramIteration = false;
131 private String lastError = null;
136 private final PaletteManager palette;
137 private final ConfigurationManager configuration;
138 private final mxStylesheet styleSheet;
139 private final List<ExternalAction> externalActions;
141 private final XcosTabFactory factory;
144 * Construct an Xcos instance.
146 * There must be only one Xcos instance per Scilab application
148 private Xcos(final XcosTabFactory factory) {
150 * Read the configuration to support dynamic (before Xcos launch)
154 LogManager.getLogManager().readConfiguration();
155 } catch (final SecurityException e) {
156 LOG.severe(e.toString());
157 } catch (final IOException e) {
158 LOG.severe(e.toString());
161 /* Check the dependencies at startup time */
167 diagrams = new HashMap<File, Collection<XcosDiagram>>();
168 // null is used for not saved diagrams
169 addDiagram(null, null);
172 * get the handlers instance
174 palette = PaletteManager.getInstance();
175 configuration = ConfigurationManager.getInstance();
176 styleSheet = new mxStylesheet();
177 externalActions = new ArrayList<ExternalAction>();
180 FileUtils.decodeStyle(styleSheet);
181 } catch (final IOException e) {
182 LOG.severe(e.toString());
186 * Register as an AbstractScilabTabFactory
188 if (factory == null) {
189 this.factory = new XcosTabFactory(false);
191 this.factory = factory;
193 ScilabTabFactory.getInstance().addTabFactory(this.factory);
197 * Check the dependencies and the version dependencies.
199 * This method use runtime class loading to handle ClassNotFoundException.
201 * This method catch any exception and rethrow it with a well defined
202 * message. Thus it doesn't pass the IllegalCatch metrics.
204 // CSOFF: IllegalCatch
205 // CSOFF: MagicNumber
206 private void checkDependencies() {
207 final ClassLoader loader = ClassLoader.getSystemClassLoader();
209 /* Check not headless */
210 if (GraphicsEnvironment.isHeadless()) {
211 throw new RuntimeException(IS_HEADLESS);
215 String mxGraphVersion = "";
217 final Class<?> klass = loader.loadClass("com.mxgraph.view.mxGraph");
218 mxGraphVersion = (String) klass.getDeclaredField("VERSION").get(null);
220 if (MXGRAPH_VERSIONS != null && !MXGRAPH_VERSIONS.contains(mxGraphVersion)) {
221 throw new Exception();
223 } catch (final Throwable e) {
224 throw new RuntimeException(String.format(UNABLE_TO_LOAD_JGRAPHX, MXGRAPH_VERSIONS.get(0), mxGraphVersion), e);
228 String batikVersion = null;
230 final Class<?> klass = loader.loadClass("org.apache.batik.Version");
231 batikVersion = klass.getPackage().getImplementationVersion().split("\\+")[0];
233 if (!BATIK_VERSIONS.contains(batikVersion)) {
234 throw new Exception();
237 } catch (final Throwable e) {
238 throw new RuntimeException(String.format(UNABLE_TO_LOAD_BATIK, BATIK_VERSIONS.get(0), batikVersion), e);
243 // CSON: IllegalCatch
246 * @return the per Scilab application, Xcos instance
248 public static synchronized Xcos getInstance() {
249 return getInstance(null);
254 * the tab factory instance or null on creation
255 * @return the per Scilab application, Xcos instance
257 private static synchronized Xcos getInstance(final XcosTabFactory factory) {
258 if (sharedInstance == null) {
259 sharedInstance = new Xcos(factory);
261 LOG.finest("Session started");
264 return sharedInstance;
270 public void quit(boolean force) {
271 if (sharedInstance == null) {
278 * Clear the shared instance.
280 private static synchronized void clearInstance() {
281 sharedInstance = null;
282 LOG.finest("Session ended");
286 * All Opened diagrams
288 * @return the opened diagrams list
290 public List<XcosDiagram> openedDiagrams() {
291 final List<XcosDiagram> opened = new ArrayList<XcosDiagram>();
292 for (File f : diagrams.keySet()) {
293 opened.addAll(openedDiagrams(f));
304 * @return the opened diagrams list
306 public List<XcosDiagram> openedDiagrams(File f) {
307 final List<XcosDiagram> opened = new ArrayList<XcosDiagram>();
308 for (XcosDiagram d : diagrams.get(f)) {
318 * Check if the in memory file representation is modified
322 * @return is modified
324 public boolean isModified(File f) {
325 for (XcosDiagram d : diagrams.get(f)) {
326 if (d.isModified()) {
335 * @return the global shared styleSheet
337 public mxStylesheet getStyleSheet() {
342 * Open a file from it's filename.
344 * This method must be called on the EDT thread. For other use, please use
345 * the {@link #xcos(String, String)} method.
348 * the file to open. If null an empty diagram is created.
350 * the variable to decode. If null no decode is performed.
352 public void open(final String file, final String variable) {
353 if (!SwingUtilities.isEventDispatchThread()) {
354 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
358 * If it is the first window opened, then open the palette first.
360 if (file == null && variable == null && openedDiagrams().isEmpty()) {
361 PaletteManager.setVisible(true);
364 XcosDiagram diag = null;
372 if (f != null && f.exists()) {
373 configuration.addToRecentFiles(f);
377 * looking for an already opened diagram
379 final Collection<XcosDiagram> diags = diagrams.get(f);
380 if (diags != null && !diags.isEmpty()) {
381 diag = diags.iterator().next();
383 // if unsaved and empty, reuse it. Allocate otherwise.
384 if (f == null && diag != null && diag.getModel().getChildCount(diag.getDefaultParent()) > 0) {
387 // if reuse then request focus
389 XcosTab tab = XcosTab.get(diag);
397 // loading disabled, unlock
398 synchronized (this) {
403 // loading enable, unlock will be performed later, on another thread
406 * Allocate and setup a new diagram
408 diag = new XcosDiagram();
409 diag.installListeners();
412 * Ask for file creation
414 if (f != null && !f.exists()) {
415 if (!diag.askForFileCreation(f)) {
416 // loading disabled, unlock
417 synchronized (this) {
422 // return now, to avoid tab creation
428 * Create a visible window before loading
430 if (XcosTab.get(diag) == null) {
431 XcosTab.restore(diag);
437 diag.transformAndLoadFile(file, variable);
440 addDiagram(diag.getSavedFile(), diag);
445 diag.updateTabTitle();
450 * Log a loading error
453 * the error description
455 public void setLastError(String error) {
456 this.lastError = error;
460 * Get an unmodifiable view of the diagrams for a specific file
464 * @return the diagram collection
466 public Collection<XcosDiagram> getDiagrams(final File f) {
467 final Collection<XcosDiagram> diags = diagrams.get(f);
471 return Collections.unmodifiableCollection(diags);
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.
483 public void addDiagram(final File f, final XcosDiagram diag) {
484 if (onDiagramIteration) {
485 throw new RuntimeException();
489 * Create the collection if it does not exist
491 Collection<XcosDiagram> diags = diagrams.get(f);
493 diags = createDiagramCollection();
494 diagrams.put(f, diags);
499 * Remove the diagram (and any child)
501 final Collection<XcosDiagram> toBeMoved = removeChildren(diag);
504 * Add the diagram to the collection
506 diags.addAll(toBeMoved);
510 private Collection<XcosDiagram> removeChildren(XcosDiagram diag) {
511 final Collection<XcosDiagram> removed = new HashSet<XcosDiagram>();
514 for (Collection<XcosDiagram> it : diagrams.values()) {
515 if (!it.contains(diag)) {
520 * Add all children to the removed collection.
522 for (XcosDiagram graph : it) {
523 if (graph instanceof SuperBlockDiagram) {
524 final XcosDiagram parent = ((SuperBlockDiagram) graph).getContainer().getParentDiagram();
526 // As "it" is sorted according to the hierarchy, "removed"
528 if (removed.contains(parent)) {
536 * really remove them all
538 it.removeAll(removed);
546 * Create a diagram collections (sorted List)
548 * @return the diagram collection
550 @SuppressWarnings("serial")
551 public Collection<XcosDiagram> createDiagramCollection() {
552 return new ArrayList<XcosDiagram>() {
554 public boolean add(XcosDiagram element) {
555 final boolean status = super.add(element);
556 DiagramComparator.sort(this);
561 public boolean addAll(Collection <? extends XcosDiagram > c) {
562 final boolean status = super.addAll(c);
563 DiagramComparator.sort(this);
570 * Try to close the graph (popup save dialog)
574 * @return if we can (or not) close the graph
576 public boolean canClose(final XcosDiagram graph) {
577 boolean canClose = false;
578 final File f = graph.getSavedFile();
580 final boolean wasLastOpened = openedDiagrams(f).size() <= 1;
581 final boolean isModified = isModified(f);
582 if (!(wasLastOpened && isModified)) {
587 final AnswerOption ans = ScilabModalDialog.show(XcosTab.get(graph), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS, IconType.QUESTION_ICON,
588 ButtonType.YES_NO_CANCEL);
592 canClose = diagrams.get(f).iterator().next().saveDiagram();
595 canClose = true; // can close
598 canClose = false; // operation canceled
604 * Update configuration before the destroy call to validate the uuid
607 configuration.addToRecentTabs(graph);
608 configuration.saveConfig();
616 * This method must be called on the EDT thread.
619 * the diagram to close
621 public void destroy(XcosDiagram graph) {
622 final File f = graph.getSavedFile();
623 final boolean wasLastOpenedForFile = openedDiagrams(f).size() <= 1;
625 if (!onDiagramIteration && wasLastOpenedForFile) {
629 if (openedDiagrams().size() <= 1) {
630 /* halt scicos (stop the simulation) */
631 InterpreterManagement.requestScilabExec("if isdef('haltscicos'), haltscicos(), end;");
637 * the graph to handle
639 * the diagram to check
640 * @return diagram name for the "Are your sure ?" dialog
642 public String askForClosing(final XcosDiagram graph, final List<SwingScilabTab> list) {
645 if (wasLastOpened(list)) {
655 * Does Xcos will close or not ?
658 * the list to be closed
659 * @return true if all files will be close on tabs close.
661 public boolean wasLastOpened(final List<SwingScilabTab> list) {
662 final HashSet<String> opened = new HashSet<String>();
663 for (XcosDiagram diag : openedDiagrams()) {
664 opened.add(diag.getGraphTab());
667 final HashSet<String> tabs = new HashSet<String>();
668 for (SwingScilabTab tab : list) {
670 tabs.add(tab.getPersistentId());
674 opened.removeAll(tabs);
676 return opened.isEmpty();
680 * @return the external action list
682 public List<ExternalAction> getExternalActions() {
683 return externalActions;
687 * Close the current xcos session.
689 * This method must be called on the EDT thread. For other use, please use
690 * the {@link #closeXcosFromScilab()} method.
692 public static synchronized void closeSession(final boolean ask) {
693 if (!SwingUtilities.isEventDispatchThread()) {
694 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
697 /* Doesn't instantiate xcos on close operation */
698 if (sharedInstance == null) {
703 * Try to close all opened files
705 final Xcos instance = sharedInstance;
708 final List<SwingScilabTab> tabs = new ArrayList<SwingScilabTab>();
709 for (final Collection<XcosDiagram> diags : instance.diagrams.values()) {
710 for (final XcosDiagram diag : diags) {
711 final SwingScilabTab tab = XcosTab.get(diag);
719 final boolean status = ClosingOperationsManager.startClosingOperation(tabs, ask, ask);
723 /* reset the shared instance state */
724 instance.diagrams.keySet().clear();
725 instance.addDiagram(null, null);
727 /* terminate any remaining simulation */
728 InterpreterManagement.putCommandInScilabQueue("if isdef('haltscicos'), haltscicos(), end;");
730 /* Saving modified data */
731 instance.palette.saveConfig();
732 instance.configuration.saveConfig();
737 * Scilab exported methods.
739 * All the following methods must use SwingUtilities method to assert that
740 * the operations will be called on the EDT thread.
742 * @see modules/xcos/src/jni/Xcos.giws.xml
744 * @see sci_gateway/xcos_gateway.xml
746 * @see modules/xcos/sci_gateway/cpp/sci_*.cpp
752 * This method invoke Xcos operation on the EDT thread.
755 * The filename (can be null)
757 * The Scilab variable to load (can be null)
759 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
760 public static void xcos(final String file, final String variable) {
761 final Xcos instance = getInstance();
762 instance.lastError = null;
764 /* load scicos libraries (macros) */
765 InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
767 synchronized (instance) {
771 SwingUtilities.invokeLater(new Runnable() {
775 instance.open(file, variable);
780 * Wait loading and fail on error only if the variable is readeable
783 while (variable != null && instance.lastError == null) {
786 } catch (InterruptedException e) {
790 if (instance.lastError != null && !instance.lastError.isEmpty()) {
791 throw new RuntimeException(instance.lastError);
796 * Close the current xcos session from any thread.
798 * This method invoke Xcos operation on the EDT thread. Please prefer using
799 * {@link #closeSession()} when the caller is on the EDT thread.
801 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
802 public static void closeXcosFromScilab() {
804 SwingUtilities.invokeAndWait(new Runnable() {
811 } catch (final InterruptedException e) {
813 } catch (final InvocationTargetException e) {
816 Throwable throwable = e;
817 String firstMessage = null;
818 while (throwable != null) {
819 firstMessage = throwable.getLocalizedMessage();
820 throwable = throwable.getCause();
823 throw new RuntimeException(firstMessage, e);
828 * Look in each diagram to find the block corresponding to the given uid and
829 * display a warning message.
831 * This method invoke Xcos operation on the EDT thread.
836 * The message to display.
838 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
839 public static void warnCellByUID(final String[] uid, final String message) {
841 SwingUtilities.invokeAndWait(new Runnable() {
844 getInstance().warnCell(uid, message);
847 } catch (final InterruptedException e) {
848 LOG.severe(e.toString());
849 } catch (final InvocationTargetException e) {
850 Throwable throwable = e;
851 String firstMessage = null;
852 while (throwable != null) {
853 firstMessage = throwable.getLocalizedMessage();
854 throwable = throwable.getCause();
857 throw new RuntimeException(firstMessage, e);
861 private void warnCell(final String[] uid, final String message) {
862 final mxCell cell = (mxCell) lookupForCell(uid);
864 // We are unable to find the block with the right id
869 // finally perform the action on the last block
870 final XcosDiagram parent = findParent(cell);
871 parent.warnCellByUID(cell.getId(), message);
873 SwingUtilities.invokeLater(new Runnable() {
877 * Focus on an existing diagram
879 XcosTab.get(parent).setCurrent();
884 private Object lookupForCell(final String[] uid) {
885 final ArrayDeque<String> deque = new ArrayDeque<String>(Arrays.asList(uid));
887 // specific case with an empty array
888 if (deque.isEmpty()) {
894 Collection<XcosDiagram> diags = null;
895 String id = deque.pop();
897 onDiagramIteration = true;
899 for (Collection<XcosDiagram> ds : diagrams.values()) {
904 final XcosDiagram root = ds.iterator().next();
906 cell = ((mxGraphModel) root.getModel()).getCell(id);
913 onDiagramIteration = false;
916 // loop to get only the last diagram
917 while (cell instanceof SuperBlock && !deque.isEmpty()) {
918 final SuperBlock block = (SuperBlock) cell;
920 block.getParentDiagram().warnCellByUID(block.getId(), XcosMessages.ERROR_UNABLE_TO_COMPILE_THIS_SUPER_BLOCK);
924 if (!diags.contains(block.getChild()) || !block.getChild().isOpened()) {
925 block.openBlockSettings(null);
928 final mxGraphModel model = ((mxGraphModel) block.getChild().getModel());
929 cell = model.getCell(id);
935 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
936 public static void updateBlock(final String h5File) {
938 SwingUtilities.invokeAndWait(new Runnable() {
941 getInstance().updateBlockInstance();
944 } catch (final InterruptedException e) {
945 LOG.severe(e.toString());
946 } catch (final InvocationTargetException e) {
947 Throwable throwable = e;
948 String firstMessage = null;
949 while (throwable != null) {
950 firstMessage = throwable.getLocalizedMessage();
951 throwable = throwable.getCause();
954 throw new RuntimeException(firstMessage, e);
958 private void updateBlockInstance() {
960 BasicBlock modifiedBlock;
962 final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
963 if (handler == null) {
968 modifiedBlock = handler.readBlock();
969 } catch (ScicosFormatException e) {
970 throw new RuntimeException(e);
974 if (modifiedBlock == null) {
979 final XcosDiagram diag = findParent(modifiedBlock);
981 throw new RuntimeException(Messages.gettext("parent diagram not found."));
984 // finally update the instance
985 final mxGraphModel model = (mxGraphModel) diag.getModel();
986 final BasicBlock block = (BasicBlock) model.getCell(modifiedBlock.getId());
987 assert block != null;
989 block.updateBlockSettings(modifiedBlock);
990 block.setInterfaceFunctionName(modifiedBlock.getInterfaceFunctionName());
991 block.setSimulationFunctionName(modifiedBlock.getSimulationFunctionName());
992 block.setSimulationFunctionType(modifiedBlock.getSimulationFunctionType());
993 if (block instanceof SuperBlock) {
994 ((SuperBlock) block).setChild(null);
997 block.setStyle(block.getStyle() + ";blockWithLabel");
998 block.setValue(block.getSimulationFunctionName());
999 BlockPositioning.updateBlockView(block);
1003 * This function convert a Xcos diagram to Scilab variable.
1005 * This method invoke Xcos operation on the EDT thread.
1008 * The xcos diagram file
1009 * @return Not used (compatibility)
1011 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1012 public static int xcosDiagramToScilab(final String xcosFile) {
1013 final File file = new File(xcosFile);
1015 if (!file.exists()) {
1020 SwingUtilities.invokeAndWait(new Runnable() {
1023 LOG.finest("xcosDiagramToScilab: entering");
1024 final XcosDiagram diagram = new XcosDiagram();
1026 final XcosFileType filetype = XcosFileType.findFileType(file);
1027 if (filetype != null) {
1029 LOG.finest("xcosDiagramToScilab: initialized");
1030 filetype.load(xcosFile, diagram);
1031 LOG.finest("xcosDiagramToScilab: loaded");
1033 final ScilabDirectHandler handler = ScilabDirectHandler.acquire();
1034 if (handler == null) {
1039 handler.writeDiagram(diagram);
1043 } catch (Exception e) {
1044 throw new RuntimeException(e);
1047 LOG.finest("xcosDiagramToScilab: exiting");
1050 } catch (final InterruptedException e) {
1051 throw new RuntimeException(e);
1052 } catch (final InvocationTargetException e) {
1053 Throwable throwable = e;
1054 String firstMessage = null;
1055 while (throwable != null) {
1056 firstMessage = throwable.getLocalizedMessage();
1057 throwable = throwable.getCause();
1060 throw new RuntimeException(firstMessage, e);
1067 * Add a menu into xcos
1072 * the callback (as a Scilab executable String)
1074 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1075 public static void addToolsMenu(final String label, final String command) {
1076 final ExternalAction action = new ExternalAction(null, command);
1077 action.putValue(Action.NAME, label);
1078 final Xcos instance = Xcos.getInstance();
1081 * Store for future tabs
1083 instance.externalActions.add(action);
1086 * Update opened tabs
1088 for (final XcosDiagram d : instance.openedDiagrams()) {
1089 final String uuid = d.getGraphTab();
1090 final SwingScilabTab tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1093 final SwingScilabMenuBar bar = ((SwingScilabMenuBar) tab.getMenuBar().getAsSimpleMenuBar());
1095 final Component[] comps = bar.getComponents();
1096 for (Component component : comps) {
1097 if (component instanceof SwingScilabMenu) {
1098 final SwingScilabMenu menu = (SwingScilabMenu) component;
1100 if (menu.getText() == XcosMessages.TOOLS) {
1101 menu.add(new ExternalAction(action, d));
1106 // Also update the parent window toolbar
1107 BarUpdater.updateBars(tab.getParentWindowId(), tab.getMenuBar(), tab.getToolBar(), tab.getInfoBar(), tab.getName(), tab.getWindowIcon());
1113 * Open a diagram by uid.
1115 * This method invoke Xcos operation on the EDT thread.
1118 * UID path to a block.
1120 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1122 public static void xcosDiagramOpen(final String[] uid) {
1123 throw new UnsupportedOperationException();
1127 * Close a diagram by uid.
1129 * This method invoke Xcos operation on the EDT thread.
1132 * The diagram id path
1134 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1136 public static void xcosDiagramClose(final String[] uid) {
1137 throw new UnsupportedOperationException();
1141 * Look for the parent diagram of the cell in the diagram hierarchy.
1144 * the cell to search for
1145 * @return the associated diagram
1147 public static XcosDiagram findParent(Object cell) {
1148 final Xcos instance = getInstance();
1150 instance.onDiagramIteration = true;
1152 for (Collection<XcosDiagram> diags : instance.diagrams.values()) {
1153 for (XcosDiagram diag : diags) {
1154 final mxGraphModel model = (mxGraphModel) diag.getModel();
1156 // use the O(1) lookup
1157 if (cell instanceof mxICell && model.getCell(((mxICell) cell).getId()) != null) {
1158 if (cell instanceof BasicBlock) {
1159 ((BasicBlock) cell).setParentDiagram(diag);
1166 instance.onDiagramIteration = false;
1173 * @see org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory
1175 public static class XcosTabFactory extends AbstractScilabTabFactory {
1180 private DocumentType cachedDocumentType;
1183 * Default constructor
1185 public XcosTabFactory() {
1189 private XcosTabFactory(boolean instanciateXcos) {
1190 if (instanciateXcos) {
1196 * Create/restore a tab for a given uuid
1200 * @return the tab instance
1203 public synchronized SwingScilabTab getTab(final String uuid) {
1208 SwingScilabTab tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1210 // Palette manager restore
1212 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1213 PaletteManagerView.restore(null, false);
1214 tab = PaletteManagerView.get();
1218 // diagram (tab or viewport) restore
1221 if (cachedDocumentType == null) {
1225 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1226 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1228 final XcosDiagram graph = getDiagram(isTab, isViewport);
1229 if (graph != null && isTab) {
1230 XcosTab.restore(graph, false);
1231 graph.fireEvent(new mxEventObject(mxEvent.ROOT));
1232 tab = XcosTab.get(graph);
1233 } else if (graph != null && isViewport) {
1234 ViewPortTab.restore(graph, false);
1235 tab = ViewPortTab.get(graph);
1237 ClosingOperationsManager.addDependency(XcosTab.get(graph), tab);
1238 WindowsConfigurationManager.makeDependency(graph.getGraphTab(), tab.getPersistentId());
1244 WindowsConfigurationManager.restorationFinished(tab);
1245 ScilabTabFactory.getInstance().addToCache(tab);
1250 private XcosDiagram getDiagram(boolean isTab, boolean isViewport) {
1251 XcosDiagram graph = null;
1253 // load a new diagram
1254 graph = getInstance().configuration.loadDiagram(cachedDocumentType);
1255 } else if (isViewport) {
1256 // get the cached diagram
1257 final File f = getInstance().configuration.getFile(cachedDocumentType);
1258 final Collection<XcosDiagram> diags = getInstance().diagrams.get(f);
1260 for (XcosDiagram d : diags) {
1261 final String id = d.getGraphTab();
1262 if (id != null && id.equals(cachedDocumentType.getUuid())) {
1273 public synchronized boolean isAValidUUID(String uuid) {
1274 // check the Palette manager view (static uuid)
1275 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1280 * Cache and check against cache to ease next getTab(uuid) call
1283 return cachedDocumentType != null;
1287 * Cache the {@link DocumentType} for the specific uuid
1292 private void cache(String uuid) {
1294 * Handle a non null cache
1296 if (cachedDocumentType != null) {
1297 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1298 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1300 if (isTab || isViewport) {
1303 cachedDocumentType = null;
1308 * Invalid cache, look for the right one
1310 final ConfigurationManager config = getInstance().configuration;
1311 final List<DocumentType> docs = config.getSettings().getTab();
1312 for (DocumentType d : docs) {
1313 final boolean isTab = uuid.equals(d.getUuid());
1314 final boolean isViewport = uuid.equals(d.getViewport());
1316 if (isTab || isViewport) {
1317 cachedDocumentType = d;
1324 public String getPackage() {
1329 public String getClassName() {
1330 return XcosTabFactory.class.getName();
1334 public String getApplication() {
1339 // CSON: ClassDataAbstractionCoupling
1340 // CSON: ClassFanOutComplexity