blob: de6caf17b560de2a2d8703eb251b614ea4460211 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.ui.internal.contexts;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.contexts.Context;
import org.eclipse.core.commands.contexts.IContextManagerListener;
import org.eclipse.core.expressions.AndExpression;
import org.eclipse.core.expressions.Expression;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ISourceProvider;
import org.eclipse.ui.contexts.IContextActivation;
import org.eclipse.ui.contexts.IContextService;
/**
* A context service which delegates almost all responsibility to the parent
* service.
* <p>
* This class is not intended for use outside of the
* <code>org.eclipse.ui.workbench</code> plug-in.
* </p>
*
* @since 3.2
*
*/
public class SlaveContextService implements IContextService {
/**
* The parent context service, which is never <code>null</code>.
*/
protected IContextService fParentService;
/**
* The default expression used when {@link #activateContext(String) } is called.
* Contexts contributed that use this expression will only be active with this
* service is active.
*/
protected Expression fDefaultExpression;
/**
* Our contexts that are currently active with the parent context service.
*/
protected Set<IContextActivation> fParentActivations;
/**
* A map of the local activation to the parent activations. If this service is
* inactive, then all parent activations are <code>null</code>. Otherwise, they
* point to the corresponding activation in the parent service.
*/
protected Map<IContextActivation, IContextActivation> fLocalActivations;
/**
* A collection of context manager listeners. The listeners are not
* activated/deactivated, but they will be removed when this service is
* disposed.
*/
private Collection<IContextManagerListener> fContextManagerListeners;
/**
* A collection of source providers. The listeners are not
* activated/deactivated, but they will be removed when this service is
* disposed.
*/
private Collection<ISourceProvider> fSourceProviders;
/**
* A collection of shells registered through this service. The listeners are not
* activated/deactivated, but they will be removed when this service is
* disposed.
*/
private Collection<Shell> fRegisteredShells;
/**
* Construct the new slave.
*
* @param parentService the parent context service; must not be
* <code>null</code>.
* @param defaultExpression A default expression to use to determine viability.
* It's mainly used for conflict resolution. It can be
* <code>null</code>.
*/
public SlaveContextService(IContextService parentService, Expression defaultExpression) {
if (parentService == null) {
throw new NullPointerException("The parent context service must not be null"); //$NON-NLS-1$
}
fParentService = parentService;
fDefaultExpression = defaultExpression;
fParentActivations = new HashSet<>();
fLocalActivations = new HashMap<>();
fContextManagerListeners = new ArrayList<>();
fSourceProviders = new ArrayList<>();
fRegisteredShells = new ArrayList<>();
}
@Override
public void deferUpdates(boolean defer) {
fParentService.deferUpdates(defer);
}
@Override
public IContextActivation activateContext(String contextId) {
ContextActivation activation = new ContextActivation(contextId, fDefaultExpression, this);
return doActivateContext(activation);
}
@Override
public IContextActivation activateContext(String contextId, Expression expression) {
return activateContext(contextId, expression, false);
}
@Override
public IContextActivation activateContext(String contextId, Expression expression, boolean global) {
if (global) {
IContextActivation activation = fParentService.activateContext(contextId, expression, global);
fParentActivations.add(activation);
return activation;
}
Expression aExpression = fDefaultExpression;
if (expression != null && fDefaultExpression != null) {
final AndExpression andExpression = new AndExpression();
andExpression.add(expression);
andExpression.add(fDefaultExpression);
aExpression = andExpression;
} else if (expression != null) {
aExpression = expression;
}
ContextActivation activation = new ContextActivation(contextId, aExpression, this);
return doActivateContext(activation);
}
@Override
public IContextActivation activateContext(String contextId, Expression expression, int sourcePriorities) {
return activateContext(contextId, expression);
}
@Override
public void addContextManagerListener(IContextManagerListener listener) {
if (!fContextManagerListeners.contains(listener)) {
fContextManagerListeners.add(listener);
}
fParentService.addContextManagerListener(listener);
}
@Override
public void addSourceProvider(ISourceProvider provider) {
if (!fSourceProviders.contains(provider)) {
fSourceProviders.add(provider);
}
fParentService.addSourceProvider(provider);
}
@Override
public void deactivateContext(IContextActivation activation) {
IContextActivation parentActivation = null;
if (fLocalActivations.containsKey(activation)) {
parentActivation = fLocalActivations.remove(activation);
} else {
parentActivation = activation;
}
if (parentActivation != null) {
fParentService.deactivateContext(parentActivation);
fParentActivations.remove(parentActivation);
}
}
@Override
public void deactivateContexts(Collection activations) {
Object[] array = activations.toArray();
for (int i = 0; i < array.length; i++) {
deactivateContext((IContextActivation) array[i]);
array[i] = null;
}
}
@Override
public void dispose() {
fParentService.deactivateContexts(fParentActivations);
fParentActivations.clear();
fLocalActivations.clear();
// Remove any "resource", like listeners, that were associated
// with this service.
if (!fContextManagerListeners.isEmpty()) {
for (IContextManagerListener element : fContextManagerListeners.toArray(new IContextManagerListener[0])) {
removeContextManagerListener(element);
}
fContextManagerListeners.clear();
}
if (!fSourceProviders.isEmpty()) {
for (Object element : fSourceProviders.toArray()) {
removeSourceProvider((ISourceProvider) element);
}
fSourceProviders.clear();
}
if (!fRegisteredShells.isEmpty()) {
for (Object element : fRegisteredShells.toArray()) {
unregisterShell((Shell) element);
}
fRegisteredShells.clear();
}
}
/**
* Activate the context with respect to this slave service.
*
* @param contextId the context id
* @param expression the expression to use
* @return the activated context
*/
protected IContextActivation doActivateContext(IContextActivation activation) {
IContextActivation parentActivation = fParentService.activateContext(activation.getContextId(),
activation.getExpression());
fParentActivations.add(parentActivation);
fLocalActivations.put(activation, parentActivation);
return activation;
}
@Override
public Collection getActiveContextIds() {
return fParentService.getActiveContextIds();
}
@Override
public Context getContext(String contextId) {
return fParentService.getContext(contextId);
}
@Override
public Collection getDefinedContextIds() {
return fParentService.getDefinedContextIds();
}
@Override
public Context[] getDefinedContexts() {
return fParentService.getDefinedContexts();
}
@Override
public int getShellType(Shell shell) {
return fParentService.getShellType(shell);
}
@Override
public void readRegistry() {
fParentService.readRegistry();
}
@Override
public boolean registerShell(Shell shell, int type) {
if (!fRegisteredShells.contains(shell)) {
fRegisteredShells.add(shell);
}
return fParentService.registerShell(shell, type);
}
@Override
public void removeContextManagerListener(IContextManagerListener listener) {
fContextManagerListeners.remove(listener);
fParentService.removeContextManagerListener(listener);
}
@Override
public void removeSourceProvider(ISourceProvider provider) {
fSourceProviders.remove(provider);
fParentService.removeSourceProvider(provider);
}
@Override
public boolean unregisterShell(Shell shell) {
fRegisteredShells.remove(shell);
return fParentService.unregisterShell(shell);
}
}