| /******************************************************************************* |
| * Copyright (c) 2000, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.core.commands.contexts; |
| |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import org.eclipse.core.commands.common.HandleObjectManager; |
| import org.eclipse.core.commands.util.Tracing; |
| import org.eclipse.core.internal.commands.util.Util; |
| |
| /** |
| * <p> |
| * A context manager tracks the sets of defined and enabled contexts within the |
| * application. The manager sends notification events to listeners when these |
| * sets change. It is also possible to retrieve any given context with its |
| * identifier. |
| * </p> |
| * <p> |
| * This class is not intended to be extended by clients. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| public final class ContextManager extends HandleObjectManager implements |
| IContextListener { |
| |
| private static final String DEFER_EVENTS = "org.eclipse.ui.internal.contexts.deferEvents"; //$NON-NLS-1$ |
| private static final String SEND_EVENTS = "org.eclipse.ui.internal.contexts.sendEvents"; //$NON-NLS-1$ |
| |
| /** |
| * This flag can be set to <code>true</code> if the context manager should |
| * print information to <code>System.out</code> when certain boundary |
| * conditions occur. |
| */ |
| public static boolean DEBUG = false; |
| |
| /** |
| * The set of active context identifiers. This value may be empty, but it is |
| * never <code>null</code>. |
| */ |
| private Set activeContextIds = new HashSet(); |
| |
| // allow the ContextManager to send one event for a larger delta |
| private boolean caching = false; |
| |
| private int cachingRef = 0; |
| |
| private boolean activeContextsChange = false; |
| |
| private Set oldIds = null; |
| |
| /** |
| * Activates a context in this context manager. |
| * |
| * @param contextId |
| * The identifier of the context to activate; must not be |
| * <code>null</code>. |
| */ |
| public final void addActiveContext(final String contextId) { |
| if (DEFER_EVENTS.equals(contextId)) { |
| cachingRef++; |
| if (cachingRef==1) { |
| setEventCaching(true); |
| } |
| return; |
| } else if (SEND_EVENTS.equals(contextId)) { |
| cachingRef--; |
| if (cachingRef==0) { |
| setEventCaching(false); |
| } |
| return; |
| } |
| |
| if (activeContextIds.contains(contextId)) { |
| return; |
| } |
| activeContextsChange = true; |
| |
| if (caching) { |
| activeContextIds.add(contextId); |
| } else { |
| final Set previouslyActiveContextIds = new HashSet(activeContextIds); |
| activeContextIds.add(contextId); |
| |
| fireContextManagerChanged(new ContextManagerEvent(this, null, |
| false, true, previouslyActiveContextIds)); |
| } |
| |
| if (DEBUG) { |
| Tracing.printTrace("CONTEXTS", activeContextIds.toString()); //$NON-NLS-1$ |
| } |
| |
| } |
| |
| /** |
| * Adds a listener to this context manager. The listener will be notified |
| * when the set of defined contexts changes. This can be used to track the |
| * global appearance and disappearance of contexts. |
| * |
| * @param listener |
| * The listener to attach; must not be <code>null</code>. |
| */ |
| public final void addContextManagerListener( |
| final IContextManagerListener listener) { |
| addListenerObject(listener); |
| } |
| |
| public final void contextChanged(final ContextEvent contextEvent) { |
| if (contextEvent.isDefinedChanged()) { |
| final Context context = contextEvent.getContext(); |
| final String contextId = context.getId(); |
| final boolean contextIdAdded = context.isDefined(); |
| if (contextIdAdded) { |
| definedHandleObjects.add(context); |
| } else { |
| definedHandleObjects.remove(context); |
| } |
| if (isListenerAttached()) { |
| fireContextManagerChanged(new ContextManagerEvent(this, |
| contextId, contextIdAdded, false, null)); |
| } |
| } |
| } |
| |
| /** |
| * Notifies all of the listeners to this manager that the set of defined |
| * context identifiers has changed. |
| * |
| * @param event |
| * The event to send to all of the listeners; must not be |
| * <code>null</code>. |
| */ |
| private final void fireContextManagerChanged(final ContextManagerEvent event) { |
| if (event == null) { |
| throw new NullPointerException(); |
| } |
| |
| final Object[] listeners = getListeners(); |
| for (int i = 0; i < listeners.length; i++) { |
| final IContextManagerListener listener = (IContextManagerListener) listeners[i]; |
| listener.contextManagerChanged(event); |
| } |
| } |
| |
| /** |
| * Returns the set of active context identifiers. |
| * |
| * @return The set of active context identifiers; this value may be |
| * <code>null</code> if no active contexts have been set yet. If |
| * the set is not <code>null</code>, then it contains only |
| * instances of <code>String</code>. |
| */ |
| public final Set getActiveContextIds() { |
| return Collections.unmodifiableSet(activeContextIds); |
| } |
| |
| /** |
| * Gets the context with the given identifier. If no such context currently |
| * exists, then the context will be created (but be undefined). |
| * |
| * @param contextId |
| * The identifier to find; must not be <code>null</code>. |
| * @return The context with the given identifier; this value will never be |
| * <code>null</code>, but it might be undefined. |
| * @see Context |
| */ |
| public final Context getContext(final String contextId) { |
| checkId(contextId); |
| |
| Context context = (Context) handleObjectsById.get(contextId); |
| if (context == null) { |
| context = new Context(contextId); |
| handleObjectsById.put(contextId, context); |
| context.addContextListener(this); |
| } |
| |
| return context; |
| } |
| |
| /** |
| * Returns the set of identifiers for those contexts that are defined. |
| * |
| * @return The set of defined context identifiers; this value may be empty, |
| * but it is never <code>null</code>. |
| */ |
| public final Set getDefinedContextIds() { |
| return getDefinedHandleObjectIds(); |
| } |
| |
| /** |
| * Returns the those contexts that are defined. |
| * |
| * @return The defined contexts; this value may be empty, but it is never |
| * <code>null</code>. |
| * @since 3.2 |
| */ |
| public final Context[] getDefinedContexts() { |
| return (Context[]) definedHandleObjects |
| .toArray(new Context[definedHandleObjects.size()]); |
| } |
| |
| /** |
| * Deactivates a context in this context manager. |
| * |
| * @param contextId |
| * The identifier of the context to deactivate; must not be |
| * <code>null</code>. |
| */ |
| public final void removeActiveContext(final String contextId) { |
| if (!activeContextIds.contains(contextId)) { |
| return; |
| } |
| |
| activeContextsChange = true; |
| if (caching) { |
| activeContextIds.remove(contextId); |
| } else { |
| final Set previouslyActiveContextIds = new HashSet(activeContextIds); |
| activeContextIds.remove(contextId); |
| |
| fireContextManagerChanged(new ContextManagerEvent(this, null, |
| false, true, previouslyActiveContextIds)); |
| } |
| |
| if (DEBUG) { |
| Tracing.printTrace("CONTEXTS", activeContextIds.toString()); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Removes a listener from this context manager. |
| * |
| * @param listener |
| * The listener to be removed; must not be <code>null</code>. |
| */ |
| public final void removeContextManagerListener( |
| final IContextManagerListener listener) { |
| removeListenerObject(listener); |
| } |
| |
| /** |
| * Changes the set of active contexts for this context manager. The whole |
| * set is required so that internal consistency can be maintained and so |
| * that excessive recomputations do nothing occur. |
| * |
| * @param activeContextIds |
| * The new set of active context identifiers; may be |
| * <code>null</code>. |
| */ |
| public final void setActiveContextIds(final Set activeContextIds) { |
| if (Util.equals(this.activeContextIds, activeContextIds)) { |
| return; |
| } |
| |
| activeContextsChange = true; |
| |
| final Set previouslyActiveContextIds = this.activeContextIds; |
| if (activeContextIds != null) { |
| this.activeContextIds = new HashSet(); |
| this.activeContextIds.addAll(activeContextIds); |
| } else { |
| this.activeContextIds = null; |
| } |
| |
| if (DEBUG) { |
| Tracing.printTrace("CONTEXTS", (activeContextIds == null) ? "none" //$NON-NLS-1$ //$NON-NLS-2$ |
| : activeContextIds.toString()); |
| } |
| |
| if (!caching) { |
| fireContextManagerChanged(new ContextManagerEvent(this, null, |
| false, true, previouslyActiveContextIds)); |
| } |
| } |
| |
| /** |
| * Set the manager to cache context id changes. |
| * |
| * @param cache |
| * <code>true</code> to turn caching on, <code>false</code> |
| * to turn caching off and send an event if necessary. |
| * @since 3.3 |
| */ |
| private void setEventCaching(boolean cache) { |
| if (caching == cache) { |
| return; |
| } |
| caching = cache; |
| boolean fireChange = activeContextsChange; |
| Set holdOldIds = (oldIds==null?Collections.EMPTY_SET:oldIds); |
| |
| if (caching) { |
| oldIds = new HashSet(activeContextIds); |
| } else { |
| oldIds = null; |
| } |
| activeContextsChange = false; |
| |
| if (!caching && fireChange) { |
| fireContextManagerChanged(new ContextManagerEvent(this, null, |
| false, true, holdOldIds)); |
| } |
| } |
| } |