Kaynağa Gözat

Handle spanned header cells when dnd reordering columns in grid. (#16643)

Prevents dragging columns from outside spanned cells to inside them, on any row.
Currently prevents dragging columns inside spanned cells. Will change this later.

Change-Id: Ie832b3c404a3afbcce0374f8b5088dc8cb124fb8
tags/7.5.0.alpha1
Pekka Hyvönen 9 yıl önce
ebeveyn
işleme
31b188e370

+ 1
- 0
client/src/com/vaadin/client/widget/grid/AutoScroller.java Dosyayı Görüntüle

@@ -669,6 +669,7 @@ public class AutoScroller {
}

private double getFrozenColumnsWidth() {
// TODO handle the case where the checkbox column is present
double value = 0;
for (int i = 0; i < grid.getFrozenColumnCount(); i++) {
value += grid.getColumn(i).getWidthActual();

+ 105
- 24
client/src/com/vaadin/client/widgets/Grid.java Dosyayı Görüntüle

@@ -25,7 +25,9 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

@@ -37,7 +39,6 @@ import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.TableCellElement;
@@ -415,6 +416,16 @@ public class Grid<T> extends ResizeComposite implements
return cells.get(column);
}

/**
* Returns <code>true</code> if this row contains spanned cells.
*
* @since
* @return does this row contain spanned cells
*/
public boolean hasSpannedCells() {
return !cellGroups.isEmpty();
}

/**
* Merges columns cells in a row
*
@@ -2906,6 +2917,11 @@ public class Grid<T> extends ResizeComposite implements
private Element dragElement;
/** Tracks index of the column whose left side the drop would occur */
private int latestColumnDropIndex;
/**
* Map of possible drop positions for the column and the corresponding
* column index.
*/
private final TreeMap<Double, Integer> possibleDropPositions = new TreeMap<Double, Integer>();
/**
* Makes sure that drag cancel doesn't cause anything unwanted like sort
*/
@@ -2952,33 +2968,33 @@ public class Grid<T> extends ResizeComposite implements
}

private void updateDragDropMarker(final int clientX) {
RowContainer header = escalator.getHeader();
NodeList<TableCellElement> cells = header.getRowElement(
eventCell.getRowIndex()).getCells();
double dropMarkerLeft = 0 - escalator.getScrollLeft();
latestColumnDropIndex = 0;
for (int i = 0; i < cells.getLength(); i++, latestColumnDropIndex++) {
TableCellElement cellElement = cells.getItem(i);
int cellX = cellElement.getAbsoluteLeft();
int cellWidth = cellElement.getOffsetWidth();
if (clientX < cellX || clientX < cellX + (cellWidth / 2)) {
break;
} else {
dropMarkerLeft += cellWidth;
}
final double scrollLeft = getScrollLeft();
final double cursorXCoordinate = clientX
- escalator.getHeader().getElement().getAbsoluteLeft();
final Entry<Double, Integer> cellEdgeOnRight = possibleDropPositions
.ceilingEntry(cursorXCoordinate);
final Entry<Double, Integer> cellEdgeOnLeft = possibleDropPositions
.floorEntry(cursorXCoordinate);
final double diffToRightEdge = cellEdgeOnRight == null ? Double.MAX_VALUE
: cellEdgeOnRight.getKey() - cursorXCoordinate;
final double diffToLeftEdge = cellEdgeOnLeft == null ? Double.MAX_VALUE
: cursorXCoordinate - cellEdgeOnLeft.getKey();

double dropMarkerLeft = 0 - scrollLeft;
if (diffToRightEdge > diffToLeftEdge) {
latestColumnDropIndex = cellEdgeOnLeft.getValue();
dropMarkerLeft += cellEdgeOnLeft.getKey();
} else {
latestColumnDropIndex = cellEdgeOnRight.getValue();
dropMarkerLeft += cellEdgeOnRight.getKey();
}

dropMarkerLeft += autoScrollX;

final double frozenColumnsWidth = getFrozenColumnsWidth();
if (dropMarkerLeft < frozenColumnsWidth) {
latestColumnDropIndex = getFrozenColumnCount();
if (getScrollLeft() == 0) {
dropMarkerLeft = frozenColumnsWidth;
} else {
dropMarkerLeft = -10000000;
}
} else if (dropMarkerLeft > header.getElement().getOffsetWidth()
|| dropMarkerLeft < 0) {
if (dropMarkerLeft < frozenColumnsWidth
|| dropMarkerLeft > escalator.getHeader().getElement()
.getOffsetWidth() || dropMarkerLeft < 0) {
dropMarkerLeft = -10000000;
}
dropMarker.getStyle().setLeft(dropMarkerLeft, Unit.PX);
@@ -3009,6 +3025,9 @@ public class Grid<T> extends ResizeComposite implements
eventCell.getElement().addClassName("dragged");
// mark the floating cell, for styling & testing
dragElement.addClassName("dragged-column-header");

calculatePossibleDropPositions();

// start the auto scroll handler
autoScroller.setScrollAreaPX(60);
autoScroller.start(startingEvent, ScrollAxis.HORIZONTAL,
@@ -3099,6 +3118,58 @@ public class Grid<T> extends ResizeComposite implements
}
return result;
}

private void calculatePossibleDropPositions() {
possibleDropPositions.clear();

if (!calculatePossibleDropPositionInsideSpannedHeader()) {
HashMap<Integer, Double> columnIndexToDropPositionMap = new HashMap<Integer, Double>();

final int frozenColumns = Math.max(0, getFrozenColumnCount());
double position = getFrozenColumnsWidth();
// add all columns except frozen columns
// TODO handle the case where the checkbox column is present
for (int i = frozenColumns; i < getColumnCount(); i++) {
columnIndexToDropPositionMap.put(i, position);
position += getColumn(i).getWidthActual();
}
// add the right side of the last column as columns.size()
columnIndexToDropPositionMap.put(getColumnCount(), position);

// can't drop inside a spanned header from outside it
// -> remove all column indexes that are inside a spanned cell
// in any header row
for (int c = frozenColumns; c < getColumnCount(); c++) {
for (int r = 0; r < getHeaderRowCount(); r++) {
HeaderRow headerRow = getHeaderRow(r);
if (headerRow.hasSpannedCells()) {
HeaderCell cell = headerRow.getCell(getColumn(c));
assert cell != null : "Somehow got a null cell for row:cell "
+ r + ":" + c;
int colspan = cell.getColspan();
while (colspan > 1) {
c++;
colspan--;
columnIndexToDropPositionMap.remove(Integer
.valueOf(c));
}
}
}
}
// finally lets flip the map, because while dragging we want the
// column index matching the X-coordinate
for (Entry<Integer, Double> entry : columnIndexToDropPositionMap
.entrySet()) {
possibleDropPositions.put(entry.getValue(), entry.getKey());
}
}
}

private boolean calculatePossibleDropPositionInsideSpannedHeader() {
// TODO if the dragged column is inside a spanned header on any row,
// then dragging is limited to inside that spanned cell
return false;
}
};

/**
@@ -5392,6 +5463,16 @@ public class Grid<T> extends ResizeComposite implements
.getFrozenColumnCount()) {
return false;
}
// for now prevent dragging of spanned cells
if (eventCell.getElement().getColSpan() > 1) {
return false;
}
// for now prevent dragging of columns belonging to a spanned cell
for (int r = 0; r < getHeaderRowCount(); r++) {
if (getHeaderRow(r).getCell(eventCell.getColumn()).getColspan() > 1) {
return false;
}
}
if (event.getTypeInt() == Event.ONMOUSEDOWN
&& event.getButton() == NativeEvent.BUTTON_LEFT
|| event.getTypeInt() == Event.ONTOUCHSTART) {

+ 11
- 2
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicClientFeaturesTest.java Dosyayı Görüntüle

@@ -15,6 +15,8 @@
*/
package com.vaadin.tests.components.grid.basicfeatures;

import java.util.List;

import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
@@ -83,10 +85,17 @@ public abstract class GridBasicClientFeaturesTest extends GridBasicFeaturesTest
if (composite) {
// Composite requires the basic client features widget for subparts
return ((TestBenchElement) findElement(By
.vaadin("//TestWidgetComponent")))
.wrap(GridElement.class);
.vaadin("//TestWidgetComponent"))).wrap(GridElement.class);
} else {
return super.getGridElement();
}
}

@Override
protected void assertColumnHeaderOrder(int... indices) {
List<TestBenchElement> headers = getGridHeaderRowCells();
for (int i = 0; i < indices.length; i++) {
assertColumnHeader("HEADER (0," + indices[i] + ")", headers.get(i));
}
}
}

+ 30
- 0
uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java Dosyayı Görüntüle

@@ -205,6 +205,36 @@ public class GridColumnReorderTest extends GridBasicClientFeaturesTest {
assertFocusedCell(4, 1);
}

@Test
public void testColumnReorder_draggingHeaderRowThatHasColumnHeadersSpanned_cantDropInsideSpannedHeaderFromOutside() {
// given
toggleColumnReorder();
selectMenuPath("Component", "Header", "Append row");
selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2");
assertColumnHeaderOrder(0, 1, 2, 3, 4);

// when
dragAndDropColumnHeader(1, 3, 1, 80);

// then
assertColumnHeaderOrder(0, 3, 1, 2, 4);
}

@Test
public void testColumnReorder_anotherRowHasColumnHeadersSpanned_cantDropInsideSpannedHeaderFromOutside() {
// given
toggleColumnReorder();
selectMenuPath("Component", "Header", "Append row");
selectMenuPath("Component", "Header", "Row 2", "Join columns 1, 2");
assertColumnHeaderOrder(0, 1, 2, 3, 4);

// when
dragAndDropColumnHeader(0, 0, 2, 20);

// then
assertColumnHeaderOrder(1, 2, 0, 3, 4);
}

private void toggleColumnReorder() {
selectMenuPath("Component", "State", "Column Reordering");
}

Loading…
İptal
Kaydet