diff options
Diffstat (limited to 'client')
4 files changed, 168 insertions, 93 deletions
diff --git a/client/src/main/java/com/vaadin/client/widget/escalator/ColumnConfiguration.java b/client/src/main/java/com/vaadin/client/widget/escalator/ColumnConfiguration.java index 51e8663749..8488981a76 100644 --- a/client/src/main/java/com/vaadin/client/widget/escalator/ColumnConfiguration.java +++ b/client/src/main/java/com/vaadin/client/widget/escalator/ColumnConfiguration.java @@ -143,7 +143,8 @@ public interface ColumnConfiguration { public double getColumnWidth(int index) throws IllegalArgumentException; /** - * Sets widths for a set of columns. + * Sets widths for a set of columns. Triggers element size recalculation for + * elements that require manual calculations. * * @param indexWidthMap * a map from column index to its respective width to be set. If @@ -160,6 +161,26 @@ public interface ColumnConfiguration { throws IllegalArgumentException; /** + * Sets widths for a set of columns. + * + * @param indexWidthMap + * a map from column index to its respective width to be set. If + * the given width for a column index is negative, the column is + * resized-to-fit. + * @param recalculateElementSizes + * should the element size recalculation be triggered for + * elements that require manual calculation + * @throws IllegalArgumentException + * if {@code indexWidthMap} is {@code null} + * @throws IllegalArgumentException + * if any column index in {@code indexWidthMap} is invalid + * @throws NullPointerException + * If any value in the map is <code>null</code> + */ + public void setColumnWidths(Map<Integer, Double> indexWidthMap, + boolean recalculateElementSizes) throws IllegalArgumentException; + + /** * Returns the actual width of a column. * * @param index diff --git a/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java b/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java index 122c302f36..3a01c267fc 100644 --- a/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java +++ b/client/src/main/java/com/vaadin/client/widget/escalator/ScrollbarBundle.java @@ -354,8 +354,6 @@ public abstract class ScrollbarBundle implements DeferredWorker { private final ScrollEventFirer scrollEventFirer = new ScrollEventFirer(); - private HandlerRegistration scrollSizeTemporaryScrollHandler; - private HandlerRegistration offsetSizeTemporaryScrollHandler; private HandlerRegistration scrollInProgress; private ScrollbarBundle() { @@ -417,27 +415,18 @@ public abstract class ScrollbarBundle implements DeferredWorker { * * @param px * the length of the scrollbar in pixels + * @see #setOffsetSizeAndScrollSize(double, double) */ public final void setOffsetSize(final double px) { - /* - * This needs to be made step-by-step because IE8 flat-out refuses to - * fire a scroll event when the scroll size becomes smaller than the - * offset size. All other browser need to suffer alongside. - */ - boolean newOffsetSizeIsGreaterThanScrollSize = px > getScrollSize(); boolean offsetSizeBecomesGreaterThanScrollSize = showsScrollHandle() && newOffsetSizeIsGreaterThanScrollSize; + if (offsetSizeBecomesGreaterThanScrollSize && getScrollPos() != 0) { - if (offsetSizeTemporaryScrollHandler != null) { - offsetSizeTemporaryScrollHandler.removeHandler(); - } - // must be a field because Java insists. - offsetSizeTemporaryScrollHandler = addScrollHandler( - event -> setOffsetSizeNow(px)); setScrollPos(0); - } else { + setOffsetSizeNow(px); + } else if (px != getOffsetSize()) { setOffsetSizeNow(px); } } @@ -447,9 +436,50 @@ public abstract class ScrollbarBundle implements DeferredWorker { recalculateMaxScrollPos(); forceScrollbar(showsScrollHandle()); fireVisibilityChangeIfNeeded(); - if (offsetSizeTemporaryScrollHandler != null) { - offsetSizeTemporaryScrollHandler.removeHandler(); - offsetSizeTemporaryScrollHandler = null; + } + + /** + * Sets the length of the scrollbar and the amount of pixels the scrollbar + * needs to be able to scroll through. + * + * @param offsetPx + * the length of the scrollbar in pixels + * @param scrollPx + * the number of pixels the scrollbar should be able to scroll + * through + */ + public final void setOffsetSizeAndScrollSize(final double offsetPx, + final double scrollPx) { + + boolean newOffsetSizeIsGreaterThanScrollSize = offsetPx > scrollPx; + boolean offsetSizeBecomesGreaterThanScrollSize = showsScrollHandle() + && newOffsetSizeIsGreaterThanScrollSize; + + boolean needsMoreHandling = false; + if (offsetSizeBecomesGreaterThanScrollSize && getScrollPos() != 0) { + setScrollPos(0); + if (offsetPx != getOffsetSize()) { + internalSetOffsetSize(Math.max(0, offsetPx)); + } + if (scrollPx != getScrollSize()) { + internalSetScrollSize(Math.max(0, scrollPx)); + } + needsMoreHandling = true; + } else { + if (offsetPx != getOffsetSize()) { + internalSetOffsetSize(Math.max(0, offsetPx)); + needsMoreHandling = true; + } + if (scrollPx != getScrollSize()) { + internalSetScrollSize(Math.max(0, scrollPx)); + needsMoreHandling = true; + } + } + + if (needsMoreHandling) { + recalculateMaxScrollPos(); + forceScrollbar(showsScrollHandle()); + fireVisibilityChangeIfNeeded(); } } @@ -626,43 +656,18 @@ public abstract class ScrollbarBundle implements DeferredWorker { * @param px * the number of pixels the scrollbar should be able to scroll * through + * @see #setOffsetSizeAndScrollSize(double, double) */ public final void setScrollSize(final double px) { - /* - * This needs to be made step-by-step because IE8 flat-out refuses to - * fire a scroll event when the scroll size becomes smaller than the - * offset size. All other browser need to suffer alongside. - * - * This really should be changed to not use any temporary scroll - * handlers at all once IE8 support is dropped, like now done only for - * Firefox. - */ - boolean newScrollSizeIsSmallerThanOffsetSize = px <= getOffsetSize(); boolean scrollSizeBecomesSmallerThanOffsetSize = showsScrollHandle() && newScrollSizeIsSmallerThanOffsetSize; + if (scrollSizeBecomesSmallerThanOffsetSize && getScrollPos() != 0) { - /* - * For whatever reason, Firefox loses the scroll event in this case - * and the onscroll handler is never called (happens when reducing - * size from 1000 items to 1 while being scrolled a bit down, see - * #19802). Based on the comment above, only IE8 should really use - * 'delayedSizeSet' - */ - boolean delayedSizeSet = !BrowserInfo.get().isFirefox(); - if (delayedSizeSet) { - if (scrollSizeTemporaryScrollHandler != null) { - scrollSizeTemporaryScrollHandler.removeHandler(); - } - scrollSizeTemporaryScrollHandler = addScrollHandler( - event -> setScrollSizeNow(px)); - } setScrollPos(0); - if (!delayedSizeSet) { - setScrollSizeNow(px); - } - } else { + setScrollSizeNow(px); + } else if (px != getScrollSize()) { setScrollSizeNow(px); } } @@ -672,10 +677,6 @@ public abstract class ScrollbarBundle implements DeferredWorker { recalculateMaxScrollPos(); forceScrollbar(showsScrollHandle()); fireVisibilityChangeIfNeeded(); - if (scrollSizeTemporaryScrollHandler != null) { - scrollSizeTemporaryScrollHandler.removeHandler(); - scrollSizeTemporaryScrollHandler = null; - } } /** @@ -913,8 +914,6 @@ public abstract class ScrollbarBundle implements DeferredWorker { public boolean isWorkPending() { // Need to include scrollEventFirer.isBeingFired as it might use // requestAnimationFrame - which is not automatically checked - return scrollSizeTemporaryScrollHandler != null - || offsetSizeTemporaryScrollHandler != null - || scrollInProgress != null || scrollEventFirer.isBeingFired; + return scrollInProgress != null || scrollEventFirer.isBeingFired; } } diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java index 61dbbf6dd9..a5046ce970 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java +++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java @@ -867,8 +867,8 @@ public class Escalator extends Widget double headerHeight = header.getHeightOfSection(); double vScrollbarHeight = Math.max(0, tableWrapperHeight - footerHeight - headerHeight); - verticalScrollbar.setOffsetSize(vScrollbarHeight); - verticalScrollbar.setScrollSize(scrollContentHeight); + verticalScrollbar.setOffsetSizeAndScrollSize(vScrollbarHeight, + scrollContentHeight); /* * If decreasing the amount of frozen columns, and scrolled to the @@ -884,8 +884,8 @@ public class Escalator extends Widget columnConfiguration.getColumnCount())); double frozenPixels = scrollContentWidth - unfrozenPixels; double hScrollOffsetWidth = tableWrapperWidth - frozenPixels; - horizontalScrollbar.setOffsetSize(hScrollOffsetWidth); - horizontalScrollbar.setScrollSize(unfrozenPixels); + horizontalScrollbar.setOffsetSizeAndScrollSize(hScrollOffsetWidth, + unfrozenPixels); horizontalScrollbar.getElement().getStyle().setLeft(frozenPixels, Unit.PX); horizontalScrollbar.setScrollPos(prevScrollPos); @@ -1524,7 +1524,8 @@ public class Escalator extends Widget Integer col = Integer.valueOf(i); colWidths.put(col, width); } - getColumnConfiguration().setColumnWidths(colWidths); + getColumnConfiguration().setColumnWidths(colWidths, + true); }); } } @@ -2486,7 +2487,7 @@ public class Escalator extends Widget */ verticalScrollbar.setOffsetSize( heightOfEscalator - header.getHeightOfSection() - - footer.getHeightOfSection()); + - footer.getHeightOfSection() + 1); body.verifyEscalatorCount(); body.spacerContainer.updateSpacerDecosVisibility(); @@ -2604,21 +2605,8 @@ public class Escalator extends Widget @Override protected void sectionHeightCalculated() { - double headerHeight = header.getHeightOfSection(); - double footerHeight = footer.getHeightOfSection(); - int vscrollHeight = (int) Math - .floor(heightOfEscalator - headerHeight - footerHeight); - - final boolean horizontalScrollbarNeeded = columnConfiguration - .calculateRowWidth() > widthOfEscalator; - if (horizontalScrollbarNeeded) { - vscrollHeight -= horizontalScrollbar.getScrollbarThickness(); - } - footerDeco.getStyle().setHeight(footer.getHeightOfSection(), Unit.PX); - - verticalScrollbar.setOffsetSize(vscrollHeight); } } @@ -5745,7 +5733,7 @@ public class Escalator extends Widget Integer col = Integer.valueOf(i); colWidths.put(col, width); } - getColumnConfiguration().setColumnWidths(colWidths); + getColumnConfiguration().setColumnWidths(colWidths, true); } // Adjust scrollbar @@ -5839,12 +5827,19 @@ public class Escalator extends Widget public void setColumnWidth(int index, double px) throws IllegalArgumentException { setColumnWidths(Collections.singletonMap(Integer.valueOf(index), - Double.valueOf(px))); + Double.valueOf(px)), true); } @Override public void setColumnWidths(Map<Integer, Double> indexWidthMap) throws IllegalArgumentException { + setColumnWidths(indexWidthMap, true); + } + + @Override + public void setColumnWidths(Map<Integer, Double> indexWidthMap, + boolean recalculateElementSizes) + throws IllegalArgumentException { if (indexWidthMap == null) { throw new IllegalArgumentException("indexWidthMap was null"); @@ -5874,7 +5869,9 @@ public class Escalator extends Widget body.reapplyColumnWidths(); footer.reapplyColumnWidths(); - recalculateElementSizes(); + if (recalculateElementSizes) { + recalculateElementSizes(); + } } finally { Profiler.leave( diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java index a47cc4bfca..d4c93751ea 100755 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -3462,10 +3462,27 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, private boolean columnsAreGuaranteedToBeWiderThanGrid() { double freeSpace = escalator.getInnerWidth(); for (Column<?, ?> column : getVisibleColumns()) { + /* + * Check the width and min width and ensure that no column can + * be expected to be narrower than what the resize handler + * requires, if one is present. + */ if (column.getWidth() >= 0) { - freeSpace -= column.getWidth(); + if (column.isResizable() && resizeHandleWidth > 0) { + freeSpace -= Math.max(resizeHandleWidth, + column.getWidth()); + } else { + freeSpace -= column.getWidth(); + } } else if (column.getMinimumWidth() >= 0) { - freeSpace -= column.getMinimumWidth(); + if (column.isResizable() && resizeHandleWidth > 0) { + freeSpace -= Math.max(resizeHandleWidth, + column.getMinimumWidth()); + } else { + freeSpace -= column.getMinimumWidth(); + } + } else if (column.isResizable() && resizeHandleWidth > 0) { + freeSpace -= resizeHandleWidth; } } return freeSpace < 0; @@ -3482,7 +3499,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, selfWidths.put(index, columns.get(index).getWidth()); } Grid.this.escalator.getColumnConfiguration() - .setColumnWidths(selfWidths); + .setColumnWidths(selfWidths, true); /* * Step 2: Make sure that each column ends up obeying their min/max @@ -3508,7 +3525,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, } } Grid.this.escalator.getColumnConfiguration() - .setColumnWidths(constrainedWidths); + .setColumnWidths(constrainedWidths, true); } private void applyColumnWidthsWithExpansion() { @@ -3530,15 +3547,21 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, for (Column<?, T> column : visibleColumns) { final double widthAsIs = column.getWidth(); final boolean isFixedWidth = widthAsIs >= 0; - // Check for max width just to be sure we don't break the limits - final double widthFixed = Math.max( - Math.min(getMaxWidth(column), widthAsIs), - column.getMinimumWidth()); defaultExpandRatios = defaultExpandRatios && (column.getExpandRatio() == -1 || column == selectionColumn); if (isFixedWidth) { + // Check for min & max width just to be sure we don't break + // the limits + double widthFixed = Math.max( + Math.min(getMaxWidth(column), widthAsIs), + column.getMinimumWidth()); + if (column.isResizable() && resizeHandleWidth > 0) { + // Ensure the resize handle fits + widthFixed = Math.max(widthFixed, resizeHandleWidth); + } + columnSizes.put(visibleColumns.indexOf(column), widthFixed); reservedPixels += widthFixed; } else { @@ -3547,7 +3570,13 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, } } - setColumnSizes(columnSizes); + /* + * Set column sizes so that it's possible to measure non-fixed + * actual sizes without previously applied expand ratio tweaks, but + * don't trigger the element size recalculation before the rest of + * this method has also been processed. + */ + setColumnSizes(columnSizes, false); for (Column<?, T> column : nonFixedColumns) { final int expandRatio = defaultExpandRatios ? 1 @@ -3555,9 +3584,21 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, final double maxWidth = getMaxWidth(column); double newWidth; if (column.isMinimumWidthFromContent()) { - newWidth = Math.min(maxWidth, column.getWidthActual()); + if (column.isResizable() && resizeHandleWidth > 0) { + // Ensure the resize handle fits + newWidth = Math.max( + Math.min(maxWidth, column.getWidthActual()), + resizeHandleWidth); + } else { + newWidth = Math.min(maxWidth, column.getWidthActual()); + } } else { - newWidth = 0; + if (column.isResizable() && resizeHandleWidth > 0) { + // Ensure the resize handle fits + newWidth = resizeHandleWidth; + } else { + newWidth = 0; + } } boolean shouldExpand = newWidth < maxWidth && expandRatio > 0 @@ -3580,8 +3621,15 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, if (pixelsToDistribute <= 0 || totalRatios <= 0) { if (pixelsToDistribute <= 0) { // Set column sizes for expanding columns - setColumnSizes(columnSizes); + setColumnSizes(columnSizes, true); } + /* + * If pixelsToDistribute > 0 the element size recalculation + * isn't done at all, even if some column sizes were set + * earlier, but this doesn't appear to be detrimental while + * attempting to trigger the recalculation here breaks a + * GridEditRow test. + */ return; } @@ -3617,7 +3665,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, } while (aColumnHasMaxedOut); if (totalRatios <= 0 && columnsToExpand.isEmpty()) { - setColumnSizes(columnSizes); + setColumnSizes(columnSizes, true); return; } assert pixelsToDistribute > 0 : "We've run out of pixels to distribute (" @@ -3722,12 +3770,14 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, } while (minWidthsCausedReflows); // Finally set all the column sizes. - setColumnSizes(columnSizes); + setColumnSizes(columnSizes, true); } - private void setColumnSizes(Map<Integer, Double> columnSizes) { + private void setColumnSizes(Map<Integer, Double> columnSizes, + boolean recalculateElementSizes) { // Set all widths at once - escalator.getColumnConfiguration().setColumnWidths(columnSizes); + escalator.getColumnConfiguration().setColumnWidths(columnSizes, + recalculateElementSizes); } private int getExpandRatio(Column<?, ?> column, @@ -4389,6 +4439,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, private boolean refreshBodyRequested = false; + private double resizeHandleWidth = 0; + private DragAndDropHandler.DragAndDropCallback headerCellDndCallback = new DragAndDropCallback() { private final AutoScrollerCallback autoScrollerCallback = new AutoScrollerCallback() { @@ -6056,6 +6108,12 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, final DragHandle dragger = new DragHandle( getStylePrimaryName() + "-column-resize-handle"); dragger.addTo(td); + // Save the newest resize handle's width with the assumption + // that all the resize handles are the same size. This is + // used in column's minimum width calculations, so the + // border of the cell is also included. + resizeHandleWidth = dragger.getElement().getOffsetWidth() + + WidgetUtil.getBorderLeftAndRightThickness(td); // Common functionality for drag handle callback // implementations |