]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorPart.java
NPE while recalculating title for CompatibilityPart
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / ResourceEditorPart.java
index 56c26e8b26b49e3fe333382b6722809ca42bc432..ca06a5d7b5d538c9091fb8b71d7f45d26ad906d3 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2013 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *     Semantum Oy - issue #4384\r
- *******************************************************************************/\r
-package org.simantics.ui.workbench;\r
-\r
-import java.util.function.Supplier;\r
-\r
-import org.eclipse.core.runtime.IProgressMonitor;\r
-import org.eclipse.jface.action.IStatusLineManager;\r
-import org.eclipse.ui.IActionBars;\r
-import org.eclipse.ui.IEditorInput;\r
-import org.eclipse.ui.IEditorSite;\r
-import org.eclipse.ui.PartInitException;\r
-import org.eclipse.ui.part.EditorPart;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.common.request.ParametrizedRead;\r
-import org.simantics.db.event.ChangeListener;\r
-import org.simantics.db.management.ISessionContext;\r
-import org.simantics.ui.SimanticsUI;\r
-\r
-/**\r
- * ResourceEditorPart is a base implementation for editors that support\r
- * {@link ResourceEditorInput} style inputs for working on top of the Simantics\r
- * graph database.\r
- * \r
- * <p>\r
- * If you want your ResourceEditorPart implementation to receive notifications\r
- * for all graph change events through the {@link ChangeListener} interface,\r
- * just implement it and it will be automatically invoked by this base\r
- * implementation.\r
- * </p>\r
- * \r
- * @author Tuukka Lehtonen\r
- */\r
-public abstract class ResourceEditorPart extends EditorPart implements IResourceEditorPart {\r
-\r
-    protected boolean               disposed = false;\r
-    protected ResourceEditorSupport support;\r
-\r
-    /**\r
-     * Override to define your own input resource editor input validator that\r
-     * the view uses by default in {@link #init(IEditorSite, IEditorInput)}.\r
-     * \r
-     * @return\r
-     */\r
-    protected ParametrizedRead<IResourceEditorInput, Boolean> getInputValidator() {\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    public void init(IEditorSite site, IEditorInput input) throws PartInitException {\r
-        init(site, input, getInputValidator());\r
-    }\r
-    \r
-    protected void createSupport(ParametrizedRead<IResourceEditorInput, Boolean> inputValidator) throws PartInitException {\r
-        support = new ResourceEditorSupport(this, inputValidator);\r
-    }\r
-\r
-    protected void init(IEditorSite site, IEditorInput input,\r
-            ParametrizedRead<IResourceEditorInput, Boolean> inputValidator) throws PartInitException {\r
-        if (!(input instanceof IResourceEditorInput))\r
-            throw new PartInitException("Invalid input: must be IResourceEditorInput");\r
-\r
-        setSite(site);\r
-        setInput(input);\r
-        createSupport(inputValidator);\r
-\r
-        // Set initial part name according to the name given by IEditorInput\r
-        setPartName(getEditorInput().getName());\r
-\r
-        Session session = SimanticsUI.peekSession();\r
-        if (session != null) {\r
-            Supplier<Boolean> disposedCallback = () -> disposed;\r
-            session.asyncRequest(\r
-                    new TitleRequest(site.getId(), getResourceInput()),\r
-                    new TitleUpdater(site.getShell().getDisplay(), this::setPartName, disposedCallback));\r
-            session.asyncRequest(\r
-                    new ToolTipRequest(site.getId(), getResourceInput()),\r
-                    new TitleUpdater(site.getShell().getDisplay(), this::setTitleToolTip, disposedCallback));\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void dispose() {\r
-        disposed = true;\r
-        support.dispose();\r
-        super.dispose();\r
-    }\r
-\r
-    protected void activateValidation() {\r
-        support.activateValidation();\r
-    }\r
-\r
-    public ISessionContext getSessionContext() {\r
-        return support.getSessionContext();\r
-    }\r
-\r
-    public Session getSession() {\r
-        return support.getSession();\r
-    }\r
-\r
-    /**\r
-     * A resource editor does not need to perform any save operations since the\r
-     * graph model is global and different parts of it need not be saved\r
-     * separately.\r
-     * \r
-     * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)\r
-     */\r
-    @Override\r
-    public void doSave(IProgressMonitor monitor) {\r
-        //System.out.println("[ResourceEditorPart] doSave: " + getPartName());\r
-    }\r
-\r
-    @Override\r
-    public void doSaveAs() {\r
-        //System.out.println("[ResourceEditorPart] doSaveAs: " + getPartName());\r
-    }\r
-\r
-    /**\r
-     * A resource editor should never be dirty since its purpose is to reflect\r
-     * the current state of the graph model.\r
-     * \r
-     * @see org.eclipse.ui.part.EditorPart#isDirty()\r
-     */\r
-    @Override\r
-    public boolean isDirty() {\r
-        //System.out.println("[ResourceEditorPart] isDirty: " + getPartName());\r
-        return false;\r
-    }\r
-\r
-    @Override\r
-    public boolean isSaveAsAllowed() {\r
-        // Graph edits are always immediately sent to "UndoCore" which means\r
-        // that resource graph editors do not support save-features as such.\r
-        return false;\r
-    }\r
-\r
-    @Override\r
-    public IResourceEditorInput getResourceInput() {\r
-        return (IResourceEditorInput) getEditorInput();\r
-    }\r
-\r
-    //-------\r
-    // UTILS\r
-    //-------\r
-\r
-    public IStatusLineManager getStatusLineManager() {\r
-        IActionBars bars = getEditorSite().getActionBars();\r
-        IStatusLineManager mgr = bars.getStatusLineManager();\r
-        return mgr;\r
-    }\r
-\r
-    /**\r
-     * @param message <code>null</code> to remove message\r
-     */\r
-    public void setStatusMessage(String message) {\r
-        getStatusLineManager().setMessage(message);\r
-    }\r
-\r
-    /**\r
-     * @param message <code>null</code> to remove message\r
-     */\r
-    public void setStatusErrorMessage(String message) {\r
-        getStatusLineManager().setErrorMessage(message);\r
-    }\r
-\r
-    protected Resource getInputResource() {\r
-        return getResourceInput().getResource();\r
-    }\r
-\r
-    protected String getInputName() {\r
-        return getEditorInput().getName();\r
-    }\r
-\r
-    protected String getTitleText() {\r
-        return getInputName();\r
-    }\r
-\r
-    protected String getTitleTooltip() {\r
-        return getInputName();\r
-    }\r
-\r
-    protected void updateTitle() {\r
-        setPartName(getTitleText());\r
-        setTitleToolTip(getTitleTooltip());\r
-    }\r
-\r
-    /**\r
-     * A utility method for easier invocation of Runnables asynchronously in the\r
-     * SWT UI thread.\r
-     * \r
-     * @param run\r
-     */\r
-    protected void asyncExec(Runnable run) {\r
-        getSite().getShell().getDisplay().asyncExec(run);\r
-    }\r
-\r
-    @SuppressWarnings("unchecked")\r
-    @Override\r
-    public <T> T getAdapter(Class<T> adapter) {\r
-        if (adapter == Session.class)\r
-            return (T) getSession();\r
-        return super.getAdapter(adapter);\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *     Semantum Oy - issue #4384
+ *     Semantum Oy - issue #7737
+ *******************************************************************************/
+package org.simantics.ui.workbench;
+
+import java.util.function.Supplier;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
+import org.eclipse.ui.part.EditorPart;
+import org.simantics.Simantics;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.request.ParametrizedRead;
+import org.simantics.db.management.ISessionContext;
+
+/**
+ * ResourceEditorPart is a base implementation for editors that support
+ * {@link ResourceEditorInput} style inputs for working on top of the Simantics
+ * graph database.
+ * 
+ * <p>
+ * If you want your ResourceEditorPart implementation to receive notifications
+ * for all graph change events through the {@link ChangeListener} interface,
+ * just implement it and it will be automatically invoked by this base
+ * implementation.
+ * </p>
+ * 
+ * @author Tuukka Lehtonen
+ * @author Jani Simomaa
+ */
+public abstract class ResourceEditorPart extends EditorPart implements IResourceEditorPart {
+
+    protected boolean               disposed = false;
+    protected ResourceEditorSupport support;
+
+    /**
+     * Override to define your own input resource editor input validator that
+     * the view uses by default in {@link #init(IEditorSite, IEditorInput)}.
+     * 
+     * @return
+     */
+    protected ParametrizedRead<IResourceEditorInput, Boolean> getInputValidator() {
+        return null;
+    }
+
+    @Override
+    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+        init(site, input, getInputValidator());
+    }
+    
+    protected void createSupport(ParametrizedRead<IResourceEditorInput, Boolean> inputValidator) throws PartInitException {
+        support = new ResourceEditorSupport(this, inputValidator);
+    }
+
+    protected void init(IEditorSite site, IEditorInput input,
+            ParametrizedRead<IResourceEditorInput, Boolean> inputValidator) throws PartInitException {
+        if (!(input instanceof IResourceEditorInput))
+            throw new PartInitException("Invalid input: must be IResourceEditorInput");
+
+        setSite(site);
+        setInput(input);
+        createSupport(inputValidator);
+
+        // Set initial part name according to the name given by IEditorInput
+        setPartName(getEditorInput().getName());
+
+        Session session = Simantics.peekSession();
+        if (session != null) {
+            Supplier<Boolean> disposedCallback = () -> disposed;
+            session.asyncRequest(
+                    new TitleRequest(site.getId(), getResourceInput()),
+                    new TitleUpdater(site.getShell().getDisplay(), this::safeSetPartName, disposedCallback));
+            session.asyncRequest(
+                    new ToolTipRequest(site.getId(), getResourceInput()),
+                    new TitleUpdater(site.getShell().getDisplay(), this::safeSetTitleToolTip, disposedCallback));
+        }
+    }
+
+    /**
+     * Safely sets part name for parts whose IEditorInput is not yet disposed (e.g.
+     * removed from database)
+     * 
+     * @param partName
+     */
+    protected void safeSetPartName(String partName) {
+        if (!disposed && checkCompatibilityPartNotBeingDisposed()) { // this is to fix bug https://gitlab.simantics.org/simantics/platform/issues/117
+            setPartName(partName);
+        }
+    }
+
+    @SuppressWarnings("restriction")
+    private boolean checkCompatibilityPartNotBeingDisposed() {
+        IWorkbenchPartSite site = getSite();
+        if (site instanceof PartSite) {
+            PartSite partSite = (PartSite) getSite();
+            Object object = partSite.getModel().getObject();
+            if (object instanceof CompatibilityEditor) {
+                CompatibilityEditor editor = (CompatibilityEditor) object;
+                return !editor.isBeingDisposed();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Safely sets title tooltip for parts whose IEditorInput is not yet disposed (e.g.
+     * removed from database)
+     * 
+     * @param toolTip
+     */
+    protected void safeSetTitleToolTip(String toolTip) {
+        if (!disposed) {
+            setTitleToolTip(toolTip);
+        }
+    }
+
+    @Override
+    public void dispose() {
+        disposed = true;
+        support.dispose();
+        super.dispose();
+    }
+
+    protected void activateValidation() {
+        support.activateValidation();
+    }
+
+    public ISessionContext getSessionContext() {
+        return support.getSessionContext();
+    }
+
+    public Session getSession() {
+        return support.getSession();
+    }
+
+    /**
+     * A resource editor does not need to perform any save operations since the
+     * graph model is global and different parts of it need not be saved
+     * separately.
+     * 
+     * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
+     */
+    @Override
+    public void doSave(IProgressMonitor monitor) {
+        //System.out.println("[ResourceEditorPart] doSave: " + getPartName());
+    }
+
+    @Override
+    public void doSaveAs() {
+        //System.out.println("[ResourceEditorPart] doSaveAs: " + getPartName());
+    }
+
+    /**
+     * A resource editor should never be dirty since its purpose is to reflect
+     * the current state of the graph model.
+     * 
+     * @see org.eclipse.ui.part.EditorPart#isDirty()
+     */
+    @Override
+    public boolean isDirty() {
+        //System.out.println("[ResourceEditorPart] isDirty: " + getPartName());
+        return false;
+    }
+
+    @Override
+    public boolean isSaveAsAllowed() {
+        // Graph edits are always immediately sent to "UndoCore" which means
+        // that resource graph editors do not support save-features as such.
+        return false;
+    }
+
+    @Override
+    public IResourceEditorInput getResourceInput() {
+        return (IResourceEditorInput) getEditorInput();
+    }
+
+    //-------
+    // UTILS
+    //-------
+
+    public IStatusLineManager getStatusLineManager() {
+        IActionBars bars = getEditorSite().getActionBars();
+        IStatusLineManager mgr = bars.getStatusLineManager();
+        return mgr;
+    }
+
+    /**
+     * @param message <code>null</code> to remove message
+     */
+    public void setStatusMessage(String message) {
+        getStatusLineManager().setMessage(message);
+    }
+
+    /**
+     * @param message <code>null</code> to remove message
+     */
+    public void setStatusErrorMessage(String message) {
+        getStatusLineManager().setErrorMessage(message);
+    }
+
+    protected Resource getInputResource() {
+        return getResourceInput().getResource();
+    }
+
+    protected String getInputName() {
+        return getEditorInput().getName();
+    }
+
+    protected String getTitleText() {
+        return getInputName();
+    }
+
+    protected String getTitleTooltip() {
+        return getInputName();
+    }
+
+    protected void updateTitle() {
+        setPartName(getTitleText());
+        setTitleToolTip(getTitleTooltip());
+    }
+
+    /**
+     * A utility method for easier invocation of Runnables asynchronously in the
+     * SWT UI thread.
+     * 
+     * @param run
+     */
+    protected void asyncExec(Runnable run) {
+        getSite().getShell().getDisplay().asyncExec(run);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == Session.class)
+            return (T) getSession();
+        return super.getAdapter(adapter);
+    }
+
+}