]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add ItemClick events to Grid
authorTeemu Suo-Anttila <teemusa@vaadin.com>
Thu, 8 Sep 2016 13:46:35 +0000 (16:46 +0300)
committerVaadin Code Review <review@vaadin.com>
Mon, 12 Sep 2016 07:41:18 +0000 (07:41 +0000)
Change-Id: I9d761245e99cde62d0e56b89e5cbb0398fd4c363

client/src/main/java/com/vaadin/client/connectors/grid/GridConnector.java
server/src/main/java/com/vaadin/ui/Grid.java
uitest/src/main/java/com/vaadin/tests/components/grid/basics/GridBasics.java
uitest/src/test/java/com/vaadin/tests/components/grid/basics/GridBasicDetailsTest.java

index 43be3f0623db09f17ceec98b331caa97bf550757..863cee0c883e48e7711fc63438452c8592f0a271 100644 (file)
@@ -22,17 +22,23 @@ import java.util.List;
 import java.util.Map;
 
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.vaadin.client.ComponentConnector;
 import com.vaadin.client.ConnectorHierarchyChangeEvent;
 import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
 import com.vaadin.client.DeferredWorker;
 import com.vaadin.client.HasComponentsConnector;
+import com.vaadin.client.MouseEventDetailsBuilder;
 import com.vaadin.client.TooltipInfo;
 import com.vaadin.client.connectors.AbstractListingConnector;
 import com.vaadin.client.data.DataSource;
 import com.vaadin.client.ui.SimpleManagedLayout;
 import com.vaadin.client.widget.grid.CellReference;
+import com.vaadin.client.widget.grid.events.BodyClickHandler;
+import com.vaadin.client.widget.grid.events.BodyDoubleClickHandler;
+import com.vaadin.client.widget.grid.events.GridClickEvent;
+import com.vaadin.client.widget.grid.events.GridDoubleClickEvent;
 import com.vaadin.client.widget.grid.selection.ClickSelectHandler;
 import com.vaadin.client.widget.grid.selection.SpaceSelectHandler;
 import com.vaadin.client.widget.grid.sort.SortEvent;
@@ -43,6 +49,7 @@ import com.vaadin.shared.data.selection.SelectionModel;
 import com.vaadin.shared.data.selection.SelectionModel.Single;
 import com.vaadin.shared.data.sort.SortDirection;
 import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.grid.GridConstants;
 import com.vaadin.shared.ui.grid.GridServerRpc;
 import com.vaadin.shared.ui.grid.GridState;
 
@@ -59,12 +66,40 @@ public class GridConnector
         extends AbstractListingConnector<SelectionModel<JsonObject>>
         implements HasComponentsConnector, SimpleManagedLayout, DeferredWorker {
 
+    private class ItemClickHandler
+            implements BodyClickHandler, BodyDoubleClickHandler {
+
+        @Override
+        public void onClick(GridClickEvent event) {
+            if (hasEventListener(GridConstants.ITEM_CLICK_EVENT_ID)) {
+                fireItemClick(event.getTargetCell(), event.getNativeEvent());
+            }
+        }
+
+        @Override
+        public void onDoubleClick(GridDoubleClickEvent event) {
+            if (hasEventListener(GridConstants.ITEM_CLICK_EVENT_ID)) {
+                fireItemClick(event.getTargetCell(), event.getNativeEvent());
+            }
+        }
+
+        private void fireItemClick(CellReference<?> cell,
+                NativeEvent mouseEvent) {
+            String rowKey = getRowKey((JsonObject) cell.getRow());
+            String columnId = columnToIdMap.get(cell.getColumn());
+            getRpcProxy(GridServerRpc.class).itemClick(rowKey, columnId,
+                    MouseEventDetailsBuilder
+                            .buildMouseEventDetails(mouseEvent));
+        }
+    }
+
     /* Map to keep track of all added columns */
     private Map<Column<?, JsonObject>, String> columnToIdMap = new HashMap<>();
     /* Child component list for HasComponentsConnector */
     private List<ComponentConnector> childComponents;
     private SpaceSelectHandler<JsonObject> spaceSelectHandler;
     private ClickSelectHandler<JsonObject> clickSelectHandler;
+    private ItemClickHandler itemClickHandler = new ItemClickHandler();
 
     /**
      * Gets the string identifier of a {@link Column} in this grid.
@@ -114,6 +149,10 @@ public class GridConnector
             return null;
         });
 
+        /* Item click events */
+        getWidget().addBodyClickHandler(itemClickHandler);
+        getWidget().addBodyDoubleClickHandler(itemClickHandler);
+
         layout();
     }
 
index 2a4f473536a502141946a5af0730ec3e2329dc14..c895ad08c3a937877635176d5919d8fb1e4a6930 100644 (file)
@@ -16,6 +16,7 @@
 package com.vaadin.ui;
 
 import java.io.Serializable;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -33,13 +34,17 @@ import java.util.function.Function;
 import java.util.stream.Stream;
 
 import com.vaadin.data.selection.SingleSelection;
+import com.vaadin.event.ConnectorEvent;
+import com.vaadin.event.EventListener;
 import com.vaadin.server.KeyMapper;
 import com.vaadin.server.data.SortOrder;
 import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.Registration;
 import com.vaadin.shared.data.DataCommunicatorConstants;
 import com.vaadin.shared.data.selection.SelectionModel;
 import com.vaadin.shared.data.sort.SortDirection;
 import com.vaadin.shared.ui.grid.ColumnState;
+import com.vaadin.shared.ui.grid.GridConstants;
 import com.vaadin.shared.ui.grid.GridConstants.Section;
 import com.vaadin.shared.ui.grid.GridServerRpc;
 import com.vaadin.shared.ui.grid.GridState;
@@ -47,6 +52,7 @@ import com.vaadin.shared.ui.grid.HeightMode;
 import com.vaadin.ui.renderers.AbstractRenderer;
 import com.vaadin.ui.renderers.Renderer;
 import com.vaadin.ui.renderers.TextRenderer;
+import com.vaadin.util.ReflectTools;
 
 import elemental.json.Json;
 import elemental.json.JsonObject;
@@ -64,6 +70,95 @@ import elemental.json.JsonValue;
 public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
         implements HasComponents {
 
+    @Deprecated
+    private static final Method ITEM_CLICK_METHOD = ReflectTools
+            .findMethod(ItemClickListener.class, "accept", ItemClick.class);
+
+    /**
+     * An event fired when an item in the Grid has been clicked.
+     *
+     * @param <T>
+     *            the grid bean type
+     */
+    public static class ItemClick<T> extends ConnectorEvent {
+
+        private final T item;
+        private final Column<T, ?> column;
+        private final MouseEventDetails mouseEventDetails;
+
+        /**
+         * Creates a new {@code ItemClick} event containing the given item and
+         * Column originating from the given Grid.
+         *
+         */
+        public ItemClick(Grid<T> source, Column<T, ?> column, T item,
+                MouseEventDetails mouseEventDetails) {
+            super(source);
+            this.column = column;
+            this.item = item;
+            this.mouseEventDetails = mouseEventDetails;
+        }
+
+        /**
+         * Returns the clicked item.
+         *
+         * @return the clicked item
+         */
+        public T getItem() {
+            return item;
+        }
+
+        /**
+         * Returns the clicked column.
+         *
+         * @return the clicked column
+         */
+        public Column<T, ?> getColumn() {
+            return column;
+        }
+
+        /**
+         * Returns the source Grid.
+         *
+         * @return the grid
+         */
+        @Override
+        public Grid<T> getSource() {
+            return (Grid<T>) super.getSource();
+        }
+
+        /**
+         * Returns the mouse event details.
+         *
+         * @return the mouse event details
+         */
+        public MouseEventDetails getMouseEventDetails() {
+            return mouseEventDetails;
+        }
+    }
+
+    /**
+     * A listener for item click events.
+     *
+     * @param <T>
+     *            the grid bean type
+     *
+     * @see ItemClick
+     * @see Registration
+     */
+    @FunctionalInterface
+    public interface ItemClickListener<T> extends EventListener<ItemClick<T>> {
+        /**
+         * Invoked when this listener receives a item click event from a Grid to
+         * which it has been added.
+         *
+         * @param event
+         *            the received event, not null
+         */
+        @Override
+        public void accept(ItemClick<T> event);
+    }
+
     /**
      * A callback interface for generating style names for an item.
      *
@@ -179,7 +274,10 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
         @Override
         public void itemClick(String rowKey, String columnId,
                 MouseEventDetails details) {
-            // TODO Auto-generated method stub
+            Column<T, ?> column = columnKeys.containsKey(columnId)
+                    ? columnKeys.get(columnId) : null;
+            T item = getDataCommunicator().getKeyMapper().get(rowKey);
+            fireEvent(new ItemClick<>(Grid.this, column, item, details));
         }
 
         @Override
@@ -1019,6 +1117,22 @@ public class Grid<T> extends AbstractListing<T, SelectionModel<T>>
         return descriptionGenerator;
     }
 
+    /**
+     * Adds an item click listener. The listener is called when an item of this
+     * {@code Grid} is clicked.
+     *
+     * @param listener
+     *            the item click listener, not null
+     * @return a registration for the listener
+     */
+    public Registration addItemClickListener(
+            ItemClickListener<? super T> listener) {
+        Objects.requireNonNull(listener, "listener cannot be null");
+        addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClick.class,
+                listener, ITEM_CLICK_METHOD);
+        return () -> removeListener(ItemClick.class, listener);
+    }
+
     @Override
     protected GridState getState() {
         return getState(true);
index 8c4aa4eec05200dea0de335cfbc3db3e64941161..c82a434e2382ff0071ea8b49c0ef3470061c9a9f 100644 (file)
@@ -11,16 +11,17 @@ import java.util.stream.Stream;
 import com.vaadin.annotations.Widgetset;
 import com.vaadin.data.selection.SingleSelection;
 import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.Registration;
 import com.vaadin.shared.ui.grid.HeightMode;
 import com.vaadin.tests.components.AbstractTestUIWithLog;
 import com.vaadin.ui.Button;
 import com.vaadin.ui.Component;
-import com.vaadin.ui.CssLayout;
 import com.vaadin.ui.Grid;
 import com.vaadin.ui.Grid.DetailsGenerator;
 import com.vaadin.ui.Grid.StyleGenerator;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.MenuBar;
+import com.vaadin.ui.MenuBar.Command;
 import com.vaadin.ui.MenuBar.MenuItem;
 import com.vaadin.ui.Notification;
 import com.vaadin.ui.Panel;
@@ -49,7 +50,7 @@ public class GridBasics extends AbstractTestUIWithLog {
 
         @Override
         public Component apply(DataObject dataObj) {
-            CssLayout cssLayout = new CssLayout();
+            VerticalLayout cssLayout = new VerticalLayout();
             cssLayout.setHeight("200px");
             cssLayout.setWidth("100%");
 
@@ -201,6 +202,33 @@ public class GridBasics extends AbstractTestUIWithLog {
                                         + t.getRowNumber() + ", Column 0"
                                         : null)))
                 .setCheckable(true);
+        stateMenu.addItem("Item click listener", new Command() {
+
+            private Registration registration = null;
+
+            @Override
+            public void menuSelected(MenuItem selectedItem) {
+                removeRegistration();
+                if (selectedItem.isChecked()) {
+                    registration = grid.addItemClickListener(e -> {
+                        grid.setDetailsVisible(e.getItem(),
+                                !grid.isDetailsVisible(e.getItem()));
+                        log("Item click on row " + e.getItem().getRowNumber()
+                                + ", Column '" + e.getColumn().getCaption()
+                                + "'");
+                    });
+                    log("Registered an item click listener.");
+                }
+            }
+
+            private void removeRegistration() {
+                if (registration != null) {
+                    registration.remove();
+                    registration = null;
+                    log("Removed an item click listener.");
+                }
+            }
+        }).setCheckable(true);
     }
 
     private void createRowStyleMenu(MenuItem rowStyleMenu) {
index a0f36703da592909304f5b3b05f93a94f18dd13c..c1f28e27cff7366ee4ac118b40ae6a9460282b06 100644 (file)
@@ -298,4 +298,26 @@ public class GridBasicDetailsTest extends GridBasicsTest {
         assertFalse(logContainsText("AssertionError"));
     }
 
+    @Test
+    public void testOpenDetailsWithItemClickHandler() {
+        selectMenuPath(DETAILS_GENERATOR_PERSISTING);
+        selectMenuPath("Component", "State", "Item click listener");
+        assertTrue("No item click listener registered",
+                logContainsText("Registered an item click listener."));
+        getGridElement().getCell(0, 1).click();
+        assertTrue("Details should open on click",
+                getGridElement().getDetails(0).getText().contains("One"));
+        assertTrue("Item click listener should log itself",
+                logContainsText("Item click on row 0, Column 'Column 1'"));
+
+        selectMenuPath("Component", "State", "Item click listener");
+        assertTrue("No removal of item click listener logged",
+                logContainsText("Removed an item click listener."));
+
+        getGridElement().getCell(0, 1).click();
+        assertTrue(
+                "Details should remain open, no item click listener to hide it",
+                getGridElement().getDetails(0).getText().contains("One"));
+    }
+
 }