blob: 8037b93c08f173ca1e454530779f10bf1a5e3805 [file] [log] [blame]
/*******************************************************************************
* 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));
}
}
}