summaryrefslogtreecommitdiffstats
path: root/client/src
diff options
context:
space:
mode:
authorPekka Hyvönen <pekka@vaadin.com>2015-03-03 11:15:06 +0200
committerPekka Hyvönen <pekka@vaadin.com>2015-03-04 09:24:00 +0200
commitde2172eda96ca3f34b2ab4e2e926b13957c113de (patch)
treeddd7e7cddfd47cf33b0837f8486097e92de89481 /client/src
parent40916228681314c843b32e59fc91bbec18548332 (diff)
downloadvaadin-framework-de2172eda96ca3f34b2ab4e2e926b13957c113de.tar.gz
vaadin-framework-de2172eda96ca3f34b2ab4e2e926b13957c113de.zip
Limit dnd-reorder of columns inside spanned headers. (#16643)
Doesn't take footers into account, yet. Change-Id: I9c62ca97bcbdb852f2fe7ad7ea2e7de0f0ed02f8
Diffstat (limited to 'client/src')
-rw-r--r--client/src/com/vaadin/client/ui/dd/DragAndDropHandler.java23
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java138
2 files changed, 103 insertions, 58 deletions
diff --git a/client/src/com/vaadin/client/ui/dd/DragAndDropHandler.java b/client/src/com/vaadin/client/ui/dd/DragAndDropHandler.java
index eec52d5def..0710606818 100644
--- a/client/src/com/vaadin/client/ui/dd/DragAndDropHandler.java
+++ b/client/src/com/vaadin/client/ui/dd/DragAndDropHandler.java
@@ -46,12 +46,15 @@ public class DragAndDropHandler {
*/
public interface DragAndDropCallback {
/**
- * Called when the drag has started.
+ * Called when the drag has started. The drag can be canceled by
+ * returning {@code false}.
*
* @param startEvent
* the original event that started the drag
+ * @return {@code true} if the drag is OK to start, {@code false} to
+ * cancel
*/
- void onDragStart(NativeEvent startEvent);
+ boolean onDragStart(NativeEvent startEvent);
/**
* Called on drag.
@@ -204,13 +207,15 @@ public class DragAndDropHandler {
private void startDrag(NativeEvent startEvent,
NativePreviewEvent triggerEvent, DragAndDropCallback callback) {
- dragging = true;
- // just capture something to prevent text selection in IE
- Event.setCapture(RootPanel.getBodyElement());
- this.callback = callback;
- dragHandlerRegistration = Event.addNativePreviewHandler(dragHandler);
- callback.onDragStart(startEvent);
- callback.onDragUpdate(triggerEvent);
+ if (callback.onDragStart(startEvent)) {
+ dragging = true;
+ // just capture something to prevent text selection in IE
+ Event.setCapture(RootPanel.getBodyElement());
+ this.callback = callback;
+ dragHandlerRegistration = Event
+ .addNativePreviewHandler(dragHandler);
+ callback.onDragUpdate(triggerEvent);
+ }
}
private void stopDrag() {
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index c237a7ba2f..26e7ba4650 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -3001,19 +3001,38 @@ public class Grid<T> extends ResizeComposite implements
}
private void resolveDragElementHorizontalPosition(final int clientX) {
- int left = clientX - table.getAbsoluteLeft();
- left = Math.max(0, Math.min(left, table.getClientWidth()));
+ double left = clientX - table.getAbsoluteLeft();
final double frozenColumnsWidth = getFrozenColumnsWidth();
if (left < frozenColumnsWidth) {
left = (int) frozenColumnsWidth;
}
+ // do not show the drag element beyond a spanned header cell
+ // limitation
+ final Double leftBound = possibleDropPositions.firstKey();
+ final Double rightBound = possibleDropPositions.lastKey();
+ double scrollLeft = getScrollLeft();
+ if (left + scrollLeft < leftBound) {
+ left = leftBound - scrollLeft + autoScrollX;
+ } else if (left + scrollLeft > rightBound) {
+ left = rightBound - scrollLeft + autoScrollX;
+ }
+
+ // do not show the drag element beyond the grid
+ left = Math.max(0, Math.min(left, table.getClientWidth()));
+
left -= dragElement.getClientWidth() / 2;
dragElement.getStyle().setLeft(left, Unit.PX);
}
@Override
- public void onDragStart(NativeEvent startingEvent) {
+ public boolean onDragStart(NativeEvent startingEvent) {
+ calculatePossibleDropPositions();
+
+ if (possibleDropPositions.isEmpty()) {
+ return false;
+ }
+
initHeaderDragElementDOM();
// needs to clone focus and sorting indicators too (UX)
dragElement = DOM.clone(eventCell.getElement(), true);
@@ -3026,12 +3045,11 @@ public class Grid<T> extends ResizeComposite implements
// 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,
autoScrollerCallback);
+ return true;
}
@Override
@@ -3147,55 +3165,82 @@ public class Grid<T> extends ResizeComposite implements
}
}
+ @SuppressWarnings("boxing")
private void calculatePossibleDropPositions() {
possibleDropPositions.clear();
- if (!calculatePossibleDropPositionInsideSpannedHeader()) {
- HashMap<Integer, Double> columnIndexToDropPositionMap = new HashMap<Integer, Double>();
+ final int draggedColumnIndex = eventCell.getColumnIndex();
+ HashSet<Integer> unavailableColumnDropIndices = new HashSet<Integer>();
- final int frozenColumns = getSelectionAndFrozenColumnCount();
- double position = getFrozenColumnsWidth();
- // add all columns except frozen columns
- 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);
+ final int frozenColumns = getSelectionAndFrozenColumnCount();
+ /*
+ * If the dragged cell is adjacent to a spanned cell in any other
+ * header or footer row, then the drag is limited inside that
+ * spanned cell. The same rules apply: the cell can't be dropped
+ * inside another spanned cell. The left and right bounds keep track
+ * of the edges of the most limiting spanned cell.
+ */
+ int leftBound = -1;
+ int rightBound = getColumnCount() + 1;
- // 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 r = 0; r < getHeaderRowCount(); r++) {
+ HeaderRow headerRow = getHeaderRow(r);
+ if (!headerRow.hasSpannedCells()) {
+ continue;
+ }
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));
- }
+ HeaderCell cell = headerRow.getCell(getColumn(c));
+ assert cell != null : "Somehow got a null cell for row:cell "
+ + r + ":" + c;
+ int colspan = cell.getColspan();
+ if (colspan <= 1) {
+ continue;
+ }
+ final int spannedCellRightEdgeIndex = c + colspan;
+ if (c <= draggedColumnIndex
+ && spannedCellRightEdgeIndex > draggedColumnIndex) {
+ // the spanned cell overlaps the dragged cell
+ if (c <= draggedColumnIndex && c > leftBound) {
+ leftBound = c;
+ }
+ if (spannedCellRightEdgeIndex < rightBound) {
+ rightBound = spannedCellRightEdgeIndex;
+ }
+ c = spannedCellRightEdgeIndex - 1;
+ }
+
+ else { // can't drop inside a spanned cell
+ while (colspan > 1) {
+ c++;
+ colspan--;
+ unavailableColumnDropIndices.add(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;
+ if (leftBound == (rightBound - 1)) {
+ return;
+ }
+
+ double position = getFrozenColumnsWidth();
+ // iterate column indices and add possible drop positions
+ for (int i = frozenColumns; i < getColumnCount(); i++) {
+ if (!unavailableColumnDropIndices.contains(i)) {
+ if (leftBound != -1) {
+ if (i >= leftBound && i <= rightBound) {
+ possibleDropPositions.put(position, i);
+ }
+ } else {
+ possibleDropPositions.put(position, i);
+ }
+ }
+ position += getColumn(i).getWidthActual();
+ }
+ if (leftBound == -1) {
+ // add the right side of the last column as columns.size()
+ possibleDropPositions.put(position, getColumnCount());
+ }
}
};
@@ -5494,12 +5539,7 @@ public class Grid<T> extends ResizeComposite implements
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) {