summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--GWT development mode for vaadin.launch24
-rw-r--r--WebContent/VAADIN/themes/base/base.scss1
-rw-r--r--WebContent/VAADIN/themes/base/boxlayout/boxlayout.css167
-rw-r--r--WebContent/VAADIN/themes/base/boxlayout/boxlayout.scss171
-rw-r--r--WebContent/VAADIN/themes/base/button/button.scss9
-rw-r--r--WebContent/VAADIN/themes/base/csslayout/csslayout.scss4
-rw-r--r--WebContent/VAADIN/themes/base/datefield/datefield.scss4
-rw-r--r--WebContent/VAADIN/themes/base/label/label.scss4
-rw-r--r--WebContent/VAADIN/themes/base/menubar/menubar.scss4
-rw-r--r--WebContent/VAADIN/themes/base/paintable/paintable.scss5
-rw-r--r--WebContent/VAADIN/themes/base/styles.scss6
-rw-r--r--WebContent/VAADIN/themes/base/textfield/textfield.scss1
-rw-r--r--WebContent/VAADIN/themes/reindeer/common/common.scss2
-rw-r--r--WebContent/VAADIN/themes/reindeer/layouts/layouts.scss16
-rw-r--r--WebContent/VAADIN/themes/runo/orderedlayout/orderedlayout.scss16
-rw-r--r--WebContent/VAADIN/themes/tests-components/styles.css17
-rw-r--r--WebContent/layout-resize-test.html41
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java9
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ComputedStyle.java26
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/LayoutManager.java46
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ServerConnector.java22
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java4
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java16
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractBoxLayoutConnector.java598
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java19
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java5
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VBoxLayout.java757
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalBoxLayoutConnector.java19
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java5
-rw-r--r--shared/src/com/vaadin/shared/ComponentState.java20
-rw-r--r--tests/testbench/com/vaadin/tests/components/orderedlayout/BoxLayoutTest.java469
-rw-r--r--tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutRenderTimeTest.java58
-rw-r--r--tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutResizeTest.java13
-rw-r--r--tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java453
-rw-r--r--tests/testbench/com/vaadin/tests/components/orderedlayout/VaadinTunesLayout.java341
-rw-r--r--tests/testbench/com/vaadin/tests/components/table/TextFieldRelativeWidth.java3
-rw-r--r--tests/testbench/com/vaadin/tests/themes/LiferayThemeTest.java37
37 files changed, 3133 insertions, 279 deletions
diff --git a/GWT development mode for vaadin.launch b/GWT development mode for vaadin.launch
new file mode 100644
index 0000000000..5195348bf5
--- /dev/null
+++ b/GWT development mode for vaadin.launch
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/vaadin"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;/Users/jouni/.ivy2/cache/com.google.gwt/gwt-dev/jars/gwt-dev-2.4.0.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry externalArchive=&quot;/Users/jouni/.ivy2/cache/com.google.gwt/gwt-user/jars/gwt-user-2.4.0.jar&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10;&lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;vaadin&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/tests/testbench&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/tests/client-side&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/tests/server-side&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noserver -war WebContent/VAADIN/widgetsets com.vaadin.terminal.gwt.DefaultWidgetSet -startupUrl http://localhost:8080/vaadin -bindAddress 0.0.0.0"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="vaadin"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512M -XX:MaxPermSize=256M"/>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="/Users/jouni/Documents/Work/Dev/Vaadin/vaadin"/>
+</launchConfiguration>
diff --git a/WebContent/VAADIN/themes/base/base.scss b/WebContent/VAADIN/themes/base/base.scss
index 58f0c32af7..efe6e0cd05 100644
--- a/WebContent/VAADIN/themes/base/base.scss
+++ b/WebContent/VAADIN/themes/base/base.scss
@@ -1,6 +1,7 @@
@import "absolutelayout/absolutelayout.scss";
@import "accordion/accordion.scss";
@import "button/button.scss";
+@import "boxlayout/boxlayout.scss";
@import "caption/caption.scss";
@import "common/common.scss";
@import "csslayout/csslayout.scss";
diff --git a/WebContent/VAADIN/themes/base/boxlayout/boxlayout.css b/WebContent/VAADIN/themes/base/boxlayout/boxlayout.css
new file mode 100644
index 0000000000..f899e8f4ac
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/boxlayout/boxlayout.css
@@ -0,0 +1,167 @@
+/*
+TODO
+- separate styles to proper places
+- decide a good class name structure for core layouts (e.g. 'v-layout', 'v-vertical', 'v-grid' etc.)
+- use !important in carefully selected places to prevent accidental layout breakage by custom theming (e.g. alignments should be forced)
+
+*/
+
+.v-boxlayout.v-margin-top {padding-top: 12px;}
+.v-boxlayout.v-margin-right {padding-right: 12px;}
+.v-boxlayout.v-margin-bottom {padding-bottom: 12px;}
+.v-boxlayout.v-margin-left {padding-left: 12px;}
+
+.v-spacing {
+ width: 6px;
+ height: 6px;
+}
+
+.v-boxlayout {
+ display: inline-block;
+}
+
+div.v-boxlayout.v-horizontal.v {
+ white-space: nowrap;
+}
+
+.v-boxlayout > .v-expand {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+}
+
+.v-slot,
+.v-spacing {
+ display: inline-block;
+ white-space: normal;
+ vertical-align: top;
+}
+
+/* Clear any floats inside the slot, to prevent unwanted collapsing */
+.v-vertical > .v-slot:after {
+ content: "";
+ display: inline-block;
+ clear: both;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.v-vertical > .v-slot,
+.v-vertical > .v-expand > .v-slot {
+ display: block;
+ clear: both;
+}
+
+.v-horizontal > .v-slot,
+.v-horizontal > .v-expand > .v-slot {
+ height: 100%;
+}
+
+.v-vertical > .v-spacing,
+.v-vertical > .v-expand > .v-spacing {
+ width: 0;
+ display: block;
+ clear: both;
+}
+
+.v-horizontal > .v-spacing,
+.v-horizontal > .v-expand > .v-spacing {
+ height: 0;
+}
+
+.v-align-middle:before,
+.v-align-bottom:before,
+.v-expand > .v-align-middle:before,
+.v-expand > .v-align-bottom:before {
+ content: "";
+ display: inline-block;
+ height: 100%;
+ vertical-align: middle;
+ width: 0;
+}
+
+.v-align-middle,
+.v-align-bottom {
+ white-space: nowrap;
+}
+
+.v-align-middle > .v,
+.v-align-bottom > .v {
+ display: inline-block;
+}
+
+.v-align-middle,
+.v-align-middle > .v {
+ vertical-align: middle;
+}
+
+.v-align-bottom,
+.v-align-bottom > .v {
+ vertical-align: bottom;
+}
+
+.v-align-center {
+ text-align: center;
+}
+
+.v-align-center > .v {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.v-align-right {
+ text-align: right;
+}
+
+.v-align-right > .v {
+ margin-left: auto;
+}
+
+.v-has-caption,
+.v-has-caption > .v-caption {
+ display: inline-block; /* Force natural width to zero */
+}
+
+.v-caption {
+ overflow: visible;
+ vertical-align: middle;
+}
+
+.v-caption-on-left,
+.v-caption-on-right {
+ white-space: nowrap;
+}
+
+.v-caption-on-top > .v-caption,
+.v-caption-on-bottom > .v-caption {
+ display: block;
+}
+
+.v-caption-on-left > .v-caption {
+ padding-right: .5em;
+}
+
+.v-caption-on-right > .v-caption {
+ padding-left: .5em;
+}
+
+.v-caption-on-left > .v,
+.v-caption-on-right > .v {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+.v-has-caption.v-has-width > .v {
+ width: 100% !important;
+}
+
+.v-has-caption.v-has-height > .v {
+ height: 100% !important;
+}
+
+.v-errorindicator {
+ vertical-align: middle;
+} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/boxlayout/boxlayout.scss b/WebContent/VAADIN/themes/base/boxlayout/boxlayout.scss
new file mode 100644
index 0000000000..ef0f021a0a
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/boxlayout/boxlayout.scss
@@ -0,0 +1,171 @@
+/*
+TODO
+- separate styles to proper places
+- decide a good class name structure for core layouts (e.g. 'v-layout', 'v-vertical', 'v-grid' etc.)
+- use !important in carefully selected places to prevent accidental layout breakage by custom theming (e.g. alignments should be forced)
+
+*/
+
+@mixin base-boxlayout {
+
+.v-boxlayout.v-margin-top {padding-top: 12px;}
+.v-boxlayout.v-margin-right {padding-right: 12px;}
+.v-boxlayout.v-margin-bottom {padding-bottom: 12px;}
+.v-boxlayout.v-margin-left {padding-left: 12px;}
+
+.v-spacing {
+ width: 6px;
+ height: 6px;
+}
+
+.v-boxlayout {
+ display: inline-block;
+}
+
+div.v-boxlayout.v-horizontal.v {
+ white-space: nowrap;
+}
+
+.v-boxlayout > .v-expand {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ height: 100%;
+}
+
+.v-slot,
+.v-spacing {
+ display: inline-block;
+ white-space: normal;
+ vertical-align: top;
+}
+
+/* Clear any floats inside the slot, to prevent unwanted collapsing */
+.v-vertical > .v-slot:after {
+ content: "";
+ display: inline-block;
+ clear: both;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.v-vertical > .v-slot,
+.v-vertical > .v-expand > .v-slot {
+ display: block;
+ clear: both;
+}
+
+.v-horizontal > .v-slot,
+.v-horizontal > .v-expand > .v-slot {
+ height: 100%;
+}
+
+.v-vertical > .v-spacing,
+.v-vertical > .v-expand > .v-spacing {
+ width: 0;
+ display: block;
+ clear: both;
+}
+
+.v-horizontal > .v-spacing,
+.v-horizontal > .v-expand > .v-spacing {
+ height: 0;
+}
+
+.v-align-middle:before,
+.v-align-bottom:before,
+.v-expand > .v-align-middle:before,
+.v-expand > .v-align-bottom:before {
+ content: "";
+ display: inline-block;
+ height: 100%;
+ vertical-align: middle;
+ width: 0;
+}
+
+.v-align-middle,
+.v-align-bottom {
+ white-space: nowrap;
+}
+
+.v-align-middle > .v,
+.v-align-bottom > .v {
+ display: inline-block;
+}
+
+.v-align-middle,
+.v-align-middle > .v {
+ vertical-align: middle;
+}
+
+.v-align-bottom,
+.v-align-bottom > .v {
+ vertical-align: bottom;
+}
+
+.v-align-center {
+ text-align: center;
+}
+
+.v-align-center > .v {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.v-align-right {
+ text-align: right;
+}
+
+.v-align-right > .v {
+ margin-left: auto;
+}
+
+.v-has-caption,
+.v-has-caption > .v-caption {
+ display: inline-block; /* Force natural width to zero */
+}
+
+.v-caption {
+ overflow: visible;
+ vertical-align: middle;
+}
+
+.v-caption-on-left,
+.v-caption-on-right {
+ white-space: nowrap;
+}
+
+.v-caption-on-top > .v-caption,
+.v-caption-on-bottom > .v-caption {
+ display: block;
+}
+
+.v-caption-on-left > .v-caption {
+ padding-right: .5em;
+}
+
+.v-caption-on-right > .v-caption {
+ padding-left: .5em;
+}
+
+.v-caption-on-left > .v,
+.v-caption-on-right > .v {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+.v-has-caption.v-has-width > .v {
+ width: 100% !important;
+}
+
+.v-has-caption.v-has-height > .v {
+ height: 100% !important;
+}
+
+.v-errorindicator {
+ vertical-align: middle;
+}
+
+} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/button/button.scss b/WebContent/VAADIN/themes/base/button/button.scss
index 1d3c4abec1..a9e7867268 100644
--- a/WebContent/VAADIN/themes/base/button/button.scss
+++ b/WebContent/VAADIN/themes/base/button/button.scss
@@ -6,7 +6,7 @@
.v-button {
display: inline-block;
zoom: 1;
- text-align: center;
+ text-align: center !important;
text-decoration: none;
border: 2px outset #ddd;
background: #eee;
@@ -23,7 +23,6 @@
user-select: none;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
box-sizing: border-box;
}
@@ -59,7 +58,7 @@
.v-button-link,
.v-nativebutton-link {
border: none;
- text-align: left;
+ text-align: left !important;
background: transparent;
padding: 0;
color: inherit;
@@ -86,7 +85,7 @@
* NativeButton styles (html button element)
* -------------------------------------- */
.v-nativebutton {
- text-align: center;
+ text-align: center !important;
cursor: pointer;
white-space: nowrap;
margin: 0;
@@ -160,4 +159,4 @@
}
*/
-} \ No newline at end of file
+}
diff --git a/WebContent/VAADIN/themes/base/csslayout/csslayout.scss b/WebContent/VAADIN/themes/base/csslayout/csslayout.scss
index 7bd26d4197..c2c1b698ad 100644
--- a/WebContent/VAADIN/themes/base/csslayout/csslayout.scss
+++ b/WebContent/VAADIN/themes/base/csslayout/csslayout.scss
@@ -3,6 +3,10 @@
.v-csslayout {
overflow: hidden;
}
+/* More specific selector to override 'v-connector' */
+div.v-csslayout {
+ display: block;
+}
.v-csslayout-margin, .v-csslayout-container {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
diff --git a/WebContent/VAADIN/themes/base/datefield/datefield.scss b/WebContent/VAADIN/themes/base/datefield/datefield.scss
index 12ce3df980..bf95baa3e6 100644
--- a/WebContent/VAADIN/themes/base/datefield/datefield.scss
+++ b/WebContent/VAADIN/themes/base/datefield/datefield.scss
@@ -2,7 +2,7 @@
.v-datefield {
white-space: nowrap;
- float: left; /* Force minimum width */
+ display: inline-block; /* Force minimum width */
}
.v-datefield-textfield {
vertical-align: top;
@@ -90,4 +90,4 @@
}
*/
-} \ No newline at end of file
+}
diff --git a/WebContent/VAADIN/themes/base/label/label.scss b/WebContent/VAADIN/themes/base/label/label.scss
index e4f3f89062..ae1539acc9 100644
--- a/WebContent/VAADIN/themes/base/label/label.scss
+++ b/WebContent/VAADIN/themes/base/label/label.scss
@@ -4,4 +4,8 @@
overflow: hidden;
}
+.v-label.v-has-width {
+ white-space: normal;
+}
+
} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/menubar/menubar.scss b/WebContent/VAADIN/themes/base/menubar/menubar.scss
index 79b94a63af..512a8ee1d5 100644
--- a/WebContent/VAADIN/themes/base/menubar/menubar.scss
+++ b/WebContent/VAADIN/themes/base/menubar/menubar.scss
@@ -1,7 +1,7 @@
@mixin base-menubar {
.v-menubar {
- float: left; /* Force minimum width */
+ display: inline-block;
white-space: nowrap;
overflow: hidden;
}
@@ -95,4 +95,4 @@
background: transparent url(img/check.gif) no-repeat left;
}
-} \ No newline at end of file
+}
diff --git a/WebContent/VAADIN/themes/base/paintable/paintable.scss b/WebContent/VAADIN/themes/base/paintable/paintable.scss
index 87431ee225..92f30604ff 100644
--- a/WebContent/VAADIN/themes/base/paintable/paintable.scss
+++ b/WebContent/VAADIN/themes/base/paintable/paintable.scss
@@ -1,9 +1,12 @@
@mixin base-paintable {
-.v-connector {
+.v {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
+ text-align: left;
+ display: inline-block;
+ white-space: normal;
}
} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/styles.scss b/WebContent/VAADIN/themes/base/styles.scss
index 89f76947f8..7a650d0818 100644
--- a/WebContent/VAADIN/themes/base/styles.scss
+++ b/WebContent/VAADIN/themes/base/styles.scss
@@ -3,7 +3,9 @@
// @include base-app;
// everything included from base theme
-// other themes should enclose corresponding definitions in theme selectors
+// other themes should enclose corresponding definitions in theme selectors
+
+@include base-paintable;
@include base-absolutelayout;
@include base-accordion;
@@ -13,6 +15,7 @@
// here for now to preserve old semantics
@include base-common;
+@include base-boxlayout;
@include base-csslayout;
@include base-customcomponent;
@include base-customlayout;
@@ -27,7 +30,6 @@
@include base-menubar;
@include base-notification;
@include base-orderedlayout;
-@include base-paintable;
@include base-panel;
@include base-popupview;
@include base-progressindicator;
diff --git a/WebContent/VAADIN/themes/base/textfield/textfield.scss b/WebContent/VAADIN/themes/base/textfield/textfield.scss
index b8e54e6887..dc6a4d9aa3 100644
--- a/WebContent/VAADIN/themes/base/textfield/textfield.scss
+++ b/WebContent/VAADIN/themes/base/textfield/textfield.scss
@@ -7,6 +7,7 @@
}
.v-textarea {
resize: none;
+ white-space: pre-wrap;
}
.v-textfield-focus,
.v-textarea-focus {
diff --git a/WebContent/VAADIN/themes/reindeer/common/common.scss b/WebContent/VAADIN/themes/reindeer/common/common.scss
index 86f546a6a2..3971f1777d 100644
--- a/WebContent/VAADIN/themes/reindeer/common/common.scss
+++ b/WebContent/VAADIN/themes/reindeer/common/common.scss
@@ -43,7 +43,7 @@
}
.v-errorindicator {
width: 13px;
- height: 16px;
+ height: 14px;
background: transparent url(../common/icons/error.png) no-repeat 50%;
}
.v-tooltip {
diff --git a/WebContent/VAADIN/themes/reindeer/layouts/layouts.scss b/WebContent/VAADIN/themes/reindeer/layouts/layouts.scss
index 832e480010..e1bef65f1e 100644
--- a/WebContent/VAADIN/themes/reindeer/layouts/layouts.scss
+++ b/WebContent/VAADIN/themes/reindeer/layouts/layouts.scss
@@ -2,22 +2,26 @@
.v-orderedlayout-margin-top,
.v-horizontallayout-margin-top,
-.v-verticallayout-margin-top {
+.v-verticallayout-margin-top,
+.v-boxlayout.v-margin-top {
padding-top: 18px;
}
.v-orderedlayout-margin-right,
.v-horizontallayout-margin-right,
-.v-verticallayout-margin-right {
+.v-verticallayout-margin-right,
+.v-boxlayout.v-margin-right {
padding-right: 18px;
}
.v-orderedlayout-margin-bottom,
.v-horizontallayout-margin-bottom,
-.v-verticallayout-margin-bottom {
+.v-verticallayout-margin-bottom,
+.v-boxlayout.v-margin-bottom {
padding-bottom: 18px;
}
.v-orderedlayout-margin-left,
.v-horizontallayout-margin-left,
-.v-verticallayout-margin-left {
+.v-verticallayout-margin-left,
+.v-boxlayout.v-margin-left {
padding-left: 18px;
}
.v-orderedlayout-spacing-on,
@@ -26,6 +30,10 @@
padding-top: 7px;
padding-left: 6px;
}
+.v-spacing {
+ height: 7px;
+ width: 6px;
+}
/* Different for historical reasons: previously was inherited directly from Base theme */
/* TODO unify these values in version 7 */
.v-gridlayout-margin-top {
diff --git a/WebContent/VAADIN/themes/runo/orderedlayout/orderedlayout.scss b/WebContent/VAADIN/themes/runo/orderedlayout/orderedlayout.scss
index a8c85d9af6..37ae0279b6 100644
--- a/WebContent/VAADIN/themes/runo/orderedlayout/orderedlayout.scss
+++ b/WebContent/VAADIN/themes/runo/orderedlayout/orderedlayout.scss
@@ -3,25 +3,29 @@
.v-orderedlayout-margin-top,
.v-horizontallayout-margin-top,
.v-verticallayout-margin-top,
-.v-csslayout-margin-top {
+.v-csslayout-margin-top,
+.v-boxlayout.v-margin-top {
padding-top: 15px;
}
.v-orderedlayout-margin-right,
.v-horizontallayout-margin-right,
.v-verticallayout-margin-right,
-.v-csslayout-margin-right {
+.v-csslayout-margin-right,
+.v-boxlayout.v-margin-right {
padding-right: 18px;
}
.v-orderedlayout-margin-bottom,
.v-horizontallayout-margin-bottom,
.v-verticallayout-margin-bottom,
-.v-csslayout-margin-bottom {
+.v-csslayout-margin-bottom,
+.v-boxlayout.v-margin-bottom {
padding-bottom: 15px;
}
.v-orderedlayout-margin-left,
.v-horizontallayout-margin-left,
.v-verticallayout-margin-left,
-.v-csslayout-margin-left {
+.v-csslayout-margin-left,
+.v-boxlayout.v-margin-left {
padding-left: 18px;
}
.v-orderedlayout-spacing-on,
@@ -30,6 +34,10 @@
padding-top: 8px;
padding-left: 8px;
}
+.v-spacing {
+ width: 8px;
+ height: 8px;
+}
.v-verticallayout-darker,
.v-horizontallayout-darker,
.v-gridlayout-darker,
diff --git a/WebContent/VAADIN/themes/tests-components/styles.css b/WebContent/VAADIN/themes/tests-components/styles.css
index c38f32f132..45a96b6d16 100644
--- a/WebContent/VAADIN/themes/tests-components/styles.css
+++ b/WebContent/VAADIN/themes/tests-components/styles.css
@@ -36,4 +36,21 @@
.v-table-row-tables-test-cell-style-red-row,
.v-table-cell-content-tables-test-cell-style-red-row {
background: #f00;
+}
+
+.v-boxlayout.test {
+ border: 1px solid #ddd;
+}
+
+.v-boxlayout.test .target {
+ outline: 2px dashed blue;
+}
+
+.fieldset {
+ padding: .5em 1em;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.2);
+ -moz-box-shadow: inset 0 1px 2px rgba(0,0,0,.2);
+ box-shadow: inset 0 1px 2px rgba(0,0,0,.2);
+ border-radius: .5em;
+ background: rgba(0,0,0,.02);
} \ No newline at end of file
diff --git a/WebContent/layout-resize-test.html b/WebContent/layout-resize-test.html
new file mode 100644
index 0000000000..b798402bb7
--- /dev/null
+++ b/WebContent/layout-resize-test.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>LayoutResizeTest opener</title>
+</head>
+<body>
+
+<button onclick="testV7()">Open LayoutResizeTest (Vaadin 7)</button><br>
+<button onclick="testV6()">Open LayoutResizeTest (Vaadin 6)</button><br>
+<button onclick="resize1()">Resize to 650x450</button><br>
+<button onclick="resize2()">Resize to 950x750</button>
+
+
+<script>
+var win1, win2;
+
+function testV7() {
+ win1 = window.open('/vaadin/run/com.vaadin.tests.components.orderedlayout.LayoutResizeTest?restartApplication&debug','layoutResizeTestV7','width=800,height=600');
+}
+
+function testV6() {
+ win2 = window.open('/LayoutBenchmark/?restartApplication&debug','layoutResizeTestV6','width=800,height=600');
+}
+
+function resize1() {
+ if(win1)
+ win1.resizeTo(650,450);
+ if(win2)
+ win2.resizeTo(650,450);
+}
+
+function resize2() {
+ if(win1)
+ win1.resizeTo(950,750);
+ if(win2)
+ win2.resizeTo(950,750);
+}
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java b/client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
index f1a2b9b925..7c75913126 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ComponentLocator.java
@@ -30,6 +30,7 @@ import com.vaadin.shared.communication.SharedState;
import com.vaadin.terminal.gwt.client.ui.SubPartAware;
import com.vaadin.terminal.gwt.client.ui.UI.VUI;
import com.vaadin.terminal.gwt.client.ui.gridlayout.VGridLayout;
+import com.vaadin.terminal.gwt.client.ui.orderedlayout.VBoxLayout;
import com.vaadin.terminal.gwt.client.ui.orderedlayout.VMeasuringOrderedLayout;
import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheetPanel;
import com.vaadin.terminal.gwt.client.ui.window.VWindow;
@@ -498,6 +499,14 @@ public class ComponentLocator {
// is always 0 which indicates the widget in the active tab
widgetPosition = 0;
}
+ if ("VVerticalLayout".equals(widgetClassName)
+ || "VHorizontalLayout".equals(widgetClassName)) {
+ widgetClassName = "VBoxLayout";
+ }
+ if (w instanceof VBoxLayout
+ && "ChildComponentContainer".equals(widgetClassName)) {
+ widgetClassName = "VBoxLayout$Slot";
+ }
/*
* The new grid and ordered layotus do not contain
diff --git a/client/src/com/vaadin/terminal/gwt/client/ComputedStyle.java b/client/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
index 7662ba634b..6e17dcfab5 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ComputedStyle.java
@@ -95,19 +95,19 @@ public class ComputedStyle {
// If we're not dealing with a regular pixel number
// but a number that has a weird ending, we need to convert it to pixels
- if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
- // Remember the original values
- var left = style.left, rsLeft = elem.runtimeStyle.left;
-
- // Put in the new values to get a computed value out
- elem.runtimeStyle.left = cs.left;
- style.left = ret || 0;
- ret = style.pixelLeft + "px";
-
- // Revert the changed values
- style.left = left;
- elem.runtimeStyle.left = rsLeft;
- }
+ if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+ // Remember the original values
+ var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = cs.left;
+ style.left = ret || 0;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+ }
}
diff --git a/client/src/com/vaadin/terminal/gwt/client/LayoutManager.java b/client/src/com/vaadin/terminal/gwt/client/LayoutManager.java
index c00f9bd865..3deb581848 100644
--- a/client/src/com/vaadin/terminal/gwt/client/LayoutManager.java
+++ b/client/src/com/vaadin/terminal/gwt/client/LayoutManager.java
@@ -215,7 +215,7 @@ public class LayoutManager {
}
}
- private void layoutLater() {
+ public void layoutLater() {
if (!layoutPending) {
layoutPending = true;
layoutTimer.schedule(100);
@@ -1032,6 +1032,50 @@ public class LayoutManager {
}
/**
+ * Gets the combined top & bottom margin of the given element, provided that
+ * they have 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 margin for
+ * @return the measured top+bottom margin of the element in pixels.
+ */
+ public int getMarginHeight(Element element) {
+ return getMarginTop(element) + getMarginBottom(element);
+ }
+
+ /**
+ * Gets the combined left & right margin of the given element, provided that
+ * they have 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 margin for
+ * @return the measured left+right margin of the element in pixels.
+ */
+ public int getMarginWidth(Element element) {
+ return getMarginLeft(element) + getMarginRight(element);
+ }
+
+ /**
* 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
diff --git a/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java b/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
index d988c5f4a2..891e45edb5 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ServerConnector.java
@@ -87,6 +87,15 @@ public interface ServerConnector extends Connector {
public HandlerRegistration addStateChangeHandler(StateChangeHandler handler);
/**
+ * Removes a handler that is called whenever any part of the state has been
+ * updated by the server.
+ *
+ * @param handler
+ * The handler that should be removed.
+ */
+ public void removeStateChangeHandler(StateChangeHandler handler);
+
+ /**
* Adds a handler that is called whenever the given part of the state has
* been updated by the server.
*
@@ -102,6 +111,19 @@ public interface ServerConnector extends Connector {
StateChangeHandler handler);
/**
+ * Removes a handler that is called whenever any part of the state has been
+ * updated by the server.
+ *
+ * @param propertyName
+ * the name of the property for which the handler should be
+ * called
+ * @param handler
+ * The handler that should be removed.
+ */
+ public void removeStateChangeHandler(String propertyName,
+ StateChangeHandler handler);
+
+ /**
* Sends the given event to all registered handlers.
*
* @param event
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
index f36107e947..14d7f4007e 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
@@ -69,8 +69,8 @@ public abstract class AbstractComponentConnector extends AbstractConnector
getConnection().getVTooltip().connectHandlersToWidget(getWidget());
- // Set v-connector style names for the widget
- getWidget().setStyleName("v-connector", true);
+ // Set the core 'v' style name for the widget
+ getWidget().setStyleName("v", true);
}
/**
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
index b861ade0bf..fabd750f8b 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright 2011 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
@@ -45,7 +45,7 @@ import com.vaadin.terminal.gwt.client.metadata.TypeData;
*
*/
public abstract class AbstractConnector implements ServerConnector,
- StateChangeHandler {
+StateChangeHandler {
private ApplicationConnection connection;
private String id;
@@ -200,12 +200,24 @@ public abstract class AbstractConnector implements ServerConnector,
}
@Override
+ public void removeStateChangeHandler(StateChangeHandler handler) {
+ ensureHandlerManager().removeHandler(StateChangeEvent.TYPE, handler);
+ }
+
+ @Override
public HandlerRegistration addStateChangeHandler(String propertyName,
StateChangeHandler handler) {
return ensureHandlerManager(propertyName).addHandler(
StateChangeEvent.TYPE, handler);
}
+ @Override
+ public void removeStateChangeHandler(String propertyName,
+ StateChangeHandler handler) {
+ ensureHandlerManager(propertyName).removeHandler(StateChangeEvent.TYPE,
+ handler);
+ }
+
private HandlerManager ensureHandlerManager(String propertyName) {
if (statePropertyHandlerManagers == null) {
statePropertyHandlerManagers = new HashMap<String, HandlerManager>();
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractBoxLayoutConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractBoxLayoutConnector.java
new file mode 100644
index 0000000000..bbf9aed570
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractBoxLayoutConnector.java
@@ -0,0 +1,598 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui.orderedlayout;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.Element;
+import com.vaadin.shared.AbstractFieldState;
+import com.vaadin.shared.ui.AlignmentInfo;
+import com.vaadin.shared.ui.LayoutClickRpc;
+import com.vaadin.shared.ui.VMarginInfo;
+import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc;
+import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState;
+import com.vaadin.terminal.gwt.client.ComponentConnector;
+import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.communication.RpcProxy;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector;
+import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector;
+import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler;
+import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeEvent;
+import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeListener;
+import com.vaadin.terminal.gwt.client.ui.orderedlayout.VBoxLayout.CaptionPosition;
+import com.vaadin.terminal.gwt.client.ui.orderedlayout.VBoxLayout.Slot;
+
+public abstract class AbstractBoxLayoutConnector extends
+ AbstractLayoutConnector /* implements PostLayoutListener */{
+
+ AbstractOrderedLayoutServerRpc rpc;
+
+ private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler(
+ this) {
+
+ @Override
+ protected ComponentConnector getChildComponent(Element element) {
+ return Util.getConnectorForElement(getConnection(), getWidget(),
+ element);
+ }
+
+ @Override
+ protected LayoutClickRpc getLayoutClickRPC() {
+ return rpc;
+ };
+
+ };
+
+ @Override
+ public void init() {
+ super.init();
+ rpc = RpcProxy.create(AbstractOrderedLayoutServerRpc.class, this);
+ getWidget().setLayoutManager(getLayoutManager());
+ }
+
+ @Override
+ public AbstractOrderedLayoutState getState() {
+ return (AbstractOrderedLayoutState) super.getState();
+ }
+
+ @Override
+ public VBoxLayout getWidget() {
+ return (VBoxLayout) super.getWidget();
+ }
+
+ /**
+ * For bookkeeping. Used to determine if extra calculations are needed for
+ * horizontal layout.
+ */
+ private HashSet<ComponentConnector> hasVerticalAlignment = new HashSet<ComponentConnector>();
+
+ /**
+ * For bookkeeping. Used to determine if extra calculations are needed for
+ * horizontal layout.
+ */
+ private HashSet<ComponentConnector> hasRelativeHeight = new HashSet<ComponentConnector>();
+
+ /**
+ * For bookkeeping. Used to determine if extra calculations are needed for
+ * horizontal layout.
+ */
+ private HashSet<ComponentConnector> hasExpandRatio = new HashSet<ComponentConnector>();
+
+ /**
+ * For bookkeeping. Used in extra calculations for horizontal layout.
+ */
+ private HashSet<Element> needsMeasure = new HashSet<Element>();
+
+ /**
+ * For bookkeeping. Used in extra calculations for horizontal layout.
+ */
+ // private HashMap<Element, Integer> childElementHeight = new
+ // HashMap<Element, Integer>();
+
+ /**
+ * For bookkeeping. Used in extra calculations for horizontal layout.
+ */
+ private HashMap<Element, Integer> childCaptionElementHeight = new HashMap<Element, Integer>();
+
+ public void updateCaption(ComponentConnector child) {
+ Slot slot = getWidget().getSlot(child);
+
+ String caption = child.getState().getCaption();
+ String iconUrl = child.getState().getIcon() != null ? child.getState()
+ .getIcon().getURL() : null;
+ List<String> styles = child.getState().getStyles();
+ String error = child.getState().getErrorMessage();
+ boolean showError = error != null;
+ if (child.getState() instanceof AbstractFieldState) {
+ AbstractFieldState abstractFieldState = (AbstractFieldState) child
+ .getState();
+ showError = showError && !abstractFieldState.isHideErrors();
+ }
+ boolean required = false;
+ if (child instanceof AbstractFieldConnector) {
+ required = ((AbstractFieldConnector) child).isRequired();
+ }
+ boolean enabled = child.getState().isEnabled();
+
+ slot.setCaption(caption, iconUrl, styles, error, showError, required,
+ enabled);
+
+ slot.setRelativeWidth(child.isRelativeWidth());
+ slot.setRelativeHeight(child.isRelativeHeight());
+
+ if (slot.hasCaption()) {
+ CaptionPosition pos = slot.getCaptionPosition();
+ getLayoutManager().addElementResizeListener(
+ slot.getCaptionElement(), slotCaptionResizeListener);
+ if (child.isRelativeHeight()
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ getWidget().updateCaptionOffset(slot.getCaptionElement());
+ } else if (child.isRelativeWidth()
+ && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
+ getWidget().updateCaptionOffset(slot.getCaptionElement());
+ }
+ } else {
+ childCaptionElementHeight.remove(child.getWidget().getElement());
+ }
+
+ updateLayoutHeight();
+
+ if (needsExpand()) {
+ updateExpand();
+ }
+ }
+
+ @Override
+ public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
+ super.onConnectorHierarchyChange(event);
+
+ List<ComponentConnector> previousChildren = event.getOldChildren();
+ int currentIndex = 0;
+ VBoxLayout layout = getWidget();
+
+ for (ComponentConnector child : getChildComponents()) {
+ Slot slot = layout.getSlot(child);
+ if (slot.getParent() != layout) {
+ child.addStateChangeHandler(childStateChangeHandler);
+ }
+ layout.addOrMoveSlot(slot, currentIndex++);
+ }
+
+ for (ComponentConnector child : previousChildren) {
+ if (child.getParent() != this) {
+ Slot slot = layout.getSlot(child);
+ hasVerticalAlignment.remove(child);
+ hasRelativeHeight.remove(child);
+ hasExpandRatio.remove(child);
+ needsMeasure.remove(child.getWidget().getElement());
+ // childElementHeight.remove(child.getWidget().getElement());
+ childCaptionElementHeight
+ .remove(child.getWidget().getElement());
+ getLayoutManager().removeElementResizeListener(
+ child.getWidget().getElement(),
+ childComponentResizeListener);
+ if (slot.hasCaption()) {
+ getLayoutManager()
+ .removeElementResizeListener(
+ slot.getCaptionElement(),
+ slotCaptionResizeListener);
+ }
+ if (slot.getSpacingElement() != null) {
+ getLayoutManager().removeElementResizeListener(
+ slot.getSpacingElement(), spacingResizeListener);
+ }
+ child.removeStateChangeHandler(childStateChangeHandler);
+ layout.removeSlot(child.getWidget());
+ }
+ }
+
+ // If some component is added/removed, we need to recalculate the expand
+ if (needsExpand()) {
+ updateExpand();
+ } else {
+ getWidget().clearExpand();
+ }
+
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ clickEventHandler.handleEventHandlerRegistration();
+ getWidget().setMargin(new VMarginInfo(getState().getMarginsBitmask()));
+ getWidget().setSpacing(getState().isSpacing());
+
+ hasExpandRatio.clear();
+ hasVerticalAlignment.clear();
+ hasRelativeHeight.clear();
+ needsMeasure.clear();
+
+ boolean equalExpandRatio = getWidget().vertical ? !isUndefinedHeight()
+ : !isUndefinedWidth();
+ for (ComponentConnector child : getChildComponents()) {
+ double expandRatio = getState().getChildData().get(child)
+ .getExpandRatio();
+ if (expandRatio > 0) {
+ equalExpandRatio = false;
+ break;
+ }
+ }
+
+ for (ComponentConnector child : getChildComponents()) {
+ Slot slot = getWidget().getSlot(child);
+
+ AlignmentInfo alignment = new AlignmentInfo(getState()
+ .getChildData().get(child).getAlignmentBitmask());
+ slot.setAlignment(alignment);
+
+ double expandRatio = getState().getChildData().get(child)
+ .getExpandRatio();
+ if (equalExpandRatio) {
+ expandRatio = 1;
+ } else if (expandRatio == 0) {
+ expandRatio = -1;
+ }
+ slot.setExpandRatio(expandRatio);
+
+ // Bookkeeping to identify special cases that need extra
+ // calculations
+ if (alignment.isVerticalCenter() || alignment.isBottom()) {
+ hasVerticalAlignment.add(child);
+ }
+
+ if (expandRatio > 0) {
+ hasExpandRatio.add(child);
+ }
+
+ // if (child.getState().isRelativeHeight()) {
+ // hasRelativeHeight.add(child);
+ // } else {
+ // needsMeasure.add(child.getWidget().getElement());
+ // }
+ }
+
+ updateAllSlotListeners();
+
+ updateLayoutHeight();
+ }
+
+ StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+
+ ComponentConnector child = (ComponentConnector) stateChangeEvent
+ .getConnector();
+
+ // We need to update the slot size if the component size is changed
+ // to relative
+ Slot slot = getWidget().getSlot(child);
+ slot.setRelativeWidth(child.isRelativeWidth());
+ slot.setRelativeHeight(child.isRelativeHeight());
+
+ // For relative sized widgets, we need to set the caption offset
+ // if (slot.hasCaption()) {
+ // CaptionPosition pos = slot.getCaptionPosition();
+ // if (child.isRelativeHeight()
+ // && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM))
+ // {
+ // getWidget().updateCaptionOffset(slot.getCaptionElement());
+ // } else if (child.isRelativeWidth()
+ // && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT))
+ // {
+ // getWidget().updateCaptionOffset(slot.getCaptionElement());
+ // }
+ // }
+
+ updateSlotListeners(child);
+ // updateAllSlotListeners();
+
+ updateLayoutHeight();
+ }
+ };
+
+ private boolean needsFixedHeight() {
+ if (!getWidget().vertical
+ && isUndefinedHeight()
+ && (hasRelativeHeight.size() > 0 || (hasVerticalAlignment
+ .size() > 0 && hasVerticalAlignment.size() < getChildren()
+ .size()))) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean needsExpand() {
+ boolean canApplyExpand = (getWidget().vertical && !isUndefinedHeight())
+ || (!getWidget().vertical && !isUndefinedWidth());
+ return hasExpandRatio.size() > 0 && canApplyExpand;
+ }
+
+ private void updateAllSlotListeners() {
+ for (ComponentConnector child : getChildComponents()) {
+ updateSlotListeners(child);
+ }
+ // if (needsFixedHeight()) {
+ // getWidget().clearHeight();
+ // setLayoutHeightListener(true);
+ // getLayoutManager().setNeedsMeasure(AbstractBoxLayoutConnector.this);
+ // } else {
+ // setLayoutHeightListener(false);
+ // }
+ }
+
+ /**
+ * Add/remove necessary ElementResizeListeners for one slot. This should be
+ * called after each update to the slot's or it's widget.
+ */
+ private void updateSlotListeners(ComponentConnector child) {
+ Slot slot = getWidget().getSlot(child);
+
+ // Clear all possible listeners first
+ dontListen(slot.getWidget().getElement(), childComponentResizeListener);
+ if (slot.hasCaption()) {
+ dontListen(slot.getCaptionElement(), slotCaptionResizeListener);
+ }
+ if (slot.hasSpacing()) {
+ dontListen(slot.getSpacingElement(), spacingResizeListener);
+ }
+
+ // Add all necessary listeners
+ if (needsFixedHeight()) {
+ listen(slot.getWidget().getElement(), childComponentResizeListener);
+ if (slot.hasCaption()) {
+ listen(slot.getCaptionElement(), slotCaptionResizeListener);
+ }
+ } else if ((child.isRelativeHeight() || child.isRelativeWidth())
+ && slot.hasCaption()) {
+ // If the slot has caption, we need to listen for it's size changes
+ // in order to update the padding/margin offset for relative sized
+ // components
+ listen(slot.getCaptionElement(), slotCaptionResizeListener);
+ }
+
+ if (needsExpand()) {
+ listen(slot.getWidget().getElement(), childComponentResizeListener);
+ if (slot.hasSpacing()) {
+ listen(slot.getSpacingElement(), spacingResizeListener);
+ }
+ }
+
+ if (child.isRelativeHeight()) {
+ hasRelativeHeight.add(child);
+ needsMeasure.remove(child.getWidget().getElement());
+ } else {
+ hasRelativeHeight.remove(child);
+ needsMeasure.add(child.getWidget().getElement());
+ }
+
+ }
+
+ // public void postLayout() {
+ // if (needsFixedHeight()) {
+ // // Re-measure all elements that are available
+ // for (Element el : needsMeasure) {
+ // childElementHeight.put(el, getLayoutManager()
+ // .getOuterHeight(el));
+ //
+ // Element captionElement = el.getParentElement()
+ // .getFirstChildElement().cast();
+ // if (captionElement.getClassName().contains("v-caption")) {
+ // childCaptionElementHeight.put(el, getLayoutManager()
+ // .getOuterHeight(captionElement));
+ // }
+ // }
+ // // System.out.println(" ### Child sizes: "
+ // // + childElementHeight.values().toString());
+ // // System.out.println(" ### Caption sizes: "
+ // // + childCaptionElementHeight.values().toString());
+ //
+ // int height = getMaxHeight()
+ // + getLayoutManager().getBorderHeight(
+ // getWidget().getElement())
+ // + getLayoutManager().getPaddingHeight(
+ // getWidget().getElement());
+ // getWidget().getElement().getStyle().setHeight(height, Unit.PX);
+ // }
+ // }
+
+ // private ElementResizeListener layoutResizeListener = new
+ // ElementResizeListener() {
+ // public void onElementResize(ElementResizeEvent e) {
+ // updateLayoutHeight();
+ // if (needsExpand() && (isUndefinedHeight() || isUndefinedWidth())) {
+ // updateExpand();
+ // }
+ // }
+ // };
+
+ private ElementResizeListener slotCaptionResizeListener = new ElementResizeListener() {
+ public void onElementResize(ElementResizeEvent e) {
+
+ // Get all needed element references
+ Element captionElement = (Element) e.getElement().cast();
+
+ // Caption position determines if the widget element is the first or
+ // last child inside the caption wrap
+ CaptionPosition pos = getWidget().getCaptionPositionFromElement(
+ (Element) captionElement.getParentElement().cast());
+
+ // The default is the last child
+ Element widgetElement = captionElement.getParentElement()
+ .getLastChild().cast();
+
+ // ...but if caption position is bottom or right, the widget is the
+ // first child
+ if (pos == CaptionPosition.BOTTOM || pos == CaptionPosition.RIGHT) {
+ widgetElement = captionElement.getParentElement()
+ .getFirstChildElement().cast();
+ }
+
+ if (captionElement == widgetElement) {
+ // Caption element already detached
+ dontListen(captionElement, slotCaptionResizeListener);
+ childCaptionElementHeight.remove(widgetElement);
+ return;
+ }
+
+ String widgetWidth = widgetElement.getStyle().getWidth();
+ String widgetHeight = widgetElement.getStyle().getHeight();
+
+ if (widgetHeight.endsWith("%")
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ getWidget().updateCaptionOffset(captionElement);
+ } else if (widgetWidth.endsWith("%")
+ && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
+ getWidget().updateCaptionOffset(captionElement);
+ }
+
+ int h = getLayoutManager().getOuterHeight(captionElement)
+ - getLayoutManager().getMarginHeight(captionElement);
+ childCaptionElementHeight.put(widgetElement, h);
+
+ // if (needsFixedHeight()) {
+ // getWidget().clearHeight();
+ // getLayoutManager().setNeedsMeasure(
+ // AbstractBoxLayoutConnector.this);
+ // }
+
+ updateLayoutHeight();
+
+ if (needsExpand()) {
+ updateExpand();
+ }
+ }
+ };
+
+ private ElementResizeListener childComponentResizeListener = new ElementResizeListener() {
+ public void onElementResize(ElementResizeEvent e) {
+ // int h = getLayoutManager().getOuterHeight(e.getElement());
+ // childElementHeight.put((Element) e.getElement().cast(), h);
+ updateLayoutHeight();
+
+ if (needsExpand()) {
+ updateExpand();
+ }
+ }
+ };
+
+ private ElementResizeListener spacingResizeListener = new ElementResizeListener() {
+ public void onElementResize(ElementResizeEvent e) {
+ if (needsExpand()) {
+ updateExpand();
+ }
+ }
+ };
+
+ private void updateLayoutHeight() {
+ if (needsFixedHeight()) {
+ int h = getMaxHeight();
+ h += getLayoutManager().getBorderHeight(getWidget().getElement())
+ + getLayoutManager().getPaddingHeight(
+ getWidget().getElement());
+ getWidget().getElement().getStyle().setHeight(h, Unit.PX);
+ getLayoutManager().setNeedsMeasure(this);
+ }
+ }
+
+ private void updateExpand() {
+ // System.out.println("All sizes: "
+ // + childElementHeight.values().toString() + " - Caption sizes: "
+ // + childCaptionElementHeight.values().toString());
+ getWidget().updateExpand();
+ }
+
+ private int getMaxHeight() {
+ int highestNonRelative = -1;
+ int highestRelative = -1;
+
+ for (ComponentConnector child : getChildComponents()) {
+ // TODO would be more efficient to measure the slot element if both
+ // caption and child widget elements need to be measured. Keeping
+ // track of what to measure is the most difficult part of this
+ // layout.
+ Element el = child.getWidget().getElement();
+ CaptionPosition pos = getWidget().getCaptionPositionFromElement(
+ (Element) el.getParentElement().cast());
+ if (needsMeasure.contains(el)) {
+ int h = getLayoutManager().getOuterHeight(el);
+ String sHeight = el.getStyle().getHeight();
+ // Only add the caption size to the height of the slot if
+ // coption position is top or bottom
+ if (childCaptionElementHeight.containsKey(el)
+ && (sHeight == null || !sHeight.endsWith("%"))
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ h += childCaptionElementHeight.get(el);
+ }
+ if (h > highestNonRelative) {
+ highestNonRelative = h;
+ }
+ } else {
+ int h = getLayoutManager().getOuterHeight(el);
+ if (childCaptionElementHeight.containsKey(el)
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ h += childCaptionElementHeight.get(el);
+ }
+ if (h > highestRelative) {
+ highestRelative = h;
+ }
+ }
+ }
+ return highestNonRelative > -1 ? highestNonRelative : highestRelative;
+ }
+
+ @Override
+ public void onUnregister() {
+ // Cleanup all ElementResizeListeners
+
+ // dontListen(getWidget().getElement(), layoutResizeListener);
+
+ for (ComponentConnector child : getChildComponents()) {
+ Slot slot = getWidget().getSlot(child);
+ if (slot.hasCaption()) {
+ dontListen(slot.getCaptionElement(), slotCaptionResizeListener);
+ }
+
+ if (slot.getSpacingElement() != null) {
+ dontListen(slot.getSpacingElement(), spacingResizeListener);
+ }
+
+ dontListen(slot.getWidget().getElement(),
+ childComponentResizeListener);
+ }
+
+ super.onUnregister();
+ }
+
+ // private void setLayoutHeightListener(boolean add) {
+ // if (add) {
+ // listen(getWidget().getElement(), layoutResizeListener);
+ // } else {
+ // dontListen(getWidget().getElement(), layoutResizeListener);
+ // if (!needsExpand()) {
+ // System.out.println("Clearing element sizes");
+ // childElementHeight.clear();
+ // childCaptionElementHeight.clear();
+ // }
+ // }
+ // }
+
+ /*
+ * Convenience methods
+ */
+
+ private void listen(Element el, ElementResizeListener listener) {
+ getLayoutManager().addElementResizeListener(el, listener);
+ }
+
+ private void dontListen(Element el, ElementResizeListener listener) {
+ getLayoutManager().removeElementResizeListener(el, listener);
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java
new file mode 100644
index 0000000000..d18ea8a178
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalBoxLayoutConnector.java
@@ -0,0 +1,19 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui.orderedlayout;
+
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.ui.HorizontalLayout;
+
+@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER)
+public class HorizontalBoxLayoutConnector extends AbstractBoxLayoutConnector {
+
+ @Override
+ public void init() {
+ super.init();
+ getWidget().setVertical(false);
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java
index 195622854d..f22b558afd 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java
@@ -15,11 +15,8 @@
*/
package com.vaadin.terminal.gwt.client.ui.orderedlayout;
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.Connect.LoadStyle;
-import com.vaadin.ui.HorizontalLayout;
-@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER)
+//@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER)
public class HorizontalLayoutConnector extends AbstractOrderedLayoutConnector {
@Override
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VBoxLayout.java b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VBoxLayout.java
new file mode 100644
index 0000000000..dcc33a36b7
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VBoxLayout.java
@@ -0,0 +1,757 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui.orderedlayout;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.regexp.shared.MatchResult;
+import com.google.gwt.regexp.shared.RegExp;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.UIObject;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.shared.ui.AlignmentInfo;
+import com.vaadin.shared.ui.VMarginInfo;
+import com.vaadin.terminal.gwt.client.ComponentConnector;
+import com.vaadin.terminal.gwt.client.LayoutManager;
+
+public class VBoxLayout extends FlowPanel {
+
+ public static final String CLASSNAME = "v-boxlayout";
+
+ private static final String ALIGN_CLASS_PREFIX = "v-align-";
+
+ protected boolean spacing = false;
+
+ protected boolean vertical = true;
+
+ protected boolean definedHeight = false;
+
+ private Map<Widget, Slot> widgetToSlot = new HashMap<Widget, Slot>();
+
+ private LayoutManager layoutManager;
+
+ public VBoxLayout() {
+ setStyleName(CLASSNAME);
+ setVertical(true);
+ }
+
+ public void setVertical(boolean isVertical) {
+ vertical = isVertical;
+ if (vertical) {
+ addStyleName("v-vertical");
+ removeStyleName("v-horizontal");
+ } else {
+ addStyleName("v-horizontal");
+ removeStyleName("v-vertical");
+ }
+ }
+
+ public void addOrMoveSlot(Slot slot, int index) {
+ if (slot.getParent() == this) {
+ int currentIndex = getWidgetIndex(slot);
+ if (index == currentIndex) {
+ return;
+ }
+ }
+ insert(slot, index);
+ }
+
+ @Override
+ protected void insert(Widget child, Element container, int beforeIndex,
+ boolean domInsert) {
+ // Validate index; adjust if the widget is already a child of this
+ // panel.
+ beforeIndex = adjustIndex(child, beforeIndex);
+
+ // Detach new child.
+ child.removeFromParent();
+
+ // Logical attach.
+ getChildren().insert(child, beforeIndex);
+
+ // Physical attach.
+ container = expandWrapper != null ? expandWrapper : getElement();
+ if (domInsert) {
+ DOM.insertChild(container, child.getElement(),
+ spacing ? beforeIndex * 2 : beforeIndex);
+ } else {
+ DOM.appendChild(container, child.getElement());
+ }
+
+ // Adopt.
+ adopt(child);
+ }
+
+ public Slot removeSlot(Widget widget) {
+ Slot slot = widgetToSlot.get(widget);
+ remove(slot);
+ widgetToSlot.remove(widget);
+ return slot;
+ }
+
+ public Slot getSlot(ComponentConnector connector) {
+ Slot slot = widgetToSlot.get(connector.getWidget());
+ if (slot == null) {
+ slot = new Slot(connector);
+ widgetToSlot.put(connector.getWidget(), slot);
+ }
+ return slot;
+ }
+
+ public enum CaptionPosition {
+ TOP, RIGHT, BOTTOM, LEFT
+ }
+
+ protected class Slot extends SimplePanel {
+
+ private ComponentConnector connector;
+
+ private Element spacer;
+
+ private Element captionWrap;
+ private Element caption;
+ private Element captionText;
+ private Icon icon;
+ private Element errorIcon;
+ private Element requiredIcon;
+
+ // Caption is placed after component unless there is some part which
+ // moves it above.
+ private CaptionPosition captionPosition = CaptionPosition.RIGHT;
+
+ private AlignmentInfo alignment;
+ private double expandRatio = -1;
+
+ public Slot(ComponentConnector connector) {
+ this.connector = connector;
+ setWidget(connector.getWidget());
+ setStylePrimaryName("v-slot");
+ }
+
+ public AlignmentInfo getAlignment() {
+ return alignment;
+ }
+
+ public void setAlignment(AlignmentInfo alignment) {
+ this.alignment = alignment;
+
+ if (alignment.isHorizontalCenter()) {
+ addStyleName(ALIGN_CLASS_PREFIX + "center");
+ removeStyleName(ALIGN_CLASS_PREFIX + "right");
+ } else if (alignment.isRight()) {
+ addStyleName(ALIGN_CLASS_PREFIX + "right");
+ removeStyleName(ALIGN_CLASS_PREFIX + "center");
+ } else {
+ removeStyleName(ALIGN_CLASS_PREFIX + "right");
+ removeStyleName(ALIGN_CLASS_PREFIX + "center");
+ }
+ if (alignment.isVerticalCenter()) {
+ addStyleName(ALIGN_CLASS_PREFIX + "middle");
+ removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
+ } else if (alignment.isBottom()) {
+ addStyleName(ALIGN_CLASS_PREFIX + "bottom");
+ removeStyleName(ALIGN_CLASS_PREFIX + "middle");
+ } else {
+ removeStyleName(ALIGN_CLASS_PREFIX + "middle");
+ removeStyleName(ALIGN_CLASS_PREFIX + "bottom");
+ }
+ }
+
+ public void setExpandRatio(double expandRatio) {
+ this.expandRatio = expandRatio;
+ }
+
+ public double getExpandRatio() {
+ return expandRatio;
+ }
+
+ public void setSpacing(boolean spacing) {
+ if (spacing && spacer == null) {
+ spacer = DOM.createDiv();
+ spacer.addClassName("v-spacing");
+ getElement().getParentElement().insertBefore(spacer,
+ getElement());
+ } else if (!spacing && spacer != null) {
+ spacer.removeFromParent();
+ spacer = null;
+ }
+ }
+
+ public Element getSpacingElement() {
+ return spacer;
+ }
+
+ public boolean hasSpacing() {
+ return getSpacingElement() != null;
+ }
+
+ protected int getSpacingSize(boolean vertical) {
+ if (spacer == null) {
+ return 0;
+ }
+
+ if (layoutManager != null) {
+ if (vertical) {
+ return layoutManager.getOuterHeight(spacer);
+ } else {
+ return layoutManager.getOuterWidth(spacer);
+ }
+ }
+ // TODO place for optimization (in expense of theme
+ // flexibility): only measure one of the elements and cache the
+ // value
+ return vertical ? spacer.getOffsetHeight() : spacer
+ .getOffsetWidth();
+ // }
+ }
+
+ public void setCaptionPosition(CaptionPosition captionPosition) {
+ if (caption == null) {
+ return;
+ }
+
+ captionWrap.removeClassName("v-caption-on-"
+ + this.captionPosition.name().toLowerCase());
+
+ this.captionPosition = captionPosition;
+ if (captionPosition == CaptionPosition.BOTTOM
+ || captionPosition == CaptionPosition.RIGHT) {
+ captionWrap.appendChild(caption);
+ } else {
+ captionWrap.insertFirst(caption);
+ }
+
+ captionWrap.addClassName("v-caption-on-"
+ + captionPosition.name().toLowerCase());
+ }
+
+ public CaptionPosition getCaptionPosition() {
+ return captionPosition;
+ }
+
+ // TODO refactor VCaption and use that instead: creates a tight coupling
+ // between this layout and Vaadin, but it's already coupled
+ public void setCaption(String captionText, String iconUrl,
+ List<String> styles, String error, boolean showError,
+ boolean required, boolean enabled) {
+
+ // TODO place for optimization: check if any of these have changed
+ // since last time, and only run those changes
+
+ // Caption wrappers
+ if (captionText != null || iconUrl != null || error != null
+ || required) {
+ if (caption == null) {
+ caption = DOM.createDiv();
+ captionWrap = DOM.createDiv();
+ captionWrap.addClassName("v");
+ captionWrap.addClassName("v-has-caption");
+ getElement().appendChild(captionWrap);
+ captionWrap.appendChild(getWidget().getElement());
+ }
+ } else if (caption != null) {
+ getElement().appendChild(getWidget().getElement());
+ captionWrap.removeFromParent();
+ caption = null;
+ captionWrap = null;
+ }
+
+ // Caption text
+ if (captionText != null) {
+ if (this.captionText == null) {
+ this.captionText = DOM.createSpan();
+ this.captionText.addClassName("v-captiontext");
+ caption.appendChild(this.captionText);
+ }
+ if (captionText.trim().equals("")) {
+ this.captionText.setInnerHTML("&nbsp;");
+ } else {
+ this.captionText.setInnerText(captionText);
+ }
+ } else if (this.captionText != null) {
+ this.captionText.removeFromParent();
+ this.captionText = null;
+ }
+
+ // Icon
+ if (iconUrl != null) {
+ if (icon == null) {
+ icon = new Icon();
+ // icon = DOM.createImg();
+ // icon.setClassName("v-icon");
+ caption.insertFirst(icon.getElement());
+ }
+ // icon.setAttribute("src", iconUrl);
+ icon.setUri(iconUrl);
+ } else if (icon != null) {
+ icon.getElement().removeFromParent();
+ icon = null;
+ }
+
+ // Required
+ if (required) {
+ if (requiredIcon == null) {
+ requiredIcon = DOM.createSpan();
+ // TODO decide something better (e.g. use CSS to insert the
+ // character)
+ requiredIcon.setInnerHTML("*");
+ requiredIcon.setClassName("v-required-field-indicator");
+ }
+ caption.appendChild(requiredIcon);
+ } else if (requiredIcon != null) {
+ requiredIcon.removeFromParent();
+ requiredIcon = null;
+ }
+
+ // Error
+ if (error != null && showError) {
+ if (errorIcon == null) {
+ errorIcon = DOM.createSpan();
+ errorIcon.setClassName("v-errorindicator");
+ }
+ caption.appendChild(errorIcon);
+ } else if (errorIcon != null) {
+ errorIcon.removeFromParent();
+ errorIcon = null;
+ }
+
+ if (caption != null) {
+ // Styles
+ caption.setClassName("v-caption");
+
+ if (styles != null) {
+ for (String style : styles) {
+ caption.addClassName("v-caption-" + style);
+ }
+ }
+
+ if (enabled) {
+ caption.removeClassName("v-disabled");
+ } else {
+ caption.addClassName("v-disabled");
+ }
+
+ // Caption position
+ if (captionText != null || iconUrl != null) {
+ setCaptionPosition(CaptionPosition.TOP);
+ } else {
+ setCaptionPosition(CaptionPosition.RIGHT);
+ }
+ }
+
+ // TODO theme flexibility: add extra styles to captionWrap as well?
+
+ }
+
+ public boolean hasCaption() {
+ return caption != null;
+ }
+
+ public Element getCaptionElement() {
+ return caption;
+ }
+
+ public void setRelativeWidth(boolean relativeWidth) {
+ updateRelativeSize(relativeWidth, "width");
+ }
+
+ public void setRelativeHeight(boolean relativeHeight) {
+ updateRelativeSize(relativeHeight, "height");
+ }
+
+ private void updateRelativeSize(boolean isRelativeSize, String direction) {
+ if (isRelativeSize && hasCaption()) {
+ captionWrap.getStyle().setProperty(
+ direction,
+ getWidget().getElement().getStyle()
+ .getProperty(direction));
+ captionWrap.addClassName("v-has-" + direction);
+ } else if (hasCaption()) {
+ if (direction.equals("height")) {
+ captionWrap.getStyle().clearHeight();
+ } else {
+ captionWrap.getStyle().clearWidth();
+ }
+ captionWrap.removeClassName("v-has-" + direction);
+ captionWrap.getStyle().clearPaddingTop();
+ captionWrap.getStyle().clearPaddingRight();
+ captionWrap.getStyle().clearPaddingBottom();
+ captionWrap.getStyle().clearPaddingLeft();
+ caption.getStyle().clearMarginTop();
+ caption.getStyle().clearMarginRight();
+ caption.getStyle().clearMarginBottom();
+ caption.getStyle().clearMarginLeft();
+ }
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ if (DOM.eventGetType(event) == Event.ONLOAD
+ && icon.getElement() == DOM.eventGetTarget(event)) {
+ if (layoutManager != null) {
+ layoutManager.layoutLater();
+ } else {
+ updateCaptionOffset(caption);
+ }
+ }
+ }
+
+ @Override
+ protected Element getContainerElement() {
+ if (captionWrap == null) {
+ return getElement();
+ } else {
+ return captionWrap;
+ }
+ }
+
+ @Override
+ protected void onDetach() {
+ if (spacer != null) {
+ spacer.removeFromParent();
+ }
+ super.onDetach();
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ if (spacer != null) {
+ getElement().getParentElement().insertBefore(spacer,
+ getElement());
+ }
+ }
+
+ }
+
+ protected class Icon extends UIObject {
+ public static final String CLASSNAME = "v-icon";
+ private String myUrl;
+
+ public Icon() {
+ setElement(DOM.createImg());
+ DOM.setElementProperty(getElement(), "alt", "");
+ setStyleName(CLASSNAME);
+ }
+
+ public void setUri(String url) {
+ if (!url.equals(myUrl)) {
+ /*
+ * Start sinking onload events, widgets responsibility to react.
+ * We must do this BEFORE we set src as IE fires the event
+ * immediately if the image is found in cache (#2592).
+ */
+ sinkEvents(Event.ONLOAD);
+
+ DOM.setElementProperty(getElement(), "src", url);
+ myUrl = url;
+ }
+ }
+
+ }
+
+ void setLayoutManager(LayoutManager manager) {
+ layoutManager = manager;
+ }
+
+ private static final RegExp captionPositionRegexp = RegExp
+ .compile("v-caption-on-(\\S+)");
+
+ CaptionPosition getCaptionPositionFromElement(Element captionWrap) {
+ // Get caption position from the classname
+ MatchResult matcher = captionPositionRegexp.exec(captionWrap
+ .getClassName());
+ if (matcher == null || matcher.getGroupCount() < 2) {
+ return CaptionPosition.TOP;
+ }
+ String captionClass = matcher.getGroup(1);
+ CaptionPosition captionPosition = CaptionPosition.valueOf(
+ CaptionPosition.class, captionClass.toUpperCase());
+ return captionPosition;
+ }
+
+ void updateCaptionOffset(Element caption) {
+
+ Element captionWrap = caption.getParentElement().cast();
+
+ Style captionWrapStyle = captionWrap.getStyle();
+ captionWrapStyle.clearPaddingTop();
+ captionWrapStyle.clearPaddingRight();
+ captionWrapStyle.clearPaddingBottom();
+ captionWrapStyle.clearPaddingLeft();
+
+ Style captionStyle = caption.getStyle();
+ captionStyle.clearMarginTop();
+ captionStyle.clearMarginRight();
+ captionStyle.clearMarginBottom();
+ captionStyle.clearMarginLeft();
+
+ // Get caption position from the classname
+ CaptionPosition captionPosition = getCaptionPositionFromElement(captionWrap);
+
+ if (captionPosition == CaptionPosition.LEFT
+ || captionPosition == CaptionPosition.RIGHT) {
+ int captionWidth;
+ if (layoutManager != null) {
+ captionWidth = layoutManager.getOuterWidth(caption)
+ - layoutManager.getMarginWidth(caption);
+ } else {
+ captionWidth = caption.getOffsetWidth();
+ }
+ if (captionWidth > 0) {
+ if (captionPosition == CaptionPosition.LEFT) {
+ captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX);
+ captionStyle.setMarginLeft(-captionWidth, Unit.PX);
+ } else {
+ captionWrapStyle.setPaddingRight(captionWidth, Unit.PX);
+ captionStyle.setMarginRight(-captionWidth, Unit.PX);
+ }
+ }
+ }
+ if (captionPosition == CaptionPosition.TOP
+ || captionPosition == CaptionPosition.BOTTOM) {
+ int captionHeight;
+ if (layoutManager != null) {
+ captionHeight = layoutManager.getOuterHeight(caption)
+ - layoutManager.getMarginHeight(caption);
+ } else {
+ captionHeight = caption.getOffsetHeight();
+ }
+ if (captionHeight > 0) {
+ if (captionPosition == CaptionPosition.TOP) {
+ captionWrapStyle.setPaddingTop(captionHeight, Unit.PX);
+ captionStyle.setMarginTop(-captionHeight, Unit.PX);
+ } else {
+ captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX);
+ captionStyle.setMarginBottom(-captionHeight, Unit.PX);
+ }
+ }
+ }
+ }
+
+ private void toggleStyleName(String name, boolean enabled) {
+ if (enabled) {
+ addStyleName(name);
+ } else {
+ removeStyleName(name);
+ }
+ }
+
+ void setMargin(VMarginInfo marginInfo) {
+ toggleStyleName("v-margin-top", marginInfo.hasTop());
+ toggleStyleName("v-margin-right", marginInfo.hasRight());
+ toggleStyleName("v-margin-bottom", marginInfo.hasBottom());
+ toggleStyleName("v-margin-left", marginInfo.hasLeft());
+ }
+
+ protected void setSpacing(boolean spacingEnabled) {
+ spacing = spacingEnabled;
+ for (Slot slot : widgetToSlot.values()) {
+ if (getWidgetIndex(slot) > 0) {
+ slot.setSpacing(spacingEnabled);
+ }
+ }
+ }
+
+ private void recalculateExpands() {
+ double total = 0;
+ for (Slot slot : widgetToSlot.values()) {
+ if (slot.getExpandRatio() > -1) {
+ total += slot.getExpandRatio();
+ } else {
+ if (vertical) {
+ slot.getElement().getStyle().clearHeight();
+ } else {
+ slot.getElement().getStyle().clearWidth();
+ }
+ }
+ }
+ for (Slot slot : widgetToSlot.values()) {
+ if (slot.getExpandRatio() > -1) {
+ if (vertical) {
+ slot.setHeight((100 * (slot.getExpandRatio() / total))
+ + "%");
+ if (slot.connector.isRelativeHeight()) {
+ layoutManager.setNeedsMeasure(slot.connector);
+ }
+ } else {
+ slot.setWidth((100 * (slot.getExpandRatio() / total)) + "%");
+ if (slot.connector.isRelativeWidth()) {
+ layoutManager.setNeedsMeasure(slot.connector);
+ }
+ }
+ }
+ }
+ }
+
+ private Element expandWrapper;
+
+ void clearExpand() {
+ if (expandWrapper != null) {
+ for (; expandWrapper.getChildCount() > 0;) {
+ Element el = expandWrapper.getChild(0).cast();
+ getElement().appendChild(el);
+ if (vertical) {
+ el.getStyle().clearHeight();
+ el.getStyle().clearMarginTop();
+ } else {
+ el.getStyle().clearWidth();
+ el.getStyle().clearMarginLeft();
+ }
+ }
+ expandWrapper.removeFromParent();
+ expandWrapper = null;
+ }
+ }
+
+ public void updateExpand() {
+ boolean isExpanding = false;
+ for (Widget slot : getChildren()) {
+ if (((Slot) slot).getExpandRatio() > -1) {
+ isExpanding = true;
+ } else {
+ if (vertical) {
+ slot.getElement().getStyle().clearHeight();
+ } else {
+ slot.getElement().getStyle().clearWidth();
+ }
+ }
+ slot.getElement().getStyle().clearMarginLeft();
+ slot.getElement().getStyle().clearMarginTop();
+ }
+
+ if (isExpanding) {
+ if (expandWrapper == null) {
+ expandWrapper = DOM.createDiv();
+ expandWrapper.setClassName("v-expand");
+ for (; getElement().getChildCount() > 0;) {
+ Node el = getElement().getChild(0);
+ expandWrapper.appendChild(el);
+ }
+ getElement().appendChild(expandWrapper);
+ }
+
+ int totalSize = 0;
+ for (Widget w : getChildren()) {
+ Slot slot = (Slot) w;
+ if (slot.getExpandRatio() == -1) {
+ if (layoutManager != null) {
+ // TODO check caption position
+ if (vertical) {
+ int size = layoutManager.getOuterHeight(slot
+ .getWidget().getElement())
+ - layoutManager.getMarginHeight(slot
+ .getWidget().getElement());
+ if (slot.hasCaption()) {
+ size += layoutManager.getOuterHeight(slot
+ .getCaptionElement())
+ - layoutManager.getMarginHeight(slot
+ .getCaptionElement());
+ }
+ if (size > 0) {
+ totalSize += size;
+ }
+ } else {
+ int max = -1;
+ max = layoutManager.getOuterWidth(slot.getWidget()
+ .getElement())
+ - layoutManager.getMarginWidth(slot
+ .getWidget().getElement());
+ if (slot.hasCaption()) {
+ int max2 = layoutManager.getOuterWidth(slot
+ .getCaptionElement())
+ - layoutManager.getMarginWidth(slot
+ .getCaptionElement());
+ max = Math.max(max, max2);
+ }
+ if (max > 0) {
+ totalSize += max;
+ }
+ }
+ } else {
+ totalSize += vertical ? slot.getOffsetHeight() : slot
+ .getOffsetWidth();
+ }
+ }
+ // TODO fails in Opera, always returns 0
+ int spacingSize = slot.getSpacingSize(vertical);
+ if (spacingSize > 0) {
+ totalSize += spacingSize;
+ }
+ }
+
+ // When we set the margin to the first child, we don't need
+ // overflow:hidden in the layout root element, since the wrapper
+ // would otherwise be placed outside of the layout root element
+ // and block events on elements below it.
+ if (vertical) {
+ expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX);
+ expandWrapper.getFirstChildElement().getStyle()
+ .setMarginTop(-totalSize, Unit.PX);
+ } else {
+ expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX);
+ expandWrapper.getFirstChildElement().getStyle()
+ .setMarginLeft(-totalSize, Unit.PX);
+ }
+
+ recalculateExpands();
+ }
+ }
+
+ public void recalculateLayoutHeight() {
+ // Only needed if a horizontal layout is undefined high, and contains
+ // relative height children or vertical alignments
+ if (vertical || definedHeight) {
+ return;
+ }
+
+ boolean hasRelativeHeightChildren = false;
+ boolean hasVAlign = false;
+
+ for (Widget slot : getChildren()) {
+ Widget widget = ((Slot) slot).getWidget();
+ String h = widget.getElement().getStyle().getHeight();
+ if (h != null && h.indexOf("%") > -1) {
+ hasRelativeHeightChildren = true;
+ }
+ AlignmentInfo a = ((Slot) slot).getAlignment();
+ if (a != null && (a.isVerticalCenter() || a.isBottom())) {
+ hasVAlign = true;
+ }
+ }
+
+ if (hasRelativeHeightChildren || hasVAlign) {
+ int newHeight;
+ if (layoutManager != null) {
+ newHeight = layoutManager.getOuterHeight(getElement())
+ - layoutManager.getMarginHeight(getElement());
+ } else {
+ newHeight = getElement().getOffsetHeight();
+ }
+ VBoxLayout.this.getElement().getStyle()
+ .setHeight(newHeight, Unit.PX);
+ }
+
+ }
+
+ void clearHeight() {
+ getElement().getStyle().clearHeight();
+ }
+
+ @Override
+ public void setHeight(String height) {
+ super.setHeight(height);
+ definedHeight = (height != null && !"".equals(height));
+ }
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalBoxLayoutConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalBoxLayoutConnector.java
new file mode 100644
index 0000000000..a480a79b2e
--- /dev/null
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalBoxLayoutConnector.java
@@ -0,0 +1,19 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui.orderedlayout;
+
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.ui.VerticalLayout;
+
+@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER)
+public class VerticalBoxLayoutConnector extends AbstractBoxLayoutConnector {
+
+ @Override
+ public void init() {
+ super.init();
+ getWidget().setVertical(true);
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java
index 441ba9c156..c53494775c 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java
@@ -15,11 +15,8 @@
*/
package com.vaadin.terminal.gwt.client.ui.orderedlayout;
-import com.vaadin.shared.ui.Connect;
-import com.vaadin.shared.ui.Connect.LoadStyle;
-import com.vaadin.ui.VerticalLayout;
-@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER)
+//@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER)
public class VerticalLayoutConnector extends AbstractOrderedLayoutConnector {
@Override
diff --git a/shared/src/com/vaadin/shared/ComponentState.java b/shared/src/com/vaadin/shared/ComponentState.java
index 92afad0520..6c9f055732 100644
--- a/shared/src/com/vaadin/shared/ComponentState.java
+++ b/shared/src/com/vaadin/shared/ComponentState.java
@@ -92,6 +92,16 @@ public class ComponentState extends SharedState {
}
/**
+ * Returns true if the component height is relative to the parent, i.e.
+ * percentage, false if it is fixed/auto.
+ *
+ * @return true if component height is relative (percentage)
+ */
+ public boolean isRelativeHeight() {
+ return getHeight().endsWith("%");
+ }
+
+ /**
* Returns the component width as set by the server.
*
* Can be relative (containing the percent sign) or absolute, or empty
@@ -130,6 +140,16 @@ public class ComponentState extends SharedState {
}
/**
+ * Returns true if the component width is relative to the parent, i.e.
+ * percentage, false if it is fixed/auto.
+ *
+ * @return true if component width is relative (percentage)
+ */
+ public boolean isRelativeWidth() {
+ return getWidth().endsWith("%");
+ }
+
+ /**
* Returns true if the component is in read-only mode.
*
* @see com.vaadin.ui.Component#isReadOnly()
diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/BoxLayoutTest.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/BoxLayoutTest.java
new file mode 100644
index 0000000000..86015a0109
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/BoxLayoutTest.java
@@ -0,0 +1,469 @@
+package com.vaadin.tests.components.orderedlayout;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.event.LayoutEvents.LayoutClickEvent;
+import com.vaadin.event.LayoutEvents.LayoutClickListener;
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.UserError;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.tests.components.AbstractTestRoot;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.AbstractOrderedLayout;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.Reindeer;
+
+@Theme("tests-components")
+public class BoxLayoutTest extends AbstractTestRoot {
+
+ protected AbstractOrderedLayout view;
+
+ protected AbstractOrderedLayout l;
+
+ protected AbstractComponent target;
+
+ protected NativeSelect componentWidth;
+ protected NativeSelect componentHeight;
+ protected NativeSelect componentCaption;
+ protected NativeSelect componentIcon;
+ protected TextField componentDescription;
+ protected CheckBox componentError;
+ protected CheckBox componentRequired;
+
+ protected NativeSelect align;
+ protected CheckBox expand;
+
+ @Override
+ protected void setup(WrappedRequest request) {
+
+ view = new VerticalLayout();
+ // view.setSizeFull();
+ view.setMargin(true);
+ view.setSpacing(true);
+
+ // view.addComponent(createControls(false));
+ // view.addComponent(createTestLayout(false));
+ // view.setExpandRatio(view.getComponent(1), 1);
+
+ for (int i = 0; i < 20; i++) {
+ view.addComponent(createHorizontalTest());
+ }
+
+ setContent(view);
+ getApplication().setRootPreserved(true);
+ }
+
+ private Component createHorizontalTest() {
+ HorizontalLayout l = new HorizontalLayout();
+ l.setWidth("100%");
+ l.setSpacing(true);
+
+ Label exp;
+
+ // l.addComponent(new Embedded(null, new ThemeResource(
+ // "../runo/icons/32/document.png")));
+ l.addComponent(exp = new Label(
+ "Mauris iaculis porttitor posuere. Praesent id metus massa, ut blandit odio. Proin quis tortor orci. Etiam at risus et justo dignissim congue. Donec."));
+ // exp.setWidth("300px");
+ l.addComponent(new Button("Edit"));
+ l.addComponent(new Button("Delete"));
+ l.setExpandRatio(exp, 1);
+
+ for (int i = 0; i < l.getComponentCount(); i++) {
+ l.setComponentAlignment(l.getComponent(i), Alignment.MIDDLE_LEFT);
+ }
+
+ return l;
+ }
+
+ protected AbstractOrderedLayout createControls(boolean horizontal) {
+ VerticalLayout root = new VerticalLayout();
+ root.setSpacing(true);
+
+ // First row
+ HorizontalLayout header = new HorizontalLayout();
+ header.setSpacing(true);
+ root.addComponent(header);
+
+ Label title = new Label("BoxLayout Test");
+ title.addStyleName(Reindeer.LABEL_H1);
+ header.addComponent(title);
+
+ final CheckBox vertical = new CheckBox("Vertical", !horizontal);
+ vertical.setImmediate(true);
+ vertical.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ view.removeAllComponents();
+
+ view.addComponent(createControls(!vertical.getValue()
+ .booleanValue()));
+ view.addComponent(createTestLayout(!vertical.getValue()
+ .booleanValue()));
+
+ view.setExpandRatio(view.getComponent(1), 1);
+
+ }
+ });
+ header.addComponent(vertical);
+
+ Button addComponent = new Button("Add Component",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ GridLayout grid = new GridLayout(2, 2);
+ Button grow = new Button("Grow Me",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ if (event.getButton().getWidth() == -1) {
+ event.getButton().setHeight("50px");
+ event.getButton().setWidth("200px");
+ } else {
+ event.getButton()
+ .setSizeUndefined();
+ }
+ }
+ });
+ grid.addComponent(new Label("Grid cell 1"));
+ grid.addComponent(new Label("Grid cell 2"));
+ grid.addComponent(grow);
+ grid.addComponent(new Label("Grid cell 4"));
+ l.addComponent(grid);
+ // l.addComponent(new TextField("Some field"));
+ }
+ });
+ header.addComponent(addComponent);
+
+ Button removeComponent = new Button("Remove Component",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ Component last = l.getComponent(l.getComponentCount() - 1);
+ l.removeComponent(last);
+ }
+ });
+ header.addComponent(removeComponent);
+
+ // Second row
+ HorizontalLayout controls = new HorizontalLayout();
+ controls.setSpacing(true);
+ root.addComponent(controls);
+
+ // Layout controls
+ HorizontalLayout layout = new HorizontalLayout();
+ layout.addStyleName("fieldset");
+ layout.setSpacing(true);
+ controls.addComponent(layout);
+ layout.addComponent(new Label("Layout"));
+
+ ArrayList<String> sizes = new ArrayList<String>();
+ sizes.addAll(Arrays.asList("100px", "30em", "100%"));
+
+ final NativeSelect width = new NativeSelect(null, sizes);
+ width.setImmediate(true);
+ width.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (width.getValue() != null) {
+ l.setWidth(width.getValue().toString());
+ } else {
+ l.setWidth(null);
+ }
+ }
+ });
+ layout.addComponent(width);
+ layout.addComponent(new Label("&times;", ContentMode.XHTML));
+ final NativeSelect height = new NativeSelect(null, sizes);
+ height.setImmediate(true);
+ height.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (height.getValue() != null) {
+ l.setHeight(height.getValue().toString());
+ } else {
+ l.setHeight(null);
+ }
+ }
+ });
+ layout.addComponent(height);
+
+ final CheckBox margin = new CheckBox("Margin", false);
+ margin.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ l.setMargin(margin.getValue().booleanValue());
+ }
+ });
+ margin.setImmediate(true);
+ layout.addComponent(margin);
+ layout.addComponent(margin);
+
+ final CheckBox spacing = new CheckBox("Spacing", false);
+ spacing.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ l.setSpacing(spacing.getValue().booleanValue());
+ }
+ });
+ spacing.setImmediate(true);
+ layout.addComponent(spacing);
+
+ // Cell controls
+ HorizontalLayout cell = new HorizontalLayout();
+ cell.addStyleName("fieldset");
+ cell.setSpacing(true);
+ controls.addComponent(cell);
+ cell.addComponent(new Label("Cell"));
+
+ ArrayList<Alignment> alignments = new ArrayList<Alignment>();
+ alignments.addAll(Arrays.asList(Alignment.TOP_LEFT,
+ Alignment.MIDDLE_LEFT, Alignment.BOTTOM_LEFT,
+ Alignment.TOP_CENTER, Alignment.MIDDLE_CENTER,
+ Alignment.BOTTOM_CENTER, Alignment.TOP_RIGHT,
+ Alignment.MIDDLE_RIGHT, Alignment.BOTTOM_RIGHT));
+
+ align = new NativeSelect(null, alignments);
+ for (Alignment a : alignments) {
+ align.setItemCaption(a,
+ a.getVerticalAlignment() + "-" + a.getHorizontalAlignment());
+ }
+ align.setImmediate(true);
+ align.setEnabled(false);
+ align.setNullSelectionAllowed(false);
+ align.select(Alignment.TOP_LEFT);
+ align.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (target == null) {
+ return;
+ }
+ l.setComponentAlignment(target, ((Alignment) align.getValue()));
+ }
+ });
+ cell.addComponent(align);
+
+ expand = new CheckBox("Expand");
+ expand.setImmediate(true);
+ expand.setEnabled(false);
+ expand.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (target != null) {
+ l.setExpandRatio(target, expand.getValue() ? 1 : 0);
+ }
+ }
+ });
+ cell.addComponent(expand);
+
+ // Component controls
+ HorizontalLayout component = new HorizontalLayout();
+ component.addStyleName("fieldset");
+ component.setSpacing(true);
+ root.addComponent(component);
+ component.addComponent(new Label("Component"));
+
+ sizes = new ArrayList<String>();
+ sizes.addAll(Arrays.asList("50px", "200px", "10em", "50%", "100%"));
+
+ componentWidth = new NativeSelect(null, sizes);
+ componentWidth.setImmediate(true);
+ componentWidth.setEnabled(false);
+ componentWidth.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (target == null) {
+ return;
+ }
+ if (componentWidth.getValue() != null) {
+ target.setWidth(componentWidth.getValue().toString());
+ } else {
+ target.setWidth(null);
+ }
+ }
+ });
+ component.addComponent(componentWidth);
+ component.addComponent(new Label("&times;", ContentMode.XHTML));
+
+ componentHeight = new NativeSelect(null, sizes);
+ componentHeight.setImmediate(true);
+ componentHeight.setEnabled(false);
+ componentHeight.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (componentHeight.getValue() != null) {
+ target.setHeight(componentHeight.getValue().toString());
+ } else {
+ target.setHeight(null);
+ }
+ }
+ });
+ component.addComponent(componentHeight);
+
+ componentCaption = new NativeSelect("Caption", Arrays.asList("Short",
+ "Slightly Longer Caption"));
+ componentCaption.setImmediate(true);
+ componentCaption.setEnabled(false);
+ componentCaption.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (componentCaption.getValue() != null) {
+ target.setCaption(componentCaption.getValue().toString());
+ } else {
+ target.setCaption(null);
+ }
+ }
+ });
+ component.addComponent(componentCaption);
+
+ componentIcon = new NativeSelect("Icon", Arrays.asList(
+ "../runo/icons/16/folder.png", "../runo/icons/32/document.png"));
+ componentIcon.setImmediate(true);
+ componentIcon.setEnabled(false);
+ componentIcon.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (componentIcon.getValue() != null) {
+ target.setIcon(new ThemeResource(componentIcon.getValue()
+ .toString()));
+ } else {
+ target.setIcon(null);
+ }
+ }
+ });
+ component.addComponent(componentIcon);
+
+ componentDescription = new TextField("Description");
+ componentDescription.setImmediate(true);
+ componentDescription.setEnabled(false);
+ componentDescription.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ target.setDescription(componentDescription.getValue());
+ }
+ });
+ component.addComponent(componentDescription);
+
+ componentError = new CheckBox("Error");
+ componentError.setImmediate(true);
+ componentError.setEnabled(false);
+ componentError.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (target != null) {
+ target.setComponentError(componentError.getValue() ? new UserError(
+ "Error message") : null);
+ }
+ }
+ });
+ component.addComponent(componentError);
+
+ componentRequired = new CheckBox("Required");
+ componentRequired.setImmediate(true);
+ componentRequired.setEnabled(false);
+ componentRequired.addListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ if (target != null && target instanceof AbstractField) {
+ ((AbstractField<?>) target).setRequired(componentRequired
+ .getValue());
+ }
+ }
+ });
+ component.addComponent(componentRequired);
+
+ for (int i = 0; i < component.getComponentCount(); i++) {
+ component.setComponentAlignment(component.getComponent(i),
+ Alignment.MIDDLE_LEFT);
+ }
+
+ return root;
+ }
+
+ protected AbstractOrderedLayout createTestLayout(boolean horizontal) {
+ l = horizontal ? new HorizontalLayout() : new VerticalLayout();
+ l.setSizeUndefined();
+ l.addStyleName("test");
+
+ Label label = new Label("Component 1");
+ l.addComponent(label);
+ l.addComponent(new Button("Component 2"));
+
+ l.addListener(new LayoutClickListener() {
+ public void layoutClick(LayoutClickEvent event) {
+ if (event.getChildComponent() == null
+ || target == event.getChildComponent()) {
+ if (target != null) {
+ target.removeStyleName("target");
+ }
+ target = null;
+ } else if (target != event.getChildComponent()) {
+ if (target != null) {
+ target.removeStyleName("target");
+ }
+ target = (AbstractComponent) event.getChildComponent();
+ target.addStyleName("target");
+ }
+ componentWidth.setEnabled(target != null);
+ componentHeight.setEnabled(target != null);
+ componentCaption.setEnabled(target != null);
+ componentIcon.setEnabled(target != null);
+ componentDescription.setEnabled(target != null);
+ componentError.setEnabled(target != null);
+ componentRequired.setEnabled(target != null
+ && target instanceof AbstractField);
+ align.setEnabled(target != null);
+ expand.setEnabled(target != null);
+ if (target != null) {
+ if (target.getWidth() > -1) {
+ componentWidth.select(new Float(target.getWidth())
+ .intValue()
+ + target.getWidthUnits().getSymbol());
+ } else {
+ componentWidth.select(null);
+ }
+ if (target.getHeight() > -1) {
+ componentHeight.select(new Float(target.getHeight())
+ .intValue()
+ + target.getHeightUnits().getSymbol());
+ } else {
+ componentHeight.select(null);
+ }
+
+ align.select(l.getComponentAlignment(target));
+ expand.setValue(new Boolean(l.getExpandRatio(target) > 0));
+
+ componentCaption.select(target.getCaption());
+ if (target.getIcon() != null) {
+ componentIcon.select(((ThemeResource) target.getIcon())
+ .getResourceId());
+ } else {
+ componentIcon.select(null);
+ }
+ componentDescription.setValue(target.getDescription());
+ componentError.setValue(target.getComponentError() != null);
+ if (target instanceof AbstractField) {
+ componentRequired.setValue(((AbstractField<?>) target)
+ .isRequired());
+ }
+ }
+ }
+ });
+
+ target = null;
+
+ return l;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+} \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutRenderTimeTest.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutRenderTimeTest.java
new file mode 100644
index 0000000000..871a467877
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutRenderTimeTest.java
@@ -0,0 +1,58 @@
+package com.vaadin.tests.components.orderedlayout;
+
+import com.vaadin.Application.LegacyApplication;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Root;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.Reindeer;
+
+public class LayoutRenderTimeTest extends LegacyApplication {
+
+ @Override
+ public void init() {
+ Root.LegacyWindow main = new Root.LegacyWindow();
+ setMainWindow(main);
+
+ VerticalLayout root = new VerticalLayout();
+ root.setWidth("100%");
+ main.setContent(root);
+
+ for (int i = 1; i <= 100; i++) {
+ root.addComponent(getRow(i));
+ }
+ }
+
+ private HorizontalLayout getRow(int i) {
+ HorizontalLayout row = new HorizontalLayout();
+ // row.setWidth("100%");
+ // row.setSpacing(true);
+
+ Embedded icon = new Embedded(null, new ThemeResource(
+ "../runo/icons/32/document.png"));
+ // row.addComponent(icon);
+ // row.setComponentAlignment(icon, Alignment.MIDDLE_LEFT);
+
+ Label text = new Label(
+ "Row content #"
+ + i
+ + ". In pellentesque faucibus vestibulum. Nulla at nulla justo, eget luctus tortor. Nulla facilisi. Duis aliquet.");
+ // row.addComponent(text);
+ // row.setExpandRatio(text, 1);
+
+ Button button = new Button("Edit");
+ button.addStyleName(Reindeer.BUTTON_SMALL);
+ row.addComponent(button);
+ // row.setComponentAlignment(button, Alignment.MIDDLE_LEFT);
+
+ button = new Button("Delete");
+ button.addStyleName(Reindeer.BUTTON_SMALL);
+ row.addComponent(button);
+ // row.setComponentAlignment(button, Alignment.MIDDLE_LEFT);
+
+ return row;
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutResizeTest.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutResizeTest.java
index 07562b7cfe..62c552ee75 100644
--- a/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutResizeTest.java
+++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutResizeTest.java
@@ -9,7 +9,6 @@ import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
-import com.vaadin.ui.JavaScript;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
@@ -40,8 +39,10 @@ public class LayoutResizeTest extends TestBase {
new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
- JavaScript
- .getCurrent()
+ event.getButton()
+ .getRoot()
+ .getPage()
+ .getJavaScript()
.execute(
"setTimeout(function() {window.resizeTo(700,400)}, 500)");
}
@@ -51,8 +52,10 @@ public class LayoutResizeTest extends TestBase {
resize = new Button("Resize to 900x600", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
- JavaScript
- .getCurrent()
+ event.getButton()
+ .getRoot()
+ .getPage()
+ .getJavaScript()
.execute(
"setTimeout(function() {window.resizeTo(900,600)}, 500)");
}
diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java
index 5aaaaec6a6..a10e69e188 100644
--- a/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java
+++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import com.vaadin.annotations.Theme;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.terminal.WrappedRequest;
@@ -20,57 +21,59 @@ import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.VerticalLayout;
+@Theme("tests-components")
public class OrderedLayoutCases extends AbstractTestUI {
+
private static final String[] dimensionValues = { "-1px", "5px", "350px",
- "800px", "100%", "50%" };
+ "800px", "100%", "50%" };
private static class SampleChild extends VerticalLayout {
public SampleChild() {
setStyleName("sampleChild");
addComponent(createSimpleSelector("Child width",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- setWidth(event.getProperty().getValue().toString());
- }
- }, dimensionValues));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setWidth(event.getProperty().getValue().toString());
+ }
+ }, dimensionValues));
addComponent(createSimpleSelector("Child height",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- setHeight(event.getProperty().getValue().toString());
- }
- }, dimensionValues));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setHeight(event.getProperty().getValue().toString());
+ }
+ }, dimensionValues));
addComponent(createSimpleSelector("Caption",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- String value = event.getProperty().getValue()
- .toString();
- if (value.length() == 0) {
- setCaption(null);
- } else if (value.equals("Long")) {
- setCaption("A rather long caption just to see what happens");
- } else {
- setCaption(value);
- }
- }
- }, "", "Short", "Long"));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ String value = event.getProperty().getValue()
+ .toString();
+ if (value.length() == 0) {
+ setCaption(null);
+ } else if (value.equals("Long")) {
+ setCaption("A rather long caption just to see what happens");
+ } else {
+ setCaption(value);
+ }
+ }
+ }, "", "Short", "Long"));
addComponent(createSimpleSelector("Expand ratio",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- AbstractOrderedLayout parent = (AbstractOrderedLayout) getParent();
- if (parent == null) {
- return;
- }
- String value = event.getProperty().getValue()
- .toString();
- parent.setExpandRatio(SampleChild.this,
- Float.parseFloat(value));
- }
- }, "0", "1", "2"));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ AbstractOrderedLayout parent = (AbstractOrderedLayout) getParent();
+ if (parent == null) {
+ return;
+ }
+ String value = event.getProperty().getValue()
+ .toString();
+ parent.setExpandRatio(SampleChild.this,
+ Float.parseFloat(value));
+ }
+ }, "0", "1", "2"));
// Why is Alignment not an enum? Now we have to use reflection just
// to get the different values as hardcoding is never an option! ;)
@@ -83,29 +86,29 @@ public class OrderedLayoutCases extends AbstractTestUI {
}
addComponent(createSimpleSelector("Alignment",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- String value = event.getProperty().getValue()
- .toString();
- AlignmentHandler parent = (AlignmentHandler) getParent();
- if (parent == null) {
- return;
- }
- try {
- Field field = Alignment.class
- .getDeclaredField(value);
- Alignment alignment = (Alignment) field
- .get(null);
- parent.setComponentAlignment(SampleChild.this,
- alignment);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }, alignmentValues, "TOP_LEFT")); // Sorry for not using
- // more reflection magic
- // just to find the
- // default value...
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ String value = event.getProperty().getValue()
+ .toString();
+ AlignmentHandler parent = (AlignmentHandler) getParent();
+ if (parent == null) {
+ return;
+ }
+ try {
+ Field field = Alignment.class
+ .getDeclaredField(value);
+ Alignment alignment = (Alignment) field
+ .get(null);
+ parent.setComponentAlignment(SampleChild.this,
+ alignment);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }, alignmentValues, "TOP_LEFT")); // Sorry for not using
+ // more reflection magic
+ // just to find the
+ // default value...
}
}
@@ -116,12 +119,12 @@ public class OrderedLayoutCases extends AbstractTestUI {
@Override
protected void setup(WrappedRequest request) {
TestUtils
- .injectCSS(
- getUI(),
- ".sampleChild, .theLayout {border: 1px solid black;}"
- + ".theLayout > div:first-child {background: aqua;}"
- + ".theLayout > div:first-child + div {background: yellow;}"
- + ".theLayout > div:first-child + div + div {background: lightgrey;}");
+ .injectCSS(
+ getUI(),
+ ".sampleChild, .theLayout {border: 1px solid black;}"
+ + ".theLayout > div:first-child {background: aqua;}"
+ + ".theLayout > div:first-child + div {background: yellow;}"
+ + ".theLayout > div:first-child + div + div {background: lightgrey;}");
currentLayout = new HorizontalLayout();
for (int i = 0; i < 3; i++) {
@@ -133,196 +136,196 @@ public class OrderedLayoutCases extends AbstractTestUI {
sizeBar.addComponent(createSimpleSelector("Layout width",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- currentLayout.setWidth(event.getProperty().getValue()
- .toString());
- }
- }, dimensionValues));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ currentLayout.setWidth(event.getProperty().getValue()
+ .toString());
+ }
+ }, dimensionValues));
sizeBar.addComponent(createSimpleSelector("Layout height",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- currentLayout.setHeight(event.getProperty().getValue()
- .toString());
- }
- }, dimensionValues));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ currentLayout.setHeight(event.getProperty().getValue()
+ .toString());
+ }
+ }, dimensionValues));
sizeBar.addComponent(createSimpleSelector("Spacing",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- currentLayout.setSpacing(Boolean.parseBoolean(event
- .getProperty().getValue().toString()));
- }
- }, "false", "true"));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ currentLayout.setSpacing(Boolean.parseBoolean(event
+ .getProperty().getValue().toString()));
+ }
+ }, "false", "true"));
sizeBar.addComponent(createSimpleSelector("Margin",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- currentLayout.setMargin(Boolean.parseBoolean(event
- .getProperty().getValue().toString()));
- }
- }, "false", "true"));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ currentLayout.setMargin(Boolean.parseBoolean(event
+ .getProperty().getValue().toString()));
+ }
+ }, "false", "true"));
sizeBar.addComponent(createSimpleSelector("Direction",
new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- Object value = event.getProperty().getValue();
-
- AbstractOrderedLayout newLayout;
- if (value.equals("Horizontal")) {
- newLayout = new HorizontalLayout();
- } else {
- newLayout = new VerticalLayout();
- }
-
- while (currentLayout.getComponentCount() > 0) {
- newLayout.addComponent(currentLayout
- .getComponent(0));
- }
- newLayout.setStyleName("theLayout");
-
- newLayout.setHeight(currentLayout.getHeight(),
- currentLayout.getHeightUnits());
- newLayout.setWidth(currentLayout.getWidth(),
- currentLayout.getWidthUnits());
-
- newLayout.setMargin(currentLayout.getMargin());
- newLayout.setSpacing(currentLayout.isSpacing());
-
- getLayout().replaceComponent(currentLayout, newLayout);
- getLayout().setExpandRatio(newLayout, 1);
- currentLayout = newLayout;
- }
- }, "Horizontal", "Vertical"));
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ Object value = event.getProperty().getValue();
+
+ AbstractOrderedLayout newLayout;
+ if (value.equals("Horizontal")) {
+ newLayout = new HorizontalLayout();
+ } else {
+ newLayout = new VerticalLayout();
+ }
+
+ while (currentLayout.getComponentCount() > 0) {
+ newLayout.addComponent(currentLayout
+ .getComponent(0));
+ }
+ newLayout.setStyleName("theLayout");
+
+ newLayout.setHeight(currentLayout.getHeight(),
+ currentLayout.getHeightUnits());
+ newLayout.setWidth(currentLayout.getWidth(),
+ currentLayout.getWidthUnits());
+
+ newLayout.setMargin(currentLayout.getMargin());
+ newLayout.setSpacing(currentLayout.isSpacing());
+
+ getLayout().replaceComponent(currentLayout, newLayout);
+ getLayout().setExpandRatio(newLayout, 1);
+ currentLayout = newLayout;
+ }
+ }, "Horizontal", "Vertical"));
HorizontalLayout caseBar = new HorizontalLayout();
caseBar.addComponent(new Button("Undefined without relative",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- setState(sizeBar, 2, 1);
- // width: 350px to middle child
- setChildState(1, 0, 2);
- // middle center allign to middle child
- setChildState(1, 4, 5);
- // long captions to right child
- setChildState(2, 2, 2);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ setState(sizeBar, 2, 1);
+ // width: 350px to middle child
+ setChildState(1, 0, 2);
+ // middle center allign to middle child
+ setChildState(1, 4, 5);
+ // long captions to right child
+ setChildState(2, 2, 2);
+ }
+ }));
caseBar.addComponent(new Button("Undefined with relative",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // width: 100% to middle child
- setChildState(1, 0, 4);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // width: 100% to middle child
+ setChildState(1, 0, 4);
+ }
+ }));
caseBar.addComponent(new Button("Fixed with overflow",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // layout width: 350px
- setState(sizeBar, 0, 2);
- // layout margin enabled
- setState(sizeBar, 3, 1);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // layout width: 350px
+ setState(sizeBar, 0, 2);
+ // layout margin enabled
+ setState(sizeBar, 3, 1);
+ }
+ }));
caseBar.addComponent(new Button("Fixed with extra space",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // Layout width: 800px
- setState(sizeBar, 0, 3);
- // layout margin enabled
- setState(sizeBar, 3, 1);
- // width: 350px to middle child
- setChildState(1, 0, 2);
- // short caption for middle child
- setChildState(1, 2, 1);
- // top center align for middle child
- setChildState(1, 4, 2);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // Layout width: 800px
+ setState(sizeBar, 0, 3);
+ // layout margin enabled
+ setState(sizeBar, 3, 1);
+ // width: 350px to middle child
+ setChildState(1, 0, 2);
+ // short caption for middle child
+ setChildState(1, 2, 1);
+ // top center align for middle child
+ setChildState(1, 4, 2);
+ }
+ }));
caseBar.addComponent(new Button("Expand with alignment",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // Layout width: 800px
- setState(sizeBar, 0, 3);
- // Layout height: 350px
- setState(sizeBar, 1, 2);
- // Expand: 1 to middle child
- setChildState(1, 3, 1);
- // Align bottom left to middle child
- setChildState(1, 4, 6);
- // Long caption to middle child
- setChildState(1, 2, 2);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // Layout width: 800px
+ setState(sizeBar, 0, 3);
+ // Layout height: 350px
+ setState(sizeBar, 1, 2);
+ // Expand: 1 to middle child
+ setChildState(1, 3, 1);
+ // Align bottom left to middle child
+ setChildState(1, 4, 6);
+ // Long caption to middle child
+ setChildState(1, 2, 2);
+ }
+ }));
caseBar.addComponent(new Button("Multiple expands",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // Layout width: 800px
- setState(sizeBar, 0, 3);
- // Layout height: 350px
- setState(sizeBar, 1, 2);
- // Long caption to left child
- setChildState(0, 2, 2);
- // Width 350px to middle child
- setChildState(1, 0, 2);
- // Apply to left and middle child
- for (int i = 0; i < 2; i++) {
- // Expand: 1
- setChildState(i, 3, 1);
- // Align: middle center
- setChildState(i, 4, 5);
- }
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // Layout width: 800px
+ setState(sizeBar, 0, 3);
+ // Layout height: 350px
+ setState(sizeBar, 1, 2);
+ // Long caption to left child
+ setChildState(0, 2, 2);
+ // Width 350px to middle child
+ setChildState(1, 0, 2);
+ // Apply to left and middle child
+ for (int i = 0; i < 2; i++) {
+ // Expand: 1
+ setChildState(i, 3, 1);
+ // Align: middle center
+ setChildState(i, 4, 5);
+ }
+ }
+ }));
caseBar.addComponent(new Button("Fixed + relative height",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // Layout height: 100%
- setState(sizeBar, 1, 4);
- // Height: 350px to left child
- setChildState(0, 1, 2);
- // Height: 100% to middle child
- setChildState(1, 1, 4);
- // Short caption to middle child
- setChildState(1, 2, 1);
- // Alignment: bottom left to right child
- setChildState(2, 4, 7);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // Layout height: 100%
+ setState(sizeBar, 1, 4);
+ // Height: 350px to left child
+ setChildState(0, 1, 2);
+ // Height: 100% to middle child
+ setChildState(1, 1, 4);
+ // Short caption to middle child
+ setChildState(1, 2, 1);
+ // Alignment: bottom left to right child
+ setChildState(2, 4, 7);
+ }
+ }));
caseBar.addComponent(new Button("Undefined + relative height",
new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- resetState();
- // Height: 350px to left child
- setChildState(0, 1, 2);
- // Short caption to left child
- setChildState(0, 2, 1);
- // Height: 100% to middle child
- setChildState(1, 1, 4);
- // Alignment: bottom left to right child
- setChildState(2, 4, 7);
- }
- }));
+ @Override
+ public void buttonClick(ClickEvent event) {
+ resetState();
+ // Height: 350px to left child
+ setChildState(0, 1, 2);
+ // Short caption to left child
+ setChildState(0, 2, 1);
+ // Height: 100% to middle child
+ setChildState(1, 1, 4);
+ // Alignment: bottom left to right child
+ setChildState(2, 4, 7);
+ }
+ }));
caseBar.setSpacing(true);
diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/VaadinTunesLayout.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/VaadinTunesLayout.java
new file mode 100644
index 0000000000..973bd63d76
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/VaadinTunesLayout.java
@@ -0,0 +1,341 @@
+package com.vaadin.tests.components.orderedlayout;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.terminal.Sizeable;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.tests.components.AbstractTestRoot;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.HorizontalSplitPanel;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.Slider;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+
+@Theme("tests-components")
+public class VaadinTunesLayout extends AbstractTestRoot {
+
+ @Override
+ public void setup(WrappedRequest request) {
+
+ /*
+ * We'll build the whole UI here, since the application will not contain
+ * any logic. Otherwise it would be more practical to separate parts of
+ * the UI into different classes and methods.
+ */
+
+ // Main (browser) window, needed in all Vaadin applications
+ VerticalLayout rootLayout = new VerticalLayout();
+ // final Window root = new Window("VaadinTunes", rootLayout);
+
+ /*
+ * We'll attach the window to the browser view already here, so we won't
+ * forget it later.
+ */
+ setContent(rootLayout);
+
+ // root.showNotification(
+ // "This is an example of how you can do layouts in Vaadin.<br/>It is not a working sound player.",
+ // Notification.TYPE_HUMANIZED_MESSAGE);
+
+ // Our root window contains one VerticalLayout, let's make
+ // sure it's 100% sized, and remove unwanted margins
+ rootLayout.setSizeFull();
+ rootLayout.setMargin(false);
+
+ // Top area, containing playback and volume controls, play status, view
+ // modes and search
+ HorizontalLayout top = new HorizontalLayout();
+ top.setWidth("100%");
+ top.setMargin(false, true, false, true); // Enable horizontal margins
+ top.setSpacing(true);
+
+ // Let's attach that one straight away too
+ rootLayout.addComponent(top);
+
+ // Create the placeholders for all the components in the top area
+ HorizontalLayout playback = new HorizontalLayout();
+ HorizontalLayout volume = new HorizontalLayout();
+ HorizontalLayout status = new HorizontalLayout();
+ HorizontalLayout viewmodes = new HorizontalLayout();
+ ComboBox search = new ComboBox();
+
+ // Add the components and align them properly
+ top.addComponent(playback);
+ top.addComponent(volume);
+ top.addComponent(status);
+ top.addComponent(viewmodes);
+ top.addComponent(search);
+ top.setComponentAlignment(playback, Alignment.MIDDLE_LEFT);
+ top.setComponentAlignment(volume, Alignment.MIDDLE_LEFT);
+ top.setComponentAlignment(status, Alignment.MIDDLE_CENTER);
+ top.setComponentAlignment(viewmodes, Alignment.MIDDLE_LEFT);
+ top.setComponentAlignment(search, Alignment.MIDDLE_LEFT);
+
+ /*
+ * We want our status area to expand if the user resizes the root
+ * window, and we want it to accommodate as much space as there is
+ * available. All other components in the top layout should stay fixed
+ * sized, so we don't need to specify any expand ratios for them (they
+ * will automatically revert to zero after the following line).
+ */
+ top.setExpandRatio(status, 1.0F);
+
+ // Playback controls
+ Button prev = new NativeButton("Previous");
+ Button play = new NativeButton("Play/pause");
+ Button next = new NativeButton("Next");
+ playback.addComponent(prev);
+ playback.addComponent(play);
+ playback.addComponent(next);
+ // Set spacing between the buttons
+ playback.setSpacing(true);
+
+ // Volume controls
+ Button mute = new NativeButton("mute");
+ Slider vol = new Slider();
+ vol.setOrientation(Slider.ORIENTATION_HORIZONTAL);
+ vol.setWidth("100px");
+ Button max = new NativeButton("max");
+ volume.addComponent(mute);
+ volume.addComponent(vol);
+ volume.addComponent(max);
+
+ // Status area
+ status.setWidth("80%");
+ status.setSpacing(true);
+
+ Button toggleVisualization = new NativeButton("Mode");
+ Label timeFromStart = new Label("0:00");
+
+ // We'll need another layout to show currently playing track and
+ // progress
+ VerticalLayout trackDetails = new VerticalLayout();
+ trackDetails.setWidth("100%");
+ Label track = new Label("Track Name");
+ Label album = new Label("Album Name - Artist");
+ track.setWidth(null);
+ album.setWidth(null);
+ Slider progress = new Slider();
+ progress.setOrientation(Slider.ORIENTATION_HORIZONTAL);
+ progress.setWidth("100%");
+ trackDetails.addComponent(track);
+ trackDetails.addComponent(album);
+ trackDetails.addComponent(progress);
+ trackDetails.setComponentAlignment(track, Alignment.TOP_CENTER);
+ trackDetails.setComponentAlignment(album, Alignment.TOP_CENTER);
+
+ Label timeToEnd = new Label("-4:46");
+ Button jumpToTrack = new NativeButton("Show");
+
+ // Place all components to the status layout and align them properly
+ status.addComponent(toggleVisualization);
+ status.setComponentAlignment(toggleVisualization, Alignment.MIDDLE_LEFT);
+ status.addComponent(timeFromStart);
+ status.setComponentAlignment(timeFromStart, Alignment.BOTTOM_LEFT);
+ status.addComponent(trackDetails);
+ status.addComponent(timeToEnd);
+ status.setComponentAlignment(timeToEnd, Alignment.BOTTOM_LEFT);
+ status.addComponent(jumpToTrack);
+ status.setComponentAlignment(jumpToTrack, Alignment.MIDDLE_LEFT);
+
+ // Then remember to specify the expand ratio
+ status.setExpandRatio(trackDetails, 1.0F);
+
+ // View mode buttons
+ Button viewAsTable = new NativeButton("Table");
+ Button viewAsGrid = new NativeButton("Grid");
+ Button coverflow = new NativeButton("Coverflow");
+ viewmodes.addComponent(viewAsTable);
+ viewmodes.addComponent(viewAsGrid);
+ viewmodes.addComponent(coverflow);
+
+ /*
+ * That covers the top bar. Now let's move on to the sidebar and track
+ * listing
+ */
+
+ // We'll need one splitpanel to separate the sidebar and track listing
+ HorizontalSplitPanel bottom = new HorizontalSplitPanel();
+ rootLayout.addComponent(bottom);
+
+ // The splitpanel is by default 100% x 100%, but we'll need to adjust
+ // our main window layout to accomodate the height
+ rootLayout.setExpandRatio(bottom, 1.0F);
+
+ // Give the sidebar less space than the listing
+ bottom.setSplitPosition(200, Sizeable.UNITS_PIXELS);
+
+ // Let's add some content to the sidebar
+ // First, we need a layout to but all components in
+ VerticalLayout sidebar = new VerticalLayout();
+ sidebar.setSizeFull();
+ bottom.setFirstComponent(sidebar);
+
+ /*
+ * Then we need some labels and buttons, and an album cover image The
+ * labels and buttons go into their own vertical layout, since we want
+ * the 'sidebar' layout to be expanding (cover image in the bottom).
+ * VerticalLayout is by default 100% wide.
+ */
+ VerticalLayout selections = new VerticalLayout();
+ Label library = new Label("Library");
+ Button music = new NativeButton("Music");
+ music.setWidth("100%");
+
+ Label store = new Label("Store");
+ Button vaadinTunesStore = new NativeButton("VaadinTunes Store");
+ vaadinTunesStore.setWidth("100%");
+ Button purchased = new NativeButton("Purchased");
+ purchased.setWidth("100%");
+
+ Label playlists = new Label("Playlists");
+ Button genius = new NativeButton("Geniues");
+ genius.setWidth("100%");
+ Button recent = new NativeButton("Recently Added");
+ recent.setWidth("100%");
+
+ // Lets add them to the 'selections' layout
+ selections.addComponent(library);
+ selections.addComponent(music);
+ selections.addComponent(store);
+ selections.addComponent(vaadinTunesStore);
+ selections.addComponent(purchased);
+ selections.addComponent(playlists);
+ selections.addComponent(genius);
+ selections.addComponent(recent);
+
+ // Then add the selections to the sidebar, and set it expanding
+ sidebar.addComponent(selections);
+ sidebar.setExpandRatio(selections, 1.0F);
+
+ // Then comes the cover artwork (we'll add the actual image in the
+ // themeing section)
+ Embedded cover = new Embedded("Currently Playing");
+ sidebar.addComponent(cover);
+
+ /*
+ * And lastly, we need the track listing table It should fill the whole
+ * left side of our bottom layout
+ */
+ Table listing = new Table();
+ listing.setSizeFull();
+ listing.setSelectable(true);
+ bottom.setSecondComponent(listing);
+
+ // Add the table headers
+ listing.addContainerProperty("Name", String.class, "");
+ listing.addContainerProperty("Time", String.class, "0:00");
+ listing.addContainerProperty("Artist", String.class, "");
+ listing.addContainerProperty("Album", String.class, "");
+ listing.addContainerProperty("Genre", String.class, "");
+ listing.addContainerProperty("Rating", NativeSelect.class,
+ new NativeSelect());
+
+ // Lets populate the table with random data
+ String[] tracks = new String[] { "Red Flag", "Millstone",
+ "Not The Sun", "Breath", "Here We Are", "Deep Heaven",
+ "Her Voice Resides", "Natural Tan", "End It All", "Kings",
+ "Daylight Slaving", "Mad Man", "Resolve", "Teargas",
+ "African Air", "Passing Bird" };
+ String[] times = new String[] { "4:12", "6:03", "5:43", "4:32", "3:42",
+ "4:45", "2:56", "9:34", "2:10", "3:44", "5:49", "6:30", "5:18",
+ "7:42", "3:13", "2:52" };
+ String[] artists = new String[] { "Billy Talent", "Brand New",
+ "Breaking Benjamin", "Becoming The Archetype",
+ "Bullet For My Valentine", "Chasing Victory", "Chimaira",
+ "Danko Jones", "Deadlock", "Deftones", "From Autumn To Ashes",
+ "Haste The Day", "Four Year Strong", "In Flames", "Kemopetrol",
+ "John Legend" };
+ String[] albums = new String[] { "Once Again", "The Caitiff Choir",
+ "The Devil And God", "Light Grenades", "Dicthonomy",
+ "Back In Black", "Dreamer", "Come Clarity", "Year Zero",
+ "Frames", "Fortress", "Phobia", "The Poison", "Manifesto",
+ "White Pony", "The Big Dirty" };
+ String[] genres = new String[] { "Rock", "Metal", "Hardcore", "Indie",
+ "Pop", "Alternative", "Blues", "Jazz", "Hip Hop",
+ "Electronica", "Punk", "Hard Rock", "Dance", "R'n'B", "Gospel",
+ "Country" };
+ for (int i = 0; i < 1000; i++) {
+ NativeSelect s = new NativeSelect();
+ s.addItem("1 star");
+ s.addItem("2 stars");
+ s.addItem("3 stars");
+ s.addItem("4 stars");
+ s.addItem("5 stars");
+ s.select(i % 5 + " stars");
+ final int index = i % 16;
+ listing.addItem(new Object[] { tracks[index], times[index],
+ artists[index], albums[index], genres[index], s }, i);
+ }
+
+ // We'll align the track time column to right as well
+ listing.setColumnAlignment("Time", Table.ALIGN_RIGHT);
+
+ // TODO the footer
+
+ // Now what's left to do? Themeing of course.
+ // setTheme("vaadintunes");
+
+ /*
+ * Let's give a namespace to our application window. This way, if
+ * someone uses the same theme for different applications, we don't get
+ * unwanted style conflicts.
+ */
+ // root.setStyleName("tTunes");
+
+ top.setStyleName("top");
+ top.setHeight("75px"); // Same as the background image height
+
+ playback.setStyleName("playback");
+ playback.setMargin(false, true, false, false); // Add right-side margin
+ play.setStyleName("play");
+ next.setStyleName("next");
+ prev.setStyleName("prev");
+ playback.setComponentAlignment(prev, Alignment.MIDDLE_LEFT);
+ playback.setComponentAlignment(next, Alignment.MIDDLE_LEFT);
+
+ volume.setStyleName("volume");
+ mute.setStyleName("mute");
+ max.setStyleName("max");
+ vol.setWidth("78px");
+
+ status.setStyleName("status");
+ status.setMargin(true);
+ status.setHeight("46px"); // Height of the background image
+
+ toggleVisualization.setStyleName("toggle-vis");
+ jumpToTrack.setStyleName("jump");
+
+ viewAsTable.setStyleName("viewmode-table");
+ viewAsGrid.setStyleName("viewmode-grid");
+ coverflow.setStyleName("viewmode-coverflow");
+
+ sidebar.setStyleName("sidebar");
+
+ music.setStyleName("selected");
+
+ cover.setSource(new ThemeResource("images/album-cover.jpg"));
+ // Because this is an image, it will retain it's aspect ratio
+ cover.setWidth("100%");
+ }
+
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+} \ No newline at end of file
diff --git a/tests/testbench/com/vaadin/tests/components/table/TextFieldRelativeWidth.java b/tests/testbench/com/vaadin/tests/components/table/TextFieldRelativeWidth.java
index ae3f4c42a4..5c7479d060 100644
--- a/tests/testbench/com/vaadin/tests/components/table/TextFieldRelativeWidth.java
+++ b/tests/testbench/com/vaadin/tests/components/table/TextFieldRelativeWidth.java
@@ -27,8 +27,7 @@ public class TextFieldRelativeWidth extends TestBase {
public class EditTable extends Table implements Button.ClickListener {
- private Button addButton = new Button("Add new row",
- (Button.ClickListener) this);
+ private Button addButton = new Button("Add new row", this);
private String inputPrompt;
diff --git a/tests/testbench/com/vaadin/tests/themes/LiferayThemeTest.java b/tests/testbench/com/vaadin/tests/themes/LiferayThemeTest.java
new file mode 100644
index 0000000000..fa15d88799
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/themes/LiferayThemeTest.java
@@ -0,0 +1,37 @@
+package com.vaadin.tests.themes;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.tests.components.AbstractTestRoot;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.themes.LiferayTheme;
+
+@Theme("liferay")
+public class LiferayThemeTest extends AbstractTestRoot {
+
+ @Override
+ protected void setup(WrappedRequest request) {
+ Panel p = new Panel("Panel");
+ addComponent(p);
+ p.addComponent(new Label("Panel content"));
+
+ p = new Panel("Light Panel");
+ p.addStyleName(LiferayTheme.PANEL_LIGHT);
+ addComponent(p);
+ p.addComponent(new Label("Panel content"));
+ }
+
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}