From accf3397d92ce951b630fcac25908e452401d9d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= <laeubi@laeubi-soft.de>
Date: Fri, 31 Jan 2025 09:09:36 +0100
Subject: [PATCH] Consider Activity Filtering when running in E3 compatibility
 mode

Currently contributions by E4 are not filtered using the E3 activity
mechanism as it is a pure E3 concept.

To improve integration and interaction of E4 and E3 when using the
compatibility layer this now installs a WorkbenchContributionFactory
into the application context that additionally takes activity filtering
of the E3 workbench into account.

See https://github.com/eclipse-platform/eclipse.platform.ui/issues/2217
---
 .../META-INF/MANIFEST.MF                      |  2 +-
 .../swt/AbstractContributionItem.java         | 12 +++
 .../DynamicContributionContributionItem.java  | 14 +++-
 .../renderers/swt/MenuManagerRenderer.java    |  4 +-
 .../META-INF/MANIFEST.MF                      |  2 +-
 .../org/eclipse/ui/internal/Workbench.java    |  3 +
 .../WorkbenchContributionFactory.java         | 74 +++++++++++++++++++
 7 files changed, 107 insertions(+), 4 deletions(-)
 create mode 100644 bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchContributionFactory.java

diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF
index 2bef9ec5ed5..cb4ef940ce1 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/META-INF/MANIFEST.MF
@@ -7,7 +7,7 @@ Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-17
 Require-Bundle: org.eclipse.e4.ui.workbench;bundle-version="0.9.0",
- org.eclipse.e4.core.services;bundle-version="0.9.0",
+ org.eclipse.e4.core.services;bundle-version="2.5.100",
  org.eclipse.e4.core.contexts;bundle-version="1.0.0",
  org.eclipse.e4.core.di;bundle-version="1.1.0",
  org.eclipse.e4.ui.services;bundle-version="0.9.0",
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/AbstractContributionItem.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/AbstractContributionItem.java
index 5328ea19862..cf5130c4a90 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/AbstractContributionItem.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/AbstractContributionItem.java
@@ -20,6 +20,7 @@
 import org.eclipse.e4.core.contexts.IContextFunction;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.contributions.IContributionFactory;
 import org.eclipse.e4.core.services.log.Logger;
 import org.eclipse.e4.ui.internal.workbench.RenderedElementUtil;
 import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
@@ -84,6 +85,9 @@ public abstract class AbstractContributionItem extends ContributionItem {
 	@Optional
 	protected EHelpService helpService;
 
+	@Inject
+	protected IContributionFactory contributionFactory;
+
 	protected Widget widget;
 	protected Listener menuItemListener;
 	protected LocalResourceManager localResourceManager;
@@ -126,6 +130,14 @@ public void update(String id) {
 		}
 	}
 
+	@Override
+	public boolean isVisible() {
+		if (contributionFactory.isEnabled(modelItem.getContributorURI())) {
+			return super.isVisible();
+		}
+		return false;
+	}
+
 	protected abstract void updateMenuItem();
 
 	protected abstract void updateToolItem();
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/DynamicContributionContributionItem.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/DynamicContributionContributionItem.java
index 65d6b294414..8b46ea8caa5 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/DynamicContributionContributionItem.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/DynamicContributionContributionItem.java
@@ -14,6 +14,7 @@
 
 package org.eclipse.e4.ui.workbench.renderers.swt;
 
+import org.eclipse.e4.core.services.contributions.IContributionFactory;
 import org.eclipse.e4.ui.model.application.ui.menu.MDynamicMenuContribution;
 import org.eclipse.jface.action.ContributionItem;
 import org.eclipse.jface.action.IContributionManager;
@@ -29,12 +30,15 @@ class DynamicContributionContributionItem extends ContributionItem {
 
 	private IMenuListener menuListener = IMenuManager::markDirty;
 
+	private IContributionFactory factory;
+
 	/**
 	 * Create the item and associated model;
 	 */
-	public DynamicContributionContributionItem(MDynamicMenuContribution item) {
+	public DynamicContributionContributionItem(MDynamicMenuContribution item, IContributionFactory factory) {
 		super(item.getElementId());
 		model = item;
+		this.factory = factory;
 	}
 
 	@Override
@@ -54,6 +58,14 @@ public MDynamicMenuContribution getModel() {
 		return model;
 	}
 
+	@Override
+	public boolean isVisible() {
+		if (factory.isEnabled(model.getContributionURI())) {
+			return super.isVisible();
+		}
+		return false;
+	}
+
 	@Override
 	public void setParent(IContributionManager parent) {
 		if (getParent() instanceof IMenuManager) {
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerRenderer.java
index 5b9ba5d721e..4511f01b4d7 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerRenderer.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/MenuManagerRenderer.java
@@ -45,6 +45,7 @@
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.contexts.RunAndTrack;
 import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.contributions.IContributionFactory;
 import org.eclipse.e4.core.services.log.Logger;
 import org.eclipse.e4.ui.di.UIEventTopic;
 import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
@@ -783,7 +784,8 @@ private void processDynamicMenuContribution(MenuManager menuManager, MDynamicMen
 			return;
 		}
 		itemModel.setRenderer(this);
-		DynamicContributionContributionItem ci = new DynamicContributionContributionItem(itemModel);
+		DynamicContributionContributionItem ci = new DynamicContributionContributionItem(itemModel,
+				application.getContext().get(IContributionFactory.class));
 		addToManager(menuManager, itemModel, ci);
 		linkModelToContribution(itemModel, ci);
 	}
diff --git a/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF
index 2e8dd48038b..4401f18cb5b 100644
--- a/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ui.workbench/META-INF/MANIFEST.MF
@@ -100,7 +100,7 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.33.0,4.0.0)",
  org.eclipse.jface.databinding;bundle-version="[1.3.0,2.0.0)",
  org.eclipse.core.databinding.property;bundle-version="[1.2.0,2.0.0)",
  org.eclipse.core.databinding.observable;bundle-version="[1.2.0,2.0.0)",
- org.eclipse.e4.core.services;bundle-version="2.2.0",
+ org.eclipse.e4.core.services;bundle-version="2.5.100",
  org.eclipse.e4.core.contexts;bundle-version="1.0.0",
  org.eclipse.e4.core.di;bundle-version="1.1.0",
  org.eclipse.e4.ui.workbench.swt;bundle-version="0.9.1",
diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java
index a3deccb4e22..8f656fffa9d 100644
--- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java
+++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java
@@ -457,6 +457,7 @@ public void serviceChanged(ServiceEvent event) {
 	 *                specializes this workbench instance
 	 * @since 3.0
 	 */
+	@SuppressWarnings("restriction")
 	private Workbench(Display display, final WorkbenchAdvisor advisor, MApplication app, IEclipseContext appContext) {
 		this.advisor = Objects.requireNonNull(advisor);
 		this.display = Objects.requireNonNull(display);
@@ -492,6 +493,8 @@ public void eventLoopException(Throwable exception) {
 				advisor.eventLoopException(exception);
 			}
 		});
+		appContext.set(org.eclipse.e4.core.services.contributions.IContributionFactory.class,
+				new WorkbenchContributionFactory(this));
 
 		// for dynamic UI [This seems to be for everything that isn't handled by
 		// some
diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchContributionFactory.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchContributionFactory.java
new file mode 100644
index 00000000000..c2e0bec3025
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchContributionFactory.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2025 Christoph Läubrich 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:
+ *     Christoph Läubrich - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.services.contributions.IContributionFactory;
+import org.eclipse.ui.activities.IIdentifier;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.osgi.framework.Bundle;
+
+/**
+ * Contribution factory that uses a delegate and additionally provides behavior
+ * from the {@link Workbench} services.
+ *
+ */
+@SuppressWarnings("restriction")
+class WorkbenchContributionFactory implements IContributionFactory {
+
+	private static final String BUNDLE_CLASS_PREFIX = "bundleclass://"; //$NON-NLS-1$
+
+	private final IContributionFactory delegate;
+
+	private final IEclipseContext context;
+
+	private IWorkbenchActivitySupport activitySupport;
+
+	WorkbenchContributionFactory(Workbench workbench) {
+		context = workbench.getApplication().getContext();
+		delegate = context.get(IContributionFactory.class);
+	}
+
+	@Override
+	public Object create(String uriString, IEclipseContext context) {
+		return delegate.create(uriString, context);
+	}
+
+	@Override
+	public Object create(String uriString, IEclipseContext context, IEclipseContext staticContext) {
+		return delegate.create(uriString, context, staticContext);
+	}
+
+	@Override
+	public Bundle getBundle(String uriString) {
+		return delegate.getBundle(uriString);
+	}
+
+	@Override
+	public boolean isEnabled(String uriString) {
+		if (uriString != null && uriString.startsWith(BUNDLE_CLASS_PREFIX)) {
+			String identifierId = uriString.substring(BUNDLE_CLASS_PREFIX.length());
+			if (activitySupport == null) {
+				activitySupport = context.get(IWorkbenchActivitySupport.class);
+			}
+			IIdentifier identifier = activitySupport.getActivityManager().getIdentifier(identifierId);
+			if (!identifier.isEnabled()) {
+				return false;
+			}
+		}
+		return delegate.isEnabled(uriString);
+	}
+
+}