Bug 366606 - [Compatibility] Failures in ContextsTestSuite

A change to allow the Workbench context service to calculate active
contexts, and then have it update the EContextService correctly.  The
old way sometimes removed a context too eagerly.

Bug: 366606
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java
index 0515c67..2d7c02c 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java
@@ -131,7 +131,7 @@
 import org.eclipse.ui.handlers.IHandlerService;
 import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
 import org.eclipse.ui.internal.actions.CommandAction;
-import org.eclipse.ui.internal.contexts.ContextService;
+import org.eclipse.ui.internal.contexts.SlaveContextService;
 import org.eclipse.ui.internal.dialogs.CustomizePerspectiveDialog;
 import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
 import org.eclipse.ui.internal.e4.compatibility.E4Util;
@@ -222,6 +222,7 @@
 	private boolean shellActivated = false;
 
 	ProgressRegion progressRegion = null;
+	private SlaveContextService contextService = null;
 
 	private List<MTrimElement> workbenchTrimElements = new ArrayList<MTrimElement>();
 
@@ -2264,9 +2265,19 @@
 		serviceLocator.registerService(LegacyActionPersistence.class, actionPersistence);
 		actionPersistence.read();
 
-		IContextService cxs = ContextInjectionFactory
-				.make(ContextService.class, model.getContext());
-		serviceLocator.registerService(IContextService.class, cxs);
+		windowContext.set(IContextService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context) {
+				if (contextService == null) {
+					contextService = new SlaveContextService(context.getParent().get(
+							IContextService.class), new ActiveShellExpression(getShell()));
+				}
+				return contextService;
+			}
+		});
+		// IContextService cxs = ContextInjectionFactory
+		// .make(ContextService.class, model.getContext());
+		// serviceLocator.registerService(IContextService.class, cxs);
 	}
 
 	public final Object getService(final Class key) {
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/contexts/ContextService.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/contexts/ContextService.java
index 8fb2bad..2b69319 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/contexts/ContextService.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/contexts/ContextService.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2012 IBM Corporation and others.
+ * Copyright (c) 2005, 2009 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
@@ -11,26 +11,21 @@
 package org.eclipse.ui.internal.contexts;
 
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Set;
 import javax.inject.Inject;
 import org.eclipse.core.commands.contexts.Context;
 import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.commands.contexts.ContextManagerEvent;
 import org.eclipse.core.commands.contexts.IContextManagerListener;
-import org.eclipse.core.expressions.EvaluationResult;
 import org.eclipse.core.expressions.Expression;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.e4.core.contexts.IEclipseContext;
-import org.eclipse.e4.core.contexts.RunAndTrack;
-import org.eclipse.e4.ui.di.UISynchronize;
 import org.eclipse.e4.ui.services.EContextService;
-import org.eclipse.e4.ui.workbench.modeling.ExpressionContext;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.ISourceProvider;
 import org.eclipse.ui.ISources;
 import org.eclipse.ui.contexts.IContextActivation;
 import org.eclipse.ui.contexts.IContextService;
-import org.eclipse.ui.internal.WorkbenchPlugin;
 
 /**
  * <p>
@@ -42,8 +37,6 @@
  */
 public final class ContextService implements IContextService {
 
-	private HashMap<IContextActivation, UpdateExpression> activationToRat = new HashMap<IContextActivation, ContextService.UpdateExpression>();
-
 	/**
 	 * The central authority for determining which context we should use.
 	 */
@@ -53,22 +46,36 @@
 	 * The context manager that supports this service. This value is never
 	 * <code>null</code>.
 	 */
-	private ContextManager contextManager;
-
-	@Inject
-	private EContextService contextService;
-
-	@Inject
-	private IEclipseContext eclipseContext;
-
-	@Inject
-	private UISynchronize synchService;
+	private final ContextManager contextManager;
 
 	/**
 	 * The persistence class for this context service.
 	 */
 	private final ContextPersistence contextPersistence;
 
+	@Inject
+	private EContextService contextService;
+
+	private IContextManagerListener syncToEclipse4 = new IContextManagerListener() {
+		public void contextManagerChanged(ContextManagerEvent contextManagerEvent) {
+			if (contextManagerEvent.isActiveContextsChanged()) {
+				final Set previouslyActiveContextIds = contextManagerEvent
+						.getPreviouslyActiveContextIds();
+				final Set activeContextIds = contextManager.getActiveContextIds();
+				final HashSet newlyActive = new HashSet(activeContextIds);
+				newlyActive.removeAll(previouslyActiveContextIds);
+				for (Object obj : newlyActive) {
+					contextService.activateContext((String) obj);
+				}
+				final HashSet noLongerActive = new HashSet(previouslyActiveContextIds);
+				noLongerActive.removeAll(activeContextIds);
+				for (Object obj : noLongerActive) {
+					contextService.deactivateContext((String) obj);
+				}
+			}
+		}
+	};
+
 	/**
 	 * Constructs a new instance of <code>ContextService</code> using a
 	 * context manager.
@@ -85,6 +92,7 @@
 		this.contextManager = contextManager;
 		this.contextAuthority = new ContextAuthority(contextManager, this);
 		this.contextPersistence = new ContextPersistence(contextManager);
+		contextManager.addContextManagerListener(syncToEclipse4);
 	}
 
 	/* (non-Javadoc)
@@ -103,47 +111,6 @@
 		return activateContext(contextId, null);
 	}
 
-	private class UpdateExpression extends RunAndTrack {
-		boolean updating = true;
-
-		private String contextId;
-		private Expression expression;
-
-		public UpdateExpression(String contextId, Expression expression) {
-			this.contextId = contextId;
-			this.expression = expression;
-		}
-
-		@Override
-		public boolean changed(IEclipseContext context) {
-			if (!updating) {
-				return false;
-			}
-			ExpressionContext ctx = new ExpressionContext(eclipseContext.getActiveLeaf());
-			try {
-				if (updating) {
-					if (expression.evaluate(ctx) != EvaluationResult.FALSE) {
-						runExternalCode(new Runnable() {
-							public void run() {
-								contextService.activateContext(contextId);
-							}
-						});
-					} else {
-						runExternalCode(new Runnable() {
-							public void run() {
-								contextService.deactivateContext(contextId);
-							}
-						});
-					}
-				}
-			} catch (CoreException e) {
-				// contextService.deactivateContext(contextId);
-				WorkbenchPlugin.log("Failed to update " + contextId, e); //$NON-NLS-1$
-			}
-			return updating;
-		}
-	}
-
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -156,13 +123,6 @@
 		final IContextActivation activation = new ContextActivation(contextId,
 				expression, this);
 		contextAuthority.activateContext(activation);
-		if (expression == null) {
-			contextService.activateContext(contextId);
-		} else {
-			final UpdateExpression runnable = new UpdateExpression(contextId, expression);
-			activationToRat.put(activation, runnable);
-			eclipseContext.runAndTrack(runnable);
-		}
 		return activation;
 	}
 
@@ -213,12 +173,7 @@
 	 * @see org.eclipse.ui.contexts.IContextService#deactivateContext(org.eclipse.ui.contexts.IContextActivation)
 	 */
 	public final void deactivateContext(final IContextActivation activation) {
-		if (activation != null && activation.getContextService() == this) {
-			final UpdateExpression rat = activationToRat.remove(activation);
-			if (rat != null) {
-				rat.updating = false;
-			}
-			contextService.deactivateContext(activation.getContextId());
+		if (activation.getContextService() == this) {
 			contextAuthority.deactivateContext(activation);
 		}
 	}
@@ -243,6 +198,7 @@
 	 * @see org.eclipse.ui.services.IDisposable#dispose()
 	 */
 	public final void dispose() {
+		contextManager.removeContextManagerListener(syncToEclipse4);
 		contextPersistence.dispose();
 		contextAuthority.dispose();
 	}
@@ -298,7 +254,7 @@
 	 * @see org.eclipse.ui.contexts.IContextService#readRegistry()
 	 */
 	public final void readRegistry() {
-		// contextPersistence.read();
+		contextPersistence.read();
 	}
 
 	/*