/******************************************************************************* * Copyright (c) 2010, 2017 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 * http://www.eclipse.org/legal/epl-v10.html * * 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 ******************************************************************************/ 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 org.eclipse.core.expressions.EvaluationResult; import org.eclipse.core.expressions.Expression; import org.eclipse.core.expressions.ExpressionInfo; import org.eclipse.core.internal.expressions.ReferenceExpression; import org.eclipse.e4.core.commands.ExpressionContext; import org.eclipse.e4.core.contexts.ContextInjectionFactory; 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.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(); boolean filtered = isFiltered(trimModel, contribution); if (filtered || !elementId.equals(parentId) || !contribution.isToBeRendered()) { continue; } toContribute.add(contribution); } } static boolean isFiltered(MTrimBar trimModel, MTrimContribution contribution) { return false; } 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(); boolean filtered = isFiltered(toolbarModel, toolBarContribution); if (filtered || !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(); boolean filtered = isFiltered(toolbarModel, toolBarContribution); if (filtered || !id.equals(parentID) || !toolBarContribution.isToBeRendered()) { continue; } toContribute.add(toolBarContribution); } } static boolean isFiltered(MToolBar toolbarModel, MToolBarContribution toolBarContribution) { return false; } 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((MCoreExpression) menuContribution.getVisibleWhen(), eContext); } public static boolean isVisible(MToolBarContribution contribution, ExpressionContext eContext) { if (contribution.getVisibleWhen() == null) { return true; } return isVisible((MCoreExpression) contribution.getVisibleWhen(), eContext); } public static boolean isVisible(MTrimContribution contribution, ExpressionContext eContext) { if (contribution.getVisibleWhen() == null) { return true; } return isVisible((MCoreExpression) 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; } Object result = null; if (exp.isTracking()) { result = invoke(imperativeExpressionObject, Evaluate.class, eContext.eclipseContext, null, missingEvaluate); } else { result = ContextInjectionFactory.invoke(imperativeExpressionObject, Evaluate.class, eContext.eclipseContext, null, missingEvaluate); } if (result == missingEvaluate) { throw new IllegalStateException( "There is no method annotated with @Evaluate in the imperative expression class"); //$NON-NLS-1$ } 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.size() == 0; 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.size() == 0) || (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); 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 Util.equals(parentId, other.parentId) && Util.equals(position, other.position) && getSchemeTag() == other.getSchemeTag() && Util.equals(exp1, exp2) && Util.equals(factory, other.factory); } @Override public int hashCode() { if (hc == -1) { Object exp1 = vexp == null ? null : vexp.getCoreExpression(); hc = Util.hashCode(parentId); hc = hc * 87 + Util.hashCode(position); hc = hc * 87 + getSchemeTag(); hc = hc * 87 + Util.hashCode(exp1); hc = hc * 87 + Util.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 (Util.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 (Util.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 (Util.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()); } } }