| /******************************************************************************* |
| * Copyright (c) 2009, 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 410426 |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 426535, 433234, 431868, 472654, 485852 |
| * Maxime Porhel <maxime.porhel@obeo.fr> Obeo - Bug 431778 |
| * Andrey Loskutov <loskutov@gmx.de> - Bugs 383569, 457198 |
| * Dirk Fauth <dirk.fauth@googlemail.com> - Bug 431990 |
| * Sopot Cela <scela@redhat.com> - Bug 472761 |
| * Patrik Suzzi <psuzzi@gmail.com> - Bug 473184 |
| * Simon Scholz <simon.scholz@vogella.com> - Bug 506306 |
| * Axel Richard <axel.richard@oebo.fr> - Bug 354538 |
| * Rolf Theunissen <rolf.theunissen@gmail.com> - Bug 378495 |
| *******************************************************************************/ |
| package org.eclipse.e4.ui.workbench.renderers.swt; |
| |
| import java.time.Duration; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import javax.annotation.PostConstruct; |
| import javax.annotation.PreDestroy; |
| import javax.inject.Inject; |
| import org.eclipse.core.expressions.ExpressionInfo; |
| import org.eclipse.e4.core.contexts.ContextInjectionFactory; |
| import org.eclipse.e4.core.contexts.IContextFunction; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.core.contexts.RunAndTrack; |
| import org.eclipse.e4.core.di.annotations.Optional; |
| import org.eclipse.e4.core.services.events.IEventBroker; |
| import org.eclipse.e4.core.services.log.Logger; |
| import org.eclipse.e4.ui.di.UIEventTopic; |
| import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer; |
| import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil; |
| import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer; |
| import org.eclipse.e4.ui.internal.workbench.swt.CSSRenderingUtils; |
| import org.eclipse.e4.ui.internal.workbench.swt.Policy; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.MApplicationElement; |
| 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.SideValue; |
| import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar; |
| import org.eclipse.e4.ui.model.application.ui.menu.MDirectToolItem; |
| import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem; |
| 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.MToolControl; |
| import org.eclipse.e4.ui.model.application.ui.menu.MToolItem; |
| import org.eclipse.e4.ui.services.IServiceConstants; |
| import org.eclipse.e4.ui.services.IStylingEngine; |
| import org.eclipse.e4.ui.workbench.IPresentationEngine; |
| import org.eclipse.e4.ui.workbench.Selector; |
| import org.eclipse.e4.ui.workbench.UIEvents; |
| import org.eclipse.e4.ui.workbench.UIEvents.ElementContainer; |
| import org.eclipse.e4.ui.workbench.UIEvents.EventTags; |
| import org.eclipse.emf.common.util.ECollections; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.jface.action.AbstractGroupMarker; |
| import org.eclipse.jface.action.ContributionItem; |
| import org.eclipse.jface.action.GroupMarker; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.IContributionManagerOverrides; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.action.ToolBarManager; |
| import org.eclipse.jface.util.Throttler; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.swt.widgets.Widget; |
| import org.osgi.service.event.Event; |
| |
| /** |
| * Create a contribute part. |
| */ |
| public class ToolBarManagerRenderer extends SWTPartRenderer { |
| |
| private static final Selector ALL_SELECTOR = element -> true; |
| |
| /** */ |
| public static final String POST_PROCESSING_FUNCTION = "ToolBarManagerRenderer.postProcess.func"; //$NON-NLS-1$ |
| /** */ |
| public static final String POST_PROCESSING_DISPOSE = "ToolBarManagerRenderer.postProcess.dispose"; //$NON-NLS-1$ |
| /** */ |
| public static final String UPDATE_VARS = "ToolBarManagerRenderer.updateVars"; //$NON-NLS-1$ |
| private static final String DISPOSE_ADDED = "ToolBarManagerRenderer.disposeAdded"; //$NON-NLS-1$ |
| |
| private Map<MToolBar, ToolBarManager> modelToManager = new HashMap<>(); |
| private Map<ToolBarManager, MToolBar> managerToModel = new HashMap<>(); |
| |
| private Map<MToolBarElement, IContributionItem> modelToContribution = new HashMap<>(); |
| private Map<IContributionItem, MToolBarElement> contributionToModel = new HashMap<>(); |
| |
| private Map<MToolBarElement, ToolBarContributionRecord> modelContributionToRecord = new HashMap<>(); |
| |
| private Map<MToolBarElement, ArrayList<ToolBarContributionRecord>> sharedElementToRecord = new HashMap<>(); |
| |
| private ToolItemUpdater enablementUpdater = new ToolItemUpdater(); |
| |
| @Inject |
| private Logger logger; |
| |
| @Inject |
| private MApplication application; |
| |
| @Inject |
| @Optional |
| private void subscribeTopicUpdateItems(@UIEventTopic(UIEvents.UILabel.TOPIC_ALL) Event event) { |
| // Ensure that this event is for a MToolBarElement |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement)) { |
| return; |
| } |
| |
| MToolBarElement itemModel = (MToolBarElement) event.getProperty(UIEvents.EventTags.ELEMENT); |
| |
| IContributionItem ici = getContribution(itemModel); |
| if (ici == null) { |
| return; |
| } |
| String attName = (String) event.getProperty(UIEvents.EventTags.ATTNAME); |
| |
| if (UIEvents.UILabel.LABEL.equals(attName) || |
| UIEvents.UILabel.LOCALIZED_LABEL.equals(attName)|| |
| UIEvents.UILabel.ICONURI.equals(attName) || |
| UIEvents.UILabel.TOOLTIP.equals(attName)|| |
| UIEvents.UILabel.LOCALIZED_TOOLTIP.equals(attName)) |
| { |
| ici.update(); |
| } |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicUpdateToBeRendered(@UIEventTopic(UIEvents.UIElement.TOPIC_ALL) Event event) { |
| // Ensure that this event is for a MToolBarElement |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement)) { |
| return; |
| } |
| |
| MToolBarElement itemModel = (MToolBarElement) event.getProperty(UIEvents.EventTags.ELEMENT); |
| String attName = (String) event.getProperty(UIEvents.EventTags.ATTNAME); |
| if (UIEvents.UIElement.TOBERENDERED.equals(attName)) { |
| Object obj = itemModel.getParent(); |
| if (!(obj instanceof MToolBar)) { |
| return; |
| } |
| ToolBarManager parent = getManager((MToolBar) obj); |
| if (itemModel.isToBeRendered()) { |
| if (parent != null) { |
| modelProcessSwitch(parent, itemModel); |
| updateWidget(parent); |
| } |
| } else { |
| removeElement(parent, itemModel); |
| if (parent != null) { |
| updateWidget(parent); |
| } |
| } |
| } else if (UIEvents.UIElement.VISIBLE.equals(attName)) { |
| IContributionItem ici = getContribution(itemModel); |
| if (ici == null) { |
| return; |
| } |
| |
| ToolBarManager parent = null; |
| if (ici instanceof MenuManager) { |
| parent = (ToolBarManager) ((MenuManager) ici).getParent(); |
| } else if (ici instanceof ContributionItem) { |
| parent = (ToolBarManager) ((ContributionItem) ici).getParent(); |
| } |
| |
| if (parent == null) { |
| ici.setVisible(itemModel.isVisible()); |
| return; |
| } |
| |
| IContributionManagerOverrides ov = parent.getOverrides(); |
| // partial fix for bug 383569: only change state if there are no |
| // extra override mechanics controlling element visibility |
| if (ov == null) { |
| ici.setVisible(itemModel.isVisible()); |
| } else { |
| Boolean visible = ov.getVisible(ici); |
| if (visible == null) { |
| // same as above: only change state if there are no extra |
| // override mechanics controlling element visibility |
| ici.setVisible(itemModel.isVisible()); |
| } |
| } |
| |
| updateWidget(parent); |
| } |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicUpdateSelection(@UIEventTopic(UIEvents.Item.TOPIC_SELECTED) Event event) { |
| // Ensure that this event is for a MToolBarElement |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement)) { |
| return; |
| } |
| |
| MToolBarElement itemModel = (MToolBarElement) event.getProperty(UIEvents.EventTags.ELEMENT); |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| ici.update(); |
| } |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicUpdateEnablement(@UIEventTopic(UIEvents.Item.TOPIC_ENABLED) Event event) { |
| // Ensure that this event is for a MToolBarElement |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBarElement)) { |
| return; |
| } |
| |
| MToolBarElement itemModel = (MToolBarElement) event.getProperty(UIEvents.EventTags.ELEMENT); |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| ici.update(); |
| } |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicUpdateChildren(@UIEventTopic(ElementContainer.TOPIC_CHILDREN) Event event) { |
| // Ensure that this event is for a MToolBar |
| if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MToolBar)) { |
| return; |
| } |
| |
| MToolBar toolbarModel = (MToolBar) event.getProperty(UIEvents.EventTags.ELEMENT); |
| ToolBarManager parentManager = getManager(toolbarModel); |
| if (parentManager == null) { |
| return; |
| } |
| |
| if (UIEvents.isADD(event)) { |
| for (Object o : UIEvents.asIterable(event, UIEvents.EventTags.NEW_VALUE)) { |
| MToolBarElement added = (MToolBarElement) o; |
| modelProcessSwitch(parentManager, added); |
| } |
| updateWidget(parentManager); |
| } else if (UIEvents.isREMOVE(event)) { |
| for (Object o : UIEvents.asIterable(event, UIEvents.EventTags.OLD_VALUE)) { |
| MToolBarElement removed = (MToolBarElement) o; |
| removed.setRenderer(null); |
| removeElement(parentManager, removed); |
| } |
| updateWidget(parentManager); |
| } else if (UIEvents.isMOVE(event)) { |
| MToolBarElement moved = (MToolBarElement) event.getProperty(UIEvents.EventTags.NEW_VALUE); |
| Integer newPos = (Integer) event.getProperty(UIEvents.EventTags.POSITION); |
| |
| IContributionItem ici = getContribution(moved); |
| parentManager.remove(ici); |
| parentManager.insert(newPos, ici); |
| |
| updateWidget(parentManager); |
| } |
| } |
| |
| private HashSet<String> updateVariables = new HashSet<>(); |
| |
| @Inject |
| @Optional |
| private void subscribeTopicDirtyChanged(@UIEventTopic(UIEvents.Dirtyable.TOPIC_DIRTY) Event eventData) { |
| getUpdater().updateContributionItems(ALL_SELECTOR); |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicUpdateToolbarEnablement( |
| @UIEventTopic(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC) Event eventData) { |
| final Object v = eventData != null ? eventData.getProperty(IEventBroker.DATA) : UIEvents.ALL_ELEMENT_ID; |
| Selector s; |
| if (v instanceof Selector) { |
| s = (Selector) v; |
| } else { |
| if (v == null || UIEvents.ALL_ELEMENT_ID.equals(v)) { |
| s = ALL_SELECTOR; |
| } else { |
| s = element -> v.equals(element.getElementId()); |
| } |
| } |
| |
| getUpdater().updateContributionItems(s); |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicTagsChanged(@UIEventTopic(UIEvents.ApplicationElement.TOPIC_TAGS) Event event) { |
| |
| Object changedObj = event.getProperty(EventTags.ELEMENT); |
| |
| if (!(changedObj instanceof MToolBar)) { |
| return; |
| } |
| |
| final MUIElement changedElement = (MUIElement) changedObj; |
| |
| if (UIEvents.isADD(event)) { |
| if (UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE, IPresentationEngine.HIDDEN_EXPLICITLY)) { |
| changedElement.setVisible(false); |
| changedElement.setToBeRendered(false); |
| } |
| } else if (UIEvents.isREMOVE(event)) { |
| if (UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE, IPresentationEngine.HIDDEN_EXPLICITLY)) { |
| changedElement.setVisible(true); |
| changedElement.setToBeRendered(true); |
| } |
| } |
| } |
| |
| @Inject |
| @Optional |
| private void subscribeTopicAppStartup(@UIEventTopic(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE) Event event) { |
| List<MToolBar> toolBars = modelService.findElements(application, null, MToolBar.class); |
| for (MToolBar mToolBar : toolBars) { |
| if (mToolBar.getTags().contains(IPresentationEngine.HIDDEN_EXPLICITLY)) { |
| mToolBar.setVisible(false); |
| mToolBar.setToBeRendered(false); |
| } |
| } |
| } |
| |
| /** |
| * |
| */ |
| @PostConstruct |
| public void init() { |
| context.set(ToolBarManagerRenderer.class, this); |
| Throttler throttler = new Throttler(Display.getDefault(), Duration.ofMillis(200), |
| () -> getUpdater().updateContributionItems(ALL_SELECTOR)); |
| |
| String[] vars = { |
| "org.eclipse.ui.internal.services.EvaluationService.evaluate", //$NON-NLS-1$ |
| IServiceConstants.ACTIVE_CONTEXTS, |
| IServiceConstants.ACTIVE_SELECTION, |
| IServiceConstants.ACTIVE_SHELL }; |
| updateVariables.addAll(Arrays.asList(vars)); |
| context.set(UPDATE_VARS, updateVariables); |
| RunAndTrack enablementUpdater = new RunAndTrack() { |
| |
| @Override |
| public boolean changed(IEclipseContext context) { |
| for (String var : updateVariables) { |
| context.get(var); |
| } |
| throttler.throttledExec(); |
| return true; |
| } |
| }; |
| context.runAndTrack(enablementUpdater); |
| } |
| |
| @PreDestroy |
| public void preDestroy() { |
| if (Policy.DEBUG_RENDERER) { |
| logger.debug("\nTBMR:dispose: modelToManager size = {0}, managerToModel size = {1}", //$NON-NLS-1$ |
| modelToManager.size(), managerToModel.size()); |
| } |
| } |
| |
| @Override |
| public Object createWidget(final MUIElement element, Object parent) { |
| if (!(element instanceof MToolBar) || !(parent instanceof Composite)) { |
| return null; |
| } |
| |
| Composite toolbarComposite = (Composite) parent; |
| // Composite which contains toolbar needs to have a separate class to allow the |
| // CSS engine to target it |
| IStylingEngine engine = getContextForParent(element).get(IStylingEngine.class); |
| if (engine != null) { |
| engine.setId(toolbarComposite, "ToolbarComposite");//$NON-NLS-1$ |
| } |
| |
| final MToolBar toolbarModel = (MToolBar) element; |
| ToolBar newTB = createToolbar(toolbarModel, toolbarComposite); |
| bindWidget(element, newTB); |
| processContribution(toolbarModel, toolbarModel.getElementId()); |
| |
| Control renderedCtrl = newTB; |
| MUIElement parentElement = element.getParent(); |
| if (parentElement instanceof MTrimBar) { |
| if (!element.getTags().contains(IPresentationEngine.NO_MOVE)) { |
| element.getTags().add(IPresentationEngine.DRAGGABLE); |
| } |
| |
| setCSSInfo(element, newTB); |
| |
| |
| boolean vertical = false; |
| MTrimBar bar = (MTrimBar) parentElement; |
| vertical = bar.getSide() == SideValue.LEFT || bar.getSide() == SideValue.RIGHT; |
| IEclipseContext parentContext = getContextForParent(element); |
| |
| CSSRenderingUtils cssUtils = parentContext.get(CSSRenderingUtils.class); |
| if (cssUtils != null) { |
| MUIElement modelElement = (MUIElement) newTB.getData(AbstractPartRenderer.OWNING_ME); |
| boolean draggable = ((modelElement != null) && (modelElement.getTags().contains(IPresentationEngine.DRAGGABLE))); |
| renderedCtrl = cssUtils.frameMeIfPossible(newTB, null, vertical, draggable); |
| } |
| } |
| |
| return renderedCtrl; |
| } |
| |
| /** |
| * @param toolbarModel |
| * @param elementId |
| */ |
| public void processContribution(MToolBar toolbarModel, String elementId) { |
| |
| ToolBarManager manager = getManager(toolbarModel); |
| if (manager != null && manager.getControl() != null) { |
| addCleanupDisposeListener(toolbarModel, manager.getControl()); |
| } |
| |
| final ArrayList<MToolBarContribution> toContribute = new ArrayList<>(); |
| ContributionsAnalyzer.XXXgatherToolBarContributions(toolbarModel, |
| application.getToolBarContributions(), elementId, toContribute); |
| generateContributions(toolbarModel, toContribute); |
| } |
| |
| private void addCleanupDisposeListener(final MToolBar toolbarModel, ToolBar control) { |
| |
| final Map<String, Object> transientData = toolbarModel.getTransientData(); |
| if (!transientData.containsKey(DISPOSE_ADDED)) { |
| transientData.put(DISPOSE_ADDED, Boolean.TRUE); |
| control.addDisposeListener(e -> { |
| cleanUp(toolbarModel); |
| Object dispose = transientData.get(POST_PROCESSING_DISPOSE); |
| if (dispose instanceof Runnable) { |
| ((Runnable) dispose).run(); |
| } |
| transientData.remove(POST_PROCESSING_DISPOSE); |
| transientData.remove(DISPOSE_ADDED); |
| }); |
| } |
| |
| } |
| |
| private void generateContributions(MToolBar toolbarModel, List<MToolBarContribution> toContribute) { |
| |
| ToolBarManager manager = getManager(toolbarModel); |
| boolean done = toContribute.isEmpty(); |
| while (!done) { |
| ArrayList<MToolBarContribution> curList = new ArrayList<>(toContribute); |
| int retryCount = toContribute.size(); |
| toContribute.clear(); |
| |
| for (final MToolBarContribution contribution : curList) { |
| if (!processAddition(toolbarModel, manager, contribution)) { |
| toContribute.add(contribution); |
| } |
| } |
| // 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; |
| } |
| } |
| |
| /** |
| * @return <code>true</code> if the contribution was successfully processed |
| */ |
| private boolean processAddition(final MToolBar toolbarModel, final ToolBarManager manager, |
| MToolBarContribution contribution) { |
| final ToolBarContributionRecord record = new ToolBarContributionRecord(toolbarModel, contribution, this); |
| if (!record.mergeIntoModel()) { |
| return false; |
| } |
| if (record.anyVisibleWhen()) { |
| ExpressionInfo info = new ExpressionInfo(); |
| record.collectInfo(info); |
| updateVariables.addAll(Arrays.asList(info.getAccessedVariableNames())); |
| final IEclipseContext parentContext = getContext(toolbarModel); |
| parentContext.runAndTrack(new RunAndTrack() { |
| @Override |
| public boolean changed(IEclipseContext context) { |
| if (getManager(toolbarModel) == null) { |
| // tool bar no longer being managed, ignore it |
| return false; |
| } |
| |
| record.updateVisibility(parentContext.getActiveLeaf()); |
| runExternalCode(() -> { |
| manager.update(false); |
| getUpdater().updateContributionItems(e -> { |
| if (e instanceof MToolBarElement) { |
| if (((MUIElement) ((MToolBarElement) e).getParent()) == toolbarModel) { |
| return true; |
| } |
| } |
| return false; |
| }); |
| }); |
| return true; |
| } |
| }); |
| } |
| |
| return true; |
| } |
| |
| private ToolBar createToolbar(final MUIElement element, Composite parent) { |
| int orientation = getOrientation(element); |
| int style = orientation | SWT.WRAP | SWT.FLAT | SWT.RIGHT; |
| ToolBarManager manager = getManager((MToolBar) element); |
| if (manager == null) { |
| manager = new ToolBarManager(style); |
| IContributionManagerOverrides overrides = null; |
| MApplicationElement parentElement = element.getParent(); |
| if (parentElement == null) { |
| parentElement = modelService.getContainer(element); |
| } |
| |
| if (parentElement != null) { |
| overrides = (IContributionManagerOverrides) parentElement.getTransientData().get( |
| IContributionManagerOverrides.class.getName()); |
| } |
| |
| manager.setOverrides(overrides); |
| linkModelToManager((MToolBar) element, manager); |
| } else { |
| ToolBar toolBar = manager.getControl(); |
| if (toolBar != null && !toolBar.isDisposed() && (toolBar.getStyle() & orientation) == 0) { |
| toolBar.dispose(); |
| } |
| manager.setStyle(style); |
| } |
| ToolBar btoolbar = manager.createControl(parent); |
| btoolbar.setData(manager); |
| btoolbar.setData(AbstractPartRenderer.OWNING_ME, element); |
| btoolbar.requestLayout(); |
| return btoolbar; |
| } |
| |
| protected void cleanUp(MToolBar toolbarModel) { |
| Collection<ToolBarContributionRecord> vals = modelContributionToRecord.values(); |
| for (ToolBarContributionRecord record : vals.toArray(new ToolBarContributionRecord[vals.size()])) { |
| if (record.toolbarModel == toolbarModel) { |
| record.dispose(); |
| for (MToolBarElement copy : record.generatedElements) { |
| cleanUpCopy(record, copy); |
| } |
| for (MToolBarElement copy : record.sharedElements) { |
| cleanUpCopy(record, copy); |
| } |
| record.generatedElements.clear(); |
| record.sharedElements.clear(); |
| } |
| } |
| } |
| |
| /** |
| * @param record |
| * @param copy |
| */ |
| public void cleanUpCopy(ToolBarContributionRecord record, MToolBarElement copy) { |
| modelContributionToRecord.remove(copy); |
| IContributionItem ici = getContribution(copy); |
| clearModelToContribution(copy, ici); |
| if (ici != null) { |
| record.getManagerForModel().remove(ici); |
| } |
| } |
| |
| private int getOrientation(final MUIElement element) { |
| MUIElement theParent = element.getParent(); |
| if (theParent instanceof MTrimBar) { |
| MTrimBar trimContainer = (MTrimBar) theParent; |
| SideValue side = trimContainer.getSide(); |
| if (side.getValue() == SideValue.LEFT_VALUE || side.getValue() == SideValue.RIGHT_VALUE) { |
| return SWT.VERTICAL; |
| } |
| } |
| return SWT.HORIZONTAL; |
| } |
| |
| @Override |
| public void processContents(MElementContainer<MUIElement> container) { |
| // I can either simply stop processing, or we can walk the model |
| // ourselves like the "old" days |
| // EMF gives us null lists if empty |
| if (container == null) { |
| return; |
| } |
| |
| Object obj = container; |
| ToolBarManager parentManager = getManager((MToolBar) obj); |
| if (parentManager == null) { |
| return; |
| } |
| // Process any contents of the newly created ME |
| List<MUIElement> parts = container.getChildren(); |
| if (parts != null) { |
| MUIElement[] plist = parts.toArray(new MUIElement[parts.size()]); |
| for (MUIElement childME : plist) { |
| modelProcessSwitch(parentManager, (MToolBarElement) childME); |
| } |
| } |
| |
| updateWidget(parentManager); |
| } |
| |
| private void updateWidget(ToolBarManager manager) { |
| manager.update(true); |
| ToolBar toolbar = manager.getControl(); |
| if (toolbar != null && !toolbar.isDisposed()) { |
| toolbar.requestLayout(); |
| } |
| } |
| |
| @Override |
| public void hideChild(MElementContainer<MUIElement> parentElement, MUIElement child) { |
| super.hideChild(parentElement, child); |
| // only handle the disposal of this element if it was actually rendered |
| // by the engine |
| if (child.getRenderer() != null) { |
| // Since there's no place to 'store' a child that's not in a menu |
| // we'll blow it away and re-create on an add |
| Widget widget = (Widget) child.getWidget(); |
| if (widget != null && !widget.isDisposed()) { |
| widget.dispose(); |
| } |
| ToolBar toolbar = (ToolBar) getUIContainer(child); |
| if (toolbar != null && !toolbar.isDisposed()) { |
| toolbar.requestLayout(); |
| } |
| } |
| } |
| |
| @Override |
| public void childRendered(MElementContainer<MUIElement> parentElement, MUIElement element) { |
| super.childRendered(parentElement, element); |
| processContents(parentElement); |
| ToolBar toolbar = (ToolBar) getUIContainer(element); |
| if (toolbar != null && !toolbar.isDisposed()) { |
| toolbar.requestLayout(); |
| } |
| } |
| |
| @Override |
| public Object getUIContainer(MUIElement childElement) { |
| Composite intermediate = (Composite) super.getUIContainer(childElement); |
| if (intermediate == null || intermediate.isDisposed()) { |
| return null; |
| } |
| if (intermediate instanceof ToolBar) { |
| return intermediate; |
| } |
| ToolBar toolbar = findToolbar(intermediate); |
| if (toolbar == null) { |
| toolbar = createToolbar(childElement.getParent(), intermediate); |
| } |
| return toolbar; |
| } |
| |
| private ToolBar findToolbar(Composite intermediate) { |
| for (Control child : intermediate.getChildren()) { |
| if (child.getData() instanceof ToolBarManager) { |
| return (ToolBar) child; |
| } |
| } |
| return null; |
| } |
| |
| private void modelProcessSwitch(ToolBarManager parentManager, |
| MToolBarElement childME) { |
| if (OpaqueElementUtil.isOpaqueToolItem(childME)) { |
| MToolItem itemModel = (MToolItem) childME; |
| processOpaqueItem(parentManager, itemModel); |
| } else if (childME instanceof MHandledToolItem) { |
| MHandledToolItem itemModel = (MHandledToolItem) childME; |
| processHandledItem(parentManager, itemModel); |
| } else if (childME instanceof MDirectToolItem) { |
| MDirectToolItem itemModel = (MDirectToolItem) childME; |
| processDirectItem(parentManager, itemModel); |
| } else if (childME instanceof MToolBarSeparator) { |
| MToolBarSeparator itemModel = (MToolBarSeparator) childME; |
| processSeparator(parentManager, itemModel); |
| } else if (childME instanceof MToolControl) { |
| MToolControl itemModel = (MToolControl) childME; |
| processToolControl(parentManager, itemModel); |
| } |
| } |
| |
| private void processSeparator(ToolBarManager parentManager, MToolBarSeparator itemModel) { |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| return; |
| } |
| itemModel.setRenderer(this); |
| AbstractGroupMarker marker = null; |
| if (itemModel.isVisible() && !itemModel.getTags().contains(MenuManagerRenderer.GROUP_MARKER)) { |
| marker = new Separator(); |
| marker.setId(itemModel.getElementId()); |
| } else { |
| if (itemModel.getElementId() != null) { |
| marker = new GroupMarker(itemModel.getElementId()); |
| } |
| } |
| if (marker != null) { |
| addToManager(parentManager, itemModel, marker); |
| linkModelToContribution(itemModel, marker); |
| } |
| } |
| |
| private void processToolControl(ToolBarManager parentManager, MToolControl itemModel) { |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| return; |
| } |
| itemModel.setRenderer(this); |
| final IEclipseContext lclContext = getContext(itemModel); |
| ToolControlContribution ci = ContextInjectionFactory.make(ToolControlContribution.class, lclContext); |
| ci.setModel(itemModel); |
| ci.setVisible(itemModel.isVisible()); |
| addToManager(parentManager, itemModel, ci); |
| linkModelToContribution(itemModel, ci); |
| } |
| |
| private void processDirectItem(ToolBarManager parentManager, MDirectToolItem itemModel) { |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| return; |
| } |
| itemModel.setRenderer(this); |
| final IEclipseContext lclContext = getContext(itemModel); |
| DirectContributionItem ci = ContextInjectionFactory.make(DirectContributionItem.class, lclContext); |
| ci.setModel(itemModel); |
| ci.setVisible(itemModel.isVisible()); |
| addToManager(parentManager, itemModel, ci); |
| linkModelToContribution(itemModel, ci); |
| } |
| |
| private void processHandledItem(ToolBarManager parentManager, MHandledToolItem itemModel) { |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| return; |
| } |
| itemModel.setRenderer(this); |
| final IEclipseContext lclContext = getContext(itemModel); |
| HandledContributionItem ci = ContextInjectionFactory.make(HandledContributionItem.class, lclContext); |
| ci.setModel(itemModel); |
| ci.setVisible(itemModel.isVisible()); |
| addToManager(parentManager, itemModel, ci); |
| linkModelToContribution(itemModel, ci); |
| } |
| |
| private void processOpaqueItem(ToolBarManager parentManager, MToolItem itemModel) { |
| IContributionItem ici = getContribution(itemModel); |
| if (ici != null) { |
| return; |
| } |
| |
| itemModel.setRenderer(this); |
| Object obj = OpaqueElementUtil.getOpaqueItem(itemModel); |
| if (obj instanceof IContributionItem) { |
| ici = (IContributionItem) obj; |
| } else { |
| return; |
| } |
| ici.setVisible(itemModel.isVisible()); |
| addToManager(parentManager, itemModel, ici); |
| linkModelToContribution(itemModel, ici); |
| } |
| |
| private void addToManager(ToolBarManager parentManager, |
| MToolBarElement model, IContributionItem ci) { |
| MElementContainer<MUIElement> parent = model.getParent(); |
| // technically this shouldn't happen |
| if (parent == null) { |
| parentManager.add(ci); |
| } else { |
| int index = parent.getChildren().indexOf(model); |
| // shouldn't be -1, but better safe than sorry |
| if (index > parentManager.getSize() || index == -1) { |
| parentManager.add(ci); |
| } else { |
| parentManager.insert(index, ci); |
| } |
| } |
| } |
| |
| private void removeElement(ToolBarManager parentManager, MToolBarElement toolBarElement) { |
| IContributionItem ici = getContribution(toolBarElement); |
| clearModelToContribution(toolBarElement, ici); |
| if (ici != null && parentManager != null) { |
| // Check if the ici is (still) in the manager; e.g. while reconciling |
| // Whoever removes an ici form the manager is responsible for disposal |
| ici = parentManager.remove(ici); |
| } |
| if (ici != null) { |
| ici.dispose(); |
| } |
| } |
| |
| /** |
| * @param model |
| * @return mapped manager, if any |
| */ |
| public ToolBarManager getManager(MToolBar model) { |
| return modelToManager.get(model); |
| } |
| |
| /** |
| * @param manager |
| * @return mapped model, if any |
| */ |
| public MToolBar getToolBarModel(ToolBarManager manager) { |
| return managerToModel.get(manager); |
| } |
| |
| /** |
| * @param model |
| * @param manager |
| */ |
| public void linkModelToManager(MToolBar model, ToolBarManager manager) { |
| modelToManager.put(model, manager); |
| managerToModel.put(manager, model); |
| if (Policy.DEBUG_RENDERER) { |
| logger.debug("\nTBMR:linkModelToManager: modelToManager size = {0}, managerToModel size = {1}", //$NON-NLS-1$ |
| modelToManager.size(), managerToModel.size()); |
| } |
| } |
| |
| /** |
| * @param model |
| * @param manager |
| */ |
| public void clearModelToManager(MToolBar model, ToolBarManager manager) { |
| for (MToolBarElement element : model.getChildren()) { |
| if (element instanceof MToolBar) { |
| clearModelToManager((MToolBar) element, getManager((MToolBar) element)); |
| } |
| IContributionItem ici = getContribution(element); |
| clearModelToContribution(element, ici); |
| } |
| ToolBarManager removed = modelToManager.remove(model); |
| if (manager == null) { |
| managerToModel.remove(removed); |
| } else { |
| managerToModel.remove(manager); |
| } |
| |
| if (Policy.DEBUG_RENDERER) { |
| logger.debug("\nTBMR:clearModelToManager: modelToManager size = {0}, managerToModel size = {1}", //$NON-NLS-1$ |
| modelToManager.size(), managerToModel.size()); |
| } |
| } |
| |
| /** |
| * @param element |
| * @return mapped contribution, if any |
| */ |
| public IContributionItem getContribution(MToolBarElement element) { |
| return modelToContribution.get(element); |
| } |
| |
| /** |
| * @param item |
| * @return mapped toolbar element, if any |
| */ |
| public MToolBarElement getToolElement(IContributionItem item) { |
| return contributionToModel.get(item); |
| } |
| |
| /** |
| * @param model |
| * @param item |
| */ |
| public void linkModelToContribution(MToolBarElement model, IContributionItem item) { |
| modelToContribution.put(model, item); |
| contributionToModel.put(item, model); |
| if (Policy.DEBUG_RENDERER) { |
| logger.debug( |
| "\nTBMR:linkModelToContribution: modelToContribution size = {0}, contributionToModel size = {1}", //$NON-NLS-1$ |
| modelToContribution.size(), contributionToModel.size()); |
| } |
| } |
| |
| /** |
| * @param model |
| * @param item |
| */ |
| public void clearModelToContribution(MToolBarElement model, IContributionItem item) { |
| if (model instanceof MToolBar) { |
| for (MToolBarElement element : ((MToolBar) model).getChildren()) { |
| IContributionItem ici = getContribution(element); |
| clearModelToContribution(element, ici); |
| } |
| } |
| modelToContribution.remove(model); |
| contributionToModel.remove(item); |
| if (Policy.DEBUG_RENDERER) { |
| logger.debug( |
| "\nTBMR:clearModelToContribution: modelToContribution size = {0}, contributionToModel size = {1}", //$NON-NLS-1$ |
| modelToContribution.size(), contributionToModel.size()); |
| } |
| } |
| |
| /** |
| * @param item |
| * @return non null records list |
| */ |
| public ArrayList<ToolBarContributionRecord> getList(MToolBarElement item) { |
| ArrayList<ToolBarContributionRecord> tmp = sharedElementToRecord.get(item); |
| if (tmp == null) { |
| tmp = new ArrayList<>(); |
| sharedElementToRecord.put(item, tmp); |
| } |
| return tmp; |
| } |
| |
| /** |
| * @param element |
| * @param record |
| */ |
| public void linkElementToContributionRecord(MToolBarElement element, ToolBarContributionRecord record) { |
| modelContributionToRecord.put(element, record); |
| } |
| |
| /** |
| * @param element |
| * @return mapped record, if any |
| */ |
| public ToolBarContributionRecord getContributionRecord(MToolBarElement element) { |
| return modelContributionToRecord.get(element); |
| } |
| |
| /** |
| * @param menuManager |
| * @param toolBar |
| */ |
| public void reconcileManagerToModel(IToolBarManager menuManager, MToolBar toolBar) { |
| List<MToolBarElement> newChildren = new ArrayList<>(); |
| |
| IContributionItem[] items = menuManager.getItems(); |
| for (IContributionItem item : items) { |
| MToolBarElement element = getToolElement(item); |
| if (element == null) { |
| element = OpaqueElementUtil.createOpaqueToolItem(); |
| element.setElementId(item.getId()); |
| OpaqueElementUtil.setOpaqueItem(element, item); |
| element.setRenderer(this); |
| linkModelToContribution(element, item); |
| } |
| element.setVisible(item.isVisible()); |
| newChildren.add(element); |
| } |
| |
| ECollections.setEList((EList<MToolBarElement>) toolBar.getChildren(), newChildren); |
| } |
| |
| @Override |
| public void postProcess(MUIElement element) { |
| if (element instanceof MToolBar) { |
| MToolBar toolbarModel = (MToolBar) element; |
| if (toolbarModel.getTransientData().containsKey(POST_PROCESSING_FUNCTION)) { |
| Object obj = toolbarModel.getTransientData().get(POST_PROCESSING_FUNCTION); |
| if (obj instanceof IContextFunction) { |
| IContextFunction func = (IContextFunction) obj; |
| final IEclipseContext ctx = getContext(toolbarModel); |
| toolbarModel.getTransientData().put(POST_PROCESSING_DISPOSE, func.compute(ctx, null)); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public IEclipseContext getContext(MUIElement el) { |
| return super.getContext(el); |
| } |
| |
| /* package */ ToolItemUpdater getUpdater() { |
| return enablementUpdater; |
| } |
| |
| } |