Delayed size changes caused by added or removed scrollbars should be taken into account.tags/8.12.0.alpha1
getLayoutManager().layoutNow(); | getLayoutManager().layoutNow(); | ||||
}); | }); | ||||
// Handling Escalator size changes | |||||
grid.getEscalator().addEscalatorSizeChangeHandler(event -> { | |||||
getLayoutManager().setNeedsMeasure(GridConnector.this); | |||||
if (!getConnection().getMessageHandler().isUpdatingState() | |||||
&& !getLayoutManager().isLayoutRunning()) { | |||||
getLayoutManager().layoutNow(); | |||||
} | |||||
}); | |||||
/* Item click events */ | /* Item click events */ | ||||
grid.addBodyClickHandler(itemClickHandler); | grid.addBodyClickHandler(itemClickHandler); | ||||
grid.addBodyDoubleClickHandler(itemClickHandler); | grid.addBodyDoubleClickHandler(itemClickHandler); |
/* | |||||
* Copyright 2000-2018 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.client.widget.grid.events; | |||||
import com.google.gwt.event.shared.EventHandler; | |||||
import com.google.gwt.event.shared.GwtEvent; | |||||
/** | |||||
* FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME! | |||||
* <p> | |||||
* Event handler that gets notified when the size of the Escalator changes. | |||||
* | |||||
* @author Vaadin Ltd | |||||
*/ | |||||
public interface EscalatorSizeChangeHandler extends EventHandler { | |||||
/** | |||||
* FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME! | |||||
* <p> | |||||
* Called when the size of the Escalator changes. | |||||
* | |||||
* @param event | |||||
* the row visibility change event describing the change | |||||
*/ | |||||
void onEscalatorSizeChange(EscalatorSizeChangeEvent event); | |||||
/** | |||||
* FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME! | |||||
* <p> | |||||
* Event fired when the Escalator size changes. | |||||
* | |||||
* @author Vaadin Ltd | |||||
*/ | |||||
public class EscalatorSizeChangeEvent | |||||
extends GwtEvent<EscalatorSizeChangeHandler> { | |||||
/** | |||||
* FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME! | |||||
* <p> | |||||
* The type of this event. | |||||
*/ | |||||
public static final Type<EscalatorSizeChangeHandler> TYPE = new Type<>(); | |||||
/** | |||||
* FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME! | |||||
* <p> | |||||
* Creates a new Escalator size change event. | |||||
* | |||||
*/ | |||||
public EscalatorSizeChangeEvent() { | |||||
// NOP | |||||
} | |||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see com.google.gwt.event.shared.GwtEvent#getAssociatedType() | |||||
*/ | |||||
@Override | |||||
public Type<EscalatorSizeChangeHandler> getAssociatedType() { | |||||
return TYPE; | |||||
} | |||||
/* | |||||
* (non-Javadoc) | |||||
* | |||||
* @see | |||||
* com.google.gwt.event.shared.GwtEvent#dispatch(com.google.gwt.event. | |||||
* shared .EventHandler) | |||||
*/ | |||||
@Override | |||||
protected void dispatch(EscalatorSizeChangeHandler handler) { | |||||
handler.onEscalatorSizeChange(this); | |||||
} | |||||
} | |||||
} |
import com.vaadin.client.widget.escalator.events.RowHeightChangedEvent; | import com.vaadin.client.widget.escalator.events.RowHeightChangedEvent; | ||||
import com.vaadin.client.widget.escalator.events.SpacerIndexChangedEvent; | import com.vaadin.client.widget.escalator.events.SpacerIndexChangedEvent; | ||||
import com.vaadin.client.widget.escalator.events.SpacerVisibilityChangedEvent; | import com.vaadin.client.widget.escalator.events.SpacerVisibilityChangedEvent; | ||||
import com.vaadin.client.widget.grid.events.EscalatorSizeChangeHandler; | |||||
import com.vaadin.client.widget.grid.events.EscalatorSizeChangeHandler.EscalatorSizeChangeEvent; | |||||
import com.vaadin.client.widget.grid.events.ScrollEvent; | import com.vaadin.client.widget.grid.events.ScrollEvent; | ||||
import com.vaadin.client.widget.grid.events.ScrollHandler; | import com.vaadin.client.widget.grid.events.ScrollHandler; | ||||
import com.vaadin.client.widgets.Escalator.JsniUtil.TouchHandlerBundle; | import com.vaadin.client.widgets.Escalator.JsniUtil.TouchHandlerBundle; | ||||
@Override | @Override | ||||
public void setWidth(final String width) { | public void setWidth(final String width) { | ||||
String oldWidth = getElement().getStyle().getProperty("width"); | |||||
if (width != null && !width.isEmpty()) { | if (width != null && !width.isEmpty()) { | ||||
super.setWidth(width); | super.setWidth(width); | ||||
if (!width.equals(oldWidth)) { | |||||
fireEscalatorSizeChangeEvent(); | |||||
} | |||||
} else { | } else { | ||||
super.setWidth(DEFAULT_WIDTH); | super.setWidth(DEFAULT_WIDTH); | ||||
if (!DEFAULT_WIDTH.equals(oldWidth)) { | |||||
fireEscalatorSizeChangeEvent(); | |||||
} | |||||
} | } | ||||
recalculateElementSizes(); | recalculateElementSizes(); | ||||
final int escalatorRowsBefore = body.visualRowOrder.size(); | final int escalatorRowsBefore = body.visualRowOrder.size(); | ||||
if (height != null && !height.isEmpty()) { | if (height != null && !height.isEmpty()) { | ||||
String oldHeight = getElement().getStyle().getProperty("height"); | |||||
super.setHeight(height); | super.setHeight(height); | ||||
if (!height.equals(oldHeight)) { | |||||
fireEscalatorSizeChangeEvent(); | |||||
} | |||||
} else { | } else { | ||||
if (getHeightMode() == HeightMode.UNDEFINED) { | if (getHeightMode() == HeightMode.UNDEFINED) { | ||||
int newHeightByRows = body.getRowCount(); | int newHeightByRows = body.getRowCount(); | ||||
} | } | ||||
return; | return; | ||||
} else { | } else { | ||||
String oldHeight = getElement().getStyle() | |||||
.getProperty("height"); | |||||
super.setHeight(DEFAULT_HEIGHT); | super.setHeight(DEFAULT_HEIGHT); | ||||
if (!DEFAULT_HEIGHT.equals(oldHeight)) { | |||||
fireEscalatorSizeChangeEvent(); | |||||
} | |||||
} | } | ||||
} | } | ||||
return array; | return array; | ||||
} | } | ||||
/** | |||||
* FOR INTERNAL USE ONLY, MAY GET REMOVED OR MODIFIED AT ANY TIME! | |||||
* <p> | |||||
* Adds an event handler that gets notified when the Escalator size changes. | |||||
* | |||||
* @param escalatorSizeChangeHandler | |||||
* the event handler | |||||
* @return a handler registration for the added handler | |||||
*/ | |||||
public HandlerRegistration addEscalatorSizeChangeHandler( | |||||
EscalatorSizeChangeHandler escalatorSizeChangeHandler) { | |||||
return addHandler(escalatorSizeChangeHandler, | |||||
EscalatorSizeChangeEvent.TYPE); | |||||
} | |||||
private void fireEscalatorSizeChangeEvent() { | |||||
fireEvent(new EscalatorSizeChangeEvent()); | |||||
} | |||||
/** | /** | ||||
* Adds an event handler that gets notified when the range of visible rows | * Adds an event handler that gets notified when the range of visible rows | ||||
* changes e.g. because of scrolling, row resizing or spacers | * changes e.g. because of scrolling, row resizing or spacers |
package com.vaadin.tests.components.grid; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import com.vaadin.annotations.Widgetset; | |||||
import com.vaadin.data.provider.DataProvider; | |||||
import com.vaadin.data.provider.ListDataProvider; | |||||
import com.vaadin.server.VaadinRequest; | |||||
import com.vaadin.shared.ui.grid.HeightMode; | |||||
import com.vaadin.tests.components.AbstractReindeerTestUI; | |||||
import com.vaadin.ui.Alignment; | |||||
import com.vaadin.ui.Button; | |||||
import com.vaadin.ui.Grid; | |||||
import com.vaadin.ui.GridLayout; | |||||
import com.vaadin.ui.TabSheet; | |||||
import com.vaadin.ui.VerticalLayout; | |||||
@Widgetset("com.vaadin.DefaultWidgetSet") | |||||
public class GridSizeChange extends AbstractReindeerTestUI { | |||||
private Grid<Integer> grid; | |||||
private List<Integer> data; | |||||
private ListDataProvider<Integer> dataProvider; | |||||
private int counter = 0; | |||||
@Override | |||||
protected void setup(VaadinRequest request) { | |||||
grid = new Grid<>(); | |||||
data = new ArrayList<>(); | |||||
for (int i = 0; i < 10; ++i) { | |||||
data.add(i); | |||||
++counter; | |||||
} | |||||
dataProvider = DataProvider.ofCollection(data); | |||||
grid.setDataProvider(dataProvider); | |||||
// create column and fill rows | |||||
grid.addColumn(item -> "row_" + item).setCaption("Item"); | |||||
// set height mode and height | |||||
grid.setHeightMode(HeightMode.ROW); | |||||
grid.setHeightByRows(10); | |||||
grid.setWidth(90, Unit.PIXELS); | |||||
// create a tabsheet with one tab and place grid inside | |||||
VerticalLayout tab = new VerticalLayout(); | |||||
tab.setSpacing(false); | |||||
tab.setMargin(false); | |||||
TabSheet tabSheet = new TabSheet(); | |||||
tabSheet.setWidthUndefined(); | |||||
tabSheet.addTab(tab, "Tab"); | |||||
tab.addComponent(grid); | |||||
GridLayout layout = new GridLayout(3, 2); | |||||
layout.setDefaultComponentAlignment(Alignment.TOP_CENTER); | |||||
layout.addComponent(new Button("Reduce height", e -> { | |||||
double newHeight = grid.getHeightByRows() - 1; | |||||
grid.setHeightByRows(newHeight); | |||||
})); | |||||
layout.addComponent(new Button("Remove row", e -> { | |||||
removeRow(); | |||||
dataProvider.refreshAll(); | |||||
})); | |||||
layout.addComponent(new Button("Reduce width", e -> { | |||||
grid.setWidth(grid.getWidth() - 30, Unit.PIXELS); | |||||
})); | |||||
layout.addComponent(new Button("Increase height", e -> { | |||||
double newHeight = grid.getHeightByRows() + 1; | |||||
grid.setHeightByRows(newHeight); | |||||
})); | |||||
layout.addComponent(new Button("Add row", e -> { | |||||
addRow(); | |||||
dataProvider.refreshAll(); | |||||
})); | |||||
layout.addComponent(new Button("Increase width", e -> { | |||||
grid.setWidth(grid.getWidth() + 30, Unit.PIXELS); | |||||
})); | |||||
addComponent(tabSheet); | |||||
addComponent(layout); | |||||
getLayout().setSpacing(true); | |||||
} | |||||
private void removeRow() { | |||||
data.remove(0); | |||||
dataProvider.refreshAll(); | |||||
} | |||||
private void addRow() { | |||||
++counter; | |||||
data.add(counter); | |||||
dataProvider.refreshAll(); | |||||
} | |||||
@Override | |||||
protected String getTestDescription() { | |||||
return "Changing Grid size should resize the TabSheet accordingly " | |||||
+ "even if scrollbar(s) appear or disappear."; | |||||
} | |||||
} |
package com.vaadin.tests.components.grid; | |||||
import static org.hamcrest.MatcherAssert.assertThat; | |||||
import static org.hamcrest.number.IsCloseTo.closeTo; | |||||
import static org.junit.Assert.assertEquals; | |||||
import org.junit.Test; | |||||
import org.openqa.selenium.WebElement; | |||||
import com.vaadin.testbench.By; | |||||
import com.vaadin.testbench.elements.ButtonElement; | |||||
import com.vaadin.testbench.elements.GridElement; | |||||
import com.vaadin.testbench.elements.TabSheetElement; | |||||
import com.vaadin.tests.tb3.MultiBrowserTest; | |||||
public class GridSizeChangeTest extends MultiBrowserTest { | |||||
private TabSheetElement tabSheet; | |||||
private GridElement grid; | |||||
private WebElement vScrollbar; | |||||
private WebElement hScrollbar; | |||||
@Test | |||||
public void scrollbarsTakenIntoAccountInSizeChanges() { | |||||
openTestURL(); | |||||
tabSheet = $(TabSheetElement.class).first(); | |||||
grid = $(GridElement.class).first(); | |||||
vScrollbar = grid.findElement(By.className("v-grid-scroller-vertical")); | |||||
hScrollbar = grid | |||||
.findElement(By.className("v-grid-scroller-horizontal")); | |||||
// ensure no initial scrollbars | |||||
ensureVerticalScrollbar(false); | |||||
ensureHorizontalScrollbar(false); | |||||
assertGridWithinTabSheet(); | |||||
$(ButtonElement.class).caption("Reduce height").first().click(); | |||||
// more rows than height -> scrollbar | |||||
assertGridWithinTabSheet(); | |||||
ensureVerticalScrollbar(true); | |||||
$(ButtonElement.class).caption("Remove row").first().click(); | |||||
// height matches rows -> no scrollbar | |||||
assertGridWithinTabSheet(); | |||||
ensureVerticalScrollbar(false); | |||||
$(ButtonElement.class).caption("Reduce width").first().click(); | |||||
// column too wide -> scrollbar | |||||
assertGridWithinTabSheet(); | |||||
ensureHorizontalScrollbar(true); | |||||
$(ButtonElement.class).caption("Increase width").first().click(); | |||||
// column fits -> no scrollbar | |||||
assertGridWithinTabSheet(); | |||||
ensureHorizontalScrollbar(false); | |||||
$(ButtonElement.class).caption("Add row").first().click(); | |||||
// more rows than height -> scrollbar | |||||
assertGridWithinTabSheet(); | |||||
ensureVerticalScrollbar(true); | |||||
$(ButtonElement.class).caption("Increase height").first().click(); | |||||
// height matches rows -> no scrollbar | |||||
assertGridWithinTabSheet(); | |||||
ensureVerticalScrollbar(false); | |||||
} | |||||
private void ensureVerticalScrollbar(boolean displayed) { | |||||
assertEquals(displayed ? "block" : "none", | |||||
vScrollbar.getCssValue("display")); | |||||
} | |||||
private void ensureHorizontalScrollbar(boolean displayed) { | |||||
assertEquals(displayed ? "block" : "none", | |||||
hScrollbar.getCssValue("display")); | |||||
} | |||||
private void assertGridWithinTabSheet() throws AssertionError { | |||||
// allow two pixel leeway | |||||
assertThat( | |||||
"Grid and TabSheet should always have the same bottom position, " | |||||
+ "not be offset by a scrollbar's thickness", | |||||
(double) grid.getLocation().getY() + grid.getSize().getHeight(), | |||||
closeTo(tabSheet.getLocation().getY() | |||||
+ tabSheet.getSize().getHeight(), 2)); | |||||
} | |||||
} |