blob: 0b4310c7e9d65b5bb035342a4141292ed6308082 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.ui.actions;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionInfo;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.internal.expressions.AndExpression;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.ActiveShellExpression;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.swt.IFocusService;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
/**
* Helper to use services for one or multiple specified SWT controls.
*
* DEV: At moment only {@link IHandlerService}, but other services can be added later if required
*/
@NonNullByDefault
public class ControlServicesUtil {
private class FocusExpression extends Expression {
String getFocusControlId() {
return ControlServicesUtil.this.id;
}
@Override
public EvaluationResult evaluate(final IEvaluationContext context) throws CoreException {
final Object id= context.getVariable(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME);
return EvaluationResult.valueOf(ControlServicesUtil.this.id == id);
}
@Override
public void collectExpressionInfo(final ExpressionInfo info) {
info.addVariableNameAccess(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME);
}
@Override
protected int computeHashCode() {
return FocusExpression.class.hashCode() * HASH_FACTOR +
hashCode(ControlServicesUtil.this.id) * HASH_FACTOR;
}
@Override
public boolean equals(final @Nullable Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof FocusExpression) {
final FocusExpression other= (FocusExpression)obj;
return ControlServicesUtil.this.id.equals(other.getFocusControlId());
}
return false;
}
}
private final String id;
private final IServiceLocator serviceLocator;
private final Expression defaultExpression;
private boolean requireDeactivation;
private @Nullable IHandlerService handlerService;
private @Nullable List<IHandlerActivation> activatedHandlers;
/**
* Creates a new util for services of the specified service locator.
*
* @param serviceLocator the servicelocator to be used
* @param id for control (group)
* @param parentControl used to get shell and listen for dispose event
*/
public ControlServicesUtil(final IServiceLocator serviceLocator, final String id,
final Control parentControl) {
assert (serviceLocator != null);
assert (id != null);
assert (parentControl != null);
this.id= id;
this.serviceLocator= serviceLocator;
this.defaultExpression= initExpression(parentControl);
parentControl.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(final DisposeEvent e) {
dispose();
}
});
}
private Expression initExpression(final Control control) {
Expression focusExpression= new FocusExpression();
if (this.serviceLocator instanceof IWorkbench) {
final AndExpression and= new AndExpression();
and.add(new ActiveShellExpression(control.getShell()));
and.add(focusExpression);
this.requireDeactivation= true;
return and;
}
else if (this.serviceLocator instanceof IWorkbenchPage
&& !control.getShell().equals(
((IWorkbenchPage)this.serviceLocator).getWorkbenchWindow().getShell() )) {
final AndExpression and= new AndExpression();
and.add(new ActiveShellExpression(control.getShell()));
and.add(focusExpression);
this.requireDeactivation= true;
return and;
}
else {
this.requireDeactivation= false;
return focusExpression;
}
}
public void addControl(final Control control) {
final IFocusService focusService= nonNullAssert(
this.serviceLocator.getService(IFocusService.class) );
focusService.addFocusTracker(control, this.id);
}
public Expression getExpression() {
return this.defaultExpression;
}
public void activateHandler(final String commandId, final IHandler handler) {
IHandlerService handlerService= this.handlerService;
if (handlerService == null) {
handlerService= nonNullAssert(
this.serviceLocator.getService(IHandlerService.class) );
this.handlerService= handlerService;
if (this.requireDeactivation) {
this.activatedHandlers= new ArrayList<>();
}
}
final IHandlerActivation handlerActivation= handlerService.activateHandler(
commandId, handler, this.defaultExpression );
final List<IHandlerActivation> activatedHandlers= this.activatedHandlers;
if (activatedHandlers != null) {
activatedHandlers.add(handlerActivation);
}
}
protected void dispose() {
IHandlerService handlerService= this.handlerService;
if (handlerService != null) {
this.handlerService= null;
if (this.activatedHandlers != null) {
handlerService.deactivateHandlers(this.activatedHandlers);
this.activatedHandlers= null;
}
}
}
}