From: Patrik Lindström Date: Wed, 2 Nov 2016 09:54:49 +0000 (+0200) Subject: Add lazy/simple resize mode to Grid (#20108) X-Git-Tag: 7.7.5~3 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9a0b4e9827cdcdb4084fb6b61ab7cd8953ee94fb;p=vaadin-framework.git Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 --- diff --git a/client/src/main/java/com/vaadin/client/connectors/GridConnector.java b/client/src/main/java/com/vaadin/client/connectors/GridConnector.java index ddde546da9..e329d4a4c8 100644 --- a/client/src/main/java/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/main/java/com/vaadin/client/connectors/GridConnector.java @@ -839,6 +839,11 @@ public class GridConnector extends AbstractHasComponentsConnector } } + // Column resize mode + if (stateChangeEvent.hasPropertyChanged("columnResizeMode")) { + getWidget().setColumnResizeMode(getState().columnResizeMode); + } + // Header and footer if (stateChangeEvent.hasPropertyChanged("header")) { updateHeaderFromState(getState().header); diff --git a/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java b/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java index a983337c22..5aec3b3fe9 100644 --- a/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java +++ b/client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java @@ -44,7 +44,7 @@ public class DragHandle { /** * Called when dragging starts */ - public void onStart(); + void onStart(); /** * Called when the drag handle has moved. @@ -54,18 +54,18 @@ public class DragHandle { * @param deltaY * change in Y direction since start */ - public void onUpdate(double deltaX, double deltaY); + void onUpdate(double deltaX, double deltaY); /** * Called when the drag operation has been cancelled (usually by * pressing ESC) */ - public void onCancel(); + void onCancel(); /** * Called when the drag operation completes successfully */ - public void onComplete(); + void onComplete(); } @@ -78,6 +78,20 @@ public class DragHandle { private DragHandleCallback userCallback; + /** + * Creates a new DragHandle. + * + * @param baseName + * CSS style name to use for this DragHandle element. This + * parameter is supplied to the constructor (rather than added + * later) both to provide the "-dragged" style and to make sure + * that the drag handle can be properly styled (it's otherwise + * invisible) + */ + public DragHandle(String baseName) { + this(baseName,null); + } + /** * Creates a new DragHandle. * @@ -106,22 +120,28 @@ public class DragHandle { @Override public void onDrop() { removeDraggingStyle(); - userCallback.onComplete(); + if(userCallback != null) { + userCallback.onComplete(); + } } @Override public void onDragUpdate(Event e) { - double dx = WidgetUtil.getTouchOrMouseClientX(e) - startX; - double dy = WidgetUtil.getTouchOrMouseClientY(e) - startY; - userCallback.onUpdate(dx, dy); + if(userCallback != null) { + double dx = WidgetUtil.getTouchOrMouseClientX(e) - startX; + double dy = WidgetUtil.getTouchOrMouseClientY(e) - startY; + userCallback.onUpdate(dx, dy); + } } @Override public boolean onDragStart(Event e) { addDraggingStyle(); - startX = WidgetUtil.getTouchOrMouseClientX(e); - startY = WidgetUtil.getTouchOrMouseClientY(e); - userCallback.onStart(); + if(userCallback != null) { + startX = WidgetUtil.getTouchOrMouseClientX(e); + startY = WidgetUtil.getTouchOrMouseClientY(e); + userCallback.onStart(); + } return true; } @@ -133,7 +153,9 @@ public class DragHandle { @Override public void onDragCancel() { removeDraggingStyle(); - userCallback.onCancel(); + if(userCallback != null) { + userCallback.onCancel(); + } } private void addDraggingStyle() { @@ -156,6 +178,17 @@ public class DragHandle { }); } + /** + * Sets the user-facing drag handle callback method. This allows + * code using the DragHandle to react to the situations where a + * drag handle first touched, when it's moved and when it's released. + * + * @param dragHandleCallback the callback object to use (can be null) + */ + public void setCallback(DragHandleCallback dragHandleCallback) { + userCallback = dragHandleCallback; + } + /** * Returns the current parent element for this drag handle. May be null. * 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 2b193a55db..3290aa8a48 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Grid.java +++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java @@ -77,6 +77,7 @@ import com.google.gwt.user.client.ui.MenuItem; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.ResizeComposite; import com.google.gwt.user.client.ui.Widget; + import com.vaadin.client.BrowserInfo; import com.vaadin.client.DeferredWorker; import com.vaadin.client.Focusable; @@ -176,6 +177,7 @@ import com.vaadin.client.widgets.Grid.Editor.State; import com.vaadin.client.widgets.Grid.StaticSection.StaticCell; import com.vaadin.client.widgets.Grid.StaticSection.StaticRow; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.grid.ColumnResizeMode; import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.shared.ui.grid.GridConstants.Section; import com.vaadin.shared.ui.grid.GridStaticCellType; @@ -5711,63 +5713,142 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, && staticRow instanceof HeaderRow && ((HeaderRow) staticRow).isDefault()) { + final DivElement resizeElement = Document.get().createDivElement(); + resizeElement.addClassName(getStylePrimaryName() + "-column-resize-simple-indicator"); + final int column = cell.getColumn(); - DragHandle dragger = new DragHandle( - getStylePrimaryName() + "-column-resize-handle", - new DragHandleCallback() { - - private Column col = getVisibleColumn( - column); - private double initialWidth = 0; - private double minCellWidth; - - @Override - public void onUpdate(double deltaX, - double deltaY) { - col.setWidth(Math.max(minCellWidth, - initialWidth + deltaX)); - } + final DragHandle dragger = new DragHandle(getStylePrimaryName() + "-column-resize-handle"); + dragger.addTo(td); - @Override - public void onStart() { - initialWidth = col.getWidthActual(); - - minCellWidth = escalator.getMinCellWidth( - getVisibleColumns().indexOf(col)); - for (Column c : getVisibleColumns()) { - if (selectionColumn == c) { - // Don't modify selection column. - continue; - } - - if (c.getWidth() < 0) { - c.setWidth(c.getWidthActual()); - fireEvent(new ColumnResizeEvent( - c)); - } - } + // Common functionality for drag handle callback implementations + abstract class AbstractDHCallback implements DragHandleCallback { + protected Column 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 c : getVisibleColumns()) { + if (selectionColumn == c) { + // Don't modify selection column. + continue; + } - WidgetUtil.setTextSelectionEnabled( - getElement(), false); + if (c.getWidth() < 0) { + c.setWidth(c.getWidthActual()); + fireEvent(new ColumnResizeEvent(c)); } + } - @Override - public void onComplete() { - fireEvent(new ColumnResizeEvent(col)); + WidgetUtil.setTextSelectionEnabled(getElement(), false); + } - WidgetUtil.setTextSelectionEnabled( - getElement(), true); - } + protected void dragEnded() { + WidgetUtil.setTextSelectionEnabled(getElement(), true); + } + } - @Override - public void onCancel() { - col.setWidth(initialWidth); + final DragHandleCallback simpleResizeMode = new AbstractDHCallback() { + protected void dragEnded() { + super.dragEnded(); + dragger.getElement().removeChild(resizeElement); + } - WidgetUtil.setTextSelectionEnabled( - getElement(), true); - } - }); - dragger.addTo(td); + @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); + } + + @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 onComplete() { + dragEnded(); + + col.setWidth(width); + fireEvent(new ColumnResizeEvent(col)); + } + }; + + final DragHandleCallback animatedResizeMode = new AbstractDHCallback() { + @Override + public void onStart() { + dragStarted(); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + width = Math.max(minCellWidth, initialWidth + deltaX); + col.setWidth(width); + } + + @Override + public void onCancel() { + dragEnded(); + col.setWidth(initialWidth); + } + + @Override + public void onComplete() { + dragEnded(); + col.setWidth(width); + fireEvent(new ColumnResizeEvent(col)); + } + }; + + // DragHandle gets assigned a 'master callback' that delegates + // functionality to the correct case-specific implementation + dragger.setCallback(new DragHandleCallback() { + + private DragHandleCallback currentCallback; + + @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"); + } + + currentCallback.onStart(); + } + + @Override + public void onUpdate(double deltaX, double deltaY) { + currentCallback.onUpdate(deltaX,deltaY); + } + + @Override + public void onCancel() { + currentCallback.onCancel(); + } + + @Override + public void onComplete() { + currentCallback.onComplete(); + } + }); } cellFocusHandler.updateFocusedCellStyle(cell, container); @@ -6023,6 +6104,26 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, fireEvent(new GridEnabledEvent(enabled)); } + private ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; + + /** + * Sets the column resize mode to use. The default mode is {@link ColumnResizeMode.ANIMATED}. + * + * @param mode a ColumnResizeMode value + */ + public void setColumnResizeMode(ColumnResizeMode mode) { + columnResizeMode = mode; + } + + /** + * Returns the current column resize mode. The default mode is {@link ColumnResizeMode.ANIMATED}. + * + * @return a ColumnResizeMode value + */ + public ColumnResizeMode getColumnResizeMode() { + return columnResizeMode; + } + @Override public void setStylePrimaryName(String style) { super.setStylePrimaryName(style); diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java index b8becd1c33..6bdcd1377b 100644 --- a/server/src/main/java/com/vaadin/ui/Grid.java +++ b/server/src/main/java/com/vaadin/ui/Grid.java @@ -85,6 +85,7 @@ import com.vaadin.server.communication.data.DataGenerator; import com.vaadin.server.communication.data.RpcDataProviderExtension; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.grid.ColumnResizeMode; import com.vaadin.shared.ui.grid.EditorClientRpc; import com.vaadin.shared.ui.grid.EditorServerRpc; import com.vaadin.shared.ui.grid.GridClientRpc; @@ -4544,6 +4545,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, private Object editedItemId = null; private boolean editorActive = false; + /** * True while the editor is storing the field values, i.e. commiting the * field group. @@ -4789,7 +4791,6 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, if (column != null && column.isResizable()) { column.getState().width = pixels; fireColumnResizeEvent(column, true); - markAsDirty(); } } }); @@ -5260,6 +5261,24 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return (GridState) super.getState(markAsDirty); } + /** + * Sets the column resize mode to use. The default mode is {@link ColumnResizeMode#ANIMATED}. + * + * @param mode a ColumnResizeMode value + */ + public void setColumnResizeMode(ColumnResizeMode mode) { + getState().columnResizeMode = mode; + } + + /** + * Returns the current column resize mode. The default mode is {@link ColumnResizeMode#ANIMATED}. + * + * @return a ColumnResizeMode value + */ + public ColumnResizeMode getColumnResizeMode() { + return getState(false).columnResizeMode; + } + /** * Creates a new column based on a property id and appends it as the last * column. diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java b/shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java new file mode 100644 index 0000000000..a19a2bb9eb --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared.ui.grid; + +/** + * Collection of modes used for resizing columns in the Grid. + */ +public enum ColumnResizeMode { + + /** + * When column resize mode is set to Animated, columns + * are resized as they are dragged. + */ + ANIMATED, + + /** + * When column resize mode is set to Simple, dragging to resize + * a column will show a marker, and the column will resize only + * after the mouse button or touch is released. + */ + SIMPLE + +} diff --git a/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java b/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java index f20f519439..7786b7e0f3 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java @@ -141,6 +141,11 @@ public class GridState extends TabIndexState { primaryStyleName = "v-grid"; } + /** + * Column resize mode in grid. + */ + public ColumnResizeMode columnResizeMode = ColumnResizeMode.ANIMATED; + /** * Columns in grid. */ diff --git a/themes/src/main/themes/VAADIN/themes/base/grid/grid.scss b/themes/src/main/themes/VAADIN/themes/base/grid/grid.scss index 983463381b..1a55cc2595 100644 --- a/themes/src/main/themes/VAADIN/themes/base/grid/grid.scss +++ b/themes/src/main/themes/VAADIN/themes/base/grid/grid.scss @@ -283,6 +283,22 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co user-select: none; } + .#{$primaryStyleName}-column-resize-simple-indicator { + position: absolute; + width: 3px; + top: 0px; + left: $v-grid-cell-padding-horizontal; + z-index: 9001; + background: #fff; + box-shadow: 0px 0px 5px #000; + + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + // Footer .#{$primaryStyleName}-footer { diff --git a/uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 18cfb56660..e3fdd68ed6 100644 --- a/uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -44,6 +44,7 @@ import com.vaadin.event.SelectionEvent.SelectionListener; import com.vaadin.event.SortEvent; import com.vaadin.event.SortEvent.SortListener; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.grid.ColumnResizeMode; import com.vaadin.shared.ui.grid.GridStaticCellType; import com.vaadin.shared.ui.grid.HeightMode; import com.vaadin.tests.components.AbstractComponentTest; @@ -1266,6 +1267,13 @@ public class GridBasicFeatures extends AbstractComponentTest { grid.getColumns().get(0).setMaximumWidth(30); } }, null); + + createBooleanAction("Simple resize mode", "Columns", false, new Command() { + @Override + public void execute(Grid g, Boolean value, Object data) { + g.setColumnResizeMode(value ? ColumnResizeMode.SIMPLE : ColumnResizeMode.ANIMATED); + } + }); } private static String getColumnProperty(int c) { diff --git a/uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java b/uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java new file mode 100644 index 0000000000..8e767eb033 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java @@ -0,0 +1,74 @@ +package com.vaadin.tests.components.grid.basicfeatures;/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +import java.util.List; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.components.grid.basicfeatures.element.CustomGridElement; + +@TestCategory("grid") +public class GridColumnResizeModeTest extends GridBasicFeaturesTest { + + @Before + public void before() { + openTestURL(); + } + + @Test + public void testSimpleResizeModeToggle() throws Exception { + + CustomGridElement grid = getGridElement(); + + List handles = grid.findElements(By.className("v-grid-column-resize-handle")); + WebElement handle = handles.get(1); + + Actions drag1 = new Actions(getDriver()).moveToElement(handle).clickAndHold(); + Actions drag2 = new Actions(getDriver()).moveByOffset(-50, 0); + Actions drag3 = new Actions(getDriver()).moveByOffset(100, 0); + Actions dragEndAction = new Actions(getDriver()).release().moveToElement(grid); + + selectMenuPath("Component", "Columns", "Simple resize mode"); + sleep(250); + + drag1.perform(); + sleep(500); + drag2.perform(); + sleep(500); + drag3.perform(); + sleep(500); + + // Make sure we find at least one simple resize mode splitter + assertElementPresent(By.className("v-grid-column-resize-simple-indicator")); + + dragEndAction.perform(); + + // Make sure it went away + assertElementNotPresent(By.className("v-grid-column-resize-simple-indicator")); + + // See that we got a resize event + sleep(500); + Assert.assertEquals("Log shows resize event", getLogRow(0), "3. ColumnResizeEvent: isUserOriginated? true"); + + } + +}