]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 /*******************************************************************************
2  * Copyright (c) 2007, 2013 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *     Semantum Oy - issue #4384
12  *     Semantum Oy - issue #7737
13  *******************************************************************************/
14 package org.simantics.ui.workbench;
15
16 import java.util.function.Supplier;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.jface.action.IStatusLineManager;
20 import org.eclipse.ui.IActionBars;
21 import org.eclipse.ui.IEditorInput;
22 import org.eclipse.ui.IEditorSite;
23 import org.eclipse.ui.IWorkbenchPartSite;
24 import org.eclipse.ui.PartInitException;
25 import org.eclipse.ui.internal.PartSite;
26 import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
27 import org.eclipse.ui.part.EditorPart;
28 import org.simantics.Simantics;
29 import org.simantics.db.Resource;
30 import org.simantics.db.Session;
31 import org.simantics.db.common.request.ParametrizedRead;
32 import org.simantics.db.management.ISessionContext;
33
34 /**
35  * ResourceEditorPart is a base implementation for editors that support
36  * {@link ResourceEditorInput} style inputs for working on top of the Simantics
37  * graph database.
38  * 
39  * <p>
40  * If you want your ResourceEditorPart implementation to receive notifications
41  * for all graph change events through the {@link ChangeListener} interface,
42  * just implement it and it will be automatically invoked by this base
43  * implementation.
44  * </p>
45  * 
46  * @author Tuukka Lehtonen
47  * @author Jani Simomaa
48  */
49 public abstract class ResourceEditorPart extends EditorPart implements IResourceEditorPart {
50
51     protected boolean               disposed = false;
52     protected ResourceEditorSupport support;
53
54     /**
55      * Override to define your own input resource editor input validator that
56      * the view uses by default in {@link #init(IEditorSite, IEditorInput)}.
57      * 
58      * @return
59      */
60     protected ParametrizedRead<IResourceEditorInput, Boolean> getInputValidator() {
61         return null;
62     }
63
64     @Override
65     public void init(IEditorSite site, IEditorInput input) throws PartInitException {
66         init(site, input, getInputValidator());
67     }
68     
69     protected void createSupport(ParametrizedRead<IResourceEditorInput, Boolean> inputValidator) throws PartInitException {
70         support = new ResourceEditorSupport(this, inputValidator);
71     }
72
73     protected void init(IEditorSite site, IEditorInput input,
74             ParametrizedRead<IResourceEditorInput, Boolean> inputValidator) throws PartInitException {
75         if (!(input instanceof IResourceEditorInput))
76             throw new PartInitException("Invalid input: must be IResourceEditorInput");
77
78         setSite(site);
79         setInput(input);
80         createSupport(inputValidator);
81
82         // Set initial part name according to the name given by IEditorInput
83         setPartName(getEditorInput().getName());
84
85         Session session = Simantics.peekSession();
86         if (session != null) {
87             Supplier<Boolean> disposedCallback = () -> disposed;
88             session.asyncRequest(
89                     new TitleRequest(site.getId(), getResourceInput()),
90                     new TitleUpdater(site.getShell().getDisplay(), this::safeSetPartName, disposedCallback));
91             session.asyncRequest(
92                     new ToolTipRequest(site.getId(), getResourceInput()),
93                     new TitleUpdater(site.getShell().getDisplay(), this::safeSetTitleToolTip, disposedCallback));
94         }
95     }
96
97     /**
98      * Safely sets part name for parts whose IEditorInput is not yet disposed (e.g.
99      * removed from database)
100      * 
101      * @param partName
102      */
103     protected void safeSetPartName(String partName) {
104         if (!disposed && checkCompatibilityPartNotBeingDisposed()) { // this is to fix bug https://gitlab.simantics.org/simantics/platform/issues/117
105             setPartName(partName);
106         }
107     }
108
109     @SuppressWarnings("restriction")
110     private boolean checkCompatibilityPartNotBeingDisposed() {
111         IWorkbenchPartSite site = getSite();
112         if (site instanceof PartSite) {
113             PartSite partSite = (PartSite) getSite();
114             Object object = partSite.getModel().getObject();
115             if (object instanceof CompatibilityEditor) {
116                 CompatibilityEditor editor = (CompatibilityEditor) object;
117                 return !editor.isBeingDisposed();
118             }
119         }
120         return true;
121     }
122
123     /**
124      * Safely sets title tooltip for parts whose IEditorInput is not yet disposed (e.g.
125      * removed from database)
126      * 
127      * @param toolTip
128      */
129     protected void safeSetTitleToolTip(String toolTip) {
130         if (!disposed) {
131             setTitleToolTip(toolTip);
132         }
133     }
134
135     @Override
136     public void dispose() {
137         disposed = true;
138         support.dispose();
139         super.dispose();
140     }
141
142     protected void activateValidation() {
143         support.activateValidation();
144     }
145
146     public ISessionContext getSessionContext() {
147         return support.getSessionContext();
148     }
149
150     public Session getSession() {
151         return support.getSession();
152     }
153
154     /**
155      * A resource editor does not need to perform any save operations since the
156      * graph model is global and different parts of it need not be saved
157      * separately.
158      * 
159      * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
160      */
161     @Override
162     public void doSave(IProgressMonitor monitor) {
163         //System.out.println("[ResourceEditorPart] doSave: " + getPartName());
164     }
165
166     @Override
167     public void doSaveAs() {
168         //System.out.println("[ResourceEditorPart] doSaveAs: " + getPartName());
169     }
170
171     /**
172      * A resource editor should never be dirty since its purpose is to reflect
173      * the current state of the graph model.
174      * 
175      * @see org.eclipse.ui.part.EditorPart#isDirty()
176      */
177     @Override
178     public boolean isDirty() {
179         //System.out.println("[ResourceEditorPart] isDirty: " + getPartName());
180         return false;
181     }
182
183     @Override
184     public boolean isSaveAsAllowed() {
185         // Graph edits are always immediately sent to "UndoCore" which means
186         // that resource graph editors do not support save-features as such.
187         return false;
188     }
189
190     @Override
191     public IResourceEditorInput getResourceInput() {
192         return (IResourceEditorInput) getEditorInput();
193     }
194
195     //-------
196     // UTILS
197     //-------
198
199     public IStatusLineManager getStatusLineManager() {
200         IActionBars bars = getEditorSite().getActionBars();
201         IStatusLineManager mgr = bars.getStatusLineManager();
202         return mgr;
203     }
204
205     /**
206      * @param message <code>null</code> to remove message
207      */
208     public void setStatusMessage(String message) {
209         getStatusLineManager().setMessage(message);
210     }
211
212     /**
213      * @param message <code>null</code> to remove message
214      */
215     public void setStatusErrorMessage(String message) {
216         getStatusLineManager().setErrorMessage(message);
217     }
218
219     protected Resource getInputResource() {
220         return getResourceInput().getResource();
221     }
222
223     protected String getInputName() {
224         return getEditorInput().getName();
225     }
226
227     protected String getTitleText() {
228         return getInputName();
229     }
230
231     protected String getTitleTooltip() {
232         return getInputName();
233     }
234
235     protected void updateTitle() {
236         setPartName(getTitleText());
237         setTitleToolTip(getTitleTooltip());
238     }
239
240     /**
241      * A utility method for easier invocation of Runnables asynchronously in the
242      * SWT UI thread.
243      * 
244      * @param run
245      */
246     protected void asyncExec(Runnable run) {
247         getSite().getShell().getDisplay().asyncExec(run);
248     }
249
250     @SuppressWarnings("unchecked")
251     @Override
252     public <T> T getAdapter(Class<T> adapter) {
253         if (adapter == Session.class)
254             return (T) getSession();
255         return super.getAdapter(adapter);
256     }
257
258 }