/******************************************************************************* * 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. * *

* 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. *

* * @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 getInputValidator() { return null; } @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { init(site, input, getInputValidator()); } protected void createSupport(ParametrizedRead inputValidator) throws PartInitException { support = new ResourceEditorSupport(this, inputValidator); } protected void init(IEditorSite site, IEditorInput input, ParametrizedRead 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 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 null to remove message */ public void setStatusMessage(String message) { getStatusLineManager().setMessage(message); } /** * @param message null 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 getAdapter(Class adapter) { if (adapter == Session.class) return (T) getSession(); return super.getAdapter(adapter); } }