/******************************************************************************* * Copyright (c) 2009, 2016 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 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 485848, 485850 *******************************************************************************/ package org.eclipse.e4.ui.workbench.renderers.swt; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer; import org.eclipse.e4.ui.model.application.ui.MUIElement; import org.eclipse.e4.ui.model.application.ui.advanced.MArea; import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; import org.eclipse.e4.ui.workbench.IPresentationEngine; import org.eclipse.e4.ui.workbench.UIEvents; import org.eclipse.e4.ui.workbench.UIEvents.EventTags; import org.eclipse.e4.ui.workbench.UIEvents.UIElement; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; /** * Default SWT renderer responsible for an MArea. See * {@link WorkbenchRendererFactory} */ public class AreaRenderer extends SWTPartRenderer { @Inject private IEventBroker eventBroker; private EventHandler itemUpdater = event -> { // Ensure that this event is for a MArea if (!(event.getProperty(UIEvents.EventTags.ELEMENT) instanceof MArea)) return; MArea areaModel = (MArea) event .getProperty(UIEvents.EventTags.ELEMENT); CTabFolder ctf = (CTabFolder) areaModel.getWidget(); CTabItem areaItem = ctf.getItem(0); // No widget == nothing to update if (areaItem == null) return; String attName = (String) event .getProperty(UIEvents.EventTags.ATTNAME); if (UIEvents.UILabel.LABEL.equals(attName) || UIEvents.UILabel.LOCALIZED_LABEL.equals(attName)) { areaItem.setText(areaModel.getLocalizedLabel()); } else if (UIEvents.UILabel.ICONURI.equals(attName)) { areaItem.setImage(getImage(areaModel)); } else if (UIEvents.UILabel.TOOLTIP.equals(attName) || UIEvents.UILabel.LOCALIZED_TOOLTIP.equals(attName)) { areaItem.setToolTipText(areaModel.getLocalizedTooltip()); } }; private EventHandler widgetListener = new EventHandler() { @Override public void handleEvent(Event event) { final MUIElement changedElement = (MUIElement) event .getProperty(EventTags.ELEMENT); if (!(changedElement instanceof MPartStack)) return; MArea areaModel = findArea(changedElement); if (areaModel != null) synchCTFState(areaModel); } private MArea findArea(MUIElement element) { MUIElement parent = element.getParent(); while (parent != null) { if (parent instanceof MArea) return (MArea) parent; parent = parent.getParent(); } return null; } }; @PostConstruct void init() { eventBroker.subscribe(UIEvents.UILabel.TOPIC_ALL, itemUpdater); eventBroker.subscribe(UIElement.TOPIC_WIDGET, widgetListener); } @PreDestroy void contextDisposed() { eventBroker.unsubscribe(itemUpdater); eventBroker.unsubscribe(widgetListener); } @Override public Object createWidget(final MUIElement element, Object parent) { if (!(element instanceof MArea) || !(parent instanceof Composite)) return null; Composite parentComp = (Composite) parent; Composite areaComp = new Composite(parentComp, SWT.NONE); areaComp.setLayout(new FillLayout()); return areaComp; } private void ensureCTF(MArea areaModel) { if (areaModel.getWidget() instanceof CTabFolder) return; Composite curComp = (Composite) areaModel.getWidget(); Composite parentComp = curComp.getParent(); CTabFolder ctf = new CTabFolder(parentComp, SWT.BORDER | SWT.SINGLE); // don't paint the split editor area tab highlighted, it looks ugly ctf.setHighlightEnabled(false); // Find the stack in the area that used to have the min/max state List<MPartStack> stacks = modelService.findElements(areaModel, null, MPartStack.class, null); MPartStack curStack = null; for (MPartStack stack : stacks) { if (stack.isToBeRendered() && stack.getWidget() instanceof CTabFolder) { CTabFolder stackCTF = (CTabFolder) stack.getWidget(); if (stackCTF.getMinimizeVisible() || stackCTF.getMaximizeVisible()) { curStack = stack; break; } } } // ...and copy over its min/max state if (curStack != null) { CTabFolder curCTF = (CTabFolder) curStack.getWidget(); ctf.setMinimizeVisible(curCTF.getMinimizeVisible()); ctf.setMaximizeVisible(curCTF.getMaximizeVisible()); ctf.setMinimized(curCTF.getMinimized()); ctf.setMaximized(curCTF.getMaximized()); if (!areaModel.getTags().contains(IPresentationEngine.MIN_MAXIMIZEABLE_CHILDREN_AREA_TAG)) { curCTF.setMinimizeVisible(false); curCTF.setMaximizeVisible(false); } } CTabItem cti = new CTabItem(ctf, SWT.NONE); if (areaModel.getLabel() != null) cti.setText(areaModel.getLocalizedLabel()); if (areaModel.getTooltip() != null) cti.setToolTipText(areaModel.getLocalizedTooltip()); if (areaModel.getIconURI() != null) cti.setImage(getImage(areaModel)); curComp.setParent(ctf); cti.setControl(curComp); ctf.setSelection(cti); curComp.setData(AbstractPartRenderer.OWNING_ME, null); bindWidget(areaModel, ctf); ctf.requestLayout(); } private void ensureComposite(MArea areaModel) { if (areaModel.getWidget() instanceof CTabFolder) { CTabFolder ctf = (CTabFolder) areaModel.getWidget(); CTabItem cti = ctf.getItem(0); Composite innerComp = (Composite) cti.getControl(); innerComp.setParent(ctf.getParent()); cti.setControl(null); // OK now copy over the min/max state of the area stack to the // remaining part stack List<MPartStack> stacks = modelService.findElements(areaModel, null, MPartStack.class, null); for (MPartStack stack : stacks) { if (stack.isToBeRendered() && stack.getWidget() instanceof CTabFolder) { CTabFolder stackCTF = (CTabFolder) stack.getWidget(); stackCTF.setMinimizeVisible(ctf.getMinimizeVisible()); stackCTF.setMaximizeVisible(ctf.getMaximizeVisible()); stackCTF.setMinimized(ctf.getMinimized()); stackCTF.setMaximized(ctf.getMaximized()); } } ctf.setData(AbstractPartRenderer.OWNING_ME, null); ctf.dispose(); bindWidget(areaModel, innerComp); innerComp.setVisible(true); innerComp.requestLayout(); } } private void synchCTFState(MArea areaModel) { List<MPartStack> stacks = modelService.findElements(areaModel, null, MPartStack.class, null); int count = 0; for (MPartStack stack : stacks) { if (stack.isToBeRendered()) count++; } // If there's more than one stack visible we use a CTF if (count > 1) ensureCTF(areaModel); else ensureComposite(areaModel); } @Override public Object getUIContainer(MUIElement element) { MUIElement parentElement = element.getParent(); if (!(parentElement instanceof MArea)) return null; MArea areaModel = (MArea) parentElement; synchCTFState(areaModel); if (areaModel.getWidget() instanceof CTabFolder) { CTabFolder ctf = (CTabFolder) areaModel.getWidget(); return ctf.getItem(0).getControl(); } return parentElement.getWidget(); } }