/******************************************************************************* * Copyright (c) 2009, 2015 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 * Tristan Hume - <trishume@gmail.com> - Bug 2369 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654 ******************************************************************************/ package org.eclipse.e4.ui.workbench.renderers.swt; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.eclipse.e4.core.commands.ExpressionContext; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.e4.core.contexts.RunAndTrack; import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer; 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; 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.basic.MTrimElement; import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow; import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; /** * */ public class TrimBarRenderer extends SWTPartRenderer { private MApplication application; private class LayoutJob implements Runnable { public List<MTrimBar> barsToLayout = new ArrayList<>(); @Override public void run() { layoutJob = null; if (barsToLayout.size() == 0) return; for (MTrimBar bar : barsToLayout) { Composite trimCtrl = (Composite) bar.getWidget(); if (trimCtrl != null && !trimCtrl.isDisposed()) trimCtrl.layout(); } } } private LayoutJob layoutJob = null; synchronized private void layoutTrim(MTrimBar trimBar) { Composite comp = (Composite) trimBar.getWidget(); if (comp == null || comp.isDisposed()) return; if (layoutJob == null) { layoutJob = new LayoutJob(); layoutJob.barsToLayout.add(trimBar); comp.getDisplay().asyncExec(layoutJob); } else if (!layoutJob.barsToLayout.contains(trimBar)) { layoutJob.barsToLayout.add(trimBar); } } @Override public void init(IEclipseContext context) { super.init(context); application = context.get(MApplication.class); } @Override public Object createWidget(MUIElement element, Object parent) { if (!(element instanceof MTrimBar) || !(parent instanceof Composite)) return null; Composite parentComp = (Composite) parent; Composite trimComposite = null; final MTrimBar trimModel = (MTrimBar) element; if (parentComp.getLayout() instanceof TrimmedPartLayout) { TrimmedPartLayout tpl = (TrimmedPartLayout) parentComp.getLayout(); switch (trimModel.getSide().getValue()) { case SideValue.TOP_VALUE: trimComposite = tpl.getTrimComposite(parentComp, SWT.TOP); break; case SideValue.BOTTOM_VALUE: trimComposite = tpl.getTrimComposite(parentComp, SWT.BOTTOM); break; case SideValue.LEFT_VALUE: trimComposite = tpl.getTrimComposite(parentComp, SWT.LEFT); break; case SideValue.RIGHT_VALUE: trimComposite = tpl.getTrimComposite(parentComp, SWT.RIGHT); break; default: return null; } trimComposite.addDisposeListener(e -> cleanUp(trimModel)); } else { trimComposite = new Composite(parentComp, SWT.NONE); trimComposite.setLayout(new TrimBarLayout(true)); } return trimComposite; } @Override public void hideChild(MElementContainer<MUIElement> parentElement, MUIElement child) { super.hideChild(parentElement, child); Object downCast = parentElement; layoutTrim((MTrimBar) downCast); } @Override public void processContents(MElementContainer<MUIElement> me) { if (!(((MUIElement) me) instanceof MTrimBar)) return; super.processContents(me); IEclipseContext ctx = getContext(me); ExpressionContext eContext = new ExpressionContext(ctx); MElementContainer<?> trimObj = me; MTrimBar trimModel = (MTrimBar) trimObj; ArrayList<MTrimContribution> toContribute = new ArrayList<>(); ContributionsAnalyzer.gatherTrimContributions(trimModel, application.getTrimContributions(), trimModel.getElementId(), toContribute, eContext); addTrimContributions(trimModel, toContribute, ctx, eContext); } private void addTrimContributions(final MTrimBar trimModel, ArrayList<MTrimContribution> toContribute, IEclipseContext ctx, final ExpressionContext eContext) { HashSet<String> existingToolbarIds = new HashSet<>(); MTrimmedWindow topWin = (MTrimmedWindow) modelService .getTopLevelWindowFor(trimModel); for (MTrimBar bar : topWin.getTrimBars()) { for (MTrimElement item : bar.getChildren()) { String id = item.getElementId(); if (id != null) { existingToolbarIds.add(id); } } } boolean done = toContribute.size() == 0; while (!done) { ArrayList<MTrimContribution> curList = new ArrayList<>( toContribute); int retryCount = toContribute.size(); toContribute.clear(); for (final MTrimContribution contribution : curList) { final ArrayList<MTrimElement> toRemove = new ArrayList<>(); if (!ContributionsAnalyzer.processAddition(trimModel, contribution, toRemove, existingToolbarIds)) { toContribute.add(contribution); } else { if (contribution.getVisibleWhen() != null) { ctx.runAndTrack(new RunAndTrack() { @Override public boolean changed(IEclipseContext context) { if (!trimModel.isToBeRendered() || !trimModel.isVisible() || trimModel.getWidget() == null) { return false; } boolean rc = ContributionsAnalyzer.isVisible( contribution, eContext); for (MTrimElement child : toRemove) { child.setToBeRendered(rc); } return true; } }); } trimModel.getPendingCleanup().addAll(toRemove); } } // 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 element * the trimBar to be cleaned up */ protected void cleanUp(MTrimBar element) { for (MTrimElement child : element.getPendingCleanup()) { element.getChildren().remove(child); } element.getPendingCleanup().clear(); } }