blob: b6690e967f6ffdff649a8f8dd227d0056802a599 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 BestSolution.at 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:
* Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
*******************************************************************************/
package org.eclipse.fx.ui.workbench.renderers.fx;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
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.fx.ui.panes.GridData;
import org.eclipse.fx.ui.panes.GridData.Alignment;
import org.eclipse.fx.ui.panes.GridLayoutPane;
import org.eclipse.fx.ui.panes.SashPane;
import org.eclipse.fx.ui.workbench.renderers.base.BaseRenderer;
import org.eclipse.fx.ui.workbench.renderers.base.BaseSashRenderer;
import org.eclipse.fx.ui.workbench.renderers.base.widget.WLayoutedWidget;
import org.eclipse.fx.ui.workbench.renderers.base.widget.WSash;
import org.eclipse.fx.ui.workbench.renderers.fx.widget.WLayoutedWidgetImpl;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.SplitPane;
import javafx.scene.control.SplitPane.Divider;
/**
* default renderer for sash
*/
public class DefSashRenderer extends BaseSashRenderer<Node> {
@Override
protected Class<? extends WSash<Node>> getWidgetClass(MPartSashContainer container) {
if (container.getTags().contains(WSash.TAG_FIXED_LAYOUT)) {
return WFixedSashImpl.class;
} else if(Boolean.getBoolean("efxclipse.eclipse.compat.sash")) { //$NON-NLS-1$
System.err.println("======> CUSTOM IMPL");
return WResizableSashImpl_2.class;
} else {
return WResizableSashImpl.class;
}
}
static class WFixedSashImpl extends WLayoutedWidgetImpl<GridLayoutPane, Node, MPartSashContainer> implements WSash<Node> {
private static @NonNull GridData toGridData(Map<String, String> dataMap) {
GridData gd = new GridData();
if (dataMap.containsKey(WSash.FIXED_LAYOUT_WIDTH)) {
gd.widthHintProperty().set(Integer.parseInt(dataMap.get(WSash.FIXED_LAYOUT_WIDTH)));
if (!dataMap.containsKey(WSash.FIXED_LAYOUT_HEIGHT)) {
gd.grabExcessVerticalSpaceProperty().set(true);
gd.verticalAlignmentProperty().set(Alignment.FILL);
}
} else {
gd.horizontalAlignmentProperty().set(Alignment.FILL);
}
if (dataMap.containsKey(WSash.FIXED_LAYOUT_HEIGHT)) {
gd.heightHintProperty().set(Integer.parseInt(dataMap.get(WSash.FIXED_LAYOUT_HEIGHT)));
if (!dataMap.containsKey(WSash.FIXED_LAYOUT_WIDTH)) {
gd.grabExcessHorizontalSpaceProperty().set(true);
gd.horizontalAlignmentProperty().set(Alignment.FILL);
}
} else {
gd.verticalAlignmentProperty().set(Alignment.FILL);
}
if (dataMap.containsKey(WSash.FIXED_LAYOUT_GRAB_HORIZONTAL)) {
gd.grabExcessHorizontalSpaceProperty().set(Boolean.parseBoolean(dataMap.get(WSash.FIXED_LAYOUT_GRAB_HORIZONTAL)));
gd.horizontalAlignmentProperty().set(Alignment.FILL);
}
if (dataMap.containsKey(WSash.FIXED_LAYOUT_GRAB_VERTICAL)) {
gd.grabExcessVerticalSpaceProperty().set(Boolean.parseBoolean(dataMap.get(WSash.FIXED_LAYOUT_GRAB_VERTICAL)));
gd.verticalAlignmentProperty().set(Alignment.FILL);
}
return gd;
}
private final @NonNull MPartSashContainer mPartSashContainer;
@Inject
public WFixedSashImpl(@NonNull @Named(BaseRenderer.CONTEXT_DOM_ELEMENT) MPartSashContainer mPartSashContainer) {
this.mPartSashContainer = mPartSashContainer;
}
@Override
public void addItem(WLayoutedWidget<MPartSashContainerElement> widget) {
Node n = (Node) widget.getStaticLayoutNode();
GridLayoutPane p = getWidget();
MPartSashContainer element = getDomElement();
if ( element != null && element.isHorizontal()) {
p.setNumColumns(p.getNumColumns() + 1);
}
MPartSashContainerElement domElement2 = widget.getDomElement();
if( domElement2 != null ) {
GridData gd = toGridData(domElement2.getPersistedState());
GridLayoutPane.setConstraint(n, gd);
}
p.getChildren().add(n);
}
@Override
public int getItemCount() {
return getWidget().getChildren().size();
}
@Override
public void addItems(List<WLayoutedWidget<MPartSashContainerElement>> list) {
List<Node> nodeList = new ArrayList<Node>();
GridLayoutPane p = getWidget();
for (WLayoutedWidget<MPartSashContainerElement> w : list) {
Node n = (Node) w.getStaticLayoutNode();
MPartSashContainerElement element = w.getDomElement();
if( element != null ) {
GridData gd = toGridData(element.getPersistedState());
GridLayoutPane.setConstraint(n, gd);
}
nodeList.add(n);
}
MPartSashContainer element = getDomElement();
if (element != null && element.isHorizontal()) {
p.setNumColumns(p.getNumColumns() + nodeList.size());
}
p.getChildren().addAll(nodeList);
}
@Override
public void addItems(int index, List<WLayoutedWidget<MPartSashContainerElement>> list) {
List<Node> nodeList = new ArrayList<Node>();
GridLayoutPane p = getWidget();
for (WLayoutedWidget<MPartSashContainerElement> w : list) {
Node n = (Node) w.getStaticLayoutNode();
MPartSashContainerElement element = w.getDomElement();
if( element != null ) {
GridData gd = toGridData(element.getPersistedState());
GridLayoutPane.setConstraint(n, gd);
}
nodeList.add(n);
}
MPartSashContainer element = getDomElement();
if (element != null && element.isHorizontal()) {
p.setNumColumns(p.getNumColumns() + nodeList.size());
}
p.getChildren().addAll(index, nodeList);
}
@Override
public void removeItem(WLayoutedWidget<MPartSashContainerElement> widget) {
Node n = (Node) widget.getStaticLayoutNode();
GridLayoutPane p = getWidget();
MPartSashContainer domElement = getDomElement();
if( domElement != null && domElement.isHorizontal() ) {
p.setNumColumns(p.getNumColumns() - 1);
}
p.getChildren().remove(n);
}
@Override
public GridLayoutPane getWidgetNode() {
return getWidget();
}
@Override
protected GridLayoutPane createWidget() {
GridLayoutPane p = new GridLayoutPane();
p.setMarginWidth(0);
p.setMarginHeight(0);
p.setHorizontalSpacing(0);
p.setVerticalSpacing(0);
p.setNumColumns(this.mPartSashContainer.isHorizontal() ? 0 : 1);
return p;
}
@Override
public void updateLayout() {
// TODO Auto-generated method stub
}
}
static class WResizableSashImpl extends WLayoutedWidgetImpl<SplitPane, SplitPane, MPartSashContainer> implements WSash<Node> {
private List<WLayoutedWidget<MPartSashContainerElement>> items = new ArrayList<WLayoutedWidget<MPartSashContainerElement>>();
ChangeListener<Number> listener = new ChangeListener<Number>() {
boolean queueing;
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (!this.queueing) {
this.queueing = true;
Platform.runLater(new Runnable() {
@SuppressWarnings("unqualified-field-access")
@Override
public void run() {
recalcWeight();
queueing = false;
}
});
}
}
};
@Override
public void updateLayout() {
updateDividers();
}
void recalcWeight() {
@Nullable
MPartSashContainer domElement = getDomElement();
if( domElement != null ) {
BaseRenderer<?, ?> r = (BaseRenderer<?, ?>) domElement.getRenderer();
r.syncUIModifications(domElement, this::doRecalcWeight);
} else {
this.logger.error("The domain object should not be null at this point"); //$NON-NLS-1$
}
}
void doRecalcWeight() {
if (this.state != WidgetState.CREATED) {
return;
}
// FIXME We should not do recalcs when we are in teardown of the
// widget
double prev = 0;
int idx = 0;
// No items nothing to recalculate
if (this.items.isEmpty()) {
return;
}
for (double d : getWidget().getDividerPositions()) {
MPartSashContainerElement element = this.items.get(idx++).getDomElement();
if( element != null ) {
element.setContainerData((d - prev) * 10 + ""); //$NON-NLS-1$
}
prev = d;
}
MPartSashContainerElement element = this.items.get(this.items.size() - 1).getDomElement();
if( element != null ) {
element.setContainerData((1.0 - prev) * 10 + ""); //$NON-NLS-1$
}
}
@Override
protected void bindProperties(final SplitPane widget) {
super.bindProperties(widget);
widget.getDividers().addListener(new ListChangeListener<Divider>() {
@Override
public void onChanged(javafx.collections.ListChangeListener.Change<? extends Divider> c) {
while (c.next()) {
for (Divider d : c.getAddedSubList()) {
d.positionProperty().addListener(WResizableSashImpl.this.listener);
}
for (Divider d : c.getRemoved()) {
d.positionProperty().removeListener(WResizableSashImpl.this.listener);
}
}
}
});
for (Divider d : widget.getDividers()) {
d.positionProperty().addListener(this.listener);
}
}
@Override
protected SplitPane createWidget() {
SplitPane p = new SplitPane();
return p;
}
@Inject
void setOrientation(@Named(UIEvents.GenericTile.HORIZONTAL) boolean horizontal) {
getWidget().setOrientation(horizontal ? Orientation.HORIZONTAL : Orientation.VERTICAL);
}
@Override
public SplitPane getWidgetNode() {
return getWidget();
}
private static void setResizableWithParent(WLayoutedWidget widget) {
MUIElement domElement = widget.getDomElement();
if( domElement != null ) {
System.err.println(domElement);
SplitPane.setResizableWithParent((Node)widget.getStaticLayoutNode(), ! domElement.getTags().contains(WSash.TAG_NO_AUTO_RESIZE));
}
}
@Override
public void addItem(WLayoutedWidget<MPartSashContainerElement> widget) {
SplitPane p = getWidget();
setResizableWithParent(widget);
p.getItems().add((Node) widget.getStaticLayoutNode());
this.items.add(widget);
updateDividers();
}
@Override
public void addItems(int index, List<WLayoutedWidget<MPartSashContainerElement>> list) {
SplitPane p = getWidget();
List<Node> l = new ArrayList<Node>();
for (WLayoutedWidget<MPartSashContainerElement> i : list) {
setResizableWithParent(i);
l.add((Node) i.getStaticLayoutNode());
}
p.getItems().addAll(index, l);
this.items.addAll(index, list);
updateDividers();
}
@Override
public void addItems(List<WLayoutedWidget<MPartSashContainerElement>> list) {
SplitPane p = getWidget();
List<Node> l = new ArrayList<Node>();
for (WLayoutedWidget<MPartSashContainerElement> i : list) {
setResizableWithParent(i);
l.add((Node) i.getStaticLayoutNode());
}
p.getItems().addAll(l);
this.items.addAll(list);
updateDividers();
}
@Override
public void setWidgetState(WidgetState state) {
super.setWidgetState(state);
if (state == WidgetState.CREATED) {
updateDividers();
}
}
@Override
public void removeItem(WLayoutedWidget<MPartSashContainerElement> widget) {
SplitPane p = getWidget();
p.getItems().remove(widget.getStaticLayoutNode());
this.items.remove(widget);
updateDividers();
}
@Override
protected void doCleanup() {
super.doCleanup();
this.items.clear();
}
private void updateDividers() {
if (this.items.size() <= 1) {
return;
}
if (this.state != WidgetState.CREATED) {
return;
}
double total = 0;
for (WLayoutedWidget<MPartSashContainerElement> w : this.items) {
total += w.getWeight();
}
double[] deviders = new double[this.items.size() - 1];
for (int i = 0; i < this.items.size() - 1; i++) {
deviders[i] = (i == 0 ? 0 : deviders[i - 1]) + (this.items.get(i).getWeight() / total);
}
getWidget().setDividerPositions(deviders);
}
@Override
public int getItemCount() {
return getWidget().getItems().size();
}
}
static class WResizableSashImpl_2 extends WLayoutedWidgetImpl<SashPane, Node, MPartSashContainer> implements WSash<Node> {
private List<WLayoutedWidget<?>> items = new ArrayList<>();
@Override
public int getItemCount() {
SashPane p = getWidget();
return p.getItems().size();
}
private static int getWeight(WLayoutedWidget<?> w) {
double v = w.getWeight();
if( v < 1 ) {
return (int)(v * 100);
} else if( w.getDomElement().getContainerData() == null) {
return 200;
} else {
return (int) v;
}
}
@Override
public void addItem(@NonNull WLayoutedWidget<MPartSashContainerElement> widget) {
syncWeights();
SashPane p = getWidget();
int[] w = p.getWeights();
p.getItems().add((Node) widget.getStaticLayoutNode());
int[] wn = new int[w.length+1];
System.arraycopy(w, 0, wn, 0, w.length);
wn[wn.length-1] = getWeight(widget);
p.setWeights(wn);
this.items.add(widget);
}
@Override
public void addItems(@NonNull List<WLayoutedWidget<MPartSashContainerElement>> list) {
syncWeights();
SashPane p = getWidget();
int[] w = p.getWeights();
p.getItems().addAll(list.stream().map( e -> (Node)e.getStaticLayoutNode()).collect(Collectors.toList()));
int[] wn = new int[w.length+list.size()];
System.arraycopy(w, 0, wn, 0, w.length);
for( int i = w.length; i < wn.length; i++ ) {
wn[i] = getWeight(list.get(i-w.length));
}
p.setWeights(wn);
this.items.addAll(list);
}
@Override
public void addItems(int index, @NonNull List<WLayoutedWidget<MPartSashContainerElement>> list) {
syncWeights();
SashPane p = getWidget();
int[] w = p.getWeights();
p.getItems().addAll(index,list.stream().map(e -> (Node)e.getStaticLayoutNode()).collect(Collectors.toList()));
int[] wn = new int[w.length+list.size()];
System.arraycopy(w, 0, wn, 0, index);
for( int i = 0; i < list.size(); i++ ) {
wn[i+index] = getWeight(list.get(i));
}
System.arraycopy(w, index, wn, index+1, w.length-index);
p.setWeights(wn);
this.items.addAll(index, list);
}
@Override
public void removeItem(@NonNull WLayoutedWidget<MPartSashContainerElement> widget) {
syncWeights();
SashPane p = getWidget();
p.getItems().remove(widget.getStaticLayoutNode());
this.items.remove(widget);
}
@Override
public void updateLayout() {
// updateDividers();
}
private void syncWeights() {
int[] weights = getWidget().getWeights();
for( int i = 0; i < weights.length; i++ ) {
MUIElement domElement = this.items.get(i).getDomElement();
if( domElement != null ) {
domElement.setContainerData(weights[i]+""); //$NON-NLS-1$
}
}
}
@Override
public @NonNull Node getWidgetNode() {
return getWidget();
}
@Override
protected @NonNull SashPane createWidget() {
SashPane p = new SashPane();
return p;
}
@Inject
void setOrientation(@Named(UIEvents.GenericTile.HORIZONTAL) boolean horizontal) {
getWidget().setHorizontal(horizontal);
}
}
}