001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.decorators;
011:
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.List;
015:
016: import org.eclipse.core.runtime.IExtension;
017: import org.eclipse.core.runtime.ISafeRunnable;
018: import org.eclipse.core.runtime.IStatus;
019: import org.eclipse.core.runtime.Platform;
020: import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
021: import org.eclipse.ui.internal.ObjectContributorManager;
022: import org.eclipse.ui.internal.WorkbenchPlugin;
023: import org.eclipse.ui.internal.misc.StatusUtil;
024: import org.eclipse.ui.internal.util.Util;
025:
026: /**
027: * The LightweightDecoratorManager is a decorator manager
028: * that encapsulates the behavior for the lightweight decorators.
029: */
030: public class LightweightDecoratorManager extends
031: ObjectContributorManager {
032:
033: /**
034: * The runnable is the object used to run the decorations
035: * so that an error in someones decorator will not kill the thread.
036: * It is implemented here to prevent aborting of decoration
037: * i.e. successful decorations will still be applied.
038: */
039:
040: private class LightweightRunnable implements ISafeRunnable {
041: private Object element;
042:
043: private DecorationBuilder decoration;
044:
045: private LightweightDecoratorDefinition decorator;
046:
047: void setValues(Object object, DecorationBuilder builder,
048: LightweightDecoratorDefinition definition) {
049: element = object;
050: decoration = builder;
051: decorator = definition;
052:
053: }
054:
055: /*
056: * @see ISafeRunnable.handleException(Throwable).
057: */
058: public void handleException(Throwable exception) {
059: IStatus status = StatusUtil.newStatus(IStatus.ERROR,
060: exception.getMessage(), exception);
061: WorkbenchPlugin.log("Exception in Decorator", status); //$NON-NLS-1$
062: if (decorator != null) {
063: decorator.crashDisable();
064: }
065: }
066:
067: /*
068: * @see ISafeRunnable.run
069: */
070: public void run() throws Exception {
071: decorator.decorate(element, decoration);
072: }
073:
074: /**
075: * Clear decorator references.
076: * @since 3.1
077: */
078: void clearReferences() {
079: decorator = null;
080: }
081: }
082:
083: private LightweightRunnable runnable = new LightweightRunnable();
084:
085: //The lightweight definitionsread from the registry
086: private LightweightDecoratorDefinition[] lightweightDefinitions;
087:
088: private static final LightweightDecoratorDefinition[] EMPTY_LIGHTWEIGHT_DEF = new LightweightDecoratorDefinition[0];
089:
090: private OverlayCache overlayCache = new OverlayCache();
091:
092: LightweightDecoratorManager(
093: LightweightDecoratorDefinition[] definitions) {
094: super ();
095: lightweightDefinitions = definitions;
096: buildContributors();
097: }
098:
099: /**
100: * Get the lightweight definitions for the receiver.
101: * @return LightweightDecoratorDefinition[]
102: */
103: LightweightDecoratorDefinition[] getDefinitions() {
104: return lightweightDefinitions;
105: }
106:
107: /**
108: * Register the decorators as object contributions so
109: * that adaptable lookup can occur.
110: */
111: private void buildContributors() {
112: for (int i = 0; i < lightweightDefinitions.length; i++) {
113: LightweightDecoratorDefinition decorator = lightweightDefinitions[i];
114: String[] types = getTargetTypes(decorator);
115: for (int j = 0; j < types.length; j++) {
116: registerContributor(decorator, types[j]);
117: }
118: }
119: }
120:
121: /**
122: * For dynamic UI
123: *
124: * @param decorator the definition to add
125: * @return whether the definition was added
126: * @since 3.0
127: */
128: public boolean addDecorator(LightweightDecoratorDefinition decorator) {
129: if (getLightweightDecoratorDefinition(decorator.getId()) == null) {
130: LightweightDecoratorDefinition[] oldDefs = lightweightDefinitions;
131: lightweightDefinitions = new LightweightDecoratorDefinition[lightweightDefinitions.length + 1];
132: System.arraycopy(oldDefs, 0, lightweightDefinitions, 0,
133: oldDefs.length);
134: lightweightDefinitions[oldDefs.length] = decorator;
135: // no reset - handled in the DecoratorManager
136: String[] types = getTargetTypes(decorator);
137: for (int i = 0; i < types.length; i++) {
138: registerContributor(decorator, types[i]);
139: }
140: return true;
141: }
142: return false;
143: }
144:
145: /**
146: * Get the name of the types that a decorator is registered for.
147: * @param decorator
148: * @return String[]
149: */
150: private String[] getTargetTypes(
151: LightweightDecoratorDefinition decorator) {
152: return decorator.getObjectClasses();
153: }
154:
155: /**
156: * For dynamic-ui
157: * @param decorator the definition to remove
158: * @return whether the definition was removed
159: * @since 3.1
160: */
161: public boolean removeDecorator(
162: LightweightDecoratorDefinition decorator) {
163: int idx = getLightweightDecoratorDefinitionIdx(decorator
164: .getId());
165: if (idx != -1) {
166: LightweightDecoratorDefinition[] oldDefs = lightweightDefinitions;
167: Util
168: .arrayCopyWithRemoval(
169: oldDefs,
170: lightweightDefinitions = new LightweightDecoratorDefinition[lightweightDefinitions.length - 1],
171: idx);
172: // no reset - handled in the DecoratorManager
173: String[] types = getTargetTypes(decorator);
174: for (int i = 0; i < types.length; i++) {
175: unregisterContributor(decorator, types[i]);
176:
177: }
178: return true;
179: }
180: return false;
181: }
182:
183: /**
184: * Get the LightweightDecoratorDefinition with the supplied id
185: * @return LightweightDecoratorDefinition or <code>null</code> if it is not found
186: * @param decoratorId String
187: * @since 3.0
188: */
189: private LightweightDecoratorDefinition getLightweightDecoratorDefinition(
190: String decoratorId) {
191: int idx = getLightweightDecoratorDefinitionIdx(decoratorId);
192: if (idx != -1) {
193: return lightweightDefinitions[idx];
194: }
195: return null;
196: }
197:
198: /**
199: * Return the index of the definition in the array.
200: *
201: * @param decoratorId the id
202: * @return the index of the definition in the array or <code>-1</code>
203: * @since 3.1
204: */
205: private int getLightweightDecoratorDefinitionIdx(String decoratorId) {
206: for (int i = 0; i < lightweightDefinitions.length; i++) {
207: if (lightweightDefinitions[i].getId().equals(decoratorId)) {
208: return i;
209: }
210: }
211: return -1;
212: }
213:
214: /**
215: * Return the enabled lightweight decorator definitions.
216: * @return LightweightDecoratorDefinition[]
217: */
218: LightweightDecoratorDefinition[] enabledDefinitions() {
219: ArrayList result = new ArrayList();
220: for (int i = 0; i < lightweightDefinitions.length; i++) {
221: if (lightweightDefinitions[i].isEnabled()) {
222: result.add(lightweightDefinitions[i]);
223: }
224: }
225: LightweightDecoratorDefinition[] returnArray = new LightweightDecoratorDefinition[result
226: .size()];
227: result.toArray(returnArray);
228: return returnArray;
229: }
230:
231: /**
232: * Return whether there are enabled lightwieght decorators
233: * @return boolean
234: */
235: boolean hasEnabledDefinitions() {
236: for (int i = 0; i < lightweightDefinitions.length; i++) {
237: if (lightweightDefinitions[i].isEnabled()) {
238: return true;
239: }
240: }
241: return false;
242: }
243:
244: /**
245: * Reset any cached values.
246: */
247: void reset() {
248: runnable.clearReferences();
249: }
250:
251: /**
252: * Shutdown the decorator manager by disabling all
253: * of the decorators so that dispose() will be called
254: * on them.
255: */
256: void shutdown() {
257: //Disable all fo the enabled decorators
258: //so as to force a dispose of thier decorators
259: for (int i = 0; i < lightweightDefinitions.length; i++) {
260: if (lightweightDefinitions[i].isEnabled()) {
261: lightweightDefinitions[i].setEnabled(false);
262: }
263: }
264: overlayCache.disposeAll();
265: }
266:
267: /**
268: * Get the LightweightDecoratorDefinition with the supplied id
269: * @return LightweightDecoratorDefinition or <code>null</code> if it is not found
270: * @param decoratorId String
271: */
272: LightweightDecoratorDefinition getDecoratorDefinition(
273: String decoratorId) {
274: for (int i = 0; i < lightweightDefinitions.length; i++) {
275: if (lightweightDefinitions[i].getId().equals(decoratorId)) {
276: return lightweightDefinitions[i];
277: }
278: }
279: return null;
280: }
281:
282: /**
283: * Get the lightweight registered for elements of this type.
284: */
285: LightweightDecoratorDefinition[] getDecoratorsFor(Object element) {
286:
287: if (element == null) {
288: return EMPTY_LIGHTWEIGHT_DEF;
289: }
290:
291: List elements = new ArrayList(1);
292: elements.add(element);
293: LightweightDecoratorDefinition[] decoratorArray = EMPTY_LIGHTWEIGHT_DEF;
294: List contributors = getContributors(elements);
295: if (!contributors.isEmpty()) {
296: Collection decorators = DecoratorManager
297: .getDecoratorsFor(
298: element,
299: (DecoratorDefinition[]) contributors
300: .toArray(new DecoratorDefinition[contributors
301: .size()]));
302: if (decorators.size() > 0) {
303: decoratorArray = new LightweightDecoratorDefinition[decorators
304: .size()];
305: decorators.toArray(decoratorArray);
306: }
307: }
308:
309: return decoratorArray;
310: }
311:
312: /**
313: * Fill the decoration with all of the results of the
314: * decorators.
315: *
316: * @param element The source element
317: * @param context The decoration context
318: * @param decoration The DecorationResult we are working on.
319: * where adaptable is true.
320: */
321: public void getDecorations(Object element,
322: DecorationBuilder decoration) {
323:
324: LightweightDecoratorDefinition[] decorators = getDecoratorsFor(element);
325:
326: for (int i = 0; i < decorators.length; i++) {
327: //If we are doing the adaptable one make sure we are
328: //only applying the adaptable decorations
329: LightweightDecoratorDefinition dd = decorators[i];
330: decoration.setCurrentDefinition(dd);
331: decorate(element, decoration, dd);
332: }
333: }
334:
335: /**
336: * Decorate the element receiver in a SafeRunnable.
337: * @param element The Object to be decorated
338: * @param decoration The object building decorations.
339: * @param decorator The decorator being applied.
340: */
341: private void decorate(Object element, DecorationBuilder decoration,
342: LightweightDecoratorDefinition decorator) {
343:
344: runnable.setValues(element, decoration, decorator);
345: Platform.run(runnable);
346: }
347:
348: /**
349: * Returns the overlayCache.
350: * @return OverlayCache
351: */
352: OverlayCache getOverlayCache() {
353: return overlayCache;
354: }
355:
356: /**
357: * Method for use by test cases
358: * @param object the object to be decorated
359: * @return the decoration result
360: */
361: public DecorationResult getDecorationResult(Object object) {
362: DecorationBuilder builder = new DecorationBuilder();
363: getDecorations(object, builder);
364: return builder.createResult();
365:
366: }
367:
368: /* (non-Javadoc)
369: * @see org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamichelpers.IExtensionTracker, org.eclipse.core.runtime.IExtension)
370: */
371: public void addExtension(IExtensionTracker tracker,
372: IExtension extension) {
373: // Do nothing as this is handled by the DecoratorManager
374: //This is not called as canHandleExtensionTracking returns
375: //false.
376: }
377:
378: /* (non-Javadoc)
379: * @see org.eclipse.ui.internal.ObjectContributorManager#canHandleExtensionTracking()
380: */
381: protected boolean canHandleExtensionTracking() {
382: return false;
383: }
384:
385: }
|