summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-08-03 14:24:33 +0300
committerLeif Åstrand <leif@vaadin.com>2012-08-03 14:24:33 +0300
commit94f81dc79526a257451c6638a0696e7505227cb7 (patch)
tree13f094b896c74032ab86d079362a511f8ce478a1
parent406c50ad6cbe537ce709b8958272f93c919e9653 (diff)
parentbc5831f069f648fbf0d89a863b28d80dc4c2bf35 (diff)
downloadvaadin-framework-94f81dc79526a257451c6638a0696e7505227cb7.tar.gz
vaadin-framework-94f81dc79526a257451c6638a0696e7505227cb7.zip
Merge remote-tracking branch 'origin/6.8'
+ add @Override Conflicts: src/com/vaadin/terminal/gwt/client/Util.java src/com/vaadin/terminal/gwt/client/ui/VOverlay.java src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java src/com/vaadin/ui/LoginForm.java src/com/vaadin/ui/Table.java tests/test.xml
-rw-r--r--WebContent/statictestfiles/LoginFormIframe.html14
-rw-r--r--src/com/vaadin/Application.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/Util.java45
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOverlay.java214
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java40
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java2
-rw-r--r--src/com/vaadin/ui/LoginForm.java2
-rw-r--r--src/com/vaadin/ui/Root.java10
-rw-r--r--src/com/vaadin/ui/Table.java16
-rw-r--r--tests/test.xml2
-rw-r--r--tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java1
-rw-r--r--tests/testbench/com/vaadin/tests/components/loginform/LoginFormInIframe.html_disabled61
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.html150
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.java93
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TableRowNoHeightNoRows.html122
20 files changed, 717 insertions, 83 deletions
diff --git a/WebContent/statictestfiles/LoginFormIframe.html b/WebContent/statictestfiles/LoginFormIframe.html
new file mode 100644
index 0000000000..0d6ee9d86b
--- /dev/null
+++ b/WebContent/statictestfiles/LoginFormIframe.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<title>LoginForm</title>
+<script type="text/javascript">
+ window.name="LoginForm";
+</script>
+</head>
+<body>
+<p>Tests that LoginForm can be submitted even when the Application is embedded inside an iframe</p>
+<iframe src="/run/com.vaadin.tests.components.loginform.LoginFormTest?restartApplication" name="LoginForm" height="500px" width="500px"></iframe>
+</body>
+</html> \ No newline at end of file
diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java
index 468a7ee8be..086caa5509 100644
--- a/src/com/vaadin/Application.java
+++ b/src/com/vaadin/Application.java
@@ -1066,6 +1066,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
* @see com.vaadin.terminal.Terminal.ErrorListener#terminalError(com.vaadin.terminal.Terminal.ErrorEvent)
*/
+ @Override
public void terminalError(Terminal.ErrorEvent event) {
final Throwable t = event.getThrowable();
if (t instanceof SocketException) {
@@ -1810,6 +1811,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
this.throwable = throwable;
}
+ @Override
public Throwable getThrowable() {
return throwable;
}
diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java
index 6339f3dc93..a27c77fa45 100644
--- a/src/com/vaadin/terminal/gwt/client/Util.java
+++ b/src/com/vaadin/terminal/gwt/client/Util.java
@@ -834,30 +834,29 @@ public class Util {
ServerConnector connector = ConnectorMap.get(c).getConnector(id);
if (connector != null) {
VConsole.log("\t" + id + " (" + connector.getClass() + ") :");
- for (MethodInvocation invocation : invocations) {
- Object[] parameters = invocation.getParameters();
- String formattedParams = null;
- if (ApplicationConnection.UPDATE_VARIABLE_METHOD
- .equals(invocation.getMethodName())
- && parameters.length == 2) {
- // name, value
- Object value = parameters[1];
- // TODO paintables inside lists/maps get rendered as
- // components in the debug console
- String formattedValue = value instanceof ServerConnector ? ((ServerConnector) value)
- .getConnectorId() : String.valueOf(value);
- formattedParams = parameters[0] + " : " + formattedValue;
- }
- if (null == formattedParams) {
- formattedParams = (null != parameters) ? Arrays
- .toString(parameters) : null;
- }
- VConsole.log("\t\t" + invocation.getInterfaceName() + "."
- + invocation.getMethodName() + "(" + formattedParams
- + ")");
- }
} else {
- VConsole.log("\t" + id + ": Warning: no corresponding connector!");
+ VConsole.log("\t" + id
+ + ": Warning: no corresponding connector for id " + id);
+ }
+ for (MethodInvocation invocation : invocations) {
+ Object[] parameters = invocation.getParameters();
+ String formattedParams = null;
+ if (ApplicationConnection.UPDATE_VARIABLE_METHOD.equals(invocation
+ .getMethodName()) && parameters.length == 2) {
+ // name, value
+ Object value = parameters[1];
+ // TODO paintables inside lists/maps get rendered as
+ // components in the debug console
+ String formattedValue = value instanceof ServerConnector ? ((ServerConnector) value)
+ .getConnectorId() : String.valueOf(value);
+ formattedParams = parameters[0] + " : " + formattedValue;
+ }
+ if (null == formattedParams) {
+ formattedParams = (null != parameters) ? Arrays
+ .toString(parameters) : null;
+ }
+ VConsole.log("\t\t" + invocation.getInterfaceName() + "."
+ + invocation.getMethodName() + "(" + formattedParams + ")");
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
index a6ef85dcf1..f2f13d1f35 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java
@@ -6,7 +6,10 @@ package com.vaadin.terminal.gwt.client.ui;
import com.google.gwt.animation.client.Animation;
import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.BorderStyle;
+import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
@@ -24,6 +27,49 @@ import com.vaadin.terminal.gwt.client.BrowserInfo;
*/
public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
+ public static class PositionAndSize {
+ private int left, top, width, height;
+
+ public int getLeft() {
+ return left;
+ }
+
+ public void setLeft(int left) {
+ this.left = left;
+ }
+
+ public int getTop() {
+ return top;
+ }
+
+ public void setTop(int top) {
+ this.top = top;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void setAnimationFromCenterProgress(double progress) {
+ left += (int) (width * (1.0 - progress) / 2.0);
+ top += (int) (height * (1.0 - progress) / 2.0);
+ width = (int) (width * progress);
+ height = (int) (height * progress);
+ }
+ }
+
/*
* The z-index value from where all overlays live. This can be overridden in
* any extending class.
@@ -53,6 +99,12 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
private Widget owner;
/**
+ * The shim iframe behind the overlay, allowing PDFs and applets to be
+ * covered by overlays.
+ */
+ private IFrameElement shimElement;
+
+ /**
* The HTML snippet that is used to render the actual shadow. In consists of
* nine different DIV-elements with the following class names:
*
@@ -73,6 +125,11 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
*/
private static final String SHADOW_HTML = "<div class=\"top-left\"></div><div class=\"top\"></div><div class=\"top-right\"></div><div class=\"left\"></div><div class=\"center\"></div><div class=\"right\"></div><div class=\"bottom-left\"></div><div class=\"bottom\"></div><div class=\"bottom-right\"></div>";
+ /**
+ * Matches {@link PopupPanel}.ANIMATION_DURATION
+ */
+ private static final int POPUP_PANEL_ANIMATION_DURATION = 200;
+
private boolean sinkShadowEvents = false;
public VOverlay() {
@@ -123,9 +180,15 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
return shadow != null;
}
+ private void removeShim() {
+ if (shimElement != null) {
+ shimElement.removeFromParent();
+ }
+ }
+
private void removeShadowIfPresent() {
if (isShadowAttached()) {
- shadow.getParentElement().removeChild(shadow);
+ shadow.removeFromParent();
// Remove event listener from the shadow
unsinkShadowEvents();
@@ -136,6 +199,10 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
return isShadowEnabled() && shadow.getParentElement() != null;
}
+ private boolean isShimAttached() {
+ return shimElement != null && shimElement.hasParentElement();
+ }
+
private void adjustZIndex() {
setZIndex(Z_INDEX);
}
@@ -163,7 +230,46 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
style.setMarginLeft(-adjustByRelativeLeftBodyMargin(), Unit.PX);
style.setMarginTop(-adjustByRelativeTopBodyMargin(), Unit.PX);
super.setPopupPosition(left, top);
- updateShadowSizeAndPosition(isAnimationEnabled() ? 0 : 1);
+ sizeOrPositionUpdated(isAnimationEnabled() ? 0 : 1);
+ }
+
+ private IFrameElement getShimElement() {
+ if (shimElement == null) {
+ shimElement = Document.get().createIFrameElement();
+
+ // Insert shim iframe before the main overlay element. It does not
+ // matter if it is in front or behind the shadow as we cannot put a
+ // shim behind the shadow due to its transparency.
+ shimElement.getStyle().setPosition(Position.ABSOLUTE);
+ shimElement.getStyle().setBorderStyle(BorderStyle.NONE);
+ shimElement.setFrameBorder(0);
+ shimElement.setMarginHeight(0);
+ }
+ return shimElement;
+ }
+
+ private int getActualTop() {
+ int y = getAbsoluteTop();
+
+ /* This is needed for IE7 at least */
+ // Account for the difference between absolute position and the
+ // body's positioning context.
+ y -= Document.get().getBodyOffsetTop();
+ y -= adjustByRelativeTopBodyMargin();
+
+ return y;
+ }
+
+ private int getActualLeft() {
+ int x = getAbsoluteLeft();
+
+ /* This is needed for IE7 at least */
+ // Account for the difference between absolute position and the
+ // body's positioning context.
+ x -= Document.get().getBodyOffsetLeft();
+ x -= adjustByRelativeLeftBodyMargin();
+
+ return x;
}
private static int adjustByRelativeTopBodyMargin() {
@@ -196,13 +302,10 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
@Override
public void show() {
super.show();
- if (isShadowEnabled()) {
- if (isAnimationEnabled()) {
- ShadowAnimation sa = new ShadowAnimation();
- sa.run(200);
- } else {
- updateShadowSizeAndPosition(1.0);
- }
+ if (isAnimationEnabled()) {
+ new ResizeAnimation().run(POPUP_PANEL_ANIMATION_DURATION);
+ } else {
+ sizeOrPositionUpdated(1.0);
}
}
@@ -212,6 +315,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
// Always ensure shadow is removed when the overlay is removed.
removeShadowIfPresent();
+ removeShim();
}
@Override
@@ -226,13 +330,13 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
@Override
public void setWidth(String width) {
super.setWidth(width);
- updateShadowSizeAndPosition(1.0);
+ sizeOrPositionUpdated(1.0);
}
@Override
public void setHeight(String height) {
super.setHeight(height);
- updateShadowSizeAndPosition(1.0);
+ sizeOrPositionUpdated(1.0);
}
/**
@@ -251,28 +355,29 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
}
}
- /*
+ /**
* Extending classes should always call this method after they change the
* size of overlay without using normal 'setWidth(String)' and
* 'setHeight(String)' methods (if not calling super.setWidth/Height).
+ *
*/
- public void updateShadowSizeAndPosition() {
- updateShadowSizeAndPosition(1.0);
+ public void sizeOrPositionUpdated() {
+ sizeOrPositionUpdated(1.0);
}
/**
- * Recalculates proper position and dimensions for the shadow element. Can
- * be used to animate the shadow, using the 'progress' parameter (used to
- * animate the shadow in sync with GWT PopupPanel's default animation
- * 'PopupPanel.AnimationType.CENTER').
+ * Recalculates proper position and dimensions for the shadow and shim
+ * elements. Can be used to animate the related elements, using the
+ * 'progress' parameter (used to animate the shadow in sync with GWT
+ * PopupPanel's default animation 'PopupPanel.AnimationType.CENTER').
*
* @param progress
* A value between 0.0 and 1.0, indicating the progress of the
* animation (0=start, 1=end).
*/
- private void updateShadowSizeAndPosition(final double progress) {
+ private void sizeOrPositionUpdated(final double progress) {
// Don't do anything if overlay element is not attached
- if (!isAttached() || shadow == null) {
+ if (!isAttached()) {
return;
}
// Calculate proper z-index
@@ -295,37 +400,26 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
getOffsetWidth();
}
- int x = getAbsoluteLeft();
- int y = getAbsoluteTop();
+ PositionAndSize positionAndSize = new PositionAndSize();
+ positionAndSize.left = getActualLeft();
+ positionAndSize.top = getActualTop();
+ positionAndSize.width = getOffsetWidth();
+ positionAndSize.height = getOffsetHeight();
- /* This is needed for IE7 at least */
- // Account for the difference between absolute position and the
- // body's positioning context.
- x -= Document.get().getBodyOffsetLeft();
- y -= Document.get().getBodyOffsetTop();
- x -= adjustByRelativeLeftBodyMargin();
- y -= adjustByRelativeTopBodyMargin();
-
- int width = getOffsetWidth();
- int height = getOffsetHeight();
-
- if (width < 0) {
- width = 0;
+ if (positionAndSize.width < 0) {
+ positionAndSize.width = 0;
}
- if (height < 0) {
- height = 0;
+ if (positionAndSize.height < 0) {
+ positionAndSize.height = 0;
}
- // Animate the shadow size
- x += (int) (width * (1.0 - progress) / 2.0);
- y += (int) (height * (1.0 - progress) / 2.0);
- width = (int) (width * progress);
- height = (int) (height * progress);
+ // Animate the size
+ positionAndSize.setAnimationFromCenterProgress(progress);
// Opera needs some shaking to get parts of the shadow showing
// properly
// (ticket #2704)
- if (BrowserInfo.get().isOpera()) {
+ if (BrowserInfo.get().isOpera() && isShadowEnabled()) {
// Clear the height of all middle elements
DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto");
DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto");
@@ -333,15 +427,17 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
}
// Update correct values
- DOM.setStyleAttribute(shadow, "zIndex", zIndex);
- DOM.setStyleAttribute(shadow, "width", width + "px");
- DOM.setStyleAttribute(shadow, "height", height + "px");
- DOM.setStyleAttribute(shadow, "top", y + "px");
- DOM.setStyleAttribute(shadow, "left", x + "px");
- DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" : "");
+ if (isShadowEnabled()) {
+ updateSizeAndPosition(shadow, positionAndSize);
+ DOM.setStyleAttribute(shadow, "zIndex", zIndex);
+ DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none"
+ : "");
+ }
+ updateSizeAndPosition((Element) Element.as(getShimElement()),
+ positionAndSize);
// Opera fix, part 2 (ticket #2704)
- if (BrowserInfo.get().isOpera()) {
+ if (BrowserInfo.get().isOpera() && isShadowEnabled()) {
// We'll fix the height of all the middle elements
DOM.getChild(shadow, 3)
.getStyle()
@@ -358,17 +454,29 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
}
// Attach to dom if not there already
- if (!isShadowAttached()) {
+ if (isShadowEnabled() && !isShadowAttached()) {
RootPanel.get().getElement().insertBefore(shadow, getElement());
sinkShadowEvents();
}
+ if (!isShimAttached()) {
+ RootPanel.get().getElement()
+ .insertBefore(shimElement, getElement());
+ }
+
+ }
+ private void updateSizeAndPosition(Element e,
+ PositionAndSize positionAndSize) {
+ e.getStyle().setLeft(positionAndSize.left, Unit.PX);
+ e.getStyle().setTop(positionAndSize.top, Unit.PX);
+ e.getStyle().setWidth(positionAndSize.width, Unit.PX);
+ e.getStyle().setHeight(positionAndSize.height, Unit.PX);
}
- protected class ShadowAnimation extends Animation {
+ protected class ResizeAnimation extends Animation {
@Override
protected void onUpdate(double progress) {
- updateShadowSizeAndPosition(progress);
+ sizeOrPositionUpdated(progress);
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java
index a96be0bc2f..47bda81362 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java
@@ -603,7 +603,7 @@ public class VMenuBar extends SimpleFocusablePanel implements
// popup
style.setWidth(contentWidth + Util.getNativeScrollbarSize(),
Unit.PX);
- popup.updateShadowSizeAndPosition();
+ popup.sizeOrPositionUpdated();
}
}
return top;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
index fb853b8a55..1309155443 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
@@ -163,6 +163,7 @@ public class VNotification extends VOverlay {
super.show();
notifications.add(this);
setPosition(position);
+ sizeOrPositionUpdated();
/**
* Android 4 fails to render notifications correctly without a little
* nudge (#8551)
diff --git a/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java
index 1b7cfd091f..6efcd8f417 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java
@@ -28,6 +28,7 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VCaptionWrapper;
+import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.terminal.gwt.client.ui.VOverlay;
@@ -246,6 +247,7 @@ public class VPopupView extends HTML {
@Override
public void hide(boolean autoClosed) {
+ VConsole.log("Hiding popupview");
hiding = true;
syncChildren();
if (popupComponentWidget != null && popupComponentWidget != loading) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
index a862a5f372..7b5097ff77 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
@@ -54,6 +54,7 @@ public class RootConnector extends AbstractComponentContainerConnector
private HandlerRegistration childStateChangeHandlerRegistration;
private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
+ @Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
// TODO Should use a more specific handler that only reacts to
// size changes
@@ -65,12 +66,14 @@ public class RootConnector extends AbstractComponentContainerConnector
protected void init() {
super.init();
registerRpc(PageClientRpc.class, new PageClientRpc() {
+ @Override
public void setTitle(String title) {
com.google.gwt.user.client.Window.setTitle(title);
}
});
}
+ @Override
public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
ConnectorMap paintableMap = ConnectorMap.get(getConnection());
getWidget().rendering = true;
@@ -121,6 +124,7 @@ public class RootConnector extends AbstractComponentContainerConnector
// to finish rendering this window in case this is a download
// (and window stays open).
Scheduler.get().scheduleDeferred(new Command() {
+ @Override
public void execute() {
VRoot.goTo(url);
}
@@ -185,6 +189,7 @@ public class RootConnector extends AbstractComponentContainerConnector
if (uidl.hasAttribute("focused")) {
// set focused component when render phase is finished
Scheduler.get().scheduleDeferred(new Command() {
+ @Override
public void execute() {
ComponentConnector paintable = (ComponentConnector) uidl
.getPaintableAttribute("focused", getConnection());
@@ -296,6 +301,7 @@ public class RootConnector extends AbstractComponentContainerConnector
};
+ @Override
public void updateCaption(ComponentConnector component) {
// NOP The main view never draws caption for its layout
}
@@ -415,6 +421,7 @@ public class RootConnector extends AbstractComponentContainerConnector
}
Scheduler.get().scheduleDeferred(new Command() {
+ @Override
public void execute() {
componentConnector.getWidget().getElement().scrollIntoView();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java b/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java
index 6ea2acc5d6..7721a3d763 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java
@@ -248,6 +248,20 @@ public class TableConnector extends AbstractComponentContainerConnector
}
}
+ /*
+ * If the server has (re)initialized the rows, our selectionRangeStart
+ * row will point to an index that the server knows nothing about,
+ * causing problems if doing multi selection with shift. The field will
+ * be cleared a little later when the row focus has been restored.
+ * (#8584)
+ */
+ if (uidl.hasAttribute(VScrollTable.ATTRIBUTE_KEY_MAPPER_RESET)
+ && uidl.getBooleanAttribute(VScrollTable.ATTRIBUTE_KEY_MAPPER_RESET)
+ && getWidget().selectionRangeStart != null) {
+ assert !getWidget().selectionRangeStart.isAttached();
+ getWidget().selectionRangeStart = getWidget().focusedRow;
+ }
+
getWidget().tabIndex = uidl.hasAttribute("tabindex") ? uidl
.getIntAttribute("tabindex") : 0;
getWidget().setProperTabIndex();
diff --git a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
index 7c5db30dba..8a58c28c5b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
@@ -131,6 +131,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
+ /**
+ * Tell the client that old keys are no longer valid because the server has
+ * cleared its key map.
+ */
+ public static final String ATTRIBUTE_KEY_MAPPER_RESET = "clearKeyMap";
+
private static final String ROW_HEADER_COLUMN_KEY = "0";
public static final String CLASSNAME = "v-table";
@@ -216,7 +222,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* Helper to store selection range start in when using the keyboard
*/
- private VScrollTableRow selectionRangeStart;
+ VScrollTableRow selectionRangeStart;
/*
* Flag for notifying when the selection has changed and should be sent to
@@ -242,6 +248,19 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
private Set<String> noncollapsibleColumns;
/**
+ * 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)}
+ * to avoid some rounding problems, e.g. round(2 * 19.8) / 2 = 20 but
+ * round(3 * 19.8) / 3 = 19.66.
+ */
+ private double lastKnownRowHeight = Double.NaN;
+
+ /**
* Represents a select range of rows
*/
private class SelectionRange {
@@ -4244,13 +4263,27 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (tBodyMeasurementsDone && !forceUpdate) {
return rowHeight;
} else {
-
if (tBodyElement.getRows().getLength() > 0) {
int tableHeight = getTableHeight();
int rowCount = tBodyElement.getRows().getLength();
rowHeight = tableHeight / (double) rowCount;
} else {
- if (isAttached()) {
+ // Special cases if we can't just measure the current rows
+ if (!Double.isNaN(lastKnownRowHeight)) {
+ // Use previous value if available
+ if (BrowserInfo.get().isIE()) {
+ /*
+ * IE needs to reflow the table element at this
+ * point to work correctly (e.g.
+ * com.vaadin.tests.components.table.
+ * ContainerSizeChange) - the other code paths
+ * already trigger reflows, but here it must be done
+ * explicitly.
+ */
+ getTableHeight();
+ }
+ rowHeight = lastKnownRowHeight;
+ } else if (isAttached()) {
// measure row height by adding a dummy row
VScrollTableRow scrollTableRow = new VScrollTableRow();
tBodyElement.appendChild(scrollTableRow.getElement());
@@ -4261,6 +4294,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return DEFAULT_ROW_HEIGHT;
}
}
+ lastKnownRowHeight = rowHeight;
tBodyMeasurementsDone = true;
return rowHeight;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java b/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java
index b09deb14da..bae4f804fc 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java
@@ -287,7 +287,7 @@ public class WindowConnector extends AbstractComponentContainerConnector
if (window.centered) {
window.center();
}
- window.updateShadowSizeAndPosition();
+ window.sizeOrPositionUpdated();
}
@Override
diff --git a/src/com/vaadin/ui/LoginForm.java b/src/com/vaadin/ui/LoginForm.java
index 2d4513c5e3..db7e5f9dd9 100644
--- a/src/com/vaadin/ui/LoginForm.java
+++ b/src/com/vaadin/ui/LoginForm.java
@@ -91,7 +91,7 @@ public class LoginForm extends CustomComponent {
response.setContentType("text/html; charset=utf-8");
response.getWriter()
.write("<html><body>Login form handled."
- + "<script type='text/javascript'>top.vaadin.forceSync();"
+ + "<script type='text/javascript'>parent.parent.vaadin.forceSync();"
+ "</script></body></html>");
Map<String, String[]> parameters = request.getParameterMap();
diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java
index a5e69d5546..bd4842632b 100644
--- a/src/com/vaadin/ui/Root.java
+++ b/src/com/vaadin/ui/Root.java
@@ -419,6 +419,7 @@ public abstract class Root extends AbstractComponentContainer implements
private Page page = new Page(this);
private RootServerRpc rpc = new RootServerRpc() {
+ @Override
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Root.this, mouseDetails));
}
@@ -502,6 +503,7 @@ public abstract class Root extends AbstractComponentContainer implements
return this;
}
+ @Override
public void replaceComponent(Component oldComponent, Component newComponent) {
throw new UnsupportedOperationException();
}
@@ -511,6 +513,7 @@ public abstract class Root extends AbstractComponentContainer implements
return application;
}
+ @Override
public void paintContent(PaintTarget target) throws PaintException {
page.paintContent(target);
@@ -550,6 +553,7 @@ public abstract class Root extends AbstractComponentContainer implements
fireEvent(new ClickEvent(this, mouseDetails));
}
+ @Override
@SuppressWarnings("unchecked")
public void changeVariables(Object source, Map<String, Object> variables) {
if (variables.containsKey(CLICK_EVENT_ID)) {
@@ -578,6 +582,7 @@ public abstract class Root extends AbstractComponentContainer implements
*
* @see com.vaadin.ui.ComponentContainer#getComponentIterator()
*/
+ @Override
public Iterator<Component> getComponentIterator() {
// TODO could directly create some kind of combined iterator instead of
// creating a new ArrayList
@@ -597,6 +602,7 @@ public abstract class Root extends AbstractComponentContainer implements
*
* @see com.vaadin.ui.ComponentContainer#getComponentCount()
*/
+ @Override
public int getComponentCount() {
return windows.size() + (getContent() == null ? 0 : 1);
}
@@ -956,11 +962,13 @@ public abstract class Root extends AbstractComponentContainer implements
return actionManager;
}
+ @Override
public <T extends Action & com.vaadin.event.Action.Listener> void addAction(
T action) {
getActionManager().addAction(action);
}
+ @Override
public <T extends Action & com.vaadin.event.Action.Listener> void removeAction(
T action) {
if (actionManager != null) {
@@ -968,10 +976,12 @@ public abstract class Root extends AbstractComponentContainer implements
}
}
+ @Override
public void addActionHandler(Handler actionHandler) {
getActionManager().addActionHandler(actionHandler);
}
+ @Override
public void removeActionHandler(Handler actionHandler) {
if (actionManager != null) {
actionManager.removeActionHandler(actionHandler);
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 71f41fb257..39b7fb7473 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -538,6 +538,13 @@ public class Table extends AbstractSelect implements Action.Container,
private HashMap<Object, Converter<String, Object>> propertyValueConverters = new HashMap<Object, Converter<String, Object>>();
+ /**
+ * Set to true if the client-side should be informed that the key mapper has
+ * been reset so it can avoid sending back references to keys that are no
+ * longer present.
+ */
+ private boolean keyMapperReset;
+
/* Table constructors */
/**
@@ -2890,6 +2897,11 @@ public class Table extends AbstractSelect implements Action.Container,
paintVisibleColumns(target);
+ if (keyMapperReset) {
+ keyMapperReset = false;
+ target.addAttribute(VScrollTable.ATTRIBUTE_KEY_MAPPER_RESET, true);
+ }
+
if (dropHandler != null) {
dropHandler.getAcceptCriterion().paint(target);
}
@@ -4053,6 +4065,10 @@ public class Table extends AbstractSelect implements Action.Container,
public void containerItemSetChange(Container.ItemSetChangeEvent event) {
super.containerItemSetChange(event);
+ // super method clears the key map, must inform client about this to
+ // avoid getting invalid keys back (#8584)
+ keyMapperReset = true;
+
// ensure that page still has first item in page, ignore buffer refresh
// (forced in this method)
setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex(), false);
diff --git a/tests/test.xml b/tests/test.xml
index 222fe0a452..9b879ec789 100644
--- a/tests/test.xml
+++ b/tests/test.xml
@@ -11,7 +11,7 @@
<!-- Configuration -->
<!-- ================================================================== -->
<!-- Browsers to use for testing -->
- <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox12,winxp-safari5,winxp-googlechrome19,winxp-opera11" />
+ <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox12,winxp-safari5,winxp-googlechrome21,winxp-opera11" />
<property name="browsers-linux" value="linux-firefox3,linux-opera10,linux-googlechrome8" />
<property name="browsers-mac" value="osx-firefox3,osx-opera10,osx-googlechrome8,osx-safari4,osx-safari5" />
diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
index 1bc76fff1e..efba67199d 100644
--- a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
+++ b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java
@@ -78,6 +78,7 @@ public abstract class AbstractFieldTest<T extends AbstractField<?>> extends
MenuItem sortValueChangesItem = abstractField.addItem(
"Show sorted value changes", new MenuBar.Command() {
+ @Override
public void menuSelected(MenuItem selectedItem) {
sortValueChanges = selectedItem.isChecked();
log("Show sorted value changes: "
diff --git a/tests/testbench/com/vaadin/tests/components/loginform/LoginFormInIframe.html_disabled b/tests/testbench/com/vaadin/tests/components/loginform/LoginFormInIframe.html_disabled
new file mode 100644
index 0000000000..075bb3c57f
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/loginform/LoginFormInIframe.html_disabled
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>LoginFormTest</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">LoginFormTest</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/statictestfiles/LoginFormIframe.html</td>
+ <td></td>
+</tr>
+<tr>
+ <td>selectFrame</td>
+ <td>LoginForm</td>
+ <td></td>
+</tr>
+<tr>
+ <td>selectFrame</td>
+ <td>PID6</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>username</td>
+ <td>username</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>password</td>
+ <td>password</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>//form[@id='loginf']/div[5]/div/span/span</td>
+ <td></td>
+</tr>
+<tr>
+ <td>selectFrame</td>
+ <td>relative=top</td>
+ <td></td>
+</tr>
+<tr>
+ <td>selectFrame</td>
+ <td>LoginForm</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsloginformLoginFormTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td>
+ <td>User 'username', password='password' logged in</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.html b/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.html
new file mode 100644
index 0000000000..c41f3fbfdd
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.html
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.table.MultiSelectWithRemovedRow?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>34,9</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::PID_SLog_row_0</td>
+ <td>1. Selection: [Joe]</td>
+</tr>
+<!--Remove selection + shift select-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>19,4:shift</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::PID_SLog_row_0</td>
+ <td>2. Selection: [William, Jack, Averell]</td>
+</tr>
+<!--Remove first + shift select-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>23,13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td>26,10:shift</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::PID_SLog_row_0</td>
+ <td>3. Selection: [Jack, Averell, Bob]</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td>34,14:shift</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::PID_SLog_row_0</td>
+ <td>4. Selection: [William, Averell, Bob, Grat]</td>
+</tr>
+<!--Sort + shift select down-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td>31,15</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>36,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>30,6:shift</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::PID_SLog_row_0</td>
+ <td>5. Selection: [Bob, Emmett, Grat]</td>
+</tr>
+<!--Sort + shift select up-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>24,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>11,2</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>30,11:shift</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableMultiSelectWithRemovedRow::PID_SLog_row_0</td>
+ <td>6. Selection: [Grat, Emmett, Bob]</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.java b/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.java
new file mode 100644
index 0000000000..12ae4a3c4d
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithRemovedRow.java
@@ -0,0 +1,93 @@
+package com.vaadin.tests.components.table;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Table;
+
+@SuppressWarnings("serial")
+public class MultiSelectWithRemovedRow extends TestBase {
+ public static class Person {
+ private final String name;
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ @Override
+ protected void setup() {
+ final Log log = new Log(5);
+ addComponent(log);
+
+ final BeanItemContainer<Person> container = new BeanItemContainer<Person>(
+ Person.class, Arrays.asList(new Person("Joe"), new Person(
+ "William"), new Person("Jack"), new Person("Averell"),
+ new Person("Bob"), new Person("Grat"), new Person(
+ "Bill"), new Person("Emmett")));
+ final Table table = new Table("Table", container);
+ table.setSelectable(true);
+ table.setMultiSelect(true);
+ table.setImmediate(true);
+ addComponent(table);
+
+ Button showButton = new Button("Show selection");
+ showButton.addListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(Button.ClickEvent clickEvent) {
+ Collection<?> selection = (Collection<?>) table.getValue();
+ log.log("Selection: " + selection);
+ }
+ });
+ addComponent(showButton);
+
+ Button removeButton = new Button("Remove selection");
+ removeButton.addListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(Button.ClickEvent clickEvent) {
+ Collection<?> selection = (Collection<?>) table.getValue();
+ for (Object selected : selection) {
+ container.removeItem(selected);
+ }
+ }
+ });
+ addComponent(removeButton);
+
+ addComponent(new Button("Remove first selected row",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Collection<?> selection = (Collection<?>) table
+ .getValue();
+ if (!selection.isEmpty()) {
+ Object firstSelected = selection.iterator().next();
+ container.removeItem(firstSelected);
+ }
+ }
+ }));
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Multi select using shift should work after removing the currently selected row";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(8584);
+ }
+} \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/table/TableRowNoHeightNoRows.html b/tests/testbench/com/vaadin/tests/components/table/TableRowNoHeightNoRows.html
new file mode 100644
index 0000000000..35d64c3a0c
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/table/TableRowNoHeightNoRows.html
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.table.Tables?restartApplication</td>
+ <td></td>
+</tr>
+<!--Remove all rows-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::PID_Smenu#item0</td>
+ <td>29,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[0]/VMenuBar[0]#item5</td>
+ <td>40,5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[1]/VMenuBar[0]#item1</td>
+ <td>53,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[2]/VMenuBar[0]#item0</td>
+ <td>4,6</td>
+</tr>
+<!--Add generated column-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::PID_Smenu#item0</td>
+ <td>34,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[0]/VMenuBar[0]#item8</td>
+ <td>40,6</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[1]/VMenuBar[0]#item4</td>
+ <td>97,5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[2]/VMenuBar[0]#item0</td>
+ <td>55,6</td>
+</tr>
+<!--Screenshot of initial state-->
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>1-no-rows-small</td>
+</tr>
+<!--Add a row to make the row height increase-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::PID_Smenu#item0</td>
+ <td>23,5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[0]/VMenuBar[0]#item5</td>
+ <td>26,1</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[1]/VMenuBar[0]#item1</td>
+ <td>68,10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[2]/VMenuBar[0]#item1</td>
+ <td>18,13</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>2-one-row-big</td>
+</tr>
+<!--Remove the row - height should be retained-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::PID_Smenu#item0</td>
+ <td>28,10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[0]/VMenuBar[0]#item5</td>
+ <td>34,6</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[1]/VMenuBar[0]#item1</td>
+ <td>62,4</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTables::Root/VOverlay[2]/VMenuBar[0]#item0</td>
+ <td>25,4</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>3-no-rows-big</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>