summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css3
-rw-r--r--WebContent/VAADIN/themes/base/common/common.css3
-rw-r--r--WebContent/VAADIN/themes/base/csslayout/csslayout.css2
-rw-r--r--WebContent/VAADIN/themes/base/panel/panel.css3
-rw-r--r--WebContent/VAADIN/themes/base/select/select.css3
-rw-r--r--WebContent/VAADIN/themes/base/window/window.css6
-rw-r--r--WebContent/VAADIN/themes/reindeer/datefield/datefield.css3
-rw-r--r--WebContent/VAADIN/themes/reindeer/select/select.css3
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/window.css3
-rw-r--r--WebContent/VAADIN/themes/runo/window/window.css3
-rw-r--r--WebContent/release-notes.html50
-rw-r--r--WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html59
-rw-r--r--build/build.xml9
-rw-r--r--src/com/vaadin/data/util/ContainerHierarchicalWrapper.java3
-rw-r--r--src/com/vaadin/data/util/IndexedContainer.java7
-rw-r--r--src/com/vaadin/event/dd/acceptcriteria/SourceIs.java27
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConnection.java105
-rw-r--r--src/com/vaadin/terminal/gwt/client/BrowserInfo.java64
-rw-r--r--src/com/vaadin/terminal/gwt/client/CSSRule.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComponentConnector.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComputedStyle.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/LayoutManager.java471
-rw-r--r--src/com/vaadin/terminal/gwt/client/ServerConnector.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/Util.java13
-rw-r--r--src/com/vaadin/terminal/gwt/client/VBrowserDetails.java127
-rw-r--r--src/com/vaadin/terminal/gwt/client/VDebugConsole.java21
-rw-r--r--src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java9
-rw-r--r--src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/ClickRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/ClickRPC.java)2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java22
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/LayoutClickRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/LayoutClickRPC.java)2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java267
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java30
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/button/VButton.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java20
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java20
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java5
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java8
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/RootServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/root/RootServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRPC.java)2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java25
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRpc.java (renamed from src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRPC.java)4
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java11
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java8
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java350
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java30
-rw-r--r--src/com/vaadin/terminal/gwt/server/ClientConnector.java2
-rw-r--r--src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java13
-rw-r--r--src/com/vaadin/terminal/gwt/server/DragAndDropService.java5
-rw-r--r--src/com/vaadin/terminal/gwt/server/JsonCodec.java485
-rw-r--r--src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java38
-rw-r--r--src/com/vaadin/terminal/gwt/server/RequestTimer.java43
-rw-r--r--src/com/vaadin/terminal/gwt/server/RpcManager.java4
-rw-r--r--src/com/vaadin/terminal/gwt/server/ServerRpcManager.java105
-rw-r--r--src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java107
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java18
-rw-r--r--src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java34
-rw-r--r--src/com/vaadin/ui/AbsoluteLayout.java4
-rw-r--r--src/com/vaadin/ui/AbstractComponent.java61
-rw-r--r--src/com/vaadin/ui/AbstractComponentContainer.java20
-rw-r--r--src/com/vaadin/ui/AbstractOrderedLayout.java4
-rw-r--r--src/com/vaadin/ui/AbstractSplitPanel.java5
-rw-r--r--src/com/vaadin/ui/Button.java29
-rw-r--r--src/com/vaadin/ui/Component.java4
-rw-r--r--src/com/vaadin/ui/CssLayout.java4
-rw-r--r--src/com/vaadin/ui/CustomLayout.java24
-rw-r--r--src/com/vaadin/ui/Embedded.java4
-rw-r--r--src/com/vaadin/ui/GridLayout.java4
-rw-r--r--src/com/vaadin/ui/Panel.java4
-rw-r--r--src/com/vaadin/ui/Root.java4
-rw-r--r--src/com/vaadin/ui/Table.java2
-rw-r--r--src/com/vaadin/ui/Window.java4
-rw-r--r--tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java120
-rw-r--r--tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html4
-rw-r--r--tests/server-side/com/vaadin/tests/server/SourceFileChecker.java42
-rw-r--r--tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java25
-rw-r--r--tests/test.xml2
-rw-r--r--tests/testbench/com/vaadin/tests/browserfeatures/FullHeightScrollbar.html47
-rw-r--r--tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html86
-rw-r--r--tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java90
-rw-r--r--tests/testbench/com/vaadin/tests/components/TouchScrollables.java314
-rw-r--r--tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html47
-rw-r--r--tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java39
-rw-r--r--tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java62
-rw-r--r--tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html21
-rw-r--r--tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html31
-rw-r--r--tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java11
-rw-r--r--tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java4
-rw-r--r--tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html26
-rw-r--r--tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html11
-rw-r--r--tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.java (renamed from tests/testbench/com/vaadin/tests/components/gridlayout/MarginsInLabels.java)2
-rw-r--r--tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html47
-rw-r--r--tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java41
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html2
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html97
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java128
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.html42
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java81
-rw-r--r--tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.html32
-rw-r--r--tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.java58
-rw-r--r--tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java2
-rw-r--r--tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html71
-rw-r--r--tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java91
-rw-r--r--tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html2
134 files changed, 3900 insertions, 830 deletions
diff --git a/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css b/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css
index 0d2f7312fb..637d829d78 100644
--- a/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css
+++ b/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css
@@ -15,8 +15,9 @@
overflow: hidden;
}
.v-absolutelayout-margin, .v-absolutelayout-canvas {
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-absolutelayout.v-has-height > div, .v-absolutelayout.v-has-height > div > div {
height: 100%;
diff --git a/WebContent/VAADIN/themes/base/common/common.css b/WebContent/VAADIN/themes/base/common/common.css
index 6de2b26267..3c08a9d584 100644
--- a/WebContent/VAADIN/themes/base/common/common.css
+++ b/WebContent/VAADIN/themes/base/common/common.css
@@ -97,8 +97,9 @@ div.v-app-loading {
}
.v-form-content {
height: 100%;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
/* Field modified */ /* Disabled by default
diff --git a/WebContent/VAADIN/themes/base/csslayout/csslayout.css b/WebContent/VAADIN/themes/base/csslayout/csslayout.css
index 2713d621a2..40cec4889f 100644
--- a/WebContent/VAADIN/themes/base/csslayout/csslayout.css
+++ b/WebContent/VAADIN/themes/base/csslayout/csslayout.css
@@ -6,8 +6,8 @@ div.v-csslayout {
display: block;
}
.v-csslayout-margin, .v-csslayout-container {
- -moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
box-sizing: border-box;
}
.v-has-width > .v-csslayout-margin,
diff --git a/WebContent/VAADIN/themes/base/panel/panel.css b/WebContent/VAADIN/themes/base/panel/panel.css
index 286b1b7f4d..489d6bc015 100644
--- a/WebContent/VAADIN/themes/base/panel/panel.css
+++ b/WebContent/VAADIN/themes/base/panel/panel.css
@@ -30,8 +30,9 @@
}
.v-panel-content {
overflow: auto;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-panel.v-has-width > .v-panel-content {
width: 100%;
diff --git a/WebContent/VAADIN/themes/base/select/select.css b/WebContent/VAADIN/themes/base/select/select.css
index fe50b98ce6..b9d0dda51f 100644
--- a/WebContent/VAADIN/themes/base/select/select.css
+++ b/WebContent/VAADIN/themes/base/select/select.css
@@ -67,8 +67,9 @@
margin: 0;
float: left;
-webkit-border-radius: 0px;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-filterselect-prompt .v-filterselect-input {
color: #999;
diff --git a/WebContent/VAADIN/themes/base/window/window.css b/WebContent/VAADIN/themes/base/window/window.css
index f553f95fdf..d728e7f60e 100644
--- a/WebContent/VAADIN/themes/base/window/window.css
+++ b/WebContent/VAADIN/themes/base/window/window.css
@@ -2,8 +2,9 @@
background: #fff;
}
.v-window-contents {
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-window.v-has-width > div.popupContent,
@@ -24,8 +25,9 @@
padding: 0.3em 1em;
height: 1.6em;
position: relative;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-window-outerheader,
diff --git a/WebContent/VAADIN/themes/reindeer/datefield/datefield.css b/WebContent/VAADIN/themes/reindeer/datefield/datefield.css
index bc8f617845..1ececf9fb4 100644
--- a/WebContent/VAADIN/themes/reindeer/datefield/datefield.css
+++ b/WebContent/VAADIN/themes/reindeer/datefield/datefield.css
@@ -250,8 +250,9 @@ td.v-datefield-calendarpanel-nextyear {
-webkit-border-top-right-radius: 0;
-webkit-border-bottom-right-radius: 0;
height: 23px;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-datefield.v-readonly input.v-datefield-textfield {
border-right-width: 1px;
diff --git a/WebContent/VAADIN/themes/reindeer/select/select.css b/WebContent/VAADIN/themes/reindeer/select/select.css
index 903066e4ab..8962862702 100644
--- a/WebContent/VAADIN/themes/reindeer/select/select.css
+++ b/WebContent/VAADIN/themes/reindeer/select/select.css
@@ -18,8 +18,9 @@
.v-window input.v-filterselect-input,
.v-popupview-popup input.v-filterselect-input {
padding: 4px 0 4px 2px;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-filterselect-prompt .v-filterselect-input {
font-style: normal;
diff --git a/WebContent/VAADIN/themes/reindeer/window/window.css b/WebContent/VAADIN/themes/reindeer/window/window.css
index 3015f70eb5..e1091ef98d 100644
--- a/WebContent/VAADIN/themes/reindeer/window/window.css
+++ b/WebContent/VAADIN/themes/reindeer/window/window.css
@@ -3,8 +3,9 @@
}
.v-window-wrap {
border: 1px solid #808386;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-sa .v-window-wrap,
.v-op .v-window-wrap {
diff --git a/WebContent/VAADIN/themes/runo/window/window.css b/WebContent/VAADIN/themes/runo/window/window.css
index d412f66605..675c8942bf 100644
--- a/WebContent/VAADIN/themes/runo/window/window.css
+++ b/WebContent/VAADIN/themes/runo/window/window.css
@@ -27,8 +27,9 @@
border: 2px solid #babfc0;
border-top: none;
border-bottom: none;
- box-sizing: border-box;
+ -webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
+ box-sizing: border-box;
}
.v-window div.v-window-footer {
height: 8px;
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index 1ca217bc56..1b56b7fb9c 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -71,16 +71,34 @@
<h2 id="enhancements">Enhancements in Vaadin @version-minor@</h2>
<p>
- @version-minor@ is the first development release of the upcoming Version 7 of the
- Vaadin Framework. It introduces the first set of new features in Vaadin 7, for the
- purpose of receiving feedback regarding the changes.
+ @version-minor@ is the second development release of the upcoming Version 7 of the
+ Vaadin Framework. It introduces the second set of new features in Vaadin 7, for the
+ purpose of receiving feedback about the changes.
</p>
- <p>The major changes in this first phase are:
+ <p>The major changes in this second alpha phase are:
<ul>
- <li>Redesign of the window and application APIs</li>
- <li>Redesign of forms and data binding</li>
+ <li>Complete overhaul of the client-server communication architecture
+ <ul>
+ <li>All add-on components that have widgets need to be ported to Vaadin 7</li>
+ <li>Integration of a GWT widget is done in a <i>connector</i> class</li>
+ <li>Component-to-widget mapping now defined on the client-side, in the connector</li>
+ <li>No more <b style="text-decoration: line-through">Paintable</b> or <b style="text-decoration: line-through">VariableOwner</b>
+ <li>Server-side component and client-side widget can have a <emphasis>shared state</emphasis> object which is automatically synchronized</li>
+ <li>Both client-side and server-side can make RPC calls to the other side
+ <ul>
+ <li>Communicated in the next request/response</li>
+ <li>No return values
+ <li>Typically for communicating events</li>
+ </ul>
+ </li>
+ <li>UIDL is deprecated</li>
+ <li>Compatibility layer for Vaadin 6 included for easy migration</li>
+ </ul>
+ </li>
+ <li>Get computed style of a component from the browser</li>
+ <li>Support for border, padding, and margin in core layout components</li>
</ul>
<p>
@@ -93,7 +111,7 @@
<p>
For a complete list of changes in this release, please see the <a
- href="http://dev.vaadin.com/query?status=closed&group=resolution&milestone=Vaadin+7.0.0.alpha1">list
+ href="http://dev.vaadin.com/query?status=closed&group=resolution&milestone=Vaadin+7.0.0.alpha2">list
of closed tickets</a>.
</p>
@@ -106,6 +124,17 @@
</p>
<p>
+ Vaadin 6 add-ons (ones that contain widgets) do not work in Vaadin 7 - please
+ check the add-ons in <a href="http://vaadin.com/directory/">Vaadin Directory</a>
+ for Vaadin 7 support.
+ </p>
+
+ <p>
+ Any custom client-side widgets need to be changed to use the new client-server
+ communication API or the Vaadin 6 compatibility API.
+ </p>
+
+ <p>
A detailed list of migration changes are given in the <a
href="http://dev.vaadin.com/wiki/Vaadin7/MigrationGuide">Vaadin 7 Migration
Guide</a>.
@@ -288,8 +317,7 @@
</p>
<ul>
- <li>Windows (see the <a href="#knownissues">Zip installation
- notice above</a>)</li>
+ <li>Windows</li>
<li>Linux</li>
<li>Mac OS X</li>
</ul>
@@ -330,11 +358,11 @@
</p>
<ul>
- <li>Mozilla Firefox 10</li>
+ <li>Mozilla Firefox 11</li>
<li>Internet Explorer 8-9</li>
<li>Safari 5</li>
<li>Opera 11</li>
- <li>Google Chrome 16</li>
+ <li>Google Chrome 18</li>
</ul>
<h2 id="vaadinontheweb">Vaadin on the Web</h2>
diff --git a/WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html b/WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html
new file mode 100644
index 0000000000..2e280da64e
--- /dev/null
+++ b/WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html
@@ -0,0 +1,59 @@
+<!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"/>
+<style type="text/css">
+.wrapper {
+ height: 150px;
+ width: 150px;
+ border: 1px solid black;
+ overflow: auto;
+ position: relative;
+}
+
+.content {
+ height: 100%;
+ width: 250px;
+ background: grey;
+}
+
+</style>
+<script type="text/javascript">
+function disableScrolling() {
+ var result = document.getElementsByClassName("content");
+ for(var i = 0; i < result.length; i++) {
+ var e = result[i];
+ e.style.width = "100%";
+ }
+}
+
+function triggerReflow() {
+ var style = "top";
+ var styleValue = "1px";
+ var result = document.getElementsByClassName("wrapper");
+ for(var i = 0; i < result.length; i++) {
+ var e = result[i];
+ var originalValue = e.style[style];
+ e.style[style] = styleValue;
+ e.offsetWidth;
+ e.style[style] = originalValue;
+ }
+}
+</script>
+</head>
+<body scroll="auto">
+<p>This test is used to verify how browsers take horizontal scrollbars into account when calculating 100% height and what happens when scrolling is no longer needed. This test tells which browsers need which workarounds for related features.</p>
+
+<p>Basic situation.
+<div class="wrapper"><div class="content"></div></div>
+</p>
+
+<p>
+Situation with position: absolute on the inner element.
+<div class="wrapper"><div class="content" style="position: absolute"></div></div>
+</p>
+
+<button id="disableScrolling" onclick="disableScrolling()">Disable scrolling</button>
+<button id="triggerReflow" onclick="triggerReflow()">Trigger reflow</button>
+</body>
+</html>
diff --git a/build/build.xml b/build/build.xml
index 08423c276b..573c799f7d 100644
--- a/build/build.xml
+++ b/build/build.xml
@@ -364,6 +364,13 @@
</fileset>
</copy>
+ <!-- Add test files to be included in test war -->
+ <copy todir="${output-dir}/WebContent">
+ <fileset dir="WebContent">
+ <include name="statictestfiles/**" />
+ </fileset>
+ </copy>
+
<!-- Add servlet and portlet configuration files from WebContent -->
<copy todir="${output-dir}/WebContent/WEB-INF">
<fileset dir="WebContent/WEB-INF">
@@ -838,7 +845,7 @@
<property file="${gpg.passphrase.file}" />
<echo>Publishing ${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name} to Maven repository</echo>
- <artifact:mvn>
+ <artifact:mvn failonerror="true">
<arg value="gpg:sign-and-deploy-file"/>
<!-- .. is a workaround as maven runs in the build directory -->
<sysproperty key="file" value="../${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name}" />
diff --git a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
index 91950f5d4f..9159fa358b 100644
--- a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
+++ b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java
@@ -294,7 +294,8 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical,
return ((Container.Hierarchical) container).hasChildren(itemId);
}
- return children.get(itemId) != null;
+ LinkedList<Object> list = children.get(itemId);
+ return (list != null && !list.isEmpty());
}
/*
diff --git a/src/com/vaadin/data/util/IndexedContainer.java b/src/com/vaadin/data/util/IndexedContainer.java
index 1e0a2fae1a..bcaa5eda42 100644
--- a/src/com/vaadin/data/util/IndexedContainer.java
+++ b/src/com/vaadin/data/util/IndexedContainer.java
@@ -865,7 +865,6 @@ public class IndexedContainer extends
* @see com.vaadin.data.Property#setValue(java.lang.Object)
*/
public void setValue(Object newValue) throws Property.ReadOnlyException {
-
// Gets the Property set
final Map<Object, Object> propertySet = items.get(itemId);
@@ -875,8 +874,10 @@ public class IndexedContainer extends
} else if (getType().isAssignableFrom(newValue.getClass())) {
propertySet.put(propertyId, newValue);
} else {
- throw new IllegalArgumentException("Value is of invalid type, "
- + getType().getName() + " expected");
+ throw new IllegalArgumentException(
+ "Value is of invalid type, got "
+ + newValue.getClass().getName() + " but "
+ + getType().getName() + " was expected");
}
// update the container filtering if this property is being filtered
diff --git a/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java b/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java
index 8562bc70ec..0d29e9a327 100644
--- a/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java
+++ b/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java
@@ -6,6 +6,9 @@
*/
package com.vaadin.event.dd.acceptcriteria;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
import com.vaadin.event.TransferableImpl;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.terminal.PaintException;
@@ -22,27 +25,39 @@ import com.vaadin.ui.Component;
@SuppressWarnings("serial")
@ClientCriterion(VDragSourceIs.class)
public class SourceIs extends ClientSideCriterion {
+ private static final Logger logger = Logger.getLogger(SourceIs.class
+ .getName());
- private Component[] component;
+ private Component[] components;
public SourceIs(Component... component) {
- this.component = component;
+ components = component;
}
@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
- target.addAttribute("c", component.length);
- for (int i = 0; i < component.length; i++) {
- target.addAttribute("component" + i, component[i]);
+ int paintedComponents = 0;
+ for (int i = 0; i < components.length; i++) {
+ Component c = components[i];
+ if (c.getApplication() != null) {
+ target.addAttribute("component" + paintedComponents++, c);
+ } else {
+ logger.log(
+ Level.WARNING,
+ "SourceIs component {0} at index {1} is not attached to the component hierachy and will thus be ignored",
+ new Object[] { c.getClass().getName(),
+ Integer.valueOf(i) });
+ }
}
+ target.addAttribute("c", paintedComponents);
}
public boolean accept(DragAndDropEvent dragEvent) {
if (dragEvent.getTransferable() instanceof TransferableImpl) {
Component sourceComponent = ((TransferableImpl) dragEvent
.getTransferable()).getSourceComponent();
- for (Component c : component) {
+ for (Component c : components) {
if (c == sourceComponent) {
return true;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
index 170e949116..ff77c5904a 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
@@ -69,6 +69,7 @@ public class ApplicationConfiguration implements EntryPoint {
if (value === null || value === undefined) {
return null;
} else {
+ // $entry not needed as function is not exported
return @java.lang.Boolean::valueOf(Z)(value);
}
}-*/;
@@ -89,6 +90,7 @@ public class ApplicationConfiguration implements EntryPoint {
if (value === null || value === undefined) {
return null;
} else {
+ // $entry not needed as function is not exported
return @java.lang.Integer::valueOf(I)(value);
}
}-*/;
@@ -589,7 +591,7 @@ public class ApplicationConfiguration implements EntryPoint {
*/
public native static void registerCallback(String widgetsetName)
/*-{
- var callbackHandler = @com.vaadin.terminal.gwt.client.ApplicationConfiguration::startApplication(Ljava/lang/String;);
+ var callbackHandler = $entry(@com.vaadin.terminal.gwt.client.ApplicationConfiguration::startApplication(Ljava/lang/String;));
$wnd.vaadin.registerWidgetset(widgetsetName, callbackHandler);
}-*/;
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 2d9398320e..739c232a72 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -256,10 +256,10 @@ public class ApplicationConnection {
/*-{
var ap = this;
var client = {};
- client.isActive = function() {
+ client.isActive = $entry(function() {
return ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::hasActiveRequest()()
|| ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::isExecutingDeferredCommands()();
- }
+ });
var vi = ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::getVersionInfo()();
if (vi) {
client.getVersionInfo = function() {
@@ -267,12 +267,21 @@ public class ApplicationConnection {
}
}
- client.getElementByPath = function(id) {
+ client.getProfilingData = $entry(function() {
+ var pd = [
+ ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::lastProcessingTime,
+ ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::totalProcessingTime
+ ];
+ pd = pd.concat(ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::serverTimingInfo);
+ return pd;
+ });
+
+ client.getElementByPath = $entry(function(id) {
return componentLocator.@com.vaadin.terminal.gwt.client.ComponentLocator::getElementByPath(Ljava/lang/String;)(id);
- }
- client.getPathForElement = function(element) {
+ });
+ client.getPathForElement = $entry(function(element) {
return componentLocator.@com.vaadin.terminal.gwt.client.ComponentLocator::getPathForElement(Lcom/google/gwt/user/client/Element;)(element);
- }
+ });
$wnd.vaadin.clients[TTAppId] = client;
}-*/;
@@ -314,22 +323,22 @@ public class ApplicationConnection {
if ($wnd.vaadin.forceSync) {
oldSync = $wnd.vaadin.forceSync;
}
- $wnd.vaadin.forceSync = function() {
+ $wnd.vaadin.forceSync = $entry(function() {
if (oldSync) {
oldSync();
}
app.@com.vaadin.terminal.gwt.client.ApplicationConnection::sendPendingVariableChanges()();
- }
+ });
var oldForceLayout;
if ($wnd.vaadin.forceLayout) {
oldForceLayout = $wnd.vaadin.forceLayout;
}
- $wnd.vaadin.forceLayout = function() {
+ $wnd.vaadin.forceLayout = $entry(function() {
if (oldForceLayout) {
oldForceLayout();
}
app.@com.vaadin.terminal.gwt.client.ApplicationConnection::forceLayout()();
- }
+ });
}-*/;
/**
@@ -536,21 +545,22 @@ public class ApplicationConnection {
return;
case 503:
- // We'll assume msec instead of the usual seconds
- int delay = Integer.parseInt(response
- .getHeader("Retry-After"));
- VConsole.log("503, retrying in " + delay + "msec");
- (new Timer() {
- @Override
- public void run() {
- // TODO why? Here used to be "activeRequests--;"
- // but can't see why exactly
- hasActiveRequest = false;
- doUidlRequest(uri, payload, synchronous);
- }
- }).schedule(delay);
- return;
-
+ /*
+ * We'll assume msec instead of the usual seconds. If
+ * there's no Retry-After header, handle the error like
+ * a 500, as per RFC 2616 section 10.5.4.
+ */
+ String delay = response.getHeader("Retry-After");
+ if (delay != null) {
+ VConsole.log("503, retrying in " + delay + "msec");
+ (new Timer() {
+ @Override
+ public void run() {
+ doUidlRequest(uri, payload, synchronous);
+ }
+ }).schedule(Integer.parseInt(delay));
+ return;
+ }
}
if ((statusCode / 100) == 4) {
@@ -561,6 +571,13 @@ public class ApplicationConnection {
+ statusCode, statusCode);
endRequest();
return;
+ } else if ((statusCode / 100) == 5) {
+ // Something's wrong on the server, there's nothing the
+ // client can do except maybe try again.
+ showCommunicationError("Server error. Error code: "
+ + statusCode, statusCode);
+ endRequest();
+ return;
}
String contentType = response.getHeader("Content-Type");
@@ -663,6 +680,26 @@ public class ApplicationConnection {
}
int cssWaits = 0;
+
+ /**
+ * Holds the time spent rendering the last request
+ */
+ protected int lastProcessingTime;
+
+ /**
+ * Holds the total time spent rendering requests during the lifetime of the
+ * session.
+ */
+ protected int totalProcessingTime;
+
+ /**
+ * Holds the timing information from the server-side. How much time was
+ * spent servicing the last request and how much time has been spent
+ * servicing the session so far. These values are always one request behind,
+ * since they cannot be measured before the request is finished.
+ */
+ private ValueMap serverTimingInfo;
+
static final int MAX_CSS_WAITS = 100;
protected void handleWhenCSSLoaded(final String jsonText,
@@ -999,6 +1036,12 @@ public class ApplicationConnection {
handleUIDLDuration.logDuration(
" * Handling type mappings from server completed", 10);
+ /*
+ * Hook for e.g. TestBench to get details about server peformance
+ */
+ if (json.containsKey("timings")) {
+ serverTimingInfo = json.getValueMap("timings");
+ }
Command c = new Command() {
public void execute() {
@@ -1183,10 +1226,12 @@ public class ApplicationConnection {
// TODO build profiling for widget impl loading time
- final long prosessingTime = (new Date().getTime())
- - start.getTime();
+ lastProcessingTime = (int) ((new Date().getTime()) - start
+ .getTime());
+ totalProcessingTime += lastProcessingTime;
+
VConsole.log(" Processing time was "
- + String.valueOf(prosessingTime) + "ms for "
+ + String.valueOf(lastProcessingTime) + "ms for "
+ jsonText.length() + " characters of JSON");
VConsole.log("Referenced paintables: " + connectorMap.size());
@@ -2367,6 +2412,10 @@ public class ApplicationConnection {
return true;
}
+ if (!manageCaption) {
+ VConsole.error(Util.getConnectorString(connector)
+ + " called updateComponent with manageCaption=false. The parameter was ignored - override delegateCaption() to return false instead. It is however not recommended to use caption this way at all.");
+ }
return false;
}
diff --git a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
index ef1dc481b1..064f175301 100644
--- a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
+++ b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
@@ -28,6 +28,8 @@ public class BrowserInfo {
private static final String OS_WINDOWS = "win";
private static final String OS_LINUX = "lin";
private static final String OS_MACOSX = "mac";
+ private static final String OS_ANDROID = "android";
+ private static final String OS_IOS = "ios";
private static BrowserInfo instance;
@@ -167,13 +169,18 @@ public class BrowserInfo {
if (osClass != null) {
cssClass = cssClass + " " + prefix + osClass;
}
+
}
return cssClass;
}
private String getOperatingSystemClass() {
- if (browserDetails.isWindows()) {
+ if (browserDetails.isAndroid()) {
+ return OS_ANDROID;
+ } else if (browserDetails.isIOS()) {
+ return OS_IOS;
+ } else if (browserDetails.isWindows()) {
return OS_WINDOWS;
} else if (browserDetails.isLinux()) {
return OS_LINUX;
@@ -312,4 +319,59 @@ public class BrowserInfo {
&& Util.getNativeScrollbarSize() > 0;
}
+ /**
+ * Checks if the browser is run on iOS
+ *
+ * @return true if the browser is run on iOS, false otherwise
+ */
+ public boolean isIOS() {
+ return browserDetails.isIOS();
+ }
+
+ /**
+ * Checks if the browser is run on Android
+ *
+ * @return true if the browser is run on Android, false otherwise
+ */
+ public boolean isAndroid() {
+ return browserDetails.isAndroid();
+ }
+
+ /**
+ * Checks if the browser is capable of handling scrolling natively or if a
+ * touch scroll helper is needed for scrolling.
+ *
+ * @return true if browser needs a touch scroll helper, false if the browser
+ * can handle scrolling natively
+ */
+ public boolean requiresTouchScrollDelegate() {
+ if (!isTouchDevice()) {
+ return false;
+ }
+
+ if (isAndroid() && isWebkit() && getWebkitVersion() < 534) {
+ return true;
+ }
+ // if (isIOS() && isWebkit() && getWebkitVersion() < ???) {
+ // return true;
+ // }
+
+ return false;
+ }
+
+ /**
+ * Tests if this is an Android devices with a broken scrollTop
+ * implementation
+ *
+ * @return true if scrollTop cannot be trusted on this device, false
+ * otherwise
+ */
+ public boolean isAndroidWithBrokenScrollTop() {
+ return isAndroid()
+ && (getOperatingSystemMajorVersion() == 3 || getOperatingSystemMajorVersion() == 4);
+ }
+
+ private int getOperatingSystemMajorVersion() {
+ return browserDetails.getOperatingSystemMajorVersion();
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/CSSRule.java b/src/com/vaadin/terminal/gwt/client/CSSRule.java
index 4d9196c8d6..c36b0611e8 100644
--- a/src/com/vaadin/terminal/gwt/client/CSSRule.java
+++ b/src/com/vaadin/terminal/gwt/client/CSSRule.java
@@ -33,6 +33,7 @@ public class CSSRule {
for(var i = 0; i < sheets.length; i++) {
var sheet = sheets[i];
if(sheet.href && sheet.href.indexOf("VAADIN/themes")>-1) {
+ // $entry not needed as function is not exported
this.@com.vaadin.terminal.gwt.client.CSSRule::rules = @com.vaadin.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Z)(sheet, selector, deep);
return;
}
@@ -58,6 +59,7 @@ public class CSSRule {
// IE handles imported sheet differently
if(deep && sheet.imports && sheet.imports.length > 0) {
for(var i=0; i < sheet.imports.length; i++) {
+ // $entry not needed as function is not exported
var imports = @com.vaadin.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Z)(sheet.imports[i], selector, deep);
allMatches.concat(imports);
}
@@ -83,6 +85,7 @@ public class CSSRule {
}
} else if(deep && r.type == 3) {
// Search @import stylesheet
+ // $entry not needed as function is not exported
var imports = @com.vaadin.terminal.gwt.client.CSSRule::searchForRule(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Z)(r.styleSheet, selector, deep);
allMatches = allMatches.concat(imports);
}
@@ -102,6 +105,7 @@ public class CSSRule {
/*-{
var j = this.@com.vaadin.terminal.gwt.client.CSSRule::rules.length;
for(var i=0; i<j; i++) {
+ // $entry not needed as function is not exported
var value = this.@com.vaadin.terminal.gwt.client.CSSRule::rules[i].style[propertyName];
if(value)
return value;
diff --git a/src/com/vaadin/terminal/gwt/client/ComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ComponentConnector.java
index 34f3f13f03..5f9171084e 100644
--- a/src/com/vaadin/terminal/gwt/client/ComponentConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ComponentConnector.java
@@ -119,4 +119,12 @@ public interface ComponentConnector extends ServerConnector {
*/
public boolean delegateCaptionHandling();
+ /**
+ * Sets the enabled state of the widget associated to this connector.
+ *
+ * @param widgetEnabled
+ * true if the widget should be enabled, false otherwise
+ */
+ public void setWidgetEnabled(boolean widgetEnabled);
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java b/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java
index 3405d838a7..dfbcf9d38b 100644
--- a/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java
+++ b/src/com/vaadin/terminal/gwt/client/ComponentDetailMap.java
@@ -62,6 +62,7 @@ final class ComponentDetailMap extends JavaScriptObject {
private final native void fillWithValues(Collection<ComponentDetail> list)
/*-{
for(var key in this) {
+ // $entry not needed as function is not exported
list.@java.util.Collection::add(Ljava/lang/Object;)(this[key]);
}
}-*/;
diff --git a/src/com/vaadin/terminal/gwt/client/ComputedStyle.java b/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
index 7dc937cee7..76f2328711 100644
--- a/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
+++ b/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
@@ -179,6 +179,7 @@ public class ComputedStyle {
if (isNaN(number))
return null;
else
+ // $entry not needed as function is not exported
return @java.lang.Integer::valueOf(I)(number);
}-*/;
diff --git a/src/com/vaadin/terminal/gwt/client/LayoutManager.java b/src/com/vaadin/terminal/gwt/client/LayoutManager.java
index 55d3fbe272..79a0030140 100644
--- a/src/com/vaadin/terminal/gwt/client/LayoutManager.java
+++ b/src/com/vaadin/terminal/gwt/client/LayoutManager.java
@@ -63,10 +63,30 @@ public class LayoutManager {
this.connection = connection;
}
+ /**
+ * Gets the layout manager associated with the given
+ * {@link ApplicationConnection}.
+ *
+ * @param connection
+ * the application connection to get a layout manager for
+ * @return the layout manager associated with the provided application
+ * connection
+ */
public static LayoutManager get(ApplicationConnection connection) {
return connection.getLayoutManager();
}
+ /**
+ * Registers that a ManagedLayout is depending on the size of an Element.
+ * This causes this layout manager to measure the element in the beginning
+ * of every layout phase and call the appropriate layout method of the
+ * managed layout if the size of the element has changed.
+ *
+ * @param owner
+ * the ManagedLayout that depends on an element
+ * @param element
+ * the Element that should be measured
+ */
public void registerDependency(ManagedLayout owner, Element element) {
MeasuredSize measuredSize = ensureMeasured(element);
setNeedsLayout(owner);
@@ -98,6 +118,16 @@ public class LayoutManager {
}
}
+ /**
+ * Assigns a measured size to an element. Method defined as protected to
+ * allow separate implementation for IE8 in which delete not always works.
+ *
+ * @param element
+ * the dom element to attach the measured size to
+ * @param measuredSize
+ * the measured size to attach to the element. If
+ * <code>null</code>, any previous measured size is removed.
+ */
protected native void setMeasuredSize(Element element,
MeasuredSize measuredSize)
/*-{
@@ -124,6 +154,17 @@ public class LayoutManager {
return measuredSize;
}
+ /**
+ * Registers that a ManagedLayout is no longer depending on the size of an
+ * Element.
+ *
+ * @see #registerDependency(ManagedLayout, Element)
+ *
+ * @param owner
+ * the ManagedLayout no longer depends on an element
+ * @param element
+ * the Element that that no longer needs to be measured
+ */
public void unregisterDependency(ManagedLayout owner, Element element) {
MeasuredSize measuredSize = getMeasuredSize(element, null);
if (measuredSize == null) {
@@ -176,8 +217,6 @@ public class LayoutManager {
private void doLayout() {
VConsole.log("Starting layout phase");
- Duration totalDuration = new Duration();
-
Map<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>();
int passes = 0;
@@ -192,9 +231,6 @@ public class LayoutManager {
needsVerticalLayout.clear();
for (ComponentConnector connector : needsMeasure) {
- // Ensure the MeasuredSize is attached to the DOM element before
- // doing measurements to avoid reflows in "some" browsers
- getMeasuredSize(connector);
currentDependencyTree.setNeedsMeasure(connector, true);
}
needsMeasure.clear();
@@ -358,9 +394,8 @@ public class LayoutManager {
VConsole.log("Invoke post layout listeners in "
+ (totalDuration.elapsedMillis() - postLayoutStart) + " ms");
- VConsole.log("<b>Total layout phase time: "
- + totalDuration.elapsedMillis() + "ms</b>");
-
+ VConsole.log("Total layout phase time: "
+ + totalDuration.elapsedMillis() + "ms");
}
private void logConnectorStatus(int connectorId) {
@@ -573,84 +608,408 @@ public class LayoutManager {
layoutNow();
}
- // TODO Rename to setNeedsLayout
+ /**
+ * Marks that a ManagedLayout should be layouted in the next layout phase
+ * even if none of the elements managed by the layout have been resized.
+ *
+ * @param layout
+ * the managed layout that should be layouted
+ */
public final void setNeedsLayout(ManagedLayout layout) {
setNeedsHorizontalLayout(layout);
setNeedsVerticalLayout(layout);
}
+ /**
+ * Marks that a ManagedLayout should be layouted horizontally in the next
+ * layout phase even if none of the elements managed by the layout have been
+ * resized horizontally.
+ *
+ * For SimpleManagedLayout which is always layouted in both directions, this
+ * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
+ *
+ * @param layout
+ * the managed layout that should be layouted
+ */
public final void setNeedsHorizontalLayout(ManagedLayout layout) {
needsHorizontalLayout.add(layout);
}
+ /**
+ * Marks that a ManagedLayout should be layouted vertically in the next
+ * layout phase even if none of the elements managed by the layout have been
+ * resized vertically.
+ *
+ * For SimpleManagedLayout which is always layouted in both directions, this
+ * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
+ *
+ * @param layout
+ * the managed layout that should be layouted
+ */
public final void setNeedsVerticalLayout(ManagedLayout layout) {
needsVerticalLayout.add(layout);
}
- public boolean isMeasured(Element element) {
- return getMeasuredSize(element, nullSize) != nullSize;
- }
-
+ /**
+ * Gets the outer height (including margins, paddings and borders) of the
+ * given element, provided that it has been measured. These elements are
+ * guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * -1 is returned if the element has not been measured. If 0 is returned, it
+ * might indicate that the element is not attached to the DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured outer height (including margins, paddings and
+ * borders) of the element in pixels.
+ */
public final int getOuterHeight(Element element) {
return getMeasuredSize(element, nullSize).getOuterHeight();
}
+ /**
+ * Gets the outer width (including margins, paddings and borders) of the
+ * given element, provided that it has been measured. These elements are
+ * guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * -1 is returned if the element has not been measured. If 0 is returned, it
+ * might indicate that the element is not attached to the DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured outer width (including margins, paddings and
+ * borders) of the element in pixels.
+ */
public final int getOuterWidth(Element element) {
return getMeasuredSize(element, nullSize).getOuterWidth();
}
+ /**
+ * Gets the inner height (excluding margins, paddings and borders) of the
+ * given element, provided that it has been measured. These elements are
+ * guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * -1 is returned if the element has not been measured. If 0 is returned, it
+ * might indicate that the element is not attached to the DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured inner height (excluding margins, paddings and
+ * borders) of the element in pixels.
+ */
public final int getInnerHeight(Element element) {
return getMeasuredSize(element, nullSize).getInnerHeight();
}
+ /**
+ * Gets the inner width (excluding margins, paddings and borders) of the
+ * given element, provided that it has been measured. These elements are
+ * guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * -1 is returned if the element has not been measured. If 0 is returned, it
+ * might indicate that the element is not attached to the DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured inner width (excluding margins, paddings and
+ * borders) of the element in pixels.
+ */
public final int getInnerWidth(Element element) {
return getMeasuredSize(element, nullSize).getInnerWidth();
}
+ /**
+ * Gets the border height (top border + bottom border) of the given element,
+ * provided that it has been measured. These elements are guaranteed to be
+ * measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured border height (top border + bottom border) of the
+ * element in pixels.
+ */
public final int getBorderHeight(Element element) {
return getMeasuredSize(element, nullSize).getBorderHeight();
}
+ /**
+ * Gets the padding height (top padding + bottom padding) of the given
+ * element, provided that it has been measured. These elements are
+ * guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured padding height (top padding + bottom padding) of the
+ * element in pixels.
+ */
public int getPaddingHeight(Element element) {
return getMeasuredSize(element, nullSize).getPaddingHeight();
}
+ /**
+ * Gets the border width (left border + right border) of the given element,
+ * provided that it has been measured. These elements are guaranteed to be
+ * measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured border width (left border + right border) of the
+ * element in pixels.
+ */
public int getBorderWidth(Element element) {
return getMeasuredSize(element, nullSize).getBorderWidth();
}
+ /**
+ * Gets the padding width (left padding + right padding) of the given
+ * element, provided that it has been measured. These elements are
+ * guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured padding width (left padding + right padding) of the
+ * element in pixels.
+ */
public int getPaddingWidth(Element element) {
return getMeasuredSize(element, nullSize).getPaddingWidth();
}
+ /**
+ * Gets the top padding of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured top padding of the element in pixels.
+ */
public int getPaddingTop(Element element) {
return getMeasuredSize(element, nullSize).getPaddingTop();
}
+ /**
+ * Gets the left padding of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured left padding of the element in pixels.
+ */
public int getPaddingLeft(Element element) {
return getMeasuredSize(element, nullSize).getPaddingLeft();
}
+ /**
+ * Gets the bottom padding of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured bottom padding of the element in pixels.
+ */
public int getPaddingBottom(Element element) {
return getMeasuredSize(element, nullSize).getPaddingBottom();
}
+ /**
+ * Gets the right padding of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured right padding of the element in pixels.
+ */
public int getPaddingRight(Element element) {
return getMeasuredSize(element, nullSize).getPaddingRight();
}
+ /**
+ * Gets the top margin of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured top margin of the element in pixels.
+ */
public int getMarginTop(Element element) {
return getMeasuredSize(element, nullSize).getMarginTop();
}
+ /**
+ * Gets the right margin of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured right margin of the element in pixels.
+ */
public int getMarginRight(Element element) {
return getMeasuredSize(element, nullSize).getMarginRight();
}
+ /**
+ * Gets the bottom margin of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured bottom margin of the element in pixels.
+ */
public int getMarginBottom(Element element) {
return getMeasuredSize(element, nullSize).getMarginBottom();
}
+ /**
+ * Gets the left margin of the given element, provided that it has been
+ * measured. These elements are guaranteed to be measured:
+ * <ul>
+ * <li>ManagedLayotus and their child Connectors
+ * <li>Elements for which there is at least one ElementResizeListener
+ * <li>Elements for which at least one ManagedLayout has registered a
+ * dependency
+ * </ul>
+ *
+ * A negative number is returned if the element has not been measured. If 0
+ * is returned, it might indicate that the element is not attached to the
+ * DOM.
+ *
+ * @param element
+ * the element to get the measured size for
+ * @return the measured left margin of the element in pixels.
+ */
public int getMarginLeft(Element element) {
return getMeasuredSize(element, nullSize).getMarginLeft();
}
@@ -663,6 +1022,19 @@ public class LayoutManager {
return getMeasuredSize(element, nullSize).getMarginHeight();
}
+ /**
+ * Registers the outer height (including margins, borders and paddings) of a
+ * component. This can be used as an optimization by ManagedLayouts; by
+ * informing the LayoutManager about what size a component will have, the
+ * layout propagation can continue directly without first measuring the
+ * potentially resized elements.
+ *
+ * @param component
+ * the component for which the size is reported
+ * @param outerHeight
+ * the new outer height (including margins, borders and paddings)
+ * of the component in pixels
+ */
public void reportOuterHeight(ComponentConnector component, int outerHeight) {
MeasuredSize measuredSize = getMeasuredSize(component);
if (isLayoutRunning()) {
@@ -679,6 +1051,19 @@ public class LayoutManager {
}
}
+ /**
+ * Registers the height reserved for a relatively sized component. This can
+ * be used as an optimization by ManagedLayouts; by informing the
+ * LayoutManager about what size a component will have, the layout
+ * propagation can continue directly without first measuring the potentially
+ * resized elements.
+ *
+ * @param component
+ * the relatively sized component for which the size is reported
+ * @param assignedHeight
+ * the inner height of the relatively sized component's parent
+ * element in pixels
+ */
public void reportHeightAssignedToRelative(ComponentConnector component,
int assignedHeight) {
assert component.isRelativeHeight();
@@ -689,6 +1074,19 @@ public class LayoutManager {
reportOuterHeight(component, effectiveHeight);
}
+ /**
+ * Registers the width reserved for a relatively sized component. This can
+ * be used as an optimization by ManagedLayouts; by informing the
+ * LayoutManager about what size a component will have, the layout
+ * propagation can continue directly without first measuring the potentially
+ * resized elements.
+ *
+ * @param component
+ * the relatively sized component for which the size is reported
+ * @param assignedWidth
+ * the inner width of the relatively sized component's parent
+ * element in pixels
+ */
public void reportWidthAssignedToRelative(ComponentConnector component,
int assignedWidth) {
assert component.isRelativeWidth();
@@ -703,6 +1101,19 @@ public class LayoutManager {
return Float.parseFloat(size.substring(0, size.length() - 1));
}
+ /**
+ * Registers the outer width (including margins, borders and paddings) of a
+ * component. This can be used as an optimization by ManagedLayouts; by
+ * informing the LayoutManager about what size a component will have, the
+ * layout propagation can continue directly without first measuring the
+ * potentially resized elements.
+ *
+ * @param component
+ * the component for which the size is reported
+ * @param outerWidth
+ * the new outer width (including margins, borders and paddings)
+ * of the component in pixels
+ */
public void reportOuterWidth(ComponentConnector component, int outerWidth) {
MeasuredSize measuredSize = getMeasuredSize(component);
if (isLayoutRunning()) {
@@ -719,6 +1130,18 @@ public class LayoutManager {
}
}
+ /**
+ * Adds a listener that will be notified whenever the size of a specific
+ * element changes. Adding a listener to an element also ensures that all
+ * sizes for that element will be available starting from the next layout
+ * phase.
+ *
+ * @param element
+ * the element that should be checked for size changes
+ * @param listener
+ * an ElementResizeListener that will be informed whenever the
+ * size of the target element has changed
+ */
public void addElementResizeListener(Element element,
ElementResizeListener listener) {
Collection<ElementResizeListener> listeners = elementResizeListeners
@@ -731,6 +1154,18 @@ public class LayoutManager {
listeners.add(listener);
}
+ /**
+ * Removes an element resize listener from the provided element. This might
+ * cause this LayoutManager to stop tracking the size of the element if no
+ * other sources are interested in the size.
+ *
+ * @param element
+ * the element to which the element resize listener was
+ * previously added
+ * @param listener
+ * the ElementResizeListener that should no longer get informed
+ * about size changes to the target element.
+ */
public void removeElementResizeListener(Element element,
ElementResizeListener listener) {
Collection<ElementResizeListener> listeners = elementResizeListeners
@@ -751,6 +1186,16 @@ public class LayoutManager {
}
}
+ /**
+ * Informs this LayoutManager that the size of a component might have
+ * changed. If there is no upcoming layout phase, a new layout phase is
+ * scheduled. This method should be used whenever a size might have changed
+ * from outside of Vaadin's normal update phase, e.g. when an icon has been
+ * loaded or when the user resizes some part of the UI using the mouse.
+ *
+ * @param component
+ * the component whose size might have changed.
+ */
public void setNeedsMeasure(ComponentConnector component) {
if (isLayoutRunning()) {
currentDependencyTree.setNeedsMeasure(component, true);
diff --git a/src/com/vaadin/terminal/gwt/client/ServerConnector.java b/src/com/vaadin/terminal/gwt/client/ServerConnector.java
index f179b29054..c10f4bb411 100644
--- a/src/com/vaadin/terminal/gwt/client/ServerConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ServerConnector.java
@@ -46,11 +46,9 @@ public interface ServerConnector extends Connector {
public ApplicationConnection getConnection();
/**
- * Tests whether the connector is enabled or not. Disabled connectors will
- * ignore all attempts at communications. Received messages will be
- * discarded. This method must check that the connector is enabled in
- * context, that is if it's parent is disabled, this method must return
- * false.
+ * Tests whether the connector is enabled or not. This method checks that
+ * the connector is enabled in context, i.e. if the parent connector is
+ * disabled, this method must return false.
*
* @return true if the connector is enabled, false otherwise
*/
diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java
index bfe63caefd..c392a0ba9c 100644
--- a/src/com/vaadin/terminal/gwt/client/Util.java
+++ b/src/com/vaadin/terminal/gwt/client/Util.java
@@ -978,6 +978,19 @@ public class Util {
*/
final Element target = getElementFromPoint(touch.getClientX(),
touch.getClientY());
+
+ /*
+ * Fixes infocusable form fields in Safari of iOS 5.x and some Android
+ * browsers.
+ */
+ Widget targetWidget = findWidget(target, null);
+ if (targetWidget instanceof com.google.gwt.user.client.ui.Focusable) {
+ final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) targetWidget;
+ toBeFocusedWidget.setFocus(true);
+ } else if (targetWidget instanceof Focusable) {
+ ((Focusable) targetWidget).focus();
+ }
+
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
public void execute() {
try {
diff --git a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java
index 89e106f063..6e0417149c 100644
--- a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java
+++ b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java
@@ -31,14 +31,19 @@ public class VBrowserDetails implements Serializable {
private boolean isOpera = false;
private boolean isIE = false;
- private boolean isWindows = false;
- private boolean isMacOSX = false;
- private boolean isLinux = false;
+ private OperatingSystem os = OperatingSystem.UNKNOWN;
+
+ public enum OperatingSystem {
+ UNKNOWN, WINDOWS, MACOSX, LINUX, IOS, ANDROID;
+ }
private float browserEngineVersion = -1;
private int browserMajorVersion = -1;
private int browserMinorVersion = -1;
+ private int osMajorVersion = -1;
+ private int osMinorVersion = -1;
+
/**
* Create an instance based on the given user agent.
*
@@ -122,14 +127,80 @@ public class VBrowserDetails implements Serializable {
// Operating system
if (userAgent.contains("windows ")) {
- isWindows = true;
+ os = OperatingSystem.WINDOWS;
} else if (userAgent.contains("linux")) {
- isLinux = true;
+ if (userAgent.contains("android")) {
+ os = OperatingSystem.ANDROID;
+ parseAndroidVersion(userAgent);
+ } else {
+ os = OperatingSystem.LINUX;
+
+ }
} else if (userAgent.contains("macintosh")
|| userAgent.contains("mac osx")
|| userAgent.contains("mac os x")) {
- isMacOSX = true;
+ if (userAgent.contains("ipad") || userAgent.contains("ipod")
+ || userAgent.contains("iphone")) {
+ os = OperatingSystem.IOS;
+ parseIOSVersion(userAgent);
+ } else {
+ os = OperatingSystem.MACOSX;
+ }
+ }
+ }
+
+ private void parseAndroidVersion(String userAgent) {
+ // Android 5.1;
+ if (!userAgent.contains("android")) {
+ return;
+ }
+
+ String osVersionString = safeSubstring(userAgent,
+ userAgent.indexOf("android ") + "android ".length(),
+ userAgent.length());
+ osVersionString = safeSubstring(osVersionString, 0,
+ osVersionString.indexOf(";"));
+ String[] parts = osVersionString.split("\\.");
+ parseOsVersion(parts);
+ }
+
+ private void parseIOSVersion(String userAgent) {
+ // OS 5_1 like Mac OS X
+ if (!userAgent.contains("os ") || !userAgent.contains(" like mac")) {
+ return;
+ }
+
+ String osVersionString = safeSubstring(userAgent,
+ userAgent.indexOf("os ") + 3, userAgent.indexOf(" like mac"));
+ String[] parts = osVersionString.split("_");
+ parseOsVersion(parts);
+ }
+
+ private void parseOsVersion(String[] parts) {
+ osMajorVersion = -1;
+ osMinorVersion = -1;
+
+ if (parts.length >= 1) {
+ try {
+ osMajorVersion = Integer.parseInt(parts[0]);
+ } catch (Exception e) {
+ }
+ }
+ if (parts.length >= 2) {
+ try {
+ osMinorVersion = Integer.parseInt(parts[1]);
+ } catch (Exception e) {
+ }
+ // Some Androids report version numbers as "2.1-update1"
+ if (osMinorVersion == -1 && parts[1].contains("-")) {
+ try {
+ osMinorVersion = Integer.parseInt(parts[1].substring(0,
+ parts[1].indexOf('-')));
+ } catch (Exception ee) {
+ }
+ }
}
+
}
private void parseVersionString(String versionString) {
@@ -306,7 +377,7 @@ public class VBrowserDetails implements Serializable {
* @return true if run on Windows, false otherwise
*/
public boolean isWindows() {
- return isWindows;
+ return os == OperatingSystem.WINDOWS;
}
/**
@@ -315,7 +386,7 @@ public class VBrowserDetails implements Serializable {
* @return true if run on Mac OSX, false otherwise
*/
public boolean isMacOSX() {
- return isMacOSX;
+ return os == OperatingSystem.MACOSX;
}
/**
@@ -324,7 +395,45 @@ public class VBrowserDetails implements Serializable {
* @return true if run on Linux, false otherwise
*/
public boolean isLinux() {
- return isLinux;
+ return os == OperatingSystem.LINUX;
+ }
+
+ /**
+ * Tests if the browser is run on Android.
+ *
+ * @return true if run on Android, false otherwise
+ */
+ public boolean isAndroid() {
+ return os == OperatingSystem.ANDROID;
+ }
+
+ /**
+ * Tests if the browser is run in iOS.
+ *
+ * @return true if run in iOS, false otherwise
+ */
+ public boolean isIOS() {
+ return os == OperatingSystem.IOS;
+ }
+
+ /**
+ * Returns the major version of the operating system. Currently only
+ * supported for mobile devices (iOS/Android)
+ *
+ * @return The major version or -1 if unknown
+ */
+ public int getOperatingSystemMajorVersion() {
+ return osMajorVersion;
+ }
+
+ /**
+ * Returns the minor version of the operating system. Currently only
+ * supported for mobile devices (iOS/Android)
+ *
+ * @return The minor version or -1 if unknown
+ */
+ public int getOperatingSystemMinorVersion() {
+ return osMinorVersion;
}
/**
diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
index c2fa4f46bf..5eaf78f255 100644
--- a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
+++ b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
@@ -180,6 +180,9 @@ public class VDebugConsole extends VOverlay implements Console {
private static final String help = "Drag title=move, shift-drag=resize, doubleclick title=min/max."
+ "Use debug=quiet to log only to browser console.";
+ private static final int DEFAULT_WIDTH = 650;
+ private static final int DEFAULT_HEIGHT = 400;
+
public VDebugConsole() {
super(false, false);
getElement().getStyle().setOverflow(Overflow.HIDDEN);
@@ -301,10 +304,20 @@ public class VDebugConsole extends VOverlay implements Console {
height = Integer.parseInt(split[3]);
autoScrollValue = Boolean.valueOf(split[4]);
} else {
- width = 400;
- height = 150;
- top = Window.getClientHeight() - 160;
- left = Window.getClientWidth() - 410;
+ int windowHeight = Window.getClientHeight();
+ int windowWidth = Window.getClientWidth();
+ width = DEFAULT_WIDTH;
+ height = DEFAULT_HEIGHT;
+
+ if (height > windowHeight / 2) {
+ height = windowHeight / 2;
+ }
+ if (width > windowWidth / 2) {
+ width = windowWidth / 2;
+ }
+
+ top = windowHeight - (height + 10);
+ left = windowWidth - (width + 10);
}
setPixelSize(width, height);
setPopupPosition(left, top);
diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java
index 294626e71a..fdc06b0e21 100644
--- a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java
+++ b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java
@@ -163,6 +163,15 @@ public class JsonEncoder {
return outerArray;
}
+ /**
+ * Returns the transport type for the given value. Only returns a transport
+ * type for internally handled values.
+ *
+ * @param value
+ * The value that should be transported
+ * @return One of the JsonEncode.VTYPE_ constants or null if the value
+ * cannot be transported using an internally handled type.
+ */
private static String getTransportType(Object value) {
if (value == null) {
return VTYPE_NULL;
diff --git a/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java b/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java
index f4305ffcaa..e61775a640 100644
--- a/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java
+++ b/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java
@@ -4,6 +4,7 @@
package com.vaadin.terminal.gwt.client.communication;
+import java.io.Serializable;
import java.util.Arrays;
/**
@@ -12,19 +13,24 @@ import java.util.Arrays;
*
* @since 7.0
*/
-public class MethodInvocation {
+public class MethodInvocation implements Serializable {
private final String connectorId;
private final String interfaceName;
private final String methodName;
- private final Object[] parameters;
+ private Object[] parameters;
public MethodInvocation(String connectorId, String interfaceName,
- String methodName, Object[] parameters) {
+ String methodName) {
this.connectorId = connectorId;
this.interfaceName = interfaceName;
this.methodName = methodName;
- this.parameters = parameters;
+ }
+
+ public MethodInvocation(String connectorId, String interfaceName,
+ String methodName, Object[] parameters) {
+ this(connectorId, interfaceName, methodName);
+ setParameters(parameters);
}
public String getConnectorId() {
@@ -43,9 +49,14 @@ public class MethodInvocation {
return parameters;
}
+ public void setParameters(Object[] parameters) {
+ this.parameters = parameters;
+ }
+
@Override
public String toString() {
return connectorId + ":" + interfaceName + "." + methodName + "("
+ Arrays.toString(parameters) + ")";
}
+
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
index 2458a27eac..fdb04f0ddf 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
@@ -5,8 +5,8 @@ package com.vaadin.terminal.gwt.client.ui;
import java.util.Set;
-import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.Focusable;
+import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.ComponentConnector;
@@ -102,10 +102,7 @@ public abstract class AbstractComponentConnector extends AbstractConnector
.getTabIndex());
}
- if (getWidget() instanceof FocusWidget) {
- FocusWidget fw = (FocusWidget) getWidget();
- fw.setEnabled(isEnabled());
- }
+ setWidgetEnabled(isEnabled());
// Style names
String styleName = getStyleNames(getWidget().getStylePrimaryName());
@@ -141,6 +138,12 @@ public abstract class AbstractComponentConnector extends AbstractConnector
updateComponentSize();
}
+ public void setWidgetEnabled(boolean widgetEnabled) {
+ if (getWidget() instanceof HasEnabled) {
+ ((HasEnabled) getWidget()).setEnabled(widgetEnabled);
+ }
+ }
+
private void updateComponentSize() {
String newWidth = getState().getWidth();
String newHeight = getState().getHeight();
@@ -338,12 +341,13 @@ public abstract class AbstractComponentConnector extends AbstractConnector
public void onUnregister() {
super.onUnregister();
- // Warn if widget is still attached to DOM. It should never be at this
- // point.
+ // Show an error if widget is still attached to DOM. It should never be
+ // at this point.
if (getWidget() != null && getWidget().isAttached()) {
- VConsole.log("Widget for unregistered connector "
+ getWidget().removeFromParent();
+ VConsole.error("Widget is still attached to the DOM after the connector ("
+ Util.getConnectorString(this)
- + " is still attached to the DOM.");
+ + ") has been unregistered. Widget was removed.");
}
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java
index d6ffc0f091..526631e4b2 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java
@@ -23,6 +23,14 @@ public abstract class AbstractComponentContainerConnector extends
private final boolean debugLogging = false;
/**
+ * Temporary storage for last enabled state to be able to see if it has
+ * changed. Can be removed once we are able to listen specifically for
+ * enabled changes in the state. Widget.isEnabled() cannot be used as all
+ * Widgets do not implement HasEnabled
+ */
+ private boolean lastWidgetEnabledState = true;
+
+ /**
* Default constructor
*/
public AbstractComponentContainerConnector() {
@@ -85,4 +93,18 @@ public abstract class AbstractComponentContainerConnector extends
ConnectorHierarchyChangeEvent.TYPE, handler);
}
+ @Override
+ public void setWidgetEnabled(boolean widgetEnabled) {
+ if (lastWidgetEnabledState == widgetEnabled) {
+ return;
+ }
+ lastWidgetEnabledState = widgetEnabled;
+
+ super.setWidgetEnabled(widgetEnabled);
+ for (ComponentConnector c : getChildren()) {
+ // Update children as they might be affected by the enabled state of
+ // their parent
+ c.setWidgetEnabled(c.isEnabled());
+ }
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickRPC.java b/src/com/vaadin/terminal/gwt/client/ui/ClickRpc.java
index 6c81b282e8..37d6443f55 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/ClickRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/ClickRpc.java
@@ -6,7 +6,7 @@ package com.vaadin.terminal.gwt.client.ui;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-public interface ClickRPC extends ServerRpc {
+public interface ClickRpc extends ServerRpc {
/**
* Called when a click event has occurred and there are server side
* listeners for the event.
diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
index 6b22f3c9f3..62697c4d98 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
@@ -3,6 +3,8 @@
*/
package com.vaadin.terminal.gwt.client.ui;
+import java.util.ArrayList;
+
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.DivElement;
@@ -21,6 +23,7 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.impl.FocusImpl;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
/**
* A scrollhandlers similar to {@link ScrollPanel}.
@@ -126,7 +129,11 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
* @return the vertical scroll position, in pixels
*/
public int getScrollPosition() {
- return getElement().getScrollTop();
+ if (getElement().getPropertyJSO("_vScrollTop") != null) {
+ return getElement().getPropertyInt("_vScrollTop");
+ } else {
+ return getElement().getScrollTop();
+ }
}
/**
@@ -146,7 +153,18 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
* the new vertical scroll position, in pixels
*/
public void setScrollPosition(int position) {
- getElement().setScrollTop(position);
+ if (BrowserInfo.get().isAndroidWithBrokenScrollTop()) {
+ ArrayList<com.google.gwt.dom.client.Element> elements = TouchScrollDelegate
+ .getElements(getElement());
+ for (com.google.gwt.dom.client.Element el : elements) {
+ final Style style = el.getStyle();
+ style.setProperty("webkitTransform", "translate3d(0px,"
+ + -position + "px,0px)");
+ }
+ getElement().setPropertyInt("_vScrollTop", position);
+ } else {
+ getElement().setScrollTop(position);
+ }
}
public void onScroll(ScrollEvent event) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java
index 09caa9ad82..7a5d85e34b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java
@@ -35,5 +35,5 @@ public abstract class LayoutClickEventHandler extends AbstractClickEventHandler
getLayoutClickRPC().layoutClick(mouseDetails, getChildComponent(event));
}
- protected abstract LayoutClickRPC getLayoutClickRPC();
+ protected abstract LayoutClickRpc getLayoutClickRPC();
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRPC.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRpc.java
index 20b9c8750b..5b76f398a9 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRpc.java
@@ -7,7 +7,7 @@ import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-public interface LayoutClickRPC extends ServerRpc {
+public interface LayoutClickRpc extends ServerRpc {
/**
* Called when a layout click event has occurred and there are server side
* listeners for the event.
diff --git a/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java b/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java
index 3c08741de5..8b2248aff6 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java
@@ -4,19 +4,22 @@
package com.vaadin.terminal.gwt.client.ui;
import java.util.ArrayList;
-import java.util.Date;
+import com.google.gwt.animation.client.Animation;
+import com.google.gwt.core.client.Duration;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Touch;
+import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.VConsole;
/**
@@ -64,27 +67,33 @@ public class TouchScrollDelegate implements NativePreviewHandler {
private static final double FRICTION = 0.002;
private static final double DECELERATION = 0.002;
private static final int MAX_DURATION = 1500;
- private int origX;
private int origY;
private Element[] scrollableElements;
private Element scrolledElement;
private int origScrollTop;
private HandlerRegistration handlerRegistration;
+ private double lastAnimatedTranslateY;
private int lastClientY;
- private double pixxelsPerMs;
- private boolean transitionPending = false;
private int deltaScrollPos;
private boolean transitionOn = false;
private int finalScrollTop;
private ArrayList<Element> layers;
private boolean moved;
+ private ScrollHandler scrollHandler;
private static TouchScrollDelegate activeScrollDelegate;
+ private static final boolean androidWithBrokenScrollTop = BrowserInfo.get()
+ .isAndroidWithBrokenScrollTop();
+
public TouchScrollDelegate(Element... elements) {
scrollableElements = elements;
}
+ public void setScrollHandler(ScrollHandler scrollHandler) {
+ this.scrollHandler = scrollHandler;
+ }
+
public static TouchScrollDelegate getActiveScrollDelegate() {
return activeScrollDelegate;
}
@@ -116,37 +125,8 @@ public class TouchScrollDelegate implements NativePreviewHandler {
public void onTouchStart(TouchStartEvent event) {
if (activeScrollDelegate == null && event.getTouches().length() == 1) {
-
- Touch touch = event.getTouches().get(0);
- if (detectScrolledElement(touch)) {
- VConsole.log("TouchDelegate takes over");
- event.stopPropagation();
- handlerRegistration = Event.addNativePreviewHandler(this);
- activeScrollDelegate = this;
- hookTransitionEndListener(scrolledElement
- .getFirstChildElement());
- origX = touch.getClientX();
- origY = touch.getClientY();
- yPositions[0] = origY;
- eventTimeStamps[0] = new Date();
- nextEvent = 1;
-
- if (transitionOn) {
- // TODO calculate current position of ongoing transition,
- // fix to that and start scroll from there. Another option
- // is to investigate if we can get even close the same
- // framerate with scheduler based impl instead of using
- // transitions (GWT examples has impl of this, with jsni
- // though). This is very smooth on native ipad, now we
- // ignore touch starts during animation.
- origScrollTop = scrolledElement.getScrollTop();
- } else {
- origScrollTop = scrolledElement.getScrollTop();
- }
- moved = false;
- // event.preventDefault();
- // event.stopPropagation();
- }
+ NativeEvent nativeEvent = event.getNativeEvent();
+ doTouchStart(nativeEvent);
} else {
/*
* Touch scroll is currenly on (possibly bouncing). Ignore.
@@ -154,16 +134,39 @@ public class TouchScrollDelegate implements NativePreviewHandler {
}
}
- private native void hookTransitionEndListener(Element element)
- /*-{
- if(!element.hasTransitionEndListener) {
- var that = this;
- element.addEventListener("webkitTransitionEnd",function(event){
- that.@com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate::onTransitionEnd()();
- },false);
- element.hasTransitionEndListener = true;
+ private void doTouchStart(NativeEvent nativeEvent) {
+ if (transitionOn) {
+ momentum.cancel();
+ }
+ Touch touch = nativeEvent.getTouches().get(0);
+ if (detectScrolledElement(touch)) {
+ VConsole.log("TouchDelegate takes over");
+ nativeEvent.stopPropagation();
+ handlerRegistration = Event.addNativePreviewHandler(this);
+ activeScrollDelegate = this;
+ origY = touch.getClientY();
+ yPositions[0] = origY;
+ eventTimeStamps[0] = getTimeStamp();
+ nextEvent = 1;
+
+ origScrollTop = getScrollTop();
+ VConsole.log("ST" + origScrollTop);
+
+ moved = false;
+ // event.preventDefault();
+ // event.stopPropagation();
+ }
+ }
+
+ private int getScrollTop() {
+ if (androidWithBrokenScrollTop) {
+ if (scrolledElement.getPropertyJSO("_vScrollTop") != null) {
+ return scrolledElement.getPropertyInt("_vScrollTop");
+ }
+ return 0;
}
- }-*/;
+ return scrolledElement.getScrollTop();
+ }
private void onTransitionEnd() {
if (finalScrollTop < 0) {
@@ -175,7 +178,6 @@ public class TouchScrollDelegate implements NativePreviewHandler {
} else {
moveTransformationToScrolloffset();
}
- transitionOn = false;
}
private void animateToScrollPosition(int to, int from) {
@@ -184,7 +186,14 @@ public class TouchScrollDelegate implements NativePreviewHandler {
if (time <= 0) {
time = 1; // get animation and transition end event
}
- translateTo(time, -to + origScrollTop);
+ VConsole.log("Animate " + time + " " + from + " " + to);
+ int translateTo = -to + origScrollTop;
+ int fromY = -from + origScrollTop;
+ if (androidWithBrokenScrollTop) {
+ fromY -= origScrollTop;
+ translateTo -= origScrollTop;
+ }
+ translateTo(time, fromY, translateTo);
}
private int getAnimationTimeForDistance(int dist) {
@@ -200,16 +209,21 @@ public class TouchScrollDelegate implements NativePreviewHandler {
* scrolltop, causing onscroll event.
*/
private void moveTransformationToScrolloffset() {
- for (Element el : layers) {
- Style style = el.getStyle();
- style.setProperty("webkitTransitionProperty", "none");
- style.setProperty("webkitTransform", "translate3d(0,0,0)");
+ if (androidWithBrokenScrollTop) {
+ scrolledElement.setPropertyInt("_vScrollTop", finalScrollTop);
+ if (scrollHandler != null) {
+ scrollHandler.onScroll(null);
+ }
+ } else {
+ for (Element el : layers) {
+ Style style = el.getStyle();
+ style.setProperty("webkitTransform", "translate3d(0,0,0)");
+ }
+ scrolledElement.setScrollTop(finalScrollTop);
}
- scrolledElement.setScrollTop(finalScrollTop);
activeScrollDelegate = null;
handlerRegistration.removeHandler();
handlerRegistration = null;
-
}
/**
@@ -225,14 +239,7 @@ public class TouchScrollDelegate implements NativePreviewHandler {
if (el.isOrHasChild(target)
&& el.getScrollHeight() > el.getClientHeight()) {
scrolledElement = el;
- NodeList<Node> childNodes = scrolledElement.getChildNodes();
- layers = new ArrayList<Element>();
- for (int i = 0; i < childNodes.getLength(); i++) {
- Node item = childNodes.getItem(i);
- if (item.getNodeType() == Node.ELEMENT_NODE) {
- layers.add((Element) item);
- }
- }
+ layers = getElements(scrolledElement);
return true;
}
@@ -240,10 +247,21 @@ public class TouchScrollDelegate implements NativePreviewHandler {
return false;
}
+ public static ArrayList<Element> getElements(Element scrolledElement2) {
+ NodeList<Node> childNodes = scrolledElement2.getChildNodes();
+ ArrayList<Element> l = new ArrayList<Element>();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node item = childNodes.getItem(i);
+ if (item.getNodeType() == Node.ELEMENT_NODE) {
+ l.add((Element) item);
+ }
+ }
+ return l;
+ }
+
private void onTouchMove(NativeEvent event) {
if (!moved) {
- Date date = new Date();
- long l = (date.getTime() - eventTimeStamps[0].getTime());
+ double l = (getTimeStamp() - eventTimeStamps[0]);
VConsole.log(l + " ms from start to move");
}
boolean handleMove = readPositionAndSpeed(event);
@@ -255,15 +273,15 @@ public class TouchScrollDelegate implements NativePreviewHandler {
int overscroll = (deltaScrollTop + origScrollTop)
- getMaxFinalY();
overscroll = overscroll / 2;
- if (overscroll > scrolledElement.getClientHeight() / 2) {
- overscroll = scrolledElement.getClientHeight() / 2;
+ if (overscroll > getMaxOverScroll()) {
+ overscroll = getMaxOverScroll();
}
deltaScrollTop = getMaxFinalY() + overscroll - origScrollTop;
} else if (finalPos < 0) {
// spring effect at the beginning
int overscroll = finalPos / 2;
- if (-overscroll > scrolledElement.getClientHeight() / 2) {
- overscroll = -scrolledElement.getClientHeight() / 2;
+ if (-overscroll > getMaxOverScroll()) {
+ overscroll = -getMaxOverScroll();
}
deltaScrollTop = overscroll - origScrollTop;
}
@@ -276,16 +294,20 @@ public class TouchScrollDelegate implements NativePreviewHandler {
private void quickSetScrollPosition(int deltaX, int deltaY) {
deltaScrollPos = deltaY;
- translateTo(0, -deltaScrollPos);
+ if (androidWithBrokenScrollTop) {
+ deltaY += origScrollTop;
+ translateTo(-deltaY);
+ } else {
+ translateTo(-deltaScrollPos);
+ }
}
private static final int EVENTS_FOR_SPEED_CALC = 3;
public static final int SIGNIFICANT_MOVE_THRESHOLD = 3;
private int[] yPositions = new int[EVENTS_FOR_SPEED_CALC];
- private Date[] eventTimeStamps = new Date[EVENTS_FOR_SPEED_CALC];
+ private double[] eventTimeStamps = new double[EVENTS_FOR_SPEED_CALC];
private int nextEvent = 0;
- private Date transitionStart;
- private Date transitionDuration;
+ private Animation momentum;
/**
*
@@ -293,12 +315,11 @@ public class TouchScrollDelegate implements NativePreviewHandler {
* @return
*/
private boolean readPositionAndSpeed(NativeEvent event) {
- Date now = new Date();
Touch touch = event.getChangedTouches().get(0);
lastClientY = touch.getClientY();
int eventIndx = nextEvent++;
eventIndx = eventIndx % EVENTS_FOR_SPEED_CALC;
- eventTimeStamps[eventIndx] = now;
+ eventTimeStamps[eventIndx] = getTimeStamp();
yPositions[eventIndx] = lastClientY;
return isMovedSignificantly();
}
@@ -348,15 +369,11 @@ public class TouchScrollDelegate implements NativePreviewHandler {
// VConsole.log("To max overscroll");
finalY = getMaxFinalY() + getMaxOverScroll();
int fixedPixelsToMove = finalY - currentY;
- pixelsPerMs = pixelsPerMs * pixelsToMove / fixedPixelsToMove
- / FRICTION;
pixelsToMove = fixedPixelsToMove;
} else if (finalY < 0 - getMaxOverScroll()) {
// VConsole.log("to min overscroll");
finalY = -getMaxOverScroll();
int fixedPixelsToMove = finalY - currentY;
- pixelsPerMs = pixelsPerMs * pixelsToMove / fixedPixelsToMove
- / FRICTION;
pixelsToMove = fixedPixelsToMove;
} else {
duration = (int) (Math.abs(pixelsPerMs / DECELERATION));
@@ -380,8 +397,13 @@ public class TouchScrollDelegate implements NativePreviewHandler {
return;
}
- int translateY = -finalY + origScrollTop;
- translateTo(duration, translateY);
+ int translateTo = -finalY + origScrollTop;
+ int fromY = -currentY + origScrollTop;
+ if (androidWithBrokenScrollTop) {
+ fromY -= origScrollTop;
+ translateTo -= origScrollTop;
+ }
+ translateTo(duration, fromY, translateTo);
}
private double calculateSpeed() {
@@ -392,47 +414,75 @@ public class TouchScrollDelegate implements NativePreviewHandler {
}
int idx = nextEvent % EVENTS_FOR_SPEED_CALC;
final int firstPos = yPositions[idx];
- final Date firstTs = eventTimeStamps[idx];
+ final double firstTs = eventTimeStamps[idx];
idx += EVENTS_FOR_SPEED_CALC;
idx--;
idx = idx % EVENTS_FOR_SPEED_CALC;
final int lastPos = yPositions[idx];
- final Date lastTs = eventTimeStamps[idx];
+ final double lastTs = eventTimeStamps[idx];
// speed as in change of scrolltop == -speedOfTouchPos
- return (firstPos - lastPos)
- / (double) (lastTs.getTime() - firstTs.getTime());
+ return (firstPos - lastPos) / (lastTs - firstTs);
}
/**
* Note positive scrolltop moves layer up, positive translate moves layer
* down.
- *
- * @param duration
- * @param translateY
*/
- private void translateTo(int duration, int translateY) {
+ private void translateTo(double translateY) {
for (Element el : layers) {
- final Style style = el.getStyle();
- if (duration > 0) {
- style.setProperty("webkitTransitionDuration", duration + "ms");
- style.setProperty("webkitTransitionTimingFunction",
- "cubic-bezier(0,0,0.25,1)");
- style.setProperty("webkitTransitionProperty",
- "-webkit-transform");
- transitionOn = true;
- transitionStart = new Date();
- transitionDuration = new Date();
- } else {
- style.setProperty("webkitTransitionProperty", "none");
- }
+ Style style = el.getStyle();
style.setProperty("webkitTransform", "translate3d(0px,"
+ translateY + "px,0px)");
}
}
+ /**
+ * Note positive scrolltop moves layer up, positive translate moves layer
+ * down.
+ *
+ * @param duration
+ */
+ private void translateTo(int duration, final int fromY, final int finalY) {
+ if (duration > 0) {
+ transitionOn = true;
+
+ momentum = new Animation() {
+
+ @Override
+ protected void onUpdate(double progress) {
+ lastAnimatedTranslateY = (fromY + (finalY - fromY)
+ * progress);
+ translateTo(lastAnimatedTranslateY);
+ }
+
+ @Override
+ protected double interpolate(double progress) {
+ return 1 + Math.pow(progress - 1, 3);
+ }
+
+ @Override
+ protected void onComplete() {
+ super.onComplete();
+ transitionOn = false;
+ onTransitionEnd();
+ }
+
+ @Override
+ protected void onCancel() {
+ int delta = (int) (finalY - lastAnimatedTranslateY);
+ finalScrollTop -= delta;
+ moveTransformationToScrolloffset();
+ transitionOn = false;
+ }
+ };
+ momentum.run(duration);
+ }
+ }
+
private int getMaxOverScroll() {
- return scrolledElement.getClientHeight() / 4;
+ return androidWithBrokenScrollTop ? 0 : scrolledElement
+ .getClientHeight() / 3;
}
private int getMaxFinalY() {
@@ -441,14 +491,18 @@ public class TouchScrollDelegate implements NativePreviewHandler {
}
public void onPreviewNativeEvent(NativePreviewEvent event) {
+ int typeInt = event.getTypeInt();
if (transitionOn) {
/*
* TODO allow starting new events. See issue in onTouchStart
*/
event.cancel();
+
+ if (typeInt == Event.ONTOUCHSTART) {
+ doTouchStart(event.getNativeEvent());
+ }
return;
}
- int typeInt = event.getTypeInt();
switch (typeInt) {
case Event.ONTOUCHMOVE:
if (!event.isCanceled()) {
@@ -484,4 +538,15 @@ public class TouchScrollDelegate implements NativePreviewHandler {
public void setElements(com.google.gwt.user.client.Element[] elements) {
scrollableElements = elements;
}
+
+ /**
+ * long calcucation are not very efficient in GWT, so this helper method
+ * returns timestamp in double.
+ *
+ * @return
+ */
+ public static double getTimeStamp() {
+ return Duration.currentTimeMillis();
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java
index 2307f67ac5..80b6254e02 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java
@@ -21,7 +21,7 @@ import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector;
import com.vaadin.terminal.gwt.client.ui.Connect;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
import com.vaadin.terminal.gwt.client.ui.absolutelayout.VAbsoluteLayout.AbsoluteWrapper;
import com.vaadin.ui.AbsoluteLayout;
@@ -38,20 +38,20 @@ public class AbsoluteLayoutConnector extends
}
@Override
- protected LayoutClickRPC getLayoutClickRPC() {
+ protected LayoutClickRpc getLayoutClickRPC() {
return rpc;
};
};
- private AbsoluteLayoutServerRPC rpc;
+ private AbsoluteLayoutServerRpc rpc;
private Map<String, AbsoluteWrapper> connectorIdToComponentWrapper = new HashMap<String, AbsoluteWrapper>();
@Override
protected void init() {
super.init();
- rpc = RpcProxy.create(AbsoluteLayoutServerRPC.class, this);
+ rpc = RpcProxy.create(AbsoluteLayoutServerRpc.class, this);
}
/**
diff --git a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRpc.java
index df7ee1b82e..d626eb5b6c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRpc.java
@@ -4,8 +4,8 @@
package com.vaadin.terminal.gwt.client.ui.absolutelayout;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
-public interface AbsoluteLayoutServerRPC extends LayoutClickRPC, ServerRpc {
+public interface AbsoluteLayoutServerRpc extends LayoutClickRpc, ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java
index 62a5e8ac8b..a555ecd392 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java
@@ -57,7 +57,11 @@ public class ButtonConnector extends AbstractComponentConnector implements
blurHandlerRegistration = EventHelper.updateBlurHandler(this,
blurHandlerRegistration);
// Set text
- getWidget().setText(getState().getCaption());
+ if (getState().isHtmlContentAllowed()) {
+ getWidget().setHtml(getState().getCaption());
+ } else {
+ getWidget().setText(getState().getCaption());
+ }
// handle error
if (null != getState().getErrorMessage()) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java
index f26cdae0c6..fdc053b3ae 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java
@@ -17,6 +17,10 @@ import com.vaadin.ui.Button;
public class ButtonState extends ComponentState {
private boolean disableOnClick = false;
private int clickShortcutKeyCode = 0;
+ /**
+ * If caption should be rendered in HTML
+ */
+ private boolean htmlContentAllowed = false;
/**
* Checks whether the button should be disabled on the client side on next
@@ -62,4 +66,30 @@ public class ButtonState extends ComponentState {
this.clickShortcutKeyCode = clickShortcutKeyCode;
}
+ /**
+ * Set whether the caption text is rendered as HTML or not. You might need
+ * to retheme button to allow higher content than the original text style.
+ *
+ * If set to true, the captions are passed to the browser as html and the
+ * developer is responsible for ensuring no harmful html is used. If set to
+ * false, the content is passed to the browser as plain text.
+ *
+ * @param htmlContentAllowed
+ * <code>true</code> if caption is rendered as HTML,
+ * <code>false</code> otherwise
+ */
+ public void setHtmlContentAllowed(boolean htmlContentAllowed) {
+ this.htmlContentAllowed = htmlContentAllowed;
+ }
+
+ /**
+ * Return HTML rendering setting.
+ *
+ * @return <code>true</code> if the caption text is to be rendered as HTML,
+ * <code>false</code> otherwise
+ */
+ public boolean isHtmlContentAllowed() {
+ return htmlContentAllowed;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java
index f7d73d3b5e..e5e7dbba8b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java
@@ -98,6 +98,10 @@ public class VButton extends FocusWidget implements ClickHandler {
captionElement.setInnerText(text);
}
+ public void setHtml(String html) {
+ captionElement.setInnerHTML(html);
+ }
+
@SuppressWarnings("deprecation")
@Override
/*
diff --git a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java
index 76fb9ab926..7df31a8593 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java
@@ -20,7 +20,7 @@ import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector;
import com.vaadin.terminal.gwt.client.ui.Connect;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
import com.vaadin.terminal.gwt.client.ui.csslayout.VCssLayout.FlowPane;
import com.vaadin.ui.CssLayout;
@@ -38,19 +38,19 @@ public class CssLayoutConnector extends AbstractLayoutConnector {
}
@Override
- protected LayoutClickRPC getLayoutClickRPC() {
+ protected LayoutClickRpc getLayoutClickRPC() {
return rpc;
};
};
- private CssLayoutServerRPC rpc;
+ private CssLayoutServerRpc rpc;
private Map<ComponentConnector, VCaption> childToCaption = new HashMap<ComponentConnector, VCaption>();
@Override
protected void init() {
super.init();
- rpc = RpcProxy.create(CssLayoutServerRPC.class, this);
+ rpc = RpcProxy.create(CssLayoutServerRpc.class, this);
}
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRpc.java
index 067ea54fdc..7ba89d4c4c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRpc.java
@@ -4,8 +4,8 @@
package com.vaadin.terminal.gwt.client.ui.csslayout;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
-public interface CssLayoutServerRPC extends LayoutClickRPC, ServerRpc {
+public interface CssLayoutServerRpc extends LayoutClickRpc, ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java b/src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java
index 5208d7cacf..b4194c40a6 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java
@@ -362,9 +362,9 @@ public class VCustomLayout extends ComplexPanel {
private native void publishResizedFunction(Element element)
/*-{
var self = this;
- element.notifyChildrenOfSizeChange = function() {
+ element.notifyChildrenOfSizeChange = $entry(function() {
self.@com.vaadin.terminal.gwt.client.ui.customlayout.VCustomLayout::notifyChildrenOfSizeChange()();
- };
+ });
}-*/;
/**
diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java
index 21e0e0820d..84b3c678eb 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java
@@ -45,6 +45,13 @@ public class VDateFieldCalendar extends VDateField {
*/
@SuppressWarnings("deprecation")
protected void updateValueFromPanel() {
+
+ // If field is invisible at the beginning, client can still be null when
+ // this function is called.
+ if (getClient() == null) {
+ return;
+ }
+
Date date2 = calendarPanel.getDate();
Date currentDate = getCurrentDate();
if (currentDate == null || date2.getTime() != currentDate.getTime()) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java
index 5cbfabbb11..d09b81e1e1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java
@@ -508,9 +508,9 @@ public class VDragAndDropWrapper extends VCustomComponent implements
protected native void hookHtml5DragStart(Element el)
/*-{
var me = this;
- el.addEventListener("dragstart", function(ev) {
+ el.addEventListener("dragstart", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragStart(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- }, false);
+ }), false);
}-*/;
/**
@@ -522,21 +522,21 @@ public class VDragAndDropWrapper extends VCustomComponent implements
/*-{
var me = this;
- el.addEventListener("dragenter", function(ev) {
+ el.addEventListener("dragenter", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragEnter(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- }, false);
+ }), false);
- el.addEventListener("dragleave", function(ev) {
+ el.addEventListener("dragleave", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragLeave(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- }, false);
+ }), false);
- el.addEventListener("dragover", function(ev) {
+ el.addEventListener("dragover", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragOver(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- }, false);
+ }), false);
- el.addEventListener("drop", function(ev) {
+ el.addEventListener("drop", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragDrop(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- }, false);
+ }), false);
}-*/;
public boolean updateDropDetails(VDragEvent drag) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java
index f819b0559a..bb511524e5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java
@@ -39,9 +39,9 @@ public class VDragAndDropWrapperIE extends VDragAndDropWrapper {
/*-{
var me = this;
- el.attachEvent("ondragstart", function(ev) {
+ el.attachEvent("ondragstart", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragStart(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- });
+ }));
}-*/;
@Override
@@ -49,21 +49,21 @@ public class VDragAndDropWrapperIE extends VDragAndDropWrapper {
/*-{
var me = this;
- el.attachEvent("ondragenter", function(ev) {
+ el.attachEvent("ondragenter", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragEnter(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- });
+ }));
- el.attachEvent("ondragleave", function(ev) {
+ el.attachEvent("ondragleave", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragLeave(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- });
+ }));
- el.attachEvent("ondragover", function(ev) {
+ el.attachEvent("ondragover", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragOver(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- });
+ }));
- el.attachEvent("ondrop", function(ev) {
+ el.attachEvent("ondrop", $entry(function(ev) {
return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragDrop(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev);
- });
+ }));
}-*/;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java
index 423aac1974..81ac195c8e 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java
@@ -35,12 +35,12 @@ public class EmbeddedConnector extends AbstractComponentConnector implements
public static final String ALTERNATE_TEXT = "alt";
- EmbeddedServerRPC rpc;
+ EmbeddedServerRpc rpc;
@Override
protected void init() {
super.init();
- rpc = RpcProxy.create(EmbeddedServerRPC.class, this);
+ rpc = RpcProxy.create(EmbeddedServerRpc.class, this);
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRpc.java
index e3410e408e..7f36c812bc 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRpc.java
@@ -4,7 +4,7 @@
package com.vaadin.terminal.gwt.client.ui.embedded;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.ClickRPC;
+import com.vaadin.terminal.gwt.client.ui.ClickRpc;
-public interface EmbeddedServerRPC extends ClickRPC, ServerRpc {
+public interface EmbeddedServerRpc extends ClickRpc, ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java
index 82f26383a1..e4a31b96ef 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java
@@ -22,7 +22,7 @@ import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector;
import com.vaadin.terminal.gwt.client.ui.AlignmentInfo;
import com.vaadin.terminal.gwt.client.ui.Connect;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
import com.vaadin.terminal.gwt.client.ui.gridlayout.VGridLayout.Cell;
import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot;
@@ -41,18 +41,18 @@ public class GridLayoutConnector extends AbstractComponentContainerConnector
}
@Override
- protected LayoutClickRPC getLayoutClickRPC() {
+ protected LayoutClickRpc getLayoutClickRPC() {
return rpc;
};
};
- private GridLayoutServerRPC rpc;
+ private GridLayoutServerRpc rpc;
private boolean needCaptionUpdate = false;
@Override
public void init() {
- rpc = RpcProxy.create(GridLayoutServerRPC.class, this);
+ rpc = RpcProxy.create(GridLayoutServerRpc.class, this);
getLayoutManager().registerDependency(this,
getWidget().spacingMeasureElement);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRpc.java
index 1b7f1a15d9..cd8df297ec 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRpc.java
@@ -4,8 +4,8 @@
package com.vaadin.terminal.gwt.client.ui.gridlayout;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
-public interface GridLayoutServerRPC extends LayoutClickRPC, ServerRpc {
+public interface GridLayoutServerRpc extends LayoutClickRpc, ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java
index 801c405826..84d3b73285 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java
@@ -58,7 +58,11 @@ public class NativeButtonConnector extends AbstractComponentConnector implements
blurHandlerRegistration);
// Set text
- getWidget().setText(getState().getCaption());
+ if (getState().isHtmlContentAllowed()) {
+ getWidget().setHTML(getState().getCaption());
+ } else {
+ getWidget().setText(getState().getCaption());
+ }
// handle error
if (null != getState().getErrorMessage()) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java
index d0b8f73eb1..01ac4fab6a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java
@@ -65,6 +65,11 @@ public class VNativeButton extends Button implements ClickHandler {
}
@Override
+ public void setHTML(String html) {
+ captionElement.setInnerHTML(html);
+ }
+
+ @Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
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 eb97160f52..0d222044ba 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
@@ -160,6 +160,13 @@ public class VNotification extends VOverlay {
}
super.show();
setPosition(position);
+ /**
+ * Android 4 fails to render notifications correctly without a little
+ * nudge (#8551)
+ */
+ if (BrowserInfo.get().isAndroid()) {
+ Util.setStyleTemporarily(getElement(), "display", "none");
+ }
}
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
index d36046d6cb..174da61bd3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
@@ -23,7 +23,7 @@ import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector;
import com.vaadin.terminal.gwt.client.ui.AlignmentInfo;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
import com.vaadin.terminal.gwt.client.ui.layout.ComponentConnectorLayoutSlot;
import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot;
@@ -31,7 +31,7 @@ import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot;
public abstract class AbstractOrderedLayoutConnector extends
AbstractLayoutConnector implements Paintable, DirectionalManagedLayout {
- AbstractOrderedLayoutServerRPC rpc;
+ AbstractOrderedLayoutServerRpc rpc;
private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
this) {
@@ -43,7 +43,7 @@ public abstract class AbstractOrderedLayoutConnector extends
}
@Override
- protected LayoutClickRPC getLayoutClickRPC() {
+ protected LayoutClickRpc getLayoutClickRPC() {
return rpc;
};
@@ -51,7 +51,7 @@ public abstract class AbstractOrderedLayoutConnector extends
@Override
public void init() {
- rpc = RpcProxy.create(AbstractOrderedLayoutServerRPC.class, this);
+ rpc = RpcProxy.create(AbstractOrderedLayoutServerRpc.class, this);
getLayoutManager().registerDependency(this,
getWidget().spacingMeasureElement);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRpc.java
index f23cda3512..5a29eacada 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRpc.java
@@ -4,9 +4,9 @@
package com.vaadin.terminal.gwt.client.ui.orderedlayout;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.LayoutClickRPC;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc;
-public interface AbstractOrderedLayoutServerRPC extends LayoutClickRPC,
+public interface AbstractOrderedLayoutServerRpc extends LayoutClickRpc,
ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java
index a8512762f1..9555c38a36 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java
@@ -43,11 +43,11 @@ public class PanelConnector extends AbstractComponentContainerConnector
private Integer uidlScrollLeft;
- private PanelServerRPC rpc;
+ private PanelServerRpc rpc;
@Override
public void init() {
- rpc = RpcProxy.create(PanelServerRPC.class, this);
+ rpc = RpcProxy.create(PanelServerRpc.class, this);
VPanel panel = getWidget();
LayoutManager layoutManager = getLayoutManager();
diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRpc.java
index 9a556cfe0e..9b59344aec 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRpc.java
@@ -4,8 +4,8 @@
package com.vaadin.terminal.gwt.client.ui.panel;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.ClickRPC;
+import com.vaadin.terminal.gwt.client.ui.ClickRpc;
-public interface PanelServerRPC extends ClickRPC, ServerRpc {
+public interface PanelServerRpc extends ClickRpc, ServerRpc {
} \ No newline at end of file
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 408c15383c..46f82d60b7 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
@@ -47,7 +47,7 @@ import com.vaadin.ui.Root;
public class RootConnector extends AbstractComponentContainerConnector
implements Paintable, MayScrollChildren {
- private RootServerRPC rpc = RpcProxy.create(RootServerRPC.class, this);
+ private RootServerRpc rpc = RpcProxy.create(RootServerRpc.class, this);
private HandlerRegistration childStateChangeHandlerRegistration;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRpc.java
index f32b972dfe..389500949d 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRpc.java
@@ -4,8 +4,8 @@
package com.vaadin.terminal.gwt.client.ui.root;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.ClickRPC;
+import com.vaadin.terminal.gwt.client.ui.ClickRpc;
-public interface RootServerRPC extends ClickRPC, ServerRpc {
+public interface RootServerRpc extends ClickRpc, ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
index 13fc55d7ea..12a69d5556 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
@@ -306,6 +306,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,
/*-{
var j;
for(j in $wnd.vaadin.vaadinConfigurations) {
+ // $entry not needed as function is not exported
list.@java.util.Collection::add(Ljava/lang/Object;)(j);
}
}-*/;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
index 7340c2cbd9..b3921204dc 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
@@ -30,12 +30,12 @@ import com.vaadin.terminal.gwt.client.ui.splitpanel.VAbstractSplitPanel.Splitter
public abstract class AbstractSplitPanelConnector extends
AbstractComponentContainerConnector implements SimpleManagedLayout {
- private AbstractSplitPanelRPC rpc;
+ private AbstractSplitPanelRpc rpc;
@Override
protected void init() {
super.init();
- rpc = RpcProxy.create(AbstractSplitPanelRPC.class, this);
+ rpc = RpcProxy.create(AbstractSplitPanelRpc.class, this);
// TODO Remove
getWidget().client = getConnection();
diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRPC.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRpc.java
index 15cd47a656..cc043838ff 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRpc.java
@@ -6,7 +6,7 @@ package com.vaadin.terminal.gwt.client.ui.splitpanel;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-public interface AbstractSplitPanelRPC extends ServerRpc {
+public interface AbstractSplitPanelRpc extends ServerRpc {
/**
* Called when the position has been updated by the user.
diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java
index 13f3adbc72..8b80eed840 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java
@@ -3,6 +3,8 @@
*/
package com.vaadin.terminal.gwt.client.ui.splitpanel;
+import java.io.Serializable;
+
import com.vaadin.terminal.gwt.client.ComponentState;
import com.vaadin.terminal.gwt.client.Connector;
@@ -44,7 +46,7 @@ public class AbstractSplitPanelState extends ComponentState {
this.splitterState = splitterState;
}
- public static class SplitterState {
+ public static class SplitterState implements Serializable {
private float position;
private String positionUnit;
private boolean positionReversed = false;
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 563ca04abe..c45c26c4ac 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
@@ -18,6 +18,7 @@ import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Display;
@@ -545,6 +546,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (touchScrollDelegate == null) {
touchScrollDelegate = new TouchScrollDelegate(
scrollBodyPanel.getElement());
+ touchScrollDelegate.setScrollHandler(this);
}
return touchScrollDelegate;
@@ -3833,6 +3835,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
DOM.appendChild(container, preSpacer);
DOM.appendChild(container, table);
DOM.appendChild(container, postSpacer);
+ if (BrowserInfo.get().isTouchDevice()) {
+ NodeList<Node> childNodes = container.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Element item = (Element) childNodes.getItem(i);
+ item.getStyle().setProperty("webkitTransform",
+ "translate3d(0,0,0)");
+ }
+ }
}
@@ -4370,7 +4380,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public class VScrollTableRow extends Panel implements ActionOwner {
- private static final int TOUCHSCROLL_TIMEOUT = 70;
+ private static final int TOUCHSCROLL_TIMEOUT = 100;
private static final int DRAGMODE_MULTIROW = 2;
protected ArrayList<Widget> childWidgets = new ArrayList<Widget>();
private boolean selected = false;
@@ -5020,9 +5030,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
};
}
- contextTouchTimeout.cancel();
- contextTouchTimeout
- .schedule(TOUCH_CONTEXT_MENU_TIMEOUT);
+ if (contextTouchTimeout != null) {
+ contextTouchTimeout.cancel();
+ contextTouchTimeout
+ .schedule(TOUCH_CONTEXT_MENU_TIMEOUT);
+ }
}
break;
case Event.ONMOUSEDOWN:
@@ -6175,6 +6187,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* The row to ensure is visible
*/
private void ensureRowIsVisible(VScrollTableRow row) {
+ if (BrowserInfo.get().isTouchDevice()) {
+ // Skip due to android devices that have broken scrolltop will may
+ // get odd scrolling here.
+ return;
+ }
Util.scrollIntoViewVertically(row.getElement());
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java
index b2141e06e5..7bd392b503 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java
@@ -234,9 +234,9 @@ public class VTextField extends TextBoxBase implements Field, ChangeHandler,
protected native void attachCutEventListener(Element el)
/*-{
var me = this;
- el.oncut = function() {
+ el.oncut = $entry(function() {
me.@com.vaadin.terminal.gwt.client.ui.textfield.VTextField::onCut()();
- };
+ });
}-*/;
protected native void detachCutEventListener(Element el)
diff --git a/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java
index 18cfc643d3..174a4b88ca 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java
@@ -8,9 +8,9 @@ public class UploadIFrameOnloadStrategy {
native void hookEvents(com.google.gwt.dom.client.Element iframe,
VUpload upload)
/*-{
- iframe.onload = function() {
+ iframe.onload = $entry(function() {
upload.@com.vaadin.terminal.gwt.client.ui.upload.VUpload::onSubmitComplete()();
- };
+ });
}-*/;
/**
diff --git a/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java
index 19d38a8a95..17a7e46bd5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java
@@ -13,11 +13,11 @@ public class UploadIFrameOnloadStrategyIE extends UploadIFrameOnloadStrategy {
@Override
native void hookEvents(Element iframe, VUpload upload)
/*-{
- iframe.onreadystatechange = function() {
+ iframe.onreadystatechange = $entry(function() {
if (iframe.readyState == 'complete') {
upload.@com.vaadin.terminal.gwt.client.ui.upload.VUpload::onSubmitComplete()();
}
- };
+ });
}-*/;
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java b/src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java
index d40f954cdc..484000b8d1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java
@@ -34,9 +34,9 @@ public class VVideo extends VMediaBase {
private native void updateDimensionsWhenMetadataLoaded(Element el)
/*-{
var self = this;
- el.addEventListener('loadedmetadata', function(e) {
- $entry(self.@com.vaadin.terminal.gwt.client.ui.video.VVideo::updateElementDynamicSize(II)(el.videoWidth, el.videoHeight));
- }, false);
+ el.addEventListener('loadedmetadata', $entry(function(e) {
+ self.@com.vaadin.terminal.gwt.client.ui.video.VVideo::updateElementDynamicSize(II)(el.videoWidth, el.videoHeight);
+ }), false);
}-*/;
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 85f4213d3e..6979982a9c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java
@@ -44,7 +44,7 @@ public class WindowConnector extends AbstractComponentContainerConnector
}
};
- private WindowServerRPC rpc;
+ private WindowServerRpc rpc;
boolean minWidthChecked = false;
@@ -56,7 +56,7 @@ public class WindowConnector extends AbstractComponentContainerConnector
@Override
protected void init() {
super.init();
- rpc = RpcProxy.create(WindowServerRPC.class, this);
+ rpc = RpcProxy.create(WindowServerRpc.class, this);
getLayoutManager().registerDependency(this,
getWidget().contentPanel.getElement());
diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRPC.java b/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRpc.java
index 782284b562..4723c55786 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRPC.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRpc.java
@@ -4,7 +4,7 @@
package com.vaadin.terminal.gwt.client.ui.window;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
-import com.vaadin.terminal.gwt.client.ui.ClickRPC;
+import com.vaadin.terminal.gwt.client.ui.ClickRpc;
-public interface WindowServerRPC extends ClickRPC, ServerRpc {
+public interface WindowServerRpc extends ClickRpc, ServerRpc {
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index 8235859758..77698805de 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -509,6 +509,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
protected void handleRequest(PortletRequest request,
PortletResponse response) throws PortletException, IOException {
+ RequestTimer requestTimer = new RequestTimer();
+ requestTimer.start();
+
AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper(
this);
@@ -610,6 +613,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
if (application.isRunning()) {
switch (requestType) {
case RENDER:
+ case ACTION:
+ // Both action requests and render requests are ok
+ // without a Root as they render the initial HTML
+ // and then do a second request
try {
root = application
.getRootForRequest(wrappedRequest);
@@ -714,6 +721,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
} finally {
Root.setCurrentRoot(null);
Application.setCurrentApplication(null);
+
+ requestTimer
+ .stop((AbstractWebApplicationContext) application
+ .getContext());
}
}
}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 18cc3f97f4..6ab2748332 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -400,6 +400,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
private void service(WrappedHttpServletRequest request,
WrappedHttpServletResponse response) throws ServletException,
IOException {
+ RequestTimer requestTimer = new RequestTimer();
+ requestTimer.start();
+
AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper(
this);
@@ -537,8 +540,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
} finally {
Root.setCurrentRoot(null);
Application.setCurrentApplication(null);
- }
+ requestTimer
+ .stop((AbstractWebApplicationContext) application
+ .getContext());
+ }
}
}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index bb6e726166..c57e7d8bc1 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -17,6 +17,7 @@ import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.security.GeneralSecurityException;
import java.text.CharacterIterator;
import java.text.DateFormat;
@@ -690,7 +691,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
outWriter.print(getSecurityKeyUIDL(request));
}
- writeUidlResponse(repaintAll, outWriter, root, analyzeLayouts);
+ writeUidlResponse(request, repaintAll, outWriter, root, analyzeLayouts);
closeJsonMessage(outWriter);
@@ -734,7 +735,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
@SuppressWarnings("unchecked")
- public void writeUidlResponse(boolean repaintAll,
+ public void writeUidlResponse(WrappedRequest request, boolean repaintAll,
final PrintWriter outWriter, Root root, boolean analyzeLayouts)
throws PaintException {
ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>();
@@ -807,8 +808,9 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (null != state) {
// encode and send shared state
try {
+ // FIXME Use declared type
JSONArray stateJsonArray = JsonCodec.encode(state,
- application);
+ state.getClass(), application);
sharedStates
.put(connector.getConnectorId(), stateJsonArray);
} catch (JSONException e) {
@@ -897,9 +899,10 @@ public abstract class AbstractCommunicationManager implements Serializable {
invocationJson.put(invocation.getInterfaceName());
invocationJson.put(invocation.getMethodName());
JSONArray paramJson = new JSONArray();
- for (int i = 0; i < invocation.getParameters().length; ++i) {
+ for (int i = 0; i < invocation.getParameterTypes().length; ++i) {
paramJson.put(JsonCodec.encode(
- invocation.getParameters()[i], application));
+ invocation.getParameters()[i],
+ invocation.getParameterTypes()[i], application));
}
invocationJson.put(paramJson);
rpcCalls.put(invocationJson);
@@ -1093,6 +1096,19 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (dragAndDropService != null) {
dragAndDropService.printJSONResponse(outWriter);
}
+
+ writePerformanceData(outWriter);
+ }
+
+ /**
+ * Adds the performance timing data (used by TestBench 3) to the UIDL
+ * response.
+ */
+ private void writePerformanceData(final PrintWriter outWriter) {
+ AbstractWebApplicationContext ctx = (AbstractWebApplicationContext) application
+ .getContext();
+ outWriter.write(String.format(", \"timings\":[%d, %d]",
+ ctx.getTotalSessionTime(), ctx.getLastRequestTime()));
}
private void legacyPaint(PaintTarget paintTarget,
@@ -1167,7 +1183,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* The child to check
* @return true if the child is visible to the client, false otherwise
*/
- private boolean isVisible(Component child) {
+ static boolean isVisible(Component child) {
HasComponents parent = child.getParent();
if (parent == null || !child.isVisible()) {
return child.isVisible();
@@ -1368,43 +1384,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
/**
- * Helper class for parsing variable change RPC calls.
- *
- * Note that variable changes still only support the old data types and
- * partly use Vaadin 6 way of encoding of values. Other RPC method calls
- * support more data types.
- *
- * @since 7.0
- */
- private class VariableChange {
- private final String name;
- private final Object value;
-
- public VariableChange(MethodInvocation invocation) throws JSONException {
- name = (String) invocation.getParameters()[0];
- value = invocation.getParameters()[1];
- }
-
- /**
- * Returns the variable name for the modification.
- *
- * @return variable name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the (parsed and converted) value of the updated variable.
- *
- * @return variable value
- */
- public Object getValue() {
- return value;
- }
- }
-
- /**
* Processes a message burst received from the client.
*
* A burst can contain any number of RPC calls, including legacy variable
@@ -1427,108 +1406,93 @@ public abstract class AbstractCommunicationManager implements Serializable {
final String burst) {
boolean success = true;
try {
- List<MethodInvocation> invocations = parseInvocations(burst);
-
- // Perform the method invocations, grouping consecutive variable
- // changes for the same Paintable.
+ Set<Connector> enabledConnectors = new HashSet<Connector>();
- // Combining of variable changes is currently needed to preserve the
- // old semantics for any component that relies on them. If the
- // support for legacy variable change events is removed, each call
- // can be performed separately and thelogic here simplified.
+ List<MethodInvocation> invocations = parseInvocations(burst);
+ for (MethodInvocation invocation : invocations) {
+ final ClientConnector connector = getConnector(app,
+ invocation.getConnectorId());
+ if (connector != null && connector.isConnectorEnabled()) {
+ enabledConnectors.add(connector);
+ }
+ }
for (int i = 0; i < invocations.size(); i++) {
MethodInvocation invocation = invocations.get(i);
- MethodInvocation nextInvocation = null;
- if (i + 1 < invocations.size()) {
- nextInvocation = invocations.get(i + 1);
- }
-
- final String interfaceName = invocation.getInterfaceName();
+ final ClientConnector connector = getConnector(app,
+ invocation.getConnectorId());
- if (!ApplicationConnection.UPDATE_VARIABLE_INTERFACE
- .equals(interfaceName)) {
- // handle other RPC calls than variable changes
- applyInvocation(app, invocation);
+ if (connector == null) {
+ logger.log(
+ Level.WARNING,
+ "RPC call to " + invocation.getInterfaceName()
+ + "." + invocation.getMethodName()
+ + " received for connector "
+ + invocation.getConnectorId()
+ + " but no such connector could be found");
continue;
}
- final ClientConnector connector = getConnector(app,
- invocation.getConnectorId());
- final VariableOwner owner = (VariableOwner) connector;
-
- boolean connectorEnabled = (connector != null && connector
- .isConnectorEnabled());
-
- if (owner != null && connectorEnabled) {
- VariableChange change = new VariableChange(invocation);
-
- // TODO could optimize with a single value map if only one
- // change for a paintable
-
- Map<String, Object> m = new HashMap<String, Object>();
- m.put(change.getName(), change.getValue());
- while (nextInvocation != null
- && invocation.getConnectorId().equals(
- nextInvocation.getConnectorId())
- && ApplicationConnection.UPDATE_VARIABLE_METHOD
- .equals(nextInvocation.getMethodName())) {
- i++;
- invocation = nextInvocation;
- change = new VariableChange(invocation);
- m.put(change.getName(), change.getValue());
- if (i + 1 < invocations.size()) {
- nextInvocation = invocations.get(i + 1);
- } else {
- nextInvocation = null;
- }
- }
- try {
- changeVariables(source, owner, m);
- } catch (Exception e) {
- Component errorComponent = null;
- if (owner instanceof Component) {
- errorComponent = (Component) owner;
- } else if (owner instanceof DragAndDropService) {
- if (m.get("dhowner") instanceof Component) {
- errorComponent = (Component) m.get("dhowner");
- }
+ if (!enabledConnectors.contains(connector)) {
+
+ if (invocation instanceof LegacyChangeVariablesInvocation) {
+ LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
+ // TODO convert window close to a separate RPC call and
+ // handle above - not a variable change
+
+ // Handle special case where window-close is called
+ // after the window has been removed from the
+ // application or the application has closed
+ Map<String, Object> changes = legacyInvocation
+ .getVariableChanges();
+ if (changes.size() == 1 && changes.containsKey("close")
+ && Boolean.TRUE.equals(changes.get("close"))) {
+ // Silently ignore this
+ continue;
}
- handleChangeVariablesError(app, errorComponent, e, m);
- }
- } else {
- // TODO convert window close to a separate RPC call and
- // handle above - not a variable change
-
- VariableChange change = new VariableChange(invocation);
-
- // Handle special case where window-close is called
- // after the window has been removed from the
- // application or the application has closed
- if ("close".equals(change.getName())
- && Boolean.TRUE.equals(change.getValue())) {
- // Silently ignore this
- continue;
}
- // Ignore variable change
- String msg = "Warning: Ignoring RPC call for ";
- if (owner != null) {
- msg += "disabled component " + owner.getClass();
- String caption = ((Component) owner).getCaption();
+ // Connector is disabled, log a warning and move to the next
+ String msg = "Ignoring RPC call for disabled connector "
+ + connector.getClass().getName();
+ if (connector instanceof Component) {
+ String caption = ((Component) connector).getCaption();
if (caption != null) {
msg += ", caption=" + caption;
}
- } else {
- msg += "non-existent component, VAR_PID="
- + invocation.getConnectorId();
- // TODO should this cause the message to be ignored?
- success = false;
}
logger.warning(msg);
continue;
}
+
+ if (invocation instanceof ServerRpcMethodInvocation) {
+ ServerRpcManager.applyInvocation(connector,
+ (ServerRpcMethodInvocation) invocation);
+ } else {
+
+ // All code below is for legacy variable changes
+ LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
+ Map<String, Object> changes = legacyInvocation
+ .getVariableChanges();
+ try {
+ changeVariables(source, (VariableOwner) connector,
+ changes);
+ } catch (Exception e) {
+ Component errorComponent = null;
+ if (connector instanceof Component) {
+ errorComponent = (Component) connector;
+ } else if (connector instanceof DragAndDropService) {
+ Object dropHandlerOwner = changes.get("dhowner");
+ if (dropHandlerOwner instanceof Component) {
+ errorComponent = (Component) dropHandlerOwner;
+ }
+ }
+ handleChangeVariablesError(app, errorComponent, e,
+ changes);
+
+ }
+ }
}
} catch (JSONException e) {
@@ -1542,34 +1506,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
/**
- * Execute an RPC call from the client by finding its target and letting the
- * RPC mechanism call the correct method for it.
- *
- * @param app
- *
- * @param invocation
- */
- protected void applyInvocation(Application app, MethodInvocation invocation) {
- Connector c = app.getConnector(invocation.getConnectorId());
- if (c instanceof RpcTarget) {
- ServerRpcManager.applyInvocation((RpcTarget) c, invocation);
- } else if (c == null) {
- logger.log(
- Level.WARNING,
- "RPC call " + invocation.getInterfaceName() + "."
- + invocation.getMethodName()
- + " received for connector id "
- + invocation.getConnectorId()
- + " but no such connector could be found");
-
- } else {
- logger.log(Level.WARNING, "RPC call received for connector "
- + c.getClass().getName() + " (" + c.getConnectorId()
- + ") but the connector is not a ServerRpcTarget");
- }
- }
-
- /**
* Parse a message burst from the client into a list of MethodInvocation
* instances.
*
@@ -1584,25 +1520,94 @@ public abstract class AbstractCommunicationManager implements Serializable {
ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>();
+ MethodInvocation previousInvocation = null;
// parse JSON to MethodInvocations
for (int i = 0; i < invocationsJson.length(); ++i) {
+
JSONArray invocationJson = invocationsJson.getJSONArray(i);
- String connectorId = invocationJson.getString(0);
- String interfaceName = invocationJson.getString(1);
- String methodName = invocationJson.getString(2);
- JSONArray parametersJson = invocationJson.getJSONArray(3);
- Object[] parameters = new Object[parametersJson.length()];
- for (int j = 0; j < parametersJson.length(); ++j) {
- parameters[j] = JsonCodec.decode(
- parametersJson.getJSONArray(j), application);
+
+ MethodInvocation invocation = parseInvocation(invocationJson,
+ previousInvocation);
+ if (invocation != null) {
+ // Can be null iff the invocation was a legacy invocation and it
+ // was merged with the previous one
+ invocations.add(invocation);
+ previousInvocation = invocation;
}
- MethodInvocation invocation = new MethodInvocation(connectorId,
- interfaceName, methodName, parameters);
- invocations.add(invocation);
}
return invocations;
}
+ private MethodInvocation parseInvocation(JSONArray invocationJson,
+ MethodInvocation previousInvocation) throws JSONException {
+ String connectorId = invocationJson.getString(0);
+ String interfaceName = invocationJson.getString(1);
+ String methodName = invocationJson.getString(2);
+
+ JSONArray parametersJson = invocationJson.getJSONArray(3);
+
+ if (LegacyChangeVariablesInvocation.isLegacyVariableChange(
+ interfaceName, methodName)) {
+ if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) {
+ previousInvocation = null;
+ }
+
+ return parseLegacyChangeVariablesInvocation(connectorId,
+ interfaceName, methodName,
+ (LegacyChangeVariablesInvocation) previousInvocation,
+ parametersJson);
+ } else {
+ return parseServerRpcInvocation(connectorId, interfaceName,
+ methodName, parametersJson);
+ }
+
+ }
+
+ private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation(
+ String connectorId, String interfaceName, String methodName,
+ LegacyChangeVariablesInvocation previousInvocation,
+ JSONArray parametersJson) throws JSONException {
+ if (parametersJson.length() != 2) {
+ throw new JSONException(
+ "Invalid parameters in legacy change variables call. Expected 2, was "
+ + parametersJson.length());
+ }
+ String variableName = (String) JsonCodec
+ .decodeInternalType(String.class, true,
+ parametersJson.getJSONArray(0), application);
+ Object value = JsonCodec.decodeInternalType(
+ parametersJson.getJSONArray(1), application);
+
+ if (previousInvocation != null
+ && previousInvocation.getConnectorId().equals(connectorId)) {
+ previousInvocation.setVariableChange(variableName, value);
+ return null;
+ } else {
+ return new LegacyChangeVariablesInvocation(connectorId,
+ variableName, value);
+ }
+ }
+
+ private ServerRpcMethodInvocation parseServerRpcInvocation(
+ String connectorId, String interfaceName, String methodName,
+ JSONArray parametersJson) throws JSONException {
+ ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation(
+ connectorId, interfaceName, methodName, parametersJson.length());
+
+ Object[] parameters = new Object[parametersJson.length()];
+ Type[] declaredRpcMethodParameterTypes = invocation.getMethod()
+ .getGenericParameterTypes();
+
+ for (int j = 0; j < parametersJson.length(); ++j) {
+ JSONArray parameterJson = parametersJson.getJSONArray(j);
+ Type parameterType = declaredRpcMethodParameterTypes[j];
+ parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType,
+ parameterJson, application);
+ }
+ invocation.setParameters(parameters);
+ return invocation;
+ }
+
protected void changeVariables(Object source, final VariableOwner owner,
Map<String, Object> m) {
owner.changeVariables(source, m);
@@ -2126,7 +2131,18 @@ public abstract class AbstractCommunicationManager implements Serializable {
String initialUIDL = getInitialUIDL(combinedRequest, root);
params.put("uidl", initialUIDL);
}
- response.getWriter().write(params.toString());
+
+ // NOTE! GateIn requires, for some weird reason, getOutputStream
+ // to be used instead of getWriter() (it seems to interpret
+ // application/json as a binary content type)
+ final OutputStream out = response.getOutputStream();
+ final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
+ new OutputStreamWriter(out, "UTF-8")));
+
+ outWriter.write(params.toString());
+ // NOTE GateIn requires the buffers to be flushed to work
+ outWriter.flush();
+ out.flush();
} catch (RootRequiresMoreInformationException e) {
// Requiring more information at this point is not allowed
// TODO handle in a better way
@@ -2158,7 +2174,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (isXSRFEnabled(root.getApplication())) {
pWriter.print(getSecurityKeyUIDL(request));
}
- writeUidlResponse(true, pWriter, root, false);
+ writeUidlResponse(request, true, pWriter, root, false);
pWriter.print("}");
String initialUIDL = sWriter.toString();
logger.log(Level.FINE, "Initial UIDL:" + initialUIDL);
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java
index c8335a8607..c0ae0afc26 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java
@@ -44,6 +44,10 @@ public abstract class AbstractWebApplicationContext implements
protected HashMap<Application, AbstractCommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, AbstractCommunicationManager>();
+ private long totalSessionTime = 0;
+
+ private long lastRequestTime = -1;
+
public void addTransactionListener(TransactionListener listener) {
if (listener != null) {
listeners.add(listener);
@@ -222,4 +226,30 @@ public abstract class AbstractWebApplicationContext implements
return relativeUri.substring(index + 1, next);
}
+ /**
+ * @return The total time spent servicing requests in this session.
+ */
+ public long getTotalSessionTime() {
+ return totalSessionTime;
+ }
+
+ /**
+ * Sets the time spent servicing the last request in the session and updates
+ * the total time spent servicing requests in this session.
+ *
+ * @param time
+ * the time spent in the last request.
+ */
+ public void setLastRequestTime(long time) {
+ lastRequestTime = time;
+ totalSessionTime += time;
+ }
+
+ /**
+ * @return the time spent servicing the last request in this session.
+ */
+ public long getLastRequestTime() {
+ return lastRequestTime;
+ }
+
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/src/com/vaadin/terminal/gwt/server/ClientConnector.java
index cc4c1161a0..7a1f0fad68 100644
--- a/src/com/vaadin/terminal/gwt/server/ClientConnector.java
+++ b/src/com/vaadin/terminal/gwt/server/ClientConnector.java
@@ -16,7 +16,7 @@ import com.vaadin.terminal.gwt.client.Connector;
* @since 7.0.0
*
*/
-public interface ClientConnector extends Connector {
+public interface ClientConnector extends Connector, RpcTarget {
/**
* Returns the list of pending server to client RPC calls and clears the
* list.
diff --git a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java
index 2edcb8a9f2..99633a13d6 100644
--- a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java
+++ b/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java
@@ -5,6 +5,7 @@
package com.vaadin.terminal.gwt.server;
import java.io.Serializable;
+import java.lang.reflect.Method;
/**
* Internal class for keeping track of pending server to client method
@@ -18,21 +19,27 @@ public class ClientMethodInvocation implements Serializable,
private final String interfaceName;
private final String methodName;
private final Object[] parameters;
+ private Class<?>[] parameterTypes;
- // used for sorting calls between different Paintables in the same Root
+ // used for sorting calls between different connectors in the same Root
private final long sequenceNumber;
// TODO may cause problems when clustering etc.
private static long counter = 0;
public ClientMethodInvocation(ClientConnector connector,
- String interfaceName, String methodName, Object[] parameters) {
+ String interfaceName, Method method, Object[] parameters) {
this.connector = connector;
this.interfaceName = interfaceName;
- this.methodName = methodName;
+ methodName = method.getName();
+ parameterTypes = method.getParameterTypes();
this.parameters = (null != parameters) ? parameters : new Object[0];
sequenceNumber = ++counter;
}
+ public Class<?>[] getParameterTypes() {
+ return parameterTypes;
+ }
+
public ClientConnector getConnector() {
return connector;
}
diff --git a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
index ca499d024d..d3fe5a890b 100644
--- a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
+++ b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
@@ -233,4 +233,9 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
public List<ClientMethodInvocation> retrievePendingRpcCalls() {
return null;
}
+
+ public RpcManager getRpcManager(Class<?> rpcInterface) {
+ // TODO Use rpc for drag'n'drop
+ return null;
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java
index 1824a16fb2..375cce4161 100644
--- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java
+++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java
@@ -10,6 +10,8 @@ import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -25,6 +27,7 @@ import com.vaadin.external.json.JSONException;
import com.vaadin.external.json.JSONObject;
import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
+import com.vaadin.ui.Component;
/**
* Decoder for converting RPC parameters and other values from JSON in transfer
@@ -36,6 +39,12 @@ public class JsonCodec implements Serializable {
private static Map<Class<?>, String> typeToTransportType = new HashMap<Class<?>, String>();
+ /**
+ * Note! This does not contain primitives.
+ * <p>
+ */
+ private static Map<String, Class<?>> transportTypeToType = new HashMap<String, Class<?>>();
+
static {
registerType(String.class, JsonEncoder.VTYPE_STRING);
registerType(Connector.class, JsonEncoder.VTYPE_CONNECTOR);
@@ -49,8 +58,6 @@ public class JsonCodec implements Serializable {
registerType(double.class, JsonEncoder.VTYPE_DOUBLE);
registerType(Long.class, JsonEncoder.VTYPE_LONG);
registerType(long.class, JsonEncoder.VTYPE_LONG);
- // transported as string representation
- registerType(Enum.class, JsonEncoder.VTYPE_STRING);
registerType(String[].class, JsonEncoder.VTYPE_STRINGARRAY);
registerType(Object[].class, JsonEncoder.VTYPE_ARRAY);
registerType(Map.class, JsonEncoder.VTYPE_MAP);
@@ -60,96 +67,260 @@ public class JsonCodec implements Serializable {
private static void registerType(Class<?> type, String transportType) {
typeToTransportType.put(type, transportType);
+ if (!type.isPrimitive()) {
+ transportTypeToType.put(transportType, type);
+ }
+ }
+
+ public static boolean isInternalTransportType(String transportType) {
+ return transportTypeToType.containsKey(transportType);
+ }
+
+ public static boolean isInternalType(Type type) {
+ if (type instanceof Class && ((Class<?>) type).isPrimitive()) {
+ // All primitive types are handled internally
+ return true;
+ }
+ return typeToTransportType.containsKey(getClassForType(type));
+ }
+
+ private static Class<?> getClassForType(Type type) {
+ if (type instanceof ParameterizedType) {
+ return (Class<?>) (((ParameterizedType) type).getRawType());
+ } else {
+ return (Class<?>) type;
+ }
+ }
+
+ public static String getTransportType(JSONArray encodedValue)
+ throws JSONException {
+ return encodedValue.getString(0);
+ }
+
+ private static Class<?> getType(String transportType) {
+ return transportTypeToType.get(transportType);
}
/**
- * Convert a JSON array with two elements (type and value) into a
- * server-side type, recursively if necessary.
+ * Decodes the given value and type, restricted to using only internal
+ * types.
*
- * @param value
- * JSON array with two elements
+ * @param valueAndType
* @param application
- * mapper between connector ID and {@link Connector} objects
- * @return converted value (does not contain JSON types)
* @throws JSONException
- * if the conversion fails
*/
- public static Object decode(JSONArray value, Application application)
- throws JSONException {
- return decodeVariableValue(value.getString(0), value.get(1),
+ @Deprecated
+ public static Object decodeInternalType(JSONArray valueAndType,
+ Application application) throws JSONException {
+ String transportType = getTransportType(valueAndType);
+ return decodeInternalType(getType(transportType), true, valueAndType,
application);
}
- private static Object decodeVariableValue(String variableType,
- Object value, Application application) throws JSONException {
- Object val = null;
- // TODO type checks etc.
- if (JsonEncoder.VTYPE_ARRAY.equals(variableType)) {
- val = decodeArray((JSONArray) value, application);
- } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) {
- val = decodeList((JSONArray) value, application);
- } else if (JsonEncoder.VTYPE_SET.equals(variableType)) {
- val = decodeSet((JSONArray) value, application);
- } else if (JsonEncoder.VTYPE_MAP_CONNECTOR.equals(variableType)) {
- val = decodeConnectorMap((JSONObject) value, application);
- } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) {
- val = decodeMap((JSONObject) value, application);
- } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) {
- val = decodeStringArray((JSONArray) value);
- } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) {
- val = value;
- } else if (JsonEncoder.VTYPE_INTEGER.equals(variableType)) {
- // TODO handle properly
- val = Integer.valueOf(String.valueOf(value));
- } else if (JsonEncoder.VTYPE_LONG.equals(variableType)) {
- // TODO handle properly
- val = Long.valueOf(String.valueOf(value));
- } else if (JsonEncoder.VTYPE_FLOAT.equals(variableType)) {
- // TODO handle properly
- val = Float.valueOf(String.valueOf(value));
- } else if (JsonEncoder.VTYPE_DOUBLE.equals(variableType)) {
- // TODO handle properly
- val = Double.valueOf(String.valueOf(value));
- } else if (JsonEncoder.VTYPE_BOOLEAN.equals(variableType)) {
- // TODO handle properly
- val = Boolean.valueOf(String.valueOf(value));
- } else if (JsonEncoder.VTYPE_CONNECTOR.equals(variableType)) {
- val = application.getConnector(String.valueOf(value));
- } else if (JsonEncoder.VTYPE_NULL.equals(variableType)) {
- val = null;
+ public static Object decodeInternalOrCustomType(Type targetType,
+ JSONArray valueAndType, Application application)
+ throws JSONException {
+ if (isInternalType(targetType)) {
+ return decodeInternalType(targetType, false, valueAndType,
+ application);
} else {
- // Try to decode object using fields
- return decodeObject(variableType, (JSONObject) value, application);
+ return decodeCustomType(targetType, valueAndType, application);
+ }
+ }
+ public static Object decodeCustomType(Type targetType,
+ JSONArray valueAndType, Application application)
+ throws JSONException {
+ if (isInternalType(targetType)) {
+ throw new JSONException("decodeCustomType cannot be used for "
+ + targetType + ", which is an internal type");
+ }
+ String transportType = getCustomTransportType(getClassForType(targetType));
+ String encodedTransportType = valueAndType.getString(0);
+ if (!transportTypesCompatible(encodedTransportType, transportType)) {
+ throw new JSONException("Expected a value of type " + transportType
+ + ", received " + encodedTransportType);
}
- return val;
+ // Try to decode object using fields
+ return decodeObject(targetType, (JSONObject) valueAndType.get(1),
+ application);
}
- private static Object decodeMap(JSONObject jsonMap, Application application)
- throws JSONException {
+ /**
+ * Decodes a value that is of an internal type.
+ * <p>
+ * Ensures the encoded value is of the same type as target type.
+ * </p>
+ * <p>
+ * Allows restricting collections so that they must be declared using
+ * generics. If this is used then all objects in the collection are encoded
+ * using the declared type. Otherwise only internal types are allowed in
+ * collections.
+ * </p>
+ *
+ * @param targetType
+ * The type that should be returned by this method
+ * @param valueAndType
+ * The encoded value and type array
+ * @param application
+ * A reference to the application
+ * @param enforceGenericsInCollections
+ * true if generics should be enforce, false to only allow
+ * internal types in collections
+ * @return
+ * @throws JSONException
+ */
+ public static Object decodeInternalType(Type targetType,
+ boolean restrictToInternalTypes, JSONArray valueAndType,
+ Application application) throws JSONException {
+ String encodedTransportType = valueAndType.getString(0);
+ if (!isInternalType(targetType)) {
+ throw new JSONException("Type " + targetType
+ + " is not a supported internal type.");
+ }
+ String transportType = getInternalTransportType(targetType);
+ if (!transportTypesCompatible(encodedTransportType, transportType)) {
+ throw new JSONException("Expected a value of type " + targetType
+ + ", received " + getType(encodedTransportType));
+ }
+
+ Object encodedJsonValue = valueAndType.get(1);
+
+ if (JsonEncoder.VTYPE_NULL.equals(encodedTransportType)) {
+ return null;
+ }
+ // Collections
+ if (JsonEncoder.VTYPE_LIST.equals(transportType)) {
+ return decodeList(targetType, restrictToInternalTypes,
+ (JSONArray) encodedJsonValue, application);
+ } else if (JsonEncoder.VTYPE_SET.equals(transportType)) {
+ return decodeSet(targetType, restrictToInternalTypes,
+ (JSONArray) encodedJsonValue, application);
+ } else if (JsonEncoder.VTYPE_MAP_CONNECTOR.equals(transportType)) {
+ return decodeConnectorToObjectMap(targetType,
+ restrictToInternalTypes, (JSONObject) encodedJsonValue,
+ application);
+ } else if (JsonEncoder.VTYPE_MAP.equals(transportType)) {
+ return decodeStringToObjectMap(targetType, restrictToInternalTypes,
+ (JSONObject) encodedJsonValue, application);
+ }
+
+ // Arrays
+ if (JsonEncoder.VTYPE_ARRAY.equals(transportType)) {
+
+ return decodeObjectArray(targetType, (JSONArray) encodedJsonValue,
+ application);
+
+ } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(transportType)) {
+ return decodeStringArray((JSONArray) encodedJsonValue);
+ }
+
+ // Special Vaadin types
+
+ String stringValue = String.valueOf(encodedJsonValue);
+
+ if (JsonEncoder.VTYPE_CONNECTOR.equals(transportType)) {
+ return application.getConnector(stringValue);
+ }
+
+ // Standard Java types
+
+ if (JsonEncoder.VTYPE_STRING.equals(transportType)) {
+ return stringValue;
+ } else if (JsonEncoder.VTYPE_INTEGER.equals(transportType)) {
+ return Integer.valueOf(stringValue);
+ } else if (JsonEncoder.VTYPE_LONG.equals(transportType)) {
+ return Long.valueOf(stringValue);
+ } else if (JsonEncoder.VTYPE_FLOAT.equals(transportType)) {
+ return Float.valueOf(stringValue);
+ } else if (JsonEncoder.VTYPE_DOUBLE.equals(transportType)) {
+ return Double.valueOf(stringValue);
+ } else if (JsonEncoder.VTYPE_BOOLEAN.equals(transportType)) {
+ return Boolean.valueOf(stringValue);
+ }
+
+ throw new JSONException("Unknown type " + transportType);
+ }
+
+ private static boolean transportTypesCompatible(
+ String encodedTransportType, String transportType) {
+ if (encodedTransportType == null) {
+ return false;
+ }
+ if (encodedTransportType.equals(transportType)) {
+ return true;
+ }
+ if (encodedTransportType.equals(JsonEncoder.VTYPE_NULL)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Deprecated
+ private static Map<String, Object> decodeStringToObjectMap(Type targetType,
+ boolean restrictToInternalTypes, JSONObject jsonMap,
+ Application application) throws JSONException {
HashMap<String, Object> map = new HashMap<String, Object>();
Iterator<String> it = jsonMap.keys();
while (it.hasNext()) {
String key = it.next();
- map.put(key, decode(jsonMap.getJSONArray(key), application));
+ JSONArray encodedValueAndType = jsonMap.getJSONArray(key);
+ Object decodedChild = decodeChild(targetType,
+ restrictToInternalTypes, 1, encodedValueAndType,
+ application);
+ map.put(key, decodedChild);
}
return map;
}
- private static Object decodeConnectorMap(JSONObject jsonMap,
- Application application) throws JSONException {
+ @Deprecated
+ private static Map<Connector, Object> decodeConnectorToObjectMap(
+ Type targetType, boolean restrictToInternalTypes,
+ JSONObject jsonMap, Application application) throws JSONException {
HashMap<Connector, Object> map = new HashMap<Connector, Object>();
Iterator<String> it = jsonMap.keys();
while (it.hasNext()) {
String connectorId = it.next();
Connector connector = application.getConnector(connectorId);
- map.put(connector,
- decode(jsonMap.getJSONArray(connectorId), application));
+ JSONArray encodedValueAndType = jsonMap.getJSONArray(connectorId);
+ Object decodedChild = decodeChild(targetType,
+ restrictToInternalTypes, 1, encodedValueAndType,
+ application);
+ map.put(connector, decodedChild);
}
return map;
}
+ /**
+ * @param targetType
+ * @param restrictToInternalTypes
+ * @param typeIndex
+ * The index of a generic type to use to define the child type
+ * that should be decoded
+ * @param encodedValueAndType
+ * @param application
+ * @return
+ * @throws JSONException
+ */
+ private static Object decodeChild(Type targetType,
+ boolean restrictToInternalTypes, int typeIndex,
+ JSONArray encodedValueAndType, Application application)
+ throws JSONException {
+ if (!restrictToInternalTypes && targetType instanceof ParameterizedType) {
+ Type childType = ((ParameterizedType) targetType)
+ .getActualTypeArguments()[typeIndex];
+ // Only decode the given type
+ return decodeInternalOrCustomType(childType, encodedValueAndType,
+ application);
+ } else {
+ // Only internal types when not enforcing a given type to avoid
+ // security issues
+ return decodeInternalType(encodedValueAndType, application);
+ }
+ }
+
private static String[] decodeStringArray(JSONArray jsonArray)
throws JSONException {
int length = jsonArray.length();
@@ -160,43 +331,93 @@ public class JsonCodec implements Serializable {
return tokens.toArray(new String[tokens.size()]);
}
- private static Object decodeArray(JSONArray jsonArray,
- Application application) throws JSONException {
- List list = decodeList(jsonArray, application);
+ private static Object[] decodeObjectArray(Type targetType,
+ JSONArray jsonArray, Application application) throws JSONException {
+ List list = decodeList(List.class, true, jsonArray, application);
return list.toArray(new Object[list.size()]);
}
- private static List<Object> decodeList(JSONArray jsonArray,
+ private static List<Object> decodeList(Type targetType,
+ boolean restrictToInternalTypes, JSONArray jsonArray,
Application application) throws JSONException {
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < jsonArray.length(); ++i) {
// each entry always has two elements: type and value
- JSONArray entryArray = jsonArray.getJSONArray(i);
- list.add(decode(entryArray, application));
+ JSONArray encodedValueAndType = jsonArray.getJSONArray(i);
+ Object decodedChild = decodeChild(targetType,
+ restrictToInternalTypes, 0, encodedValueAndType,
+ application);
+ list.add(decodedChild);
}
return list;
}
- private static Set<Object> decodeSet(JSONArray jsonArray,
+ private static Set<Object> decodeSet(Type targetType,
+ boolean restrictToInternalTypes, JSONArray jsonArray,
Application application) throws JSONException {
HashSet<Object> set = new HashSet<Object>();
- set.addAll(decodeList(jsonArray, application));
+ set.addAll(decodeList(List.class, restrictToInternalTypes, jsonArray,
+ application));
return set;
}
/**
- * Encode a value to a JSON representation for transport from the server to
- * the client.
+ * Returns the name that should be used as field name in the JSON. We strip
+ * "set" from the setter, keeping the result - this is easy to do on both
+ * server and client, avoiding some issues with cASE. E.g setZIndex()
+ * becomes "ZIndex". Also ensures that both getter and setter are present,
+ * returning null otherwise.
*
- * @param value
- * value to convert
- * @param application
- * mapper between connector ID and {@link Connector} objects
- * @return JSON representation of the value
- * @throws JSONException
- * if encoding a value fails (e.g. NaN or infinite number)
+ * @param pd
+ * @return the name to be used or null if both getter and setter are not
+ * found.
*/
- public static JSONArray encode(Object value, Application application)
+ private static String getTransportFieldName(PropertyDescriptor pd) {
+ if (pd.getReadMethod() == null || pd.getWriteMethod() == null) {
+ return null;
+ }
+ return pd.getWriteMethod().getName().substring(3);
+ }
+
+ private static Object decodeObject(Type targetType,
+ JSONObject serializedObject, Application application)
+ throws JSONException {
+
+ Class<?> targetClass = getClassForType(targetType);
+ try {
+ Object decodedObject = targetClass.newInstance();
+ for (PropertyDescriptor pd : Introspector.getBeanInfo(targetClass)
+ .getPropertyDescriptors()) {
+
+ String fieldName = getTransportFieldName(pd);
+ if (fieldName == null) {
+ continue;
+ }
+ JSONArray encodedFieldValue = serializedObject
+ .getJSONArray(fieldName);
+ Type fieldType = pd.getReadMethod().getGenericReturnType();
+ Object decodedFieldValue = decodeInternalOrCustomType(
+ fieldType, encodedFieldValue, application);
+
+ pd.getWriteMethod().invoke(decodedObject, decodedFieldValue);
+ }
+
+ return decodedObject;
+ } catch (IllegalArgumentException e) {
+ throw new JSONException(e);
+ } catch (IllegalAccessException e) {
+ throw new JSONException(e);
+ } catch (InvocationTargetException e) {
+ throw new JSONException(e);
+ } catch (InstantiationException e) {
+ throw new JSONException(e);
+ } catch (IntrospectionException e) {
+ throw new JSONException(e);
+ }
+ }
+
+ @Deprecated
+ private static JSONArray encode(Object value, Application application)
throws JSONException {
return encode(value, null, application);
}
@@ -205,14 +426,14 @@ public class JsonCodec implements Serializable {
Application application) throws JSONException {
if (null == value) {
- return combineTypeAndValue(JsonEncoder.VTYPE_NULL, JSONObject.NULL);
+ return encodeNull();
}
if (valueType == null) {
valueType = value.getClass();
}
- String transportType = getTransportType(valueType);
+ String internalTransportType = getInternalTransportType(valueType);
if (value instanceof String[]) {
String[] array = (String[]) value;
JSONArray jsonArray = new JSONArray();
@@ -225,16 +446,16 @@ public class JsonCodec implements Serializable {
} else if (value instanceof Boolean) {
return combineTypeAndValue(JsonEncoder.VTYPE_BOOLEAN, value);
} else if (value instanceof Number) {
- return combineTypeAndValue(transportType, value);
+ return combineTypeAndValue(internalTransportType, value);
} else if (value instanceof Collection) {
- if (transportType == null) {
+ if (internalTransportType == null) {
throw new RuntimeException(
"Unable to serialize unsupported type: " + valueType);
}
Collection<?> collection = (Collection<?>) value;
JSONArray jsonArray = encodeCollection(collection, application);
- return combineTypeAndValue(transportType, jsonArray);
+ return combineTypeAndValue(internalTransportType, jsonArray);
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
JSONArray jsonArray = encodeArrayContents(array, application);
@@ -252,18 +473,28 @@ public class JsonCodec implements Serializable {
}
} else if (value instanceof Connector) {
Connector connector = (Connector) value;
+ if (value instanceof Component
+ && !(AbstractCommunicationManager
+ .isVisible((Component) value))) {
+ return encodeNull();
+ }
return combineTypeAndValue(JsonEncoder.VTYPE_CONNECTOR,
connector.getConnectorId());
- } else if (transportType != null) {
- return combineTypeAndValue(transportType, String.valueOf(value));
+ } else if (internalTransportType != null) {
+ return combineTypeAndValue(internalTransportType,
+ String.valueOf(value));
} else {
// Any object that we do not know how to encode we encode by looping
// through fields
- return combineTypeAndValue(valueType.getName(),
+ return combineTypeAndValue(getCustomTransportType(valueType),
encodeObject(value, application));
}
}
+ private static JSONArray encodeNull() {
+ return combineTypeAndValue(JsonEncoder.VTYPE_NULL, JSONObject.NULL);
+ }
+
private static Object encodeObject(Object value, Application application)
throws JSONException {
JSONObject jsonMap = new JSONObject();
@@ -288,68 +519,11 @@ public class JsonCodec implements Serializable {
return jsonMap;
}
- /**
- * Returns the name that should be used as field name in the JSON. We strip
- * "set" from the setter, keeping the result - this is easy to do on both
- * server and client, avoiding some issues with cASE. E.g setZIndex()
- * becomes "ZIndex". Also ensures that both getter and setter are present,
- * returning null otherwise.
- *
- * @param pd
- * @return the name to be used or null if both getter and setter are not
- * found.
- */
- private static String getTransportFieldName(PropertyDescriptor pd) {
- if (pd.getReadMethod() == null || pd.getWriteMethod() == null) {
- return null;
- }
- return pd.getWriteMethod().getName().substring(3);
- }
-
- private static Object decodeObject(String type,
- JSONObject serializedObject, Application application)
- throws JSONException {
-
- Class<?> cls;
- try {
- cls = Class.forName(type);
-
- Object decodedObject = cls.newInstance();
- for (PropertyDescriptor pd : Introspector.getBeanInfo(cls)
- .getPropertyDescriptors()) {
-
- String fieldName = getTransportFieldName(pd);
- if (fieldName == null) {
- continue;
- }
- JSONArray encodedObject = serializedObject
- .getJSONArray(fieldName);
- pd.getWriteMethod().invoke(decodedObject,
- decode(encodedObject, application));
- }
-
- return decodedObject;
- } catch (ClassNotFoundException e) {
- throw new JSONException(e);
- } catch (IllegalArgumentException e) {
- throw new JSONException(e);
- } catch (IllegalAccessException e) {
- throw new JSONException(e);
- } catch (InvocationTargetException e) {
- throw new JSONException(e);
- } catch (InstantiationException e) {
- throw new JSONException(e);
- } catch (IntrospectionException e) {
- throw new JSONException(e);
- }
- }
-
private static JSONArray encodeArrayContents(Object[] array,
Application application) throws JSONException {
JSONArray jsonArray = new JSONArray();
for (Object o : array) {
- // TODO handle object graph loops?
- jsonArray.put(encode(o, application));
+ jsonArray.put(encode(o, null, application));
}
return jsonArray;
}
@@ -358,7 +532,6 @@ public class JsonCodec implements Serializable {
Application application) throws JSONException {
JSONArray jsonArray = new JSONArray();
for (Object o : collection) {
- // TODO handle object graph loops?
jsonArray.put(encode(o, application));
}
return jsonArray;
@@ -378,7 +551,7 @@ public class JsonCodec implements Serializable {
"Only maps with String/Connector keys are currently supported (#8602)");
}
- jsonMap.put((String) mapKey, encode(mapValue, application));
+ jsonMap.put((String) mapKey, encode(mapValue, null, application));
}
return jsonMap;
}
@@ -395,21 +568,6 @@ public class JsonCodec implements Serializable {
}
/**
- * Gets the transport type for the value. Returns null if no transport type
- * can be found.
- *
- * @param value
- * @return
- * @throws JSONException
- */
- private static String getTransportType(Object value) {
- if (null == value) {
- return JsonEncoder.VTYPE_NULL;
- }
- return getTransportType(value.getClass());
- }
-
- /**
* Gets the transport type for the given class. Returns null if no transport
* type can be found.
*
@@ -418,9 +576,12 @@ public class JsonCodec implements Serializable {
* @return
* @throws JSONException
*/
- private static String getTransportType(Class<?> valueType) {
- return typeToTransportType.get(valueType);
+ private static String getInternalTransportType(Type valueType) {
+ return typeToTransportType.get(getClassForType(valueType));
+ }
+ private static String getCustomTransportType(Class<?> targetType) {
+ return targetType.getName();
}
}
diff --git a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java
new file mode 100644
index 0000000000..42fa3ab5a5
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java
@@ -0,0 +1,38 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
+
+public class LegacyChangeVariablesInvocation extends MethodInvocation {
+ private Map<String, Object> variableChanges = new HashMap<String, Object>();
+
+ public LegacyChangeVariablesInvocation(String connectorId,
+ String variableName, Object value) {
+ super(connectorId, ApplicationConnection.UPDATE_VARIABLE_INTERFACE,
+ ApplicationConnection.UPDATE_VARIABLE_METHOD);
+ setVariableChange(variableName, value);
+ }
+
+ public static boolean isLegacyVariableChange(String interfaceName,
+ String methodName) {
+ return ApplicationConnection.UPDATE_VARIABLE_METHOD
+ .equals(interfaceName)
+ && ApplicationConnection.UPDATE_VARIABLE_METHOD
+ .equals(methodName);
+ }
+
+ public void setVariableChange(String name, Object value) {
+ variableChanges.put(name, value);
+ }
+
+ public Map<String, Object> getVariableChanges() {
+ return variableChanges;
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/server/RequestTimer.java b/src/com/vaadin/terminal/gwt/server/RequestTimer.java
new file mode 100644
index 0000000000..6c0edec466
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/RequestTimer.java
@@ -0,0 +1,43 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.Serializable;
+
+/**
+ * Times the handling of requests and stores the information as an attribute in
+ * the request. The timing info is later passed on to the client in the UIDL and
+ * the client provides JavaScript API for accessing this data from e.g.
+ * TestBench.
+ *
+ * @author Jonatan Kronqvist / Vaadin Ltd
+ */
+public class RequestTimer implements Serializable {
+ private long requestStartTime = 0;
+
+ /**
+ * Starts the timing of a request. This should be called before any
+ * processing of the request.
+ */
+ public void start() {
+ requestStartTime = System.nanoTime();
+ }
+
+ /**
+ * Stops the timing of a request. This should be called when all processing
+ * of a request has finished.
+ *
+ * @param context
+ */
+ public void stop(AbstractWebApplicationContext context) {
+ // Measure and store the total handling time. This data can be
+ // used in TestBench 3 tests.
+ long time = (System.nanoTime() - requestStartTime) / 1000000;
+
+ // The timings must be stored in the context, since a new
+ // RequestTimer is created for every request.
+ context.setLastRequestTime(time);
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/server/RpcManager.java b/src/com/vaadin/terminal/gwt/server/RpcManager.java
index 5fcfda50a5..d240ab8467 100644
--- a/src/com/vaadin/terminal/gwt/server/RpcManager.java
+++ b/src/com/vaadin/terminal/gwt/server/RpcManager.java
@@ -6,8 +6,6 @@ package com.vaadin.terminal.gwt.server;
import java.io.Serializable;
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
-
/**
* Server side RPC manager that can invoke methods based on RPC calls received
* from the client.
@@ -15,5 +13,5 @@ import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
* @since 7.0
*/
public interface RpcManager extends Serializable {
- public void applyInvocation(MethodInvocation invocation);
+ public void applyInvocation(ServerRpcMethodInvocation invocation);
}
diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java
index cdab4b327f..07f83864c2 100644
--- a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java
+++ b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java
@@ -8,12 +8,10 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.terminal.gwt.client.Connector;
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
/**
* Server side RPC manager that handles RPC calls coming from the client.
@@ -26,13 +24,9 @@ import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
*/
public class ServerRpcManager<T> implements RpcManager {
- private final RpcTarget target;
private final T implementation;
private final Class<T> rpcInterface;
- private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>(
- 128, 0.75f, 1);
-
private static final Map<Class<?>, Class<?>> boxedTypes = new HashMap<Class<?>, Class<?>>();
static {
try {
@@ -59,9 +53,7 @@ public class ServerRpcManager<T> implements RpcManager {
* @param rpcInterface
* RPC interface type
*/
- public ServerRpcManager(RpcTarget target, T implementation,
- Class<T> rpcInterface) {
- this.target = target;
+ public ServerRpcManager(T implementation, Class<T> rpcInterface) {
this.implementation = implementation;
this.rpcInterface = rpcInterface;
}
@@ -76,39 +68,23 @@ public class ServerRpcManager<T> implements RpcManager {
* method invocation to perform
*/
public static void applyInvocation(RpcTarget target,
- MethodInvocation invocation) {
- try {
- Class<?> rpcInterfaceClass = Class.forName(invocation
- .getInterfaceName());
- RpcManager manager = target.getRpcManager(rpcInterfaceClass);
- if (manager != null) {
- manager.applyInvocation(invocation);
- } else {
- getLogger()
- .log(Level.WARNING,
- "RPC call received for RpcTarget "
- + target.getClass().getName()
- + " ("
- + invocation.getConnectorId()
- + ") but the target has not registered any RPC interfaces");
- }
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("Class for RPC interface "
- + invocation.getInterfaceName() + " of the target "
- + target + " could not be found.");
+ ServerRpcMethodInvocation invocation) {
+ RpcManager manager = target.getRpcManager(invocation
+ .getInterfaceClass());
+ if (manager != null) {
+ manager.applyInvocation(invocation);
+ } else {
+ getLogger()
+ .log(Level.WARNING,
+ "RPC call received for RpcTarget "
+ + target.getClass().getName()
+ + " ("
+ + invocation.getConnectorId()
+ + ") but the target has not registered any RPC interfaces");
}
}
/**
- * Returns the RPC target of this RPC manager instance.
- *
- * @return RpcTarget, typically a {@link Connector}
- */
- public RpcTarget getTarget() {
- return target;
- }
-
- /**
* Returns the RPC interface implementation for the RPC target.
*
* @return RPC interface implementation
@@ -133,21 +109,11 @@ public class ServerRpcManager<T> implements RpcManager {
* @param invocation
* method invocation to perform
*/
- public void applyInvocation(MethodInvocation invocation) {
- String methodName = invocation.getMethodName();
- // here, we already know that the interface is an rpcInterface
- Object[] arguments = invocation.getParameters();
-
- Method method = findInvocationMethod(rpcInterface, methodName,
- arguments.length);
- if (method == null) {
- throw new RuntimeException(implementation + " does not contain "
- + rpcInterface.getName() + "." + methodName + " with "
- + arguments.length + " parameters");
- }
-
+ public void applyInvocation(ServerRpcMethodInvocation invocation) {
+ Method method = invocation.getMethod();
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] args = new Object[parameterTypes.length];
+ Object[] arguments = invocation.getParameters();
for (int i = 0; i < args.length; i++) {
// no conversion needed for basic cases
// Class<?> type = parameterTypes[i];
@@ -159,41 +125,10 @@ public class ServerRpcManager<T> implements RpcManager {
try {
method.invoke(implementation, args);
} catch (Exception e) {
- throw new RuntimeException(methodName, e);
- }
- }
-
- private Method findInvocationMethod(Class<?> targetType, String methodName,
- int parameterCount) {
- // TODO currently only using method name and number of parameters as the
- // signature
- String signature = targetType.getName() + "." + methodName + "("
- + parameterCount;
- Method invocationMethod = invocationMethodCache.get(signature);
-
- if (invocationMethod == null) {
- invocationMethod = doFindInvocationMethod(targetType, methodName,
- parameterCount);
-
- if (invocationMethod != null) {
- invocationMethodCache.put(signature, invocationMethod);
- }
- }
-
- return invocationMethod;
- }
-
- private Method doFindInvocationMethod(Class<?> targetType,
- String methodName, int parameterCount) {
- Method[] methods = targetType.getMethods();
- for (Method method : methods) {
- Class<?>[] parameterTypes = method.getParameterTypes();
- if (method.getName().equals(methodName)
- && parameterTypes.length == parameterCount) {
- return method;
- }
+ throw new RuntimeException("Unable to invoke method "
+ + invocation.getMethodName() + " in "
+ + invocation.getInterfaceName(), e);
}
- return null;
}
private static Logger getLogger() {
diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java
new file mode 100644
index 0000000000..6f278f7797
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java
@@ -0,0 +1,107 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.server;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
+import com.vaadin.terminal.gwt.client.communication.ServerRpc;
+
+public class ServerRpcMethodInvocation extends MethodInvocation {
+
+ private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>(
+ 128, 0.75f, 1);
+
+ private final Method method;
+
+ private Class<? extends ServerRpc> interfaceClass;
+
+ public ServerRpcMethodInvocation(String connectorId, String interfaceName,
+ String methodName, int parameterCount) {
+ super(connectorId, interfaceName, methodName);
+
+ interfaceClass = findClass();
+ method = findInvocationMethod(interfaceClass, methodName,
+ parameterCount);
+ }
+
+ private Class<? extends ServerRpc> findClass() {
+ try {
+ Class<?> rpcInterface = Class.forName(getInterfaceName());
+ if (!ServerRpc.class.isAssignableFrom(rpcInterface)) {
+ throw new IllegalArgumentException("The interface "
+ + getInterfaceName() + "is not a server RPC interface.");
+ }
+ return (Class<? extends ServerRpc>) rpcInterface;
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("The server RPC interface "
+ + getInterfaceName() + " could not be found", e);
+ } finally {
+
+ }
+ }
+
+ public Class<? extends ServerRpc> getInterfaceClass() {
+ return interfaceClass;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ /**
+ * Tries to find the method from the cache or alternatively by invoking
+ * {@link #doFindInvocationMethod(Class, String, int)} and updating the
+ * cache.
+ *
+ * @param targetType
+ * @param methodName
+ * @param parameterCount
+ * @return
+ */
+ private Method findInvocationMethod(Class<?> targetType, String methodName,
+ int parameterCount) {
+ // TODO currently only using method name and number of parameters as the
+ // signature
+ String signature = targetType.getName() + "." + methodName + "("
+ + parameterCount;
+ Method invocationMethod = invocationMethodCache.get(signature);
+
+ if (invocationMethod == null) {
+ invocationMethod = doFindInvocationMethod(targetType, methodName,
+ parameterCount);
+
+ if (invocationMethod != null) {
+ invocationMethodCache.put(signature, invocationMethod);
+ }
+ }
+
+ return invocationMethod;
+ }
+
+ /**
+ * Tries to find the method from the class by looping through available
+ * methods.
+ *
+ * @param targetType
+ * @param methodName
+ * @param parameterCount
+ * @return
+ */
+ private Method doFindInvocationMethod(Class<?> targetType,
+ String methodName, int parameterCount) {
+ Method[] methods = targetType.getMethods();
+ for (Method method : methods) {
+ Class<?>[] parameterTypes = method.getParameterTypes();
+ if (method.getName().equals(methodName)
+ && parameterTypes.length == parameterCount) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
index 2c9828b66b..3838695aa3 100644
--- a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
+++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
@@ -13,6 +13,7 @@ import javax.portlet.ClientDataRequest;
import javax.portlet.PortletRequest;
import javax.portlet.ResourceRequest;
+import com.vaadin.Application;
import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.WrappedRequest;
@@ -118,8 +119,21 @@ public class WrappedPortletRequest implements WrappedRequest {
}
public BrowserDetails getBrowserDetails() {
- // No browserDetails available for normal requests
- return null;
+ return new BrowserDetails() {
+ public String getUriFragment() {
+ return null;
+ }
+
+ public String getWindowName() {
+ return null;
+ }
+
+ public WebBrowser getWebBrowser() {
+ PortletApplicationContext2 context = (PortletApplicationContext2) Application
+ .getCurrentApplication().getContext();
+ return context.getBrowser();
+ }
+ };
}
public Locale getLocale() {
diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
index e09545962b..013df4710c 100644
--- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
+++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java
@@ -5,6 +5,7 @@
package com.vaadin.terminal.gwt.widgetsetutils;
import java.io.PrintWriter;
+import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@@ -52,6 +53,8 @@ public class SerializerMapGenerator extends Generator {
TypeOracle typeOracle = context.getTypeOracle();
Set<JClassType> typesNeedingSerializers = findTypesNeedingSerializers(
typeOracle, logger);
+ warnIfNotJavaSerializable(typesNeedingSerializers, typeOracle,
+ logger);
Set<JClassType> typesWithExistingSerializers = findTypesWithExistingSerializers(
typeOracle, logger);
Set<JClassType> serializerMappings = new HashSet<JClassType>();
@@ -77,6 +80,34 @@ public class SerializerMapGenerator extends Generator {
return packageName + "." + className;
}
+ /**
+ * Emits a warning for all classes that are used in communication but do not
+ * implement java.io.Serializable. Implementing java.io.Serializable is not
+ * needed for communication but for the server side Application to be
+ * serializable i.e. work in GAE for instance.
+ *
+ * @param typesNeedingSerializers
+ * @param typeOracle
+ * @param logger
+ */
+ private void warnIfNotJavaSerializable(
+ Set<JClassType> typesNeedingSerializers, TypeOracle typeOracle,
+ TreeLogger logger) {
+ JClassType javaSerializable = typeOracle.findType(Serializable.class
+ .getName());
+ for (JClassType type : typesNeedingSerializers) {
+ boolean serializable = type.isAssignableTo(javaSerializable);
+ if (!serializable) {
+ logger.log(
+ Type.ERROR,
+ type
+ + " is used in RPC or shared state but does not implement "
+ + Serializable.class.getName()
+ + ". Communication will work but the Application on server side cannot be serialized if it refers to objects of this type.");
+ }
+ }
+ }
+
private Set<JClassType> findTypesWithExistingSerializers(
TypeOracle typeOracle, TreeLogger logger) {
JClassType serializerInterface = typeOracle
@@ -233,8 +264,9 @@ public class SerializerMapGenerator extends Generator {
return;
}
- if (serializableTypes.contains(type))
+ if (serializableTypes.contains(type)) {
return;
+ }
JClassType typeClass = type.isClass();
if (typeClass != null) {
diff --git a/src/com/vaadin/ui/AbsoluteLayout.java b/src/com/vaadin/ui/AbsoluteLayout.java
index e548798abe..9ba005f75a 100644
--- a/src/com/vaadin/ui/AbsoluteLayout.java
+++ b/src/com/vaadin/ui/AbsoluteLayout.java
@@ -16,7 +16,7 @@ import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.absolutelayout.AbsoluteLayoutServerRPC;
+import com.vaadin.terminal.gwt.client.ui.absolutelayout.AbsoluteLayoutServerRpc;
import com.vaadin.terminal.gwt.client.ui.absolutelayout.AbsoluteLayoutState;
/**
@@ -28,7 +28,7 @@ import com.vaadin.terminal.gwt.client.ui.absolutelayout.AbsoluteLayoutState;
public class AbsoluteLayout extends AbstractLayout implements
LayoutClickNotifier {
- private AbsoluteLayoutServerRPC rpc = new AbsoluteLayoutServerRPC() {
+ private AbsoluteLayoutServerRpc rpc = new AbsoluteLayoutServerRpc() {
public void layoutClick(MouseEventDetails mouseDetails,
Connector clickedConnector) {
diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java
index 83e6f54ad3..79a07ae00e 100644
--- a/src/com/vaadin/ui/AbstractComponent.java
+++ b/src/com/vaadin/ui/AbstractComponent.java
@@ -534,6 +534,31 @@ public abstract class AbstractComponent implements Component, MethodEventSource
return parent;
}
+ /**
+ * Returns the closest ancestor with the given type.
+ * <p>
+ * To find the Window that contains the component, use {@code Window w =
+ * getParent(Window.class);}
+ * </p>
+ *
+ * @param <T>
+ * The type of the ancestor
+ * @param parentType
+ * The ancestor class we are looking for
+ * @return The first ancestor that can be assigned to the given class. Null
+ * if no ancestor with the correct type could be found.
+ */
+ public <T extends HasComponents> T findAncestor(Class<T> parentType) {
+ HasComponents p = getParent();
+ while (p != null) {
+ if (parentType.isAssignableFrom(p.getClass())) {
+ return parentType.cast(p);
+ }
+ p = p.getParent();
+ }
+ return null;
+ }
+
/*
* Sets the parent component. Don't add a JavaDoc comment here, we use the
* default documentation from implemented interface.
@@ -1461,7 +1486,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
private void setActionManagerViewer() {
if (actionManager != null && getRoot() != null) {
// Attached and has action manager
- Window w = findParentOfType(Window.class, this);
+ Window w = findAncestor(Window.class);
if (w != null) {
actionManager.setViewer(w);
} else {
@@ -1471,32 +1496,6 @@ public abstract class AbstractComponent implements Component, MethodEventSource
}
- /**
- * Helper method for finding the first parent component of a given type.
- * Useful e.g. for finding the Window the component is inside.
- *
- * @param <T>
- * @param parentType
- * The type to look for
- * @param c
- * The target component
- * @return A parent component of type {@literal parentType} or null if no
- * parent component in the hierarchy can be assigned to the given
- * type.
- */
- private static <T extends Component> T findParentOfType(
- Class<T> parentType, Component c) {
- Component p = c.getParent();
- if (p == null) {
- return null;
- }
-
- if (parentType.isAssignableFrom(p.getClass())) {
- return (T) p;
- }
- return findParentOfType(parentType, p);
- }
-
public void addShortcutListener(ShortcutListener shortcut) {
getActionManager().addAction(shortcut);
}
@@ -1522,7 +1521,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* registered
*/
protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) {
- rpcManagerMap.put(rpcInterfaceType, new ServerRpcManager<T>(this,
+ rpcManagerMap.put(rpcInterfaceType, new ServerRpcManager<T>(
implementation, rpcInterfaceType));
}
@@ -1597,7 +1596,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
- addMethodInvocationToQueue(rpcInterfaceName, method.getName(), args);
+ addMethodInvocationToQueue(rpcInterfaceName, method, args);
// TODO no need to do full repaint if only RPC calls
requestRepaint();
return null;
@@ -1618,10 +1617,10 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* @since 7.0
*/
protected void addMethodInvocationToQueue(String interfaceName,
- String methodName, Object[] parameters) {
+ Method method, Object[] parameters) {
// add to queue
pendingInvocations.add(new ClientMethodInvocation(this, interfaceName,
- methodName, parameters));
+ method, parameters));
}
/**
diff --git a/src/com/vaadin/ui/AbstractComponentContainer.java b/src/com/vaadin/ui/AbstractComponentContainer.java
index b597451a57..1c857a03cd 100644
--- a/src/com/vaadin/ui/AbstractComponentContainer.java
+++ b/src/com/vaadin/ui/AbstractComponentContainer.java
@@ -215,17 +215,6 @@ public abstract class AbstractComponentContainer extends AbstractComponent
}
@Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- if (getParent() != null && !getParent().isEnabled()) {
- // some ancestor still disabled, don't update children
- return;
- } else {
- requestRepaintAll();
- }
- }
-
- @Override
public void setVisible(boolean visible) {
if (getState().isVisible() == visible) {
return;
@@ -379,6 +368,15 @@ public abstract class AbstractComponentContainer extends AbstractComponent
*/
public static void requestRepaintAll(HasComponents container) {
container.requestRepaint();
+ if (container instanceof Panel) {
+ Panel p = (Panel) container;
+ // #2924 Panel is invalid, really invalid.
+ // Panel.getComponentIterator returns the children of content, not
+ // of Panel...
+ if (p.getContent() != null) {
+ p.getContent().requestRepaint();
+ }
+ }
for (Iterator<Component> childIterator = container
.getComponentIterator(); childIterator.hasNext();) {
Component c = childIterator.next();
diff --git a/src/com/vaadin/ui/AbstractOrderedLayout.java b/src/com/vaadin/ui/AbstractOrderedLayout.java
index 0f2f670331..3606fa6572 100644
--- a/src/com/vaadin/ui/AbstractOrderedLayout.java
+++ b/src/com/vaadin/ui/AbstractOrderedLayout.java
@@ -19,7 +19,7 @@ import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutServerRPC;
+import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutState;
@SuppressWarnings("serial")
@@ -27,7 +27,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier,
Vaadin6Component {
- private AbstractOrderedLayoutServerRPC rpc = new AbstractOrderedLayoutServerRPC() {
+ private AbstractOrderedLayoutServerRpc rpc = new AbstractOrderedLayoutServerRpc() {
public void layoutClick(MouseEventDetails mouseDetails,
Connector clickedConnector) {
diff --git a/src/com/vaadin/ui/AbstractSplitPanel.java b/src/com/vaadin/ui/AbstractSplitPanel.java
index 5eb46b85a9..5205952621 100644
--- a/src/com/vaadin/ui/AbstractSplitPanel.java
+++ b/src/com/vaadin/ui/AbstractSplitPanel.java
@@ -13,7 +13,7 @@ import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.ClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelRPC;
+import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelRpc;
import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState;
import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState.SplitterState;
import com.vaadin.tools.ReflectTools;
@@ -33,7 +33,7 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer {
private Unit posUnit;
- private AbstractSplitPanelRPC rpc = new AbstractSplitPanelRPC() {
+ private AbstractSplitPanelRpc rpc = new AbstractSplitPanelRpc() {
public void splitterClick(MouseEventDetails mouseDetails) {
fireEvent(new SplitterClickEvent(AbstractSplitPanel.this,
@@ -71,7 +71,6 @@ public abstract class AbstractSplitPanel extends AbstractComponentContainer {
return null;
}
i++;
- AbstractSplitPanelState state = getState();
if (i == 1) {
return (getFirstComponent() == null ? getSecondComponent()
: getFirstComponent());
diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java
index f5e45ef3ef..876fe593e2 100644
--- a/src/com/vaadin/ui/Button.java
+++ b/src/com/vaadin/ui/Button.java
@@ -489,4 +489,33 @@ public class Button extends AbstractComponent implements
return (ButtonState) super.getState();
}
+ /**
+ * Set whether the caption text is rendered as HTML or not. You might need
+ * to retheme button to allow higher content than the original text style.
+ *
+ * If set to true, the captions are passed to the browser as html and the
+ * developer is responsible for ensuring no harmful html is used. If set to
+ * false, the content is passed to the browser as plain text.
+ *
+ * @param htmlContentAllowed
+ * <code>true</code> if caption is rendered as HTML,
+ * <code>false</code> otherwise
+ */
+ public void setHtmlContentAllowed(boolean htmlContentAllowed) {
+ if (getState().isHtmlContentAllowed() != htmlContentAllowed) {
+ getState().setHtmlContentAllowed(htmlContentAllowed);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Return HTML rendering setting
+ *
+ * @return <code>true</code> if the caption text is to be rendered as HTML,
+ * <code>false</code> otherwise
+ */
+ public boolean isHtmlContentAllowed() {
+ return getState().isHtmlContentAllowed();
+ }
+
}
diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java
index eacf17b6a7..3632c4ca5e 100644
--- a/src/com/vaadin/ui/Component.java
+++ b/src/com/vaadin/ui/Component.java
@@ -17,7 +17,6 @@ import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.VariableOwner;
import com.vaadin.terminal.gwt.client.ComponentState;
import com.vaadin.terminal.gwt.server.ClientConnector;
-import com.vaadin.terminal.gwt.server.RpcTarget;
/**
* {@code Component} is the top-level interface that is and must be implemented
@@ -52,8 +51,7 @@ import com.vaadin.terminal.gwt.server.RpcTarget;
* @VERSION@
* @since 3.0
*/
-public interface Component extends ClientConnector, Sizeable, Serializable,
- RpcTarget {
+public interface Component extends ClientConnector, Sizeable, Serializable {
/**
* Gets all user-defined CSS style names of a component. If the component
diff --git a/src/com/vaadin/ui/CssLayout.java b/src/com/vaadin/ui/CssLayout.java
index ac4f4b31a9..0a2656af31 100644
--- a/src/com/vaadin/ui/CssLayout.java
+++ b/src/com/vaadin/ui/CssLayout.java
@@ -11,7 +11,7 @@ import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.event.LayoutEvents.LayoutClickNotifier;
import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.ui.csslayout.CssLayoutServerRPC;
+import com.vaadin.terminal.gwt.client.ui.csslayout.CssLayoutServerRpc;
import com.vaadin.terminal.gwt.client.ui.csslayout.CssLayoutState;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
@@ -58,7 +58,7 @@ import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
*/
public class CssLayout extends AbstractLayout implements LayoutClickNotifier {
- private CssLayoutServerRPC rpc = new CssLayoutServerRPC() {
+ private CssLayoutServerRpc rpc = new CssLayoutServerRpc() {
public void layoutClick(MouseEventDetails mouseDetails,
Connector clickedConnector) {
diff --git a/src/com/vaadin/ui/CustomLayout.java b/src/com/vaadin/ui/CustomLayout.java
index 0d74fe9878..97cea1c49d 100644
--- a/src/com/vaadin/ui/CustomLayout.java
+++ b/src/com/vaadin/ui/CustomLayout.java
@@ -9,8 +9,14 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.gwt.client.ui.customlayout.CustomLayoutState;
+import com.vaadin.terminal.gwt.server.JsonPaintTarget;
/**
* <p>
@@ -42,7 +48,7 @@ import com.vaadin.terminal.gwt.client.ui.customlayout.CustomLayoutState;
* @since 3.0
*/
@SuppressWarnings("serial")
-public class CustomLayout extends AbstractLayout {
+public class CustomLayout extends AbstractLayout implements Vaadin6Component {
private static final int BUFFER_SIZE = 10000;
@@ -299,4 +305,20 @@ public class CustomLayout extends AbstractLayout {
"CustomLayout does not support margins.");
}
+ public void changeVariables(Object source, Map<String, Object> variables) {
+ // Nothing to see here
+ }
+
+ public void paintContent(PaintTarget target) throws PaintException {
+ // Workaround to make the CommunicationManager read the template file
+ // and send it to the client
+ String templateName = getState().getTemplateName();
+ if (templateName != null && templateName.length() != 0) {
+ Set<Object> usedResources = ((JsonPaintTarget) target)
+ .getUsedResources();
+ String resourceName = "layouts/" + templateName + ".html";
+ usedResources.add(resourceName);
+ }
+ }
+
}
diff --git a/src/com/vaadin/ui/Embedded.java b/src/com/vaadin/ui/Embedded.java
index 052436cef7..1bcd984666 100644
--- a/src/com/vaadin/ui/Embedded.java
+++ b/src/com/vaadin/ui/Embedded.java
@@ -17,7 +17,7 @@ import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.ClickEventHandler;
import com.vaadin.terminal.gwt.client.ui.embedded.EmbeddedConnector;
-import com.vaadin.terminal.gwt.client.ui.embedded.EmbeddedServerRPC;
+import com.vaadin.terminal.gwt.client.ui.embedded.EmbeddedServerRpc;
/**
* Component for embedding external objects.
@@ -80,7 +80,7 @@ public class Embedded extends AbstractComponent implements Vaadin6Component {
private String altText;
- private EmbeddedServerRPC rpc = new EmbeddedServerRPC() {
+ private EmbeddedServerRpc rpc = new EmbeddedServerRpc() {
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Embedded.this, mouseDetails));
}
diff --git a/src/com/vaadin/ui/GridLayout.java b/src/com/vaadin/ui/GridLayout.java
index 689cdcf28e..0ab729ce5c 100644
--- a/src/com/vaadin/ui/GridLayout.java
+++ b/src/com/vaadin/ui/GridLayout.java
@@ -22,7 +22,7 @@ import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.gridlayout.GridLayoutServerRPC;
+import com.vaadin.terminal.gwt.client.ui.gridlayout.GridLayoutServerRpc;
import com.vaadin.terminal.gwt.client.ui.gridlayout.GridLayoutState;
/**
@@ -56,7 +56,7 @@ public class GridLayout extends AbstractLayout implements
Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier,
Vaadin6Component {
- private GridLayoutServerRPC rpc = new GridLayoutServerRPC() {
+ private GridLayoutServerRpc rpc = new GridLayoutServerRpc() {
public void layoutClick(MouseEventDetails mouseDetails,
Connector clickedConnector) {
diff --git a/src/com/vaadin/ui/Panel.java b/src/com/vaadin/ui/Panel.java
index e358462bbb..b2916f78c7 100644
--- a/src/com/vaadin/ui/Panel.java
+++ b/src/com/vaadin/ui/Panel.java
@@ -18,7 +18,7 @@ import com.vaadin.terminal.Scrollable;
import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.ClickEventHandler;
-import com.vaadin.terminal.gwt.client.ui.panel.PanelServerRPC;
+import com.vaadin.terminal.gwt.client.ui.panel.PanelServerRpc;
import com.vaadin.terminal.gwt.client.ui.panel.PanelState;
import com.vaadin.ui.Component.Focusable;
@@ -47,7 +47,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable,
*/
protected ActionManager actionManager;
- private PanelServerRPC rpc = new PanelServerRPC() {
+ private PanelServerRpc rpc = new PanelServerRpc() {
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Panel.this, mouseDetails));
}
diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java
index 541127e092..405ae8da93 100644
--- a/src/com/vaadin/ui/Root.java
+++ b/src/com/vaadin/ui/Root.java
@@ -33,7 +33,7 @@ import com.vaadin.terminal.WrappedRequest.BrowserDetails;
import com.vaadin.terminal.gwt.client.ComponentState;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.notification.VNotification;
-import com.vaadin.terminal.gwt.client.ui.root.RootServerRPC;
+import com.vaadin.terminal.gwt.client.ui.root.RootServerRpc;
import com.vaadin.terminal.gwt.client.ui.root.RootState;
import com.vaadin.terminal.gwt.client.ui.root.VRoot;
import com.vaadin.tools.ReflectTools;
@@ -409,7 +409,7 @@ public abstract class Root extends AbstractComponentContainer implements
private DirtyConnectorTracker dirtyConnectorTracker = new DirtyConnectorTracker(
this);
- private RootServerRPC rpc = new RootServerRPC() {
+ private RootServerRpc rpc = new RootServerRpc() {
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Root.this, mouseDetails));
}
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 2fffedd9d6..ba4c6529c5 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -1930,7 +1930,7 @@ public class Table extends AbstractSelect implements Action.Container,
if (index < firstIndexNotInCache
&& index >= pageBufferFirstIndex
&& pageBuffer[CELL_GENERATED_ROW][indexInOldBuffer] == null
- && pageBuffer[CELL_ITEMID][indexInOldBuffer] == id) {
+ && id.equals(pageBuffer[CELL_ITEMID][indexInOldBuffer])) {
// we already have data in our cache,
// recycle it instead of fetching it via
// getValue/getPropertyValue
diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java
index 6c3d75a920..3c17baf414 100644
--- a/src/com/vaadin/ui/Window.java
+++ b/src/com/vaadin/ui/Window.java
@@ -24,7 +24,7 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.ui.window.WindowServerRPC;
+import com.vaadin.terminal.gwt.client.ui.window.WindowServerRpc;
import com.vaadin.terminal.gwt.client.ui.window.WindowState;
/**
@@ -76,7 +76,7 @@ import com.vaadin.terminal.gwt.client.ui.window.WindowState;
public class Window extends Panel implements FocusNotifier, BlurNotifier,
Vaadin6Component {
- private WindowServerRPC rpc = new WindowServerRPC() {
+ private WindowServerRpc rpc = new WindowServerRpc() {
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Window.this, mouseDetails));
diff --git a/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java b/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java
index f661b6cf15..fedce98ecf 100644
--- a/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java
+++ b/tests/client-side/com/vaadin/terminal/gwt/client/TestVBrowserDetailsUserAgentParser.java
@@ -2,8 +2,6 @@ package com.vaadin.terminal.gwt.client;
import junit.framework.TestCase;
-import com.vaadin.terminal.gwt.client.VBrowserDetails;
-
public class TestVBrowserDetailsUserAgentParser extends TestCase {
private static final String FIREFOX30_WINDOWS = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6";
@@ -37,6 +35,15 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase {
private static final String SAFARI3_WINDOWS = "Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29";
private static final String SAFARI4_MAC = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_8; en-us) AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7";
+ private static final String IPHONE_IOS_5_1 = "Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B179 Safari/7534.48.3";
+ private static final String IPHONE_IOS_4_0 = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";
+ private static final String IPAD_IOS_4_3_1 = "Mozilla/5.0 (iPad; U; CPU OS 4_3_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8G4 Safari/6533.18.5";
+
+ private static final String ANDROID_HTC_2_1 = "Mozilla/5.0 (Linux; U; Android 2.1-update1; en-us; ADR6300 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17";
+ private static final String ANDROID_GOOGLE_NEXUS_2_2 = "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
+ private static final String ANDROID_MOTOROLA_3_0 = "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13";
+ private static final String ANDROID_GALAXY_NEXUS_4_0_4_CHROME = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19";
+
public void testSafari3() {
VBrowserDetails bd = new VBrowserDetails(SAFARI3_WINDOWS);
assertWebKit(bd);
@@ -57,6 +64,86 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase {
assertMacOSX(bd);
}
+ public void testIPhoneIOS5() {
+ VBrowserDetails bd = new VBrowserDetails(IPHONE_IOS_5_1);
+ assertWebKit(bd);
+ assertSafari(bd);
+ assertBrowserMajorVersion(bd, 5);
+ assertBrowserMinorVersion(bd, 1);
+ assertEngineVersion(bd, 534f);
+ assertIOS(bd, 5, 1);
+ }
+
+ public void testIPhoneIOS4() {
+ VBrowserDetails bd = new VBrowserDetails(IPHONE_IOS_4_0);
+ assertWebKit(bd);
+ assertSafari(bd);
+ assertBrowserMajorVersion(bd, 4);
+ assertBrowserMinorVersion(bd, 0);
+ assertEngineVersion(bd, 532f);
+ assertIOS(bd, 4, 0);
+ }
+
+ public void testIPadIOS4() {
+ VBrowserDetails bd = new VBrowserDetails(IPAD_IOS_4_3_1);
+ assertWebKit(bd);
+ assertSafari(bd);
+ assertBrowserMajorVersion(bd, 5);
+ assertBrowserMinorVersion(bd, 0);
+ assertEngineVersion(bd, 533f);
+ assertIOS(bd, 4, 3);
+ }
+
+ public void testAndroid21() {
+ VBrowserDetails bd = new VBrowserDetails(ANDROID_HTC_2_1);
+ assertWebKit(bd);
+ assertSafari(bd);
+ assertBrowserMajorVersion(bd, 4);
+ assertBrowserMinorVersion(bd, 0);
+ assertEngineVersion(bd, 530f);
+ assertAndroid(bd, 2, 1);
+
+ }
+
+ public void testAndroid22() {
+ VBrowserDetails bd = new VBrowserDetails(ANDROID_GOOGLE_NEXUS_2_2);
+ assertWebKit(bd);
+ assertSafari(bd);
+ assertBrowserMajorVersion(bd, 4);
+ assertBrowserMinorVersion(bd, 0);
+ assertEngineVersion(bd, 533f);
+ assertAndroid(bd, 2, 2);
+ }
+
+ public void testAndroid30() {
+ VBrowserDetails bd = new VBrowserDetails(ANDROID_MOTOROLA_3_0);
+ assertWebKit(bd);
+ assertSafari(bd);
+ assertBrowserMajorVersion(bd, 4);
+ assertBrowserMinorVersion(bd, 0);
+ assertEngineVersion(bd, 534f);
+ assertAndroid(bd, 3, 0);
+ }
+
+ public void testAndroid40Chrome() {
+ VBrowserDetails bd = new VBrowserDetails(
+ ANDROID_GALAXY_NEXUS_4_0_4_CHROME);
+ assertWebKit(bd);
+ assertChrome(bd);
+ assertBrowserMajorVersion(bd, 18);
+ assertBrowserMinorVersion(bd, 0);
+ assertEngineVersion(bd, 535f);
+ assertAndroid(bd, 4, 0);
+ }
+
+ private void assertOSMajorVersion(VBrowserDetails bd, int i) {
+ assertEquals(i, bd.getOperatingSystemMajorVersion());
+ }
+
+ private void assertOSMinorVersion(VBrowserDetails bd, int i) {
+ assertEquals(i, bd.getOperatingSystemMinorVersion());
+ }
+
public void testChrome3() {
VBrowserDetails bd = new VBrowserDetails(CHROME3_MAC);
assertWebKit(bd);
@@ -352,18 +439,47 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase {
assertFalse(browserDetails.isLinux());
assertFalse(browserDetails.isWindows());
assertTrue(browserDetails.isMacOSX());
+ assertFalse(browserDetails.isAndroid());
+ }
+
+ private void assertAndroid(VBrowserDetails browserDetails,
+ int majorVersion, int minorVersion) {
+ assertFalse(browserDetails.isLinux());
+ assertFalse(browserDetails.isWindows());
+ assertFalse(browserDetails.isMacOSX());
+ assertFalse(browserDetails.isIOS());
+ assertTrue(browserDetails.isAndroid());
+
+ assertOSMajorVersion(browserDetails, majorVersion);
+ assertOSMinorVersion(browserDetails, minorVersion);
+ }
+
+ private void assertIOS(VBrowserDetails browserDetails, int majorVersion,
+ int minorVersion) {
+ assertFalse(browserDetails.isLinux());
+ assertFalse(browserDetails.isWindows());
+ assertFalse(browserDetails.isMacOSX());
+ assertTrue(browserDetails.isIOS());
+ assertFalse(browserDetails.isAndroid());
+
+ assertOSMajorVersion(browserDetails, majorVersion);
+ assertOSMinorVersion(browserDetails, minorVersion);
}
private void assertWindows(VBrowserDetails browserDetails) {
assertFalse(browserDetails.isLinux());
assertTrue(browserDetails.isWindows());
assertFalse(browserDetails.isMacOSX());
+ assertFalse(browserDetails.isIOS());
+ assertFalse(browserDetails.isAndroid());
}
private void assertLinux(VBrowserDetails browserDetails) {
assertTrue(browserDetails.isLinux());
assertFalse(browserDetails.isWindows());
assertFalse(browserDetails.isMacOSX());
+ assertFalse(browserDetails.isIOS());
+ assertFalse(browserDetails.isAndroid());
}
}
diff --git a/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html b/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html
index d97a9dce4a..85258d7036 100644
--- a/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html
+++ b/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html
@@ -118,7 +118,7 @@
</tr>
<tr>
<td>mouseClickAndWait</td>
- <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div/div[5]/div/div/a</td>
+ <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div[5]/div/a</td>
<td>10,10</td>
</tr>
<tr>
@@ -138,7 +138,7 @@
</tr>
<tr>
<td>mouseClickAndWait</td>
- <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div/div[5]/div/div/a</td>
+ <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div[5]/div/a</td>
<td>15,8</td>
</tr>
<tr>
diff --git a/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java b/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java
index 453aab5af8..9906990165 100644
--- a/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java
+++ b/tests/server-side/com/vaadin/tests/server/SourceFileChecker.java
@@ -5,6 +5,8 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import junit.framework.Assert;
import junit.framework.TestCase;
@@ -81,6 +83,17 @@ public class SourceFileChecker extends TestCase {
}
}
+ public void testGwtFilesUsingEntry() {
+ Set<String> ignore = new HashSet<String>(alwaysIgnore);
+ ignore.add(externalJavaFiles);
+ validateFiles(
+ SRC_DIR,
+ new GwtEntryChecker(),
+ ignore,
+ "The following files might export javscript callbacks without $entry:\n{0}",
+ ".java");
+ }
+
public interface FileValidator {
void validateFile(File f) throws Exception;
}
@@ -171,4 +184,33 @@ public class SourceFileChecker extends TestCase {
}
}
}
+
+ class GwtEntryChecker extends FileContentsValidator {
+ // Matches e.g.
+ // @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::escapeHtml(
+ private final Matcher matcher = Pattern.compile("@[\\w.]+::\\w+\\(")
+ .matcher("");
+
+ @Override
+ protected void validateContents(File f, String contents)
+ throws Exception {
+ matcher.reset(contents);
+ while (matcher.find()) {
+ int start = matcher.start();
+
+ // Search backwards to find index of native block start
+ int nativeBlockStart = contents.lastIndexOf("/*-{", start);
+
+ // Get contents between block start and our match
+ String beforeMatchInBlock = contents.substring(
+ nativeBlockStart, start);
+
+ // Fail if there's no $entry
+ if (!beforeMatchInBlock.contains("$entry")) {
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+
+ }
}
diff --git a/tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java b/tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java
new file mode 100644
index 0000000000..66535d3ffb
--- /dev/null
+++ b/tests/server-side/com/vaadin/tests/server/component/tree/TestHasChildren.java
@@ -0,0 +1,25 @@
+package com.vaadin.tests.server.component.tree;
+
+import junit.framework.TestCase;
+
+import com.vaadin.ui.Tree;
+
+public class TestHasChildren extends TestCase {
+
+ private Tree tree;
+
+ @Override
+ protected void setUp() {
+ tree = new Tree();
+ tree.addItem("parent");
+ tree.addItem("child");
+ tree.setChildrenAllowed("parent", true);
+ tree.setParent("child", "parent");
+ }
+
+ public void testRemoveChildren() {
+ assertTrue(tree.hasChildren("parent"));
+ tree.removeItem("child");
+ assertFalse(tree.hasChildren("parent"));
+ }
+}
diff --git a/tests/test.xml b/tests/test.xml
index 28459c37e9..67e48ee137 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-firefox11,winxp-safari5,winxp-googlechrome18,winxp-opera11" />
+ <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox12,winxp-safari5,winxp-googlechrome18,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/browserfeatures/FullHeightScrollbar.html b/tests/testbench/com/vaadin/tests/browserfeatures/FullHeightScrollbar.html
new file mode 100644
index 0000000000..37fee35746
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/browserfeatures/FullHeightScrollbar.html
@@ -0,0 +1,47 @@
+<?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="http://192.168.2.41:8888/" />
+<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>/statictestfiles/browserfeatures/fullHeightScrollbar.html</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>1-withScrolling</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>disableScrolling</td>
+ <td>34,7</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>2-withoutScrolling</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>triggerReflow</td>
+ <td>34,7</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>3-afterReflow</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html
new file mode 100644
index 0000000000..029da64754
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html
@@ -0,0 +1,86 @@
+<?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>DisableEnableCascade</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">DisableEnableCascade</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.DisableEnableCascade?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>panel-disabled</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>tabsheet-disabled</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>all-enabled</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>tabsheet-button-disabled</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>all-enabled2</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java
new file mode 100644
index 0000000000..aa83ff7a42
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java
@@ -0,0 +1,90 @@
+package com.vaadin.tests.components;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TabSheet;
+
+public class DisableEnableCascade extends TestBase {
+
+ private Panel outerPanel;
+ private TabSheet innerTabsheet;
+ private Button button;
+ private Button enableDisablePanelButton;
+ private Button enableDisableTabSheetButton;
+ private Button enableDisableButtonButton;
+
+ @Override
+ protected void setup() {
+
+ outerPanel = new Panel("Outer panel, enabled");
+ innerTabsheet = new TabSheet();
+ innerTabsheet.setCaption("Inner Tabsheet, enabled");
+
+ button = new Button("Button, enabled");
+
+ outerPanel.setContent(innerTabsheet);
+ innerTabsheet.addTab(button, "Tab containing button");
+
+ addComponent(outerPanel);
+
+ enableDisablePanelButton = new Button("Disable panel",
+ new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ enableDisable(outerPanel, enableDisablePanelButton);
+
+ }
+ });
+
+ enableDisableTabSheetButton = new Button("Disable TabSheet",
+ new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ enableDisable(innerTabsheet,
+ enableDisableTabSheetButton);
+
+ }
+ });
+
+ enableDisableButtonButton = new Button("Disable Button",
+ new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ enableDisable(button, enableDisableButtonButton);
+
+ }
+ });
+
+ addComponent(enableDisablePanelButton);
+ addComponent(enableDisableTabSheetButton);
+ addComponent(enableDisableButtonButton);
+ }
+
+ protected void enableDisable(Component target, Button button) {
+ if (target.isEnabled()) {
+ target.setEnabled(false);
+ button.setCaption(button.getCaption().replace("Disable", "Enable"));
+ target.setCaption(target.getCaption()
+ .replace("enabled", "disabled"));
+ } else {
+ target.setEnabled(true);
+ button.setCaption(button.getCaption().replace("Enable", "Disable"));
+ target.setCaption(target.getCaption()
+ .replace("disabled", "enabled"));
+ }
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Tests the disable state is cascaded correctly to children. Disabling a parent should disabled its children aswell. The buttons only toggle the state of the target component.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8507;
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/components/TouchScrollables.java b/tests/testbench/com/vaadin/tests/components/TouchScrollables.java
new file mode 100644
index 0000000000..053691e738
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/TouchScrollables.java
@@ -0,0 +1,314 @@
+package com.vaadin.tests.components;
+
+import java.util.Collection;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.event.Action;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.event.DataBoundTransferable;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.SourceIs;
+import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+import com.vaadin.tests.util.Person;
+import com.vaadin.tests.util.PersonContainer;
+import com.vaadin.tests.util.TestUtils;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.Accordion;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.HorizontalSplitPanel;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+
+public class TouchScrollables extends TestBase {
+ java.util.Random r = new java.util.Random(1);
+
+ private TabSheet testSelector = new TabSheet();
+
+ @Override
+ public void setup() {
+ getLayout().addComponent(testSelector);
+ testSelector.setHeight("500px");
+
+ addTest(getPanelTest());
+ addTest(getSimpleTableTest());
+ addTest(getDDSortableTableTest());
+ addTest(getTabSheetTest());
+ addTest(getSplitPanelTest());
+ addTest(getAccordionTest());
+ addTest(getSubWindowTest());
+
+ TestUtils
+ .injectCSS(
+ getLayout().getRoot(),
+ "body * {-webkit-user-select: none;} .v-table-row-drag-middle .v-table-cell-content {"
+ + " background-color: inherit ; border-bottom: 1px solid cyan;"
+ + "}"
+ + ".v-table-row-drag-middle .v-table-cell-wrapper {"
+ + " margin-bottom: -1px;" + "}" + ""
+
+ );
+ }
+
+ private Component getPanelTest() {
+ Layout cssLayout = new CssLayout();
+ cssLayout.setCaption("Panel");
+
+ final Panel p = new Panel();
+ p.setHeight("400px");
+ Label l50 = null;
+ for (int i = 0; i < 100; i++) {
+ Label c = new Label("Label" + i);
+ p.addComponent(c);
+ if (i == 50) {
+ l50 = c;
+ }
+ }
+
+ final Label l = l50;
+ Button button = new Button("Scroll to label 50",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ getLayout().getRoot().scrollIntoView(l);
+ }
+ });
+ cssLayout.addComponent(button);
+ button = new Button("Scroll to 100px", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ p.setScrollTop(100);
+ }
+ });
+ cssLayout.addComponent(button);
+ cssLayout.addComponent(p);
+ return cssLayout;
+ }
+
+ private Component getTabSheetTest() {
+ TabSheet ts = new TabSheet();
+ ts.setCaption("Tabsheet");
+ ts.setHeight("100%");
+ ts.addTab(getBigComponent(), "Tab 1");
+ ts.addTab(getBigComponent(), "Tab 2");
+ return ts;
+ }
+
+ private Component getSplitPanelTest() {
+ HorizontalSplitPanel sp = new HorizontalSplitPanel();
+ sp.setCaption("Splitpanel");
+ sp.addComponent(getBigComponent());
+ sp.addComponent(getBigComponent());
+ return sp;
+ }
+
+ private Component getSimpleTableTest() {
+ CssLayout cssLayout = new CssLayout();
+ final Table table = new Table();
+
+ Button button = new Button("Toggle lazyloading");
+ button.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (table.getCacheRate() == 100) {
+ table.setCacheRate(2);
+ table.setPageLength(15);
+ } else {
+ table.setCacheRate(100);
+ table.setHeight("400px");
+ }
+ }
+ });
+ cssLayout.addComponent(button);
+
+ button = new Button("Toggle selectable");
+ button.addListener(new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ table.setSelectable(!table.isSelectable());
+ }
+ });
+ cssLayout.addComponent(button);
+
+ table.addContainerProperty("foo", String.class, "bar");
+ table.setRowHeaderMode(Table.ROW_HEADER_MODE_INDEX);
+ for (int i = 0; i < 1000; i++) {
+ table.addItem();
+ }
+ cssLayout.addComponent(table);
+ cssLayout.setCaption("Table");
+ return cssLayout;
+ }
+
+ private Component getAccordionTest() {
+ Accordion a = new Accordion();
+ a.setCaption("Accordion");
+ a.setHeight("100%");
+ a.addTab(getBigComponent(), "Tab 1");
+ a.addTab(getBigComponent(), "Tab 2");
+ a.addTab(getBigComponent(), "Tab 3");
+ return a;
+ }
+
+ private Component getSubWindowTest() {
+ Button b = new Button("Open subwindow", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Window w = new Window("Subwindow");
+ w.center();
+ w.setHeight("200px");
+ w.addComponent(getBigComponent());
+ getMainWindow().addWindow(w);
+ }
+ });
+ return b;
+ }
+
+ private Component getDDSortableTableTest() {
+ final Table table;
+ table = new Table();
+ table.setCaption("DD sortable table with context menus");
+ // table.setWidth("100%");
+ table.setPageLength(10);
+ table.setRowHeaderMode(Table.ROW_HEADER_MODE_ID);
+ table.setSelectable(true);
+ table.setMultiSelect(true);
+
+ table.addActionHandler(new Handler() {
+
+ Action[] actions = new Action[] { new Action("FOO"),
+ new Action("BAR"), new Action("CAR") };
+
+ public Action[] getActions(Object target, Object sender) {
+ return actions;
+ }
+
+ public void handleAction(Action action, Object sender, Object target) {
+ getLayout().getRoot().showNotification(action.getCaption());
+
+ }
+ });
+
+ populateTable(table);
+
+ /*
+ * Make table rows draggable
+ */
+ table.setDragMode(Table.TableDragMode.ROW);
+
+ table.setDropHandler(new DropHandler() {
+ // accept only drags from this table
+ AcceptCriterion crit = new SourceIs(table);
+
+ public AcceptCriterion getAcceptCriterion() {
+ return crit;
+ }
+
+ public void drop(DragAndDropEvent dropEvent) {
+ AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dropEvent
+ .getTargetDetails();
+ DataBoundTransferable transferable = (DataBoundTransferable) dropEvent
+ .getTransferable();
+ Object itemIdOver = dropTargetData.getItemIdOver();
+ Object itemId = transferable.getItemId();
+ if (itemId == null || itemIdOver == null
+ || itemId.equals(itemIdOver)) {
+ return; // no move happened
+ }
+
+ // IndexedContainer goodies... (hint: don't use it in real apps)
+ IndexedContainer containerDataSource = (IndexedContainer) table
+ .getContainerDataSource();
+ int newIndex = containerDataSource.indexOfId(itemIdOver) - 1;
+ if (dropTargetData.getDropLocation() != VerticalDropLocation.TOP) {
+ newIndex++;
+ }
+ if (newIndex < 0) {
+ newIndex = 0;
+ }
+ Object idAfter = containerDataSource.getIdByIndex(newIndex);
+ Collection<?> selections = (Collection<?>) table.getValue();
+ if (selections != null && selections.contains(itemId)) {
+ // dragged a selected item, if multiple rows selected, drag
+ // them too (functionality similar to apple mail)
+ for (Object object : selections) {
+ moveAfter(containerDataSource, object, idAfter);
+ }
+
+ } else {
+ // move just the dragged row, not considering selection at
+ // all
+ moveAfter(containerDataSource, itemId, idAfter);
+ }
+
+ }
+
+ private void moveAfter(IndexedContainer containerDataSource,
+ Object itemId, Object idAfter) {
+ try {
+ IndexedContainer clone = null;
+ clone = (IndexedContainer) containerDataSource.clone();
+ containerDataSource.removeItem(itemId);
+ Item newItem = containerDataSource.addItemAfter(idAfter,
+ itemId);
+ Item item = clone.getItem(itemId);
+ for (Object propId : item.getItemPropertyIds()) {
+ newItem.getItemProperty(propId).setValue(
+ item.getItemProperty(propId).getValue());
+ }
+
+ // TODO Auto-generated method stub
+ } catch (CloneNotSupportedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+ });
+ return table;
+ }
+
+ private void populateTable(Table table) {
+ table.addContainerProperty("Name", String.class, "");
+ table.addContainerProperty("Weight", Integer.class, 0);
+
+ PersonContainer testData = PersonContainer.createWithTestData();
+
+ for (int i = 0; i < 40; i++) {
+ Item addItem = table.addItem("Item" + i);
+ Person p = testData.getIdByIndex(i);
+ addItem.getItemProperty("Name").setValue(
+ p.getFirstName() + " " + p.getLastName());
+ addItem.getItemProperty("Weight").setValue(50 + r.nextInt(60));
+ }
+
+ }
+
+ private void addTest(final Component t) {
+ testSelector.addComponent(t);
+ }
+
+ private Component getBigComponent() {
+ Layout l = new VerticalLayout();
+ for (int i = 0; i < 100; i++) {
+ Label c = new Label("Label" + i);
+ l.addComponent(c);
+ }
+ return l;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Various components and setups suitable for testing scrolling on touch devices.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return null;
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html
new file mode 100644
index 0000000000..2d58d0e2e1
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.html
@@ -0,0 +1,47 @@
+<?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>ButtonHtml</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">ButtonHtml</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.button.ButtonHtml?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>initial</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>after_1_click</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>after_2_clicks</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java
new file mode 100644
index 0000000000..253de5b43c
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/button/ButtonHtml.java
@@ -0,0 +1,39 @@
+package com.vaadin.tests.components.button;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+
+public class ButtonHtml extends TestBase {
+
+ @Override
+ protected void setup() {
+ Button b = new Button("<b>Plain text button</b>");
+ addComponent(b);
+
+ b = new Button(
+ "<span style=\"color: red; font-weight: bold;\">HTML</span> button");
+ b.setHtmlContentAllowed(true);
+ addComponent(b);
+
+ final Button swapButton = new Button("<i>Swap button<i>");
+ swapButton.addListener(new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ swapButton.setHtmlContentAllowed(!swapButton
+ .isHtmlContentAllowed());
+ }
+ });
+ addComponent(swapButton);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Verify that Button HTML rendering works";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8663;
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java b/tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java
new file mode 100644
index 0000000000..37b0fe21a1
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java
@@ -0,0 +1,62 @@
+package com.vaadin.tests.components.combobox;
+
+import com.vaadin.tests.components.AbstractTestCase;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Root;
+import com.vaadin.ui.Select;
+
+@SuppressWarnings("serial")
+public class GridLayoutComboBoxZoomOut extends AbstractTestCase {
+
+ @Override
+ public void init() {
+ Root.LegacyWindow mainWindow = new Root.LegacyWindow(
+ "Gridlayoutbug Application");
+ setMainWindow(mainWindow);
+
+ Label description = new Label(
+ "Open this application in Chrome, zoom out (cmd + \"-\") and "
+ + "open the ComboBox for weird behaviour.");
+ mainWindow.addComponent(description);
+
+ Layout formLayout = new GridLayout(2, 1);
+ // formLayout.setWidth("100%");
+ formLayout.setWidth("1000px");
+
+ Select countryField = new ComboBox();
+ countryField.addItem("Finland");
+ countryField.addItem("Sweden");
+ countryField.addItem("Canada");
+ countryField.addItem("USA");
+ countryField.setCaption("Country");
+ countryField.setWidth("100%");
+ formLayout.addComponent(countryField);
+
+ Select statusField = new ComboBox();
+ statusField.addItem("Available");
+ statusField.addItem("On vacation");
+ statusField.addItem("Busy");
+ statusField.addItem("Left the building");
+ statusField.setCaption("Status");
+ statusField.setWidth("100%");
+ formLayout.addComponent(statusField);
+
+ mainWindow.addComponent(formLayout);
+ }
+
+ @Override
+ protected String getDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html
new file mode 100644
index 0000000000..b2806afe5c
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html
@@ -0,0 +1,21 @@
+<?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>com.vaadin.tests.components.accordion.AccordionInactiveTabSize</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">com.vaadin.tests.components.accordion.AccordionInactiveTabSize</td></tr></thead><tbody><tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.customcomponent.CustomLayoutUsingTemplate?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>initial</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscustomcomponentCustomLayoutUsingTemplate::/VVerticalLayout[0]/VVerticalLayout[0]/VCustomLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>with-text-field</td>
+</tr>
+</tbody></table></body></html> \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html
new file mode 100644
index 0000000000..954afb2adb
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html
@@ -0,0 +1,31 @@
+<?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>com.vaadin.tests.components.accordion.AccordionInactiveTabSize</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">com.vaadin.tests.components.accordion.AccordionInactiveTabSize</td></tr></thead><tbody><tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.customcomponent.CustomLayoutUsingTheme?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>initial</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscustomcomponentCustomLayoutUsingTheme::/VVerticalLayout[0]/VVerticalLayout[0]/VCustomLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>label</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscustomcomponentCustomLayoutUsingTheme::/VVerticalLayout[0]/VVerticalLayout[0]/VCustomLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>button</td>
+</tr>
+</tbody></table></body></html> \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java
index e8df335c7d..6ea1d0a0c5 100644
--- a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java
+++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java
@@ -18,25 +18,26 @@ public class CustomLayoutUsingTheme extends TestBase implements ClickListener {
@Override
protected void setup() {
setTheme("tests-tickets");
- layout = new CustomLayout("Ticket1775.html");
+ layout = new CustomLayout("Ticket1775");
addComponent(layout);
layout.addComponent(new TextField("Username"), "loginUser");
layout.addComponent(new TextField("Password"), "loginPassword");
layout.addComponent(new Button("Login"), "loginButton");
+ layout.setWidth(null);
VerticalLayout menu = new VerticalLayout();
- menu.addComponent(new Button("Set main to label", new ClickListener() {
+ menu.addComponent(new Button("Set body to label", new ClickListener() {
public void buttonClick(ClickEvent event) {
- layout.addComponent(new Label(LoremIpsum.get(200)), "main");
+ layout.addComponent(new Label(LoremIpsum.get(200)), "body");
}
}));
- menu.addComponent(new Button("Set main to huge NativeButton",
+ menu.addComponent(new Button("Set body to huge NativeButton",
new ClickListener() {
public void buttonClick(ClickEvent event) {
layout.addComponent(new NativeButton(
- "This is it, the main!"), "main");
+ "This is it, the body!"), "body");
}
}));
layout.addComponent(menu, "menu");
diff --git a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java
index de08477dd3..b8c5be57bf 100644
--- a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java
+++ b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java
@@ -25,6 +25,10 @@ public class InlineDateFields extends ComponentTestCase<InlineDateField> {
@Override
protected void initializeComponents() {
+ InlineDateField hidden = new InlineDateField();
+ hidden.setVisible(false); // Used to break rest of layout #8693
+ addComponent(hidden);
+
Locale locale = LOCALES[0];
InlineDateField pd = createInlineDateField("Undefined width", "-1",
diff --git a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html
new file mode 100644
index 0000000000..6b79ef419b
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldsHiddenOnStart.html
@@ -0,0 +1,26 @@
+<?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.datefield.InlineDateFields?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFields::PID_SLocale-en_US-undefined-wide/VCalendarPanel[0]#header</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html
new file mode 100644
index 0000000000..080200092d
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html
@@ -0,0 +1,11 @@
+<?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>com.vaadin.tests.components.accordion.AccordionInactiveTabSize</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">com.vaadin.tests.components.accordion.AccordionInactiveTabSize</td></tr></thead><tbody><tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.label.MarginsInLabels?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td></td>
+</tr>
+</tbody></table></body></html> \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/gridlayout/MarginsInLabels.java b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.java
index 1cbed2a17d..699f94bb7e 100644
--- a/tests/testbench/com/vaadin/tests/components/gridlayout/MarginsInLabels.java
+++ b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.java
@@ -1,4 +1,4 @@
-package com.vaadin.tests.components.gridlayout;
+package com.vaadin.tests.components.label;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.tests.components.AbstractTestRoot;
diff --git a/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html
new file mode 100644
index 0000000000..8a1b21c35d
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.html
@@ -0,0 +1,47 @@
+<?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>NativeButtonHtml</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">NativeButtonHtml</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.nativebutton.NativeButtonHtml?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>initial</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VNativeButton[0]</td>
+ <td>116,9</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>after_1_click</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonHtml::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VNativeButton[0]</td>
+ <td>74,10</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>after_2_clicks</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java
new file mode 100644
index 0000000000..011439f810
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonHtml.java
@@ -0,0 +1,41 @@
+package com.vaadin.tests.components.nativebutton;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.NativeButton;
+
+public class NativeButtonHtml extends TestBase {
+
+ @Override
+ protected void setup() {
+ NativeButton b = new NativeButton("<b>Plain text button</b>");
+ addComponent(b);
+
+ b = new NativeButton(
+ "<span style=\"color: red; font-weight: bold;\">HTML</span> button");
+ b.setHtmlContentAllowed(true);
+ addComponent(b);
+
+ final NativeButton swapButton = new NativeButton("<i>Swap button<i>");
+ swapButton.addListener(new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ swapButton.setHtmlContentAllowed(!swapButton
+ .isHtmlContentAllowed());
+ }
+ });
+ addComponent(swapButton);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Verify that NativeButton HTML rendering works";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // 8663 was for normal button (see ButtonHtml test)
+ return null;
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html b/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html
index 1a91211040..93e5a802ee 100644
--- a/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html
+++ b/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html
@@ -28,7 +28,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentstableTableScrollOnFocus::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableScrollOnFocus::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td>
<td>391,141</td>
</tr>
<tr>
diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html
new file mode 100644
index 0000000000..5364b1cd1e
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.html
@@ -0,0 +1,97 @@
+<?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="http://arturwin.office.itmill.com:9999/" />
+<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.TableWithContainerRequiringEqualsForItemId?debug&amp;restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[0]</td>
+ <td>523,81</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td>
+ <td>1. Button Button999 clicked</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[14]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td>
+ <td>2. Button Button985 clicked</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>19,7</td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td>
+ <td>3. Button Button0 clicked</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>8,15</td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>999</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/FocusableScrollPanel[0]/VScrollTable$VScrollTableBody[0]/VScrollTable$VScrollTableBody$VScrollTableRow[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentstableTableWithContainerRequiringEqualsForItemId::PID_SLog_row_0</td>
+ <td>4. Button Button999 clicked</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java
new file mode 100644
index 0000000000..1b0335b673
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/table/TableWithContainerRequiringEqualsForItemId.java
@@ -0,0 +1,128 @@
+package com.vaadin.tests.components.table;
+
+import java.util.Date;
+
+import com.vaadin.data.util.BeanContainer;
+import com.vaadin.data.util.BeanItem;
+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.Component;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.themes.Reindeer;
+
+public class TableWithContainerRequiringEqualsForItemId extends TestBase {
+
+ private MyEntityContainer container = new MyEntityContainer();
+ private Log log = new Log(10);
+
+ public static class MyEntityContainer extends BeanContainer<Long, MyEntity> {
+
+ public MyEntityContainer() {
+ super(MyEntity.class);
+ setBeanIdResolver(new BeanIdResolver<Long, TableWithContainerRequiringEqualsForItemId.MyEntity>() {
+
+ public Long getIdForBean(MyEntity bean) {
+ // Return a new instance every time to ensure Table can
+ // handle it
+ return new Long(bean.getId());
+ }
+ });
+
+ }
+
+ @Override
+ public Long getIdByIndex(int index) {
+ // Explicitly get the id using the resolver to make sure the
+ // instance does not stay the same
+ BeanItem<MyEntity> beanItem = getItem(super.getIdByIndex(index));
+ return getBeanIdResolver().getIdForBean(beanItem.getBean());
+ };
+
+ }
+
+ @Override
+ protected void setup() {
+ Table t = new Table("Table with 1000 item");
+ t.addGeneratedColumn("Actions", new Table.ColumnGenerator() {
+ public Component generateCell(final Table source,
+ final Object itemId, final Object columnId) {
+ Button tripFolderLink = new Button("Button" + itemId);
+ tripFolderLink.addListener(new Button.ClickListener() {
+ public void buttonClick(final ClickEvent event) {
+ log.log("Button " + event.getButton().getCaption()
+ + " clicked");
+ }
+ });
+ tripFolderLink.setStyleName(Reindeer.BUTTON_SMALL);
+ return tripFolderLink;
+ }
+ });
+
+ for (int i = 0; i < 1000; i++) {
+ MyEntity myEntity = new MyEntity(i + "st");
+ myEntity.setCreated(new Date(new Date().getTime() - 24 * 60 * 60
+ * 1000L));
+ myEntity.setId(i);
+ container.addBean(myEntity);
+ // entityProvider.addEntity(myEntity);
+ }
+
+ t.setContainerDataSource(container);
+ t.setVisibleColumns(new String[] { "id", "created", "name", "Actions" });
+
+ addComponent(t);
+ addComponent(log);
+
+ t.sort(new Object[] { "id" }, new boolean[] { false });
+
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Test that verifies that Table works correctly with containers which do not return the same instance of the itemId object but instead requires an itemId.equals(otherItemId) check";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8712;
+ }
+
+ public static class MyEntity {
+
+ private long id;
+
+ private String name;
+
+ private Date created;
+
+ public MyEntity() {
+ }
+
+ public MyEntity(String string) {
+ name = string;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.html b/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.html
new file mode 100644
index 0000000000..ac06706aa5
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.html
@@ -0,0 +1,42 @@
+<?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>TestCurrentPageFirstItem</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">TestCurrentPageFirstItem</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/TestCurrentPageFirstItem?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runTestCurrentPageFirstItem::/VHorizontalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runTestCurrentPageFirstItem::/VHorizontalLayout[0]/ChildComponentContainer[5]/VButton[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runTestCurrentPageFirstItem::/VHorizontalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td></td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java b/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java
index 1748c27426..7fb096739a 100644
--- a/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java
+++ b/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java
@@ -1,60 +1,77 @@
package com.vaadin.tests.components.table;
-import com.vaadin.Application;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Root.LegacyWindow;
+import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
-public class TestCurrentPageFirstItem extends Application.LegacyApplication
- implements ClickListener {
+public class TestCurrentPageFirstItem extends TestBase implements ClickListener {
private Button buttonIndex;
private Button buttonItem;
- private Table table;
+ private Table[] tables = new Table[4];
private int counter = 0;
IndexedContainer container = new IndexedContainer();
@Override
- public void init() {
- try {
- LegacyWindow main = new LegacyWindow("Table header Test");
- setMainWindow(main);
- main.setSizeFull();
- // setTheme("testtheme");
- VerticalLayout baseLayout = new VerticalLayout();
- main.setContent(baseLayout);
-
- table = new Table();
- container.addContainerProperty("row", String.class, "");
- table.setContainerDataSource(container);
- table.setWidth("100%");
- table.setPageLength(3);
- buttonIndex = new Button("Add row and select last index", this);
- buttonItem = new Button("Add row and select last item", this);
-
- baseLayout.addComponent(table);
- baseLayout.addComponent(buttonIndex);
- baseLayout.addComponent(buttonItem);
- } catch (Exception e) {
- e.printStackTrace();
+ public void setup() {
+ container.addContainerProperty("row", String.class, "");
+
+ HorizontalLayout baseLayout = new HorizontalLayout();
+ baseLayout.setHeight("115px");
+ getMainWindow().setContent(baseLayout);
+
+ for (int i = 0; i < tables.length; ++i) {
+ Table t = new Table();
+ t.setContainerDataSource(container);
+ t.setWidth("100px");
+ baseLayout.addComponent(t);
+ tables[i] = t;
}
+ tables[0].setSizeFull();
+ tables[0].setCaption("Full");
+ tables[1].setHeight("100px");
+ tables[1].setCaption("100px");
+ tables[2].setHeight("95%");
+ tables[2].setCaption("95%");
+ tables[3].setPageLength(3);
+ tables[3].setCaption("3 rows");
+
+ buttonIndex = new Button("Add row and select last index", this);
+ buttonItem = new Button("Add row and select last item", this);
+ baseLayout.addComponent(buttonIndex);
+ baseLayout.addComponent(buttonItem);
}
public void buttonClick(ClickEvent event) {
Item item = container.addItem(++counter);
item.getItemProperty("row").setValue(counter + "");
- table.select(counter);
- if (event.getButton() == buttonIndex) {
- table.setCurrentPageFirstItemIndex(((Container.Indexed) table
- .getContainerDataSource()).indexOfId(counter));
- } else {
- table.setCurrentPageFirstItemId(counter);
+ for (int i = 0; i < tables.length; ++i) {
+ Table t = tables[i];
+ t.select(counter);
+ if (event.getButton() == buttonIndex) {
+ t.setCurrentPageFirstItemIndex(((Container.Indexed) t
+ .getContainerDataSource()).indexOfId(counter));
+ } else {
+ t.setCurrentPageFirstItemId(counter);
+ }
}
}
+
+ @Override
+ protected String getDescription() {
+ return "Table height changes when using setCurrentPageFirstItemId";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 2864;
+ }
}
diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.html b/tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.html
new file mode 100644
index 0000000000..f5579c9875
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.html
@@ -0,0 +1,32 @@
+<?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>ScrollbarsInNestedTabsheets</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">ScrollbarsInNestedTabsheets</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/ScrollbarsInNestedTabsheets?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runScrollbarsInNestedTabsheets::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VTabsheet[0]/VTabsheetPanel[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>27,8</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>should-not-have-scrollbars</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.java b/tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.java
new file mode 100644
index 0000000000..de250539ff
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/tabsheet/ScrollbarsInNestedTabsheets.java
@@ -0,0 +1,58 @@
+package com.vaadin.tests.components.tabsheet;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+@SuppressWarnings("serial")
+public class ScrollbarsInNestedTabsheets extends TestBase {
+
+ @Override
+ public void setup() {
+ setTheme("chameleon");
+ final Label l = new Label("Select Sub Tab 2");
+ final TabSheet t = new TabSheet();
+ final TabSheet t2 = getTabSheet();
+ t.addTab(t2, "Main Tab");
+ addComponent(l);
+ addComponent(t);
+ }
+
+ private TabSheet getTabSheet() {
+ final TabSheet t = new TabSheet();
+ t.addTab(getDummyLayout1(), "Sub Tab 1");
+ t.addTab(getDummyLayout2(), "Sub Tab 2");
+
+ return t;
+ }
+
+ private Layout getDummyLayout1() {
+ final VerticalLayout l = new VerticalLayout();
+ l.addComponent(new DateField("Date"));
+
+ return l;
+ }
+
+ private Layout getDummyLayout2() {
+ final VerticalLayout l = new VerticalLayout();
+ l.addComponent(new DateField("Date"));
+ l.addComponent(new TextField("TextField"));
+
+ return l;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Nested tabsheets show unwanted scrollbars with Chameleon theme when the inner tabsheet is resized";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8625;
+ }
+
+} \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java b/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java
index 4cd3854d6f..bcfbc7f55a 100644
--- a/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java
+++ b/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java
@@ -37,7 +37,7 @@ public class CloseSubWindow extends TestBase {
Button closeButton = new Button("Close");
closeButton.addListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
- window.close();
+ event.getButton().findAncestor(Window.class).close();
}
});
window.addComponent(closeButton);
diff --git a/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html
new file mode 100644
index 0000000000..03a4830584
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.html
@@ -0,0 +1,71 @@
+<?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="http://localhost:8888/" />
+<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.dd.NotPaintedAcceptSource?restartApplication</td>
+ <td></td>
+</tr>
+<!--Drag value 0 to target-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>50,9</td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>124,20</td>
+</tr>
+<!--Assert drag was successful-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>Source 1 value 0</td>
+</tr>
+<!--Swap source and verify it was properly painted-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/VVerticalLayout[0]/VHorizontalLayout[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>Source 2</td>
+</tr>
+<!--Drag value 0 from source 2 and verify-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>19,8</td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>139,18</td>
+</tr>
+<tr>
+ <td>contextmenu</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsddNotPaintedAcceptSource::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[0]</td>
+ <td>Source 2 value 0</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java
new file mode 100644
index 0000000000..74774f09ab
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/dd/NotPaintedAcceptSource.java
@@ -0,0 +1,91 @@
+package com.vaadin.tests.dd;
+
+import com.vaadin.data.Item;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.event.dd.acceptcriteria.SourceIs;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.Table.TableDragMode;
+import com.vaadin.ui.Table.TableTransferable;
+
+public class NotPaintedAcceptSource extends TestBase {
+
+ @Override
+ protected void setup() {
+ final Table source1 = createTable("Source 1");
+ final Table source2 = createTable("Source 2");
+ final Table target = createTable("Target");
+
+ source1.setDragMode(TableDragMode.ROW);
+ source2.setDragMode(TableDragMode.ROW);
+
+ target.setDropHandler(new DropHandler() {
+ public AcceptCriterion getAcceptCriterion() {
+ return new SourceIs(source1, source2);
+ }
+
+ public void drop(DragAndDropEvent event) {
+ TableTransferable transferable = (TableTransferable) event
+ .getTransferable();
+ Item item = transferable.getSourceComponent().getItem(
+ transferable.getItemId());
+ Object value = item.getItemProperty("value").getValue();
+ AbstractSelectTargetDetails targetDetails = (AbstractSelectTargetDetails) event
+ .getTargetDetails();
+ Object targetItemId = targetDetails.getItemIdOver();
+ Object addItemAfter = target.addItemAfter(targetItemId);
+ target.getItem(addItemAfter).getItemProperty("value")
+ .setValue(value);
+ transferable.getSourceComponent().removeItem(
+ transferable.getItemId());
+ }
+ });
+
+ final HorizontalLayout horizontalLayout = new HorizontalLayout();
+ horizontalLayout.setSpacing(true);
+ horizontalLayout.addComponent(source1);
+ horizontalLayout.addComponent(target);
+
+ addComponent(horizontalLayout);
+
+ addComponent(new Button("Swap sources", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (source1.getParent() != null) {
+ horizontalLayout.replaceComponent(source1, source2);
+ } else {
+ horizontalLayout.replaceComponent(source2, source1);
+ }
+ target.requestRepaint();
+ }
+ }));
+
+ }
+
+ private Table createTable(String caption) {
+ Table table = new Table(caption);
+ table.addContainerProperty("value", String.class, "");
+ for (int i = 0; i < 10; i++) {
+ table.addItem(new Object[] { caption + " value " + i },
+ Integer.valueOf(i));
+ }
+ table.setWidth("300px");
+ return table;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Including a component in an accept criterion when the actual component is not included in a layout and thus not painted should still allow painting the component properly when it is added to a layout.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(8730);
+ }
+
+}
diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html
index 4bc409b881..8408aba9fd 100644
--- a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html
+++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html
@@ -13,7 +13,7 @@
</thead><tbody>
<tr>
<td>open</td>
- <td>/run/com.vaadin.tests.layouts.layouttester.LayoutTesterApplication</td>
+ <td>/run/com.vaadin.tests.layouts.layouttester.LayoutTesterApplication?restartApplication</td>
<td></td>
</tr>
<tr>