]> source.dussan.org Git - vaadin-framework.git/commitdiff
Implement ContextClickEvent for Table (#19042)
authorTeemu Suo-Anttila <teemusa@vaadin.com>
Thu, 1 Oct 2015 08:53:23 +0000 (11:53 +0300)
committerVaadin Code Review <review@vaadin.com>
Fri, 2 Oct 2015 08:17:15 +0000 (08:17 +0000)
This patch also introduces a testing infrastructure for context click
event and listener testing.

Change-Id: I3aa88758278c91086df3d0971edb34914a93fd29

client/src/com/vaadin/client/ui/table/TableConnector.java
server/src/com/vaadin/ui/Table.java
server/tests/src/com/vaadin/tests/server/component/table/TableContextClickTest.java [new file with mode: 0644]
shared/src/com/vaadin/shared/ui/table/TableConstants.java
shared/src/com/vaadin/shared/ui/table/TableServerRpc.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/contextclick/AbstractContextClickTest.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/contextclick/AbstractContextClickUI.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/contextclick/ListenerAddAndRemoveTest.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/contextclick/TableContextClick.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/contextclick/TableContextClickTest.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/contextclick/TableContextClickTestBase.java [new file with mode: 0644]

index 7bbda39c4354165063e195a87418d052640e74b4..70248d367c194c4e0e09a08922ce6f8333b82f0c 100644 (file)
@@ -22,7 +22,9 @@ import java.util.List;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.EventTarget;
 import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.event.dom.client.ContextMenuEvent;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.client.ApplicationConnection;
@@ -32,6 +34,7 @@ import com.vaadin.client.ConnectorHierarchyChangeEvent;
 import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
 import com.vaadin.client.DirectionalManagedLayout;
 import com.vaadin.client.HasComponentsConnector;
+import com.vaadin.client.MouseEventDetailsBuilder;
 import com.vaadin.client.Paintable;
 import com.vaadin.client.ServerConnector;
 import com.vaadin.client.TooltipInfo;
@@ -41,9 +44,14 @@ import com.vaadin.client.ui.AbstractFieldConnector;
 import com.vaadin.client.ui.PostLayoutListener;
 import com.vaadin.client.ui.VScrollTable;
 import com.vaadin.client.ui.VScrollTable.ContextMenuDetails;
+import com.vaadin.client.ui.VScrollTable.FooterCell;
+import com.vaadin.client.ui.VScrollTable.HeaderCell;
 import com.vaadin.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;
+import com.vaadin.shared.MouseEventDetails;
 import com.vaadin.shared.ui.Connect;
 import com.vaadin.shared.ui.table.TableConstants;
+import com.vaadin.shared.ui.table.TableConstants.Section;
+import com.vaadin.shared.ui.table.TableServerRpc;
 import com.vaadin.shared.ui.table.TableState;
 
 @Connect(com.vaadin.ui.Table.class)
@@ -74,6 +82,59 @@ public class TableConnector extends AbstractFieldConnector implements
         getWidget().onUnregister();
     }
 
+    @Override
+    protected void sendContextClickEvent(ContextMenuEvent event) {
+        EventTarget eventTarget = event.getNativeEvent().getEventTarget();
+        if (!Element.is(eventTarget)) {
+            super.sendContextClickEvent(event);
+            return;
+        }
+        Element e = Element.as(eventTarget);
+
+        Section section;
+        String colKey;
+        String rowKey = null;
+        if (getWidget().tFoot.getElement().isOrHasChild(e)) {
+            section = Section.FOOTER;
+            FooterCell w = WidgetUtil.findWidget(e, FooterCell.class);
+            colKey = w.getColKey();
+        } else if (getWidget().tHead.getElement().isOrHasChild(e)) {
+            section = Section.HEADER;
+            HeaderCell w = WidgetUtil.findWidget(e, HeaderCell.class);
+            colKey = w.getColKey();
+        } else if (getWidget().scrollBody.getElement().isOrHasChild(e)) {
+            section = Section.BODY;
+            VScrollTableRow w = WidgetUtil.findWidget(e, VScrollTableRow.class);
+            rowKey = w.getKey();
+            colKey = getWidget().tHead.getHeaderCell(
+                    getElementIndex(e, w.getElement())).getColKey();
+        } else {
+            super.sendContextClickEvent(event);
+            return;
+        }
+
+        MouseEventDetails details = MouseEventDetailsBuilder
+                .buildMouseEventDetails(event.getNativeEvent());
+
+        // Prevent browser default context menu
+        event.preventDefault();
+        event.stopPropagation();
+
+        getRpcProxy(TableServerRpc.class).contextClick(rowKey, colKey, section,
+                details);
+    }
+
+    private int getElementIndex(Element e,
+            com.google.gwt.user.client.Element element) {
+        int i = 0;
+        Element current = element.getFirstChildElement();
+        while (!current.isOrHasChild(e)) {
+            current = current.getNextSiblingElement();
+            ++i;
+        }
+        return i;
+    }
+
     /*
      * (non-Javadoc)
      * 
index 5f22ec46aba331cf17dd866181e23babdac56fc2..f7b0853ce9748a0de0b04b773a08a7b3577bcbaf 100644 (file)
@@ -46,6 +46,7 @@ import com.vaadin.data.util.converter.Converter;
 import com.vaadin.data.util.converter.ConverterUtil;
 import com.vaadin.event.Action;
 import com.vaadin.event.Action.Handler;
+import com.vaadin.event.ContextClickEvent;
 import com.vaadin.event.DataBoundTransferable;
 import com.vaadin.event.ItemClickEvent;
 import com.vaadin.event.ItemClickEvent.ItemClickListener;
@@ -65,6 +66,8 @@ import com.vaadin.server.Resource;
 import com.vaadin.shared.MouseEventDetails;
 import com.vaadin.shared.ui.MultiSelectMode;
 import com.vaadin.shared.ui.table.TableConstants;
+import com.vaadin.shared.ui.table.TableConstants.Section;
+import com.vaadin.shared.ui.table.TableServerRpc;
 import com.vaadin.shared.util.SharedUtil;
 import com.vaadin.ui.declarative.DesignAttributeHandler;
 import com.vaadin.ui.declarative.DesignContext;
@@ -595,6 +598,18 @@ public class Table extends AbstractSelect implements Action.Container,
      */
     public Table() {
         setRowHeaderMode(ROW_HEADER_MODE_HIDDEN);
+
+        registerRpc(new TableServerRpc() {
+
+            @Override
+            public void contextClick(String rowKey, String colKey,
+                    Section section, MouseEventDetails details) {
+                Object itemId = itemIdMapper.get(rowKey);
+                Object propertyId = columnIdMap.get(colKey);
+                fireEvent(new TableContextClickEvent(Table.this, details,
+                        itemId, propertyId, section));
+            }
+        });
     }
 
     /**
@@ -6377,6 +6392,57 @@ public class Table extends AbstractSelect implements Action.Container,
         return result;
     }
 
+    /* Context Click handling */
+
+    public static class TableContextClickEvent extends ContextClickEvent {
+
+        private final Object itemId;
+        private final Object propertyId;
+        private final Section section;
+
+        public TableContextClickEvent(Table source,
+                MouseEventDetails mouseEventDetails, Object itemId,
+                Object propertyId, Section section) {
+            super(source, mouseEventDetails);
+
+            this.itemId = itemId;
+            this.propertyId = propertyId;
+            this.section = section;
+        }
+
+        /**
+         * Returns the item id of context clicked row.
+         * 
+         * @return item id of clicked row; <code>null</code> if header or footer
+         */
+        public Object getItemId() {
+            return itemId;
+        }
+
+        /**
+         * Returns the property id of context clicked column.
+         * 
+         * @return property id
+         */
+        public Object getPropertyId() {
+            return propertyId;
+        }
+
+        /**
+         * Returns the clicked section of Table.
+         * 
+         * @return section of Table
+         */
+        public Section getSection() {
+            return section;
+        }
+
+        @Override
+        public Table getComponent() {
+            return (Table) super.getComponent();
+        }
+    }
+
     private final Logger getLogger() {
         if (logger == null) {
             logger = Logger.getLogger(Table.class.getName());
diff --git a/server/tests/src/com/vaadin/tests/server/component/table/TableContextClickTest.java b/server/tests/src/com/vaadin/tests/server/component/table/TableContextClickTest.java
new file mode 100644 (file)
index 0000000..d96a5d6
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2014 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.tests.server.component.table;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.event.ContextClickEvent;
+import com.vaadin.event.ContextClickEvent.ContextClickListener;
+import com.vaadin.shared.ui.table.TableConstants.Section;
+import com.vaadin.ui.Table;
+
+public class TableContextClickTest extends Table {
+
+    private String error = null;
+    private boolean handled = false;
+
+    @Test
+    public void testContextClickListenerWithTableEvent() {
+        addContextClickListener(new ContextClickListener() {
+
+            @Override
+            public void contextClick(ContextClickEvent event) {
+                if (!(event instanceof TableContextClickEvent)) {
+                    return;
+                }
+
+                TableContextClickEvent e = (TableContextClickEvent) event;
+                if (e.getSection() != Section.BODY) {
+                    error = "Event section was not BODY.";
+                }
+                handled = true;
+            }
+        });
+        fireEvent(new TableContextClickEvent(this, null, null, null,
+                Section.BODY));
+
+        if (error != null) {
+            Assert.fail(error);
+        } else if (!handled) {
+            Assert.fail("Event was not handled by the ContextClickListener");
+        }
+    }
+}
index e782492e9d859d3ab056acbbe911a6b45c7412b6..9117729eb1d456c8a0049e2d23bcb85962ff73eb 100644 (file)
@@ -18,6 +18,13 @@ package com.vaadin.shared.ui.table;
 import java.io.Serializable;
 
 public class TableConstants implements Serializable {
+    /**
+     * Enum describing different sections of Table.
+     */
+    public enum Section {
+        HEADER, BODY, FOOTER
+    }
+
     public static final String ITEM_CLICK_EVENT_ID = "itemClick";
     public static final String HEADER_CLICK_EVENT_ID = "handleHeaderClick";
     public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick";
diff --git a/shared/src/com/vaadin/shared/ui/table/TableServerRpc.java b/shared/src/com/vaadin/shared/ui/table/TableServerRpc.java
new file mode 100644 (file)
index 0000000..bfd6f54
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2014 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.table;
+
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.shared.ui.table.TableConstants.Section;
+
+/**
+ * Client-to-server RPC interface for the Table component
+ * 
+ * @since
+ * @author Vaadin Ltd
+ */
+public interface TableServerRpc extends ServerRpc {
+
+    /**
+     * Informs the server that a context click happened inside of Table
+     */
+    public void contextClick(String rowKey, String colKey, Section section,
+            MouseEventDetails details);
+
+}
diff --git a/uitest/src/com/vaadin/tests/contextclick/AbstractContextClickTest.java b/uitest/src/com/vaadin/tests/contextclick/AbstractContextClickTest.java
new file mode 100644 (file)
index 0000000..2323d0c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2000-2014 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.tests.contextclick;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.Point;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.remote.DesiredCapabilities;
+
+import com.vaadin.testbench.elements.AbstractComponentElement;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.parallel.BrowserUtil;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public abstract class AbstractContextClickTest extends MultiBrowserTest {
+
+    @Override
+    public List<DesiredCapabilities> getBrowsersToTest() {
+        return getBrowsersSupportingContextMenu();
+    }
+
+    @Test
+    public void testDefaultListener() {
+        openTestURL();
+
+        addOrRemoveDefaultListener();
+
+        assertDefaultContextClickListener(1);
+    }
+
+    protected void assertNoContextClickHandler() {
+        AbstractComponentElement component = $(AbstractComponentElement.class)
+                .id("testComponent");
+
+        String log = getLogRow(0);
+
+        contextClick(component);
+
+        assertEquals("Log entry without a context click listener.", log,
+                getLogRow(0));
+
+    }
+
+    protected void assertDefaultContextClickListener(int index) {
+        AbstractComponentElement component = $(AbstractComponentElement.class)
+                .id("testComponent");
+
+        contextClick(component);
+
+        Point l = component.getLocation();
+
+        int drift = 0;
+        // IE 10 and 11 report different Y location.
+        if (BrowserUtil.isIE(getDesiredCapabilities(), 10)
+                || BrowserUtil.isIE(getDesiredCapabilities(), 11)) {
+            drift = 1;
+        }
+
+        assertEquals(index + ". ContextClickEvent: (" + (l.getX() + 10) + ", "
+                + (l.getY() + 10 + drift) + ")", getLogRow(0));
+    }
+
+    protected void addOrRemoveDefaultListener() {
+        $(ButtonElement.class).caption("Add/Remove default listener").first()
+                .click();
+    }
+
+    protected void addOrRemoveTypedListener() {
+        $(ButtonElement.class).caption("Add/Remove typed listener").first()
+                .click();
+    }
+
+    /**
+     * Performs a context click followed by a regular click. This prevents
+     * browser context menu from blocking future operations.
+     * 
+     * @param e
+     *            web element
+     */
+    protected void contextClick(WebElement e) {
+        new Actions(getDriver()).moveToElement(e, 10, 10).contextClick()
+                .perform();
+        new Actions(getDriver()).moveToElement(e, 5, 5).click().perform();
+    }
+}
diff --git a/uitest/src/com/vaadin/tests/contextclick/AbstractContextClickUI.java b/uitest/src/com/vaadin/tests/contextclick/AbstractContextClickUI.java
new file mode 100644 (file)
index 0000000..9a0ef31
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2014 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.tests.contextclick;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.event.ContextClickEvent;
+import com.vaadin.event.ContextClickEvent.ContextClickListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+
+@Theme("valo")
+public abstract class AbstractContextClickUI<T extends AbstractComponent, E extends ContextClickEvent>
+        extends AbstractTestUIWithLog {
+
+    private final class ListenerHandler implements Button.ClickListener {
+        private boolean hasListener = false;
+        private final ContextClickListener listener;
+
+        public ListenerHandler(ContextClickListener listener) {
+            this.listener = listener;
+        }
+
+        @Override
+        public void buttonClick(ClickEvent event) {
+            if (!hasListener) {
+                testComponent.addContextClickListener(listener);
+                event.getButton().setDescription("Remove listener");
+                hasListener = true;
+            } else {
+                testComponent.removeContextClickListener(listener);
+                event.getButton().setDescription("Add listener");
+                hasListener = false;
+            }
+        }
+    }
+
+    protected T testComponent;
+    private ContextClickListener defaultListener = new ContextClickListener() {
+
+        @Override
+        public void contextClick(ContextClickEvent event) {
+            log("ContextClickEvent: (" + event.getClientX() + ", "
+                    + event.getClientY() + ")");
+        }
+    };
+
+    private ContextClickListener typedListener = new ContextClickListener() {
+
+        @Override
+        public void contextClick(ContextClickEvent event) {
+            try {
+                E typedEvent = (E) event;
+                handleContextClickEvent(typedEvent);
+            } catch (Exception e) {
+                log("UNEXPECTED EVENT TYPE!");
+            }
+        }
+    };
+
+    @Override
+    protected void setup(VaadinRequest request) {
+        testComponent = createTestComponent();
+        testComponent.setId("testComponent");
+
+        addComponent(testComponent);
+
+        addComponent(new Button("Add/Remove default listener",
+                new ListenerHandler(defaultListener)));
+        addComponent(new Button("Add/Remove typed listener",
+                new ListenerHandler(typedListener)));
+    }
+
+    protected abstract T createTestComponent();
+
+    protected abstract void handleContextClickEvent(E event);
+}
diff --git a/uitest/src/com/vaadin/tests/contextclick/ListenerAddAndRemoveTest.java b/uitest/src/com/vaadin/tests/contextclick/ListenerAddAndRemoveTest.java
new file mode 100644 (file)
index 0000000..01fbd87
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2014 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.tests.contextclick;
+
+import org.junit.Test;
+
+public class ListenerAddAndRemoveTest extends TableContextClickTestBase {
+
+    @Test
+    public void testAddAndRemoveListeners() {
+        openTestURL();
+
+        // Add typed listener
+        addOrRemoveTypedListener();
+
+        // Add default listener
+        addOrRemoveDefaultListener();
+
+        // Remove the default listener
+        addOrRemoveDefaultListener();
+
+        // Check that typed listener is still working
+        assertTypedContextClickListener(1);
+
+        // Re-add the default listener
+        addOrRemoveDefaultListener();
+
+        // Remove typed listener
+        addOrRemoveTypedListener();
+
+        // Check that default listener still works
+        assertDefaultContextClickListener(3);
+
+        // Remove default listener
+        addOrRemoveDefaultListener();
+
+        // Assert no listeners present.
+        assertNoContextClickHandler();
+
+        // Re-add typed listener
+        addOrRemoveTypedListener();
+
+        assertTypedContextClickListener(4);
+    }
+}
diff --git a/uitest/src/com/vaadin/tests/contextclick/TableContextClick.java b/uitest/src/com/vaadin/tests/contextclick/TableContextClick.java
new file mode 100644 (file)
index 0000000..8d75dd6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2014 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.tests.contextclick;
+
+import com.vaadin.data.Item;
+import com.vaadin.shared.ui.table.TableConstants.Section;
+import com.vaadin.tests.util.PersonContainer;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableContextClickEvent;
+
+public class TableContextClick extends
+        AbstractContextClickUI<Table, TableContextClickEvent> {
+
+    @Override
+    protected Table createTestComponent() {
+        Table table = new Table();
+        table.setContainerDataSource(PersonContainer.createWithTestData());
+        table.setFooterVisible(true);
+        return table;
+    }
+
+    @Override
+    protected void handleContextClickEvent(TableContextClickEvent event) {
+        String value = "";
+        Object propertyId = event.getPropertyId();
+        if (event.getItemId() != null) {
+            Item item = event.getComponent().getContainerDataSource()
+                    .getItem(event.getItemId());
+            value += item.getItemProperty("firstName").getValue() + " ";
+            value += item.getItemProperty("lastName").getValue();
+        } else if (event.getSection() == Section.HEADER) {
+            value = testComponent.getColumnHeader(propertyId);
+        } else if (event.getSection() == Section.FOOTER) {
+            value = testComponent.getColumnFooter(propertyId);
+        }
+        log("ContextClickEvent value: " + value + ", propertyId: " + propertyId
+                + ", section: " + event.getSection());
+    }
+}
diff --git a/uitest/src/com/vaadin/tests/contextclick/TableContextClickTest.java b/uitest/src/com/vaadin/tests/contextclick/TableContextClickTest.java
new file mode 100644 (file)
index 0000000..51efbf9
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2000-2014 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.tests.contextclick;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.TableElement;
+
+public class TableContextClickTest extends TableContextClickTestBase {
+
+    @Test
+    public void testBodyContextClickWithTypedListener() {
+        openTestURL();
+
+        addOrRemoveTypedListener();
+
+        assertTypedContextClickListener(1);
+    }
+
+    @Test
+    public void testHeaderContextClickWithTypedListener() {
+        openTestURL();
+
+        addOrRemoveTypedListener();
+
+        contextClick($(TableElement.class).first().getHeaderCell(0));
+
+        assertEquals(
+                "1. ContextClickEvent value: address, propertyId: address, section: HEADER",
+                getLogRow(0));
+
+        contextClick($(TableElement.class).first().getHeaderCell(3));
+
+        assertEquals(
+                "2. ContextClickEvent value: lastName, propertyId: lastName, section: HEADER",
+                getLogRow(0));
+    }
+
+    @Test
+    public void testFooterContextClickWithTypedListener() {
+        openTestURL();
+
+        addOrRemoveTypedListener();
+
+        contextClick($(TableElement.class).first().getFooterCell(0));
+
+        assertEquals(
+                "1. ContextClickEvent value: null, propertyId: address, section: FOOTER",
+                getLogRow(0));
+
+        contextClick($(TableElement.class).first().getFooterCell(3));
+
+        assertEquals(
+                "2. ContextClickEvent value: null, propertyId: lastName, section: FOOTER",
+                getLogRow(0));
+    }
+
+}
diff --git a/uitest/src/com/vaadin/tests/contextclick/TableContextClickTestBase.java b/uitest/src/com/vaadin/tests/contextclick/TableContextClickTestBase.java
new file mode 100644 (file)
index 0000000..e3f4647
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2014 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.tests.contextclick;
+
+import static org.junit.Assert.assertEquals;
+
+import com.vaadin.testbench.elements.TableElement;
+
+public abstract class TableContextClickTestBase extends
+        AbstractContextClickTest {
+
+    @Override
+    protected Class<?> getUIClass() {
+        return TableContextClick.class;
+    }
+
+    protected void assertTypedContextClickListener(int startIndex) {
+        contextClick($(TableElement.class).first().getCell(0, 0));
+
+        assertEquals(
+                (startIndex++)
+                        + ". ContextClickEvent value: Lisa Schneider, propertyId: address, section: BODY",
+                getLogRow(0));
+
+        contextClick($(TableElement.class).first().getCell(0, 3));
+
+        assertEquals(
+                startIndex
+                        + ". ContextClickEvent value: Lisa Schneider, propertyId: lastName, section: BODY",
+                getLogRow(0));
+    }
+}