001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.util;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.lang.reflect.Method;
014: import java.util.ArrayList;
015: import java.util.Iterator;
016: import java.util.List;
017:
018: import org.eclipse.jface.resource.ColorDescriptor;
019: import org.eclipse.jface.resource.DeviceResourceDescriptor;
020: import org.eclipse.jface.resource.DeviceResourceException;
021: import org.eclipse.jface.resource.FontDescriptor;
022: import org.eclipse.jface.resource.ImageDescriptor;
023: import org.eclipse.jface.resource.JFaceResources;
024: import org.eclipse.jface.resource.ResourceManager;
025: import org.eclipse.swt.events.DisposeEvent;
026: import org.eclipse.swt.events.DisposeListener;
027: import org.eclipse.swt.graphics.Color;
028: import org.eclipse.swt.graphics.Font;
029: import org.eclipse.swt.graphics.Image;
030: import org.eclipse.swt.widgets.Button;
031: import org.eclipse.swt.widgets.Control;
032: import org.eclipse.swt.widgets.Item;
033: import org.eclipse.swt.widgets.Label;
034: import org.eclipse.swt.widgets.TableItem;
035: import org.eclipse.swt.widgets.ToolItem;
036: import org.eclipse.swt.widgets.Widget;
037: import org.eclipse.ui.internal.WorkbenchPlugin;
038:
039: /**
040: * Contains a bunch of helper methods that allow JFace resource descriptors to be passed
041: * directly to SWT widgets without worrying about resource allocation. This class is internal,
042: * but it should be moved into JFace if the pattern is found generally useful. The current
043: * implementation uses a lot of reflection to save repeated code, but this could all be inlined
044: * (without reflection) if performance turns out to be a problem.
045: *
046: * <p>
047: * For example, an Image might be passed to a TableItem as follows:
048: * <p>
049: *
050: * <code>
051: * ImageDescriptor someDescriptor = ...;
052: * TableItem someTableItem = ...;
053: * ResourceManager manager = JFaceResources.getResources();
054: *
055: * Image actualImage = manager.createImage(someDescriptor);
056: * someTableItem.setImage(actualImage);
057: *
058: * // do something with the table item
059: *
060: * someTableItem.dispose();
061: * manager.destroyImage(someDescriptor);
062: * </code>
063: *
064: * <p>
065: * It is much more convenient to do the following:
066: * </p>
067: *
068: * <code>
069: * ImageDescriptor someDescriptor = ...;
070: * TableItem someTableItem = ...;
071: *
072: * Descriptors.setImage(someTableItem, someDescriptor);
073: *
074: * // do something with the table item
075: *
076: * someTableItem.dispose();
077: * </code>
078: *
079: * <p>
080: * This class tries to behave as if the table item itself had a set method that took a descriptor.
081: * Resource allocation and deallocation happens for free. All the methods are leakproof. That is,
082: * if any images, colors, etc. need to be allocated and passed to the SWT widget, they will be
083: * deallocated automatically when the widget goes away (the implementation hooks a dispose listener
084: * on the widget which cleans up as soon as the widget is disposed).
085: * </p>
086: *
087: * @since 3.1
088: */
089: public final class Descriptors {
090: private static final String DISPOSE_LIST = "Descriptors.disposeList"; //$NON-NLS-1$
091:
092: private Descriptors() {
093: }
094:
095: private static final class ResourceMethod {
096: ResourceMethod(Method m, String id) {
097: method = m;
098: this .id = id;
099: }
100:
101: Method method;
102: DeviceResourceDescriptor oldDescriptor;
103: String id;
104:
105: public void invoke(Widget toCall,
106: DeviceResourceDescriptor newDescriptor) {
107: if (newDescriptor == oldDescriptor) {
108: return;
109: }
110:
111: ResourceManager mgr = JFaceResources.getResources(toCall
112: .getDisplay());
113:
114: Object newResource;
115: try {
116: newResource = newDescriptor == null ? null : mgr
117: .create(newDescriptor);
118: } catch (DeviceResourceException e1) {
119: WorkbenchPlugin.log(e1);
120: return;
121: }
122:
123: try {
124: method.invoke(toCall, new Object[] { newResource });
125: } catch (IllegalArgumentException e) {
126: throw e;
127: } catch (IllegalAccessException e) {
128: WorkbenchPlugin.log(e);
129: return;
130: } catch (InvocationTargetException e) {
131: if (e.getTargetException() instanceof RuntimeException) {
132: throw (RuntimeException) e.getTargetException();
133: }
134: WorkbenchPlugin.log(e);
135: return;
136: }
137:
138: // Deallocate the old image
139: if (oldDescriptor != null) {
140: // Dispose the image
141: mgr.destroy(oldDescriptor);
142: }
143:
144: // Remember the new image for next time
145:
146: oldDescriptor = newDescriptor;
147: }
148:
149: public void dispose() {
150: // Deallocate the old image
151: if (oldDescriptor != null) {
152: ResourceManager mgr = JFaceResources.getResources();
153: // Dispose the image
154: mgr.destroy(oldDescriptor);
155: oldDescriptor = null;
156: }
157:
158: }
159: }
160:
161: private static DisposeListener disposeListener = new DisposeListener() {
162: public void widgetDisposed(DisposeEvent e) {
163: doDispose(e.widget);
164: }
165: };
166:
167: // Item //////////////////////////////////////////////////////////////////////////////////
168:
169: /**
170: * Sets the image on the given ToolItem. The image will be automatically allocated and
171: * disposed as needed.
172: *
173: * @since 3.1
174: *
175: * @param item
176: * @param descriptor
177: */
178: public static void setImage(Item item, ImageDescriptor descriptor) {
179: callMethod(item, "setImage", descriptor, Image.class); //$NON-NLS-1$
180: }
181:
182: // ToolItem //////////////////////////////////////////////////////////////////////////////
183:
184: public static void setHotImage(ToolItem item,
185: ImageDescriptor descriptor) {
186: callMethod(item, "setHotImage", descriptor, Image.class); //$NON-NLS-1$
187: }
188:
189: public static void setDisabledImage(ToolItem item,
190: ImageDescriptor descriptor) {
191: callMethod(item, "setDisabledImage", descriptor, Image.class); //$NON-NLS-1$
192: }
193:
194: // TableItem //////////////////////////////////////////////////////////////////////////////
195:
196: public static void setFont(TableItem item, FontDescriptor descriptor) {
197: callMethod(item, "setFont", descriptor, Font.class); //$NON-NLS-1$
198: }
199:
200: public static void setBackground(TableItem item,
201: ColorDescriptor descriptor) {
202: callMethod(item, "setBackground", descriptor, Color.class); //$NON-NLS-1$
203: }
204:
205: public static void setForeground(TableItem item,
206: ColorDescriptor descriptor) {
207: callMethod(item, "setForeground", descriptor, Color.class); //$NON-NLS-1$
208: }
209:
210: // Control ///////////////////////////////////////////////////////////////////////////////
211:
212: public static void setBackground(Control control,
213: ColorDescriptor descriptor) {
214: callMethod(control, "setBackground", descriptor, Color.class); //$NON-NLS-1$
215: }
216:
217: public static void setForeground(Control control,
218: ColorDescriptor descriptor) {
219: callMethod(control, "setForeground", descriptor, Color.class); //$NON-NLS-1$
220: }
221:
222: // Button ///////////////////////////////////////////////////////////////////////////////
223:
224: public static void setImage(Button button,
225: ImageDescriptor descriptor) {
226: callMethod(button, "setImage", descriptor, Image.class); //$NON-NLS-1$
227: }
228:
229: public static void setImage(Label label, ImageDescriptor descriptor) {
230: callMethod(label, "setImage", descriptor, Image.class); //$NON-NLS-1$
231: }
232:
233: private static ResourceMethod getResourceMethod(Widget toCall,
234: String methodName, Class resourceType)
235: throws NoSuchMethodException {
236: Object oldData = toCall.getData(DISPOSE_LIST);
237:
238: if (oldData instanceof List) {
239: // Check for existing data
240: for (Iterator iter = ((List) oldData).iterator(); iter
241: .hasNext();) {
242: ResourceMethod method = (ResourceMethod) iter.next();
243:
244: if (method.id == methodName) {
245: return method;
246: }
247: }
248: }
249: if (oldData instanceof ResourceMethod) {
250: if (((ResourceMethod) oldData).id == methodName) {
251: return ((ResourceMethod) oldData);
252: }
253:
254: List newList = new ArrayList();
255: newList.add(oldData);
256: oldData = newList;
257: toCall.setData(DISPOSE_LIST, oldData);
258: }
259:
260: // At this point, the DISPOSE_LIST data is either null or points to an ArrayList
261:
262: Class clazz = toCall.getClass();
263:
264: Method method;
265: try {
266: method = clazz.getMethod(methodName,
267: new Class[] { resourceType });
268: } catch (SecurityException e) {
269: throw e;
270: }
271:
272: ResourceMethod result = new ResourceMethod(method, methodName);
273:
274: if (oldData == null) {
275: toCall.setData(DISPOSE_LIST, result);
276: toCall.addDisposeListener(disposeListener);
277: } else {
278: ((List) oldData).add(result);
279: }
280:
281: return result;
282: }
283:
284: private static void callMethod(Widget toCall, String methodName,
285: DeviceResourceDescriptor descriptor, Class resourceType) {
286: ResourceMethod method;
287: try {
288: method = getResourceMethod(toCall, methodName, resourceType);
289: } catch (NoSuchMethodException e) {
290: WorkbenchPlugin.log(e);
291: return;
292: }
293:
294: method.invoke(toCall, descriptor);
295: }
296:
297: private static void doDispose(Widget widget) {
298: Object oldData = widget.getData(DISPOSE_LIST);
299:
300: if (oldData instanceof ArrayList) {
301: ArrayList list = ((ArrayList) oldData);
302: ResourceMethod[] data = (ResourceMethod[]) list
303: .toArray(new ResourceMethod[list.size()]);
304:
305: // Clear out the images
306: for (int i = 0; i < data.length; i++) {
307: ResourceMethod method = data[i];
308:
309: method.dispose();
310: }
311: }
312:
313: if (oldData instanceof ResourceMethod) {
314: ((ResourceMethod) oldData).dispose();
315: }
316: }
317:
318: }
|