Browse Source

Adds Escalator.scrollToSpacer (#17270)

Change-Id: Ib420e8da6c167fdba9d3023a73cb242643c7af67
tags/7.5.0.beta1
Henrik Paul 9 years ago
parent
commit
754caf060f

+ 119
- 40
client/src/com/vaadin/client/widgets/Escalator.java View File

@@ -827,8 +827,8 @@ public class Escalator extends Widget implements RequiresResize,

boolean verticalScrollNeeded = scrollContentHeight > tableWrapperHeight
+ WidgetUtil.PIXEL_EPSILON
- header.heightOfSection
- footer.heightOfSection;
- header.getHeightOfSection()
- footer.getHeightOfSection();
boolean horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth
+ WidgetUtil.PIXEL_EPSILON;

@@ -837,8 +837,8 @@ public class Escalator extends Widget implements RequiresResize,
if (!verticalScrollNeeded && horizontalScrollNeeded) {
verticalScrollNeeded = scrollContentHeight > tableWrapperHeight
+ WidgetUtil.PIXEL_EPSILON
- header.heightOfSection
- footer.heightOfSection
- header.getHeightOfSection()
- footer.getHeightOfSection()
- horizontalScrollbar.getScrollbarThickness();
} else {
horizontalScrollNeeded = scrollContentWidth > tableWrapperWidth
@@ -860,8 +860,10 @@ public class Escalator extends Widget implements RequiresResize,
tableWrapper.getStyle().setHeight(tableWrapperHeight, Unit.PX);
tableWrapper.getStyle().setWidth(tableWrapperWidth, Unit.PX);

double footerHeight = footer.getHeightOfSection();
double headerHeight = header.getHeightOfSection();
double vScrollbarHeight = Math.max(0, tableWrapperHeight
- footer.heightOfSection - header.heightOfSection);
- footerHeight - headerHeight);
verticalScrollbar.setOffsetSize(vScrollbarHeight);
verticalScrollbar.setScrollSize(scrollContentHeight);

@@ -1158,7 +1160,7 @@ public class Escalator extends Widget implements RequiresResize,

final double viewportStartPx = getScrollTop();
final double viewportEndPx = viewportStartPx
+ body.calculateHeight();
+ body.getHeightOfSection();

final double scrollTop = getScrollPos(destination, targetStartPx,
targetEndPx, viewportStartPx, viewportEndPx, padding);
@@ -1183,9 +1185,6 @@ public class Escalator extends Widget implements RequiresResize,
*/
protected final TableSectionElement root;

/** The height of the combined rows in the DOM. Never negative. */
protected double heightOfSection = 0;

/**
* The primary style name of the escalator. Most commonly provided by
* Escalator as "v-escalator".
@@ -2097,10 +2096,24 @@ public class Escalator extends Widget implements RequiresResize,
refreshCells(rowRange, colRange);
}
}

/**
* The height of this table section.
* <p>
* Note that {@link Escalator#getBody() the body} will calculate its
* height, while the others will return a precomputed value.
*
* @return the height of this table section
*/
protected abstract double getHeightOfSection();
}

private abstract class AbstractStaticRowContainer extends
AbstractRowContainer {

/** The height of the combined rows in the DOM. Never negative. */
private double heightOfSection = 0;

public AbstractStaticRowContainer(final TableSectionElement headElement) {
super(headElement);
}
@@ -2194,7 +2207,8 @@ public class Escalator extends Widget implements RequiresResize,
* indices are calculated from the scrollbar position.
*/
verticalScrollbar.setOffsetSize(heightOfEscalator
- header.heightOfSection - footer.heightOfSection);
- header.getHeightOfSection()
- footer.getHeightOfSection());

body.verifyEscalatorCount();
}
@@ -2246,6 +2260,11 @@ public class Escalator extends Widget implements RequiresResize,
assert root.isOrHasChild(tr) : "Row does not belong to this table section";
return true;
}

@Override
protected double getHeightOfSection() {
return Math.max(0, heightOfSection);
}
}

private class HeaderRowContainer extends AbstractStaticRowContainer {
@@ -2255,10 +2274,10 @@ public class Escalator extends Widget implements RequiresResize,

@Override
protected void sectionHeightCalculated() {
bodyElem.getStyle().setMarginTop(heightOfSection, Unit.PX);
bodyElem.getStyle().setMarginTop(getHeightOfSection(), Unit.PX);
verticalScrollbar.getElement().getStyle()
.setTop(heightOfSection, Unit.PX);
headerDeco.getStyle().setHeight(heightOfSection, Unit.PX);
.setTop(getHeightOfSection(), Unit.PX);
headerDeco.getStyle().setHeight(getHeightOfSection(), Unit.PX);
}

@Override
@@ -2291,8 +2310,10 @@ public class Escalator extends Widget implements RequiresResize,

@Override
protected void sectionHeightCalculated() {
double headerHeight = header.getHeightOfSection();
double footerHeight = footer.getHeightOfSection();
int vscrollHeight = (int) Math.floor(heightOfEscalator
- header.heightOfSection - footer.heightOfSection);
- headerHeight - footerHeight);

final boolean horizontalScrollbarNeeded = columnConfiguration
.calculateRowWidth() > widthOfEscalator;
@@ -2300,7 +2321,8 @@ public class Escalator extends Widget implements RequiresResize,
vscrollHeight -= horizontalScrollbar.getScrollbarThickness();
}

footerDeco.getStyle().setHeight(footer.heightOfSection, Unit.PX);
footerDeco.getStyle().setHeight(footer.getHeightOfSection(),
Unit.PX);

verticalScrollbar.setOffsetSize(vscrollHeight);
}
@@ -2633,7 +2655,7 @@ public class Escalator extends Widget implements RequiresResize,
* getDefaultRowHeight() < getScrollTop();
final boolean addedRowsBelowCurrentViewport = index
* getDefaultRowHeight() > getScrollTop()
+ calculateHeight();
+ getHeightOfSection();

if (addedRowsAboveCurrentViewport) {
/*
@@ -2917,7 +2939,7 @@ public class Escalator extends Widget implements RequiresResize,

private int getMaxEscalatorRowCapacity() {
final int maxEscalatorRowCapacity = (int) Math
.ceil(calculateHeight() / getDefaultRowHeight()) + 1;
.ceil(getHeightOfSection() / getDefaultRowHeight()) + 1;

/*
* maxEscalatorRowCapacity can become negative if the headers and
@@ -3087,7 +3109,7 @@ public class Escalator extends Widget implements RequiresResize,
final double contentBottom = getRowCount()
* getDefaultRowHeight();
final double viewportBottom = tBodyScrollTop
+ calculateHeight();
+ getHeightOfSection();
if (viewportBottom <= contentBottom) {
/*
* We're in the middle of the row container, everything
@@ -3219,7 +3241,7 @@ public class Escalator extends Widget implements RequiresResize,
* 5 5
*/
final double newScrollTop = contentBottom
- calculateHeight();
- getHeightOfSection();
setScrollTop(newScrollTop);
/*
* Manually call the scroll handler, so we get immediate
@@ -3406,15 +3428,14 @@ public class Escalator extends Widget implements RequiresResize,
return "td";
}

/**
* Calculates the height of the {@code <tbody>} as it should be rendered
* in the DOM.
*/
private double calculateHeight() {
@Override
protected double getHeightOfSection() {
final int tableHeight = tableWrapper.getOffsetHeight();
final double footerHeight = footer.heightOfSection;
final double headerHeight = header.heightOfSection;
return tableHeight - footerHeight - headerHeight;
final double footerHeight = footer.getHeightOfSection();
final double headerHeight = header.getHeightOfSection();

double heightOfSection = tableHeight - footerHeight - headerHeight;
return Math.max(0, heightOfSection);
}

@Override
@@ -3862,9 +3883,14 @@ public class Escalator extends Widget implements RequiresResize,
return visualRowOrder.contains(tr);
}

public void reapplySpacerWidths() {
void reapplySpacerWidths() {
spacerContainer.reapplySpacerWidths();
}

void scrollToSpacer(int spacerIndex, ScrollDestination destination,
int padding) {
spacerContainer.scrollToSpacer(spacerIndex, destination, padding);
}
}

private class ColumnConfigurationImpl implements ColumnConfiguration {
@@ -4723,6 +4749,32 @@ public class Escalator extends Widget implements RequiresResize,
}
}

@SuppressWarnings("boxing")
void scrollToSpacer(int spacerIndex, ScrollDestination destination,
int padding) {

assert !destination.equals(ScrollDestination.MIDDLE)
|| padding != 0 : "destination/padding check should be done before this method";

if (!rowIndexToSpacer.containsKey(spacerIndex)) {
throw new IllegalArgumentException("No spacer open at index "
+ spacerIndex);
}

SpacerImpl spacer = rowIndexToSpacer.get(spacerIndex);
double targetStartPx = spacer.getTop();
double targetEndPx = targetStartPx + spacer.getHeight();

Range viewportPixels = getViewportPixels();
double viewportStartPx = viewportPixels.getStart();
double viewportEndPx = viewportPixels.getEnd();

double scrollTop = getScrollPos(destination, targetStartPx,
targetEndPx, viewportStartPx, viewportEndPx, padding);

setScrollTop(scrollTop);
}

public void reapplySpacerWidths() {
for (SpacerImpl spacer : rowIndexToSpacer.values()) {
spacer.getRootElement().getStyle()
@@ -5812,10 +5864,7 @@ public class Escalator extends Widget implements RequiresResize,
public void scrollToColumn(final int columnIndex,
final ScrollDestination destination, final int padding)
throws IndexOutOfBoundsException, IllegalArgumentException {
if (destination == ScrollDestination.MIDDLE && padding != 0) {
throw new IllegalArgumentException(
"You cannot have a padding with a MIDDLE destination");
}
validateScrollDestination(destination, padding);
verifyValidColumnIndex(columnIndex);

if (columnIndex < columnConfiguration.frozenColumns) {
@@ -5856,10 +5905,7 @@ public class Escalator extends Widget implements RequiresResize,
public void scrollToRow(final int rowIndex,
final ScrollDestination destination, final int padding)
throws IndexOutOfBoundsException, IllegalArgumentException {
if (destination == ScrollDestination.MIDDLE && padding != 0) {
throw new IllegalArgumentException(
"You cannot have a padding with a MIDDLE destination");
}
validateScrollDestination(destination, padding);
verifyValidRowIndex(rowIndex);

scroller.scrollToRow(rowIndex, destination, padding);
@@ -5872,6 +5918,39 @@ public class Escalator extends Widget implements RequiresResize,
}
}

/**
* Scrolls the body vertically so that the spacer at the given row index is
* visible and there is at least {@literal padding} pixesl to the given
* scroll destination
*
* @since
* @param spacerIndex
* the row index of the spacer to scroll to
* @param destination
* where the spacer should be aligned visually after scrolling
* @param padding
* the number of pixels to place between the scrolled-to spacer
* and the viewport edge
* @throws IllegalArgumentException
* if {@code spacerIndex} is not an opened spacer if
* {@code destination} is {@link ScrollDestination#MIDDLE} and
* padding is nonzero
*/
public void scrollToSpacer(final int spacerIndex,
ScrollDestination destination, final int padding)
throws IllegalArgumentException {
validateScrollDestination(destination, padding);
body.scrollToSpacer(spacerIndex, destination, padding);
}

private static void validateScrollDestination(
final ScrollDestination destination, final int padding) {
if (destination == ScrollDestination.MIDDLE && padding != 0) {
throw new IllegalArgumentException(
"You cannot have a padding with a MIDDLE destination");
}
}

/**
* Recalculates the dimensions for all elements that require manual
* calculations. Also updates the dimension caches.
@@ -6074,8 +6153,8 @@ public class Escalator extends Widget implements RequiresResize,
return;
}

double headerHeight = header.heightOfSection;
double footerHeight = footer.heightOfSection;
double headerHeight = header.getHeightOfSection();
double footerHeight = footer.getHeightOfSection();
double bodyHeight = body.getDefaultRowHeight() * heightByRows;
double scrollbar = horizontalScrollbar.showsScrollHandle() ? horizontalScrollbar
.getScrollbarThickness() : 0;
@@ -6271,8 +6350,8 @@ public class Escalator extends Widget implements RequiresResize,

private Range getViewportPixels() {
int from = (int) Math.floor(verticalScrollbar.getScrollPos());
int to = (int) Math.ceil(body.heightOfSection);
return Range.between(from, to);
int to = (int) body.getHeightOfSection();
return Range.withLength(from, to);
}

@Override

+ 2
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/EscalatorBasicClientFeaturesTest.java View File

@@ -77,11 +77,13 @@ public abstract class EscalatorBasicClientFeaturesTest extends MultiBrowserTest
protected static final String COLSPAN_NONE = "Apply no colspan";
protected static final String SET_100PX = "Set 100px";
protected static final String SPACERS = "Spacers";
protected static final String SCROLL_HERE_ANY_0PADDING = "Scroll here (ANY, 0)";
protected static final String REMOVE = "Remove";

protected static final String ROW_MINUS1 = "Row -1";
protected static final String ROW_1 = "Row 1";
protected static final String ROW_25 = "Row 25";
protected static final String ROW_50 = "Row 50";
protected static final String ROW_75 = "Row 75";
protected static final String ROW_99 = "Row 99";


+ 37
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/escalator/EscalatorSpacerTest.java View File

@@ -30,6 +30,7 @@ import org.junit.Test;
import org.openqa.selenium.WebElement;

import com.vaadin.client.WidgetUtil;
import com.vaadin.shared.ui.grid.Range;
import com.vaadin.testbench.elements.NotificationElement;
import com.vaadin.tests.components.grid.basicfeatures.EscalatorBasicClientFeaturesTest;

@@ -96,6 +97,7 @@ public class EscalatorSpacerTest extends EscalatorBasicClientFeaturesTest {
@Before
public void before() {
openTestURL();
selectMenuPath(COLUMNS_AND_ROWS, BODY_ROWS, "Set 20px default height");
populate();
}

@@ -299,6 +301,41 @@ public class EscalatorSpacerTest extends EscalatorBasicClientFeaturesTest {
}
}

@Test
public void scrollToSpacerFromAbove() throws Exception {
selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);

// Browsers might vary with a few pixels.
Range allowableScrollRange = Range.between(765, 780);
int scrollTop = (int) getScrollTop();
assertTrue("Scroll position was not " + allowableScrollRange + ", but "
+ scrollTop, allowableScrollRange.contains(scrollTop));
}

@Test
public void scrollToSpacerFromBelow() throws Exception {
selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
scrollVerticallyTo(999999);
selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);

// Browsers might vary with a few pixels.
Range allowableScrollRange = Range.between(1015, 1025);
int scrollTop = (int) getScrollTop();
assertTrue("Scroll position was not " + allowableScrollRange + ", but "
+ scrollTop, allowableScrollRange.contains(scrollTop));
}

@Test
public void scrollToSpacerAlreadyInViewport() throws Exception {
selectMenuPath(FEATURES, SPACERS, ROW_50, SET_100PX);
scrollVerticallyTo(1000);
selectMenuPath(FEATURES, SPACERS, ROW_50, SCROLL_HERE_ANY_0PADDING);

// Browsers might vary with a few pixels.
assertEquals(getScrollTop(), 1000);
}

private static double[] getElementDimensions(WebElement element) {
/*
* we need to parse the style attribute, since using getCssValue gets a

+ 13
- 0
uitest/src/com/vaadin/tests/widgetset/client/grid/EscalatorBasicClientFeaturesWidget.java View File

@@ -585,6 +585,13 @@ public class EscalatorBasicClientFeaturesWidget extends
}
}, scrollToRowMenuPath);
}

addMenuCommand("Set 20px default height", new ScheduledCommand() {
@Override
public void execute() {
escalator.getBody().setDefaultRowHeight(20);
}
}, menupath);
}

private void createRowsMenu(final RowContainer container, String[] menupath) {
@@ -685,6 +692,12 @@ public class EscalatorBasicClientFeaturesWidget extends
escalator.getBody().setSpacer(rowIndex, -1);
}
}, menupath);
addMenuCommand("Scroll here (ANY, 0)", new ScheduledCommand() {
@Override
public void execute() {
escalator.scrollToSpacer(rowIndex, ScrollDestination.ANY, 0);
}
}, menupath);
}

private void insertRows(final RowContainer container, int offset, int number) {

Loading…
Cancel
Save