From bc78b47d1df883e71aa99082c52502efe4f48a3a Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Fri, 28 Aug 2015 21:47:26 +0300 Subject: Force FormLayout children to shrink with the layout (#11154) The used by the FormLayout doesn't reduce its size if any child component has locked its own size (which is the case with e.g. Table and some other components doing explicit pixel calculations). To work around this, we need to detect the situation, force the
to reduce its width by temporarily assigning explicit widths to the cells and then remove the forced size after all children have adjusted. Change-Id: Iacef62979acf24c869a5cbeb82efb0c1e537ec95 --- client/src/com/vaadin/client/ui/VFormLayout.java | 2 +- .../client/ui/formlayout/FormLayoutConnector.java | 145 ++++++++++++++++++++- 2 files changed, 145 insertions(+), 2 deletions(-) (limited to 'client/src') diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java index bcbb3ebf7b..3719688f2b 100644 --- a/client/src/com/vaadin/client/ui/VFormLayout.java +++ b/client/src/com/vaadin/client/ui/VFormLayout.java @@ -86,7 +86,7 @@ public class VFormLayout extends SimplePanel { private static final int COLUMN_CAPTION = 0; private static final int COLUMN_ERRORFLAG = 1; - private static final int COLUMN_WIDGET = 2; + public static final int COLUMN_WIDGET = 2; private HashMap widgetToCaption = new HashMap(); private HashMap widgetToError = new HashMap(); diff --git a/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java b/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java index bab4153649..3f0b4345c4 100644 --- a/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java @@ -15,26 +15,124 @@ */ package com.vaadin.client.ui.formlayout; +import java.util.HashMap; +import java.util.Map; + import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; +import com.vaadin.client.LayoutManager; import com.vaadin.client.TooltipInfo; import com.vaadin.client.WidgetUtil; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractLayoutConnector; +import com.vaadin.client.ui.PostLayoutListener; import com.vaadin.client.ui.VFormLayout; import com.vaadin.client.ui.VFormLayout.Caption; import com.vaadin.client.ui.VFormLayout.ErrorFlag; import com.vaadin.client.ui.VFormLayout.VFormLayoutTable; +import com.vaadin.client.ui.layout.ElementResizeEvent; +import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.MarginInfo; import com.vaadin.shared.ui.orderedlayout.FormLayoutState; import com.vaadin.ui.FormLayout; @Connect(FormLayout.class) -public class FormLayoutConnector extends AbstractLayoutConnector { +public class FormLayoutConnector extends AbstractLayoutConnector implements + PostLayoutListener { + + private Map oldMaxWidths = null; + + private static final ElementResizeListener dummyFirstCellResizeListener = new ElementResizeListener() { + @Override + public void onElementResize(ElementResizeEvent e) { + // Ignore event, listener added just to make measurements available + } + }; + + // Detects situations when there's something inside the FormLayout that + // prevents it from shrinking + private ElementResizeListener resizeListener = new ElementResizeListener() { + @Override + public void onElementResize(ElementResizeEvent e) { + LayoutManager layoutManager = getLayoutManager(); + double tableWidth = layoutManager + .getOuterWidthDouble(getWidget().table.getElement()); + double ownWidth = layoutManager.getInnerWidthDouble(getWidget() + .getElement()); + if (ownWidth < tableWidth) { + // Something inside the table prevents it from shrinking, + // temporarily force column widths + double excessWidth = tableWidth - ownWidth; + + // All td elements in the component column have the same width, + // so we only need to check the width of the first one to know + // how wide the column is. + Element firstComponentTd = findFirstComponentTd(); + if (firstComponentTd == null) { + // Can't do anything if there are no rows + return; + } + + double componentColWidth = layoutManager + .getOuterWidthDouble(firstComponentTd); + + if (componentColWidth == -1) { + // Didn't get a proper width reading, best to not touch + // anything + return; + } + + // Restrict content td width + // Round down to prevent interactions with fractional sizes of + // other columns + int targetWidth = (int) Math.floor(componentColWidth + - excessWidth); + + // Target might be negative if captions are wider than the total + // available width + targetWidth = Math.max(0, targetWidth); + + if (oldMaxWidths == null) { + oldMaxWidths = new HashMap(); + } + + for (ComponentConnector child : getChildComponents()) { + Element childElement = child.getWidget().getElement(); + if (!oldMaxWidths.containsKey(child)) { + oldMaxWidths.put(child, + childElement.getPropertyString("maxWidth")); + } + childElement.getStyle().setPropertyPx("maxWidth", + targetWidth); + layoutManager.reportOuterWidth(child, targetWidth); + } + } + } + }; + + @Override + protected void init() { + super.init(); + getLayoutManager().addElementResizeListener( + getWidget().table.getElement(), resizeListener); + getLayoutManager().addElementResizeListener(getWidget().getElement(), + resizeListener); + addComponentCellListener(); + } + + @Override + public void onUnregister() { + getLayoutManager().removeElementResizeListener( + getWidget().table.getElement(), resizeListener); + getLayoutManager().removeElementResizeListener( + getWidget().getElement(), resizeListener); + removeComponentCellListener(); + super.onUnregister(); + } @Override public FormLayoutState getState() { @@ -57,6 +155,8 @@ public class FormLayoutConnector extends AbstractLayoutConnector { VFormLayout formLayout = getWidget(); VFormLayoutTable formLayoutTable = getWidget().table; + removeComponentCellListener(); + int childId = 0; formLayoutTable.setRowCount(getChildComponents().size()); @@ -87,6 +187,33 @@ public class FormLayoutConnector extends AbstractLayoutConnector { formLayoutTable.cleanReferences(oldChild.getWidget()); } + addComponentCellListener(); + } + + private void addComponentCellListener() { + Element td = findFirstComponentTd(); + if (td != null) { + getLayoutManager().addElementResizeListener(td, + dummyFirstCellResizeListener); + } + } + + private void removeComponentCellListener() { + Element td = findFirstComponentTd(); + if (td != null) { + getLayoutManager().removeElementResizeListener(td, + dummyFirstCellResizeListener); + } + } + + private Element findFirstComponentTd() { + VFormLayoutTable table = getWidget().table; + if (table.getRowCount() == 0) { + return null; + } else { + return table.getCellFormatter().getElement(0, + VFormLayoutTable.COLUMN_WIDGET); + } } @Override @@ -148,4 +275,20 @@ public class FormLayoutConnector extends AbstractLayoutConnector { return true; } + @Override + public void postLayout() { + if (oldMaxWidths != null) { + for (ComponentConnector child : getChildComponents()) { + Element childNode = child.getWidget().getElement(); + String oldValue = oldMaxWidths.get(child); + if (oldValue == null) { + childNode.getStyle().clearProperty("maxWidth"); + } else { + childNode.getStyle().setProperty("maxWidth", oldValue); + } + } + oldMaxWidths = null; + } + } + } -- cgit v1.2.3