Bug 365903 - [Compatibility] Programmatic Contribution Factories not
supported

Add support for programmatic factories for toolbars
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarContributionRecord.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarContributionRecord.java
index 3642078..75ffd53 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarContributionRecord.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarContributionRecord.java
@@ -12,8 +12,12 @@
 package org.eclipse.e4.ui.workbench.renderers.swt;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IContextFunction;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
 import org.eclipse.e4.ui.model.application.ui.MCoreExpression;
@@ -28,12 +32,17 @@
 import org.eclipse.jface.action.ToolBarManager;
 
 public class ToolBarContributionRecord {
+	public static final String FACTORY = "ToolBarContributionFactory"; //$NON-NLS-1$
+	static final String STATIC_CONTEXT = "ToolBarContributionFactoryContext"; //$NON-NLS-1$
+
 	MToolBar toolbarModel;
 	MToolBarContribution toolbarContribution;
 	ArrayList<MToolBarElement> generatedElements = new ArrayList<MToolBarElement>();
 	HashSet<MToolBarElement> sharedElements = new HashSet<MToolBarElement>();
 	ToolBarManagerRenderer renderer;
 	boolean isVisible = true;
+	private IEclipseContext infoContext;
+	private Runnable factoryDispose;
 
 	public ToolBarContributionRecord(MToolBar model,
 			MToolBarContribution contribution, ToolBarManagerRenderer renderer) {
@@ -128,9 +137,18 @@
 			return false;
 		}
 
-		for (MToolBarElement item : toolbarContribution.getChildren()) {
-			MToolBarElement copy = (MToolBarElement) EcoreUtil
-					.copy((EObject) item);
+		final List<MToolBarElement> copyElements;
+		if (toolbarContribution.getTransientData().get(FACTORY) != null) {
+			copyElements = mergeFactoryIntoModel();
+		} else {
+			copyElements = new ArrayList<MToolBarElement>();
+			for (MToolBarElement item : toolbarContribution.getChildren()) {
+				MToolBarElement copy = (MToolBarElement) EcoreUtil
+						.copy((EObject) item);
+				copyElements.add(copy);
+			}
+		}
+		for (MToolBarElement copy : copyElements) {
 			// if a visibleWhen clause is defined, the item should not be
 			// visible until the clause has been evaluated and returned 'true'
 			copy.setVisible(!anyVisibleWhen());
@@ -159,6 +177,36 @@
 		return true;
 	}
 
+	/**
+	 * @return
+	 */
+	private List<MToolBarElement> mergeFactoryIntoModel() {
+		Object obj = toolbarContribution.getTransientData().get(FACTORY);
+		if (!(obj instanceof IContextFunction)) {
+			return Collections.EMPTY_LIST;
+		}
+		IEclipseContext staticContext = getStaticContext();
+		staticContext.remove(List.class);
+		factoryDispose = (Runnable) ((IContextFunction) obj)
+				.compute(staticContext);
+		return staticContext.get(List.class);
+	}
+
+	private IEclipseContext getStaticContext() {
+		if (infoContext == null) {
+			IEclipseContext parentContext = renderer.getContext(toolbarModel);
+			if (parentContext != null) {
+				infoContext = parentContext.createChild(STATIC_CONTEXT);
+			} else {
+				infoContext = EclipseContextFactory.create(STATIC_CONTEXT);
+			}
+			ContributionsAnalyzer.populateModelInterfaces(toolbarModel,
+					infoContext, toolbarModel.getClass().getInterfaces());
+			infoContext.set(ToolBarManagerRenderer.class, renderer);
+		}
+		return infoContext;
+	}
+
 	MToolBarSeparator findExistingSeparator(String id) {
 		if (id == null) {
 			return null;
@@ -184,6 +232,10 @@
 				toolbarModel.getChildren().remove(shared);
 			}
 		}
+		if (factoryDispose != null) {
+			factoryDispose.run();
+			factoryDispose = null;
+		}
 	}
 
 	private static int getIndex(MElementContainer<?> model,
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarManagerRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarManagerRenderer.java
index 114a2de..03c1ae5 100644
--- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarManagerRenderer.java
+++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/ToolBarManagerRenderer.java
@@ -565,7 +565,10 @@
 	 */
 	private void modelProcessSwitch(ToolBarManager parentManager,
 			MToolBarElement childME) {
-		if (childME instanceof MHandledToolItem) {
+		if (childME instanceof MOpaqueToolItem) {
+			MOpaqueToolItem itemModel = (MOpaqueToolItem) childME;
+			processOpaqueItem(parentManager, itemModel);
+		} else if (childME instanceof MHandledToolItem) {
 			MHandledToolItem itemModel = (MHandledToolItem) childME;
 			processHandledItem(parentManager, itemModel);
 		} else if (childME instanceof MDirectToolItem) {
@@ -664,6 +667,23 @@
 		linkModelToContribution(itemModel, ci);
 	}
 
+	void processOpaqueItem(ToolBarManager parentManager,
+			MOpaqueToolItem itemModel) {
+		IContributionItem ici = getContribution(itemModel);
+		if (ici != null) {
+			return;
+		}
+		Object obj = itemModel.getOpaqueItem();
+		if (obj instanceof IContributionItem) {
+			ici = (IContributionItem) obj;
+		} else {
+			return;
+		}
+		ici.setVisible(itemModel.isVisible());
+		addToManager(parentManager, itemModel, ici);
+		linkModelToContribution(itemModel, ici);
+	}
+
 	/**
 	 * @param parentManager
 	 * @param itemModel
@@ -789,4 +809,7 @@
 		}
 	}
 
+	public IEclipseContext getContext(MUIElement el) {
+		return super.getContext(el);
+	}
 }
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java
index a57ff4a..ac6be5c 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java
@@ -21,9 +21,10 @@
 import org.eclipse.e4.core.contexts.ContextFunction;
 import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.ui.model.application.ui.MCoreExpression;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
 import org.eclipse.e4.ui.model.application.ui.impl.UiFactoryImpl;
-import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
 import org.eclipse.e4.ui.model.application.ui.menu.MOpaqueMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MOpaqueToolItem;
 import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
 import org.eclipse.jface.action.IContributionItem;
 import org.eclipse.ui.internal.WorkbenchPlugin;
@@ -34,13 +35,16 @@
 public class ContributionFactoryGenerator extends ContextFunction {
 	private AbstractContributionFactory factoryImpl;
 	private IConfigurationElement configElement;
+	private int type;
 
-	public ContributionFactoryGenerator(AbstractContributionFactory factory) {
+	public ContributionFactoryGenerator(AbstractContributionFactory factory, int type) {
 		this.factoryImpl = factory;
+		this.type = type;
 	}
 
-	public ContributionFactoryGenerator(IConfigurationElement element) {
+	public ContributionFactoryGenerator(IConfigurationElement element, int type) {
 		configElement = element;
+		this.type = type;
 	}
 
 	private AbstractContributionFactory getFactory() {
@@ -74,21 +78,21 @@
 		factory.createContributionItems(sl, root);
 		final List contributionItems = root.getItems();
 		final Map<IContributionItem, Expression> itemsToExpression = root.getVisibleWhen();
-		List<MMenuElement> menuElements = new ArrayList<MMenuElement>();
+		List<MUIElement> menuElements = new ArrayList<MUIElement>();
 		for (Object obj : contributionItems) {
 			if (obj instanceof IContributionItem) {
 				IContributionItem ici = (IContributionItem) obj;
-				MOpaqueMenuItem opaqueItem = MenuFactoryImpl.eINSTANCE.createOpaqueMenuItem();
-				opaqueItem.setElementId(ici.getId());
-				opaqueItem.setOpaqueItem(ici);
-				if (itemsToExpression.containsKey(ici)) {
-					final Expression ex = itemsToExpression.get(ici);
-					MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
-					exp.setCoreExpressionId("programmatic." + ici.getId()); //$NON-NLS-1$
-					exp.setCoreExpression(ex);
-					opaqueItem.setVisibleWhen(exp);
+				MUIElement opaqueItem = createUIElement(ici);
+				if (opaqueItem != null) {
+					if (itemsToExpression.containsKey(ici)) {
+						final Expression ex = itemsToExpression.get(ici);
+						MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
+						exp.setCoreExpressionId("programmatic." + ici.getId()); //$NON-NLS-1$
+						exp.setCoreExpression(ex);
+						opaqueItem.setVisibleWhen(exp);
+					}
+					menuElements.add(opaqueItem);
 				}
-				menuElements.add(opaqueItem);
 			}
 		}
 		context.set(List.class, menuElements);
@@ -101,4 +105,27 @@
 		};
 	}
 
+	private MUIElement createUIElement(IContributionItem ici) {
+		switch (type) {
+		case 0:
+			return createMenuItem(ici);
+		case 1:
+			return createToolItem(ici);
+		}
+		return null;
+	}
+
+	private MUIElement createMenuItem(IContributionItem ici) {
+		MOpaqueMenuItem opaqueItem = MenuFactoryImpl.eINSTANCE.createOpaqueMenuItem();
+		opaqueItem.setElementId(ici.getId());
+		opaqueItem.setOpaqueItem(ici);
+		return opaqueItem;
+	}
+
+	private MUIElement createToolItem(IContributionItem ici) {
+		MOpaqueToolItem opaqueItem = MenuFactoryImpl.eINSTANCE.createOpaqueToolItem();
+		opaqueItem.setElementId(ici.getId());
+		opaqueItem.setOpaqueItem(ici);
+		return opaqueItem;
+	}
 }
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java
index 4174498..4a8a494 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java
@@ -42,17 +42,17 @@
 import org.eclipse.ui.internal.services.ServiceLocator;
 
 public class MenuAdditionCacheEntry {
-	private final static String MAIN_TOOLBAR = "org.eclipse.ui.main.toolbar"; //$NON-NLS-1$
+	final static String MAIN_TOOLBAR = "org.eclipse.ui.main.toolbar"; //$NON-NLS-1$
 
-	private final static String TRIM_COMMAND1 = "org.eclipse.ui.trim.command1"; //$NON-NLS-1$
+	final static String TRIM_COMMAND1 = "org.eclipse.ui.trim.command1"; //$NON-NLS-1$
 
-	private final static String TRIM_COMMAND2 = "org.eclipse.ui.trim.command2"; //$NON-NLS-1$
+	final static String TRIM_COMMAND2 = "org.eclipse.ui.trim.command2"; //$NON-NLS-1$
 
-	private final static String TRIM_VERTICAL1 = "org.eclipse.ui.trim.vertical1"; //$NON-NLS-1$
+	final static String TRIM_VERTICAL1 = "org.eclipse.ui.trim.vertical1"; //$NON-NLS-1$
 
-	private final static String TRIM_VERTICAL2 = "org.eclipse.ui.trim.vertical2"; //$NON-NLS-1$
+	final static String TRIM_VERTICAL2 = "org.eclipse.ui.trim.vertical2"; //$NON-NLS-1$
 
-	private final static String TRIM_STATUS = "org.eclipse.ui.trim.status"; //$NON-NLS-1$
+	final static String TRIM_STATUS = "org.eclipse.ui.trim.status"; //$NON-NLS-1$
 
 	private MApplication application;
 	// private IEclipseContext appContext;
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java
index c31fe1c..78121f8 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java
@@ -22,6 +22,7 @@
 import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
 import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
 import org.eclipse.e4.ui.workbench.renderers.swt.ContributionRecord;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarContributionRecord;
 
 /**
  * @since 3.102.0
@@ -41,9 +42,32 @@
 		this.location = new MenuLocationURI(attribute);
 	}
 
+	private boolean inToolbar() {
+		return location.getScheme().startsWith("toolbar"); //$NON-NLS-1$
+	}
+
 	public void mergeIntoModel(ArrayList<MMenuContribution> menuContributions,
 			ArrayList<MToolBarContribution> toolBarContributions,
 			ArrayList<MTrimContribution> trimContributions) {
+		if (inToolbar()) {
+			String path = location.getPath();
+			if (path.equals(MenuAdditionCacheEntry.MAIN_TOOLBAR)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_COMMAND1)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_COMMAND2)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_VERTICAL1)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_VERTICAL2)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_STATUS)) {
+				// processTrimChildren(trimContributions, toolBarContributions,
+				// configElement);
+			} else {
+				String query = location.getQuery();
+				if (query == null || query.length() == 0) {
+					query = "after=additions"; //$NON-NLS-1$
+				}
+				processToolbarChildren(toolBarContributions, configElement, path, query);
+			}
+			return;
+		}
 		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
 		String idContrib = MenuHelper.getId(configElement);
 		if (idContrib != null && idContrib.length() > 0) {
@@ -66,8 +90,26 @@
 		}
 		menuContribution.getTags().add(filter);
 		menuContribution.setVisibleWhen(MenuHelper.getVisibleWhen(configElement));
-		ContextFunction generator = new ContributionFactoryGenerator(configElement);
+		ContextFunction generator = new ContributionFactoryGenerator(configElement, 0);
 		menuContribution.getTransientData().put(ContributionRecord.FACTORY, generator);
 		menuContributions.add(menuContribution);
 	}
+
+	private void processToolbarChildren(ArrayList<MToolBarContribution> contributions,
+			IConfigurationElement toolbar, String parentId, String position) {
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		String idContrib = MenuHelper.getId(toolbar);
+		if (idContrib != null && idContrib.length() > 0) {
+			toolBarContribution.setElementId(idContrib);
+		}
+		toolBarContribution.setParentId(parentId);
+		toolBarContribution.setPositionInParent(position);
+		toolBarContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+
+		ContextFunction generator = new ContributionFactoryGenerator(configElement, 1);
+		toolBarContribution.getTransientData().put(ToolBarContributionRecord.FACTORY, generator);
+
+		contributions.add(toolBarContribution);
+	}
 }
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/WorkbenchMenuService.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/WorkbenchMenuService.java
index cfe9096..b065fef 100755
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/WorkbenchMenuService.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/menus/WorkbenchMenuService.java
@@ -21,9 +21,11 @@
 import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
 import org.eclipse.e4.ui.model.application.MApplication;
 import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
 import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
 import org.eclipse.e4.ui.workbench.modeling.ExpressionContext;
 import org.eclipse.e4.ui.workbench.renderers.swt.ContributionRecord;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarContributionRecord;
 import org.eclipse.jface.action.ContributionManager;
 import org.eclipse.jface.action.IContributionItem;
 import org.eclipse.ui.ISourceProvider;
@@ -42,7 +44,7 @@
 	// private ServiceLocator serviceLocator;
 	private ExpressionContext legacyContext;
 	private MenuPersistence persistence;
-	private Map<AbstractContributionFactory, MMenuContribution> factoriesToContributions = new HashMap<AbstractContributionFactory, MMenuContribution>();
+	private Map<AbstractContributionFactory, Object> factoriesToContributions = new HashMap<AbstractContributionFactory, Object>();
 
 	/**
 	 * @param serviceLocator
@@ -78,13 +80,37 @@
 		persistence.dispose();
 	}
 
+	private boolean inToolbar(MenuLocationURI location) {
+		return location.getScheme().startsWith("toolbar"); //$NON-NLS-1$
+	}
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.ui.menus.IMenuService#addContributionFactory(org.eclipse.ui.menus.AbstractContributionFactory)
 	 */
 	public void addContributionFactory(final AbstractContributionFactory factory) {
+		MenuLocationURI location = new MenuLocationURI(factory.getLocation());
+
+		if (inToolbar(location)) {
+			String path = location.getPath();
+			if (path.equals(MenuAdditionCacheEntry.MAIN_TOOLBAR)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_COMMAND1)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_COMMAND2)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_VERTICAL1)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_VERTICAL2)
+					|| path.equals(MenuAdditionCacheEntry.TRIM_STATUS)) {
+				// processTrimChildren(trimContributions, toolBarContributions,
+				// configElement);
+			} else {
+				String query = location.getQuery();
+				if (query == null || query.length() == 0) {
+					query = "after=additions"; //$NON-NLS-1$
+				}
+				processToolbarChildren(factory, location, path, query);
+			}
+			return;
+		}
 		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
 		menuContribution.setElementId(factory.getNamespace() + ":" + factory.hashCode()); //$NON-NLS-1$
-		MenuLocationURI location = new MenuLocationURI(factory.getLocation());
 
 		if ("org.eclipse.ui.popup.any".equals(location.getPath())) { //$NON-NLS-1$
 			menuContribution.setParentId("popup"); //$NON-NLS-1$
@@ -102,21 +128,41 @@
 			filter = ContributionsAnalyzer.MC_POPUP;
 		}
 		menuContribution.getTags().add(filter);
-		ContextFunction generator = new ContributionFactoryGenerator(factory);
+		ContextFunction generator = new ContributionFactoryGenerator(factory, 0);
 		menuContribution.getTransientData().put(ContributionRecord.FACTORY, generator);
 		factoriesToContributions.put(factory, menuContribution);
 		MApplication app = e4Context.get(MApplication.class);
 		app.getMenuContributions().add(menuContribution);
 	}
 
+	private void processToolbarChildren(AbstractContributionFactory factory,
+			MenuLocationURI location, String parentId, String position) {
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		toolBarContribution.setElementId(factory.getNamespace() + ":" + factory.hashCode()); //$NON-NLS-1$
+		toolBarContribution.setParentId(parentId);
+		toolBarContribution.setPositionInParent(position);
+		toolBarContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+
+		ContextFunction generator = new ContributionFactoryGenerator(factory, 1);
+		toolBarContribution.getTransientData().put(ToolBarContributionRecord.FACTORY, generator);
+		factoriesToContributions.put(factory, toolBarContribution);
+		MApplication app = e4Context.get(MApplication.class);
+		app.getToolBarContributions().add(toolBarContribution);
+	}
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.ui.menus.IMenuService#removeContributionFactory(org.eclipse.ui.menus.AbstractContributionFactory)
 	 */
 	public void removeContributionFactory(AbstractContributionFactory factory) {
-		MMenuContribution menuContribution;
-		if ((menuContribution = factoriesToContributions.remove(factory)) != null) {
+		Object contribution;
+		if ((contribution = factoriesToContributions.remove(factory)) != null) {
 			MApplication app = e4Context.get(MApplication.class);
-			app.getMenuContributions().remove(menuContribution);
+			if (contribution instanceof MMenuContribution) {
+				app.getMenuContributions().remove(contribution);
+			} else if (contribution instanceof MToolBarContribution) {
+				app.getToolBarContributions().remove(contribution);
+			}
 		}
 	}