]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add lazy/simple resize mode to Grid (#20108)
authorPatrik Lindström <patrik@vaadin.com>
Wed, 2 Nov 2016 09:54:49 +0000 (11:54 +0200)
committerPekka Hyvönen <pekka@vaadin.com>
Thu, 17 Nov 2016 10:05:47 +0000 (10:05 +0000)
Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4

client/src/main/java/com/vaadin/client/connectors/GridConnector.java
client/src/main/java/com/vaadin/client/ui/dd/DragHandle.java
client/src/main/java/com/vaadin/client/widgets/Grid.java
server/src/main/java/com/vaadin/ui/Grid.java
shared/src/main/java/com/vaadin/shared/ui/grid/ColumnResizeMode.java [new file with mode: 0644]
shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java
themes/src/main/themes/VAADIN/themes/base/grid/grid.scss
uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java
uitest/src/test/java/com/vaadin/tests/components/grid/basicfeatures/GridColumnResizeModeTest.java [new file with mode: 0644]

index ddde546da9210102c392ef21877a187d21582bae..e329d4a4c812065c36e57a80e13a77bac14b4eb5 100644 (file)
@@ -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);
index a983337c229a3db9527c3ee83eb77e4ea195ff51..5aec3b3fe958eb8c5e27ca144a8a269dbe1a35b8 100644 (file)
@@ -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.
      *
index 2b193a55db3e55661795056bc08f1d0e8c378193..3290aa8a481581f4819df70d30dfc2e7a0d0a7df 100644 (file)
@@ -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<T> extends ResizeComposite implements HasSelectionHandlers<T>,
                         && 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<?, T> 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<?, T> c : getVisibleColumns()) {
-                                        if (selectionColumn == c) {
-                                            // Don't modify selection column.
-                                            continue;
-                                        }
-
-                                        if (c.getWidth() < 0) {
-                                            c.setWidth(c.getWidthActual());
-                                            fireEvent(new ColumnResizeEvent<T>(
-                                                    c));
-                                        }
-                                    }
+                    // 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;
+                                }
 
-                                    WidgetUtil.setTextSelectionEnabled(
-                                            getElement(), false);
+                                if (c.getWidth() < 0) {
+                                    c.setWidth(c.getWidthActual());
+                                    fireEvent(new ColumnResizeEvent<T>(c));
                                 }
+                            }
 
-                                @Override
-                                public void onComplete() {
-                                    fireEvent(new ColumnResizeEvent<T>(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<T>(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<T>(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<T> extends ResizeComposite implements HasSelectionHandlers<T>,
         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);
index b8becd1c338638936f5254e9ee0b91cb23d19fb2..6bdcd1377b0487e9a04e63a068708fe7943961f8 100644 (file)
@@ -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 (file)
index 0000000..a19a2bb
--- /dev/null
@@ -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
+
+}
index f20f519439880d251f3785bf30f74b52cce5150b..7786b7e0f36091ce44515fa2b5b22c251f43507e 100644 (file)
@@ -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.
      */
index 983463381b6b465caa6120a98d1da9c8e32e0e58..1a55cc2595da8adb5c075b813842858ac473e2b8 100644 (file)
@@ -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 {
index 18cfb56660319f4547178db73ce9433bf43a5fbb..e3fdd68ed60bc1c18b1e5c7839b78f0a7bfe593a 100644 (file)
@@ -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> {
                         grid.getColumns().get(0).setMaximumWidth(30);
                     }
                 }, null);
+
+        createBooleanAction("Simple resize mode", "Columns", false, new Command<Grid, Boolean>() {
+            @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 (file)
index 0000000..8e767eb
--- /dev/null
@@ -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<WebElement> 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");
+
+    }
+
+}