]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.ui/src/org/simantics/ui/workbench/dialogs/ResourceLabelProvider.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / dialogs / ResourceLabelProvider.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 - index based searching (#4255)
12  *******************************************************************************/
13 package org.simantics.ui.workbench.dialogs;
14
15 import gnu.trove.map.hash.THashMap;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.concurrent.CopyOnWriteArrayList;
21 import java.util.concurrent.atomic.AtomicBoolean;
22
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.MultiStatus;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.core.runtime.jobs.Job;
28 import org.eclipse.jface.resource.DeviceResourceManager;
29 import org.eclipse.jface.resource.ImageDescriptor;
30 import org.eclipse.jface.resource.ResourceManager;
31 import org.eclipse.jface.viewers.ILabelProvider;
32 import org.eclipse.jface.viewers.ILabelProviderListener;
33 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
34 import org.eclipse.swt.graphics.Device;
35 import org.eclipse.swt.graphics.Image;
36 import org.eclipse.swt.widgets.Display;
37 import org.eclipse.ui.progress.IProgressConstants;
38 import org.simantics.DatabaseJob;
39 import org.simantics.Simantics;
40 import org.simantics.db.ReadGraph;
41 import org.simantics.db.Resource;
42 import org.simantics.db.Session;
43 import org.simantics.db.common.request.ReadRequest;
44 import org.simantics.db.common.utils.NameUtils;
45 import org.simantics.db.exception.DatabaseException;
46 import org.simantics.ui.icons.ImageDescriptorProvider;
47 import org.simantics.ui.icons.ImageUtil;
48 import org.simantics.ui.internal.Activator;
49 import org.simantics.utils.threads.IThreadWorkQueue;
50 import org.simantics.utils.threads.SWTThread;
51 import org.simantics.utils.ui.gfx.CompositionImageDescriptor;
52
53 /**
54  * ResourceLabelProvider is a label provider for Simantics database
55  * {@link Resource}s.
56  * 
57  * <p>
58  * This label provider utilizes {@link ImageDescriptorProvider} adapters for
59  * determining the icon to use.
60  * 
61  * @author Toni Kalajainen
62  * @author Tuukka Lehtonen
63  * 
64  * @see Resource
65  * @see ILabelProvider
66  * @see ILabelProviderListener
67  */
68 public class ResourceLabelProvider implements ILabelProvider {
69
70     protected List<ILabelProviderListener> listeners = null;
71     protected IThreadWorkQueue thread;
72     protected TaskRepository tasks;
73     protected LoadJob loadJob;
74
75     public ResourceLabelProvider(Display display) {
76         this.thread = SWTThread.getThreadAccess(display);
77         this.tasks = new TaskRepository(display);
78         this.loadJob = new LoadJob("Resource Labeler", tasks, this);
79     }
80
81     public void fireChangedEvent(LabelProviderChangedEvent e) {
82         ILabelProviderListener[] listeners;
83         synchronized(this) {
84             if (this.listeners == null)
85                 return;
86             listeners = this.listeners.toArray(new ILabelProviderListener[0]);
87         }
88         for (ILabelProviderListener l : listeners)
89             l.labelProviderChanged(e);
90     }
91
92     public void asyncFireChangedEvent(final LabelProviderChangedEvent e) {
93         thread.asyncExec(new Runnable() {
94             @Override
95             public void run() {
96                 fireChangedEvent(e);
97             }
98         });
99     }
100
101     public synchronized void addListener(ILabelProviderListener listener) {
102         if (listeners == null)
103             listeners = new CopyOnWriteArrayList<ILabelProviderListener>();
104         listeners.add(listener);
105     }
106
107     public void dispose() {
108         if (listeners != null)
109             listeners.clear();
110         loadJob.dispose();
111         tasks.dispose();
112     }
113
114     public void clear() {
115         tasks.clear();
116     }
117
118     public boolean isLabelProperty(Object element, String property) {
119         System.out.println("isLabelProperty(" + element + ", " + property + ")");
120         return false;
121     }
122
123     public synchronized void removeListener(ILabelProviderListener listener) {
124         if (listeners != null)
125             listeners.remove(listener);
126     }
127
128     @Override
129     public Image getImage(Object element) {
130         if (element == null)
131             return null;
132         Resource r = (Resource) element;
133         Task task = tasks.getCompleted(r);
134         if (task != null) {
135             return task.image;
136         }
137         task = tasks.queue(r);
138         loadJob.scheduleIfNecessary(100);
139         return task.image;
140     }
141
142     @Override
143     public String getText(Object element) {
144         if (element == null)
145             return null;
146         Resource r = (Resource) element;
147         Task task = tasks.getCompleted(r);
148         if (task != null) {
149             return task.label;
150         }
151         task = tasks.queue(r);
152         loadJob.scheduleIfNecessary(100);
153         return task.label;
154     }
155
156     private static class LoadJob extends DatabaseJob {
157         private TaskRepository tasks;
158         private ResourceLabelProvider labelProvider;
159         private AtomicBoolean isScheduled = new AtomicBoolean();
160
161         public LoadJob(String name, TaskRepository tasks, ResourceLabelProvider labelProvider) {
162             super(name);
163             setUser(false);
164             setSystem(true);
165             setPriority(SHORT);
166             setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE);
167             this.tasks = tasks;
168             this.labelProvider = labelProvider;
169         }
170
171         /**
172          * Schedules the job with {@link Job#schedule()} if necessary, i.e. if
173          * not already scheduled. This method avoids some unnecessary overhead
174          * caused by repeatedly invoking {@link Job#schedule()}.
175          * 
176          * @return <code>true</code> if scheduled, <code>false</code> otherwise
177          */
178         public boolean scheduleIfNecessary(long delay) {
179             if (isScheduled.compareAndSet(false, true)) {
180                 schedule(delay);
181                 return true;
182             }
183             return false;
184         }
185
186         void dispose() {
187             tasks = null;
188             labelProvider = null;
189         }
190
191         @Override
192         public boolean shouldSchedule() {
193             return tasks != null;
194         }
195
196         @Override
197         public boolean shouldRun() {
198             return tasks != null;
199         }
200
201         @Override
202         protected IStatus run(IProgressMonitor monitor) {
203             try {
204                 isScheduled.set(false);
205
206                 TaskRepository tr = tasks;
207                 if (tr == null)
208                     return Status.CANCEL_STATUS;
209
210                 Task[] taskList = tr.pruneTasks();
211                 return runTasks(tr, taskList);
212             } finally {
213                 monitor.done();
214             }
215         }
216
217         private IStatus runTasks(final TaskRepository tr, final Task[] taskList) {
218             Session session = Simantics.peekSession();
219             if (session == null)
220                 return Status.CANCEL_STATUS;
221             final ResourceManager rm = tr.resourceManager;
222             if (rm == null)
223                 return Status.CANCEL_STATUS;
224
225             final MultiStatus result = new MultiStatus(Activator.PLUGIN_ID, 0, "Problems encountered while invoking resource label provider:", null);
226             try {
227                 Simantics.getSession().syncRequest(new ReadRequest() {
228                     @Override
229                     public void run(ReadGraph graph) throws DatabaseException {
230                         for (Task task : taskList) {
231                             try {
232                                 if (tr.isDisposed())
233                                     return;
234
235                                 runTask(rm, graph, task);
236                                 tasks.complete(task);
237                             } catch (DatabaseException e) {
238                                 result.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e));
239                             }
240                         }
241                     }
242                 });
243                 return result;
244             } catch (DatabaseException e) {
245                 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Resource label provider failed unexpectedly.", e);
246             } finally {
247                 labelProvider.asyncFireChangedEvent(new LabelProviderChangedEvent(labelProvider));
248             }
249         }
250
251         protected void runTask(ResourceManager rm, ReadGraph graph, Task task) throws DatabaseException {
252             task.label = getText(graph, task.resource);
253             task.image = getImage(rm, graph, task.resource);
254         }
255
256         protected String getText(ReadGraph graph, Resource resource) {
257             try {
258                 return graph.adapt(resource, String.class);
259             } catch (DatabaseException e) {
260                 try {
261                     return NameUtils.getSafeName(graph, resource);
262                 } catch (DatabaseException e2) {
263                     return "";
264                 }
265             }
266         }
267
268         public Image getImage(ResourceManager rm, ReadGraph graph, Resource resource) throws DatabaseException {
269             ImageDescriptor i = getImageDescriptor(graph, resource);
270             return i == null ? null : (Image) rm.get(i);
271         }
272
273         public ImageDescriptor getImageDescriptor(ReadGraph graph, Resource resource, ImageDescriptor... decorations)
274                 throws DatabaseException {
275             ImageDescriptor baseImage = ImageUtil.adaptImageDescriptor(graph, resource);
276             if (baseImage == null)
277                 return null;
278             if (decorations == null || decorations.length == 0)
279                 return baseImage;
280             List<ImageDescriptor> images = new ArrayList<ImageDescriptor>(1+decorations.length);
281             images.add(baseImage);
282             for (ImageDescriptor image : decorations)
283                 images.add(image);
284             return CompositionImageDescriptor.compose(images);
285         }
286
287     }
288
289     private static class TaskRepository {
290         Map<Resource, Task> tasks = new THashMap<Resource, Task>();
291         Map<Resource, Task> completed = new THashMap<Resource, Task>();
292
293         ResourceManager resourceManager;
294
295         public TaskRepository(Device device) {
296             this.resourceManager = new DeviceResourceManager(device);
297         }
298
299         public boolean isDisposed() {
300             return resourceManager == null;
301         }
302
303         public void dispose() {
304             if (resourceManager != null) {
305                 resourceManager.dispose();
306                 resourceManager = null;
307             }
308         }
309
310         public Task queue(Task task) {
311             synchronized (tasks) {
312                 tasks.put(task.resource, task);
313             }
314             return task;
315         }
316
317         public Task queue(Resource resource) {
318             return queue(new Task(resource));
319         }
320
321         public void clear() {
322             pruneTasks();
323             pruneCompleted();
324         }
325
326         public Task[] pruneTasks() {
327             synchronized (tasks) {
328                 Task[] result = tasks.values().toArray(Task.NONE);
329                 tasks.clear();
330                 return result;
331             }
332         }
333
334         public void pruneCompleted() {
335             synchronized (completed) {
336                 completed.clear();
337             }
338         }
339
340         public void complete(Task task) {
341             synchronized (completed) {
342                  completed.put(task.resource, task);
343             }
344         }
345
346         public Task getCompleted(Resource r) {
347             synchronized (completed) {
348                 return completed.get(r);
349             }
350         }
351
352     }
353
354     private static class Task {
355         public static final Task[] NONE = {};
356
357         public final Resource resource;
358         public String label = "";
359         public Image image;
360
361         public Task(Resource resource) {
362             this.resource = resource;
363         }
364     }
365
366 }