blob: 7048d840283cd554b1dcfe79dd74bf455237d6fa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2016 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
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 441150, 441120
*******************************************************************************/
package org.eclipse.e4.ui.workbench.renderers.swt;
import javax.inject.Inject;
import org.eclipse.core.runtime.Platform;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.ui.di.UIEventTopic;
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.MPartSashContainer;
import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Layout;
import org.osgi.service.event.Event;
/**
* Default SWT renderer responsible for a MPartSashContainer. See
* {@link WorkbenchRendererFactory}
*/
public class SashRenderer extends SWTPartRenderer {
private static final int DEFAULT_WEIGHT = 5000;
private int processedContent = 0;
@SuppressWarnings("unchecked")
@Inject
@Optional
private void subscribeTopicOrientationChanged(@UIEventTopic(UIEvents.GenericTile.TOPIC_HORIZONTAL) Event event) {
// Ensure that this event is for a MPartSashContainer
MUIElement element = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT);
if (element.getRenderer() != SashRenderer.this) {
return;
}
forceLayout((MElementContainer<MUIElement>) element);
}
@Inject
@Optional
private void subscribeTopicSashWeightChanged(@UIEventTopic(UIEvents.UIElement.TOPIC_CONTAINERDATA) Event event) {
// Ensure that this event is for a child of a MPartSashContainer
MUIElement element = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT);
MElementContainer<MUIElement> parent = element.getParent();
if (parent.getRenderer() != SashRenderer.this) {
return;
}
forceLayout(parent);
}
/**
* @param pscModel
*/
protected void forceLayout(MElementContainer<MUIElement> pscModel) {
if (processedContent != 0) {
return;
}
// layout the containing Composite
while (!(pscModel.getWidget() instanceof Composite)) {
pscModel = pscModel.getParent();
}
Composite s = (Composite) pscModel.getWidget();
// FIXME SWT Win requires a synchronous layout call to update the UI
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=558392
// once this is fixed, the requestLayout call should be sufficient
if (Platform.getOS().equals(Platform.OS_WIN32)) {
Layout layout = s.getLayout();
if (layout instanceof SashLayout) {
if (((SashLayout) layout).layoutUpdateInProgress) {
return;
}
}
s.layout(true, true);
} else {
s.requestLayout();
}
}
@Override
public Object createWidget(final MUIElement element, Object parent) {
MUIElement elementParent = element.getParent();
if (elementParent == null && element.getCurSharedRef() != null)
elementParent = element.getCurSharedRef();
if (elementParent != null && elementParent.getRenderer() == this) {
Rectangle newRect = new Rectangle(0, 0, 0, 0);
// If my layout's container gets disposed 'unbind' the sash elements
if (parent instanceof Composite) {
((Composite) parent).addDisposeListener(e -> {
element.setWidget(null);
element.setRenderer(null);
});
}
return newRect;
}
// Check to see if this is a new PSC added 'above' the previous 'root'
// sash
Composite sashComposite = null;
MPartSashContainer psc = (MPartSashContainer) element;
for (MPartSashContainerElement psce : psc.getChildren()) {
if (psce instanceof MPartSashContainer && psce.getWidget() instanceof Composite) {
// 'Adopt' the previous root's layout / composite
sashComposite = (Composite) psce.getWidget();
bindWidget(psce, new Rectangle(0, 0, 0, 0));
sashComposite.setParent((Composite) parent);
}
}
// This is a 'root' sash container, create a composite
if (sashComposite == null) {
sashComposite = new Composite((Composite) parent, SWT.NONE);
}
sashComposite.setLayout(new SashLayout(sashComposite, element));
return sashComposite;
}
@Override
public void childRendered(MElementContainer<MUIElement> parentElement, MUIElement element) {
super.childRendered(parentElement, element);
// Ensure that the element's 'containerInfo' is initialized
ensureLayoutWeight(element);
forceLayout(parentElement);
}
@Override
public void processContents(MElementContainer<MUIElement> container) {
try {
processedContent++;
super.processContents(container);
} finally {
processedContent--;
if (processedContent == 0) {
forceLayout(container);
}
}
}
@Override
public void hideChild(MElementContainer<MUIElement> parentElement, MUIElement child) {
super.hideChild(parentElement, child);
forceLayout(parentElement);
}
@Override
public Object getUIContainer(MUIElement element) {
// OK, find the 'root' of the sash container
MUIElement parentElement = element.getParent();
while (parentElement.getRenderer() == this && !(parentElement.getWidget() instanceof Composite)) {
parentElement = parentElement.getParent();
}
if (parentElement.getWidget() instanceof Composite) {
return parentElement.getWidget();
}
return null;
}
/*
* Container data is used by the SashLayout to determine the size of the control
*/
private static void ensureLayoutWeight(MUIElement element) {
int weight = DEFAULT_WEIGHT;
String info = element.getContainerData();
if (info != null && info.length() > 0) {
try {
int value = Integer.parseInt(info);
weight = value;
} catch (NumberFormatException e) {
// continue to use the default value
}
}
element.setContainerData(Integer.toString(weight));
}
}