]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorInput.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / ResourceEditorInput.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in 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.ui.workbench;\r
13 \r
14 import java.lang.ref.Reference;\r
15 import java.util.ArrayList;\r
16 import java.util.Collections;\r
17 import java.util.List;\r
18 \r
19 import org.eclipse.core.runtime.IAdaptable;\r
20 import org.eclipse.core.runtime.PlatformObject;\r
21 import org.eclipse.jface.resource.ImageDescriptor;\r
22 import org.eclipse.ui.IMemento;\r
23 import org.eclipse.ui.IPersistableElement;\r
24 import org.simantics.Simantics;\r
25 import org.simantics.db.ReadGraph;\r
26 import org.simantics.db.Resource;\r
27 import org.simantics.db.Session;\r
28 import org.simantics.db.common.ResourceArray;\r
29 import org.simantics.db.common.request.ReadRequest;\r
30 import org.simantics.db.exception.AdaptionException;\r
31 import org.simantics.db.exception.DatabaseException;\r
32 import org.simantics.db.service.LifecycleSupport;\r
33 import org.simantics.ui.icons.ImageDescriptorProvider;\r
34 import org.simantics.ui.workbench.editor.input.ResourceEditorInputMatchingStrategy;\r
35 import org.simantics.utils.ObjectUtils;\r
36 import org.simantics.utils.datastructures.cache.ProvisionException;\r
37 import org.simantics.utils.ui.ErrorLogger;\r
38 import org.simantics.utils.ui.workbench.StringMemento;\r
39 \r
40 /**\r
41  * A basic editor input for Simantics database {@link Resource} instances.\r
42  * \r
43  * Editor extensions requiring these as input should always use\r
44  * {@link ResourceEditorInputMatchingStrategy} as their matchingStrategy.\r
45  * \r
46  * @author Tuukka Lehtonen\r
47  * \r
48  * @see ResourceEditorInput2\r
49  * @see ResourceEditorInputMatchingStrategy\r
50  */\r
51 public class ResourceEditorInput extends PlatformObject implements IResourceEditorInput, IPersistableElement {\r
52 \r
53     static final String                        NO_NAME         = "(no name)";\r
54 \r
55     private final String                       editorID;\r
56 \r
57     private List<String>                       resourceIds;\r
58 \r
59     private transient Reference<ResourceArray> resources;\r
60 \r
61     private transient boolean                  exists;\r
62 \r
63     private transient String                   name;\r
64 \r
65     private transient String                   tooltip;\r
66 \r
67     private transient ImageDescriptor          imageDesc;\r
68 \r
69     /** Persistent memento for external data */\r
70     private final StringMemento                persistentStore = new StringMemento();\r
71 \r
72     /**\r
73      * @param editorID\r
74      * @param r\r
75      */\r
76     public ResourceEditorInput(String editorID, Resource r) {\r
77         this(editorID, new ResourceArray(r));\r
78     }\r
79 \r
80     /**\r
81      * @param editorID\r
82      * @param ra\r
83      */\r
84     public ResourceEditorInput(String editorID, ResourceArray ra) {\r
85         if (editorID == null)\r
86             throw new IllegalArgumentException("null editor id");\r
87         if (ra == null)\r
88             throw new IllegalArgumentException("null resource array");\r
89         if (ra.isEmpty())\r
90             throw new IllegalArgumentException("input resource array is empty, expected non-empty list");\r
91         for (Resource r : ra.resources)\r
92             if (r == null)\r
93                 throw new IllegalArgumentException("input resource array contains null resources: " + ra);\r
94 \r
95         this.editorID = editorID;\r
96         this.resources = ResourceInputs.makeReference(ra);\r
97         this.resourceIds = ResourceInputs.getRandomAccessIds(ra);\r
98 \r
99         setNonExistant();\r
100     }\r
101 \r
102     /**\r
103      * @param editorID\r
104      * @param randomAccessResourceId\r
105      */\r
106     public ResourceEditorInput(String editorID, String randomAccessResourceId) {\r
107         this(editorID, Collections.singletonList(randomAccessResourceId));\r
108     }\r
109 \r
110     /**\r
111      * @param editorID\r
112      * @param randomAccessResourceId a non-empty list of random access resource\r
113      *        ids\r
114      * @throws IllegalArgumentException if the specified random access id list\r
115      *         is <code>null</code> or empty\r
116      */\r
117     public ResourceEditorInput(String editorID, List<String> randomAccessResourceId) {\r
118         if (randomAccessResourceId == null)\r
119             throw new IllegalArgumentException("null resource id list");\r
120         if (randomAccessResourceId.isEmpty())\r
121             throw new IllegalArgumentException("input resource id list is empty, expected non-empty list");\r
122         for (String id : randomAccessResourceId)\r
123             if (id == null)\r
124                 throw new IllegalArgumentException("input resource id list contains null IDs: " + randomAccessResourceId);\r
125 \r
126         this.editorID = editorID;\r
127         if (editorID == null)\r
128             editorID = "";\r
129         this.resourceIds = Collections.unmodifiableList(new ArrayList<String>(randomAccessResourceId));\r
130         this.resources = ResourceInputs.makeReference(ResourceArray.EMPTY);\r
131 \r
132         setNonExistant();\r
133     }\r
134 \r
135     @Override\r
136     public void init(IAdaptable adapter) throws DatabaseException {\r
137         // Initialize resource array if at all possible\r
138         ResourceArray ra = getResourceArray();\r
139         if (!ra.isEmpty())\r
140             updateCaches(true);\r
141     }\r
142 \r
143     @Override\r
144     public void dispose() {\r
145         //System.out.println("dispose resource editor input: " + name);\r
146         // NOTE: this has to be done since Eclipse will cache these IEditorInput\r
147         // instances within EditorHistoryItem's that are stored in an EditorHistory\r
148         // instance. They are held by strong reference which means that the session\r
149         // cannot be collected if it is not nulled here.\r
150         resources = null;\r
151     }\r
152 \r
153     @Override\r
154     public boolean exists() {\r
155         return exists;\r
156     }\r
157 \r
158     @Override\r
159     public boolean exists(ReadGraph graph) throws DatabaseException {\r
160         for (Resource r : getResourceArray().resources)\r
161             if (!graph.hasStatement(r))\r
162                 return false;\r
163         return true;\r
164     }\r
165 \r
166     @Override\r
167     public Resource getResource() {\r
168         ResourceArray ra = getResourceArray();\r
169         return ra.isEmpty() ? null : ra.resources[0];\r
170     }\r
171 \r
172     public ResourceArray getResourceArray0() throws DatabaseException {\r
173         ResourceArray ra = tryGetResourceArray();\r
174         if (!ra.isEmpty())\r
175             return ra;\r
176 \r
177         Session s = ResourceInputs.peekSession();\r
178         if (s == null)\r
179             return ResourceArray.EMPTY;\r
180 \r
181         ra = ResourceInputs.makeResourceArray( s, resourceIds );\r
182         this.resources = ResourceInputs.makeReference( ra );\r
183         return ra;\r
184     }\r
185 \r
186     @Override\r
187     public ResourceArray getResourceArray() {\r
188         try {\r
189             return getResourceArray0();\r
190         } catch (DatabaseException e) {\r
191             ErrorLogger.defaultLogError(e);\r
192             return ResourceArray.EMPTY;\r
193         }\r
194     }\r
195 \r
196     /* (non-Javadoc)\r
197      * @see org.eclipse.ui.IEditorInput#getImageDescriptor()\r
198      */\r
199     @Override\r
200     public ImageDescriptor getImageDescriptor() {\r
201         return imageDesc;\r
202     }\r
203 \r
204     /* (non-Javadoc)\r
205      * @see org.eclipse.ui.IEditorInput#getName()\r
206      */\r
207     @Override\r
208     public String getName() {\r
209         return name;\r
210     }\r
211 \r
212     /* (non-Javadoc)\r
213      * @see org.eclipse.ui.IEditorInput#getToolTipText()\r
214      */\r
215     @Override\r
216     public String getToolTipText() {\r
217         return tooltip;\r
218     }\r
219 \r
220     /* (non-Javadoc)\r
221      * @see org.eclipse.ui.IEditorInput#getPersistable()\r
222      */\r
223     @Override\r
224     public IPersistableElement getPersistable() {\r
225         // Don't allow persistability when it's not possible.\r
226         if (!isPersistable())\r
227             return null;\r
228         return this;\r
229     }\r
230 \r
231     protected boolean isPersistable() {\r
232         Session session = Simantics.peekSession();\r
233         if (session == null)\r
234             return false;\r
235         LifecycleSupport lc = session.peekService(LifecycleSupport.class);\r
236         if (lc == null)\r
237             return false;\r
238         if (lc.isClosed())\r
239             return false;\r
240         return true;\r
241     }\r
242 \r
243     /* (non-Javadoc)\r
244      * @see org.eclipse.ui.IPersistableElement#getFactoryId()\r
245      */\r
246     @Override\r
247     public String getFactoryId() {\r
248         return ResourceEditorInputFactory.getFactoryId();\r
249     }\r
250 \r
251     /**\r
252      * Saves the state of the given resource editor input into the given memento.\r
253      *\r
254      * @param memento the storage area for element state\r
255      * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)\r
256      */\r
257     @Override\r
258     public void saveState(IMemento memento) {\r
259         for (String id : resourceIds) {\r
260             IMemento child = memento.createChild(ResourceEditorInputFactory.TAG_RESOURCE_ID);\r
261             child.putTextData(id);\r
262         }\r
263         memento.putString(ResourceEditorInputFactory.TAG_EDITOR_ID, editorID);\r
264         memento.putString(ResourceEditorInputFactory.TAG_EXTERNAL_MEMENTO_ID, persistentStore.toString());\r
265     }\r
266 \r
267     @Override\r
268     public int hashCode() {\r
269         final int prime = 31;\r
270         int result = 1;\r
271         result = prime * result + editorID.hashCode();\r
272         result = prime * result + ObjectUtils.hashCode(resourceIds);\r
273         return result;\r
274     }\r
275 \r
276     @Override\r
277     public boolean equals(Object obj) {\r
278         if (this == obj)\r
279             return true;\r
280         if (obj == null)\r
281             return false;\r
282         if (getClass() != obj.getClass())\r
283             return false;\r
284         final ResourceEditorInput other = (ResourceEditorInput) obj;\r
285         if (!editorID.equals(other.editorID))\r
286             return false;\r
287         if (!ObjectUtils.objectEquals(resourceIds, other.resourceIds))\r
288             return false;\r
289         return true;\r
290     }\r
291 \r
292     private void updateCaches(boolean sync) throws DatabaseException {\r
293         ReadRequest req = new ReadRequest() {\r
294             @Override\r
295             public void run(ReadGraph g) throws DatabaseException {\r
296                 update(g);\r
297             }\r
298         };\r
299         Session s = ResourceInputs.getSession();\r
300         if (sync) {\r
301             s.syncRequest(req);\r
302         } else {\r
303             s.asyncRequest(req);\r
304         }\r
305     }\r
306 \r
307     /* (non-Javadoc)\r
308      * @see org.simantics.ui.workbench.IResourceEditorInput#update(org.simantics.db.Graph)\r
309      */\r
310     @Override\r
311     public void update(ReadGraph g) throws DatabaseException {\r
312         Resource r = getResource();\r
313         if (r == null)\r
314             return;\r
315 \r
316         exists = g.hasStatement(r);\r
317         if (exists) {\r
318             name = g.syncRequest(new TitleRequest(editorID, this));\r
319             if (name == null)\r
320                 name = NO_NAME;\r
321 \r
322             tooltip = g.syncRequest(new ToolTipRequest(editorID, this));\r
323             if (tooltip == null)\r
324                 tooltip = NO_NAME;\r
325 \r
326             try {\r
327                 ImageDescriptorProvider idp = g.adapt(r, ImageDescriptorProvider.class);\r
328                 imageDesc = idp.get();\r
329             } catch (AdaptionException e) {\r
330                 imageDesc = ImageDescriptor.getMissingImageDescriptor();\r
331             } catch (ProvisionException e) {\r
332                 imageDesc = ImageDescriptor.getMissingImageDescriptor();\r
333                 ErrorLogger.defaultLogError(e);\r
334             }\r
335         } else {\r
336             setNonExistant();\r
337         }\r
338     }\r
339 \r
340     private void setNonExistant() {\r
341         exists = false;\r
342         tooltip = name = NO_NAME;\r
343         imageDesc = ImageDescriptor.getMissingImageDescriptor();\r
344     }\r
345 \r
346     public IMemento getPersistentStore() {\r
347         return persistentStore;\r
348     }\r
349 \r
350     @Override\r
351     public String toString() {\r
352         return getClass().getSimpleName() + " [name=" + getName() + ", resourceIds=" + resourceIds + ", resources=" + resources + "]";\r
353     }\r
354 \r
355     private ResourceArray tryGetResourceArray() {\r
356         Reference<ResourceArray> ref = resources;\r
357         if (ref == null)\r
358             return ResourceArray.EMPTY;\r
359         ResourceArray ra = ref.get();\r
360         return ra == null ? ResourceArray.EMPTY : ra;\r
361     }\r
362 \r
363 }