summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeikki Ohinmaa <heikki@vaadin.com>2014-07-23 11:38:27 +0300
committerBogdan Udrescu <bogdan@vaadin.com>2014-07-29 17:10:19 +0300
commit6f3aec50bfb17d14c75318f0172c45695c22a811 (patch)
tree14cfa68c1b58f66e17195490213ee8938946ee3c
parent2ed3a310ca9e32f255602139eb1b08bfdfe2f25f (diff)
downloadvaadin-framework-6f3aec50bfb17d14c75318f0172c45695c22a811.tar.gz
vaadin-framework-6f3aec50bfb17d14c75318f0172c45695c22a811.zip
Context menu is not shown in Table body on mobile browsers (#13694)
Change-Id: I095401164a931f3a69dea91037a6cbf35b197121
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java520
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TabletContextMenu.java139
2 files changed, 449 insertions, 210 deletions
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 270661fe31..7d4b904515 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -47,8 +47,6 @@ import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.ContextMenuEvent;
-import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
@@ -103,31 +101,160 @@ import com.vaadin.shared.ui.table.TableConstants;
/**
* VScrollTable
- *
+ *
* VScrollTable is a FlowPanel having two widgets in it: * TableHead component *
* ScrollPanel
- *
+ *
* TableHead contains table's header and widgets + logic for resizing,
* reordering and hiding columns.
- *
+ *
* ScrollPanel contains VScrollTableBody object which handles content. To save
* some bandwidth and to improve clients responsiveness with loads of data, in
* VScrollTableBody all rows are not necessary rendered. There are "spacers" in
* VScrollTableBody to use the exact same space as non-rendered rows would use.
* This way we can use seamlessly traditional scrollbars and scrolling to fetch
* more rows instead of "paging".
- *
+ *
* In VScrollTable we listen to scroll events. On horizontal scrolling we also
* update TableHeads scroll position which has its scrollbars hidden. On
* vertical scroll events we will check if we are reaching the end of area where
* we have rows rendered and
- *
+ *
* TODO implement unregistering for child components in Cells
*/
public class VScrollTable extends FlowPanel implements HasWidgets,
ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable,
ActionOwner, SubPartAware {
+ /**
+ * Simple interface for parts of the table capable of owning a context menu.
+ *
+ * @author Vaadin Ltd
+ */
+ private interface ContextMenuOwner {
+ public void showContextMenu(Event event);
+ }
+
+ /**
+ * Handles showing context menu on "long press" from a touch screen.
+ *
+ * @author Vaadin Ltd
+ */
+ private class TouchContextProvider {
+ private static final int TOUCH_CONTEXT_MENU_TIMEOUT = 500;
+ private Timer contextTouchTimeout;
+
+ private Event touchStart;
+ private int touchStartY;
+ private int touchStartX;
+
+ private ContextMenuOwner target;
+
+ /**
+ * Initializes a handler for a certain context menu owner.
+ *
+ * @param target
+ * the owner of the context menu
+ */
+ public TouchContextProvider(ContextMenuOwner target) {
+ this.target = target;
+ }
+
+ /**
+ * Cancels the current context touch timeout.
+ */
+ public void cancel() {
+ if (contextTouchTimeout != null) {
+ contextTouchTimeout.cancel();
+ contextTouchTimeout = null;
+ }
+ touchStart = null;
+ }
+
+ /**
+ * A function to handle touch context events in a table.
+ *
+ * @param event
+ * browser event to handle
+ */
+ public void handleTouchEvent(final Event event) {
+ int type = event.getTypeInt();
+
+ switch (type) {
+ case Event.ONCONTEXTMENU:
+ target.showContextMenu(event);
+ break;
+ case Event.ONTOUCHSTART:
+ // save position to fields, touches in events are same
+ // instance during the operation.
+ touchStart = event;
+
+ Touch touch = event.getChangedTouches().get(0);
+ touchStartX = touch.getClientX();
+ touchStartY = touch.getClientY();
+
+ if (contextTouchTimeout == null) {
+ contextTouchTimeout = new Timer() {
+
+ @Override
+ public void run() {
+ if (touchStart != null) {
+ // Open the context menu if finger
+ // is held in place long enough.
+ target.showContextMenu(touchStart);
+ event.preventDefault();
+ touchStart = null;
+ }
+ }
+ };
+ }
+ contextTouchTimeout.schedule(TOUCH_CONTEXT_MENU_TIMEOUT);
+ break;
+ case Event.ONTOUCHCANCEL:
+ case Event.ONTOUCHEND:
+ cancel();
+ break;
+ case Event.ONTOUCHMOVE:
+ if (isSignificantMove(event)) {
+ // Moved finger before the context menu timer
+ // expired, so let the browser handle the event.
+ cancel();
+ }
+ }
+ }
+
+ /**
+ * Calculates how many pixels away the user's finger has traveled. This
+ * reduces the chance of small non-intentional movements from canceling
+ * the long press detection.
+ *
+ * @param event
+ * the Event for which to check the move distance
+ * @return true if this is considered an intentional move by the user
+ */
+ protected boolean isSignificantMove(Event event) {
+ if (touchStart == null) {
+ // no touch start
+ return false;
+ }
+
+ // Calculate the distance between touch start and the current touch
+ // position
+ Touch touch = event.getChangedTouches().get(0);
+ int deltaX = touch.getClientX() - touchStartX;
+ int deltaY = touch.getClientY() - touchStartY;
+ int delta = deltaX * deltaX + deltaY * deltaY;
+
+ // Compare to the square of the significant move threshold to remove
+ // the need for a square root
+ if (delta > TouchScrollDelegate.SIGNIFICANT_MOVE_THRESHOLD
+ * TouchScrollDelegate.SIGNIFICANT_MOVE_THRESHOLD) {
+ return true;
+ }
+ return false;
+ }
+ }
+
public static final String STYLENAME = "v-table";
public enum SelectMode {
@@ -264,7 +391,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* The last known row height used to preserve the height of a table with
* custom row heights and a fixed page length after removing the last row
* from the table.
- *
+ *
* A new VScrollTableBody instance is created every time the number of rows
* changes causing {@link VScrollTableBody#rowHeight} to be discarded and
* the height recalculated by {@link VScrollTableBody#getRowHeight(boolean)}
@@ -308,7 +435,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see java.lang.Object#toString()
*/
@@ -369,9 +496,34 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/** For internal use only. May be removed or replaced in the future. */
public final TableFooter tFoot = new TableFooter();
+ /** Handles context menu for table body */
+ private ContextMenuOwner contextMenuOwner = new ContextMenuOwner() {
+
+ @Override
+ public void showContextMenu(Event event) {
+ int left = Util.getTouchOrMouseClientX(event);
+ int top = Util.getTouchOrMouseClientY(event);
+ boolean menuShown = handleBodyContextMenu(left, top);
+ if (menuShown) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }
+ };
+
+ /** Handles touch events to display a context menu for table body */
+ private TouchContextProvider touchContextProvider = new TouchContextProvider(
+ contextMenuOwner);
+
/** For internal use only. May be removed or replaced in the future. */
public final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(
- true);
+ true) {
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ touchContextProvider.handleTouchEvent(event);
+ };
+ };
private KeyPressHandler navKeyPressHandler = new KeyPressHandler() {
@@ -533,14 +685,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Values (serverCacheFirst+serverCacheLast) sent by server that tells which
* rows (indexes) are in the server side cache (page buffer). -1 means
* unknown. The server side cache row MUST MATCH the client side cache rows.
- *
+ *
* If the client side cache contains additional rows with e.g. buttons, it
* will cause out of sync when such a button is pressed.
- *
+ *
* If the server side cache contains additional rows with e.g. buttons,
* scrolling in the client will cause empty buttons to be rendered
* (cached=true request for non-existing components)
- *
+ *
* For internal use only. May be removed or replaced in the future.
*/
public int serverCacheFirst = -1;
@@ -610,16 +762,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
scrollBodyPanel.addKeyUpHandler(navKeyUpHandler);
- scrollBodyPanel.sinkEvents(Event.TOUCHEVENTS);
-
- scrollBodyPanel.sinkEvents(Event.ONCONTEXTMENU);
- scrollBodyPanel.addDomHandler(new ContextMenuHandler() {
-
- @Override
- public void onContextMenu(ContextMenuEvent event) {
- handleBodyContextMenu(event);
- }
- }, ContextMenuEvent.getType());
+ scrollBodyPanel.sinkEvents(Event.TOUCHEVENTS | Event.ONCONTEXTMENU);
setStyleName(STYLENAME);
@@ -681,25 +824,29 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
});
}
- private void handleBodyContextMenu(ContextMenuEvent event) {
+ /**
+ * Handles a context menu event on table body.
+ *
+ * @param left
+ * left position of the context menu
+ * @param top
+ * top position of the context menu
+ * @return true if a context menu was shown, otherwise false
+ */
+ private boolean handleBodyContextMenu(int left, int top) {
if (enabled && bodyActionKeys != null) {
- int left = Util.getTouchOrMouseClientX(event.getNativeEvent());
- int top = Util.getTouchOrMouseClientY(event.getNativeEvent());
top += Window.getScrollTop();
left += Window.getScrollLeft();
client.getContextMenu().showAt(this, left, top);
-
- // Only prevent browser context menu if there are action handlers
- // registered
- event.stopPropagation();
- event.preventDefault();
+ return true;
}
+ return false;
}
/**
* Fires a column resize event which sends the resize information to the
* server.
- *
+ *
* @param columnId
* The columnId of the column which was resized
* @param originalWidth
@@ -721,7 +868,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Non-immediate variable update of column widths for a collection of
* columns.
- *
+ *
* @param columns
* the columns to trigger the events for.
*/
@@ -737,7 +884,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Moves the focus one step down
- *
+ *
* @return Returns true if succeeded
*/
private boolean moveFocusDown() {
@@ -746,7 +893,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Moves the focus down by 1+offset rows
- *
+ *
* @return Returns true if succeeded, else false if the selection could not
* be move downwards
*/
@@ -770,7 +917,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Moves the selection one step up
- *
+ *
* @return Returns true if succeeded
*/
private boolean moveFocusUp() {
@@ -779,10 +926,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Moves the focus row upwards
- *
+ *
* @return Returns true if succeeded, else false if the selection could not
* be move upwards
- *
+ *
*/
private boolean moveFocusUp(int offset) {
if (isSelectable()) {
@@ -806,7 +953,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Selects a row where the current selection head is
- *
+ *
* @param ctrlSelect
* Is the selection a ctrl+selection
* @param shiftSelect
@@ -841,7 +988,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Sends the selection to the server if it has been changed since the last
* update/visit.
- *
+ *
* @param immediately
* set to true to immediately send the rows
*/
@@ -898,7 +1045,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key that moves the selection head upwards. By default it is the
* up arrow key but by overriding this you can change the key to whatever
* you want.
- *
+ *
* @return The keycode of the key
*/
protected int getNavigationUpKey() {
@@ -909,7 +1056,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key that moves the selection head downwards. By default it is the
* down arrow key but by overriding this you can change the key to whatever
* you want.
- *
+ *
* @return The keycode of the key
*/
protected int getNavigationDownKey() {
@@ -920,7 +1067,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key that scrolls to the left in the table. By default it is the
* left arrow key but by overriding this you can change the key to whatever
* you want.
- *
+ *
* @return The keycode of the key
*/
protected int getNavigationLeftKey() {
@@ -931,7 +1078,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key that scroll to the right on the table. By default it is the
* right arrow key but by overriding this you can change the key to whatever
* you want.
- *
+ *
* @return The keycode of the key
*/
protected int getNavigationRightKey() {
@@ -942,7 +1089,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key that selects an item in the table. By default it is the space
* bar key but by overriding this you can change the key to whatever you
* want.
- *
+ *
* @return
*/
protected int getNavigationSelectKey() {
@@ -953,7 +1100,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key the moves the selection one page up in the table. By default
* this is the Page Up key but by overriding this you can change the key to
* whatever you want.
- *
+ *
* @return
*/
protected int getNavigationPageUpKey() {
@@ -964,7 +1111,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key the moves the selection one page down in the table. By
* default this is the Page Down key but by overriding this you can change
* the key to whatever you want.
- *
+ *
* @return
*/
protected int getNavigationPageDownKey() {
@@ -975,7 +1122,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key the moves the selection to the beginning of the table. By
* default this is the Home key but by overriding this you can change the
* key to whatever you want.
- *
+ *
* @return
*/
protected int getNavigationStartKey() {
@@ -986,7 +1133,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Get the key the moves the selection to the end of the table. By default
* this is the End key but by overriding this you can change the key to
* whatever you want.
- *
+ *
* @return
*/
protected int getNavigationEndKey() {
@@ -1093,9 +1240,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* The focus is no longer on a selected row. Move
* focus to the selected row. (#10522)
- *
+ *
* Don't do this for multiselect (#13341).
- *
+ *
* Checking the selection mode here instead of in
* setRowFocus allows keyboard shift+downarrow
* selection to work as expected.
@@ -1302,7 +1449,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the extra space that is given to the header column when column
* width is determined by header text.
- *
+ *
* @return extra space in pixels
*/
private int getHeaderPadding() {
@@ -1313,7 +1460,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* This method exists for the needs of {@link VTreeTable} only. Not part of
* the official API, <b>extend at your own risk</b>. May be removed or
* replaced in the future.
- *
+ *
* @return index of TreeTable's hierarchy column, or -1 if not applicable
*/
protected int getHierarchyColumnIndex() {
@@ -1359,7 +1506,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Selects the last row visible in the table
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param focusOnly
* Should the focus only be moved to the last row
*/
@@ -1386,7 +1533,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Selects the first row visible in the table
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param focusOnly
* Should the focus only be moved to the first row
*/
@@ -1485,7 +1632,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* <p>
* Update headers whould be called before this method is called!
* </p>
- *
+ *
* @param strings
*/
private void updateFooter(String[] strings) {
@@ -1514,7 +1661,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param uidl
* which contains row data
* @param firstRow
@@ -1643,7 +1790,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* on the commands in the UIDL.
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param partialRowAdditions
* the UIDL containing row updates.
*/
@@ -1673,7 +1820,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Gives correct column index for given column key ("cid" in UIDL).
- *
+ *
* @param colKey
* @return column index of visible columns, -1 if column not visible
*/
@@ -1741,9 +1888,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Note: not part of the official API, extend at your own risk. May be
* removed or replaced in the future.
- *
+ *
* Sets the indicated column's width for headers and scrollBody alike.
- *
+ *
* @param colIndex
* index of the modified column
* @param w
@@ -1791,7 +1938,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Get a rendered row by its key
- *
+ *
* @param key
* The key to search with
* @return
@@ -1812,10 +1959,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the next row to the given row
- *
+ *
* @param row
* The row to calculate from
- *
+ *
* @return The next row or null if no row exists
*/
private VScrollTableRow getNextRow(VScrollTableRow row, int offset) {
@@ -1838,7 +1985,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the previous row from the given row
- *
+ *
* @param row
* The row to calculate from
* @return The previous row or null if no row exists
@@ -1950,13 +2097,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Run only once when component is attached and received its initial
* content. This function:
- *
+ *
* * Syncs headers and bodys "natural widths and saves the values.
- *
+ *
* * Sets proper width and height
- *
+ *
* * Makes deferred request to get some cache rows
- *
+ *
* For internal use only. May be removed or replaced in the future.
*/
public void sizeInit() {
@@ -1968,7 +2115,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* We will use browsers table rendering algorithm to find proper column
* widths. If content and header take less space than available, we will
* divide extra space relatively to each column which has not width set.
- *
+ *
* Overflow pixels are added to last column.
*/
@@ -2267,7 +2414,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Note: this method is not part of official API although declared as
* protected. Extend at your own risk.
- *
+ *
* @return true if content area will have scrollbars visible.
*/
protected boolean willHaveScrollbars() {
@@ -2657,7 +2804,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Sets width to the header cell. This width should not include any
* possible indent modifications that are present in
* {@link VScrollTableBody#getMaxIndent()}.
- *
+ *
* @param w
* required width of the cell sans indentations
* @param ensureDefinedWidth
@@ -2720,7 +2867,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Detects if width is fixed by developer on server side or resized to
* current width by user.
- *
+ *
* @return true if defined, false if "natural" width
*/
public boolean isDefinedWidth() {
@@ -2729,10 +2876,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* This method exists for the needs of {@link VTreeTable} only.
- *
+ *
* Returns the pixels width of the header cell. This includes the
* indent, if applicable.
- *
+ *
* @return The width in pixels
*/
protected int getWidthWithIndent() {
@@ -2747,7 +2894,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the pixels width of the header cell.
- *
+ *
* @return The width in pixels
*/
public int getWidth() {
@@ -2756,7 +2903,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* This method exists for the needs of {@link VTreeTable} only.
- *
+ *
* @return <code>true</code> if this is hierarcyColumn's header cell,
* <code>false</code> otherwise
*/
@@ -2870,7 +3017,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Fires a header click event after the user has clicked a column header
* cell
- *
+ *
* @param event
* The click event
*/
@@ -3082,7 +3229,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the smallest possible cell width in pixels.
- *
+ *
* @param includeIndent
* - width should include hierarchy column indent if
* applicable (VTreeTable only)
@@ -3134,10 +3281,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Detects the natural minimum width for the column of this header cell.
* If column is resized by user or the width is defined by server the
* actual width is returned. Else the natural min width is returned.
- *
+ *
* @param columnIndex
* column index hint, if -1 (unknown) it will be detected
- *
+ *
* @return
*/
public int getNaturalColumnWidth(int columnIndex) {
@@ -3198,7 +3345,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* HeaderCell that is header cell for row headers.
- *
+ *
* Reordering disabled and clicking on it resets sorting.
*/
public class RowHeadersHeaderCell extends HeaderCell {
@@ -3527,9 +3674,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Get's HeaderCell by it's column Key.
- *
+ *
* Note that this returns HeaderCell even if it is currently collapsed.
- *
+ *
* @param cid
* Column key of accessed HeaderCell
* @return HeaderCell
@@ -3822,7 +3969,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Sets the text of the footer
- *
+ *
* @param footerText
* The text in the footer
*/
@@ -3836,7 +3983,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Set alignment of the text in the cell
- *
+ *
* @param c
* The alignment which can be ALIGN_CENTER, ALIGN_LEFT,
* ALIGN_RIGHT
@@ -3860,7 +4007,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Get the alignment of the text int the cell
- *
+ *
* @return Returns either ALIGN_CENTER, ALIGN_LEFT or ALIGN_RIGHT
*/
public char getAlign() {
@@ -3871,7 +4018,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Sets the width of the cell. This width should not include any
* possible indent modifications that are present in
* {@link VScrollTableBody#getMaxIndent()}.
- *
+ *
* @param w
* The width of the cell
* @param ensureDefinedWidth
@@ -3953,7 +4100,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Detects if width is fixed by developer on server side or resized to
* current width by user.
- *
+ *
* @return true if defined, false if "natural" width
*/
public boolean isDefinedWidth() {
@@ -3962,7 +4109,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the pixels width of the footer cell.
- *
+ *
* @return The width in pixels
*/
public int getWidth() {
@@ -3971,7 +4118,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Sets the expand ratio of the cell
- *
+ *
* @param floatAttribute
* The expand ratio
*/
@@ -3981,7 +4128,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the expand ration of the cell
- *
+ *
* @return The expand ratio
*/
public float getExpandRatio() {
@@ -3990,7 +4137,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Is the cell enabled?
- *
+ *
* @return True if enabled else False
*/
public boolean isEnabled() {
@@ -4026,7 +4173,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Handles a event on the captions
- *
+ *
* @param event
* The event to handle
*/
@@ -4040,7 +4187,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Fires a footer click event after the user has clicked a column footer
* cell
- *
+ *
* @param event
* The click event
*/
@@ -4057,7 +4204,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the column key of the column
- *
+ *
* @return The column key
*/
public String getColKey() {
@@ -4068,10 +4215,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Detects the natural minimum width for the column of this header cell.
* If column is resized by user or the width is defined by server the
* actual width is returned. Else the natural min width is returned.
- *
+ *
* @param columnIndex
* column index hint, if -1 (unknown) it will be detected
- *
+ *
* @return
*/
public int getNaturalColumnWidth(int columnIndex) {
@@ -4117,7 +4264,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* HeaderCell that is header cell for row headers.
- *
+ *
* Reordering disabled and clicking on it resets sorting.
*/
public class RowHeadersFooterCell extends FooterCell {
@@ -4187,7 +4334,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see
* com.google.gwt.user.client.ui.Panel#remove(com.google.gwt.user.client
* .ui.Widget)
@@ -4206,7 +4353,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see com.google.gwt.user.client.ui.HasWidgets#iterator()
*/
@@ -4217,10 +4364,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Gets a footer cell which represents the given columnId
- *
+ *
* @param cid
* The columnId
- *
+ *
* @return The cell
*/
public FooterCell getFooterCell(String cid) {
@@ -4229,7 +4376,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Gets a footer cell by using a column index
- *
+ *
* @param index
* The index of the column
* @return The Cell
@@ -4244,7 +4391,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Updates the cells contents when updateUIDL request is received
- *
+ *
* @param uidl
* The UIDL
*/
@@ -4315,7 +4462,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Set a footer cell for a specified column index
- *
+ *
* @param index
* The index
* @param cell
@@ -4346,7 +4493,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Remove a cell by using the columnId
- *
+ *
* @param colKey
* The columnId to remove
*/
@@ -4357,7 +4504,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Enable a column (Sets the footer cell)
- *
+ *
* @param cid
* The columnId
* @param index
@@ -4390,7 +4537,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Set the horizontal position in the cell in the footer. This is done
* when a horizontal scrollbar is present.
- *
+ *
* @param scrollLeft
* The value of the leftScroll
*/
@@ -4400,7 +4547,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Swap cells when the column are dragged
- *
+ *
* @param oldIndex
* The old index of the cell
* @param newIndex
@@ -4422,7 +4569,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* This Panel can only contain VScrollTableRow type of widgets. This
* "simulates" very large table, keeping spacers which take room of
* unrendered rows.
- *
+ *
*/
public class VScrollTableBody extends Panel {
@@ -4615,7 +4762,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* #8040 - scroll position is completely changed since the
* latest request, so request a new set of rows.
- *
+ *
* TODO: We should probably check whether the fetched rows match
* the current scroll position right when they arrive, so as to
* not waste time rendering a set of rows that will never be
@@ -4630,7 +4777,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
} else if (firstRendered > reactFirstRow) {
/*
* Branch for fetching cache above visible area.
- *
+ *
* If cache needed for both before and after visible area, this
* will be rendered after-cache is received and rendered. So in
* some rare situations the table may make two cache visits to
@@ -4643,7 +4790,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Inserts rows as provided in the rowData starting at firstIndex.
- *
+ *
* @param rowData
* @param firstIndex
* @param rows
@@ -4725,9 +4872,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* This method is used to instantiate new rows for this table. It
* automatically sets correct widths to rows cells and assigns correct
* client reference for child widgets.
- *
+ *
* This method can be called only after table has been initialized
- *
+ *
* @param uidl
*/
private VScrollTableRow prepareRow(UIDL uidl) {
@@ -4968,7 +5115,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Returns the width available for column content.
- *
+ *
* @param columnIndex
* @return
*/
@@ -4994,14 +5141,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Sets the content width of a column.
- *
+ *
* Due IE limitation, we must set the width to a wrapper elements inside
* table cells (with overflow hidden, which does not work on td
* elements).
- *
+ *
* To get this work properly crossplatform, we will also set the width
* of td.
- *
+ *
* @param colIndex
* @param w
*/
@@ -5027,9 +5174,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* This method exists for the needs of {@link VTreeTable} only. May be
* removed or replaced in the future.</br> </br> Returns the maximum
* indent of the hierarcyColumn, if applicable.
- *
+ *
* @see {@link VScrollTable#getHierarchyColumnIndex()}
- *
+ *
* @return maximum indent in pixels
*/
protected int getMaxIndent() {
@@ -5120,7 +5267,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return -1;
}
- public class VScrollTableRow extends Panel implements ActionOwner {
+ public class VScrollTableRow extends Panel implements ActionOwner,
+ ContextMenuOwner {
private static final int TOUCHSCROLL_TIMEOUT = 100;
private static final int DRAGMODE_MULTIROW = 2;
@@ -5131,13 +5279,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
private String[] actionKeys = null;
private final TableRowElement rowElement;
private int index;
- private Event touchStart;
- private static final int TOUCH_CONTEXT_MENU_TIMEOUT = 500;
- private Timer contextTouchTimeout;
+ private Event touchStart;
private Timer dragTouchTimeout;
private int touchStartY;
private int touchStartX;
+
+ private TouchContextProvider touchContextProvider = new TouchContextProvider(
+ this);
+
private TooltipInfo tooltipInfo = null;
private Map<TableCellElement, TooltipInfo> cellToolTips = new HashMap<TableCellElement, TooltipInfo>();
private boolean isDragging = false;
@@ -5295,7 +5445,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Overriding this and returning true causes all text cells to be
* rendered as HTML.
- *
+ *
* @return always returns false in the default implementation
*/
protected boolean isRenderHtmlInCells() {
@@ -5304,7 +5454,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Detects whether row is visible in tables viewport.
- *
+ *
* @return
*/
public boolean isInViewPort() {
@@ -5320,7 +5470,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Makes a check based on indexes whether the row is before the
* compared row.
- *
+ *
* @param row1
* @return true if this rows index is smaller than in the row1
*/
@@ -5331,7 +5481,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Sets the index of the row in the whole table. Currently used just
* to set even/odd classname
- *
+ *
* @param indexInWholeTable
*/
private void setIndex(int indexInWholeTable) {
@@ -5510,7 +5660,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* If there are registered click listeners, sends a click event and
* returns true. Otherwise, does nothing and returns false.
- *
+ *
* @param event
* @param targetTdOrTr
* @param immediate
@@ -5585,7 +5735,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Special handler for touch devices that support native scrolling
- *
+ *
* @return Whether the event was handled by this method.
*/
private boolean handleTouchEvent(final Event event) {
@@ -5593,6 +5743,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
boolean touchEventHandled = false;
if (enabled && hasNativeTouchScrolling) {
+ touchContextProvider.handleTouchEvent(event);
+
final Element targetTdOrTr = getEventTargetTdOrTr(event);
final int type = event.getTypeInt();
@@ -5623,37 +5775,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
dragTouchTimeout.schedule(TOUCHSCROLL_TIMEOUT);
}
-
- if (actionKeys != null) {
- if (contextTouchTimeout == null) {
- contextTouchTimeout = new Timer() {
-
- @Override
- public void run() {
- if (touchStart != null) {
- // Open the context menu if finger
- // is held in place long enough.
- showContextMenu(touchStart);
- event.preventDefault();
- touchStart = null;
- }
- }
- };
- }
- contextTouchTimeout
- .schedule(TOUCH_CONTEXT_MENU_TIMEOUT);
- }
break;
case Event.ONTOUCHMOVE:
touchEventHandled = true;
if (isSignificantMove(event)) {
- if (contextTouchTimeout != null) {
- // Moved finger before the context menu timer
- // expired, so let the browser handle this as a
- // scroll.
- contextTouchTimeout.cancel();
- contextTouchTimeout = null;
- }
if (!isDragging && dragTouchTimeout != null) {
// Moved finger before the drag timer expired,
// so let the browser handle this as a scroll.
@@ -5673,9 +5798,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
case Event.ONTOUCHEND:
case Event.ONTOUCHCANCEL:
touchEventHandled = true;
- if (contextTouchTimeout != null) {
- contextTouchTimeout.cancel();
- }
if (dragTouchTimeout != null) {
dragTouchTimeout.cancel();
}
@@ -5853,9 +5975,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
Util.simulateClickFromTouchEvent(touchStart, this);
touchStart = null;
}
- if (contextTouchTimeout != null) {
- contextTouchTimeout.cancel();
- }
+ touchContextProvider.cancel();
break;
case Event.ONTOUCHMOVE:
if (isSignificantMove(event)) {
@@ -5870,9 +5990,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
.getActiveScrollDelegate() == null)) {
startRowDrag(touchStart, type, targetTdOrTr);
}
- if (contextTouchTimeout != null) {
- contextTouchTimeout.cancel();
- }
+ touchContextProvider.cancel();
/*
* Avoid clicks and drags by clearing touch start
* flag.
@@ -5929,25 +6047,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
}.schedule(TOUCHSCROLL_TIMEOUT);
-
- if (contextTouchTimeout == null
- && actionKeys != null) {
- contextTouchTimeout = new Timer() {
-
- @Override
- public void run() {
- if (touchStart != null) {
- showContextMenu(touchStart);
- touchStart = null;
- }
- }
- };
- }
- if (contextTouchTimeout != null) {
- contextTouchTimeout.cancel();
- contextTouchTimeout
- .schedule(TOUCH_CONTEXT_MENU_TIMEOUT);
- }
}
break;
case Event.ONMOUSEDOWN:
@@ -6008,7 +6107,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Checks if the row represented by the row key has been selected
- *
+ *
* @param key
* The generated row key
*/
@@ -6078,7 +6177,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* target of the event should not be handled. If the event target is
* the row directly this method returns the TR element instead of
* the TD.
- *
+ *
* @param event
* @return TD or TR element that the event targets (the actual event
* target is this element or a child of it)
@@ -6108,6 +6207,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return getTdOrTr(eventTarget);
}
+ @Override
public void showContextMenu(Event event) {
if (enabled && actionKeys != null) {
// Show context menu if there are registered action handlers
@@ -6127,7 +6227,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Has the row been selected?
- *
+ *
* @return Returns true if selected, else false
*/
public boolean isSelected() {
@@ -6152,7 +6252,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Is called when a user clicks an item when holding SHIFT key down.
* This will select a new range from the last focused row
- *
+ *
* @param deselectPrevious
* Should the previous selected range be deselected
*/
@@ -6221,7 +6321,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.client.ui.IActionOwner#getActions ()
*/
@@ -6399,7 +6499,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Ensure the component has a focus.
- *
+ *
* TODO the current implementation simply always calls focus for the
* component. In case the Table at some point implements focus/blur
* listeners, this method needs to be evolved to conditionally call
@@ -6593,7 +6693,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (getTotalRows() == 0) {
/*
* Too wide header combined with no rows in the table.
- *
+ *
* No horizontal scrollbars would be displayed because
* there's no rows that grows too wide causing the
* scrollBody container div to overflow. Must explicitely
@@ -6744,7 +6844,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* helper to set pixel size of head and body part
- *
+ *
* @param pixels
*/
private void setContentWidth(int pixels) {
@@ -6900,7 +7000,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Helper function to build html snippet for column or row headers
- *
+ *
* @param uidl
* possibly with values caption and icon
* @return html snippet containing possibly an icon + caption text
@@ -6933,7 +7033,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
scrollTop = scrollBodyPanel.getScrollPosition();
/*
* #6970 - IE sometimes fires scroll events for a detached table.
- *
+ *
* FIXME initializedAndAttached should probably be renamed - its name
* doesn't seem to reflect its semantics. onDetach() doesn't set it to
* false, and changing that might break something else, so we need to
@@ -7225,7 +7325,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Moves the selection head to a specific row
- *
+ *
* @param row
* The row to where the selection head should move
* @return Returns true if focus was moved successfully, else false
@@ -7266,7 +7366,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Ensures that the row is visible
- *
+ *
* @param row
* The row to ensure is visible
*/
@@ -7281,7 +7381,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Handles the keyboard events handled by the table
- *
+ *
* @param event
* The keyboard event received
* @return true iff the navigation event was handled
@@ -7538,7 +7638,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see
* com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event
* .dom.client.FocusEvent)
@@ -7560,7 +7660,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see
* com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event
* .dom.client.BlurEvent)
@@ -7598,7 +7698,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Removes a key from a range if the key is found in a selected range
- *
+ *
* @param key
* The key to remove
*/
@@ -7624,7 +7724,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Can the Table be focused?
- *
+ *
* @return True if the table can be focused, else false
*/
public boolean isFocusable() {
@@ -7644,7 +7744,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.client.Focusable#focus()
*/
@@ -7713,7 +7813,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
/**
- *
+ *
* @param keyCode
* @return true if the given keyCode is used by the table for navigation
*/
@@ -7774,7 +7874,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Add this to the element mouse down event by using element.setPropertyJSO
* ("onselectstart",applyDisableTextSelectionIEHack()); Remove it then again
* when the mouse is depressed in the mouse up event.
- *
+ *
* @return Returns the JSO preventing text selection
*/
private static native JavaScriptObject getPreventTextSelectionIEHack()
diff --git a/uitest/src/com/vaadin/tests/components/table/TabletContextMenu.java b/uitest/src/com/vaadin/tests/components/table/TabletContextMenu.java
new file mode 100644
index 0000000000..193cb499a7
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TabletContextMenu.java
@@ -0,0 +1,139 @@
+/*
+ * 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.components.table;
+
+import com.vaadin.event.Action;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.event.ShortcutAction;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Table;
+
+/**
+ * A test UI for context menus on different parts of a VSCrollTable.
+ *
+ * This UI has no attached unit test due to the poor support of touch events on
+ * Selenium.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class TabletContextMenu extends AbstractTestUI {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server.
+ * VaadinRequest)
+ */
+ @Override
+ protected void setup(VaadinRequest request) {
+ setSizeFull();
+
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.setSizeFull();
+ layout.setSpacing(true);
+ addComponent(layout);
+
+ Table table1 = createTable("no scrolling, has context menu");
+ addActionHandler(table1);
+ table1.addItem();
+ layout.addComponent(table1);
+
+ Table table2 = createTable("should scroll, has context menu");
+ for (int i = 0; i < 100; ++i) {
+ table2.addItem();
+ }
+ addActionHandler(table2);
+ layout.addComponent(table2);
+
+ Table table3 = createTable("no scrolling, no context menu");
+ table3.addItem();
+ layout.addComponent(table3);
+
+ Table table4 = createTable("should scroll, no context menu");
+ for (int i = 0; i < 100; ++i) {
+ table4.addItem();
+ }
+ layout.addComponent(table4);
+ }
+
+ private Table createTable(String caption) {
+ Table table = new Table(caption);
+ table.setImmediate(true);
+
+ table.addContainerProperty("column1", String.class, "test");
+ table.setSizeFull();
+ table.setHeight("500px");
+ table.setSelectable(true);
+
+ return table;
+ }
+
+ private void addActionHandler(Table table) {
+ table.addActionHandler(new Handler() {
+
+ Action tabNext = new ShortcutAction("Shift",
+ ShortcutAction.KeyCode.TAB, null);
+ Action tabPrev = new ShortcutAction("Shift+Tab",
+ ShortcutAction.KeyCode.TAB,
+ new int[] { ShortcutAction.ModifierKey.SHIFT });
+ Action curDown = new ShortcutAction("Down",
+ ShortcutAction.KeyCode.ARROW_DOWN, null);
+ Action curUp = new ShortcutAction("Up",
+ ShortcutAction.KeyCode.ARROW_UP, null);
+ Action enter = new ShortcutAction("Enter",
+ ShortcutAction.KeyCode.ENTER, null);
+ Action add = new ShortcutAction("Add Below",
+ ShortcutAction.KeyCode.A, null);
+ Action delete = new ShortcutAction("Delete",
+ ShortcutAction.KeyCode.DELETE, null);
+
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ System.out.println(action.getCaption());
+ }
+
+ @Override
+ public Action[] getActions(Object target, Object sender) {
+ return new Action[] { tabNext, tabPrev, curDown, curUp, enter,
+ add, delete };
+ }
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription()
+ */
+ @Override
+ protected String getTestDescription() {
+ return "Make sure empty table parts have context menu on touch screen devices";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber()
+ */
+ @Override
+ protected Integer getTicketNumber() {
+ return 13694;
+ }
+
+}