Bug 325392 - Render menu and toolbar contributions using the ContributionManagers filling in visibility on SWT.Show
diff --git a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/NewMenuRenderer.java b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/NewMenuRenderer.java index 789433d..e86f465 100644 --- a/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/NewMenuRenderer.java +++ b/bundles/org.eclipse.e4.ui.workbench.renderers.swt/src/org/eclipse/e4/ui/workbench/renderers/swt/NewMenuRenderer.java
@@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import javax.annotation.PostConstruct; @@ -23,6 +24,7 @@ import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.core.services.log.Logger; import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer; +import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer; import org.eclipse.e4.ui.model.application.MApplication; import org.eclipse.e4.ui.model.application.ui.MElementContainer; import org.eclipse.e4.ui.model.application.ui.MUIElement; @@ -38,12 +40,16 @@ import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu; import org.eclipse.e4.ui.workbench.IResourceUtilities; import org.eclipse.e4.ui.workbench.UIEvents; +import org.eclipse.e4.ui.workbench.modeling.ExpressionContext; import org.eclipse.e4.ui.workbench.swt.util.ISWTResourceUtilities; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jface.action.AbstractGroupMarker; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.resource.ImageDescriptor; @@ -63,7 +69,7 @@ private Map<MMenuItem, IContributionItem> modelToContribution = new HashMap<MMenuItem, IContributionItem>(); - private Map<MMenu, ArrayList<MMenuElement>> modelToMenuContributions = new HashMap<MMenu, ArrayList<MMenuElement>>(); + private Map<MMenuElement, ContributionRecord> modelContributionToRecord = new HashMap<MMenuElement, ContributionRecord>(); @Inject private Logger logger; @@ -167,6 +173,35 @@ } }; + private IMenuListener visibilityCalculationListener = new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + MenuManager menuManager = (MenuManager) manager; + if (menuManager.getMenu() == null) { + return; + } + Menu menu = menuManager.getMenu(); + Object obj = menu.getData(AbstractPartRenderer.OWNING_ME); + if (obj == null && menu.getParentItem() != null) { + obj = menu.getParentItem().getData( + AbstractPartRenderer.OWNING_ME); + } + if (!(obj instanceof MMenu)) { + return; + } + MMenu menuModel = (MMenu) obj; + final IEclipseContext parentContext = modelService + .getContainingContext(menuModel); + HashSet<ContributionRecord> records = new HashSet<ContributionRecord>(); + for (MMenuElement element : menuModel.getChildren()) { + ContributionRecord record = modelContributionToRecord + .get(element); + if (records.add(record)) { + record.updateVisibility(parentContext); + } + } + } + }; + @PostConstruct public void init() { eventBroker.subscribe(UIEvents.buildTopic(UIEvents.UILabel.TOPIC), @@ -211,6 +246,7 @@ MenuManager menuBarManager = new MenuManager(NO_LABEL, menuModel.getElementId()); modelToManager.put(menuModel, menuBarManager); + menuBarManager.addMenuListener(visibilityCalculationListener); newMenu = menuBarManager.createMenuBar((Decorations) parent); ((Decorations) parent).setMenuBar(newMenu); newMenu.setData(menuBarManager); @@ -218,6 +254,7 @@ MenuManager popupManager = new MenuManager(NO_LABEL, menuModel.getElementId()); modelToManager.put(menuModel, popupManager); + popupManager.addMenuListener(visibilityCalculationListener); newMenu = popupManager.createContextMenu((Control) parent); ((Control) parent).setMenu(newMenu); newMenu.setData(popupManager); @@ -231,6 +268,7 @@ MenuManager popupManager = new MenuManager(NO_LABEL, menuModel.getElementId()); modelToManager.put(menuModel, popupManager); + popupManager.addMenuListener(visibilityCalculationListener); newMenu = popupManager.createContextMenu((Control) parent); ((Control) parent).setMenu(newMenu); newMenu.setData(popupManager); @@ -244,13 +282,147 @@ */ private void processContributions(MMenu menuModel) { final ArrayList<MMenuContribution> toContribute = new ArrayList<MMenuContribution>(); - final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<MMenuElement>(); - ContributionsAnalyzer.gatherMenuContributions(menuModel, + ContributionsAnalyzer.XXXgatherMenuContributions(menuModel, application.getMenuContributions(), menuModel.getElementId(), toContribute, null, menuModel instanceof MPopupMenu); - ContributionsAnalyzer.addMenuContributions(menuModel, toContribute, - menuContributionsToRemove); - modelToMenuContributions.put(menuModel, menuContributionsToRemove); + generateContributions(menuModel, toContribute); + } + + /** + * @param menuModel + * @param toContribute + */ + private void generateContributions(MMenu menuModel, + ArrayList<MMenuContribution> toContribute) { + HashSet<String> existingMenuIds = new HashSet<String>(); + HashSet<String> existingSeparatorNames = new HashSet<String>(); + 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); + } + } + + MenuManager manager = modelToManager.get(menuModel); + boolean done = toContribute.size() == 0; + while (!done) { + ArrayList<MMenuContribution> curList = new ArrayList<MMenuContribution>( + toContribute); + int retryCount = toContribute.size(); + toContribute.clear(); + + for (MMenuContribution menuContribution : curList) { + if (!processAddition(menuModel, manager, 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); + } + } + + /** + * @param menuModel + * @param manager + * @param menuContribution + * @return true if the menuContribution was processed + */ + private boolean processAddition(MMenu menuModel, MenuManager manager, + MMenuContribution menuContribution, + final HashSet<String> existingMenuIds, + HashSet<String> existingSeparatorNames) { + int idx = getIndex(menuModel, menuContribution.getPositionInParent()); + if (idx == -1) { + return false; + } + ContributionRecord record = new ContributionRecord(menuModel, + menuContribution); + record.generate(); + for (MMenuElement copy : record.generatedElements) { + modelContributionToRecord.put(copy, record); + if (copy instanceof MMenu + && existingMenuIds.contains(copy.getElementId())) { + // skip this, it's already there + continue; + } else if (copy instanceof MMenuSeparator + && existingSeparatorNames.contains(copy.getElementId())) { + // skip this, it's already there + continue; + } + 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; + } + + 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]; + 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$ + } + + static class ContributionRecord { + MMenu menuModel; + MMenuContribution menuContribution; + ArrayList<MMenuElement> generatedElements = new ArrayList<MMenuElement>(); + + public ContributionRecord(MMenu menuModel, + MMenuContribution contribution) { + this.menuModel = menuModel; + this.menuContribution = contribution; + } + + /** + * @param context + */ + public void updateVisibility(IEclipseContext context) { + ExpressionContext exprContext = new ExpressionContext(context); + boolean isVisible = ContributionsAnalyzer.isVisible( + menuContribution, exprContext); + for (MMenuElement item : generatedElements) { + item.setVisible(isVisible); + } + } + + public void generate() { + for (MMenuElement item : menuContribution.getChildren()) { + MMenuElement copy = (MMenuElement) EcoreUtil + .copy((EObject) item); + generatedElements.add(copy); + } + } } void removeMenuContributions(final MMenu menuModel, @@ -301,6 +473,7 @@ MenuManager menuManager = new MenuManager(menuText, desc, menuModel.getElementId()); modelToManager.put(menuModel, menuManager); + menuManager.addMenuListener(visibilityCalculationListener); parentManager.add(menuManager); processContributions(menuModel); List<MMenuElement> parts = menuModel.getChildren();
diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ContributionsAnalyzer.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ContributionsAnalyzer.java index 39d01ce..9d4696a 100644 --- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ContributionsAnalyzer.java +++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ContributionsAnalyzer.java
@@ -24,8 +24,10 @@ 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.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; @@ -85,7 +87,7 @@ return false; } - public static void gatherMenuContributions(final MMenu menuModel, + public static void XXXgatherMenuContributions(final MMenu menuModel, final List<MMenuContribution> menuContributionList, final String id, final ArrayList<MMenuContribution> toContribute, final ExpressionContext eContext, boolean includePopups) { @@ -105,6 +107,29 @@ } } + public static void gatherMenuContributions(final MMenu menuModel, + final List<MMenuContribution> menuContributionList, final String id, + final ArrayList<MMenuContribution> toContribute, final ExpressionContext eContext, + boolean includePopups) { + 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); + if (filtered || (!popup && !parentID.equals(id)) || !menuContribution.isToBeRendered()) { + continue; + } + if (menuBar || isVisible(menuContribution, eContext)) { + toContribute.add(menuContribution); + } + } + } + static boolean isFiltered(MMenu menuModel, MMenuContribution menuContribution) { if (menuModel.getTags().contains(ContributionsAnalyzer.MC_POPUP)) { return !menuContribution.getTags().contains(ContributionsAnalyzer.MC_POPUP)