blob: 0efa3b16f3084d606a7ab964e8624708d611b1db [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 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
******************************************************************************/
package org.eclipse.ui.internal.menus;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.commands.contexts.Context;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionInfo;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
import org.eclipse.e4.ui.model.application.MApplication;
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.impl.UiFactoryImpl;
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.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.model.application.ui.menu.impl.MenuFactoryImpl;
import org.eclipse.e4.ui.services.EContextService;
import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.e4.compatibility.E4Util;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
/**
* @since e4
*
*/
public class ActionSet {
protected static final String MAIN_TOOLBAR = "org.eclipse.ui.main.toolbar"; //$NON-NLS-1$
protected static final String MAIN_MENU = "org.eclipse.ui.main.menu"; //$NON-NLS-1$
protected IConfigurationElement configElement;
protected MApplication application;
protected Expression visibleWhen;
private HashSet<String> menuContributionGroupIds = new HashSet<String>();
private HashSet<String> toolbarContributionGroupIds = new HashSet<String>();
private String id;
public String getId() {
return id;
}
public ActionSet(MApplication application, IEclipseContext appContext,
IConfigurationElement element) {
this.application = application;
this.configElement = element;
this.id = MenuHelper.getId(configElement);
}
public void addToModel(ArrayList<MMenuContribution> menuContributions,
ArrayList<MToolBarContribution> toolBarContributions,
ArrayList<MTrimContribution> trimContributions) {
String idContrib = MenuHelper.getId(configElement);
visibleWhen = createExpression(configElement);
EContextService contextService = application.getContext().get(EContextService.class);
Context actionSetContext = contextService.getContext(idContrib);
if (!actionSetContext.isDefined()) {
actionSetContext.define(MenuHelper.getLabel(configElement),
MenuHelper.getDescription(configElement), "org.eclipse.ui.contexts.actionSet"); //$NON-NLS-1$
}
IConfigurationElement[] menus = configElement
.getChildren(IWorkbenchRegistryConstants.TAG_MENU);
if (menus.length > 0) {
for (int i = menus.length; i > 0; i--) {
IConfigurationElement element = menus[i - 1];
addContribution(idContrib, menuContributions, element, true, MAIN_MENU);
}
}
IConfigurationElement[] actions = configElement
.getChildren(IWorkbenchRegistryConstants.TAG_ACTION);
if (actions.length > 0) {
for (int i = 0; i < actions.length; i++) {
IConfigurationElement up = actions[i];
IConfigurationElement down = actions[actions.length - 1 - i];
addContribution(idContrib, menuContributions, down, false, MAIN_MENU);
addToolBarContribution(idContrib, toolBarContributions, trimContributions, up,
MAIN_TOOLBAR);
}
}
}
protected Expression createExpression(IConfigurationElement configElement) {
String actionSetId = MenuHelper.getId(configElement);
Set<String> associatedPartIds = actionSetPartAssociations(actionSetId);
return new ActionSetAndPartExpression(actionSetId, associatedPartIds);
}
private Set<String> actionSetPartAssociations(String actionSetId) {
HashSet<String> result = new HashSet<String>();
final IExtensionRegistry registry = Platform.getExtensionRegistry();
final IConfigurationElement[] associations = registry
.getConfigurationElementsFor(PlatformUI.PLUGIN_ID + '.'
+ IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS);
for (IConfigurationElement element : associations) {
String targetId = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
if (!actionSetId.equals(targetId)) {
continue;
}
IConfigurationElement[] children = element
.getChildren(IWorkbenchRegistryConstants.TAG_PART);
for (IConfigurationElement part : children) {
String id = MenuHelper.getId(part);
if (id != null && id.length() > 0) {
MenuHelper.trace(IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS
+ ':' + actionSetId + ':' + id, null);
result.add(id);
}
}
}
return result;
}
static class ActionSetAndPartExpression extends Expression {
private String id;
private Set<String> partIds;
public ActionSetAndPartExpression(String id, Set<String> associatedPartIds) {
this.id = id;
this.partIds = associatedPartIds;
}
@Override
public void collectExpressionInfo(ExpressionInfo info) {
info.addVariableNameAccess(ISources.ACTIVE_CONTEXT_NAME);
info.addVariableNameAccess(ISources.ACTIVE_PART_ID_NAME);
}
@Override
public EvaluationResult evaluate(IEvaluationContext context) throws CoreException {
Object obj = context.getVariable(ISources.ACTIVE_CONTEXT_NAME);
if (obj instanceof Collection<?>) {
boolean rc = ((Collection) obj).contains(id);
if (rc) {
return EvaluationResult.TRUE;
}
}
if (!partIds.isEmpty()) {
return EvaluationResult.valueOf(partIds.contains(context
.getVariable(ISources.ACTIVE_PART_ID_NAME)));
}
return EvaluationResult.FALSE;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ActionSetAndPartExpression)) {
return false;
}
ActionSetAndPartExpression exp = (ActionSetAndPartExpression) obj;
return id.equals(exp.id) && partIds.equals(exp.partIds);
}
@Override
public int hashCode() {
return id.hashCode() + partIds.hashCode();
}
}
private MCoreExpression createVisibleWhen() {
if (visibleWhen == null) {
return null;
}
MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
exp.setCoreExpressionId("programmatic." + MenuHelper.getId(configElement)); //$NON-NLS-1$
exp.setCoreExpression(visibleWhen);
return exp;
}
protected void addContribution(String idContrib, ArrayList<MMenuContribution> contributions,
IConfigurationElement element, boolean isMenu, String parentId) {
MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
menuContribution.setVisibleWhen(createVisibleWhen());
menuContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
menuContribution.getTags().add("scheme:menu"); //$NON-NLS-1$
final String elementId = MenuHelper.getId(element);
if (idContrib != null && idContrib.length() > 0) {
menuContribution.setElementId(idContrib + "/" + elementId); //$NON-NLS-1$
} else {
menuContribution.setElementId(elementId);
}
String path = isMenu ? MenuHelper.getPath(element) : MenuHelper.getMenuBarPath(element);
if (path == null || path.length() == 0) {
if (!isMenu) {
return;
}
path = IWorkbenchActionConstants.MB_ADDITIONS;
}
if (path.endsWith("/")) { //$NON-NLS-1$
path += IWorkbenchActionConstants.MB_ADDITIONS;
}
Path menuPath = new Path(path);
String positionInParent = "after=" + menuPath.segment(0); //$NON-NLS-1$
int segmentCount = menuPath.segmentCount();
if (segmentCount > 1) {
parentId = menuPath.segment(segmentCount - 2);
positionInParent = "after=" + menuPath.segment(segmentCount - 1); //$NON-NLS-1$
}
menuContribution.setParentId(parentId);
menuContribution.setPositionInParent(positionInParent);
if (isMenu) {
MMenu menu = MenuHelper.createMenuAddition(element);
if (menu != null) {
contributeMenuGroup(contributions, parentId, positionInParent);
menuContribution.getChildren().add(menu);
menu.getTransientData().put("ActionSet", id); //$NON-NLS-1$
}
} else {
if (parentId.equals(MAIN_MENU)) {
E4Util.unsupported("****MC: bad pie: " + menuPath); //$NON-NLS-1$
parentId = IWorkbenchActionConstants.M_WINDOW;
menuContribution.setParentId(parentId);
}
MMenuElement action = MenuHelper.createLegacyMenuActionAdditions(application, element);
if (action != null) {
contributeMenuGroup(contributions, parentId, positionInParent);
menuContribution.getChildren().add(action);
action.getTransientData().put("ActionSet", id); //$NON-NLS-1$
}
}
if (menuContribution.getChildren().size() > 0) {
contributions.add(menuContribution);
}
if (isMenu) {
processGroups(idContrib, contributions, element);
}
}
private void contributeMenuGroup(ArrayList<MMenuContribution> contributions, String parentId,
String positionInParent) {
String group = positionInParent.substring(6);
if (menuContributionGroupIds.contains(parentId + group)) {
return;
}
menuContributionGroupIds.add(parentId + group);
MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
menuContribution.setVisibleWhen(createVisibleWhen());
menuContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
menuContribution.getTags().add("scheme:menu"); //$NON-NLS-1$
menuContribution.setParentId(parentId);
menuContribution.setPositionInParent("after=additions"); //$NON-NLS-1$
MMenuElement sep = MenuFactoryImpl.eINSTANCE.createMenuSeparator();
sep.getTags().add(MenuManagerRenderer.GROUP_MARKER);
sep.setVisible(false);
sep.setElementId(group);
menuContribution.getChildren().add(sep);
contributions.add(menuContribution);
}
private void contributeToolBarGroup(ArrayList<MToolBarContribution> contributions,
String parentId, String group) {
if (toolbarContributionGroupIds.contains(parentId + group)) {
return;
}
toolbarContributionGroupIds.add(parentId + group);
MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
.createToolBarContribution();
toolBarContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
toolBarContribution.getTags().add("scheme:toolbar"); //$NON-NLS-1$
toolBarContribution.setParentId(parentId);
toolBarContribution.setPositionInParent("after=additions"); //$NON-NLS-1$
MToolBarSeparator sep = MenuFactoryImpl.eINSTANCE.createToolBarSeparator();
sep.setElementId(group);
sep.setVisible(false);
toolBarContribution.getChildren().add(sep);
contributions.add(toolBarContribution);
}
protected void addToolBarContribution(String idContrib,
ArrayList<MToolBarContribution> contributions,
ArrayList<MTrimContribution> trimContributions, IConfigurationElement element,
String parentId) {
String tpath = MenuHelper.getToolBarPath(element);
if (tpath == null) {
return;
}
if (tpath.endsWith("/")) { //$NON-NLS-1$
tpath += IWorkbenchActionConstants.MB_ADDITIONS;
}
MToolBarElement action = MenuHelper
.createLegacyToolBarActionAdditions(application, element);
if (action == null) {
return;
}
action.getTransientData().put("Name", MenuHelper.getLabel(element)); //$NON-NLS-1$
action.getTransientData().put("ActionSet", id); //$NON-NLS-1$
MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
.createToolBarContribution();
toolBarContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
toolBarContribution.getTags().add("scheme:toolbar"); //$NON-NLS-1$
final String elementId = MenuHelper.getId(element);
if (idContrib != null && idContrib.length() > 0) {
toolBarContribution.setElementId(idContrib + "/" + elementId); //$NON-NLS-1$
toolBarContribution.getTags().add("ActionSet::" + idContrib); //$NON-NLS-1$
} else {
toolBarContribution.setElementId(elementId);
}
String tgroup = null;
if (tpath != null) {
int loc = tpath.lastIndexOf('/');
if (loc != -1) {
tgroup = tpath.substring(loc + 1);
tpath = tpath.substring(0, loc);
} else {
tgroup = tpath;
tpath = null;
}
}
if (tpath == null || tpath.equals("Normal")) { //$NON-NLS-1$
IConfigurationElement parent = (IConfigurationElement) element.getParent();
tpath = parent.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
}
Path menuPath = new Path(tpath);
tpath = menuPath.segment(0);
if (MAIN_TOOLBAR.equals(parentId)) {
addTrimContribution(idContrib, contributions, trimContributions, element, parentId,
tpath, tgroup);
} else {
tpath = parentId;
}
// String positionInParent =
// MenuHelper.isSeparatorVisible(configElement) ? null
// : "after=" + tpath; //$NON-NLS-1$
String positionInParent = "after=" + tgroup;//$NON-NLS-1$
contributeToolBarGroup(contributions, tpath, tgroup);
toolBarContribution.setParentId(tpath);
toolBarContribution.setPositionInParent(positionInParent);
toolBarContribution.setVisibleWhen(createVisibleWhen());
toolBarContribution.getChildren().add(action);
contributions.add(toolBarContribution);
}
private void addTrimContribution(String idContrib,
ArrayList<MToolBarContribution> contributions,
ArrayList<MTrimContribution> trimContributions, IConfigurationElement element,
String parentId, String tpath, String tgroup) {
final String elementId = MenuHelper.getId(element);
MTrimContribution trimContribution = MenuFactoryImpl.eINSTANCE.createTrimContribution();
trimContribution.getTags().add(ContributionsAnalyzer.MC_TOOLBAR);
trimContribution.getTags().add("scheme:toolbar"); //$NON-NLS-1$
if (idContrib != null && idContrib.length() > 0) {
trimContribution.setElementId(idContrib + "/" + elementId); //$NON-NLS-1$
} else {
trimContribution.setElementId(elementId);
}
trimContribution.setParentId(parentId);
trimContribution.setPositionInParent("after=additions"); //$NON-NLS-1$ trimContribution.setVisibleWhen(createVisibleWhen());
MToolBar tb = MenuFactoryImpl.eINSTANCE.createToolBar();
tb.setElementId(tpath);
tb.getTransientData().put("Name", MenuHelper.getLabel(this.configElement)); //$NON-NLS-1$
tb.getTransientData().put("ActionSet", id); //$NON-NLS-1$
trimContribution.getChildren().add(tb);
trimContributions.add(trimContribution);
}
private void processGroups(String idContrib, ArrayList<MMenuContribution> contributions,
IConfigurationElement element) {
MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
menuContribution.setVisibleWhen(createVisibleWhen());
menuContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
menuContribution.getTags().add("scheme:menu"); //$NON-NLS-1$
final String elementId = MenuHelper.getId(element);
if (idContrib != null && idContrib.length() > 0) {
menuContribution.setElementId(idContrib + "/" + elementId + ".groups"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
menuContribution.setElementId(elementId + ".groups"); //$NON-NLS-1$
}
menuContribution.setParentId(elementId);
menuContribution.setPositionInParent("after=additions"); //$NON-NLS-1$
IConfigurationElement[] children = element.getChildren();
for (IConfigurationElement sepAddition : children) {
String name = sepAddition.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
String tag = sepAddition.getName();
MMenuElement sep = MenuFactoryImpl.eINSTANCE.createMenuSeparator();
sep.setElementId(name);
if ("groupMarker".equals(tag)) { //$NON-NLS-1$
sep.setVisible(false);
sep.getTags().add(MenuManagerRenderer.GROUP_MARKER);
}
menuContribution.getChildren().add(sep);
}
if (menuContribution.getChildren().size() > 0) {
contributions.add(menuContribution);
}
}
MElementContainer<MMenuElement> findMenuFromPath(MElementContainer<MMenuElement> menu,
Path menuPath, int segment) {
int idx = ContributionsAnalyzer.indexForId(menu, menuPath.segment(segment));
if (idx == -1) {
if (segment + 1 < menuPath.segmentCount() || !menuPath.hasTrailingSeparator()) {
return null;
}
return menu;
}
MElementContainer<MMenuElement> item = (MElementContainer<MMenuElement>) menu.getChildren()
.get(idx);
if (item.getChildren().size() == 0) {
if (segment + 1 == menuPath.segmentCount()) {
return menu;
} else {
return null;
}
}
return findMenuFromPath(item, menuPath, segment + 1);
}
}