001: /*******************************************************************************
002: * Copyright (c) 2003, 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.jface.resource;
011:
012: import java.util.ArrayList;
013: import java.util.Collections;
014: import java.util.HashMap;
015: import java.util.Iterator;
016: import java.util.List;
017: import java.util.Map;
018: import java.util.Set;
019:
020: import org.eclipse.core.runtime.Assert;
021: import org.eclipse.swt.graphics.Color;
022: import org.eclipse.swt.graphics.RGB;
023: import org.eclipse.swt.widgets.Display;
024:
025: /**
026: * A color registry maintains a mapping between symbolic color names and SWT
027: * <code>Color</code>s.
028: * <p>
029: * A color registry owns all of the <code>Color</code> objects registered with
030: * it, and automatically disposes of them when the SWT Display that creates the
031: * <code>Color</code>s is disposed. Because of this, clients do not need to
032: * (indeed, must not attempt to) dispose of <code>Color</code> objects
033: * themselves.
034: * </p>
035: * <p>
036: * Methods are provided for registering listeners that will be kept
037: * apprised of changes to list of registed colors.
038: * </p>
039: * <p>
040: * Clients may instantiate this class (it was not designed to be subclassed).
041: * </p>
042: *
043: * @since 3.0
044: */
045: public class ColorRegistry extends ResourceRegistry {
046:
047: /**
048: * Default color value. This is cyan (very unappetizing).
049: * @since 3.4
050: */
051: private static final ColorDescriptor DEFAULT_COLOR = new RGBColorDescriptor(
052: new RGB(0, 255, 255));
053:
054: /**
055: * This registries <code>Display</code>. All colors will be allocated using
056: * it.
057: */
058: protected Display display;
059:
060: /**
061: * Collection of <code>Color</code> that are now stale to be disposed when
062: * it is safe to do so (i.e. on shutdown).
063: */
064: private List staleColors = new ArrayList();
065:
066: /**
067: * Table of known colors, keyed by symbolic color name (key type: <code>String</code>,
068: * value type: <code>org.eclipse.swt.graphics.Color</code>.
069: */
070: private Map stringToColor = new HashMap(7);
071:
072: /**
073: * Table of known color data, keyed by symbolic color name (key type:
074: * <code>String</code>, value type: <code>org.eclipse.swt.graphics.RGB</code>).
075: */
076: private Map stringToRGB = new HashMap(7);
077:
078: /**
079: * Runnable that cleans up the manager on disposal of the display.
080: */
081: protected Runnable displayRunnable = new Runnable() {
082: public void run() {
083: clearCaches();
084: }
085: };
086:
087: /**
088: * Create a new instance of the receiver that is hooked to the current
089: * display.
090: *
091: * @see org.eclipse.swt.widgets.Display#getCurrent()
092: */
093: public ColorRegistry() {
094: this (Display.getCurrent(), true);
095: }
096:
097: /**
098: * Create a new instance of the receiver.
099: *
100: * @param display the <code>Display</code> to hook into.
101: */
102: public ColorRegistry(Display display) {
103: this (display, true);
104: }
105:
106: /**
107: * Create a new instance of the receiver.
108: *
109: * @param display the <code>Display</code> to hook into
110: * @param cleanOnDisplayDisposal
111: * whether all fonts allocated by this <code>ColorRegistry</code>
112: * should be disposed when the display is disposed
113: * @since 3.1
114: */
115: public ColorRegistry(Display display, boolean cleanOnDisplayDisposal) {
116: Assert.isNotNull(display);
117: this .display = display;
118: if (cleanOnDisplayDisposal) {
119: hookDisplayDispose();
120: }
121: }
122:
123: /**
124: * Create a new <code>Color</code> on the receivers <code>Display</code>.
125: *
126: * @param rgb the <code>RGB</code> data for the color.
127: * @return the new <code>Color</code> object.
128: *
129: * @since 3.1
130: */
131: private Color createColor(RGB rgb) {
132: return new Color(display, rgb);
133: }
134:
135: /**
136: * Dispose of all of the <code>Color</code>s in this iterator.
137: *
138: * @param iterator over <code>Collection</code> of <code>Color</code>
139: */
140: private void disposeColors(Iterator iterator) {
141: while (iterator.hasNext()) {
142: Object next = iterator.next();
143: ((Color) next).dispose();
144: }
145: }
146:
147: /**
148: * Returns the <code>color</code> associated with the given symbolic color
149: * name, or <code>null</code> if no such definition exists.
150: *
151: * @param symbolicName symbolic color name
152: * @return the <code>Color</code> or <code>null</code>
153: */
154: public Color get(String symbolicName) {
155:
156: Assert.isNotNull(symbolicName);
157: Object result = stringToColor.get(symbolicName);
158: if (result != null) {
159: return (Color) result;
160: }
161:
162: Color color = null;
163:
164: result = stringToRGB.get(symbolicName);
165: if (result == null) {
166: return null;
167: }
168:
169: color = createColor((RGB) result);
170:
171: stringToColor.put(symbolicName, color);
172:
173: return color;
174: }
175:
176: /* (non-Javadoc)
177: * @see org.eclipse.jface.resource.ResourceRegistry#getKeySet()
178: */
179: public Set getKeySet() {
180: return Collections.unmodifiableSet(stringToRGB.keySet());
181: }
182:
183: /**
184: * Returns the color data associated with the given symbolic color name.
185: *
186: * @param symbolicName symbolic color name.
187: * @return the <code>RGB</code> data, or <code>null</code> if the symbolic name
188: * is not valid.
189: */
190: public RGB getRGB(String symbolicName) {
191: Assert.isNotNull(symbolicName);
192: return (RGB) stringToRGB.get(symbolicName);
193: }
194:
195: /**
196: * Returns the color descriptor associated with the given symbolic color
197: * name. As of 3.4 if this color is not defined then an unspecified color
198: * is returned. Users that wish to ensure a reasonable default value should
199: * use {@link #getColorDescriptor(String, ColorDescriptor)} instead.
200: *
201: * @since 3.1
202: *
203: * @param symbolicName
204: * @return the color descriptor associated with the given symbolic color
205: * name or an unspecified sentinel.
206: */
207: public ColorDescriptor getColorDescriptor(String symbolicName) {
208: return getColorDescriptor(symbolicName, DEFAULT_COLOR);
209: }
210:
211: /**
212: * Returns the color descriptor associated with the given symbolic color
213: * name. If this name does not exist within the registry the supplied
214: * default value will be used.
215: *
216: * @param symbolicName
217: * @param defaultValue
218: * @return the color descriptor associated with the given symbolic color
219: * name or the default
220: * @since 3.4
221: */
222: public ColorDescriptor getColorDescriptor(String symbolicName,
223: ColorDescriptor defaultValue) {
224: RGB rgb = getRGB(symbolicName);
225: if (rgb == null)
226: return defaultValue;
227: return ColorDescriptor.createFrom(rgb);
228: }
229:
230: /*
231: * (non-Javadoc)
232: *
233: * @see org.eclipse.jface.resource.ResourceRegistry#clearCaches()
234: */
235: protected void clearCaches() {
236: disposeColors(stringToColor.values().iterator());
237: disposeColors(staleColors.iterator());
238: stringToColor.clear();
239: staleColors.clear();
240: }
241:
242: /* (non-Javadoc)
243: * @see org.eclipse.jface.resource.ResourceRegistry#hasValueFor(java.lang.String)
244: */
245: public boolean hasValueFor(String colorKey) {
246: return stringToRGB.containsKey(colorKey);
247: }
248:
249: /**
250: * Hook a dispose listener on the SWT display.
251: */
252: private void hookDisplayDispose() {
253: display.disposeExec(displayRunnable);
254: }
255:
256: /**
257: * Adds (or replaces) a color to this color registry under the given
258: * symbolic name.
259: * <p>
260: * A property change event is reported whenever the mapping from a symbolic
261: * name to a color changes. The source of the event is this registry; the
262: * property name is the symbolic color name.
263: * </p>
264: *
265: * @param symbolicName the symbolic color name
266: * @param colorData an <code>RGB</code> object
267: */
268: public void put(String symbolicName, RGB colorData) {
269: put(symbolicName, colorData, true);
270: }
271:
272: /**
273: * Adds (or replaces) a color to this color registry under the given
274: * symbolic name.
275: * <p>
276: * A property change event is reported whenever the mapping from a symbolic
277: * name to a color changes. The source of the event is this registry; the
278: * property name is the symbolic color name.
279: * </p>
280: *
281: * @param symbolicName the symbolic color name
282: * @param colorData an <code>RGB</code> object
283: * @param update - fire a color mapping changed if true. False if this
284: * method is called from the get method as no setting has
285: * changed.
286: */
287: private void put(String symbolicName, RGB colorData, boolean update) {
288:
289: Assert.isNotNull(symbolicName);
290: Assert.isNotNull(colorData);
291:
292: RGB existing = (RGB) stringToRGB.get(symbolicName);
293: if (colorData.equals(existing)) {
294: return;
295: }
296:
297: Color oldColor = (Color) stringToColor.remove(symbolicName);
298: stringToRGB.put(symbolicName, colorData);
299: if (update) {
300: fireMappingChanged(symbolicName, existing, colorData);
301: }
302:
303: if (oldColor != null) {
304: staleColors.add(oldColor);
305: }
306: }
307: }
|