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 JavaController.register_view(Xcos.class.getName(), view);
177 // allocate and install the browser view on demand to avoid any cost
181 * get the handlers instance
183 palette = PaletteManager.getInstance();
184 configuration = ConfigurationManager.getInstance();
185 styleSheet = new mxStylesheet();
186 externalActions = new ArrayList<>();
189 FileUtils.decodeStyle(styleSheet);
190 } catch (final IOException e) {
191 LOG.severe(e.toString());
195 * Register as an AbstractScilabTabFactory
197 if (factory == null) {
198 this.factory = new XcosTabFactory(false);
200 this.factory = factory;
202 ScilabTabFactory.getInstance().addTabFactory(this.factory);
207 protected void finalize() throws Throwable {
208 if (browser != null) {
209 JavaController.unregister_view(browser);
212 JavaController.unregister_view(view);
218 * Check the dependencies and the version dependencies.
220 * This method use runtime class loading to handle ClassNotFoundException.
222 * This method catch any exception and rethrow it with a well defined message. Thus it doesn't pass the IllegalCatch metrics.
224 // CSOFF: IllegalCatch
225 // CSOFF: MagicNumber
226 private void checkDependencies() {
227 final ClassLoader loader = ClassLoader.getSystemClassLoader();
230 String mxGraphVersion = "";
232 final Class<?> klass = loader.loadClass("com.mxgraph.view.mxGraph");
233 mxGraphVersion = (String) klass.getDeclaredField("VERSION").get(null);
235 if (MXGRAPH_VERSIONS != null && !MXGRAPH_VERSIONS.contains(mxGraphVersion)) {
236 throw new Exception();
238 } catch (final Throwable e) {
239 throw new RuntimeException(String.format(UNABLE_TO_LOAD_JGRAPHX, MXGRAPH_VERSIONS.get(0), mxGraphVersion), e);
243 String batikVersion = null;
245 final Class<?> klass = loader.loadClass("org.apache.batik.Version");
246 batikVersion = klass.getPackage().getImplementationVersion().split("\\+")[0];
248 if (!BATIK_VERSIONS.contains(batikVersion)) {
249 throw new Exception();
252 } catch (final Throwable e) {
253 throw new RuntimeException(String.format(UNABLE_TO_LOAD_BATIK, BATIK_VERSIONS.get(0), batikVersion), e);
258 // CSON: IllegalCatch
261 * @return the per Scilab application, Xcos instance
263 public static synchronized Xcos getInstance() {
264 return getInstance(null);
269 * the tab factory instance or null on creation
270 * @return the per Scilab application, Xcos instance
272 private static synchronized Xcos getInstance(final XcosTabFactory factory) {
273 if (sharedInstance == null) {
275 if (!SwingUtilities.isEventDispatchThread()) {
276 SwingUtilities.invokeAndWait(() -> {
277 sharedInstance = new Xcos(factory);
280 sharedInstance = new Xcos(factory);
282 } catch (InvocationTargetException e) {
284 } catch (InterruptedException e) {
288 LOG.finest("Session started");
291 return sharedInstance;
297 public void quit(boolean force) {
298 if (sharedInstance == null) {
302 // TODO : perform something ?
306 * Clear the shared instance.
308 private static synchronized void clearInstance() {
309 sharedInstance = null;
310 LOG.finest("Session ended");
314 * All Opened diagrams
316 * @return the opened diagrams list
318 public List<XcosDiagram> openedDiagrams() {
319 ArrayList<XcosDiagram> opened = new ArrayList<>();
320 diagrams.values().stream().forEach(l -> opened.addAll(l));
329 * @return the opened diagrams list
331 public List<XcosDiagram> openedDiagrams(ScicosObjectOwner root) {
332 return diagrams.getOrDefault(root, Collections.emptyList());
335 public ScicosObjectOwner openedDiagram(File f) {
336 ScicosObjectOwner opened = null;
341 for (ScicosObjectOwner root : diagrams.keySet()) {
342 List<XcosDiagram> diags = diagrams.getOrDefault(root, Collections.emptyList());
344 if (!diags.isEmpty() && f.equals(diags.get(0).getSavedFile())) {
354 * Check if the in memory file representation is modified
358 * @return is modified
360 public boolean isModified(ScicosObjectOwner root) {
361 for (XcosDiagram d : diagrams.get(root)) {
362 if (d.isModified()) {
371 * Set the full diagram as modified
372 * @param root the root diagram
373 * @param modified the modified status
375 public void setModified(ScicosObjectOwner root, boolean modified) {
376 for (XcosDiagram d : diagrams.get(root)) {
377 d.setModified(modified);
382 * Popup a dialog to ask for a file creation
386 * @return true if creation is has been performed
388 public boolean askForFileCreation(final XcosDiagram diag, final File f) {
391 answer = ScilabModalDialog.show(diag.getAsComponent(), new String[] { String.format(XcosMessages.FILE_DOESNT_EXIST, f.getCanonicalFile()) },
392 XcosMessages.XCOS, IconType.QUESTION_ICON, ButtonType.YES_NO);
393 } catch (final IOException e) {
394 LOG.severe(e.toString());
395 answer = AnswerOption.YES_OPTION;
398 if (answer == AnswerOption.YES_OPTION) {
399 return diag.saveDiagramAs(f);
406 * @return the global shared styleSheet
408 public mxStylesheet getStyleSheet() {
413 * Open a file from it's filename.
415 * This method must be called on the EDT thread. For other use, please use the {@link #xcos(String, String)} method.
418 * the file to open. If null an empty diagram is created.
420 * the MVC ID to track. If 0 no association is performed.
422 public void open(final String file, final long diagramId) {
423 if (!SwingUtilities.isEventDispatchThread()) {
424 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
428 * If it is the first window opened, then open the palette first.
430 boolean openThePalette = openedDiagrams().isEmpty();
432 JavaController controller = new JavaController();
433 XcosDiagram diag = null;
441 if (f != null && f.exists()) {
442 configuration.addToRecentFiles(f);
446 * looking for an already opened diagram
448 ScicosObjectOwner root = openedDiagram(f);
450 diag = diagrams.get(root).iterator().next();
452 // if unsaved and empty, reuse it. Allocate otherwise.
453 if (f == null && diag != null && diag.getModel().getChildCount(diag.getDefaultParent()) > 0) {
457 // looking for an empty, unsaved diagram to use if opening a new file
458 // if not found an already open instance of the file
460 // traverse through the key set of all the opened diagrams
461 for (Map.Entry<ScicosObjectOwner, List<XcosDiagram>> entry : diagrams.entrySet()) {
462 List<XcosDiagram> diagramsWithKey = entry.getValue();
463 XcosDiagram diagramWithKey = diagramsWithKey.get(0); // get the diagram that maps to that key
464 int childCount = diagramWithKey.countChildren(); //count the number of children in the diagram
465 // if empty, unsaved and unused
466 if (childCount == 0 && diagramWithKey.getSavedFile() == null && !diagramWithKey.isModified()) {
467 // use that open diagram
468 diag = diagramWithKey;
469 diag.transformAndLoadFile(controller, file);
473 // if reuse then request focus
475 XcosTab tab = XcosTab.get(diag);
482 final long currentId;
483 if (diagramId != 0) {
484 currentId = diagramId;
486 currentId = controller.createObject(Kind.DIAGRAM);
490 // loading disabled, unlock
491 synchronized (this) {
496 // loading enable, unlock will be performed later, on another thread
499 * Allocate and setup a new diagram
501 diag = new XcosDiagram(controller, currentId, controller.getKind(currentId), "");
502 diag.installListeners();
504 root = findRoot(controller, diag);
505 addDiagram(root, diag);
508 * Ask for file creation
510 if (f != null && !f.exists()) {
511 if (!askForFileCreation(diag, f)) {
512 // loading disabled, unlock
513 synchronized (this) {
518 // return now, to avoid tab creation
519 diagrams.remove(root);
526 * Create a visible window before loading
528 if (XcosTab.get(diag) == null) {
529 XcosTab.restore(diag);
532 if (openThePalette) {
533 PaletteManager.setVisible(true);
539 diag.transformAndLoadFile(controller, file);
544 * Log a loading error
547 * the error description
549 public void setLastError(String error) {
550 this.lastError = error;
554 * @return the Xcos view
556 public XcosView getXcosView() {
561 * @return the Browser view
563 public BrowserView getBrowser() {
564 if (browser == null) {
565 browser = new BrowserView();
566 JavaController.register_view(BrowserView.class.getSimpleName(), browser);
572 * Clear the browser state and unregister the current view.
574 public void clearBrowser() {
575 if (browser != null) {
576 JavaController.unregister_view(browser);
582 * Get an unmodifiable view of the diagrams for an UID
586 * @return the diagram collection
588 public Collection<XcosDiagram> getDiagrams(final ScicosObjectOwner root) {
589 final Collection<XcosDiagram> diags = diagrams.get(root);
593 return Collections.unmodifiableCollection(diags);
597 * 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.
604 public void addDiagram(final ScicosObjectOwner root, final XcosDiagram diag) {
605 if (onDiagramIteration) {
606 throw new RuntimeException();
609 throw new IllegalArgumentException();
613 * Create the collection if it does not exist
615 List<XcosDiagram> diags = diagrams.get(root);
617 diags = createDiagramCollection();
618 diagrams.put(root, diags);
621 // insert the diagram
626 * Add a diagram to the opened list
628 * This method manage both super-block and root diagrams.
629 * @param diag the diagram to add
631 public void addDiagram(final XcosDiagram diag) {
632 ScicosObjectOwner root = findRoot(diag);
633 addDiagram(root, diag);
637 * Create a diagram collections (sorted List)
639 * @return the diagram collection
641 @SuppressWarnings("serial")
642 public List<XcosDiagram> createDiagramCollection() {
643 return new ArrayList<XcosDiagram>() {
645 public boolean add(XcosDiagram element) {
646 final boolean status = super.add(element);
647 DiagramComparator.sort(this);
652 public boolean addAll(Collection<? extends XcosDiagram> c) {
653 final boolean status = super.addAll(c);
654 DiagramComparator.sort(this);
661 * Try to close the graph (popup save dialog)
665 * @return if we can (or not) close the graph
667 public boolean canClose(final XcosDiagram graph) {
668 boolean canClose = false;
670 ScicosObjectOwner root = findRoot(graph);
672 final boolean wasLastOpened = openedDiagrams(root).size() <= 1;
673 final boolean isModified = isModified(root);
674 if (!(wasLastOpened && isModified)) {
679 final AnswerOption ans = ScilabModalDialog.show(XcosTab.get(graph), XcosMessages.DIAGRAM_MODIFIED, XcosMessages.XCOS, IconType.QUESTION_ICON,
680 ButtonType.YES_NO_CANCEL);
684 canClose = diagrams.get(root).iterator().next().saveDiagram();
687 canClose = true; // can close
690 canClose = false; // operation canceled
696 * Update configuration before the destroy call to validate the uuid
699 configuration.addToRecentTabs(graph);
700 configuration.saveConfig();
708 * This method must be called on the EDT thread.
711 * the diagram to close
713 public void destroy(XcosDiagram graph) {
714 ScicosObjectOwner root = findRoot(graph);
716 final boolean wasLastOpenedForFile = openedDiagrams(root).size() <= 1;
717 if (wasLastOpenedForFile) {
718 diagrams.remove(root);
720 diagrams.get(root).remove(graph);
723 if (openedDiagrams().size() <= 0) {
724 JavaController.end_simulation();
730 * the graph to handle
732 * the diagram to check
733 * @return diagram name for the "Are your sure ?" dialog
735 public String askForClosing(final XcosDiagram graph, final List<SwingScilabDockablePanel> list) {
738 if (wasLastOpened(list)) {
748 * Does Xcos will close or not ?
751 * the list to be closed
752 * @return true if all files will be close on tabs close.
754 public boolean wasLastOpened(final List<SwingScilabDockablePanel> list) {
755 final HashSet<String> opened = new HashSet<String>();
756 for (XcosDiagram diag : openedDiagrams()) {
757 opened.add(diag.getGraphTab());
760 final HashSet<String> tabs = new HashSet<String>();
761 for (SwingScilabDockablePanel tab : list) {
763 tabs.add(tab.getPersistentId());
767 opened.removeAll(tabs);
769 return opened.isEmpty();
773 * @return the external action list
775 public List<ExternalAction> getExternalActions() {
776 return externalActions;
780 * Close the current xcos session.
782 * This method must be called on the EDT thread. For other use, please use the {@link #closeXcosFromScilab()} method.
784 public static synchronized void closeSession(final boolean ask) {
785 if (!SwingUtilities.isEventDispatchThread()) {
786 LOG.severe(CALLED_OUTSIDE_THE_EDT_THREAD);
789 /* Doesn't instantiate xcos on close operation */
790 if (sharedInstance == null) {
795 * Try to close all opened files
797 final Xcos instance = sharedInstance;
800 final List<SwingScilabDockablePanel> tabs = new ArrayList<SwingScilabDockablePanel>();
801 for (final Collection<XcosDiagram> diags : instance.diagrams.values()) {
802 for (final XcosDiagram diag : diags) {
803 final SwingScilabDockablePanel tab = XcosTab.get(diag);
811 final boolean status = ClosingOperationsManager.startClosingOperation(tabs, ask, ask);
815 /* reset the shared instance state */
816 instance.diagrams.clear();
818 /* terminate any remaining simulation */
819 JavaController.end_simulation();
821 /* Saving modified data */
822 instance.palette.saveConfig();
823 instance.configuration.saveConfig();
828 * Scilab exported methods.
830 * All the following methods must use SwingUtilities method to assert that the operations will be called on the EDT thread.
832 * @see modules/xcos/src/jni/Xcos.giws.xml
834 * @see sci_gateway/xcos_gateway.xml
836 * @see modules/xcos/sci_gateway/cpp/sci_*.cpp
842 * This method invoke Xcos operation on the EDT thread.
845 * The filename (can be null)
847 * The Xcos DIAGRAM model ID (can be 0)
849 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
850 public static void xcos(final String file, final long diagramId) {
851 final Xcos instance = getInstance();
852 instance.lastError = null;
854 /* load scicos libraries (macros) */
855 InterpreterManagement.requestScilabExec(LOAD_XCOS_LIBS_LOAD_SCICOS);
857 synchronized (instance) {
861 SwingUtilities.invokeLater(new Runnable() {
865 instance.open(file, diagramId);
869 if (instance.lastError != null && !instance.lastError.isEmpty()) {
870 throw new RuntimeException(instance.lastError);
875 * Load or Save an xcos diagram without using Scilab at all.
878 * This support a reduced number of format and should be mainly used to test
883 * the diagram to load into
885 * flag used to indicate an export (true == export ; false == import)
889 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
890 public static void xcosDiagramToScilab(String file, long diagramId, boolean export) throws Exception {
891 XcosFileType filetype = XcosFileType.findFileType(file);
892 if (filetype == null) {
893 throw new IllegalArgumentException("not handled filetype");
896 if (XcosFileType.getAvailableSaveFormats().contains(filetype)) {
898 filetype.save(file, new XcosDiagram(new JavaController(), diagramId, Kind.DIAGRAM, ""));
900 filetype.load(file, new XcosDiagram(new JavaController(), diagramId, Kind.DIAGRAM, ""));
903 throw new IllegalArgumentException("not handled filetype");
908 * Close the current xcos session from any thread.
910 * This method invoke Xcos operation on the EDT thread. Please prefer using {@link #closeSession()} when the caller is on the EDT thread.
912 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
913 public static void closeXcosFromScilab() {
915 SwingUtilities.invokeAndWait(new Runnable() {
922 } catch (final InterruptedException e) {
924 } catch (final InvocationTargetException e) {
927 Throwable throwable = e;
928 String firstMessage = null;
929 while (throwable != null) {
930 firstMessage = throwable.getLocalizedMessage();
931 throwable = throwable.getCause();
934 throw new RuntimeException(firstMessage, e);
939 * Look in each diagram to find the block corresponding to the given uid and display a warning message.
941 * This method invoke Xcos operation on the EDT thread.
946 * The message to display.
948 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
949 public static void warnCellByUID(final String[] uids, final String message) {
951 SwingUtilities.invokeAndWait(new Runnable() {
954 getInstance().warnCell(uids, message);
957 } catch (final InterruptedException e) {
958 LOG.severe(e.toString());
959 } catch (final InvocationTargetException e) {
960 Throwable throwable = e;
961 String firstMessage = null;
962 while (throwable != null) {
963 firstMessage = throwable.getLocalizedMessage();
964 throwable = throwable.getCause();
967 throw new RuntimeException(firstMessage, e);
971 private void warnCell(final String[] uids, final String message) {
973 final mxCell[] cells = new mxCell[uids.length];
974 final XcosDiagram[] diags = new XcosDiagram[uids.length];
976 lookupForCells(uids, cells, diags);
977 for (int i = cells.length - 1; i >= 0; --i) {
978 mxCell cell = cells[i];
980 // perform the action on the last visible block
982 final XcosDiagram parent = diags[i];
983 parent.warnCellByUID(cell.getId(), message);
985 // Focus on an existing diagram
986 SwingUtilities.invokeLater(() -> {
987 XcosTab.get(parent).setCurrent();
996 public void lookupForCells(final String[] uid, final mxCell[] cells, final XcosDiagram[] diags) {
997 final List<XcosDiagram> all = openedDiagrams();
998 for (int i = 0; i < uid.length; i++) {
999 final String id = uid[i];
1000 diags[i] = all.stream().filter(d -> ((XcosGraphModel) d.getModel()).getCell(id) != null)
1001 .findFirst().orElse(null);
1002 if (diags[i] != null) {
1003 cells[i] = (mxCell) ((XcosGraphModel) diags[i].getModel()).getCell(id);
1009 * Add a menu into xcos
1014 * the callback (as a Scilab executable String)
1016 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1017 public static void addToolsMenu(final String label, final String command) {
1018 final ExternalAction action = new ExternalAction(null, command);
1019 action.putValue(Action.NAME, label);
1020 final Xcos instance = Xcos.getInstance();
1023 * Store for future tabs
1025 instance.externalActions.add(action);
1028 * Update opened tabs
1030 for (final XcosDiagram d : instance.openedDiagrams()) {
1031 final String uuid = d.getGraphTab();
1032 final SwingScilabDockablePanel tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1035 final SwingScilabMenuBar bar = ((SwingScilabMenuBar) tab.getMenuBar().getAsSimpleMenuBar());
1037 final Component[] comps = bar.getComponents();
1038 for (Component component : comps) {
1039 if (component instanceof SwingScilabMenu) {
1040 final SwingScilabMenu menu = (SwingScilabMenu) component;
1042 if (menu.getText() == XcosMessages.TOOLS) {
1043 menu.add(new ExternalAction(action, d));
1048 // Also update the parent window toolbar
1049 BarUpdater.updateBars(tab.getParentWindowId(), tab.getMenuBar(), tab.getToolBar(), tab.getInfoBar(), tab.getName(), tab.getWindowIcon());
1055 * Inform Xcos the simulator has just started
1058 @ScilabExported(module = "xcos", filename = "Xcos.giws.xml")
1059 public static void xcosSimulationStarted() {
1060 SwingUtilities.invokeLater(new Runnable() {
1063 GraphActionManager.setEnable(StopAction.class, true);
1069 * Look for the parent diagram of the cell in the diagram hierarchy.
1072 * the cell to search for
1073 * @return the associated diagram
1075 public static XcosDiagram findParent(Object cell) {
1076 final Xcos instance = getInstance();
1078 for (Collection<XcosDiagram> diags : instance.diagrams.values()) {
1079 for (XcosDiagram diag : diags) {
1080 final mxGraphModel model = (mxGraphModel) diag.getModel();
1082 // use the O(1) lookup
1083 if (cell instanceof mxICell && model.getCell(((mxICell) cell).getId()) != null) {
1093 * Look for the root object of the whole graph hierarchy
1094 * @param graph the graph
1095 * @return the root MVC object with Kind.DIAGRAM
1097 public static ScicosObjectOwner findRoot(XcosDiagram graph) {
1098 return findRoot(new JavaController(), graph);
1102 * Look for the root object of the whole graph hierarchy
1103 * @param controller the shared controller
1104 * @param graph the graph
1105 * @return the root MVC object with Kind.DIAGRAM
1107 public static ScicosObjectOwner findRoot(JavaController controller, XcosDiagram graph) {
1108 ScicosObjectOwner root;
1109 if (graph.getKind() == Kind.DIAGRAM) {
1110 root = new ScicosObjectOwner(controller, graph.getUID(), graph.getKind());
1112 long[] rootDiagram = new long[1];
1113 controller.getObjectProperty(graph.getUID(), graph.getKind(), ObjectProperties.PARENT_DIAGRAM, rootDiagram);
1114 root = new ScicosObjectOwner(controller, rootDiagram[0], Kind.DIAGRAM);
1122 * @see org.scilab.modules.gui.tabfactory.AbstractScilabTabFactory
1124 public static class XcosTabFactory extends AbstractScilabTabFactory {
1129 private DocumentType cachedDocumentType;
1132 * Default constructor
1134 public XcosTabFactory() {
1138 private XcosTabFactory(boolean instanciateXcos) {
1139 if (instanciateXcos) {
1145 * Create/restore a tab for a given uuid
1149 * @return the tab instance
1152 public synchronized SwingScilabDockablePanel getTab(final String uuid) {
1157 SwingScilabDockablePanel tab = ScilabTabFactory.getInstance().getFromCache(uuid);
1159 // Palette manager restore
1161 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1162 PaletteManagerView.restore(null, false);
1163 tab = PaletteManagerView.get();
1167 // diagram (tab or viewport) restore
1170 if (cachedDocumentType == null) {
1174 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1175 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1177 final XcosDiagram graph = getDiagram(isTab, isViewport);
1178 if (graph != null && isTab) {
1179 XcosTab.restore(graph, false);
1180 graph.fireEvent(new mxEventObject(mxEvent.ROOT));
1181 tab = XcosTab.get(graph);
1182 } else if (graph != null && isViewport) {
1183 ViewPortTab.restore(graph, false);
1184 tab = ViewPortTab.get(graph);
1186 ClosingOperationsManager.addDependency(XcosTab.get(graph), tab);
1187 WindowsConfigurationManager.makeDependency(graph.getGraphTab(), tab.getPersistentId());
1193 WindowsConfigurationManager.restorationFinished(tab);
1194 ScilabTabFactory.getInstance().addToCache(tab);
1199 private XcosDiagram getDiagram(boolean isTab, boolean isViewport) {
1200 final Xcos instance = getInstance();
1201 XcosDiagram graph = null;
1204 // load a new diagram
1205 graph = getInstance().configuration.loadDiagram(cachedDocumentType);
1206 } else if (isViewport) {
1207 // get the cached diagram
1208 final File f = instance.configuration.getFile(cachedDocumentType);
1209 final ScicosObjectOwner root = getInstance().openedDiagram(f);
1211 Collection<XcosDiagram> diags = instance.diagrams.getOrDefault(root, Collections.emptyList());
1212 for (XcosDiagram d : diags) {
1213 final String id = d.getGraphTab();
1214 if (id != null && id.equals(cachedDocumentType.getUuid())) {
1225 public synchronized boolean isAValidUUID(String uuid) {
1226 // check the Palette manager view (static uuid)
1227 if (PaletteManagerView.DEFAULT_TAB_UUID.equals(uuid)) {
1232 * Cache and check against cache to ease next getTab(uuid) call
1235 return cachedDocumentType != null;
1239 * Cache the {@link DocumentType} for the specific uuid
1244 private void cache(String uuid) {
1246 * Handle a non null cache
1248 if (cachedDocumentType != null) {
1249 final boolean isTab = uuid.equals(cachedDocumentType.getUuid());
1250 final boolean isViewport = uuid.equals(cachedDocumentType.getViewport());
1252 if (isTab || isViewport) {
1255 cachedDocumentType = null;
1260 * Invalid cache, look for the right one
1262 final ConfigurationManager config = getInstance().configuration;
1263 final List<DocumentType> docs = config.getSettings().getTab();
1264 for (DocumentType d : docs) {
1265 final boolean isTab = uuid.equals(d.getUuid());
1266 final boolean isViewport = uuid.equals(d.getViewport());
1268 if (isTab || isViewport) {
1269 cachedDocumentType = d;
1276 public String getPackage() {
1281 public String getClassName() {
1282 return XcosTabFactory.class.getName();
1286 public String getApplication() {
1291 // CSON: ClassDataAbstractionCoupling
1292 // CSON: ClassFanOutComplexity