Browse Source

Divide too long Grid and Escalator methods into smaller units. (#12340)

tags/8.14.0.alpha1
Anna Koskinen 2 years ago
parent
commit
0c9ef57b21
No account linked to committer's email address

+ 115
- 107
client/src/main/java/com/vaadin/client/widgets/Escalator.java View File

@@ -4729,7 +4729,6 @@ public class Escalator extends Widget
return;
}

int oldTopRowLogicalIndex = getTopRowLogicalIndex();
int oldVisualRangeLength = visualRowOrder.size();

final int maxVisibleRowCount = getMaxVisibleRowCount();
@@ -4740,132 +4739,141 @@ public class Escalator extends Widget

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

+ 233
- 152
client/src/main/java/com/vaadin/client/widgets/Grid.java View File

@@ -2129,21 +2129,19 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
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;
@@ -2248,6 +2246,10 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}

setMessageAndButtonsWrapperVisible(isBuffered());
}

private void updateSizeAndPosition(DivElement gridElement,
TableRowElement tr) {

updateHorizontalScrollPosition();

@@ -2362,6 +2364,17 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}
}

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.
@@ -3913,6 +3926,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
.setColumnWidths(constrainedWidths, true);
}

@SuppressWarnings("unchecked")
private void applyColumnWidthsWithExpansion() {
boolean defaultExpandRatios = true;
int totalRatios = 0;
@@ -4019,6 +4033,46 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
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
@@ -4051,20 +4105,20 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

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")) {
@@ -4093,6 +4147,14 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
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.
@@ -4138,7 +4200,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* 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);
}
@@ -4154,8 +4216,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

} while (minWidthsCausedReflows);

// Finally set all the column sizes.
setColumnSizes(columnSizes, true);
return columnSizes;
}

private void setColumnSizes(Map<Integer, Double> columnSizes,
@@ -6533,161 +6594,181 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
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) {

Loading…
Cancel
Save