1 /*******************************************************************************
2 * Copyright (c) 2007, 2013 Association for Decentralized Information Management
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
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;
15 import gnu.trove.map.hash.THashMap;
17 import java.util.ArrayList;
18 import java.util.List;
20 import java.util.concurrent.CopyOnWriteArrayList;
21 import java.util.concurrent.atomic.AtomicBoolean;
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;
54 * ResourceLabelProvider is a label provider for Simantics database
58 * This label provider utilizes {@link ImageDescriptorProvider} adapters for
59 * determining the icon to use.
61 * @author Toni Kalajainen
62 * @author Tuukka Lehtonen
66 * @see ILabelProviderListener
68 public class ResourceLabelProvider implements ILabelProvider {
70 protected List<ILabelProviderListener> listeners = null;
71 protected IThreadWorkQueue thread;
72 protected TaskRepository tasks;
73 protected LoadJob loadJob;
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);
81 public void fireChangedEvent(LabelProviderChangedEvent e) {
82 ILabelProviderListener[] listeners;
84 if (this.listeners == null)
86 listeners = this.listeners.toArray(new ILabelProviderListener[0]);
88 for (ILabelProviderListener l : listeners)
89 l.labelProviderChanged(e);
92 public void asyncFireChangedEvent(final LabelProviderChangedEvent e) {
93 thread.asyncExec(new Runnable() {
101 public synchronized void addListener(ILabelProviderListener listener) {
102 if (listeners == null)
103 listeners = new CopyOnWriteArrayList<ILabelProviderListener>();
104 listeners.add(listener);
107 public void dispose() {
108 if (listeners != null)
114 public void clear() {
118 public boolean isLabelProperty(Object element, String property) {
119 System.out.println("isLabelProperty(" + element + ", " + property + ")");
123 public synchronized void removeListener(ILabelProviderListener listener) {
124 if (listeners != null)
125 listeners.remove(listener);
129 public Image getImage(Object element) {
132 Resource r = (Resource) element;
133 Task task = tasks.getCompleted(r);
137 task = tasks.queue(r);
138 loadJob.scheduleIfNecessary(100);
143 public String getText(Object element) {
146 Resource r = (Resource) element;
147 Task task = tasks.getCompleted(r);
151 task = tasks.queue(r);
152 loadJob.scheduleIfNecessary(100);
156 private static class LoadJob extends DatabaseJob {
157 private TaskRepository tasks;
158 private ResourceLabelProvider labelProvider;
159 private AtomicBoolean isScheduled = new AtomicBoolean();
161 public LoadJob(String name, TaskRepository tasks, ResourceLabelProvider labelProvider) {
166 setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE);
168 this.labelProvider = labelProvider;
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()}.
176 * @return <code>true</code> if scheduled, <code>false</code> otherwise
178 public boolean scheduleIfNecessary(long delay) {
179 if (isScheduled.compareAndSet(false, true)) {
188 labelProvider = null;
192 public boolean shouldSchedule() {
193 return tasks != null;
197 public boolean shouldRun() {
198 return tasks != null;
202 protected IStatus run(IProgressMonitor monitor) {
204 isScheduled.set(false);
206 TaskRepository tr = tasks;
208 return Status.CANCEL_STATUS;
210 Task[] taskList = tr.pruneTasks();
211 return runTasks(tr, taskList);
217 private IStatus runTasks(final TaskRepository tr, final Task[] taskList) {
218 Session session = Simantics.peekSession();
220 return Status.CANCEL_STATUS;
221 final ResourceManager rm = tr.resourceManager;
223 return Status.CANCEL_STATUS;
225 final MultiStatus result = new MultiStatus(Activator.PLUGIN_ID, 0, "Problems encountered while invoking resource label provider:", null);
227 Simantics.getSession().syncRequest(new ReadRequest() {
229 public void run(ReadGraph graph) throws DatabaseException {
230 for (Task task : taskList) {
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));
244 } catch (DatabaseException e) {
245 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Resource label provider failed unexpectedly.", e);
247 labelProvider.asyncFireChangedEvent(new LabelProviderChangedEvent(labelProvider));
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);
256 protected String getText(ReadGraph graph, Resource resource) {
258 return graph.adapt(resource, String.class);
259 } catch (DatabaseException e) {
261 return NameUtils.getSafeName(graph, resource);
262 } catch (DatabaseException e2) {
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);
273 public ImageDescriptor getImageDescriptor(ReadGraph graph, Resource resource, ImageDescriptor... decorations)
274 throws DatabaseException {
275 ImageDescriptor baseImage = ImageUtil.adaptImageDescriptor(graph, resource);
276 if (baseImage == null)
278 if (decorations == null || decorations.length == 0)
280 List<ImageDescriptor> images = new ArrayList<ImageDescriptor>(1+decorations.length);
281 images.add(baseImage);
282 for (ImageDescriptor image : decorations)
284 return CompositionImageDescriptor.compose(images);
289 private static class TaskRepository {
290 Map<Resource, Task> tasks = new THashMap<Resource, Task>();
291 Map<Resource, Task> completed = new THashMap<Resource, Task>();
293 ResourceManager resourceManager;
295 public TaskRepository(Device device) {
296 this.resourceManager = new DeviceResourceManager(device);
299 public boolean isDisposed() {
300 return resourceManager == null;
303 public void dispose() {
304 if (resourceManager != null) {
305 resourceManager.dispose();
306 resourceManager = null;
310 public Task queue(Task task) {
311 synchronized (tasks) {
312 tasks.put(task.resource, task);
317 public Task queue(Resource resource) {
318 return queue(new Task(resource));
321 public void clear() {
326 public Task[] pruneTasks() {
327 synchronized (tasks) {
328 Task[] result = tasks.values().toArray(Task.NONE);
334 public void pruneCompleted() {
335 synchronized (completed) {
340 public void complete(Task task) {
341 synchronized (completed) {
342 completed.put(task.resource, task);
346 public Task getCompleted(Resource r) {
347 synchronized (completed) {
348 return completed.get(r);
354 private static class Task {
355 public static final Task[] NONE = {};
357 public final Resource resource;
358 public String label = "";
361 public Task(Resource resource) {
362 this.resource = resource;