001: /*******************************************************************************
002: * Copyright (c) 2003, 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.navigator;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.HashMap;
015: import java.util.HashSet;
016: import java.util.Iterator;
017: import java.util.List;
018: import java.util.Map;
019: import java.util.Set;
020:
021: import org.eclipse.core.runtime.ListenerList;
022: import org.eclipse.core.runtime.Preferences;
023: import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor;
024: import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptorManager;
025: import org.eclipse.ui.navigator.IExtensionActivationListener;
026: import org.eclipse.ui.navigator.INavigatorActivationService;
027: import org.eclipse.ui.navigator.INavigatorContentDescriptor;
028: import org.eclipse.ui.navigator.INavigatorContentService;
029:
030: /**
031: *
032: * The activation service determines if an extension is <i>active</i> within the
033: * context of a given viewer. If an extension is <i>active</i> then the extension
034: * will contribute functionality to the viewer. If an extension is not <i>active</i>,
035: * then the extension will not be given opportunities to contribute
036: * functionality to the given viewer. See {@link INavigatorContentService} for
037: * more detail on what states are associated with a content extension.
038: *
039: *
040: * @since 3.2
041: */
042: public final class NavigatorActivationService implements
043: INavigatorActivationService {
044:
045: private static final String ACTIVATED_EXTENSIONS = ".activatedExtensions"; //$NON-NLS-1$
046:
047: private static final NavigatorContentDescriptorManager CONTENT_DESCRIPTOR_REGISTRY = NavigatorContentDescriptorManager
048: .getInstance();
049:
050: private static final INavigatorContentDescriptor[] NO_DESCRIPTORS = new INavigatorContentDescriptor[0];
051:
052: private static final String DELIM = ";"; //$NON-NLS-1$
053:
054: private static final char EQUALS = '=';
055:
056: /*
057: * Set of ids of activated extensions.
058: */
059: //private final Set activatedExtensions = new HashSet();
060: /*
061: * Set of ids of activated extensions.
062: */
063: private final Map/*<String, Boolean>*/activatedExtensionsMap = new HashMap();
064:
065: /*
066: * IExtensionActivationListeners
067: */
068: private final ListenerList listeners = new ListenerList();
069:
070: private INavigatorContentService contentService;
071:
072: /**
073: * Create an instance of the service.
074: *
075: * @param aContentService
076: * The associated content service.
077: */
078: public NavigatorActivationService(
079: INavigatorContentService aContentService) {
080: contentService = aContentService;
081: revertExtensionActivations();
082: }
083:
084: /**
085: *
086: * Checks the known activation state for the given viewer id to determine if
087: * the given navigator extension is 'active'.
088: *
089: * @param aNavigatorExtensionId
090: * The unique identifier associated with a given extension.
091: *
092: * @return True if the extension is active in the context of the viewer id.
093: */
094: public boolean isNavigatorExtensionActive(
095: String aNavigatorExtensionId) {
096: Boolean b = (Boolean) activatedExtensionsMap
097: .get(aNavigatorExtensionId);
098: if (b != null)
099: return b.booleanValue();
100: synchronized (activatedExtensionsMap) {
101: NavigatorContentDescriptor descriptor = CONTENT_DESCRIPTOR_REGISTRY
102: .getContentDescriptor(aNavigatorExtensionId);
103: if (descriptor.isActiveByDefault())
104: activatedExtensionsMap.put(aNavigatorExtensionId,
105: Boolean.TRUE);
106: else
107: activatedExtensionsMap.put(aNavigatorExtensionId,
108: Boolean.FALSE);
109: return descriptor.isActiveByDefault();
110: }
111: //return activatedExtensions.contains(aNavigatorExtensionId);
112: }
113:
114: /**
115: * Set the activation state for the given extension in the context of the
116: * given viewer id. Each instance of an INavigatorContentService listens for
117: * the activation service to update; and if those instances were created
118: * with viewers, they will issue a refresh. Otherwise, clients are
119: * responsible for refreshing the viewers.
120: *
121: * <p>
122: * Clients must call {@link #persistExtensionActivations()} to save
123: * the the activation state.
124: * </p>
125: *
126: * <p>
127: * When clients are updating a batch of extensions, consider using
128: * {@link #setActive(String[], boolean)} when
129: * possible to avoid unnecessary notifications.
130: * </p>
131: *
132: * @param aNavigatorExtensionId
133: * The unique identifier associated with a given extension.
134: * @param toEnable
135: * True indicates the extension should be enabled; False
136: * indicates otherwise.
137: *
138: */
139: public void setActive(String aNavigatorExtensionId, boolean toEnable) {
140:
141: boolean currentlyActive = isNavigatorExtensionActive(aNavigatorExtensionId);
142: if (currentlyActive == toEnable) {
143: return;
144: }
145:
146: if (toEnable) {
147: //activatedExtensions.add(aNavigatorExtensionId);
148: activatedExtensionsMap.put(aNavigatorExtensionId,
149: Boolean.TRUE);
150: } else {
151: //activatedExtensions.remove(aNavigatorExtensionId);
152: activatedExtensionsMap.put(aNavigatorExtensionId,
153: Boolean.FALSE);
154: }
155: notifyListeners(new String[] { aNavigatorExtensionId },
156: toEnable);
157:
158: }
159:
160: /**
161: * Set the activation state for the given extension in the context of the
162: * given viewer id. Each instance of an INavigatorContentService listens for
163: * the activation service to update; and if those instances were created
164: * with viewers, they will issue a refresh. Otherwise, clients are
165: * responsible for refreshing the viewers.
166: *
167: * <p>
168: * Clients must call {@link #persistExtensionActivations()} to save
169: * the the activation state.
170: * </p>
171: *
172: * @param aNavigatorExtensionIds
173: * An array of unique identifiers associated with existing
174: * extension.
175: * @param toEnable
176: * True indicates the extension should be enabled; False
177: * indicates otherwise.
178: *
179: */
180: public void setActive(String[] aNavigatorExtensionIds,
181: boolean toEnable) {
182:
183: if (toEnable) {
184: for (int i = 0; i < aNavigatorExtensionIds.length; i++) {
185: //activatedExtensions.add(aNavigatorExtensionIds[i]);
186: activatedExtensionsMap.put(aNavigatorExtensionIds[i],
187: Boolean.TRUE);
188: }
189: } else {
190: for (int i = 0; i < aNavigatorExtensionIds.length; i++) {
191: //activatedExtensions.remove(aNavigatorExtensionIds[i]);
192: activatedExtensionsMap.put(aNavigatorExtensionIds[i],
193: Boolean.FALSE);
194: }
195: }
196: notifyListeners(aNavigatorExtensionIds, toEnable);
197:
198: }
199:
200: /**
201: * Save the activation state for the given viewer.
202: *
203: */
204: public void persistExtensionActivations() {
205:
206: Preferences preferences = NavigatorPlugin.getDefault()
207: .getPluginPreferences();
208:
209: //synchronized (activatedExtensions) {
210: synchronized (activatedExtensionsMap) {
211: //Iterator activatedExtensionsIterator = activatedExtensions.iterator();
212: Iterator activatedExtensionsIterator = activatedExtensionsMap
213: .keySet().iterator();
214:
215: /* ensure that the preference will be non-empty */
216: StringBuffer preferenceValue = new StringBuffer();
217: String navigatorExtensionId = null;
218: boolean isActive = false;
219: while (activatedExtensionsIterator.hasNext()) {
220: navigatorExtensionId = (String) activatedExtensionsIterator
221: .next();
222: isActive = isNavigatorExtensionActive(navigatorExtensionId);
223: preferenceValue.append(navigatorExtensionId).append(
224: EQUALS).append(
225: isActive ? Boolean.TRUE : Boolean.FALSE)
226: .append(DELIM);
227: }
228: preferences.setValue(getPreferenceKey(), preferenceValue
229: .toString());
230: }
231: NavigatorPlugin.getDefault().savePluginPreferences();
232: }
233:
234: /**
235: * Request notification when the activation state changes for the given
236: * viewer id.
237: *
238: * @param aListener
239: * An implementation of {@link IExtensionActivationListener}
240: */
241: public void addExtensionActivationListener(
242: IExtensionActivationListener aListener) {
243: listeners.add(aListener);
244: }
245:
246: /**
247: * No longer receive notification when activation state changes.
248: *
249: * @param aListener
250: * An implementation of {@link IExtensionActivationListener}
251: */
252: public void removeExtensionActivationListener(
253: IExtensionActivationListener aListener) {
254: listeners.remove(aListener);
255: }
256:
257: private void notifyListeners(String[] navigatorExtensionIds,
258: boolean toEnable) {
259:
260: if (navigatorExtensionIds != null) { // should really never be null, but just in case
261: if (navigatorExtensionIds.length > 1)
262: Arrays.sort(navigatorExtensionIds);
263:
264: Object[] listenerArray = listeners.getListeners();
265: for (int i = 0; i < listenerArray.length; i++) {
266: ((IExtensionActivationListener) listenerArray[i])
267: .onExtensionActivation(contentService
268: .getViewerId(), navigatorExtensionIds,
269: toEnable);
270: }
271: }
272:
273: }
274:
275: private void revertExtensionActivations() {
276:
277: Preferences preferences = NavigatorPlugin.getDefault()
278: .getPluginPreferences();
279:
280: String activatedExtensionsString = preferences
281: .getString(getPreferenceKey());
282:
283: if (activatedExtensionsString != null
284: && activatedExtensionsString.length() > 0) {
285: String[] contentExtensionIds = activatedExtensionsString
286: .split(DELIM);
287:
288: String id = null;
289: String booleanString = null;
290: int indx = 0;
291: for (int i = 0; i < contentExtensionIds.length; i++) {
292: //activatedExtensions.add(contentExtensionIds[i]);
293: if ((indx = contentExtensionIds[i].indexOf(EQUALS)) > -1) {
294: // up to but not including the equals
295: id = contentExtensionIds[i].substring(0, indx);
296: booleanString = contentExtensionIds[i].substring(
297: indx + 1, contentExtensionIds[i].length());
298: activatedExtensionsMap.put(id, Boolean
299: .valueOf(booleanString));
300: } else {
301: // IS THIS THE RIGHT WAY TO HANDLE THIS CASE?
302: NavigatorContentDescriptor descriptor = CONTENT_DESCRIPTOR_REGISTRY
303: .getContentDescriptor(contentExtensionIds[i]);
304: if (descriptor != null)
305: activatedExtensionsMap.put(id,
306: Boolean.valueOf(descriptor
307: .isActiveByDefault()));
308: }
309: }
310:
311: } else {
312: /*
313: * We add the default activation of every known extension, even
314: * though some may not be bound to the associated content service;
315: * this is because they could be bound at a later time through the
316: * programmatic binding mechanism in INavigatorContentService.
317: */
318: INavigatorContentDescriptor[] contentDescriptors = CONTENT_DESCRIPTOR_REGISTRY
319: .getAllContentDescriptors();
320: for (int i = 0; i < contentDescriptors.length; i++) {
321: if (contentDescriptors[i].isActiveByDefault()) {
322: //activatedExtensions.add(contentDescriptors[i].getId());
323: activatedExtensionsMap.put(contentDescriptors[i]
324: .getId(), Boolean.TRUE);
325: }
326: }
327: }
328: }
329:
330: private String getPreferenceKey() {
331: return contentService.getViewerId() + ACTIVATED_EXTENSIONS;
332: }
333:
334: public INavigatorContentDescriptor[] activateExtensions(
335: String[] extensionIds, boolean toDeactivateAllOthers) {
336:
337: Set activatedDescriptors = new HashSet();
338: setActive(extensionIds, true);
339: for (int extId = 0; extId < extensionIds.length; extId++) {
340: activatedDescriptors.add(CONTENT_DESCRIPTOR_REGISTRY
341: .getContentDescriptor(extensionIds[extId]));
342: }
343:
344: if (toDeactivateAllOthers) {
345: NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
346: .getAllContentDescriptors();
347: List descriptorList = new ArrayList(Arrays
348: .asList(descriptors));
349:
350: for (int descriptorIndx = 0; descriptorIndx < descriptors.length; descriptorIndx++) {
351: for (int extId = 0; extId < extensionIds.length; extId++) {
352: if (descriptors[descriptorIndx].getId().equals(
353: extensionIds[extId])) {
354: descriptorList
355: .remove(descriptors[descriptorIndx]);
356: }
357: }
358: }
359:
360: String[] deactivatedExtensions = new String[descriptorList
361: .size()];
362: for (int i = 0; i < descriptorList.size(); i++) {
363: INavigatorContentDescriptor descriptor = (INavigatorContentDescriptor) descriptorList
364: .get(i);
365: deactivatedExtensions[i] = descriptor.getId();
366: }
367: setActive(deactivatedExtensions, false);
368: }
369:
370: if (activatedDescriptors.size() == 0) {
371: return NO_DESCRIPTORS;
372: }
373: return (INavigatorContentDescriptor[]) activatedDescriptors
374: .toArray(new NavigatorContentDescriptor[activatedDescriptors
375: .size()]);
376: }
377:
378: public INavigatorContentDescriptor[] deactivateExtensions(
379: String[] extensionIds, boolean toEnableAllOthers) {
380:
381: Set activatedDescriptors = new HashSet();
382: setActive(extensionIds, false);
383:
384: if (toEnableAllOthers) {
385: NavigatorContentDescriptor[] descriptors = CONTENT_DESCRIPTOR_REGISTRY
386: .getAllContentDescriptors();
387: List descriptorList = new ArrayList(Arrays
388: .asList(descriptors));
389:
390: for (int descriptorIndx = 0; descriptorIndx < descriptors.length; descriptorIndx++) {
391: for (int extId = 0; extId < extensionIds.length; extId++) {
392: if (descriptors[descriptorIndx].getId().equals(
393: extensionIds[extId])) {
394: descriptorList
395: .remove(descriptors[descriptorIndx]);
396: }
397: }
398: }
399:
400: String[] activatedExtensions = new String[descriptorList
401: .size()];
402: for (int i = 0; i < descriptorList.size(); i++) {
403: NavigatorContentDescriptor descriptor = (NavigatorContentDescriptor) descriptorList
404: .get(i);
405: activatedExtensions[i] = descriptor.getId();
406: activatedDescriptors.add(descriptor);
407: }
408: setActive(activatedExtensions, true);
409: }
410: if (activatedDescriptors.size() == 0) {
411: return NO_DESCRIPTORS;
412: }
413:
414: return (INavigatorContentDescriptor[]) activatedDescriptors
415: .toArray(new NavigatorContentDescriptor[activatedDescriptors
416: .size()]);
417: }
418:
419: }
|