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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.ui.workbench;
\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
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
41 * A basic editor input for Simantics database {@link Resource} instances.
\r
43 * Editor extensions requiring these as input should always use
\r
44 * {@link ResourceEditorInputMatchingStrategy} as their matchingStrategy.
\r
46 * @author Tuukka Lehtonen
\r
48 * @see ResourceEditorInput2
\r
49 * @see ResourceEditorInputMatchingStrategy
\r
51 public class ResourceEditorInput extends PlatformObject implements IResourceEditorInput, IPersistableElement {
\r
53 static final String NO_NAME = "(no name)";
\r
55 private final String editorID;
\r
57 private List<String> resourceIds;
\r
59 private transient Reference<ResourceArray> resources;
\r
61 private transient boolean exists;
\r
63 private transient String name;
\r
65 private transient String tooltip;
\r
67 private transient ImageDescriptor imageDesc;
\r
69 /** Persistent memento for external data */
\r
70 private final StringMemento persistentStore = new StringMemento();
\r
76 public ResourceEditorInput(String editorID, Resource r) {
\r
77 this(editorID, new ResourceArray(r));
\r
84 public ResourceEditorInput(String editorID, ResourceArray ra) {
\r
85 if (editorID == null)
\r
86 throw new IllegalArgumentException("null editor id");
\r
88 throw new IllegalArgumentException("null resource array");
\r
90 throw new IllegalArgumentException("input resource array is empty, expected non-empty list");
\r
91 for (Resource r : ra.resources)
\r
93 throw new IllegalArgumentException("input resource array contains null resources: " + ra);
\r
95 this.editorID = editorID;
\r
96 this.resources = ResourceInputs.makeReference(ra);
\r
97 this.resourceIds = ResourceInputs.getRandomAccessIds(ra);
\r
104 * @param randomAccessResourceId
\r
106 public ResourceEditorInput(String editorID, String randomAccessResourceId) {
\r
107 this(editorID, Collections.singletonList(randomAccessResourceId));
\r
112 * @param randomAccessResourceId a non-empty list of random access resource
\r
114 * @throws IllegalArgumentException if the specified random access id list
\r
115 * is <code>null</code> or empty
\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
124 throw new IllegalArgumentException("input resource id list contains null IDs: " + randomAccessResourceId);
\r
126 this.editorID = editorID;
\r
127 if (editorID == null)
\r
129 this.resourceIds = Collections.unmodifiableList(new ArrayList<String>(randomAccessResourceId));
\r
130 this.resources = ResourceInputs.makeReference(ResourceArray.EMPTY);
\r
136 public void init(IAdaptable adapter) throws DatabaseException {
\r
137 // Initialize resource array if at all possible
\r
138 ResourceArray ra = getResourceArray();
\r
140 updateCaches(true);
\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
154 public boolean exists() {
\r
159 public boolean exists(ReadGraph graph) throws DatabaseException {
\r
160 for (Resource r : getResourceArray().resources)
\r
161 if (!graph.hasStatement(r))
\r
167 public Resource getResource() {
\r
168 ResourceArray ra = getResourceArray();
\r
169 return ra.isEmpty() ? null : ra.resources[0];
\r
172 public ResourceArray getResourceArray0() throws DatabaseException {
\r
173 ResourceArray ra = tryGetResourceArray();
\r
177 Session s = ResourceInputs.peekSession();
\r
179 return ResourceArray.EMPTY;
\r
181 ra = ResourceInputs.makeResourceArray( s, resourceIds );
\r
182 this.resources = ResourceInputs.makeReference( ra );
\r
187 public ResourceArray getResourceArray() {
\r
189 return getResourceArray0();
\r
190 } catch (DatabaseException e) {
\r
191 ErrorLogger.defaultLogError(e);
\r
192 return ResourceArray.EMPTY;
\r
197 * @see org.eclipse.ui.IEditorInput#getImageDescriptor()
\r
200 public ImageDescriptor getImageDescriptor() {
\r
205 * @see org.eclipse.ui.IEditorInput#getName()
\r
208 public String getName() {
\r
213 * @see org.eclipse.ui.IEditorInput#getToolTipText()
\r
216 public String getToolTipText() {
\r
221 * @see org.eclipse.ui.IEditorInput#getPersistable()
\r
224 public IPersistableElement getPersistable() {
\r
225 // Don't allow persistability when it's not possible.
\r
226 if (!isPersistable())
\r
231 protected boolean isPersistable() {
\r
232 Session session = Simantics.peekSession();
\r
233 if (session == null)
\r
235 LifecycleSupport lc = session.peekService(LifecycleSupport.class);
\r
244 * @see org.eclipse.ui.IPersistableElement#getFactoryId()
\r
247 public String getFactoryId() {
\r
248 return ResourceEditorInputFactory.getFactoryId();
\r
252 * Saves the state of the given resource editor input into the given memento.
\r
254 * @param memento the storage area for element state
\r
255 * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)
\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
263 memento.putString(ResourceEditorInputFactory.TAG_EDITOR_ID, editorID);
\r
264 memento.putString(ResourceEditorInputFactory.TAG_EXTERNAL_MEMENTO_ID, persistentStore.toString());
\r
268 public int hashCode() {
\r
269 final int prime = 31;
\r
271 result = prime * result + editorID.hashCode();
\r
272 result = prime * result + ObjectUtils.hashCode(resourceIds);
\r
277 public boolean equals(Object obj) {
\r
282 if (getClass() != obj.getClass())
\r
284 final ResourceEditorInput other = (ResourceEditorInput) obj;
\r
285 if (!editorID.equals(other.editorID))
\r
287 if (!ObjectUtils.objectEquals(resourceIds, other.resourceIds))
\r
292 private void updateCaches(boolean sync) throws DatabaseException {
\r
293 ReadRequest req = new ReadRequest() {
\r
295 public void run(ReadGraph g) throws DatabaseException {
\r
299 Session s = ResourceInputs.getSession();
\r
301 s.syncRequest(req);
\r
303 s.asyncRequest(req);
\r
308 * @see org.simantics.ui.workbench.IResourceEditorInput#update(org.simantics.db.Graph)
\r
311 public void update(ReadGraph g) throws DatabaseException {
\r
312 Resource r = getResource();
\r
316 exists = g.hasStatement(r);
\r
318 name = g.syncRequest(new TitleRequest(editorID, this));
\r
322 tooltip = g.syncRequest(new ToolTipRequest(editorID, this));
\r
323 if (tooltip == null)
\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
340 private void setNonExistant() {
\r
342 tooltip = name = NO_NAME;
\r
343 imageDesc = ImageDescriptor.getMissingImageDescriptor();
\r
346 public IMemento getPersistentStore() {
\r
347 return persistentStore;
\r
351 public String toString() {
\r
352 return getClass().getSimpleName() + " [name=" + getName() + ", resourceIds=" + resourceIds + ", resources=" + resources + "]";
\r
355 private ResourceArray tryGetResourceArray() {
\r
356 Reference<ResourceArray> ref = resources;
\r
358 return ResourceArray.EMPTY;
\r
359 ResourceArray ra = ref.get();
\r
360 return ra == null ? ResourceArray.EMPTY : ra;
\r