Bug 390379 - [Performance] Seemingly excessive calls to contextManager
diff --git a/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/internal/services/ContextContextService.java b/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/internal/services/ContextContextService.java
index ce839b9..90629d3 100644
--- a/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/internal/services/ContextContextService.java
+++ b/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/internal/services/ContextContextService.java
@@ -25,6 +25,10 @@
 
 	private IEclipseContext eclipseContext;
 	private ContextManager contextManager;
+	
+	private boolean deferUpdates = false;
+
+	private int cachingRef = 0;
 
 	public ContextContextService(IEclipseContext context) {
 		eclipseContext = context;
@@ -40,6 +44,10 @@
 	 * String)
 	 */
 	public void activateContext(String id) {
+		if (deferUpdates) {
+			deferActivateContext(id);
+			return;
+		}
 		LinkedList<String> locals = (LinkedList<String>) eclipseContext
 				.getLocal(LOCAL_CONTEXTS);
 		if (locals == null) {
@@ -54,7 +62,76 @@
 			}
 		}
 	}
+	
+	/**
+	 * Informs the manager that a batch operation has started.
+	 * <p>
+	 * <b>Note:</b> You must insure that if you call
+	 * <code>deferUpdates(true)</code> that nothing in your batched operation
+	 * will prevent the matching call to <code>deferUpdates(false)</code>.
+	 * </p>
+	 * 
+	 * @param defer
+	 *            true when starting a batch operation false when ending the
+	 *            operation
+	 * 
+	 * @since 4.3
+	 */
+	public void deferUpdates(boolean defer) {
+		if(defer) {
+			cachingRef ++;
+			if (cachingRef==1) {
+				setEventCaching(true);
+			}
+		}else {
+			cachingRef--;
+			if (cachingRef==0) {
+				setEventCaching(false);
+			}
+		}
+	}
 
+	private void deferActivateContext(String id) {
+		LinkedList<String> locals = (LinkedList<String>) eclipseContext
+				.getLocal(LOCAL_CONTEXTS+".a");
+		if (locals == null) {
+			locals = new LinkedList<String>();
+			eclipseContext.set(LOCAL_CONTEXTS+ ".a", locals);
+		}
+		locals.add(id);
+	}
+
+	private void setEventCaching(boolean cache) {
+		if (cache) {
+			deferUpdates = true;
+			return;
+		}
+
+		deferUpdates = false;
+		LinkedList<String> locals = (LinkedList<String>) eclipseContext
+				.getLocal(LOCAL_CONTEXTS);
+		if (locals == null) {
+			locals = new LinkedList<String>();
+		}
+		LinkedList<String> activates = (LinkedList<String>) eclipseContext
+				.getLocal(LOCAL_CONTEXTS + ".a");
+		if (activates != null) {
+			eclipseContext.remove(LOCAL_CONTEXTS + ".a");
+			for (String id : activates) {
+				locals.add(id);
+			}
+		}
+		LinkedList<String> deactivates = (LinkedList<String>) eclipseContext
+				.getLocal(LOCAL_CONTEXTS + ".d");
+		if (deactivates != null) {
+			eclipseContext.remove(LOCAL_CONTEXTS + ".d");
+			for (String id : deactivates) {
+				locals.remove(id);
+			}
+		}
+		eclipseContext.set(LOCAL_CONTEXTS, locals.clone());
+	}
+	
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -63,6 +140,10 @@
 	 * .String)
 	 */
 	public void deactivateContext(String id) {
+		if (deferUpdates) {
+			deferDeactivateContext(id);
+			return;
+		}
 		LinkedList<String> locals = (LinkedList<String>) eclipseContext
 				.getLocal(LOCAL_CONTEXTS);
 		if (locals != null && locals.remove(id)) {
@@ -74,6 +155,16 @@
 		}
 	}
 
+	private void deferDeactivateContext(String id) {
+		LinkedList<String> locals = (LinkedList<String>) eclipseContext
+				.getLocal(LOCAL_CONTEXTS+".d");
+		if (locals == null) {
+			locals = new LinkedList<String>();
+			eclipseContext.set(LOCAL_CONTEXTS+ ".d", locals);
+		}
+		locals.add(id);
+	}
+
 	/*
 	 * (non-Javadoc)
 	 * 
diff --git a/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/services/EContextService.java b/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/services/EContextService.java
index ffaa03b..a754b2c 100644
--- a/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/services/EContextService.java
+++ b/bundles/org.eclipse.e4.ui.services/src/org/eclipse/e4/ui/services/EContextService.java
@@ -22,4 +22,6 @@
 	public void deactivateContext(String id);
 	
 	public Collection<String> getActiveContextIds();
+	
+	public void deferUpdates(boolean defer);
 }
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/PartServiceImpl.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/PartServiceImpl.java
index 20138a8..89df348 100644
--- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/PartServiceImpl.java
+++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/PartServiceImpl.java
@@ -46,6 +46,7 @@
 import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
 import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicFactoryImpl;
 import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.services.EContextService;
 import org.eclipse.e4.ui.services.IServiceConstants;
 import org.eclipse.e4.ui.workbench.IPresentationEngine;
 import org.eclipse.e4.ui.workbench.UIEvents;
@@ -125,6 +126,9 @@
 	@Inject
 	private IEventBroker eventBroker;
 
+	@Inject
+	private EContextService contextService;
+
 	private PartActivationHistory partActivationHistory;
 
 	private MPart activePart;
@@ -544,32 +548,37 @@
 			UIEvents.publishEvent(UIEvents.UILifeCycle.ACTIVATE, part);
 			return;
 		}
+		contextService.deferUpdates(true);
+		try {
+			// record any sibling into the activation history if necessary, this will allow it to be
+			// reselected again in the future as it will be an activation candidate in the future,
+			// this
+			// prevents other unrendered elements from being selected arbitrarily which would cause
+			// unwanted bundle activation
+			recordStackActivation(part);
 
-		// record any sibling into the activation history if necessary, this will allow it to be
-		// reselected again in the future as it will be an activation candidate in the future, this
-		// prevents other unrendered elements from being selected arbitrarily which would cause
-		// unwanted bundle activation
-		recordStackActivation(part);
+			delegateBringToTop(part);
+			window.getParent().setSelectedElement(window);
 
-		delegateBringToTop(part);
-		window.getParent().setSelectedElement(window);
+			partActivationHistory.activate(part, activateBranch);
 
-		partActivationHistory.activate(part, activateBranch);
+			Object object = part.getObject();
+			if (object != null && requiresFocus) {
+				try {
+					ContextInjectionFactory.invoke(object, Focus.class, part.getContext(), null);
 
-		Object object = part.getObject();
-		if (object != null && requiresFocus) {
-			try {
-				ContextInjectionFactory.invoke(object, Focus.class, part.getContext(), null);
-
-				firePartActivated(part);
-				UIEvents.publishEvent(UIEvents.UILifeCycle.ACTIVATE, part);
-			} catch (InjectionException e) {
-				log("Failed to grant focus to part", "Failed to grant focus to part ({0})", //$NON-NLS-1$ //$NON-NLS-2$
-						part.getElementId(), e);
-			} catch (RuntimeException e) {
-				log("Failed to grant focus to part via DI", //$NON-NLS-1$
-						"Failed to grant focus via DI to part ({0})", part.getElementId(), e); //$NON-NLS-1$
+					firePartActivated(part);
+					UIEvents.publishEvent(UIEvents.UILifeCycle.ACTIVATE, part);
+				} catch (InjectionException e) {
+					log("Failed to grant focus to part", "Failed to grant focus to part ({0})", //$NON-NLS-1$ //$NON-NLS-2$
+							part.getElementId(), e);
+				} catch (RuntimeException e) {
+					log("Failed to grant focus to part via DI", //$NON-NLS-1$
+							"Failed to grant focus via DI to part ({0})", part.getElementId(), e); //$NON-NLS-1$
+				}
 			}
+		} finally {
+			contextService.deferUpdates(false);
 		}
 	}
 
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 f471cbe..4205cbc 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
@@ -92,6 +92,7 @@
 	 */
 	public void deferUpdates(boolean defer) {
 		contextManager.deferUpdates(defer);
+		contextService.deferUpdates(defer);
 	}
 
 	/*