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 * Copyright (C) 2011-2017 - Scilab Enterprises - Clement DAVID
7 * Copyright (C) 2012 - 2016 - Scilab Enterprises
9 * This file is hereby licensed under the terms of the GNU GPL v2.0,
10 * pursuant to article 5.3.4 of the CeCILL v.2.1.
11 * This file was originally licensed under the terms of the CeCILL v2.1,
12 * and continues to be available under such terms.
13 * For more information, see the COPYING file which you should have received
14 * along with this program.
18 package org.scilab.modules.xcos;
20 import java.awt.Component;
22 import java.io.IOException;
23 import java.lang.reflect.InvocationTargetException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
32 import java.util.logging.LogManager;
33 import java.util.logging.Logger;
35 import javax.swing.Action;
36 import javax.swing.ImageIcon;
37 import javax.swing.SwingUtilities;
39 import org.scilab.modules.action_binding.InterpreterManagement;
40 import org.scilab.modules.commons.gui.FindIconHelper;
41 import org.scilab.modules.commons.xml.XConfiguration;
42 import org.scilab.modules.core.Scilab;
43 import org.scilab.modules.graph.actions.base.GraphActionManager;
44 import org.scilab.modules.graph.utils.ScilabExported;
45 import org.scilab.modules.gui.bridge.menu.SwingScilabMenu;
46 import org.scilab.modules.gui.bridge.menubar.SwingScilabMenuBar;
47 import org.scilab.modules.gui.bridge.tab.SwingScilabDockablePanel;
48 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
49 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
50 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
51 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
52 import org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory;
53 import org.scilab.modules.gui.tabfactory.ScilabTabFactory;
54 import org.scilab.modules.gui.utils.BarUpdater;
55 import org.scilab.modules.gui.utils.ClosingOperationsManager;
56 import org.scilab.modules.gui.utils.WindowsConfigurationManager;
57 import org.scilab.modules.localization.Messages;
58 import org.scilab.modules.xcos.actions.ExternalAction;
59 import org.scilab.modules.xcos.actions.StopAction;
60 import org.scilab.modules.xcos.configuration.ConfigurationManager;
61 import org.scilab.modules.xcos.configuration.model.DocumentType;
62 import org.scilab.modules.xcos.graph.DiagramComparator;
63 import org.scilab.modules.xcos.graph.XcosDiagram;
64 import org.scilab.modules.xcos.io.XcosFileType;
65 import org.scilab.modules.xcos.palette.PaletteManager;
66 import org.scilab.modules.xcos.palette.view.PaletteManagerView;
67 import org.scilab.modules.xcos.preferences.XcosConfiguration;
68 import org.scilab.modules.xcos.utils.FileUtils;
69 import org.scilab.modules.xcos.utils.XcosMessages;
71 import com.mxgraph.model.mxCell;
72 import com.mxgraph.model.mxGraphModel;
73 import com.mxgraph.model.mxICell;
74 import com.mxgraph.util.mxEvent;
75 import com.mxgraph.util.mxEventObject;
76 import com.mxgraph.view.mxStylesheet;
77 import javax.swing.Timer;
78 import org.scilab.modules.commons.ScilabCommons;
79 import org.scilab.modules.xcos.graph.model.ScicosObjectOwner;
80 import org.scilab.modules.xcos.graph.model.XcosGraphModel;
83 * Xcos entry point class
85 // CSOFF: ClassFanOutComplexity
86 // CSOFF: ClassDataAbstractionCoupling
87 public final class Xcos {
89 * The current Xcos version
91 public static final String VERSION = "2.0";
93 * The current Xcos tradename
95 public static final String TRADENAME = Xcos.class.getSimpleName();
96 public static final ImageIcon ICON = new ImageIcon(FindIconHelper.findIcon("utilities-system-monitor", "256x256"));
98 private static final String LOAD_XCOS_LIBS_LOAD_SCICOS = "prot=funcprot(); funcprot(0); loadXcosLibs(); loadScicos(); funcprot(prot); clear prot";
101 * Dependencies version
103 private static final List<String> MXGRAPH_VERSIONS = null;
104 private static final List<String> BATIK_VERSIONS = Arrays.asList("1.7", "1.8pre", "1.8");
106 private static final String UNABLE_TO_LOAD_JGRAPHX = Messages.gettext("Unable to load the jgraphx library.\nExpecting version %s ; Getting version %s .");
107 private static final String UNABLE_TO_LOAD_BATIK = Messages.gettext("Unable to load the Batik library. \nExpecting version %s ; Getting version %s .");
109 private static final String CALLED_OUTSIDE_THE_EDT_THREAD = "Called outside the EDT thread.";
110 private static final Logger LOG = Logger.getLogger(Xcos.class.getName());
112 /** common shared instance */
113 private static volatile Xcos sharedInstance;
116 Scilab.registerInitialHook(() -> {
117 // wait the Scilab startup termination
118 final Timer t = new Timer(500, null);
119 t.addActionListener((e) -> {
120 if (ScilabCommons.getStartProcessing() == 1)
124 /* load scicos libraries (macros) */
125 InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
130 XConfiguration.addXConfigurationListener(new XcosConfiguration());
136 private final Map<ScicosObjectOwner, List<XcosDiagram>> diagrams;
137 private XcosView view;
138 private BrowserView browser;
139 private boolean onDiagramIteration = false;
140 private String lastError = null;
145 private final PaletteManager palette;
146 private final ConfigurationManager configuration;
147 private final mxStylesheet styleSheet;
148 private final List<ExternalAction> externalActions;
150 private final XcosTabFactory factory;
153 * Construct an Xcos instance.
155 * There must be only one Xcos instance per Scilab application
157 private Xcos(final XcosTabFactory factory) {
159 * Read the configuration to support dynamic (before Xcos launch) settings.
162 LogManager.getLogManager().readConfiguration();
163 } catch (final SecurityException | IOException e) {
164 LOG.severe(e.toString());
167 /* Check the dependencies at startup time */
173 diagrams = new HashMap<>();
175 view = new XcosView();
176 // allocate and install the browser view on demand to avoid any cost
180 * get the handlers instance
182 palette = PaletteManager.getInstance();
183 configuration = ConfigurationManager.getInstance();
184 styleSheet = new mxStylesheet();
185 externalActions = new ArrayList<>();
188 FileUtils.decodeStyle(styleSheet);
189 } catch (final IOException e) {
190 LOG.severe(e.toString());
194 * Register as an AbstractScilabTabFactory
196 if (factory == null) {
197 this.factory = new XcosTabFactory(false);
199 this.factory = factory;
201 ScilabTabFactory.getInstance().addTabFactory(this.factory);
206 protected void finalize() throws Throwable {
207 if (browser != null) {
208 JavaController.unregister_view(browser);
211 JavaController.unregister_view(view);
217 * Check the dependencies and the version dependencies.
219 * This method use runtime class loading to handle ClassNotFoundException.
221 * This method catch any exception and rethrow it with a well defined message. Thus it doesn't pass the IllegalCatch metrics.
223 // CSOFF: IllegalCatch
224 // CSOFF: MagicNumber
225 private void checkDependencies() {
226 final ClassLoader loader = ClassLoader.getSystemClassLoader();
229 String mxGraphVersion = "";
231 final Class<?> klass = loader.loadClass("com.mxgraph.view.mxGraph");
232 mxGraphVersion = (String) klass.getDeclaredField("VERSION").get(null);
234 if (MXGRAPH_VERSIONS != null && !MXGRAPH_VERSIONS.contains(mxGraphVersion)) {
235 throw new Exception();
237 } catch (final Throwable e) {
238 throw new RuntimeException(String.format(UNABLE_TO_LOAD_JGRAPHX, MXGRAPH_VERSIONS.get(0), mxGraphVersion), e);
242 String batikVersion = null;
244 final Class<?> klass = loader.loadClass("org.apache.batik.Version");
245 batikVersion = klass.getPackage().getImplementationVersion().split("\\+")[0];
247 if (!BATIK_VERSIONS.contains(batikVersion)) {
248 throw new Exception();
251 } catch (final Throwable e) {
252 throw new RuntimeException(String.format(UNABLE_TO_LOAD_BATIK, BATIK_VERSIONS.get(0), batikVersion), e);
257 // CSON: IllegalCatch
260 * @return the per Scilab application, Xcos instance
262 public static synchronized Xcos getInstance() {
263 return getInstance(null);
268 * the tab factory instance or null on creation
269 * @return the per Scilab application, Xcos instance
271 private static synchronized Xcos getInstance(final XcosTabFactory factory) {
272 if (sharedInstance == null) {
274 if (!SwingUtilities.isEventDispatchThread()) {
275 SwingUtilities.invokeAndWait(() -> {
276 sharedInstance = new Xcos(factory);
279 sharedInstance = new Xcos(factory);
281 } catch (InvocationTargetException e) {
283 } catch (InterruptedException e) {
287 LOG.finest("Session started");
290 return sharedInstance;
296 public void quit(boolean force) {
297 if (sharedInstance == null) {
301 // TODO : perform something ?
305 * Clear the shared instance.
307 private static synchronized void clearInstance() {
308 sharedInstance = null;
309 LOG.finest("Session ended");
313 * All Opened diagrams
315 * @return the opened diagrams list
317 public List<XcosDiagram> openedDiagrams() {
318 ArrayList<XcosDiagram> opened = new ArrayList<>();
319 diagrams.values().stream().forEach(l -> opened.addAll(l));
328 * @return the opened diagrams list
330 public List<XcosDiagram> openedDiagrams(ScicosObjectOwner root) {
331 return diagrams.getOrDefault(root, Collections.emptyList());
334 public ScicosObjectOwner openedDiagram(File f) {
335 ScicosObjectOwner opened = null;
340 for (ScicosObjectOwner root : diagrams.keySet()) {
341 List<XcosDiagram> diags = diagrams.getOrDefault(root, Collections.emptyList());
343 if (!diags.isEmpty() && f.equals(diags.get(0).getSavedFile())) {
353 * Check if the in memory file representation is modified
357 * @return is modified
359 public boolean isModified(ScicosObjectOwner root) {
360 for (XcosDiagram d : diagrams.get(root)) {
361 if (d.isModified()) {
370 * Set the full diagram as modified
371 * @param root the root diagram
372 * @param modified the modified status
374 public void setModified(ScicosObjectOwner root, boolean modified) {
375 for (XcosDiagram d : diagrams.get(root)) {
376 d.setModified(modified);
381 * Popup a dialog to ask for a file creation
385 * @return true if creation is has been performed
387 public boolean askForFileCreation(final XcosDiagram diag, final File f) {
390 answer = ScilabModalDialog.show(diag.getAsComponent(), new String[] { String.format(XcosMessages.FILE_DOESNT_EXIST, f.getCanonicalFile()) },
391 XcosMessages.XCOS, IconType.QUESTION_ICON, ButtonType.YES_NO);
392 } catch (final IOException e) {
393 LOG.severe(e.toString());
394 answer = AnswerOption.YES_OPTION;
397 if (answer == AnswerOption.YES_OPTION) {
398 return diag.saveDiagramAs(f);
405 * @return the global shared styleSheet
407 public mxStylesheet getStyleSheet() {
412 * Open a file from it's filename.
414 * This method must be called on the EDT thread. For other use, please use the {@link #xcos(String, String)} method.
417 * the file to open. If null an empty diagram is created.
419 * the MVC ID to track. If 0 no association is performed.
421 public void open(final String file, final long diagramId) {
422 if (!SwingUtilities.isEventDispatchThread()) {
423 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
427 * If it is the first window opened, then open the palette first.
429 boolean openThePalette = openedDiagrams().isEmpty();
431 JavaController controller = new JavaController();
432 XcosDiagram diag = null;
440 if (f != null && f.exists()) {
441 configuration.addToRecentFiles(f);
445 * looking for an already opened diagram
447 ScicosObjectOwner root = openedDiagram(f);
449 diag = diagrams.get(root).iterator().next();
451 // if unsaved and empty, reuse it. Allocate otherwise.
452 if (f == null && diag != null && diag.getModel().getChildCount(diag.getDefaultParent()) > 0) {
456 // looking for an empty, unsaved diagram to use if opening a new file
457 // if not found an already open instance of the file
459 // traverse through the key set of all the opened diagrams
460 for (Map.Entry<ScicosObjectOwner, List<XcosDiagram>> entry : diagrams.entrySet()) {
461 List<XcosDiagram> diagramsWithKey = entry.getValue();
462 XcosDiagram diagramWithKey = diagramsWithKey.get(0); // get the diagram that maps to that key
463 int childCount = diagramWithKey.countChildren(); //count the number of children in the diagram
464 // if empty, unsaved and unused
465 if (childCount == 0 && diagramWithKey.getSavedFile() == null && !diagramWithKey.isModified()) {
466 // use that open diagram
467 diag = diagramWithKey;
468 diag.transformAndLoadFile(controller, file);
472 // if reuse then request focus
474 XcosTab tab = XcosTab.get(diag);
481 final long currentId;
482 if (diagramId != 0) {
483 currentId = diagramId;
485 currentId = controller.createObject(Kind.DIAGRAM);
489 // loading disabled, unlock
490 synchronized (this) {
495 // loading enable, unlock will be performed later, on another thread
498 * Allocate and setup a new diagram
500 diag = new XcosDiagram(controller, currentId, controller.getKind(currentId), "");
501 diag.installListeners();
503 root = findRoot(controller, diag);
504 addDiagram(root, diag);
507 * Ask for file creation
509 if (f != null && !f.exists()) {
510 if (!askForFileCreation(diag, f)) {
511 // loading disabled, unlock
512 synchronized (this) {
517 // return now, to avoid tab creation
518 diagrams.remove(root);
525 * Create a visible window before loading
527 if (XcosTab.get(diag) == null) {
528 XcosTab.restore(diag);
531 if (openThePalette) {
532 PaletteManager.setVisible(true);
538 diag.transformAndLoadFile(controller, file);
543 * Log a loading error
546 * the error description
548 public void setLastError(String error) {
549 this.lastError = error;
553 * @return the Xcos view
555 public XcosView getXcosView() {
560 * @return the Browser view
562 public BrowserView getBrowser() {
563 if (browser == null) {
564 browser = new BrowserView();
565 JavaController.register_view(BrowserView.class.getSimpleName(), browser);
571 * Clear the browser state and unregister the current view.
573 public void clearBrowser() {
574 if (browser != null) {
575 JavaController.unregister_view(browser);
581 * Get an unmodifiable view of the diagrams for an UID
585 * @return the diagram collection
587 public Collection<XcosDiagram> getDiagrams(final ScicosObjectOwner root) {
588 final Collection<XcosDiagram> diags = diagrams.get(root);
592 return Collections.unmodifiableCollection(diags);
596 * Add a diagram to the diagram list for a file. Be sure to set the right opened status on the diagram before calling this method.
603 public void addDiagram(final ScicosObjectOwner root, final XcosDiagram diag) {
604 if (onDiagramIteration) {
605 throw new RuntimeException();
608 throw new IllegalArgumentException();
612 * Create the collection if it does not exist
614 List<XcosDiagram> diags = diagrams.get(root);
616 diags = createDiagramCollection();
617 diagrams.put(root, diags);
620 // insert the diagram
625 * Add a diagram to the opened list
627 * This method manage both super-block and root diagrams.
628 * @param diag the diagram to add
630 public void addDiagram(final XcosDiagram diag) {
631 ScicosObjectOwner root = findRoot(diag);
632 addDiagram(root, diag);
636 * Create a diagram collections (sorted List)
638 * @return the diagram collection
640 @SuppressWarnings("serial")
641 public List<XcosDiagram> createDiagramCollection() {
642 return new ArrayList<XcosDiagram>() {
644 public boolean add(XcosDiagram element) {
645 final boolean status = super.add(element);
646 DiagramComparator.sort(this);
651 public boolean addAll(Collection<? extends XcosDiagram> c) {
652 final boolean status = super.addAll(c);
653 DiagramComparator.sort(this);
660 * Try to close the graph (popup save dialog)
664 * @return if we can (or not) close the graph
666 public boolean canClose(final XcosDiagram graph) {
667 boolean canClose = false;
669 ScicosObjectOwner root = findRoot(graph);
671 final boolean wasLastOpened = openedDiagrams(root).size() <= 1;
672 final boolean isModified = isModified(root);
673 if (!(wasLastOpened && isModified)) {
678 final AnswerOption ans = ScilabModalDialog.show(XcosTab.get(graph), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS, IconType.QUESTION_ICON,
679 ButtonType.YES_NO_CANCEL);
683 canClose = diagrams.get(root).iterator().next().saveDiagram();
686 canClose = true; // can close
689 canClose = false; // operation canceled
695 * Update configuration before the destroy call to validate the uuid
698 configuration.addToRecentTabs(graph);
699 configuration.saveConfig();
707 * This method must be called on the EDT thread.
710 * the diagram to close
712 public void destroy(XcosDiagram graph) {
713 ScicosObjectOwner root = findRoot(graph);
715 final boolean wasLastOpenedForFile = openedDiagrams(root).size() <= 1;
716 if (wasLastOpenedForFile) {
717 diagrams.remove(root);
719 diagrams.get(root).remove(graph);
722 if (openedDiagrams().size() <= 0) {
723 JavaController.end_simulation();
729 * the graph to handle
731 * the diagram to check
732 * @return diagram name for the "Are your sure ?" dialog
734 public String askForClosing(final XcosDiagram graph, final List<SwingScilabDockablePanel> list) {
737 if (wasLastOpened(list)) {
747 * Does Xcos will close or not ?
750 * the list to be closed
751 * @return true if all files will be close on tabs close.
753 public boolean wasLastOpened(final List<SwingScilabDockablePanel> list) {
754 final HashSet<String> opened = new HashSet<String>();
755 for (XcosDiagram diag : openedDiagrams()) {
756 opened.add(diag.getGraphTab());
759 final HashSet<String> tabs = new HashSet<String>();
760 for (SwingScilabDockablePanel tab : list) {
762 tabs.add(tab.getPersistentId());
766 opened.removeAll(tabs);
768 return opened.isEmpty();
772 * @return the external action list
774 public List<ExternalAction> getExternalActions() {
775 return externalActions;
779 * Close the current xcos session.
781 * This method must be called on the EDT thread. For other use, please use the {@link #closeXcosFromScilab()} method.
783 public static synchronized void closeSession(final boolean ask) {
784 if (!SwingUtilities.isEventDispatchThread()) {
785 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
788 /* Doesn't instantiate xcos on close operation */
789 if (sharedInstance == null) {
794 * Try to close all opened files
796 final Xcos instance = sharedInstance;
799 final List<SwingScilabDockablePanel> tabs = new ArrayList<SwingScilabDockablePanel>();
800 for (final Collection<XcosDiagram> diags : instance.diagrams.values()) {
801 for (final XcosDiagram diag : diags) {
802 final SwingScilabDockablePanel tab = XcosTab.get(diag);
810 final boolean status = ClosingOperationsManager.startClosingOperation(tabs, ask, ask);
814 /* reset the shared instance state */
815 instance.diagrams.clear();
817 /* terminate any remaining simulation */
818 JavaController.end_simulation();
820 /* Saving modified data */
821 instance.palette.saveConfig();
822 instance.configuration.saveConfig();
827 * Scilab exported methods.
829 * All the following methods must use SwingUtilities method to assert that the operations will be called on the EDT thread.
831 * @see modules/xcos/src/jni/Xcos.giws.xml
833 * @see sci_gateway/xcos_gateway.xml
835 * @see modules/xcos/sci_gateway/cpp/sci_*.cpp
841 * This method invoke Xcos operation on the EDT thread.
844 * The filename (can be null)
846 * The Xcos DIAGRAM model ID (can be 0)
848 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
849 public static void xcos(final String file, final long diagramId) {
850 final Xcos instance = getInstance();
851 instance.lastError = null;
853 /* load scicos libraries (macros) */
854 InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
856 synchronized (instance) {
860 SwingUtilities.invokeLater(new Runnable() {
864 instance.open(file, diagramId);
868 if (instance.lastError != null && !instance.lastError.isEmpty()) {
869 throw new RuntimeException(instance.lastError);
874 * Load or Save an xcos diagram without using Scilab at all.
877 * This support a reduced number of format and should be mainly used to test
882 * the diagram to load into
884 * flag used to indicate an export (true == export ; false == import)
888 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
889 public static void xcosDiagramToScilab(String file, long diagramId, boolean export) throws Exception {
890 XcosFileType filetype = XcosFileType.findFileType(file);
891 if (filetype == null) {
892 throw new IllegalArgumentException("not handled filetype");
895 if (XcosFileType.getAvailableSaveFormats().contains(filetype)) {
897 filetype.save(file, new XcosDiagram(new JavaController(), diagramId, Kind.DIAGRAM, ""));
899 filetype.load(file, new XcosDiagram(new JavaController(), diagramId, Kind.DIAGRAM, ""));
902 throw new IllegalArgumentException("not handled filetype");
907 * Close the current xcos session from any thread.
909 * This method invoke Xcos operation on the EDT thread. Please prefer using {@link #closeSession()} when the caller is on the EDT thread.
911 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
912 public static void closeXcosFromScilab() {
914 SwingUtilities.invokeAndWait(new Runnable() {
921 } catch (final InterruptedException e) {
923 } catch (final InvocationTargetException e) {
926 Throwable throwable = e;
927 String firstMessage = null;
928 while (throwable != null) {
929 firstMessage = throwable.getLocalizedMessage();
930 throwable = throwable.getCause();
933 throw new RuntimeException(firstMessage, e);
938 * Look in each diagram to find the block corresponding to the given uid and display a warning message.
940 * This method invoke Xcos operation on the EDT thread.
945 * The message to display.
947 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
948 public static void warnCellByUID(final String[] uids, final String message) {
950 SwingUtilities.invokeAndWait(new Runnable() {
953 getInstance().warnCell(uids, message);
956 } catch (final InterruptedException e) {
957 LOG.severe(e.toString());
958 } catch (final InvocationTargetException e) {
959 Throwable throwable = e;
960 String firstMessage = null;
961 while (throwable != null) {
962 firstMessage = throwable.getLocalizedMessage();
963 throwable = throwable.getCause();
966 throw new RuntimeException(firstMessage, e);
970 private void warnCell(final String[] uids, final String message) {
972 final mxCell[] cells = new mxCell[uids.length];
973 final XcosDiagram[] diags = new XcosDiagram[uids.length];
975 lookupForCells(uids, cells, diags);
976 for (int i = cells.length - 1; i >= 0; --i) {
977 mxCell cell = cells[i];
979 // perform the action on the last visible block
981 final XcosDiagram parent = diags[i];
982 parent.warnCellByUID(cell.getId(), message);
984 // Focus on an existing diagram
985 SwingUtilities.invokeLater(() -> {
986 XcosTab.get(parent).setCurrent();
995 public void lookupForCells(final String[] uid, final mxCell[] cells, final XcosDiagram[] diags) {
996 final List<XcosDiagram> all = openedDiagrams();
997 for (int i = 0; i < uid.length; i++) {
998 final String id = uid[i];
999 diags[i] = all.stream().filter(d -> ((XcosGraphModel) d.getModel()).getCell(id) != null)
1000 .findFirst().orElse(null);
1001 if (diags[i] != null) {
1002 cells[i] = (mxCell) ((XcosGraphModel) diags[i].getModel()).getCell(id);
1008 * Add a menu into xcos
1013 * the callback (as a Scilab executable String)
1015 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1016 public static void addToolsMenu(final String label, final String command) {
1017 final ExternalAction action = new ExternalAction(null, command);
1018 action.putValue(Action.NAME, label);
1019 final Xcos instance = Xcos.getInstance();
1022 * Store for future tabs
1024 instance.externalActions.add(action);
1027 * Update opened tabs
1029 for (final XcosDiagram d : instance.openedDiagrams()) {
1030 final String uuid = d.getGraphTab();
1031 final SwingScilabDockablePanel tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1034 final SwingScilabMenuBar bar = ((SwingScilabMenuBar) tab.getMenuBar().getAsSimpleMenuBar());
1036 final Component[] comps = bar.getComponents();
1037 for (Component component : comps) {
1038 if (component instanceof SwingScilabMenu) {
1039 final SwingScilabMenu menu = (SwingScilabMenu) component;
1041 if (menu.getText() == XcosMessages.TOOLS) {
1042 menu.add(new ExternalAction(action, d));
1047 // Also update the parent window toolbar
1048 BarUpdater.updateBars(tab.getParentWindowId(), tab.getMenuBar(), tab.getToolBar(), tab.getInfoBar(), tab.getName(), tab.getWindowIcon());
1054 * Inform Xcos the simulator has just started
1057 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1058 public static void xcosSimulationStarted() {
1059 SwingUtilities.invokeLater(new Runnable() {
1062 GraphActionManager.setEnable(StopAction.class, true);
1068 * Look for the parent diagram of the cell in the diagram hierarchy.
1071 * the cell to search for
1072 * @return the associated diagram
1074 public static XcosDiagram findParent(Object cell) {
1075 final Xcos instance = getInstance();
1077 for (Collection<XcosDiagram> diags : instance.diagrams.values()) {
1078 for (XcosDiagram diag : diags) {
1079 final mxGraphModel model = (mxGraphModel) diag.getModel();
1081 // use the O(1) lookup
1082 if (cell instanceof mxICell && model.getCell(((mxICell) cell).getId()) != null) {
1092 * Look for the root object of the whole graph hierarchy
1093 * @param graph the graph
1094 * @return the root MVC object with Kind.DIAGRAM
1096 public static ScicosObjectOwner findRoot(XcosDiagram graph) {
1097 return findRoot(new JavaController(), graph);
1101 * Look for the root object of the whole graph hierarchy
1102 * @param controller the shared controller
1103 * @param graph the graph
1104 * @return the root MVC object with Kind.DIAGRAM
1106 public static ScicosObjectOwner findRoot(JavaController controller, XcosDiagram graph) {
1107 ScicosObjectOwner root;
1108 if (graph.getKind() == Kind.DIAGRAM) {
1109 root = new ScicosObjectOwner(controller, graph.getUID(), graph.getKind());
1111 long[] rootDiagram = new long[1];
1112 controller.getObjectProperty(graph.getUID(), graph.getKind(), ObjectProperties.PARENT_DIAGRAM, rootDiagram);
1113 root = new ScicosObjectOwner(controller, rootDiagram[0], Kind.DIAGRAM);
1121 * @see org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory
1123 public static class XcosTabFactory extends AbstractScilabTabFactory {
1128 private DocumentType cachedDocumentType;
1131 * Default constructor
1133 public XcosTabFactory() {
1137 private XcosTabFactory(boolean instanciateXcos) {
1138 if (instanciateXcos) {
1144 * Create/restore a tab for a given uuid
1148 * @return the tab instance
1151 public synchronized SwingScilabDockablePanel getTab(final String uuid) {
1156 SwingScilabDockablePanel tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1158 // Palette manager restore
1160 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1161 PaletteManagerView.restore(null, false);
1162 tab = PaletteManagerView.get();
1166 // diagram (tab or viewport) restore
1169 if (cachedDocumentType == null) {
1173 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1174 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1176 final XcosDiagram graph = getDiagram(isTab, isViewport);
1177 if (graph != null && isTab) {
1178 XcosTab.restore(graph, false);
1179 graph.fireEvent(new mxEventObject(mxEvent.ROOT));
1180 tab = XcosTab.get(graph);
1181 } else if (graph != null && isViewport) {
1182 ViewPortTab.restore(graph, false);
1183 tab = ViewPortTab.get(graph);
1185 ClosingOperationsManager.addDependency(XcosTab.get(graph), tab);
1186 WindowsConfigurationManager.makeDependency(graph.getGraphTab(), tab.getPersistentId());
1192 WindowsConfigurationManager.restorationFinished(tab);
1193 ScilabTabFactory.getInstance().addToCache(tab);
1198 private XcosDiagram getDiagram(boolean isTab, boolean isViewport) {
1199 final Xcos instance = getInstance();
1200 XcosDiagram graph = null;
1203 // load a new diagram
1204 graph = getInstance().configuration.loadDiagram(cachedDocumentType);
1205 } else if (isViewport) {
1206 // get the cached diagram
1207 final File f = instance.configuration.getFile(cachedDocumentType);
1208 final ScicosObjectOwner root = getInstance().openedDiagram(f);
1210 Collection<XcosDiagram> diags = instance.diagrams.getOrDefault(root, Collections.emptyList());
1211 for (XcosDiagram d : diags) {
1212 final String id = d.getGraphTab();
1213 if (id != null && id.equals(cachedDocumentType.getUuid())) {
1224 public synchronized boolean isAValidUUID(String uuid) {
1225 // check the Palette manager view (static uuid)
1226 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1231 * Cache and check against cache to ease next getTab(uuid) call
1234 return cachedDocumentType != null;
1238 * Cache the {@link DocumentType} for the specific uuid
1243 private void cache(String uuid) {
1245 * Handle a non null cache
1247 if (cachedDocumentType != null) {
1248 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1249 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1251 if (isTab || isViewport) {
1254 cachedDocumentType = null;
1259 * Invalid cache, look for the right one
1261 final ConfigurationManager config = getInstance().configuration;
1262 final List<DocumentType> docs = config.getSettings().getTab();
1263 for (DocumentType d : docs) {
1264 final boolean isTab = uuid.equals(d.getUuid());
1265 final boolean isViewport = uuid.equals(d.getViewport());
1267 if (isTab || isViewport) {
1268 cachedDocumentType = d;
1275 public String getPackage() {
1280 public String getClassName() {
1281 return XcosTabFactory.class.getName();
1285 public String getApplication() {
1290 // CSON: ClassDataAbstractionCoupling
1291 // CSON: ClassFanOutComplexity