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-2015 - 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.SwingWorker;
78 import org.scilab.modules.graph.ScilabCanvas;
79 import org.scilab.modules.xcos.graph.swing.GraphComponent;
82 * Xcos entry point class
84 // CSOFF: ClassFanOutComplexity
85 // CSOFF: ClassDataAbstractionCoupling
86 public final class Xcos {
88 * The current Xcos version
90 public static final String VERSION = "2.0";
92 * The current Xcos tradename
94 public static final String TRADENAME = Xcos.class.getSimpleName();
95 public static final ImageIcon ICON = new ImageIcon(FindIconHelper.findIcon("utilities-system-monitor", "256x256"));
97 private static final String LOAD_XCOS_LIBS_LOAD_SCICOS = "prot=funcprot(); funcprot(0); loadXcosLibs(); loadScicos(); funcprot(prot); clear prot";
100 * Dependencies version
102 private static final List<String> MXGRAPH_VERSIONS = null;
103 private static final List<String> BATIK_VERSIONS = Arrays.asList("1.7", "1.8pre", "1.8");
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.getName());
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());
126 * Load some classes in the background to avoid any lag on the first drag'n drop.
128 * This will setup the whole rendering stack by dummy rendering a block' style
130 (new SwingWorker<Void, Void>() {
132 protected Void doInBackground() throws Exception {
133 Map<String, Object> style = Xcos.getInstance().getStyleSheet().getCellStyle("CLOCK_c", new HashMap<>());
134 ScilabCanvas canvas = new GraphComponent(null).createCanvas();
135 canvas.paintSvgForegroundImage(1, 1, canvas.getImageForStyle(style));
145 private final Map<Long, List<XcosDiagram>> diagrams;
146 private XcosView view;
147 private BrowserView browser;
148 private boolean onDiagramIteration = false;
149 private String lastError = null;
154 private final PaletteManager palette;
155 private final ConfigurationManager configuration;
156 private final mxStylesheet styleSheet;
157 private final List<ExternalAction> externalActions;
159 private final XcosTabFactory factory;
162 * Construct an Xcos instance.
164 * There must be only one Xcos instance per Scilab application
166 private Xcos(final XcosTabFactory factory) {
168 * Read the configuration to support dynamic (before Xcos launch) settings.
171 LogManager.getLogManager().readConfiguration();
172 } catch (final SecurityException | IOException e) {
173 LOG.severe(e.toString());
176 /* Check the dependencies at startup time */
182 diagrams = new HashMap<>();
184 view = new XcosView();
185 JavaController.register_view(Xcos.class.getName(), view);
186 // allocate and install the browser view on demand to avoid any cost
190 * get the handlers instance
192 palette = PaletteManager.getInstance();
193 configuration = ConfigurationManager.getInstance();
194 styleSheet = new mxStylesheet();
195 externalActions = new ArrayList<>();
198 FileUtils.decodeStyle(styleSheet);
199 } catch (final IOException e) {
200 LOG.severe(e.toString());
204 * Register as an AbstractScilabTabFactory
206 if (factory == null) {
207 this.factory = new XcosTabFactory(false);
209 this.factory = factory;
211 ScilabTabFactory.getInstance().addTabFactory(this.factory);
216 protected void finalize() throws Throwable {
217 if (browser != null) {
218 JavaController.unregister_view(browser);
221 JavaController.unregister_view(view);
227 * Check the dependencies and the version dependencies.
229 * This method use runtime class loading to handle ClassNotFoundException.
231 * This method catch any exception and rethrow it with a well defined message. Thus it doesn't pass the IllegalCatch metrics.
233 // CSOFF: IllegalCatch
234 // CSOFF: MagicNumber
235 private void checkDependencies() {
236 final ClassLoader loader = ClassLoader.getSystemClassLoader();
239 String mxGraphVersion = "";
241 final Class<?> klass = loader.loadClass("com.mxgraph.view.mxGraph");
242 mxGraphVersion = (String) klass.getDeclaredField("VERSION").get(null);
244 if (MXGRAPH_VERSIONS != null && !MXGRAPH_VERSIONS.contains(mxGraphVersion)) {
245 throw new Exception();
247 } catch (final Throwable e) {
248 throw new RuntimeException(String.format(UNABLE_TO_LOAD_JGRAPHX, MXGRAPH_VERSIONS.get(0), mxGraphVersion), e);
252 String batikVersion = null;
254 final Class<?> klass = loader.loadClass("org.apache.batik.Version");
255 batikVersion = klass.getPackage().getImplementationVersion().split("\\+")[0];
257 if (!BATIK_VERSIONS.contains(batikVersion)) {
258 throw new Exception();
261 } catch (final Throwable e) {
262 throw new RuntimeException(String.format(UNABLE_TO_LOAD_BATIK, BATIK_VERSIONS.get(0), batikVersion), e);
267 // CSON: IllegalCatch
270 * @return the per Scilab application, Xcos instance
272 public static synchronized Xcos getInstance() {
273 return getInstance(null);
278 * the tab factory instance or null on creation
279 * @return the per Scilab application, Xcos instance
281 private static synchronized Xcos getInstance(final XcosTabFactory factory) {
282 if (sharedInstance == null) {
284 if (!SwingUtilities.isEventDispatchThread()) {
285 SwingUtilities.invokeAndWait(() -> {
286 sharedInstance = new Xcos(factory);
289 sharedInstance = new Xcos(factory);
291 } catch (InvocationTargetException e) {
293 } catch (InterruptedException e) {
297 LOG.finest("Session started");
300 return sharedInstance;
306 public void quit(boolean force) {
307 if (sharedInstance == null) {
311 // TODO : perform something ?
315 * Clear the shared instance.
317 private static synchronized void clearInstance() {
318 sharedInstance = null;
319 LOG.finest("Session ended");
323 * All Opened diagrams
325 * @return the opened diagrams list
327 public List<XcosDiagram> openedDiagrams() {
328 final List<XcosDiagram> opened = new ArrayList<XcosDiagram>();
329 for (Long l : diagrams.keySet()) {
330 opened.addAll(openedDiagrams(l));
340 * the root diagram uid
341 * @return the opened diagrams list
343 public List<XcosDiagram> openedDiagrams(Long l) {
344 final List<XcosDiagram> opened = new ArrayList<>();
345 for (XcosDiagram d : diagrams.get(l)) {
354 public Long openedDiagramUID(File f) {
360 for (Long diagUID : diagrams.keySet()) {
361 List<XcosDiagram> diags = diagrams.getOrDefault(diagUID, Collections.emptyList());
363 if (!diags.isEmpty() && f.equals(diags.get(0).getSavedFile())) {
373 * Check if the in memory file representation is modified
376 * the root diagram UID
377 * @return is modified
379 public boolean isModified(Long l) {
380 for (XcosDiagram d : diagrams.get(l)) {
381 if (d.isModified()) {
390 * Popup a dialog to ask for a file creation
394 * @return true if creation is has been performed
396 public boolean askForFileCreation(final XcosDiagram diag, final File f) {
399 answer = ScilabModalDialog.show(diag.getAsComponent(), new String[] { String.format(XcosMessages.FILE_DOESNT_EXIST, f.getCanonicalFile()) },
400 XcosMessages.XCOS, IconType.QUESTION_ICON, ButtonType.YES_NO);
401 } catch (final IOException e) {
402 LOG.severe(e.toString());
403 answer = AnswerOption.YES_OPTION;
406 if (answer == AnswerOption.YES_OPTION) {
407 return diag.saveDiagramAs(f);
414 * @return the global shared styleSheet
416 public mxStylesheet getStyleSheet() {
421 * Open a file from it's filename.
423 * This method must be called on the EDT thread. For other use, please use the {@link #xcos(String, String)} method.
426 * the file to open. If null an empty diagram is created.
428 * the MVC ID to track. If 0 no association is performed.
430 public void open(final String file, final long diagramId) {
431 if (!SwingUtilities.isEventDispatchThread()) {
432 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
436 * If it is the first window opened, then open the palette first.
438 if (openedDiagrams().isEmpty()) {
439 PaletteManager.setVisible(true);
442 JavaController controller = new JavaController();
443 XcosDiagram diag = null;
451 if (f != null && f.exists()) {
452 configuration.addToRecentFiles(f);
456 * looking for an already opened diagram
458 final Long rootUID = openedDiagramUID(f);
460 diag = diagrams.get(rootUID).iterator().next();
462 // if unsaved and empty, reuse it. Allocate otherwise.
463 if (f == null && diag != null && diag.getModel().getChildCount(diag.getDefaultParent()) > 0) {
466 // if reuse then request focus
468 XcosTab tab = XcosTab.get(diag);
475 final long currentId;
476 if (diagramId != 0) {
477 currentId = diagramId;
479 currentId = controller.createObject(Kind.DIAGRAM);
483 // loading disabled, unlock
484 synchronized (this) {
489 // loading enable, unlock will be performed later, on another thread
492 * Allocate and setup a new diagram
494 diag = new XcosDiagram(controller, currentId, Kind.DIAGRAM, "");
495 diag.installListeners();
498 * Ask for file creation
500 if (f != null && !f.exists()) {
501 if (!askForFileCreation(diag, f)) {
502 // loading disabled, unlock
503 synchronized (this) {
508 // return now, to avoid tab creation
509 controller.deleteObject(diag.getUID());
515 * Create a visible window before loading
517 if (XcosTab.get(diag) == null) {
518 XcosTab.restore(diag);
524 diag.transformAndLoadFile(controller, file);
526 addDiagram(diag.getUID(), diag);
531 * Log a loading error
534 * the error description
536 public void setLastError(String error) {
537 this.lastError = error;
541 * @return the Xcos view
543 public XcosView getXcosView() {
548 * @return the Browser view
550 public BrowserView getBrowser() {
551 if (browser == null) {
552 browser = new BrowserView();
553 JavaController.register_view(BrowserView.class.getSimpleName(), browser);
559 * Clear the browser state and unregister the current view.
561 public void clearBrowser() {
562 if (browser != null) {
563 JavaController.unregister_view(browser);
569 * Get an unmodifiable view of the diagrams for an UID
572 * the root diagram UID
573 * @return the diagram collection
575 public Collection<XcosDiagram> getDiagrams(final long l) {
576 final Collection<XcosDiagram> diags = diagrams.get(l);
580 return Collections.unmodifiableCollection(diags);
584 * 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.
587 * the root diagram UID
591 public void addDiagram(final long l, final XcosDiagram diag) {
592 if (onDiagramIteration) {
593 throw new RuntimeException();
596 throw new IllegalArgumentException();
600 * Create the collection if it does not exist
602 List<XcosDiagram> diags = diagrams.get(l);
604 diags = createDiagramCollection();
605 diagrams.put(l, diags);
608 // insert the diagram
613 * Add a diagram to the opened list
615 * This method manage both super-block and root diagrams.
616 * @param diag the diagram to add
618 public void addDiagram(final XcosDiagram diag) {
619 if (diag.getKind() == Kind.DIAGRAM) {
620 addDiagram(diag.getUID(), diag);
622 long[] root = new long[1];
623 new JavaController().getObjectProperty(diag.getUID(), diag.getKind(), ObjectProperties.PARENT_DIAGRAM, root);
625 addDiagram(root[0], diag);
633 * Create a diagram collections (sorted List)
635 * @return the diagram collection
637 @SuppressWarnings("serial")
638 public List<XcosDiagram> createDiagramCollection() {
639 return new ArrayList<XcosDiagram>() {
641 public boolean add(XcosDiagram element) {
642 final boolean status = super.add(element);
643 DiagramComparator.sort(this);
648 public boolean addAll(Collection<? extends XcosDiagram> c) {
649 final boolean status = super.addAll(c);
650 DiagramComparator.sort(this);
657 * Try to close the graph (popup save dialog)
661 * @return if we can (or not) close the graph
663 public boolean canClose(final XcosDiagram graph) {
664 boolean canClose = false;
666 JavaController controller = new JavaController();
667 long[] rootDiagram = new long[1];
668 controller.getObjectProperty(graph.getUID(), graph.getKind(), ObjectProperties.PARENT_DIAGRAM, rootDiagram);
669 if (rootDiagram[0] == 0l) {
670 rootDiagram[0] = graph.getUID();
673 final boolean wasLastOpened = openedDiagrams(rootDiagram[0]).size() <= 1;
674 final boolean isModified = isModified(rootDiagram[0]);
675 if (!(wasLastOpened && isModified)) {
680 final AnswerOption ans = ScilabModalDialog.show(XcosTab.get(graph), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS, IconType.QUESTION_ICON,
681 ButtonType.YES_NO_CANCEL);
685 canClose = diagrams.get(rootDiagram[0]).iterator().next().saveDiagram();
688 canClose = true; // can close
691 canClose = false; // operation canceled
697 * Update configuration before the destroy call to validate the uuid
700 configuration.addToRecentTabs(graph);
701 configuration.saveConfig();
709 * This method must be called on the EDT thread.
712 * the diagram to close
714 public void destroy(XcosDiagram graph) {
715 JavaController controller = new JavaController();
716 long[] rootDiagram = new long[1];
717 controller.getObjectProperty(graph.getUID(), graph.getKind(), ObjectProperties.PARENT_DIAGRAM, rootDiagram);
718 if (rootDiagram[0] == 0l) {
719 rootDiagram[0] = graph.getUID();
722 final boolean wasLastOpenedForFile = openedDiagrams(rootDiagram[0]).size() <= 1;
723 if (wasLastOpenedForFile) {
724 diagrams.remove(rootDiagram[0]);
726 diagrams.get(rootDiagram[0]).remove(graph);
729 if (openedDiagrams().size() <= 0) {
730 JavaController.end_simulation();
736 * the graph to handle
738 * the diagram to check
739 * @return diagram name for the "Are your sure ?" dialog
741 public String askForClosing(final XcosDiagram graph, final List<SwingScilabDockablePanel> list) {
744 if (wasLastOpened(list)) {
754 * Does Xcos will close or not ?
757 * the list to be closed
758 * @return true if all files will be close on tabs close.
760 public boolean wasLastOpened(final List<SwingScilabDockablePanel> list) {
761 final HashSet<String> opened = new HashSet<String>();
762 for (XcosDiagram diag : openedDiagrams()) {
763 opened.add(diag.getGraphTab());
766 final HashSet<String> tabs = new HashSet<String>();
767 for (SwingScilabDockablePanel tab : list) {
769 tabs.add(tab.getPersistentId());
773 opened.removeAll(tabs);
775 return opened.isEmpty();
779 * @return the external action list
781 public List<ExternalAction> getExternalActions() {
782 return externalActions;
786 * Close the current xcos session.
788 * This method must be called on the EDT thread. For other use, please use the {@link #closeXcosFromScilab()} method.
790 public static synchronized void closeSession(final boolean ask) {
791 if (!SwingUtilities.isEventDispatchThread()) {
792 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
795 /* Doesn't instantiate xcos on close operation */
796 if (sharedInstance == null) {
801 * Try to close all opened files
803 final Xcos instance = sharedInstance;
806 final List<SwingScilabDockablePanel> tabs = new ArrayList<SwingScilabDockablePanel>();
807 for (final Collection<XcosDiagram> diags : instance.diagrams.values()) {
808 for (final XcosDiagram diag : diags) {
809 final SwingScilabDockablePanel tab = XcosTab.get(diag);
817 final boolean status = ClosingOperationsManager.startClosingOperation(tabs, ask, ask);
821 /* reset the shared instance state */
822 instance.diagrams.keySet().clear();
824 /* terminate any remaining simulation */
825 JavaController.end_simulation();
827 /* Saving modified data */
828 instance.palette.saveConfig();
829 instance.configuration.saveConfig();
834 * Scilab exported methods.
836 * All the following methods must use SwingUtilities method to assert that the operations will be called on the EDT thread.
838 * @see modules/xcos/src/jni/Xcos.giws.xml
840 * @see sci_gateway/xcos_gateway.xml
842 * @see modules/xcos/sci_gateway/cpp/sci_*.cpp
848 * This method invoke Xcos operation on the EDT thread.
851 * The filename (can be null)
853 * The Xcos DIAGRAM model ID (can be 0)
855 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
856 public static void xcos(final String file, final long diagramId) {
857 final Xcos instance = getInstance();
858 instance.lastError = null;
860 /* load scicos libraries (macros) */
861 InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
863 synchronized (instance) {
867 SwingUtilities.invokeLater(new Runnable() {
871 instance.open(file, diagramId);
875 if (instance.lastError != null && !instance.lastError.isEmpty()) {
876 throw new RuntimeException(instance.lastError);
881 * Load or Save an xcos diagram without using Scilab at all.
884 * This support a reduced number of format and should be mainly used to test
889 * the diagram to load into
891 * flag used to indicate an export (true == export ; false == import)
895 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
896 public static void xcosDiagramToScilab(String file, long diagramId, boolean export) throws Exception {
897 XcosFileType filetype = XcosFileType.findFileType(file);
898 if (filetype == null) {
899 throw new IllegalArgumentException("not handled filetype");
906 filetype.save(file, new XcosDiagram(new JavaController(), diagramId, Kind.DIAGRAM, ""));
908 filetype.load(file, new XcosDiagram(new JavaController(), diagramId, Kind.DIAGRAM, ""));
912 throw new IllegalArgumentException("not handled filetype");
917 * Close the current xcos session from any thread.
919 * This method invoke Xcos operation on the EDT thread. Please prefer using {@link #closeSession()} when the caller is on the EDT thread.
921 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
922 public static void closeXcosFromScilab() {
924 SwingUtilities.invokeAndWait(new Runnable() {
931 } catch (final InterruptedException e) {
933 } catch (final InvocationTargetException e) {
936 Throwable throwable = e;
937 String firstMessage = null;
938 while (throwable != null) {
939 firstMessage = throwable.getLocalizedMessage();
940 throwable = throwable.getCause();
943 throw new RuntimeException(firstMessage, e);
948 * Look in each diagram to find the block corresponding to the given uid and display a warning message.
950 * This method invoke Xcos operation on the EDT thread.
955 * The message to display.
957 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
958 public static void warnCellByUID(final String[] uids, final String message) {
960 SwingUtilities.invokeAndWait(new Runnable() {
963 getInstance().warnCell(uids, message);
966 } catch (final InterruptedException e) {
967 LOG.severe(e.toString());
968 } catch (final InvocationTargetException e) {
969 Throwable throwable = e;
970 String firstMessage = null;
971 while (throwable != null) {
972 firstMessage = throwable.getLocalizedMessage();
973 throwable = throwable.getCause();
976 throw new RuntimeException(firstMessage, e);
980 private void warnCell(final String[] uids, final String message) {
982 final mxCell[] cells = lookupForCells(uids);
983 for (int i = cells.length - 1; i >= 0; --i) {
984 mxCell cell = cells[i];
986 // perform the action on the last visible block
988 final XcosDiagram parent = findParent(cell);
989 parent.warnCellByUID(cell.getId(), message);
991 SwingUtilities.invokeLater(new Runnable() {
995 * Focus on an existing diagram
997 XcosTab.get(parent).setCurrent();
1007 public mxCell[] lookupForCells(final String[] uid) {
1008 mxCell[] found = new mxCell[uid.length];
1009 XcosView view = (XcosView) JavaController.lookup_view(Xcos.class.getName());
1011 final String[] sortedUIDs = Arrays.copyOf(uid, uid.length);
1012 Arrays.sort(sortedUIDs);
1014 view.getVisibleObjects().values().stream()
1015 // look for the visible objects in the UID set
1016 .filter(o -> o instanceof mxCell).map(o -> (mxCell) o).filter(o -> Arrays.binarySearch(sortedUIDs, o.getId()) >= 0)
1018 // push the results to the resulting array
1019 .forEach(o -> found[Arrays.asList(uid).indexOf(o.getId())] = o);
1025 * Add a menu into xcos
1030 * the callback (as a Scilab executable String)
1032 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1033 public static void addToolsMenu(final String label, final String command) {
1034 final ExternalAction action = new ExternalAction(null, command);
1035 action.putValue(Action.NAME, label);
1036 final Xcos instance = Xcos.getInstance();
1039 * Store for future tabs
1041 instance.externalActions.add(action);
1044 * Update opened tabs
1046 for (final XcosDiagram d : instance.openedDiagrams()) {
1047 final String uuid = d.getGraphTab();
1048 final SwingScilabDockablePanel tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1051 final SwingScilabMenuBar bar = ((SwingScilabMenuBar) tab.getMenuBar().getAsSimpleMenuBar());
1053 final Component[] comps = bar.getComponents();
1054 for (Component component : comps) {
1055 if (component instanceof SwingScilabMenu) {
1056 final SwingScilabMenu menu = (SwingScilabMenu) component;
1058 if (menu.getText() == XcosMessages.TOOLS) {
1059 menu.add(new ExternalAction(action, d));
1064 // Also update the parent window toolbar
1065 BarUpdater.updateBars(tab.getParentWindowId(), tab.getMenuBar(), tab.getToolBar(), tab.getInfoBar(), tab.getName(), tab.getWindowIcon());
1071 * Inform Xcos the simulator has just started
1074 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1075 public static void xcosSimulationStarted() {
1076 SwingUtilities.invokeLater(new Runnable() {
1079 GraphActionManager.setEnable(StopAction.class, true);
1085 * Look for the parent diagram of the cell in the diagram hierarchy.
1088 * the cell to search for
1089 * @return the associated diagram
1091 public static XcosDiagram findParent(Object cell) {
1092 final Xcos instance = getInstance();
1094 for (Collection<XcosDiagram> diags : instance.diagrams.values()) {
1095 for (XcosDiagram diag : diags) {
1096 final mxGraphModel model = (mxGraphModel) diag.getModel();
1098 // use the O(1) lookup
1099 if (cell instanceof mxICell && model.getCell(((mxICell) cell).getId()) != null) {
1109 * @see org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory
1111 public static class XcosTabFactory extends AbstractScilabTabFactory {
1116 private DocumentType cachedDocumentType;
1119 * Default constructor
1121 public XcosTabFactory() {
1125 private XcosTabFactory(boolean instanciateXcos) {
1126 if (instanciateXcos) {
1132 * Create/restore a tab for a given uuid
1136 * @return the tab instance
1139 public synchronized SwingScilabDockablePanel getTab(final String uuid) {
1144 SwingScilabDockablePanel tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1146 // Palette manager restore
1148 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1149 PaletteManagerView.restore(null, false);
1150 tab = PaletteManagerView.get();
1154 // diagram (tab or viewport) restore
1157 if (cachedDocumentType == null) {
1161 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1162 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1164 final XcosDiagram graph = getDiagram(isTab, isViewport);
1165 if (graph != null && isTab) {
1166 XcosTab.restore(graph, false);
1167 graph.fireEvent(new mxEventObject(mxEvent.ROOT));
1168 tab = XcosTab.get(graph);
1169 } else if (graph != null && isViewport) {
1170 ViewPortTab.restore(graph, false);
1171 tab = ViewPortTab.get(graph);
1173 ClosingOperationsManager.addDependency(XcosTab.get(graph), tab);
1174 WindowsConfigurationManager.makeDependency(graph.getGraphTab(), tab.getPersistentId());
1180 WindowsConfigurationManager.restorationFinished(tab);
1181 ScilabTabFactory.getInstance().addToCache(tab);
1186 private XcosDiagram getDiagram(boolean isTab, boolean isViewport) {
1187 final Xcos instance = getInstance();
1188 XcosDiagram graph = null;
1191 // load a new diagram
1192 graph = getInstance().configuration.loadDiagram(cachedDocumentType);
1193 } else if (isViewport) {
1194 // get the cached diagram
1195 final File f = instance.configuration.getFile(cachedDocumentType);
1196 final Long rootUID = getInstance().openedDiagramUID(f);
1198 Collection<XcosDiagram> diags = instance.diagrams.getOrDefault(rootUID, Collections.emptyList());
1199 for (XcosDiagram d : diags) {
1200 final String id = d.getGraphTab();
1201 if (id != null && id.equals(cachedDocumentType.getUuid())) {
1212 public synchronized boolean isAValidUUID(String uuid) {
1213 // check the Palette manager view (static uuid)
1214 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1219 * Cache and check against cache to ease next getTab(uuid) call
1222 return cachedDocumentType != null;
1226 * Cache the {@link DocumentType} for the specific uuid
1231 private void cache(String uuid) {
1233 * Handle a non null cache
1235 if (cachedDocumentType != null) {
1236 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1237 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1239 if (isTab || isViewport) {
1242 cachedDocumentType = null;
1247 * Invalid cache, look for the right one
1249 final ConfigurationManager config = getInstance().configuration;
1250 final List<DocumentType> docs = config.getSettings().getTab();
1251 for (DocumentType d : docs) {
1252 final boolean isTab = uuid.equals(d.getUuid());
1253 final boolean isViewport = uuid.equals(d.getViewport());
1255 if (isTab || isViewport) {
1256 cachedDocumentType = d;
1263 public String getPackage() {
1268 public String getClassName() {
1269 return XcosTabFactory.class.getName();
1273 public String getApplication() {
1278 // CSON: ClassDataAbstractionCoupling
1279 // CSON: ClassFanOutComplexity