]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramEditor.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / DiagramEditor.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.ui.diagramEditor;\r
13 \r
14 import java.lang.reflect.Constructor;\r
15 \r
16 import org.eclipse.core.runtime.IConfigurationElement;\r
17 import org.eclipse.core.runtime.IExecutableExtension;\r
18 import org.eclipse.core.runtime.IProgressMonitor;\r
19 import org.eclipse.core.runtime.Platform;\r
20 import org.eclipse.swt.SWT;\r
21 import org.eclipse.swt.widgets.Composite;\r
22 import org.eclipse.ui.IEditorInput;\r
23 import org.eclipse.ui.IEditorSite;\r
24 import org.eclipse.ui.IPartListener2;\r
25 import org.eclipse.ui.IWorkbenchPart;\r
26 import org.eclipse.ui.IWorkbenchPartReference;\r
27 import org.eclipse.ui.PartInitException;\r
28 import org.eclipse.ui.PlatformUI;\r
29 import org.eclipse.ui.part.EditorPart;\r
30 import org.osgi.framework.Bundle;\r
31 import org.simantics.db.Resource;\r
32 import org.simantics.diagram.ui.WorkbenchSelectionProvider;\r
33 import org.simantics.g2d.diagram.IDiagram;\r
34 import org.simantics.modeling.ui.diagramEditor.DiagramViewer.DiagramViewerHost;\r
35 import org.simantics.ui.workbench.IResourceEditorInput;\r
36 import org.simantics.ui.workbench.IResourceEditorInput2;\r
37 import org.simantics.ui.workbench.IResourceEditorPart2;\r
38 import org.simantics.ui.workbench.ResourceEditorSupport;\r
39 import org.simantics.utils.DataContainer;\r
40 import org.simantics.utils.threads.IThreadWorkQueue;\r
41 import org.simantics.utils.threads.SWTThread;\r
42 import org.simantics.utils.ui.ErrorLogger;\r
43 \r
44 /**\r
45  * A class for diagram editor parts that contains logic for destruction and\r
46  * (re)initialization of the actual diagram viewer and its controls during the\r
47  * life cycle of this editor part.\r
48  * \r
49  * <p>\r
50  * To use this class in an editor part extension, define the following in the\r
51  * <code>class</code> attribute of the extension:\r
52  * \r
53  * <pre>\r
54  * class="org.simantics.modeling.ui.diagramEditor.DiagramEditor:viewer=%VIEWER%"\r
55  * </pre>\r
56  * \r
57  * where <code>%VIEWER%</code> is the name of the class that either is or\r
58  * extends {@link org.simantics.modeling.ui.diagramEditor.DiagramViewer}. The\r
59  * <code>viewer</code> argument tells {@link DiagramEditor} where to find the\r
60  * initializer for the diagram editor controls. The initializer must have a\r
61  * default constructor.\r
62  * \r
63  * <p>\r
64  * This class is not intended to be extended by clients. Customizations should\r
65  * be performed through the viewer class.\r
66  * \r
67  * @author Tuukka Lehtonen\r
68  * @author Antti Villberg\r
69  */\r
70 public class DiagramEditor extends EditorPart implements IResourceEditorPart2, IPartListener2, DiagramViewerHost, IExecutableExtension {\r
71 \r
72     /**\r
73      * The {@value #ARG_VIEWER} argument for this editor part class tells the\r
74      * name of the class to use for initializing the diagram viewer, i.e.\r
75      * {@link #viewer}. The class is instantiated through reflection using the\r
76      * class loader of the bundle named {@link #viewerContributor}.\r
77      * \r
78      * @see #setInitializationData(IConfigurationElement, String, Object)\r
79      */\r
80     public static final String    ARG_VIEWER = "viewer";\r
81 \r
82     private Composite             parent;\r
83 \r
84     private String                viewerContributor;\r
85     private String                viewerClassName;\r
86 \r
87     private ResourceEditorSupport support;\r
88     private DiagramViewer         viewer;\r
89 \r
90     /**\r
91      * Used for distributing the reference to the IDiagram eventually loaded by\r
92      * the diagram viewer to both the diagram viewer and\r
93      * {@link #createSelectionProvider()}. {@link DiagramViewerLoadJob} is what\r
94      * ultimately does the actual loading and sets this container's value.\r
95      * @see #createSelectionProvider()\r
96      * @see DiagramViewerLoadJob\r
97      */\r
98     protected DataContainer<IDiagram>    diagramContainer = new DataContainer<IDiagram>();\r
99     protected IThreadWorkQueue           swt;\r
100     protected WorkbenchSelectionProvider selectionProvider;\r
101 \r
102     /**\r
103      * Reads the class arguments from the string in the data argument.\r
104      * \r
105      * @see org.eclipse.ui.part.EditorPart#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,\r
106      *      java.lang.String, java.lang.Object)\r
107      * @see #createViewer()\r
108      */\r
109     @Override\r
110     public void setInitializationData(IConfigurationElement cfig, String propertyName, Object data) {\r
111         super.setInitializationData(cfig, propertyName, data);\r
112 \r
113         if (data instanceof String) {\r
114             viewerContributor = cfig.getContributor().getName();\r
115 \r
116             String[] parameters = ((String) data).split(";");\r
117 \r
118             for (String parameter : parameters) {\r
119                 String[] keyValue = parameter.split("=");\r
120                 if (keyValue.length > 2) {\r
121                     ErrorLogger.defaultLogWarning("Invalid parameter '" + parameter + ". Complete view argument: " + data, null);\r
122                     continue;\r
123                 }\r
124                 String key = keyValue[0];\r
125                 String value = keyValue.length > 1 ? keyValue[1] : "";\r
126 \r
127                 if (ARG_VIEWER.equals(key)) {\r
128                     viewerClassName = value;\r
129                 } \r
130             }\r
131         }\r
132     }\r
133 \r
134     protected DiagramViewer createViewer() throws PartInitException {\r
135         if (viewerClassName == null)\r
136             throw new PartInitException(\r
137                     "DiagramViewer contributor class was not specified in editor extension's class attribute viewer-argument. contributor is '"\r
138                             + viewerContributor + "'");\r
139 \r
140         try {\r
141             Bundle b = Platform.getBundle(viewerContributor);\r
142             if (b == null)\r
143                 throw new PartInitException("DiagramViewer '" + viewerClassName + "' contributor bundle '"\r
144                         + viewerContributor + "' was not found in the platform.");\r
145 \r
146             Class<?> clazz = b.loadClass(viewerClassName);\r
147             if (!DiagramViewer.class.isAssignableFrom(clazz))\r
148                 throw new PartInitException("DiagramViewer class '" + viewerClassName + "' is not assignable to "\r
149                         + DiagramViewer.class + ".");\r
150 \r
151             Constructor<?> ctor = clazz.getConstructor();\r
152             return (DiagramViewer) ctor.newInstance();\r
153         } catch (Exception e) {\r
154             throw new PartInitException("Failed to instantiate DiagramViewer implementation '" + viewerClassName\r
155                     + "' from bundle '" + viewerContributor + "'. See exception for details.", e);\r
156         }\r
157     }\r
158 \r
159     @Override\r
160     public IResourceEditorInput getResourceInput() {\r
161         return viewer.getResourceInput();\r
162     }\r
163 \r
164     @Override\r
165     public IResourceEditorInput2 getResourceInput2() {\r
166         return viewer.getResourceInput2();\r
167     }\r
168 \r
169     public DiagramViewer getViewer() {\r
170         return viewer;\r
171     }\r
172 \r
173     public Resource getRuntimeResource() {\r
174         DiagramViewer viewer = this.viewer;\r
175         return viewer != null ? viewer.getRuntime() : null;\r
176     }\r
177     \r
178     public Resource getInputResource() {\r
179         DiagramViewer viewer = this.viewer;\r
180         return viewer != null ? viewer.getInputResource() : null;\r
181     }\r
182 \r
183     @Override\r
184     public void doSave(IProgressMonitor monitor) {\r
185     }\r
186 \r
187     @Override\r
188     public void doSaveAs() {\r
189     }\r
190 \r
191     @Override\r
192     public boolean isDirty() {\r
193         return false;\r
194     }\r
195 \r
196     @Override\r
197     public boolean isSaveAsAllowed() {\r
198         return false;\r
199     }\r
200 \r
201     @Override\r
202     public void init(IEditorSite site, IEditorInput input) throws PartInitException {\r
203         setSite(site);\r
204         setInput(input);\r
205 \r
206         viewer = createViewer();\r
207 \r
208         // selectionProvider MUST be created and attached to the workbench site:\r
209         //   1. only once during the life-cycle of this editor part\r
210         //   2. in SWT UI thread\r
211         //   3. at least before returning from #createPartControl\r
212         swt = SWTThread.getThreadAccess(PlatformUI.getWorkbench().getDisplay());\r
213         selectionProvider = createSelectionProvider();\r
214 \r
215         viewer.init(this, site, input, diagramContainer, selectionProvider);\r
216 \r
217         getSite().getPage().addPartListener(this);\r
218 \r
219         support = new ResourceEditorSupport(this, viewer.getInputValidator());\r
220         support.activateValidation();\r
221     }\r
222 \r
223     @Override\r
224     public void createPartControl(Composite parent) {\r
225         this.parent = parent;\r
226         initializeViewer();\r
227     }\r
228 \r
229     private void initializeViewer() {\r
230         parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));\r
231         viewer.createPartControl(parent);\r
232         // It is possible that something goes wrong and the parent gets disposed already\r
233         if(parent.isDisposed()) return;\r
234         parent.layout(true);\r
235     }\r
236 \r
237     @Override\r
238     public void setFocus() {\r
239         if (viewer != null)\r
240             viewer.setFocus();\r
241     }\r
242 \r
243     /**\r
244      * Override this to customize the kind of selection provider created for\r
245      * this {@link DiagramEditor}.\r
246      * \r
247      * @return the selection provider to set for the site\r
248      */\r
249     protected WorkbenchSelectionProvider createSelectionProvider() {\r
250         return new DiagramViewerSelectionProvider(swt, getSite(), diagramContainer);\r
251     }\r
252 \r
253     @SuppressWarnings("unchecked")\r
254     public <T> T getAdapter(Class<T> adapter) {\r
255         if (adapter == DiagramViewer.class)\r
256             return (T) viewer;\r
257         if (viewer == null)\r
258             return (T) super.getAdapter(adapter);\r
259 \r
260         Object result = viewer.getAdapter(adapter);\r
261         if (result != null)\r
262             return (T) result;\r
263         return super.getAdapter(adapter);\r
264     }\r
265 \r
266     @Override\r
267     public void dispose() {\r
268         getSite().getPage().removePartListener(this);\r
269 \r
270         if (support != null) {\r
271             support.dispose();\r
272             support = null;\r
273         }\r
274 \r
275         DISPOSING_POLICY.removeDisposer(disposer);\r
276         tryDisposeViewer();\r
277 \r
278         super.dispose();\r
279     }\r
280 \r
281     @Override\r
282     public void doSetPartName(String name) {\r
283         setPartName(name);\r
284     }\r
285 \r
286     @Override\r
287     public void doSetTitleToolTip(String name) {\r
288         setTitleToolTip(name);\r
289     }\r
290 \r
291     // BEGIN: IPartListener2 implementation\r
292 \r
293     @Override\r
294     public void partActivated(IWorkbenchPartReference partRef) {\r
295     }\r
296 \r
297     @Override\r
298     public void partBroughtToTop(IWorkbenchPartReference partRef) {\r
299     }\r
300 \r
301     @Override\r
302     public void partClosed(IWorkbenchPartReference partRef) {\r
303     }\r
304 \r
305     @Override\r
306     public void partDeactivated(IWorkbenchPartReference partRef) {\r
307     }\r
308 \r
309     @Override\r
310     public void partOpened(IWorkbenchPartReference partRef) {\r
311     }\r
312 \r
313     /**\r
314      * Disposes of the diagram viewer if not already disposed.\r
315      */\r
316     @Override\r
317     public void partHidden(IWorkbenchPartReference partRef) {\r
318         IWorkbenchPart part = partRef.getPart(false);\r
319         if (this.equals(part)) {\r
320             DISPOSING_POLICY.addDisposer(disposer);\r
321         }\r
322     }\r
323     \r
324     private static final DisposingPolicy DISPOSING_POLICY = \r
325             new DisposingPolicy();\r
326     \r
327     private Runnable disposer = new Runnable() {\r
328         @Override\r
329         public void run() {\r
330             tryDisposeViewer();\r
331         }\r
332     };\r
333 \r
334     private void tryDisposeViewer() {\r
335         if (viewer != null) {\r
336             Composite viewerComposite = viewer.getComposite();\r
337             viewer.dispose();\r
338             viewer = null;\r
339             if (viewerComposite != null) {\r
340                 viewerComposite.dispose();\r
341             }\r
342         }\r
343     }\r
344     \r
345     /**\r
346      * Initializes the diagram viewer if not already initialized.\r
347      */\r
348     @Override\r
349     public void partVisible(IWorkbenchPartReference partRef) {\r
350         IWorkbenchPart part = partRef.getPart(false);\r
351         if (this.equals(part)) {\r
352             DISPOSING_POLICY.removeDisposer(disposer);\r
353             if (viewer == null) {\r
354                 try {\r
355                     viewer = createViewer();\r
356                     viewer.init(this, getEditorSite(), getEditorInput(), diagramContainer, selectionProvider);\r
357                     initializeViewer();\r
358                 } catch (PartInitException e) {\r
359                     // This should never happen!\r
360                     ErrorLogger.defaultLogError(e);\r
361                 }\r
362             }\r
363         }\r
364     }\r
365 \r
366     @Override\r
367     public void partInputChanged(IWorkbenchPartReference partRef) {\r
368     }\r
369 \r
370     // END: IPartListener2 implementation\r
371 \r
372 }\r