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