blob: e0dc6cfd68e41697c5311fb3b22c54982caf5a7e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2019 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Maxime Porhel <maxime.porhel@obeo.fr> Obeo - Bug 435949
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
* Simon Scholz <simon.scholz@vogella.com> - Bug 484398, 546815
******************************************************************************/
package org.eclipse.e4.ui.internal.workbench;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionInfo;
import org.eclipse.core.expressions.ReferenceExpression;
import org.eclipse.e4.core.commands.ExpressionContext;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.InjectionException;
import org.eclipse.e4.core.di.InjectorFactory;
import org.eclipse.e4.core.di.annotations.Evaluate;
import org.eclipse.e4.core.di.suppliers.PrimaryObjectSupplier;
import org.eclipse.e4.core.internal.contexts.ContextObjectSupplier;
import org.eclipse.e4.core.internal.di.InjectorImpl;
import org.eclipse.e4.core.services.contributions.IContributionFactory;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.commands.MCommand;
import org.eclipse.e4.ui.model.application.ui.MCoreExpression;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MExpression;
import org.eclipse.e4.ui.model.application.ui.MImperativeExpression;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
public final class ContributionsAnalyzer {
private static final Object missingEvaluate = new Object();
public static void trace(String msg, Throwable error) {
if (DEBUG) {
Activator.trace(Policy.DEBUG_MENUS_FLAG, msg, error);
}
}
private static boolean DEBUG = Policy.DEBUG_MENUS;
private static void trace(String msg, Object menu, Object menuModel) {
trace(msg + ": " + menu + ": " + menuModel, null); //$NON-NLS-1$ //$NON-NLS-2$
}
public static void gatherTrimContributions(MTrimBar trimModel,
List<MTrimContribution> trimContributions, String elementId,
ArrayList<MTrimContribution> toContribute, ExpressionContext eContext) {
if (elementId == null || elementId.length() == 0) {
return;
}
for (MTrimContribution contribution : trimContributions) {
String parentId = contribution.getParentId();
if (!elementId.equals(parentId) || !contribution.isToBeRendered()) {
continue;
}
toContribute.add(contribution);
}
}
public static void XXXgatherToolBarContributions(final MToolBar toolbarModel,
final List<MToolBarContribution> toolbarContributionList, final String id,
final ArrayList<MToolBarContribution> toContribute) {
if (id == null || id.length() == 0) {
return;
}
for (MToolBarContribution toolBarContribution : toolbarContributionList) {
String parentID = toolBarContribution.getParentId();
if (!id.equals(parentID) || !toolBarContribution.isToBeRendered()) {
continue;
}
toContribute.add(toolBarContribution);
}
}
public static void gatherToolBarContributions(final MToolBar toolbarModel,
final List<MToolBarContribution> toolbarContributionList, final String id,
final ArrayList<MToolBarContribution> toContribute, final ExpressionContext eContext) {
if (id == null || id.length() == 0) {
return;
}
for (MToolBarContribution toolBarContribution : toolbarContributionList) {
String parentID = toolBarContribution.getParentId();
if (!id.equals(parentID) || !toolBarContribution.isToBeRendered()) {
continue;
}
toContribute.add(toolBarContribution);
}
}
public static void XXXgatherMenuContributions(final MMenu menuModel,
final List<MMenuContribution> menuContributionList, final String id,
final ArrayList<MMenuContribution> toContribute, final ExpressionContext eContext,
boolean includePopups) {
if (id == null || id.length() == 0) {
return;
}
ArrayList<String> popupIds = new ArrayList<>();
if (includePopups) {
popupIds.add(id);
for (String tag : menuModel.getTags()) {
if (tag.startsWith("popup:")) { //$NON-NLS-1$
String tmp = tag.substring("popup:".length()); //$NON-NLS-1$
if (!popupIds.contains(tmp)) {
popupIds.add(tmp);
}
}
}
}
ArrayList<MMenuContribution> includedPopups = new ArrayList<>();
for (MMenuContribution menuContribution : menuContributionList) {
String parentID = menuContribution.getParentId();
if (parentID == null) {
// it doesn't make sense for this to be null, temporary workaround for bug 320790
continue;
}
boolean popupTarget = includePopups && popupIds.contains(parentID);
boolean popupAny = includePopups && menuModel instanceof MPopupMenu
&& POPUP_PARENT_ID.equals(parentID);
boolean filtered = isFiltered(menuModel, menuContribution, includePopups);
if (!filtered && menuContribution.isToBeRendered() && popupAny) {
// process POPUP_ANY first
toContribute.add(menuContribution);
} else {
if (filtered || (!popupTarget && !parentID.equals(id))
|| !menuContribution.isToBeRendered()) {
continue;
}
includedPopups.add(menuContribution);
}
}
toContribute.addAll(includedPopups);
}
public static void gatherMenuContributions(final MMenu menuModel,
final List<MMenuContribution> menuContributionList, final String id,
final ArrayList<MMenuContribution> toContribute, final ExpressionContext eContext,
boolean includePopups) {
if (id == null || id.length() == 0) {
return;
}
boolean menuBar = (((MUIElement) ((EObject) menuModel).eContainer()) instanceof MWindow);
for (MMenuContribution menuContribution : menuContributionList) {
String parentID = menuContribution.getParentId();
if (parentID == null) {
// it doesn't make sense for this to be null, temporary workaround for bug 320790
continue;
}
boolean popup = parentID.equals(POPUP_PARENT_ID) && (menuModel instanceof MPopupMenu)
&& includePopups;
boolean filtered = isFiltered(menuModel, menuContribution, includePopups);
if (filtered || (!popup && !parentID.equals(id)) || !menuContribution.isToBeRendered()) {
continue;
}
if (menuBar || isVisible(menuContribution, eContext)) {
toContribute.add(menuContribution);
}
}
}
static boolean isFiltered(MMenu menuModel, MMenuContribution menuContribution,
boolean includePopups) {
if (includePopups || menuModel.getTags().contains(ContributionsAnalyzer.MC_POPUP)) {
return !menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP)
&& menuContribution.getTags().contains(ContributionsAnalyzer.MC_MENU);
}
if (menuModel.getTags().contains(ContributionsAnalyzer.MC_MENU)) {
return !menuContribution.getTags().contains(ContributionsAnalyzer.MC_MENU)
&& menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP);
}
if (!includePopups) {
// not including popups, so filter out popup menu contributions if the menu is a regular
// menu
return menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP);
}
return false;
}
public static void collectInfo(ExpressionInfo info, MExpression exp) {
if (!(exp instanceof MCoreExpression)) {
return;
}
MCoreExpression expr = (MCoreExpression) exp;
Expression ref = null;
if (expr.getCoreExpression() instanceof Expression) {
ref = (Expression) expr.getCoreExpression();
} else {
ref = new ReferenceExpression(expr.getCoreExpressionId());
expr.setCoreExpression(ref);
}
ref.collectExpressionInfo(info);
}
public static boolean isVisible(MMenuContribution menuContribution, ExpressionContext eContext) {
if (menuContribution.getVisibleWhen() == null) {
return true;
}
return isVisible(menuContribution.getVisibleWhen(), eContext);
}
public static boolean isVisible(MToolBarContribution contribution, ExpressionContext eContext) {
if (contribution.getVisibleWhen() == null) {
return true;
}
return isVisible(contribution.getVisibleWhen(), eContext);
}
public static boolean isVisible(MTrimContribution contribution, ExpressionContext eContext) {
if (contribution.getVisibleWhen() == null) {
return true;
}
return isVisible(contribution.getVisibleWhen(), eContext);
}
public static boolean isVisible(MExpression exp, final ExpressionContext eContext) {
if (exp instanceof MCoreExpression) {
MCoreExpression coreExpression = (MCoreExpression) exp;
return isCoreExpressionVisible(coreExpression, eContext);
} else if (exp instanceof MImperativeExpression) {
return isImperativeExpressionVisible((MImperativeExpression) exp, eContext);
}
return true;
}
private static boolean isCoreExpressionVisible(MCoreExpression coreExpression, final ExpressionContext eContext) {
final Expression ref;
if (coreExpression.getCoreExpression() instanceof Expression) {
ref = (Expression) coreExpression.getCoreExpression();
} else {
ref = new ReferenceExpression(coreExpression.getCoreExpressionId());
coreExpression.setCoreExpression(ref);
}
// Creates dependency on a predefined value that can be "poked" by
// the evaluation
// service
ExpressionInfo info = ref.computeExpressionInfo();
String[] names = info.getAccessedPropertyNames();
for (String name : names) {
eContext.getVariable(name + ".evaluationServiceLink"); //$NON-NLS-1$
}
boolean ret = false;
try {
ret = ref.evaluate(eContext) != EvaluationResult.FALSE;
} catch (Exception e) {
if (DEBUG) {
trace("isVisible exception", e); //$NON-NLS-1$
}
}
return ret;
}
private static boolean isImperativeExpressionVisible(MImperativeExpression exp, final ExpressionContext eContext) {
Object imperativeExpressionObject = exp.getObject();
if (imperativeExpressionObject == null) {
IContributionFactory contributionFactory = eContext.eclipseContext.get(IContributionFactory.class);
Object newImperativeExpression = contributionFactory.create(exp.getContributionURI(),
eContext.eclipseContext);
exp.setObject(newImperativeExpression);
imperativeExpressionObject = newImperativeExpression;
}
if (imperativeExpressionObject == null) {
return false;
}
Object result = null;
IEclipseContext staticContext = EclipseContextFactory.create("Evaluation-Static");//$NON-NLS-1$
staticContext.set(MImperativeExpression.class, exp);
try {
if (exp.isTracking()) {
result = invoke(imperativeExpressionObject, Evaluate.class, eContext.eclipseContext, staticContext,
missingEvaluate);
} else {
result = ContextInjectionFactory.invoke(imperativeExpressionObject, Evaluate.class,
eContext.eclipseContext, staticContext, missingEvaluate);
}
} finally {
staticContext.dispose();
}
if (result == missingEvaluate) {
String className="null";//$NON-NLS-1$
if (imperativeExpressionObject != null) {
className = imperativeExpressionObject.getClass().getName();
}
throw new IllegalStateException(
"There is no method annotated with @Evaluate in the " + className + " imperative expression class " //$NON-NLS-1$ //$NON-NLS-2$
);
}
return (boolean) result;
}
final private static InjectorImpl injector = (InjectorImpl) InjectorFactory.getDefault();
static private Object invoke(Object object, Class<? extends Annotation> qualifier, IEclipseContext context,
IEclipseContext localContext, Object defaultValue) throws InjectionException {
PrimaryObjectSupplier supplier = ContextObjectSupplier.getObjectSupplier(context, injector);
PrimaryObjectSupplier tempSupplier = ContextObjectSupplier.getObjectSupplier(localContext, injector);
return injector.invoke(object, qualifier, defaultValue, supplier, tempSupplier, false, true);
}
public static void addMenuContributions(final MMenu menuModel,
final ArrayList<MMenuContribution> toContribute,
final ArrayList<MMenuElement> menuContributionsToRemove) {
HashSet<String> existingMenuIds = new HashSet<>();
HashSet<String> existingSeparatorNames = new HashSet<>();
for (MMenuElement child : menuModel.getChildren()) {
String elementId = child.getElementId();
if (child instanceof MMenu && elementId != null) {
existingMenuIds.add(elementId);
} else if (child instanceof MMenuSeparator && elementId != null) {
existingSeparatorNames.add(elementId);
}
}
boolean done = toContribute.isEmpty();
while (!done) {
ArrayList<MMenuContribution> curList = new ArrayList<>(toContribute);
int retryCount = toContribute.size();
toContribute.clear();
for (MMenuContribution menuContribution : curList) {
if (!processAddition(menuModel, menuContributionsToRemove, menuContribution,
existingMenuIds, existingSeparatorNames)) {
toContribute.add(menuContribution);
}
}
// We're done if the retryList is now empty (everything done) or
// if the list hasn't changed at all (no hope)
done = (toContribute.isEmpty()) || (toContribute.size() == retryCount);
}
}
public static boolean processAddition(final MMenu menuModel,
final ArrayList<MMenuElement> menuContributionsToRemove,
MMenuContribution menuContribution, final HashSet<String> existingMenuIds,
HashSet<String> existingSeparatorNames) {
int idx = getIndex(menuModel, menuContribution.getPositionInParent());
if (idx == -1) {
return false;
}
for (MMenuElement item : menuContribution.getChildren()) {
if (item instanceof MMenu && existingMenuIds.contains(item.getElementId())) {
// skip this, it's already there
continue;
} else if (item instanceof MMenuSeparator
&& existingSeparatorNames.contains(item.getElementId())) {
// skip this, it's already there
continue;
}
MMenuElement copy = (MMenuElement) EcoreUtil.copy((EObject) item);
if (DEBUG) {
trace("addMenuContribution " + copy, menuModel.getWidget(), menuModel); //$NON-NLS-1$
}
menuContributionsToRemove.add(copy);
menuModel.getChildren().add(idx++, copy);
if (copy instanceof MMenu && copy.getElementId() != null) {
existingMenuIds.add(copy.getElementId());
} else if (copy instanceof MMenuSeparator && copy.getElementId() != null) {
existingSeparatorNames.add(copy.getElementId());
}
}
return true;
}
public static boolean processAddition(final MToolBar toolBarModel,
MToolBarContribution toolBarContribution, List<MToolBarElement> contributions,
HashSet<String> existingSeparatorNames) {
int idx = getIndex(toolBarModel, toolBarContribution.getPositionInParent());
if (idx == -1) {
return false;
}
for (MToolBarElement item : toolBarContribution.getChildren()) {
if (item instanceof MToolBarSeparator
&& existingSeparatorNames.contains(item.getElementId())) {
// skip this, it's already there
continue;
}
MToolBarElement copy = (MToolBarElement) EcoreUtil.copy((EObject) item);
if (DEBUG) {
trace("addToolBarContribution " + copy, toolBarModel.getWidget(), toolBarModel); //$NON-NLS-1$
}
toolBarModel.getChildren().add(idx++, copy);
contributions.add(copy);
if (copy instanceof MToolBarSeparator && copy.getElementId() != null) {
existingSeparatorNames.add(copy.getElementId());
}
}
return true;
}
public static boolean processAddition(final MTrimBar trimBar, MTrimContribution contribution,
List<MTrimElement> contributions, HashSet<String> existingToolbarIds) {
int idx = getIndex(trimBar, contribution.getPositionInParent());
if (idx == -1) {
return false;
}
for (MTrimElement item : contribution.getChildren()) {
if (item instanceof MToolBar && existingToolbarIds.contains(item.getElementId())) {
// skip this, it's already there
continue;
}
MTrimElement copy = (MTrimElement) EcoreUtil.copy((EObject) item);
copy.getPersistedState().put(IWorkbench.PERSIST_STATE, Boolean.FALSE.toString());
if (DEBUG) {
trace("addTrimContribution " + copy, trimBar.getWidget(), trimBar); //$NON-NLS-1$
}
trimBar.getChildren().add(idx++, copy);
contributions.add(copy);
if (copy instanceof MToolBar && copy.getElementId() != null) {
existingToolbarIds.add(copy.getElementId());
}
}
return true;
}
private static int getIndex(MElementContainer<?> menuModel, String positionInParent) {
String id = null;
String modifier = null;
if (positionInParent != null && positionInParent.length() > 0) {
String[] array = positionInParent.split("="); //$NON-NLS-1$
modifier = array[0];
// may have an invalid position, check for this
if (array.length > 1) {
id = array[1];
}
}
if (id == null) {
return menuModel.getChildren().size();
}
int idx = 0;
int size = menuModel.getChildren().size();
while (idx < size) {
if (id.equals(menuModel.getChildren().get(idx).getElementId())) {
if ("after".equals(modifier)) { //$NON-NLS-1$
idx++;
}
return idx;
}
idx++;
}
return id.equals("additions") ? menuModel.getChildren().size() : -1; //$NON-NLS-1$
}
public static MCommand getCommandById(MApplication app, String cmdId) {
return app.getCommand(cmdId);
}
static class Key {
private int tag = -1;
private int hc = -1;
private String parentId;
private String position;
private MCoreExpression vexp;
private Object factory;
public Key(String parentId, String position, List<String> tags, MCoreExpression vexp,
Object factory) {
this.parentId = parentId;
this.position = position;
this.vexp = vexp;
this.factory = factory;
if (tags.contains("scheme:menu")) { //$NON-NLS-1$
tag = 1;
} else if (tags.contains("scheme:popup")) { //$NON-NLS-1$
tag = 2;
} else if (tags.contains("scheme:toolbar")) { //$NON-NLS-1$
tag = 3;
} else {
tag = 0;
}
}
int getSchemeTag() {
return tag;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Key)) {
return false;
}
Key other = (Key) obj;
Object exp1 = vexp == null ? null : vexp.getCoreExpression();
Object exp2 = other.vexp == null ? null : other.vexp.getCoreExpression();
return Objects.equals(parentId, other.parentId) && Objects.equals(position, other.position)
&& getSchemeTag() == other.getSchemeTag() && Objects.equals(exp1, exp2)
&& Objects.equals(factory, other.factory);
}
@Override
public int hashCode() {
if (hc == -1) {
Object exp1 = vexp == null ? null : vexp.getCoreExpression();
hc = Objects.hashCode(parentId);
hc = hc * 87 + Objects.hashCode(position);
hc = hc * 87 + getSchemeTag();
hc = hc * 87 + Objects.hashCode(exp1);
hc = hc * 87 + Objects.hashCode(factory);
}
return hc;
}
@Override
public String toString() {
return getClass().getName() + " " + parentId + "--" + position //$NON-NLS-1$ //$NON-NLS-2$
+ "--" + getSchemeTag() + "--" + vexp; //$NON-NLS-1$//$NON-NLS-2$
}
}
static class MenuKey extends Key {
static final String FACTORY = "ContributionFactory"; //$NON-NLS-1$
private MMenuContribution contribution;
public MenuKey(MMenuContribution mc) {
super(mc.getParentId(), mc.getPositionInParent(), mc.getTags(), (MCoreExpression) mc
.getVisibleWhen(), mc.getTransientData().get(FACTORY));
this.contribution = mc;
mc.setWidget(this);
}
public MMenuContribution getContribution() {
return contribution;
}
}
static class ToolBarKey extends Key {
static final String FACTORY = "ToolBarContributionFactory"; //$NON-NLS-1$
private MToolBarContribution contribution;
public ToolBarKey(MToolBarContribution mc) {
super(mc.getParentId(), mc.getPositionInParent(), mc.getTags(), (MCoreExpression) mc
.getVisibleWhen(), mc.getTransientData().get(FACTORY));
this.contribution = mc;
mc.setWidget(this);
}
public MToolBarContribution getContribution() {
return contribution;
}
}
static class TrimKey extends Key {
private MTrimContribution contribution;
public TrimKey(MTrimContribution mc) {
super(mc.getParentId(), mc.getPositionInParent(), mc.getTags(), (MCoreExpression) mc
.getVisibleWhen(), null);
this.contribution = mc;
mc.setWidget(this);
}
public MTrimContribution getContribution() {
return contribution;
}
}
private static MenuKey getKey(MMenuContribution contribution) {
if (contribution.getWidget() instanceof MenuKey) {
return (MenuKey) contribution.getWidget();
}
return new MenuKey(contribution);
}
private static ToolBarKey getKey(MToolBarContribution contribution) {
if (contribution.getWidget() instanceof ToolBarKey) {
return (ToolBarKey) contribution.getWidget();
}
return new ToolBarKey(contribution);
}
private static TrimKey getKey(MTrimContribution contribution) {
if (contribution.getWidget() instanceof TrimKey) {
return (TrimKey) contribution.getWidget();
}
return new TrimKey(contribution);
}
public static void printContributions(ArrayList<MMenuContribution> contributions) {
if (!DEBUG) {
return;
}
for (MMenuContribution c : contributions) {
trace("\n" + c, null); //$NON-NLS-1$
for (MMenuElement element : c.getChildren()) {
printElement(1, element);
}
}
}
private static void printElement(int level, MMenuElement element) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < level; i++) {
buf.append('\t');
}
buf.append(element.toString());
trace(buf.toString(), null);
if (element instanceof MMenu) {
for (MMenuElement item : ((MMenu) element).getChildren()) {
printElement(level + 1, item);
}
}
}
public static void mergeToolBarContributions(ArrayList<MToolBarContribution> contributions,
ArrayList<MToolBarContribution> result) {
HashMap<ToolBarKey, ArrayList<MToolBarContribution>> buckets = new HashMap<>();
if (DEBUG) {
trace("mergeContributions size: " + contributions.size(), null); //$NON-NLS-1$
}
// first pass, sort by parentId?position,scheme,visibleWhen
for (MToolBarContribution contribution : contributions) {
ToolBarKey key = getKey(contribution);
ArrayList<MToolBarContribution> slot = buckets.get(key);
if (slot == null) {
slot = new ArrayList<>();
buckets.put(key, slot);
}
slot.add(contribution);
}
Iterator<MToolBarContribution> i = contributions.iterator();
while (i.hasNext() && !buckets.isEmpty()) {
MToolBarContribution contribution = i.next();
ToolBarKey key = getKey(contribution);
ArrayList<MToolBarContribution> slot = buckets.remove(key);
if (slot == null) {
continue;
}
MToolBarContribution toContribute = null;
for (MToolBarContribution item : slot) {
if (toContribute == null) {
toContribute = item;
continue;
}
Object[] array = item.getChildren().toArray();
for (Object element : array) {
MToolBarElement me = (MToolBarElement) element;
if (!containsMatching(toContribute.getChildren(), me)) {
toContribute.getChildren().add(me);
}
}
}
if (toContribute != null) {
toContribute.setWidget(null);
result.add(toContribute);
}
}
if (DEBUG) {
trace("mergeContributions: final size: " + result.size(), null); //$NON-NLS-1$
}
}
public static void mergeContributions(ArrayList<MMenuContribution> contributions,
ArrayList<MMenuContribution> result) {
HashMap<MenuKey, ArrayList<MMenuContribution>> buckets = new HashMap<>();
if (DEBUG) {
trace("mergeContributions size: " + contributions.size(), null); //$NON-NLS-1$
printContributions(contributions);
}
// first pass, sort by parentId?position,scheme,visibleWhen
for (MMenuContribution contribution : contributions) {
MenuKey key = getKey(contribution);
ArrayList<MMenuContribution> slot = buckets.get(key);
if (slot == null) {
slot = new ArrayList<>();
buckets.put(key, slot);
}
slot.add(contribution);
}
Iterator<MMenuContribution> i = contributions.iterator();
while (i.hasNext() && !buckets.isEmpty()) {
MMenuContribution contribution = i.next();
MenuKey key = getKey(contribution);
ArrayList<MMenuContribution> slot = buckets.remove(key);
if (slot == null) {
continue;
}
MMenuContribution toContribute = null;
for (MMenuContribution item : slot) {
if (toContribute == null) {
toContribute = item;
continue;
}
Object[] array = item.getChildren().toArray();
int idx = getIndex(toContribute, item.getPositionInParent());
if (idx == -1) {
idx = 0;
}
for (Object element : array) {
MMenuElement me = (MMenuElement) element;
if (!containsMatching(toContribute.getChildren(), me)) {
toContribute.getChildren().add(idx, me);
idx++;
}
}
}
if (toContribute != null) {
toContribute.setWidget(null);
result.add(toContribute);
}
}
trace("mergeContributions: final size: " + result.size(), null); //$NON-NLS-1$
}
private static boolean containsMatching(List<MMenuElement> children, MMenuElement me) {
for (MMenuElement element : children) {
if (Objects.equals(me.getElementId(), element.getElementId())
&& element.getClass().isInstance(me)
&& (element instanceof MMenuSeparator || element instanceof MMenu)) {
return true;
}
}
return false;
}
private static boolean containsMatching(List<MToolBarElement> children, MToolBarElement me) {
for (MToolBarElement element : children) {
if (Objects.equals(me.getElementId(), element.getElementId())
&& element.getClass().isInstance(me)
&& (element instanceof MToolBarSeparator || element instanceof MToolBar)) {
return true;
}
}
return false;
}
private static boolean containsMatching(List<MTrimElement> children, MTrimElement me) {
for (MTrimElement element : children) {
if (Objects.equals(me.getElementId(), element.getElementId())
&& element.getClass().isInstance(me)
&& (element instanceof MToolBarSeparator || element instanceof MToolBar)) {
return true;
}
}
return false;
}
public static int indexForId(MElementContainer<MMenuElement> parentMenu, String id) {
if (id == null || id.length() == 0) {
return -1;
}
int i = 0;
for (MMenuElement item : parentMenu.getChildren()) {
if (id.equals(item.getElementId())) {
return i;
}
i++;
}
return -1;
}
public static final String MC_POPUP = "menuContribution:popup"; //$NON-NLS-1$
public static final String MC_MENU = "menuContribution:menu"; //$NON-NLS-1$
public static final String MC_TOOLBAR = "menuContribution:toolbar"; //$NON-NLS-1$
public static final String POPUP_PARENT_ID = "popup"; //$NON-NLS-1$
public static void mergeTrimContributions(ArrayList<MTrimContribution> contributions,
ArrayList<MTrimContribution> result) {
HashMap<TrimKey, ArrayList<MTrimContribution>> buckets = new HashMap<>();
if (DEBUG) {
trace("mergeContributions size: " + contributions.size(), null); //$NON-NLS-1$
}
// first pass, sort by parentId?position,scheme,visibleWhen
for (MTrimContribution contribution : contributions) {
TrimKey key = getKey(contribution);
ArrayList<MTrimContribution> slot = buckets.get(key);
if (slot == null) {
slot = new ArrayList<>();
buckets.put(key, slot);
}
slot.add(contribution);
}
Iterator<MTrimContribution> i = contributions.iterator();
while (i.hasNext() && !buckets.isEmpty()) {
MTrimContribution contribution = i.next();
TrimKey key = getKey(contribution);
ArrayList<MTrimContribution> slot = buckets.remove(key);
if (slot == null) {
continue;
}
MTrimContribution toContribute = null;
for (MTrimContribution item : slot) {
if (toContribute == null) {
toContribute = item;
continue;
}
Object[] array = item.getChildren().toArray();
for (Object element : array) {
MTrimElement me = (MTrimElement) element;
if (!containsMatching(toContribute.getChildren(), me)) {
toContribute.getChildren().add(me);
}
}
}
if (toContribute != null) {
toContribute.setWidget(null);
result.add(toContribute);
}
}
if (DEBUG) {
trace("mergeContributions: final size: " + result.size(), null); //$NON-NLS-1$
}
}
public static void populateModelInterfaces(Object modelObject, IEclipseContext context,
Class<?>[] interfaces) {
for (Class<?> intf : interfaces) {
if (Policy.DEBUG_CONTEXTS) {
Activator.trace(Policy.DEBUG_CONTEXTS_FLAG, "Adding " + intf.getName() + " for " //$NON-NLS-1$ //$NON-NLS-2$
+ modelObject.getClass().getName(), null);
}
context.set(intf.getName(), modelObject);
populateModelInterfaces(modelObject, context, intf.getInterfaces());
}
}
}