return;
}
- int oldTopRowLogicalIndex = getTopRowLogicalIndex();
int oldVisualRangeLength = visualRowOrder.size();
final int maxVisibleRowCount = getMaxVisibleRowCount();
if (rowDiff > 0) {
// more rows are needed
+ handleAddingRequiredRows(rowDiff);
+ } else if (rowDiff < 0) {
+ // rows need to be removed
+ handleRemovingExcessRows(rowDiff);
+ }
- // calculate the indexes for adding rows below the last row of
- // the visual range
- final int visualTargetIndex = oldVisualRangeLength;
- final int logicalTargetIndex;
- if (!visualRowOrder.isEmpty()) {
- logicalTargetIndex = oldTopRowLogicalIndex
- + visualTargetIndex;
- } else {
- logicalTargetIndex = 0;
- }
-
- // prioritise adding to the bottom so that there's less chance
- // for a gap if a details row is later closed (e.g. by user)
- final int addToBottom = Math.min(rowDiff,
- getRowCount() - logicalTargetIndex);
- final int addToTop = Math.max(rowDiff - addToBottom, 0);
+ Profiler.leave("Escalator.BodyRowContainer.verifyEscalatorCount");
+ }
- if (addToTop > 0) {
- fillAndPopulateEscalatorRowsIfNeeded(0,
- oldTopRowLogicalIndex - addToTop, addToTop);
+ private void handleAddingRequiredRows(final int rowDiff) {
+ int oldTopRowLogicalIndex = getTopRowLogicalIndex();
- updateTopRowLogicalIndex(-addToTop);
- }
- if (addToBottom > 0) {
- // take into account that rows may have got added to top as
- // well, affects visual but not logical indexing
- fillAndPopulateEscalatorRowsIfNeeded(
- visualTargetIndex + addToTop, logicalTargetIndex,
- addToBottom);
-
- // adding new rows due to resizing may have created a gap in
- // the middle, check whether the existing rows need moving
- double rowTop = getRowTop(oldTopRowLogicalIndex);
- if (rowTop > getRowTop(visualRowOrder.get(addToTop))) {
- for (int i = addToTop; i < visualTargetIndex; i++) {
-
- final TableRowElement tr = visualRowOrder.get(i);
-
- setRowPosition(tr, 0, rowTop);
- rowTop += getDefaultRowHeight();
- SpacerContainer.SpacerImpl spacer = spacerContainer
- .getSpacer(oldTopRowLogicalIndex + i);
- if (spacer != null) {
- spacer.setPosition(0, rowTop);
- rowTop += spacer.getHeight();
- }
+ // calculate the indexes for adding rows below the last row of
+ // the visual range
+ final int visualTargetIndex = visualRowOrder.size();
+ final int logicalTargetIndex;
+ if (!visualRowOrder.isEmpty()) {
+ logicalTargetIndex = oldTopRowLogicalIndex + visualTargetIndex;
+ } else {
+ logicalTargetIndex = 0;
+ }
+
+ // prioritise adding to the bottom so that there's less chance
+ // for a gap if a details row is later closed (e.g. by user)
+ final int addToBottom = Math.min(rowDiff,
+ getRowCount() - logicalTargetIndex);
+ final int addToTop = Math.max(rowDiff - addToBottom, 0);
+
+ if (addToTop > 0) {
+ fillAndPopulateEscalatorRowsIfNeeded(0,
+ oldTopRowLogicalIndex - addToTop, addToTop);
+
+ updateTopRowLogicalIndex(-addToTop);
+ }
+ if (addToBottom > 0) {
+ // take into account that rows may have got added to top as
+ // well, affects visual but not logical indexing
+ fillAndPopulateEscalatorRowsIfNeeded(
+ visualTargetIndex + addToTop, logicalTargetIndex,
+ addToBottom);
+
+ // adding new rows due to resizing may have created a gap in
+ // the middle, check whether the existing rows need moving
+ double rowTop = getRowTop(oldTopRowLogicalIndex);
+ if (rowTop > getRowTop(visualRowOrder.get(addToTop))) {
+ for (int i = addToTop; i < visualTargetIndex; i++) {
+
+ final TableRowElement tr = visualRowOrder.get(i);
+
+ setRowPosition(tr, 0, rowTop);
+ rowTop += getDefaultRowHeight();
+ SpacerContainer.SpacerImpl spacer = spacerContainer
+ .getSpacer(oldTopRowLogicalIndex + i);
+ if (spacer != null) {
+ spacer.setPosition(0, rowTop);
+ rowTop += spacer.getHeight();
}
}
}
- } else if (rowDiff < 0) {
- // rows need to be removed
+ }
- // prioritise removing rows from above the viewport as they are
- // less likely to be needed in a hurry -- the rows below are
- // more likely to slide into view when spacer contents are
- // updated
-
- // top of visible area before any rows are actually added
- double scrollTop = getScrollTop();
-
- // visual index of the first actually visible row, including
- // spacer
- int oldFirstVisibleVisualIndex = -1;
- ListIterator<TableRowElement> iter = visualRowOrder
- .listIterator(0);
- for (int i = 0; i < visualRowOrder.size(); ++i) {
- if (positions.getTop(iter.next()) > scrollTop) {
- break;
- }
- oldFirstVisibleVisualIndex = i;
- }
+ scroller.recalculateScrollbarsForVirtualViewport();
+ fireRowVisibilityChangeEvent();
+ }
- int rowsToRemoveFromAbove = Math.max(0, Math
- .min(Math.abs(rowDiff), oldFirstVisibleVisualIndex));
+ private void handleRemovingExcessRows(final int rowDiff) {
+ // prioritise removing rows from above the viewport as they are
+ // less likely to be needed in a hurry -- the rows below are
+ // more likely to slide into view when spacer contents are
+ // updated
- boolean spacersRemovedFromAbove = false;
- if (rowsToRemoveFromAbove > 0) {
- double initialSpacerHeightSum = spacerContainer
- .getSpacerHeightsSum();
- iter = visualRowOrder.listIterator(0);
- for (int i = 0; i < rowsToRemoveFromAbove; ++i) {
- final Element first = iter.next();
- first.removeFromParent();
- iter.remove();
+ int oldTopRowLogicalIndex = getTopRowLogicalIndex();
+ final int oldVisualRangeLength = visualRowOrder.size();
- spacerContainer.removeSpacer(oldTopRowLogicalIndex + i);
- }
- spacersRemovedFromAbove = initialSpacerHeightSum != spacerContainer
- .getSpacerHeightsSum();
- }
+ // top of visible area before any rows are actually added
+ double scrollTop = getScrollTop();
- // if there weren't enough rows above, remove the rest from
- // below
- int rowsToRemoveFromBelow = Math.abs(rowDiff)
- - rowsToRemoveFromAbove;
- if (rowsToRemoveFromBelow > 0) {
- iter = visualRowOrder.listIterator(visualRowOrder.size());
- for (int i = 1; i <= rowsToRemoveFromBelow; ++i) {
- final Element last = iter.previous();
- last.removeFromParent();
- iter.remove();
-
- spacerContainer.removeSpacer(oldTopRowLogicalIndex
- + oldVisualRangeLength - i);
- }
+ // visual index of the first actually visible row, including
+ // spacer
+ int oldFirstVisibleVisualIndex = -1;
+ ListIterator<TableRowElement> iter = visualRowOrder.listIterator(0);
+ for (int i = 0; i < visualRowOrder.size(); ++i) {
+ if (positions.getTop(iter.next()) > scrollTop) {
+ break;
}
+ oldFirstVisibleVisualIndex = i;
+ }
- updateTopRowLogicalIndex(rowsToRemoveFromAbove);
+ int rowsToRemoveFromAbove = Math.max(0,
+ Math.min(Math.abs(rowDiff), oldFirstVisibleVisualIndex));
- if (spacersRemovedFromAbove) {
- updateRowPositions(oldTopRowLogicalIndex, 0,
- visualRowOrder.size());
- }
+ boolean spacersRemovedFromAbove = false;
+ if (rowsToRemoveFromAbove > 0) {
+ double initialSpacerHeightSum = spacerContainer
+ .getSpacerHeightsSum();
+ iter = visualRowOrder.listIterator(0);
+ for (int i = 0; i < rowsToRemoveFromAbove; ++i) {
+ final Element first = iter.next();
+ first.removeFromParent();
+ iter.remove();
- // removing rows might cause a gap at the bottom
- adjustScrollPositionIfNeeded();
+ spacerContainer.removeSpacer(oldTopRowLogicalIndex + i);
+ }
+ spacersRemovedFromAbove = initialSpacerHeightSum != spacerContainer
+ .getSpacerHeightsSum();
+ }
+
+ // if there weren't enough rows above, remove the rest from
+ // below
+ int rowsToRemoveFromBelow = Math.abs(rowDiff)
+ - rowsToRemoveFromAbove;
+ if (rowsToRemoveFromBelow > 0) {
+ iter = visualRowOrder.listIterator(visualRowOrder.size());
+ for (int i = 1; i <= rowsToRemoveFromBelow; ++i) {
+ final Element last = iter.previous();
+ last.removeFromParent();
+ iter.remove();
+
+ spacerContainer.removeSpacer(
+ oldTopRowLogicalIndex + oldVisualRangeLength - i);
+ }
}
- if (rowDiff != 0) {
- scroller.recalculateScrollbarsForVirtualViewport();
+ updateTopRowLogicalIndex(rowsToRemoveFromAbove);
- fireRowVisibilityChangeEvent();
+ if (spacersRemovedFromAbove) {
+ updateRowPositions(oldTopRowLogicalIndex, 0,
+ visualRowOrder.size());
}
- Profiler.leave("Escalator.BodyRowContainer.verifyEscalatorCount");
+ // removing rows might cause a gap at the bottom
+ adjustScrollPositionIfNeeded();
+
+ scroller.recalculateScrollbarsForVirtualViewport();
+ fireRowVisibilityChangeEvent();
}
@Override
updateVerticalScrollPosition();
});
+ addEditorAndContents(gridElement, tr);
+ updateSizeAndPosition(gridElement, tr);
+ }
+
+ private void addEditorAndContents(DivElement gridElement,
+ TableRowElement tr) {
gridElement.appendChild(editorOverlay);
editorOverlay.appendChild(frozenCellWrapper);
editorOverlay.appendChild(cellWrapper);
editorOverlay.appendChild(messageAndButtonsWrapper);
updateBufferedStyleName();
-
- // Add class name with selected modifier if the editor is being
- // opened on selected row, see #11634
- String selectedStylename = styleName + "-selected";
- if (grid.isSelected(grid.getDataSource().getRow(getRow()))) {
- cellWrapper.addClassName(selectedStylename);
- } else {
- cellWrapper.removeClassName(selectedStylename);
- }
+ updateSelectedStyleName();
int frozenColumns = grid.getVisibleFrozenColumnCount();
double frozenColumnsWidth = 0;
}
setMessageAndButtonsWrapperVisible(isBuffered());
+ }
+
+ private void updateSizeAndPosition(DivElement gridElement,
+ TableRowElement tr) {
updateHorizontalScrollPosition();
}
}
+ private void updateSelectedStyleName() {
+ // Add class name with selected modifier if the editor is being
+ // opened on selected row, see #11634
+ String selectedStylename = styleName + "-selected";
+ if (grid.isSelected(grid.getDataSource().getRow(getRow()))) {
+ cellWrapper.addClassName(selectedStylename);
+ } else {
+ cellWrapper.removeClassName(selectedStylename);
+ }
+ }
+
/**
* Sets the editor's primary style name and updates all dependent style
* names.
.setColumnWidths(constrainedWidths, true);
}
+ @SuppressWarnings("unchecked")
private void applyColumnWidthsWithExpansion() {
boolean defaultExpandRatios = true;
int totalRatios = 0;
return;
}
+ Object[] result = handleMaximumWidths(totalRatios,
+ pixelsToDistribute, defaultExpandRatios, columnsToExpand,
+ visibleColumns, columnSizes);
+ if (result.length != 3) {
+ // everything handled already
+ return;
+ }
+ // update values based on maximum width handling
+ totalRatios = (int) result[0];
+ pixelsToDistribute = (double) result[1];
+ columnSizes = (Map<Integer, Double>) result[2];
+
+ assert pixelsToDistribute > 0 : "We've run out of pixels to distribute ("
+ + pixelsToDistribute + "px to " + totalRatios
+ + " ratios between " + columnsToExpand.size() + " columns)";
+ assert totalRatios > 0 && !columnsToExpand
+ .isEmpty() : "Bookkeeping out of sync. Ratios: "
+ + totalRatios + " Columns: "
+ + columnsToExpand.size();
+
+ /*
+ * If we still have anything left, distribute the remaining pixels
+ * to the remaining columns.
+ */
+ columnSizes = distributeRemainingPixels(totalRatios,
+ pixelsToDistribute, defaultExpandRatios, columnsToExpand,
+ visibleColumns, columnSizes);
+
+ columnSizes = handleMinimumWidths(defaultExpandRatios,
+ columnsToExpand, visibleColumns, columnSizes);
+
+ // Finally set all the column sizes.
+ setColumnSizes(columnSizes, true);
+ }
+
+ private Object[] handleMaximumWidths(int totalRatios,
+ double pixelsToDistribute, final boolean defaultExpandRatios,
+ final Set<Column<?, T>> columnsToExpand,
+ final List<Column<?, T>> visibleColumns,
+ final Map<Integer, Double> columnSizes) {
/*
* Check for columns that hit their max width. Adjust
* pixelsToDistribute and totalRatios accordingly. Recheck. Stop
if (totalRatios <= 0 && columnsToExpand.isEmpty()) {
setColumnSizes(columnSizes, true);
- return;
+ // nothing left to handle
+ return new Object[] {};
}
- assert pixelsToDistribute > 0 : "We've run out of pixels to distribute ("
- + pixelsToDistribute + "px to " + totalRatios
- + " ratios between " + columnsToExpand.size() + " columns)";
- assert totalRatios > 0 && !columnsToExpand
- .isEmpty() : "Bookkeeping out of sync. Ratios: "
- + totalRatios + " Columns: "
- + columnsToExpand.size();
+ // this must return exactly 3 objects in this precise order
+ return new Object[] { totalRatios, pixelsToDistribute,
+ columnSizes };
+ }
- /*
- * If we still have anything left, distribute the remaining pixels
- * to the remaining columns.
- */
+ private Map<Integer, Double> distributeRemainingPixels(int totalRatios,
+ final double pixelsToDistribute,
+ final boolean defaultExpandRatios,
+ final Set<Column<?, T>> columnsToExpand,
+ final List<Column<?, T>> visibleColumns,
+ final Map<Integer, Double> columnSizes) {
final double widthPerRatio;
int leftOver = 0;
if (BrowserInfo.getBrowserString().contains("PhantomJS")) {
assert totalRatios == 0 : "Bookkeeping error: there were still some ratios left undistributed: "
+ totalRatios;
+ return columnSizes;
+ }
+
+ private Map<Integer, Double> handleMinimumWidths(
+ final boolean defaultExpandRatios,
+ final Set<Column<?, T>> columnsToExpand,
+ final List<Column<?, T>> visibleColumns,
+ final Map<Integer, Double> columnSizes) {
/*
* Check the guarantees for minimum width and scoot back the columns
* that don't care.
* Now we need to shrink the remaining columns according to
* their ratios. Recalculate the sum of remaining ratios.
*/
- totalRatios = 0;
+ int totalRatios = 0;
for (Column<?, ?> column : columnsToExpand) {
totalRatios += getExpandRatio(column, defaultExpandRatios);
}
} while (minWidthsCausedReflows);
- // Finally set all the column sizes.
- setColumnSizes(columnSizes, true);
+ return columnSizes;
}
private void setColumnSizes(Map<Integer, Double> columnSizes,
resizeHandleWidth = dragger.getElement().getOffsetWidth()
+ WidgetUtil.getBorderLeftAndRightThickness(td);
- // Common functionality for drag handle callback
- // implementations
- abstract class AbstractDHCallback
- implements DragHandleCallback {
- protected Column<?, T> col = getVisibleColumn(column);
- protected double initialWidth = 0;
- protected double minCellWidth;
- protected double width;
-
- protected void dragStarted() {
- initialWidth = col.getWidthActual();
- width = initialWidth;
-
- minCellWidth = escalator.getMinCellWidth(
- getVisibleColumns().indexOf(col));
- for (Column<?, T> c : getVisibleColumns()) {
- if (selectionColumn == c) {
- // Don't modify selection column.
- continue;
- }
+ final DragHandleCallback simpleResizeMode = createSimpleResizeModeCallback(
+ column, dragger, resizeElement);
- if (c.getWidth() < 0) {
- c.setWidth(c.getWidthActual());
- fireEvent(new ColumnResizeEvent<>(c));
- }
- }
+ final DragHandleCallback animatedResizeMode = createAnimatedResizeModeCallback(
+ column);
- WidgetUtil.setTextSelectionEnabled(getElement(),
- false);
- }
+ // DragHandle gets assigned a 'master callback' that
+ // delegates functionality to the correct case-specific
+ // implementation
+ dragger.setCallback(createResizeModeAwareDragHandleCallback(
+ simpleResizeMode, animatedResizeMode));
+ }
- protected void dragEnded() {
- WidgetUtil.setTextSelectionEnabled(getElement(),
- true);
- }
+ cellFocusHandler.updateFocusedCellStyle(cell, container);
+ }
+ }
+
+ // Common functionality for drag handle callback
+ // implementations
+ private abstract class AbstractDHCallback
+ implements DragHandleCallback {
+ protected Column<?, T> col;
+ protected double initialWidth = 0;
+ protected double minCellWidth;
+ protected double width;
+
+ AbstractDHCallback(int column) {
+ col = getVisibleColumn(column);
+ }
+
+ protected void dragStarted() {
+ initialWidth = col.getWidthActual();
+ width = initialWidth;
+
+ minCellWidth = escalator
+ .getMinCellWidth(getVisibleColumns().indexOf(col));
+ for (Column<?, T> c : getVisibleColumns()) {
+ if (selectionColumn == c) {
+ // Don't modify selection column.
+ continue;
}
- final DragHandleCallback simpleResizeMode = new AbstractDHCallback() {
- @Override
- protected void dragEnded() {
- super.dragEnded();
- dragger.getElement().removeChild(resizeElement);
- }
+ if (c.getWidth() < 0) {
+ c.setWidth(c.getWidthActual());
+ fireEvent(new ColumnResizeEvent<>(c));
+ }
+ }
- @Override
- public void onStart() {
- dragStarted();
- dragger.getElement().appendChild(resizeElement);
- resizeElement.getStyle().setLeft(
- (dragger.getElement().getOffsetWidth()
- - resizeElement.getOffsetWidth())
- * .5,
+ WidgetUtil.setTextSelectionEnabled(getElement(), false);
+ }
+
+ protected void dragEnded() {
+ WidgetUtil.setTextSelectionEnabled(getElement(), true);
+ }
+ }
+
+ private DragHandleCallback createSimpleResizeModeCallback(
+ final int column, final DragHandle dragger,
+ final DivElement resizeElement) {
+ return new AbstractDHCallback(column) {
+ @Override
+ protected void dragEnded() {
+ super.dragEnded();
+ dragger.getElement().removeChild(resizeElement);
+ }
+
+ @Override
+ public void onStart() {
+ dragStarted();
+ dragger.getElement().appendChild(resizeElement);
+ resizeElement.getStyle()
+ .setLeft((dragger.getElement().getOffsetWidth()
+ - resizeElement.getOffsetWidth()) * .5,
Unit.PX);
- resizeElement.getStyle().setHeight(
- col.grid.getOffsetHeight(), Unit.PX);
- }
+ resizeElement.getStyle()
+ .setHeight(col.grid.getOffsetHeight(), Unit.PX);
+ }
- @Override
- public void onUpdate(double deltaX, double deltaY) {
- width = Math.max(minCellWidth,
- initialWidth + deltaX);
- resizeElement.getStyle().setLeft(
+ @Override
+ public void onUpdate(double deltaX, double deltaY) {
+ width = Math.max(minCellWidth, initialWidth + deltaX);
+ resizeElement.getStyle()
+ .setLeft(
(dragger.getElement().getOffsetWidth()
- resizeElement.getOffsetWidth())
* .5 + (width - initialWidth),
Unit.PX);
- }
+ }
- @Override
- public void onCancel() {
- dragEnded();
- }
+ @Override
+ public void onCancel() {
+ dragEnded();
+ }
- @Override
- public void onComplete() {
- dragEnded();
- col.setWidth(width);
-
- // Need to wait for column width recalculation
- // scheduled by setWidth() before firing the event
- Scheduler.get().scheduleDeferred(() -> fireEvent(
- new ColumnResizeEvent<>(col)));
- }
- };
+ @Override
+ public void onComplete() {
+ dragEnded();
+ col.setWidth(width);
- final DragHandleCallback animatedResizeMode = new AbstractDHCallback() {
- @Override
- public void onStart() {
- dragStarted();
- }
+ // Need to wait for column width recalculation
+ // scheduled by setWidth() before firing the event
+ Scheduler.get().scheduleDeferred(
+ () -> fireEvent(new ColumnResizeEvent<>(col)));
+ }
+ };
+ }
- @Override
- public void onUpdate(double deltaX, double deltaY) {
- width = Math.max(minCellWidth,
- initialWidth + deltaX);
- col.setWidth(width);
- }
+ private DragHandleCallback createAnimatedResizeModeCallback(
+ final int column) {
+ return new AbstractDHCallback(column) {
+ @Override
+ public void onStart() {
+ dragStarted();
+ }
- @Override
- public void onCancel() {
- dragEnded();
- col.setWidth(initialWidth);
- }
+ @Override
+ public void onUpdate(double deltaX, double deltaY) {
+ width = Math.max(minCellWidth, initialWidth + deltaX);
+ col.setWidth(width);
+ }
- @Override
- public void onComplete() {
- dragEnded();
- col.setWidth(width);
- fireEvent(new ColumnResizeEvent<>(col));
- }
- };
+ @Override
+ public void onCancel() {
+ dragEnded();
+ col.setWidth(initialWidth);
+ }
- // DragHandle gets assigned a 'master callback' that
- // delegates
- // functionality to the correct case-specific implementation
- dragger.setCallback(new DragHandleCallback() {
+ @Override
+ public void onComplete() {
+ dragEnded();
+ col.setWidth(width);
+ fireEvent(new ColumnResizeEvent<>(col));
+ }
+ };
+ }
- private DragHandleCallback currentCallback;
+ private DragHandleCallback createResizeModeAwareDragHandleCallback(
+ final DragHandleCallback simpleResizeMode,
+ final DragHandleCallback animatedResizeMode) {
+ return new DragHandleCallback() {
- @Override
- public void onStart() {
- switch (getColumnResizeMode()) {
- case SIMPLE:
- currentCallback = simpleResizeMode;
- break;
- case ANIMATED:
- currentCallback = animatedResizeMode;
- break;
- default:
- throw new UnsupportedOperationException(
- "Support for current column resize mode is not yet implemented");
- }
+ private DragHandleCallback currentCallback;
- currentCallback.onStart();
- }
+ @Override
+ public void onStart() {
+ switch (getColumnResizeMode()) {
+ case SIMPLE:
+ currentCallback = simpleResizeMode;
+ break;
+ case ANIMATED:
+ currentCallback = animatedResizeMode;
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ "Support for current column resize mode is not yet implemented");
+ }
- @Override
- public void onUpdate(double deltaX, double deltaY) {
- currentCallback.onUpdate(deltaX, deltaY);
- }
+ currentCallback.onStart();
+ }
- @Override
- public void onCancel() {
- currentCallback.onCancel();
- }
+ @Override
+ public void onUpdate(double deltaX, double deltaY) {
+ currentCallback.onUpdate(deltaX, deltaY);
+ }
- @Override
- public void onComplete() {
- currentCallback.onComplete();
- }
- });
+ @Override
+ public void onCancel() {
+ currentCallback.onCancel();
}
- cellFocusHandler.updateFocusedCellStyle(cell, container);
- }
+ @Override
+ public void onComplete() {
+ currentCallback.onComplete();
+ }
+ };
}
private void addAriaLabelToHeaderRow(FlyweightCell cell) {