8
|
1 /*******************************************************************************
|
|
2 * Copyright (c) 2004, 2006 IBM Corporation and others.
|
|
3 * All rights reserved. This program and the accompanying materials
|
|
4 * are made available under the terms of the Eclipse Public License v1.0
|
|
5 * which accompanies this distribution, and is available at
|
|
6 * http://www.eclipse.org/legal/epl-v10.html
|
|
7 *
|
|
8 * Contributors:
|
|
9 * IBM Corporation - initial API and implementation
|
|
10 * Port to the D programming language:
|
|
11 * Frank Benoit <benoit@tionex.de>
|
|
12 *******************************************************************************/
|
|
13 module dwtx.jface.resource.ResourceManager;
|
|
14
|
|
15 import dwtx.jface.resource.DeviceResourceDescriptor;
|
|
16 import dwtx.jface.resource.ImageDescriptor;
|
|
17 import dwtx.jface.resource.ColorDescriptor;
|
|
18 import dwtx.jface.resource.FontDescriptor;
|
|
19 import dwtx.jface.resource.DeviceResourceException;
|
|
20 import dwtx.jface.resource.RGBColorDescriptor;
|
|
21
|
|
22 // import java.util.ArrayList;
|
|
23 import tango.util.collection.model.Seq;
|
|
24 import tango.util.collection.ArraySeq;
|
|
25
|
|
26 import dwt.DWTException;
|
|
27 import dwt.graphics.Color;
|
|
28 import dwt.graphics.Device;
|
|
29 import dwt.graphics.Font;
|
|
30 import dwt.graphics.Image;
|
|
31 import dwt.graphics.RGB;
|
|
32 import dwtx.core.runtime.Assert;
|
|
33 import dwtx.core.runtime.IStatus;
|
|
34 import dwtx.core.runtime.Status;
|
|
35 import dwtx.jface.util.Policy;
|
|
36
|
|
37 import dwt.dwthelper.utils;
|
|
38 import dwt.dwthelper.Runnable;
|
|
39
|
|
40 /**
|
|
41 * This class manages DWT resources. It manages reference-counted instances of resources
|
|
42 * such as Fonts, Images, and Colors, and allows them to be accessed using descriptors.
|
|
43 * Everything allocated through the registry should also be disposed through the registry.
|
|
44 * Since the resources are shared and reference counted, they should never be disposed
|
|
45 * directly.
|
|
46 * <p>
|
|
47 * ResourceManager handles correct allocation and disposal of resources. It differs from
|
|
48 * the various JFace *Registry classes, which also map symbolic IDs onto resources. In
|
|
49 * general, you should use a *Registry class to map IDs onto descriptors, and use a
|
|
50 * ResourceManager to convert the descriptors into real Images/Fonts/etc.
|
|
51 * </p>
|
|
52 *
|
|
53 * @since 3.1
|
|
54 */
|
|
55 public abstract class ResourceManager {
|
|
56
|
|
57 /**
|
|
58 * List of Runnables scheduled to run when the ResourceManager is disposed.
|
|
59 * null if empty.
|
|
60 */
|
|
61 private Seq!(Runnable) disposeExecs = null;
|
|
62
|
|
63 /**
|
|
64 * Returns the Device for which this ResourceManager will create resources
|
|
65 *
|
|
66 * @since 3.1
|
|
67 *
|
|
68 * @return the Device associated with this ResourceManager
|
|
69 */
|
|
70 public abstract Device getDevice();
|
|
71
|
|
72 /**
|
|
73 * Returns the resource described by the given descriptor. If the resource already
|
|
74 * exists, the reference count is incremented and the exiting resource is returned.
|
|
75 * Otherwise, a new resource is allocated. Every call to this method should have
|
|
76 * a corresponding call to {@link #destroy(DeviceResourceDescriptor)}.
|
|
77 *
|
|
78 * <p>If the resource is intended to live for entire lifetime of the resource manager,
|
|
79 * a subsequent call to {@link #destroy(DeviceResourceDescriptor)} may be omitted and the
|
|
80 * resource will be cleaned up when the resource manager is disposed. This pattern
|
|
81 * is useful for short-lived {@link LocalResourceManager}s, but should never be used
|
|
82 * with the global resource manager since doing so effectively leaks the resource.</p>
|
|
83 *
|
|
84 * <p>The resources returned from this method are reference counted and may be shared
|
|
85 * internally with other resource managers. They should never be disposed outside of the
|
|
86 * ResourceManager framework, or it will cause exceptions in other code that shares
|
|
87 * them. For example, never call {@link dwt.graphics.Resource#dispose()}
|
|
88 * on anything returned from this method.</p>
|
|
89 *
|
|
90 * <p>Callers may safely downcast the result to the resource type associated with
|
|
91 * the descriptor. For example, when given an ImageDescriptor, the return
|
|
92 * value of this method will always be an Image.</p>
|
|
93 *
|
|
94 * @since 3.1
|
|
95 *
|
|
96 * @param descriptor descriptor for the resource to allocate
|
|
97 * @return the newly allocated resource (not null)
|
|
98 * @throws DeviceResourceException if unable to allocate the resource
|
|
99 */
|
|
100 public abstract Object create(DeviceResourceDescriptor descriptor);
|
|
101
|
|
102 /**
|
|
103 * Deallocates a resource previously allocated by {@link #create(DeviceResourceDescriptor)}.
|
|
104 * Descriptors are compared by equality, not identity. If the same resource was
|
|
105 * created multiple times, this may decrement a reference count rather than
|
|
106 * disposing the actual resource.
|
|
107 *
|
|
108 * @since 3.1
|
|
109 *
|
|
110 * @param descriptor identifier for the resource
|
|
111 */
|
|
112 public abstract void destroy(DeviceResourceDescriptor descriptor);
|
|
113
|
|
114 /**
|
|
115 * <p>Returns a previously-allocated resource or allocates a new one if none
|
|
116 * exists yet. The resource will remain allocated for at least the lifetime
|
|
117 * of this resource manager. If necessary, the resource will be deallocated
|
|
118 * automatically when the resource manager is disposed.</p>
|
|
119 *
|
|
120 * <p>The resources returned from this method are reference counted and may be shared
|
|
121 * internally with other resource managers. They should never be disposed outside of the
|
|
122 * ResourceManager framework, or it will cause exceptions in other code that shares
|
|
123 * them. For example, never call {@link dwt.graphics.Resource#dispose()}
|
|
124 * on anything returned from this method.</p>
|
|
125 *
|
|
126 * <p>
|
|
127 * Callers may safely downcast the result to the resource type associated with
|
|
128 * the descriptor. For example, when given an ImageDescriptor, the return
|
|
129 * value of this method may be downcast to Image.
|
|
130 * </p>
|
|
131 *
|
|
132 * <p>
|
|
133 * This method should only be used for resources that should remain
|
|
134 * allocated for the lifetime of the resource manager. To allocate shorter-lived
|
|
135 * resources, manage them with <code>create</code>, and <code>destroy</code>
|
|
136 * rather than this method.
|
|
137 * </p>
|
|
138 *
|
|
139 * <p>
|
|
140 * This method should never be called on the global resource manager,
|
|
141 * since all resources will remain allocated for the lifetime of the app and
|
|
142 * will be effectively leaked.
|
|
143 * </p>
|
|
144 *
|
|
145 * @param descriptor identifier for the requested resource
|
|
146 * @return the requested resource. Never null.
|
|
147 * @throws DeviceResourceException if the resource does not exist yet and cannot
|
|
148 * be created for any reason.
|
|
149 *
|
|
150 * @since 3.3
|
|
151 */
|
|
152 public final Object get(DeviceResourceDescriptor descriptor) {
|
|
153 Object result = find(descriptor);
|
|
154
|
|
155 if (result is null) {
|
|
156 result = create(descriptor);
|
|
157 }
|
|
158
|
|
159 return result;
|
|
160 }
|
|
161
|
|
162 /**
|
|
163 * <p>Creates an image, given an image descriptor. Images allocated in this manner must
|
|
164 * be disposed by {@link #destroyImage(ImageDescriptor)}, and never by calling
|
|
165 * {@link Image#dispose()}.</p>
|
|
166 *
|
|
167 * <p>
|
|
168 * If the image is intended to remain allocated for the lifetime of the ResourceManager,
|
|
169 * the call to destroyImage may be omitted and the image will be cleaned up automatically
|
|
170 * when the ResourceManager is disposed. This should only be done with short-lived ResourceManagers,
|
|
171 * as doing so with the global manager effectively leaks the resource.
|
|
172 * </p>
|
|
173 *
|
|
174 * @since 3.1
|
|
175 *
|
|
176 * @param descriptor descriptor for the image to create
|
|
177 * @return the Image described by this descriptor (possibly shared by other equivalent
|
|
178 * ImageDescriptors)
|
|
179 * @throws DeviceResourceException if unable to allocate the Image
|
|
180 */
|
|
181 public final Image createImage(ImageDescriptor descriptor) {
|
|
182 // Assertion added to help diagnose client bugs. See bug #83711 and bug #90454.
|
|
183 Assert.isNotNull(descriptor);
|
|
184
|
|
185 return cast(Image)create(descriptor);
|
|
186 }
|
|
187
|
|
188 /**
|
|
189 * Creates an image, given an image descriptor. Images allocated in this manner must
|
|
190 * be disposed by {@link #destroyImage(ImageDescriptor)}, and never by calling
|
|
191 * {@link Image#dispose()}.
|
|
192 *
|
|
193 * @since 3.1
|
|
194 *
|
|
195 * @param descriptor descriptor for the image to create
|
|
196 * @return the Image described by this descriptor (possibly shared by other equivalent
|
|
197 * ImageDescriptors)
|
|
198 */
|
|
199 public final Image createImageWithDefault(ImageDescriptor descriptor) {
|
|
200 if (descriptor is null) {
|
|
201 return getDefaultImage();
|
|
202 }
|
|
203
|
|
204 try {
|
|
205 return cast(Image) create(descriptor);
|
|
206 } catch (DeviceResourceException e) {
|
|
207 Policy.getLog().log(
|
|
208 new Status(IStatus.WARNING, "dwtx.jface", 0, //$NON-NLS-1$
|
|
209 "The image could not be loaded: " ~ descriptor.toString, //$NON-NLS-1$
|
|
210 e));
|
|
211 return getDefaultImage();
|
|
212 } catch (DWTException e) {
|
|
213 Policy.getLog().log(
|
|
214 new Status(IStatus.WARNING, "dwtx.jface", 0, //$NON-NLS-1$
|
|
215 "The image could not be loaded: " ~ descriptor.toString, //$NON-NLS-1$
|
|
216 e));
|
|
217 return getDefaultImage();
|
|
218 }
|
|
219 }
|
|
220
|
|
221 /**
|
|
222 * Returns the default image that will be returned in the event that the intended
|
|
223 * image is missing.
|
|
224 *
|
|
225 * @since 3.1
|
|
226 *
|
|
227 * @return a default image that will be returned in the event that the intended
|
|
228 * image is missing.
|
|
229 */
|
|
230 protected abstract Image getDefaultImage();
|
9
|
231 package Image getDefaultImage_(){
|
|
232 return getDefaultImage();
|
|
233 }
|
8
|
234
|
|
235 /**
|
|
236 * Undoes everything that was done by {@link #createImage(ImageDescriptor)}.
|
|
237 *
|
|
238 * @since 3.1
|
|
239 *
|
|
240 * @param descriptor identifier for the image to dispose
|
|
241 */
|
|
242 public final void destroyImage(ImageDescriptor descriptor) {
|
|
243 destroy(descriptor);
|
|
244 }
|
|
245
|
|
246 /**
|
|
247 * Allocates a color, given a color descriptor. Any color allocated in this
|
|
248 * manner must be disposed by calling {@link #destroyColor(ColorDescriptor)},
|
|
249 * or by an eventual call to {@link #dispose()}. {@link Color#dispose()} must
|
|
250 * never been called directly on the returned color.
|
|
251 *
|
|
252 * @since 3.1
|
|
253 *
|
|
254 * @param descriptor descriptor for the color to create
|
|
255 * @return the Color described by the given ColorDescriptor (not null)
|
|
256 * @throws DeviceResourceException if unable to create the color
|
|
257 */
|
|
258 public final Color createColor(ColorDescriptor descriptor) {
|
|
259 return cast(Color)create(descriptor);
|
|
260 }
|
|
261
|
|
262 /**
|
|
263 * Allocates a color, given its RGB value. Any color allocated in this
|
|
264 * manner must be disposed by calling {@link #destroyColor(RGB)},
|
|
265 * or by an eventual call to {@link #dispose()}. {@link Color#dispose()} must
|
|
266 * never been called directly on the returned color.
|
|
267 *
|
|
268 * @since 3.1
|
|
269 *
|
|
270 * @param descriptor descriptor for the color to create
|
|
271 * @return the Color described by the given ColorDescriptor (not null)
|
|
272 * @throws DeviceResourceException if unable to create the color
|
|
273 */
|
|
274 public final Color createColor(RGB descriptor) {
|
|
275 return createColor(new RGBColorDescriptor(descriptor));
|
|
276 }
|
|
277
|
|
278 /**
|
|
279 * Undoes everything that was done by a call to {@link #createColor(RGB)}.
|
|
280 *
|
|
281 * @since 3.1
|
|
282 *
|
|
283 * @param descriptor RGB value of the color to dispose
|
|
284 */
|
|
285 public final void destroyColor(RGB descriptor) {
|
|
286 destroyColor(new RGBColorDescriptor(descriptor));
|
|
287 }
|
|
288
|
|
289 /**
|
|
290 * Undoes everything that was done by a call to {@link #createColor(ColorDescriptor)}.
|
|
291 *
|
|
292 *
|
|
293 * @since 3.1
|
|
294 *
|
|
295 * @param descriptor identifier for the color to dispose
|
|
296 */
|
|
297 public final void destroyColor(ColorDescriptor descriptor) {
|
|
298 destroy(descriptor);
|
|
299 }
|
|
300
|
|
301 /**
|
|
302 * Returns the Font described by the given FontDescriptor. Any Font
|
|
303 * allocated in this manner must be deallocated by calling disposeFont(...),
|
|
304 * or by an eventual call to {@link #dispose()}. The method {@link Font#dispose()}
|
|
305 * must never be called directly on the returned font.
|
|
306 *
|
|
307 * @since 3.1
|
|
308 *
|
|
309 * @param descriptor description of the font to create
|
|
310 * @return the Font described by the given descriptor
|
|
311 * @throws DeviceResourceException if unable to create the font
|
|
312 */
|
|
313 public final Font createFont(FontDescriptor descriptor) {
|
|
314 return cast(Font)create(descriptor);
|
|
315 }
|
|
316
|
|
317 /**
|
|
318 * Undoes everything that was done by a previous call to {@link #createFont(FontDescriptor)}.
|
|
319 *
|
|
320 * @since 3.1
|
|
321 *
|
|
322 * @param descriptor description of the font to destroy
|
|
323 */
|
|
324 public final void destroyFont(FontDescriptor descriptor) {
|
|
325 destroy(descriptor);
|
|
326 }
|
|
327
|
|
328 /**
|
|
329 * Disposes any remaining resources allocated by this manager.
|
|
330 */
|
|
331 public void dispose() {
|
|
332 if (disposeExecs is null) {
|
|
333 return;
|
|
334 }
|
|
335
|
|
336 // If one of the runnables throws an exception, we need to propagate it.
|
|
337 // However, this should not prevent the remaining runnables from being
|
|
338 // notified. If any runnables throw an exception, we remember one of them
|
|
339 // here and throw it at the end of the method.
|
|
340 RuntimeException foundException = null;
|
|
341
|
|
342 Runnable[] execs = disposeExecs.toArray();
|
|
343 for (int i = 0; i < execs.length; i++) {
|
|
344 Runnable exec = execs[i];
|
|
345
|
|
346 try {
|
|
347 exec.run();
|
|
348 } catch (RuntimeException e) {
|
|
349 // Ensure that we propagate an exception, but don't stop notifying
|
|
350 // the remaining runnables.
|
|
351 foundException = e;
|
|
352 }
|
|
353 }
|
|
354
|
|
355 if (foundException !is null) {
|
|
356 // If any runnables threw an exception, propagate one of them.
|
|
357 throw foundException;
|
|
358 }
|
|
359 }
|
|
360
|
|
361 /**
|
|
362 * Returns a previously allocated resource associated with the given descriptor, or
|
|
363 * null if none exists yet.
|
|
364 *
|
|
365 * @since 3.1
|
|
366 *
|
|
367 * @param descriptor descriptor to find
|
|
368 * @return a previously allocated resource for the given descriptor or null if none.
|
|
369 */
|
|
370 public abstract Object find(DeviceResourceDescriptor descriptor);
|
|
371
|
|
372 /**
|
|
373 * Causes the <code>run()</code> method of the runnable to
|
|
374 * be invoked just before the receiver is disposed. The runnable
|
|
375 * can be subsequently canceled by a call to <code>cancelDisposeExec</code>.
|
|
376 *
|
|
377 * @param r runnable to execute.
|
|
378 */
|
|
379 public void disposeExec(Runnable r) {
|
|
380 Assert.isNotNull(cast(Object)r);
|
|
381
|
|
382 if (disposeExecs is null) {
|
|
383 disposeExecs = new ArraySeq!(Runnable);
|
|
384 }
|
|
385
|
|
386 disposeExecs.append(r);
|
|
387 }
|
|
388
|
|
389 /**
|
|
390 * Cancels a runnable that was previously scheduled with <code>disposeExec</code>.
|
|
391 * Has no effect if the given runnable was not previously registered with
|
|
392 * disposeExec.
|
|
393 *
|
|
394 * @param r runnable to cancel
|
|
395 */
|
|
396 public void cancelDisposeExec(Runnable r) {
|
|
397 Assert.isNotNull(cast(Object)r);
|
|
398
|
|
399 if (disposeExecs is null) {
|
|
400 return;
|
|
401 }
|
|
402
|
|
403 disposeExecs.remove(r);
|
|
404
|
|
405 if (disposeExecs.drained()) {
|
|
406 disposeExecs = null;
|
|
407 }
|
|
408 }
|
|
409 }
|