diff options
1222 files changed, 51841 insertions, 35113 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..42a4e9cc07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ + +# / +/.classpath +/.cvsignore +/.project +/.tomcatplugin +/.settings +/work +/.gwt-cache +/.externalToolBuilders +/extras + +# /WebContent/VAADIN/themes/base/ +/WebContent/VAADIN/themes/base/styles.css + +# /WebContent/VAADIN/themes/chameleon/ +/WebContent/VAADIN/themes/chameleon/styles.css + +# /WebContent/VAADIN/themes/liferay/ +/WebContent/VAADIN/themes/liferay/styles.css + +# /WebContent/VAADIN/themes/reindeer/ +/WebContent/VAADIN/themes/reindeer/styles.css + +# /WebContent/VAADIN/themes/reindeer/button/img/ +/WebContent/VAADIN/themes/reindeer/button/img/*-sprites*.png + +# /WebContent/VAADIN/themes/reindeer/common/img/ +/WebContent/VAADIN/themes/reindeer/common/img/*-sprites*.png + +# /WebContent/VAADIN/themes/runo/ +/WebContent/VAADIN/themes/runo/styles.css + +# /WebContent/VAADIN/themes/runo/common/img/ +/WebContent/VAADIN/themes/runo/common/img/ajax-loader-red.gif +/WebContent/VAADIN/themes/runo/common/img/ajax-loader-yellow.gif + +# /WebContent/VAADIN/widgetsets/ +/WebContent/VAADIN/widgetsets +/WebContent/VAADIN/gwt-unitCache* + +# /WebContent/WEB-INF/ +/WebContent/WEB-INF/classes + +# /build/ +/build/result +/build/gwt +/build/checkout +/build/classes +/build/test-output +/build/integration-test-output +/build/buildhelpers/com/vaadin/buildhelpers/*.class + +# /bin/ +/bin + +# Mac +*.DS_Store diff --git a/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css b/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css index b2c2ed2858..4373c52922 100644 --- a/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css +++ b/WebContent/VAADIN/themes/base/absolutelayout/absolutelayout.css @@ -1,4 +1,15 @@ .v-absolutelayout-wrapper { position: absolute; overflow: hidden; -}
\ No newline at end of file +} +.v-absolutelayout-margin, .v-absolutelayout-canvas { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.v-absolutelayout.v-has-height > div, .v-absolutelayout.v-has-height > div > div { + height: 100%; +} +.v-absolutelayout.v-has-width > div, .v-absolutelayout.v-has-width > div > div { + width: 100%; +} diff --git a/WebContent/VAADIN/themes/base/button/button.css b/WebContent/VAADIN/themes/base/button/button.css index 48d30d4576..2e14d59a90 100644 --- a/WebContent/VAADIN/themes/base/button/button.css +++ b/WebContent/VAADIN/themes/base/button/button.css @@ -29,14 +29,6 @@ cursor: default; } -.v-ie6 .v-button { - display: inline; -} - -.v-ie7 .v-button { - display: inline; -} - .v-button-wrap, .v-button-caption { vertical-align: middle; @@ -117,10 +109,7 @@ zoom: 1; float: none; } -/* Fixes streched buttons in IE6 and IE7*/ -.v-ie6 .v-nativebutton { - width: 1px; -} +/* Fixes stretched buttons in IE7*/ .v-ie .v-nativebutton { overflow: visible; padding-left: 1em; @@ -147,12 +136,6 @@ white-space: nowrap; } -/* Fix for IE6/IE7 issue where checkbox moves 1 pixel down after selection (#4636) */ -.v-ie6 .v-checkbox, -.v-ie7 .v-checkbox { - vertical-align: baseline; -} - .v-checkbox .v-icon { margin: 0 2px; } diff --git a/WebContent/VAADIN/themes/base/caption/caption.css b/WebContent/VAADIN/themes/base/caption/caption.css index bdeaae3de2..364b68a226 100644 --- a/WebContent/VAADIN/themes/base/caption/caption.css +++ b/WebContent/VAADIN/themes/base/caption/caption.css @@ -6,40 +6,18 @@ white-space: nowrap; } .v-errorindicator { - float: left; + display: inline-block; } .v-caption .v-icon { - float: left; + display: inline-block; padding-right: 2px; vertical-align: middle; } .v-caption .v-captiontext { - float: left; + display: inline-block; overflow: hidden; vertical-align: middle; } .v-caption .v-required-field-indicator { - float: left; + display: inline-block; } - -.v-caption-clearelem { - clear: both; - width: 0; - height: 0; - overflow: hidden; -} - -/* Fix IE6 "double-float-margin-bug" */ -.v-ie6 .v-errorindicator, -.v-ie6 .v-icon, -.v-ie6 .v-captiontext, -.v-ie6 .v-required-field-indicator { - display: inline; -} - -.v-ie9 .v-gridlayout-margin>div>div>.v-caption, -.v-ie9 .v-verticallayout>div>div>.v-caption, -.v-ie9 .v-horizontallayout>div>div>.v-caption { - /* Fix possible sub pixel rounding errors that cause error indicators to drop */ - margin-right:-0.5px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/common/common.css b/WebContent/VAADIN/themes/base/common/common.css index 27bc57dd00..3c08a9d584 100644 --- a/WebContent/VAADIN/themes/base/common/common.css +++ b/WebContent/VAADIN/themes/base/common/common.css @@ -32,9 +32,12 @@ div.v-app-loading { overflow: auto; /* avoid scrollbars with margins in root layout */ outline: none; + position: relative; +} +/* Prevent margin collapse */ +.v-view.v-view-embedded { margin-top: -1px; border-top: 1px solid transparent; - position: relative; } /** * Try to handle printing somehow. Reasonable printing support @@ -90,7 +93,15 @@ div.v-app-loading { border: none; padding: 0; margin: 0; + height: 100%; +} +.v-form-content { + height: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + /* Field modified */ /* Disabled by default .v-modified, .v-richtextarea.v-modified iframe.gwt-RichTextArea, @@ -229,4 +240,8 @@ div.v-app-loading { opacity: 0.5; filter: alpha(opacity=50); cursor: default; +} + +.v-clip { + overflow: hidden; }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/csslayout/csslayout.css b/WebContent/VAADIN/themes/base/csslayout/csslayout.css index 1f85d6f460..064edd28a4 100644 --- a/WebContent/VAADIN/themes/base/csslayout/csslayout.css +++ b/WebContent/VAADIN/themes/base/csslayout/csslayout.css @@ -1,6 +1,19 @@ .v-csslayout { overflow: hidden; } +.v-csslayout-margin, .v-csslayout-container { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.v-has-width > .v-csslayout-margin, +.v-has-width > .v-csslayout-margin > .v-csslayout-container { + width: 100%; +} +.v-has-height > .v-csslayout-margin, +.v-has-height > .v-csslayout-margin > .v-csslayout-container { + height: 100%; +} .v-csslayout-margin-top { padding-top: 12px; } diff --git a/WebContent/VAADIN/themes/base/datefield/datefield.css b/WebContent/VAADIN/themes/base/datefield/datefield.css index 8e2e9aeb2b..7af440c735 100644 --- a/WebContent/VAADIN/themes/base/datefield/datefield.css +++ b/WebContent/VAADIN/themes/base/datefield/datefield.css @@ -64,16 +64,6 @@ color: #666; } -.v-ie6 .v-datefield-calendarpanel-day, -.v-ie7 .v-datefield-calendarpanel-day { - margin: 1px; -} -.v-ie6 .v-datefield-calendarpanel-day-focused, -.v-ie7 .v-datefield-calendarpanel-day-focused { - border: 1px dotted black; - margin: 0px; -} - .v-datefield-time { white-space: nowrap; } @@ -97,10 +87,3 @@ background-color: #ffe0e0; } */ -/* IE somehow loses generic v-disabled alpha. See #1960 */ -.v-ie6 .v-disabled .v-datefield-button, -.v-ie6 .v-disabled .v-datefield-textfield, -.v-ie7 .v-disabled .v-datefield-button, -.v-ie7 .v-disabled .v-datefield-textfield { - filter: alpha(opacity=30); -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/formlayout/formlayout.css b/WebContent/VAADIN/themes/base/formlayout/formlayout.css index 9566ff1663..755a59bc89 100644 --- a/WebContent/VAADIN/themes/base/formlayout/formlayout.css +++ b/WebContent/VAADIN/themes/base/formlayout/formlayout.css @@ -1,3 +1,9 @@ +.v-formlayout.v-has-width > table { + width: 100%; +} +.v-formlayout.v-has-height > table { + height: 100%; +} .v-formlayout-cell .v-errorindicator { display: block; } @@ -9,6 +15,9 @@ text-align:right; white-space: nowrap; } +.v-formlayout-errorcell, .v-formlayout-captioncell { + width: 1px; /* Don't use any extra space */ +} .v-formlayout-captioncell .v-caption { overflow: visible; } diff --git a/WebContent/VAADIN/themes/base/gridlayout/gridlayout.css b/WebContent/VAADIN/themes/base/gridlayout/gridlayout.css index 87cdcfd361..9edaf152a0 100644 --- a/WebContent/VAADIN/themes/base/gridlayout/gridlayout.css +++ b/WebContent/VAADIN/themes/base/gridlayout/gridlayout.css @@ -1,3 +1,9 @@ +.v-gridlayout { + position: relative; +} +.v-gridlayout-slot { + position: absolute; +} .v-gridlayout-margin-top { padding-top: 12px; } @@ -23,8 +29,3 @@ .v-gridlayout-spacing-off { overflow: hidden; } -/* Ensure that resizing gridlayout works in IE */ -.v-ie6 .v-gridlayout, -.v-ie7 .v-gridlayout { - overflow: hidden; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/label/label.css b/WebContent/VAADIN/themes/base/label/label.css new file mode 100644 index 0000000000..366dbdf26f --- /dev/null +++ b/WebContent/VAADIN/themes/base/label/label.css @@ -0,0 +1,3 @@ +.v-label { + overflow: hidden; +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/menubar/menubar.css b/WebContent/VAADIN/themes/base/menubar/menubar.css index 8b44085c28..943d0dcc21 100644 --- a/WebContent/VAADIN/themes/base/menubar/menubar.css +++ b/WebContent/VAADIN/themes/base/menubar/menubar.css @@ -1,6 +1,7 @@ .v-menubar { float: left; /* Force minimum width */ white-space: nowrap; + overflow: hidden; } .v-menubar .v-menubar-menuitem { cursor: default; diff --git a/WebContent/VAADIN/themes/base/orderedlayout/orderedlayout.css b/WebContent/VAADIN/themes/base/orderedlayout/orderedlayout.css index 9f91669385..727ca92f72 100644 --- a/WebContent/VAADIN/themes/base/orderedlayout/orderedlayout.css +++ b/WebContent/VAADIN/themes/base/orderedlayout/orderedlayout.css @@ -1,3 +1,9 @@ +.v-orderedlayout, +.v-horizontallayout, +.v-verticallayout { + position: relative; +} + .v-orderedlayout-margin-top, .v-horizontallayout-margin-top, .v-verticallayout-margin-top { @@ -31,12 +37,7 @@ padding-top: 0; padding-left: 0; } -/* To make sure IE don't expand elements larger than they should */ -.v-ie6 .v-orderedlayout, -.v-ie6 .v-horizontallayout, -.v-ie6 .v-verticallayout, -.v-ie7 .v-orderedlayout, -.v-ie7 .v-horizontallayout, -.v-ie7 .v-verticallayout { - overflow: hidden; + +.v-horizontallayout-slot, .v-verticallayout-slot { + position: absolute; } diff --git a/WebContent/VAADIN/themes/base/paintable/paintable.css b/WebContent/VAADIN/themes/base/paintable/paintable.css new file mode 100644 index 0000000000..41fc0ef287 --- /dev/null +++ b/WebContent/VAADIN/themes/base/paintable/paintable.css @@ -0,0 +1,5 @@ +.v-connector { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/panel/panel.css b/WebContent/VAADIN/themes/base/panel/panel.css index 126d3da91c..489d6bc015 100644 --- a/WebContent/VAADIN/themes/base/panel/panel.css +++ b/WebContent/VAADIN/themes/base/panel/panel.css @@ -30,6 +30,15 @@ } .v-panel-content { overflow: auto; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.v-panel.v-has-width > .v-panel-content { + width: 100%; +} +.v-panel.v-has-height > .v-panel-content { + height: 100%; } .v-panel-deco { }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/progressindicator/progressindicator.css b/WebContent/VAADIN/themes/base/progressindicator/progressindicator.css index a9a90c4b06..4037802cf2 100644 --- a/WebContent/VAADIN/themes/base/progressindicator/progressindicator.css +++ b/WebContent/VAADIN/themes/base/progressindicator/progressindicator.css @@ -1,21 +1,17 @@ .v-progressindicator { - overflow: hidden; /* for IE6 */ width: 150px; } .v-progressindicator-wrapper { - overflow: hidden; /* for IE6 */ height: 7px; border: 1px solid #ddd; } .v-progressindicator-indicator { height: 7px; - overflow: hidden; /* for IE6 */ background: #ddd; } div.v-progressindicator-indeterminate { height: 20px; width: 20px; - overflow: hidden; /* for IE6 */ background: #fff url(../common/img/ajax-loader-medium.gif) no-repeat 50%; border-radius: 4px; -webkit-border-radius: 4px; @@ -31,6 +27,5 @@ div.v-progressindicator-indeterminate { div.v-progressindicator-indeterminate-disabled { height: 20px; width: 20px; - overflow: hidden; /* for IE6 */ background: transparent; }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/select/select.css b/WebContent/VAADIN/themes/base/select/select.css index 4487bc6a4e..b9d0dda51f 100644 --- a/WebContent/VAADIN/themes/base/select/select.css +++ b/WebContent/VAADIN/themes/base/select/select.css @@ -56,6 +56,7 @@ .v-filterselect { white-space: nowrap; text-align: left; + display: inline-block; } .v-filterselect .v-icon { float: left; @@ -63,15 +64,19 @@ .v-app .v-filterselect-input, .v-window .v-filterselect-input, .v-popupview-popup .v-filterselect-input { + margin: 0; float: left; -webkit-border-radius: 0px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .v-filterselect-prompt .v-filterselect-input { color: #999; font-style: italic; } .v-filterselect-button { - float: right; + display: inline-block; cursor: pointer; width: 1em; height: 1em; diff --git a/WebContent/VAADIN/themes/base/shadow/shadow.css b/WebContent/VAADIN/themes/base/shadow/shadow.css index 209dd0e235..c576a026bd 100644 --- a/WebContent/VAADIN/themes/base/shadow/shadow.css +++ b/WebContent/VAADIN/themes/base/shadow/shadow.css @@ -66,20 +66,3 @@ width: 10px; height: 10px; background: transparent url(img/bottom-right.png); } - - - - - -/* For IE6 (no transparent png's, we use a blur filter) */ - -.v-ie6 .v-shadow * { - display: none; -} - -.v-ie6 .v-shadow { - background: #000; - filter: progid:DXImageTransform.Microsoft.Blur(pixelRadius=2) alpha(opacity=20); - margin-top: -2px; - margin-left: -2px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/slider/slider.css b/WebContent/VAADIN/themes/base/slider/slider.css index 5ee6cbf31c..1be474f04e 100644 --- a/WebContent/VAADIN/themes/base/slider/slider.css +++ b/WebContent/VAADIN/themes/base/slider/slider.css @@ -63,15 +63,3 @@ background: #FFE0E0; } */ - -/* IE specific styles */ -.v-ie6 .v-slider, -.v-ie6 .v-slider-vertical { - margin: 0; -} -.v-ie6 .v-slider .v-slider-handle { - margin: -1px 0; -} -.v-ie6 .v-slider-vertical .v-slider-handle { - margin: 0 -1px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/splitpanel/splitpanel.css b/WebContent/VAADIN/themes/base/splitpanel/splitpanel.css index 80a2133b23..7831a8d9ce 100644 --- a/WebContent/VAADIN/themes/base/splitpanel/splitpanel.css +++ b/WebContent/VAADIN/themes/base/splitpanel/splitpanel.css @@ -4,11 +4,9 @@ } .v-splitpanel-hsplitter { width: 6px; - font-size: 1px; /* for IE6 */ } .v-splitpanel-hsplitter div { width: 6px; - font-size: 1px; /* for IE6 */ position: absolute; top: 0; bottom: 0; @@ -21,11 +19,9 @@ } .v-splitpanel-vsplitter { height: 6px; - font-size: 1px; /* for IE6 */ } .v-splitpanel-vsplitter div { height: 6px; - font-size: 1px; /* for IE6 */ background: #ddd; cursor: s-resize; cursor: row-resize; @@ -33,13 +29,3 @@ .v-disabled .v-splitpanel-vsplitter div { cursor: default; } -/* IE specific styles */ -.v-ie6 .v-splitpanel-hsplitter div { - height: 99%; -} -.v-ie6 .v-splitpanel-first-container, -.v-ie6 .v-splitpanel-second-container, -.v-ie7 .v-splitpanel-first-container, -.v-ie7 .v-splitpanel-second-container { - position: relative; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/table/table.css b/WebContent/VAADIN/themes/base/table/table.css index 2c1e3d9593..653063ccb5 100644 --- a/WebContent/VAADIN/themes/base/table/table.css +++ b/WebContent/VAADIN/themes/base/table/table.css @@ -26,9 +26,6 @@ overflow: hidden; text-align: left; /* Force default alignment */ } -.v-ie7 .v-table { - overflow: visible; -} .v-table-header-wrap { overflow: hidden; border: 1px solid #aaa; @@ -102,10 +99,6 @@ white-space: nowrap; margin-left: 6px; } -.v-ie7 .v-table-caption-container-align-right { - margin-left: 0px; - padding-left: 6px; -} .v-table-caption-container-align-right { float: right; } @@ -193,10 +186,6 @@ .v-table.v-disabled .v-table-column-selector { cursor: default; } -.v-ie6 .v-table-column-selector, -.v-ie7 .v-table-column-selector { - position: static; -} .v-table-focus-slot-left { border-left: 2px solid #999; float: none; diff --git a/WebContent/VAADIN/themes/base/tabsheet/tabsheet.css b/WebContent/VAADIN/themes/base/tabsheet/tabsheet.css index 7288d32d89..d369cd99f0 100644 --- a/WebContent/VAADIN/themes/base/tabsheet/tabsheet.css +++ b/WebContent/VAADIN/themes/base/tabsheet/tabsheet.css @@ -39,9 +39,6 @@ text-align: right; margin-top: -1em; } -.v-ff2 .v-tabsheet-scroller { - position: relative; -} .v-disabled .v-tabsheet-scroller { display: none; } @@ -84,13 +81,9 @@ cursor: default; visibility: hidden; } -.v-tabsheet-tabitem:hover .v-tabsheet-caption-close, -.v-ie6 .v-tabsheet-caption-close { +.v-tabsheet-tabitem:hover .v-tabsheet-caption-close { visibility: visible; } -.v-ie6 .v-tabsheet-caption-close { - float: right; -} .v-tabsheet-tabitem { border: 1px solid #aaa; border-right: none; @@ -118,10 +111,6 @@ border-bottom: none; position: relative; } -.v-ie6 .v-tabsheet-content, -.v-ie7 .v-tabsheet-content { - zoom: 1; -} .v-tabsheet-deco { height: 1px; background: #aaa; diff --git a/WebContent/VAADIN/themes/base/tree/img/connector-collapse-ie6.png b/WebContent/VAADIN/themes/base/tree/img/connector-collapse-ie6.png Binary files differdeleted file mode 100644 index f0e5953235..0000000000 --- a/WebContent/VAADIN/themes/base/tree/img/connector-collapse-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/base/tree/img/connector-collapse-last-ie6.png b/WebContent/VAADIN/themes/base/tree/img/connector-collapse-last-ie6.png Binary files differdeleted file mode 100644 index 0d2fd54885..0000000000 --- a/WebContent/VAADIN/themes/base/tree/img/connector-collapse-last-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/base/tree/img/connector-expand-ie6.png b/WebContent/VAADIN/themes/base/tree/img/connector-expand-ie6.png Binary files differdeleted file mode 100644 index 1a7758fce5..0000000000 --- a/WebContent/VAADIN/themes/base/tree/img/connector-expand-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/base/tree/img/connector-expand-last-ie6.png b/WebContent/VAADIN/themes/base/tree/img/connector-expand-last-ie6.png Binary files differdeleted file mode 100644 index db94fc0d8e..0000000000 --- a/WebContent/VAADIN/themes/base/tree/img/connector-expand-last-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/base/tree/tree-connectors.css b/WebContent/VAADIN/themes/base/tree/tree-connectors.css index 6e7ce45391..c60e41c48b 100644 --- a/WebContent/VAADIN/themes/base/tree/tree-connectors.css +++ b/WebContent/VAADIN/themes/base/tree/tree-connectors.css @@ -33,17 +33,3 @@ .v-tree-connectors .v-tree-node-drag-top.v-tree-node-leaf { background-position: 2px 50%; } - -/* IE6 */ -.v-ie6 .v-tree-connectors .v-tree-node { - background: transparent url(img/connector-expand-ie6.png) no-repeat 2px -52px; -} -.v-ie6 .v-tree-connectors .v-tree-node-expanded { - background: transparent url(img/connector-collapse-ie6.png) no-repeat 2px -52px; -} -.v-ie6 .v-tree-connectors .v-tree-node-last { - background: transparent url(img/connector-expand-last-ie6.png) no-repeat 2px -52px; -} -.v-ie6 .v-tree-connectors .v-tree-node-last.v-tree-node-expanded { - background: transparent url(img/connector-collapse-last-ie6.png) no-repeat 2px -52px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/base/tree/tree-default.css b/WebContent/VAADIN/themes/base/tree/tree-default.css index c486233ea8..23721c77ae 100644 --- a/WebContent/VAADIN/themes/base/tree/tree-default.css +++ b/WebContent/VAADIN/themes/base/tree/tree-default.css @@ -37,27 +37,6 @@ div.v-tree-node-leaf { .v-tree-node-children { padding-left: 1em; } -/* ie6compatnode is hidden from non ie6 browsers, for ie6 - * uses weird hack to sink all events properly - */ -.v-tree-node-ie6compatnode { - display: none; -} -/* IMPORTANT keep the offsetWidth of this element the same as the margin-left of v-tree-node-caption */ -.v-ie6 .v-tree-node-ie6compatnode { - display: inline; - float: left; - background: orange; - margin: 0; - width: 0.8em; - height: 0.8em; - padding: 0.1em; - filter: alpha(opacity=0); -} -.v-ie6 .v-tree-node, -.v-ie6 .v-tree-node-children { - clear: left; -} /*************************************** * Drag'n'drop styles ***************************************/ @@ -106,9 +85,6 @@ div.v-tree-node-leaf { margin: -2px 2px -2px -2px; background-color: #bcdcff; } -.v-ie6 .v-tree .v-tree-node-caption-drag-center div { - margin: -2px ; -} .v-tree .v-tree-node-caption-drag-center div { background-color: rgba(169,209,255,.6); } diff --git a/WebContent/VAADIN/themes/base/treetable/treetable.css b/WebContent/VAADIN/themes/base/treetable/treetable.css index 1bc21b890c..de505ba774 100644 --- a/WebContent/VAADIN/themes/base/treetable/treetable.css +++ b/WebContent/VAADIN/themes/base/treetable/treetable.css @@ -5,26 +5,15 @@ /* defines the amount of indent per level */ width: 18px; } -.v-ie7 .v-treetable-treespacer{ - height: 100%; /* #7388 */ -} .v-treetable-node-closed { background: url(../treetable/img/arrow-right.png) right center no-repeat; } -.v-ie6 .v-treetable-node-closed { - background-image: url(../treetable/img/arrow-right.gif); -} - .v-treetable-node-open { background: url(../treetable/img/arrow-down.png) right center no-repeat; } -.v-ie6 .v-treetable-node-open { - background-image: url(../treetable/img/arrow-down.gif); -} - .v-treetable .v-checkbox { display: inline-block; padding-bottom: 4px; diff --git a/WebContent/VAADIN/themes/base/upload/upload.css b/WebContent/VAADIN/themes/base/upload/upload.css index e6b58fb14e..adc5751d7c 100644 --- a/WebContent/VAADIN/themes/base/upload/upload.css +++ b/WebContent/VAADIN/themes/base/upload/upload.css @@ -2,10 +2,6 @@ white-space: nowrap; } -.v-ie6 .v-upload, -.v-ie7 .v-upload { - margin:0; -} .v-upload-immediate { position: relative; diff --git a/WebContent/VAADIN/themes/base/window/window.css b/WebContent/VAADIN/themes/base/window/window.css index 398238426e..d728e7f60e 100644 --- a/WebContent/VAADIN/themes/base/window/window.css +++ b/WebContent/VAADIN/themes/base/window/window.css @@ -1,16 +1,39 @@ .v-window { background: #fff; } +.v-window-contents { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.v-window.v-has-width > div.popupContent, +.v-window.v-has-width .v-window-wrap, +.v-window.v-has-width .v-window-contents, +.v-window.v-has-width .v-window-contents > div { + width: 100%; +} + +.v-window.v-has-height > div.popupContent, +.v-window.v-has-height .v-window-wrap, +.v-window.v-has-height .v-window-contents, +.v-window.v-has-height .v-window-contents > div { + height: 100%; +} + .v-window-outerheader { padding: 0.3em 1em; - height: 1em; + height: 1.6em; + position: relative; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .v-window-outerheader, .v-window-draggingCurtain { cursor: move; } - .v-window-header { font-weight: bold; } @@ -22,21 +45,9 @@ div.v-window-header { overflow: hidden; padding: 0; } -.v-ie6 .v-window-header { - width: 100%; -} .v-window-header .v-icon { vertical-align: middle; /* This has to be 'middle', not 'bottom', to allow larger icons than 16px */ } -/* Partial fix for bug #1106 */ -/* Target Firefox 2 (somehow this will force almost all window borders on top of a Flash object) */ -.v-window-contents, x:-moz-any-link { - overflow: hidden; -} -/* Target Firefox 3 (it doesn't need any trickery, so revert the previous) */ -.v-window-contents, x:-moz-any-link, x:default { - overflow: visible; -} .v-window-contents > div { outline: none; } @@ -88,15 +99,6 @@ div.v-window-header { height: 100%; filter: alpha(opacity=50); } -/* IE6 workaround for position:fixed; */ -.v-ie6 .v-window-modalitycurtain { - position: absolute; - top: expression(document.documentElement.scrollTop + "px"); -} -/* min-width for IE6 */ -.v-ie6 .v-window { - width: 0; /* */ -} /* Shadow for window */ .v-shadow-window { position: absolute; @@ -158,13 +160,3 @@ div.v-window-header { width: 28px; height: 28px; background: transparent url(img/shadow/bottom-right.png); } -/* For IE6 (no transparent png's, we use a blur filter) */ -.v-ie6 .v-shadow-window * { - display: none; -} -.v-ie6 .v-shadow-window { - background: #000; - filter: progid:DXImageTransform.Microsoft.Blur(pixelRadius=5) alpha(opacity=20); - margin-top: 2px; - margin-left: 2px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/common/common.css b/WebContent/VAADIN/themes/chameleon/common/common.css index e1a5bdce7a..9d5a64b2ad 100644 --- a/WebContent/VAADIN/themes/chameleon/common/common.css +++ b/WebContent/VAADIN/themes/chameleon/common/common.css @@ -28,8 +28,7 @@ -moz-border-radius: 4px; } -.v-sa .v-tooltip, -.v-ff3 .v-tooltip { +.v-sa .v-tooltip { outline: 1px solid rgba(0,0,0,.2); -webkit-border-radius: 0; -moz-border-radius: 0; @@ -98,16 +97,6 @@ overflow: hidden; } -.v-ie6 .v-window, -.v-ie6 .v-popupview-popup, -.v-ie6 .v-filterselect-suggestpopup, -.v-ie6 .v-datefield-popup, -.v-ie6 .v-contextmenu, -.v-ie6 .v-Notification, -.v-ie6 .v-menubar-submenu { - background-image: none; - } - .v-filterselect-suggestpopup, .v-contextmenu, .v-menubar-submenu { diff --git a/WebContent/VAADIN/themes/chameleon/components/accordion/accordion.css b/WebContent/VAADIN/themes/chameleon/components/accordion/accordion.css index 6b0f69aaaa..8fb7254008 100644 --- a/WebContent/VAADIN/themes/chameleon/components/accordion/accordion.css +++ b/WebContent/VAADIN/themes/chameleon/components/accordion/accordion.css @@ -14,10 +14,6 @@ border-style: solid none; } -.v-ie6 .v-accordion-item-caption { - background-image: none; - } - div.v-accordion-item-caption, div.v-accordion-item-open .v-accordion-item-caption:active { background-color: transparent; diff --git a/WebContent/VAADIN/themes/chameleon/components/button/button.css b/WebContent/VAADIN/themes/chameleon/components/button/button.css index 0a9544b5ae..1dffddb4c2 100644 --- a/WebContent/VAADIN/themes/chameleon/components/button/button.css +++ b/WebContent/VAADIN/themes/chameleon/components/button/button.css @@ -1,5 +1,4 @@ .v-button:active, -.v-ie7 .v-pressed.v-button, .v-ie8 .v-pressed.v-button, div.v-button-down { background-image: url(../../img/grad-dark-bottom2.png); @@ -7,7 +6,6 @@ div.v-button-down { } .v-button:active .v-button-wrap, -.v-ie7 .v-pressed.v-button .v-button-wrap, .v-ie8 .v-pressed.v-button .v-button-wrap, .v-button-down .v-button-wrap { background-image: url(../../img/grad-dark-top2.png); @@ -22,10 +20,6 @@ div.v-button-down .v-button-wrap { background-image: url(../../img/grad-dark-top2.png); } -.v-ie6 div.v-button-down .v-button-wrap { - background-image: none; - } - .v-button { overflow: hidden; } @@ -66,16 +60,6 @@ div.v-button-down .v-button-wrap { overflow: hidden; } -body.v-ie6 .v-button { - background-image: none; - } - -body.v-ie6 .v-button .v-button-wrap { - background-image: none; - display: inline; - zoom: 1; - } - .v-button:focus { outline: none; } @@ -110,7 +94,6 @@ body.v-ie6 .v-button .v-button-wrap { } .v-button-small:active .v-button-wrap, -.v-ie7 .v-button-small.v-pressed .v-button-wrap, .v-ie8 .v-button-small.v-pressed .v-button-wrap, .v-button-down.small .v-button-wrap { padding: 2px 10px; @@ -131,7 +114,6 @@ body.v-ie6 .v-button .v-button-wrap { } .v-button-wide:active .v-button-wrap, -.v-ie7 .v-button-wide.v-pressed .v-button-wrap, .v-ie8 .v-button-wide.v-pressed .v-button-wrap { padding-left: 25px; padding-right: 25px; @@ -147,7 +129,6 @@ body.v-ie6 .v-button .v-button-wrap { } .v-button-tall:active .v-button-wrap, -.v-ie7 .v-button-tall.v-pressed .v-button-wrap, .v-ie8 .v-button-tall.v-pressed .v-button-wrap { padding-top: 12px; padding-bottom: 12px; @@ -263,22 +244,6 @@ body.v-ie .v-pressed.v-button-borderless .v-button-wrap { margin-right: -0.5em; } -.v-ie6 .v-button-icon-on-right, -.v-ie7 .v-button-icon-on-right { - position: relative; - } - -.v-ie6 .v-button-icon-on-right .v-button-caption, -.v-ie7 .v-button-icon-on-right .v-button-caption { - padding-right: 14px; - } - -.v-ie6 .v-button-icon-on-right .v-icon, -.v-ie7 .v-button-icon-on-right .v-icon { - position: absolute; - right: 0; - margin: 0; - } /******************************************************************************* * Icon-only @@ -289,4 +254,4 @@ body.v-ie .v-pressed.v-button-borderless .v-button-wrap { .v-button-icon-only .v-icon { margin-right: -.5em; - }
\ No newline at end of file + } diff --git a/WebContent/VAADIN/themes/chameleon/components/datefield/datefield.css b/WebContent/VAADIN/themes/chameleon/components/datefield/datefield.css index 71771ad6e1..3804ab52e0 100644 --- a/WebContent/VAADIN/themes/chameleon/components/datefield/datefield.css +++ b/WebContent/VAADIN/themes/chameleon/components/datefield/datefield.css @@ -23,25 +23,6 @@ height: 1.2em; } -.v-ie6 .v-datefield-button, -.v-ie7 .v-datefield-button { - height: 1.55em; - margin-top: 1px; - padding: 0; - } - -.v-ie7 .v-datefield-button { - height: 1.85em; - } - -.v-ie7 .v-datefield-small .v-datefield-button { - height: 1.75em; - } - -.v-ie7 .v-datefield-big .v-datefield-button { - height: 2em; - } - .v-ie8 .v-datefield-button { height: 1.6em; padding: 0; @@ -116,10 +97,6 @@ td.v-datefield-calendarpanel-month { text-shadow: 0 1px 0 rgba(255,255,255,.7); } -.v-ie6 td.v-datefield-calendarpanel-month { - background-image: none; - } - span.v-datefield-calendarpanel-month { display: block; text-align: center; @@ -172,10 +149,6 @@ td.v-datefield-calendarpanel-nextyear { background-position: 0 0; } -.v-ie6 .v-datefield-calendarpanel-header button { - background-image: none; - } - .v-datefield-calendarpanel-header button:active { background-image: url(../../img/grad-dark-top2.png); } @@ -239,10 +212,6 @@ td.v-datefield-calendarpanel-nextyear { margin-bottom: 2px; } -.v-ie6 .v-datefield-calendarpanel-weekdays strong { - background-image: none; - } - .v-datefield-calendarpanel .v-first strong { -webkit-border-bottom-left-radius: 3px; -moz-border-radius-bottomleft: 3px; @@ -293,10 +262,6 @@ td.v-datefield-calendarpanel-nextyear { border: 1px solid #c9c9c9; } -.v-ie6 .v-datefield-calendarpanel-day-today { - background-image: none; - } - .v-datefield-calendarpanel-day-selected, .v-datefield-calendarpanel-day-selected:hover { margin: 0 0 0 .3em; diff --git a/WebContent/VAADIN/themes/chameleon/components/menubar/menubar.css b/WebContent/VAADIN/themes/chameleon/components/menubar/menubar.css index 00b062f8d6..4f6be1b923 100644 --- a/WebContent/VAADIN/themes/chameleon/components/menubar/menubar.css +++ b/WebContent/VAADIN/themes/chameleon/components/menubar/menubar.css @@ -5,10 +5,6 @@ border-width: 1px 0; } -.v-ie6 .v-menubar { - background-image: none; - } - .v-menubar .v-menubar-menuitem { padding: .2em .5em; line-height: normal; @@ -26,7 +22,3 @@ background-image: url(../../img/grad-light-top2.png); background-position: 0 -1px; } - -.v-ie6 .v-menubar-submenu .v-menubar-menuitem-selected { - background-image: none; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/components/notification/notification.css b/WebContent/VAADIN/themes/chameleon/components/notification/notification.css index 1e4268cf92..ee686912c5 100644 --- a/WebContent/VAADIN/themes/chameleon/components/notification/notification.css +++ b/WebContent/VAADIN/themes/chameleon/components/notification/notification.css @@ -47,10 +47,6 @@ div.v-Notification-tray { text-shadow: 0 1px 1px rgba(0,0,0,.5); } -.v-ie6 .v-Notification-tray { - background-image: none; - } - .v-Notification-tray h1 { font-size: 14px; line-height: 18px; diff --git a/WebContent/VAADIN/themes/chameleon/components/panel/panel.css b/WebContent/VAADIN/themes/chameleon/components/panel/panel.css index e83e245ce6..0e5dcb8a38 100644 --- a/WebContent/VAADIN/themes/chameleon/components/panel/panel.css +++ b/WebContent/VAADIN/themes/chameleon/components/panel/panel.css @@ -87,10 +87,6 @@ div.v-panel-content-light { padding: .3em .6em; } -.v-ie6 .v-panel-bubble .v-panel-caption-bubble { - background-image: none; - } - .v-panel-nocaption-bubble { padding: 0; margin: 0; diff --git a/WebContent/VAADIN/themes/chameleon/components/progressindicator/progressindicator.css b/WebContent/VAADIN/themes/chameleon/components/progressindicator/progressindicator.css index b13b627ed6..c080c0fc43 100644 --- a/WebContent/VAADIN/themes/chameleon/components/progressindicator/progressindicator.css +++ b/WebContent/VAADIN/themes/chameleon/components/progressindicator/progressindicator.css @@ -18,11 +18,6 @@ border: 1px solid #b3b3b3; } -.v-ie6 .v-progressindicator-wrapper, -.v-ie6 .v-progressindicator-indicator { - background-image: none; - } - /******************************************************************************* * Small diff --git a/WebContent/VAADIN/themes/chameleon/components/selects/selects.css b/WebContent/VAADIN/themes/chameleon/components/selects/selects.css index 170a4bb991..3c8496f0fe 100644 --- a/WebContent/VAADIN/themes/chameleon/components/selects/selects.css +++ b/WebContent/VAADIN/themes/chameleon/components/selects/selects.css @@ -84,13 +84,6 @@ body .v-filterselect-suggestpopup-big td { -ms-user-select: none; } -.v-ie6 .v-filterselect-prevpage-off, -.v-ie6 .v-filterselect-nextpage-off, -.v-ie6 .v-filterselect-prevpage, -.v-ie6 .v-filterselect-nextpage { - background-image: none; - } - .v-filterselect-prevpage:active, .v-filterselect-nextpage:active { background-image: (../../img/grad-dark-bottom2.png); @@ -126,10 +119,6 @@ body .v-filterselect-suggestpopup-big td { background-position: 0 -1px; } -.v-ie6 .v-filterselect-suggestmenu .gwt-menuItem-selected { - background-image: none; - } - .v-filterselect-suggestpopup-small .v-filterselect-status { font-size: .8em; } @@ -156,10 +145,6 @@ body .v-filterselect-suggestpopup-big td { padding: .3em .5em; } -.v-ie6 .v-filterselect-select-button { - background-image: none; - } - .v-filterselect-select-button .v-filterselect-input { display: block; width: 100% !important; @@ -176,10 +161,3 @@ body .v-filterselect-suggestpopup-big td { height: 100%; background-position: 100% -8px; } - -.v-ie6 .v-filterselect-select-button .v-filterselect-button { - float: none; - position: relative; - margin: -1.8em -.5em -.3em -.5em; - padding: .3em .5em; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/components/slider/slider.css b/WebContent/VAADIN/themes/chameleon/components/slider/slider.css index c0fc271d3f..6a430723e2 100644 --- a/WebContent/VAADIN/themes/chameleon/components/slider/slider.css +++ b/WebContent/VAADIN/themes/chameleon/components/slider/slider.css @@ -42,10 +42,6 @@ border-width: 0 1px; } -.v-ie6 .v-slider-vertical { - width: 6px; - } - .v-slider-vertical .v-slider-base { background-image: none; width: 4px; @@ -58,8 +54,3 @@ margin: 0; margin-left: -5px; } - -.v-ie6 .v-slider-base, -.v-ie6 .v-slider-handle { - background-image: none; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/components/splitpanel/splitpanel.css b/WebContent/VAADIN/themes/chameleon/components/splitpanel/splitpanel.css index bd407592cb..1cb04bc29b 100644 --- a/WebContent/VAADIN/themes/chameleon/components/splitpanel/splitpanel.css +++ b/WebContent/VAADIN/themes/chameleon/components/splitpanel/splitpanel.css @@ -5,11 +5,6 @@ width: 9px; } -.v-ie6 .v-splitpanel-hsplitter div, -.v-ie6 .v-splitpanel-vsplitter div { - background-image: url(../../img/split-handle-ie6.png); - } - .v-splitpanel-vsplitter div { background-position: 50% 2px; margin: -1px 0; @@ -35,13 +30,6 @@ background: #b3b3b3 url(../../img/grad-light-top.png) repeat-x; } -.v-ie6 .v-splitpanel-hsplitter, -.v-ie6 .v-splitpanel-hsplitter-locked, -.v-ie6 .v-splitpanel-vsplitter, -.v-ie6 .v-splitpanel-vsplitter-locked { - background-image: none; - } - /******************************************************************************* * Small ******************************************************************************/ @@ -61,11 +49,6 @@ body .v-splitpanel-vsplitter-small-locked { line-height: 1px; } -body.v-ie6 .v-splitpanel-vsplitter-small, -body.v-ie6 .v-splitpanel-vsplitter-small-locked { - overflow: hidden; - } - .v-splitpanel-hsplitter-small div { width: 7px; margin-left: -2px; @@ -78,8 +61,3 @@ body.v-ie6 .v-splitpanel-vsplitter-small-locked { background: transparent; overflow: hidden; } - -.v-ie6 .v-splitpanel-hsplitter-small div, -.v-ie6 .v-splitpanel-vsplitter-small div { - background-image: none; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/components/table/table.css b/WebContent/VAADIN/themes/chameleon/components/table/table.css index 66ab6d6101..2bc52bc844 100644 --- a/WebContent/VAADIN/themes/chameleon/components/table/table.css +++ b/WebContent/VAADIN/themes/chameleon/components/table/table.css @@ -5,11 +5,6 @@ line-height: normal; } -.v-ie6 .v-table-header-wrap, -.v-ie6 .v-table-header-drag { - background-image: none; - } - .v-table-caption-container, .v-table-header-drag { padding-top: .2em; @@ -52,10 +47,6 @@ div.v-table-focus-slot-left { background-position: 0 -1px; } -.v-ie6 .v-table tr.v-selected { - background-image: none; - } - div.v-table-focus-slot-right { background: transparent; border-right: 2px solid #b3b3b3; diff --git a/WebContent/VAADIN/themes/chameleon/components/tabsheet/tabsheet.css b/WebContent/VAADIN/themes/chameleon/components/tabsheet/tabsheet.css index 4ca7359094..d1697c584a 100644 --- a/WebContent/VAADIN/themes/chameleon/components/tabsheet/tabsheet.css +++ b/WebContent/VAADIN/themes/chameleon/components/tabsheet/tabsheet.css @@ -36,10 +36,6 @@ -moz-border-radius-topright: 2px; } -.v-ie6 .v-tabsheet-tabitem-selected .v-caption { - background-image: none; - } - .v-tabsheet-content { background: #fff; border-color: #b3b3b3; @@ -62,10 +58,6 @@ margin: .2em 0 0 0; } -.v-ie6 .v-tabsheet-caption-close { - background-image: url(../../img/close-btn-ie6.png); - } - .v-tabsheet-caption-close:hover { background-position: .5em -25px; } @@ -89,10 +81,6 @@ -moz-border-radius: 6px; } -.v-ie6 .v-tabsheet-scroller { - background-image: none; - } - .v-tabsheet-scrollerPrev, .v-tabsheet-scrollerNext, .v-tabsheet-scrollerPrev-disabled, @@ -109,13 +97,6 @@ filter: alpha(opacity=50); } -.v-ie6 .v-tabsheet-scrollerPrev, -.v-ie6 .v-tabsheet-scrollerNext, -.v-ie6 .v-tabsheet-scrollerPrev-disabled, -.v-ie6 .v-tabsheet-scrollerNext-disabled{ - background-image: url(../../img/tab-arrows-ie6.png); - } - .v-tabsheet-scroller button::-moz-focus-inner { border: none; padding: 0; diff --git a/WebContent/VAADIN/themes/chameleon/components/textfield/textfield.css b/WebContent/VAADIN/themes/chameleon/components/textfield/textfield.css index 9c448eee00..74882fa693 100644 --- a/WebContent/VAADIN/themes/chameleon/components/textfield/textfield.css +++ b/WebContent/VAADIN/themes/chameleon/components/textfield/textfield.css @@ -21,11 +21,15 @@ textarea.v-textarea, padding: .2em; } -input.v-textfield[type="text"], -.v-filterselect { +input.v-textfield[type="text"] { height: 1.2em; } +input.v-connector.v-textfield[type="text"], +.v-filterselect { + height: 1.6em; + } + body input.v-textfield, body textarea.v-textarea, body input.v-filterselect-input { @@ -123,8 +127,3 @@ input.v-textfield-search[type=text], .v-filterselect-search { padding-left: 17px; } - -.v-ie6 input.v-textfield-search { - /* Compensate for big style as well, since IE6 doesn't handle the selector */ - padding-left: 21px; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/chameleon/components/window/window.css b/WebContent/VAADIN/themes/chameleon/components/window/window.css index 3034a58fbf..6ca8622a76 100644 --- a/WebContent/VAADIN/themes/chameleon/components/window/window.css +++ b/WebContent/VAADIN/themes/chameleon/components/window/window.css @@ -11,10 +11,6 @@ z-index: 2; } -.v-ie6 .v-window-closebox { - background-image: url(../../img/close-btn-ie6.png); - } - .v-window-closebox:hover { background-position: 0 -25px; } @@ -34,11 +30,6 @@ background-image: url(../../img/grad-light-top.png); background-repeat: repeat-x; } - -.v-ie6 .v-window-wrap { - background: transparent !important; - } - .v-window-outerheader { padding: .2em 1.7em .5em 1.2em; height: auto; diff --git a/WebContent/VAADIN/themes/chameleon/compound/sidebar-menu/sidebar-menu.css b/WebContent/VAADIN/themes/chameleon/compound/sidebar-menu/sidebar-menu.css index 83b736584f..e2ab7f2080 100644 --- a/WebContent/VAADIN/themes/chameleon/compound/sidebar-menu/sidebar-menu.css +++ b/WebContent/VAADIN/themes/chameleon/compound/sidebar-menu/sidebar-menu.css @@ -33,11 +33,6 @@ color: #fff; } -.v-ie6 .sidebar-menu .tab-selected, -.v-ie6 .sidebar-menu .selected { - background-image: none; - } - .sidebar-menu .tab-selected:focus, .sidebar-menu .selected:focus { outline: none; diff --git a/WebContent/VAADIN/themes/chameleon/compound/toolbar/toolbar.css b/WebContent/VAADIN/themes/chameleon/compound/toolbar/toolbar.css index 594fc245a6..468172037e 100644 --- a/WebContent/VAADIN/themes/chameleon/compound/toolbar/toolbar.css +++ b/WebContent/VAADIN/themes/chameleon/compound/toolbar/toolbar.css @@ -4,10 +4,6 @@ border-width: 1px 0; } -.v-ie6 .v-csslayout-toolbar { - background-image: none; - } - .v-csslayout-toolbar .v-csslayout-margin { margin: 3px .3em 2px; padding-bottom: 1px; diff --git a/WebContent/VAADIN/themes/chameleon/img/close-btn-ie6.png b/WebContent/VAADIN/themes/chameleon/img/close-btn-ie6.png Binary files differdeleted file mode 100644 index 334b03769a..0000000000 --- a/WebContent/VAADIN/themes/chameleon/img/close-btn-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/chameleon/img/date-btn-ie6.png b/WebContent/VAADIN/themes/chameleon/img/date-btn-ie6.png Binary files differdeleted file mode 100644 index d22411b260..0000000000 --- a/WebContent/VAADIN/themes/chameleon/img/date-btn-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/chameleon/img/split-handle-ie6.png b/WebContent/VAADIN/themes/chameleon/img/split-handle-ie6.png Binary files differdeleted file mode 100644 index 2e23c10d90..0000000000 --- a/WebContent/VAADIN/themes/chameleon/img/split-handle-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/chameleon/img/tab-arrows-ie6.png b/WebContent/VAADIN/themes/chameleon/img/tab-arrows-ie6.png Binary files differdeleted file mode 100644 index 963cf2e1a0..0000000000 --- a/WebContent/VAADIN/themes/chameleon/img/tab-arrows-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/liferay/button/button.css b/WebContent/VAADIN/themes/liferay/button/button.css index 8181a041a0..bd0f307947 100644 --- a/WebContent/VAADIN/themes/liferay/button/button.css +++ b/WebContent/VAADIN/themes/liferay/button/button.css @@ -50,11 +50,6 @@ line-height: 16px; } -.v-ie6 .v-button .v-button-wrap { - display: inline; - zoom: 1; -} - /* Link style button */ .v-button-link, .v-disabled.v-button-link, diff --git a/WebContent/VAADIN/themes/liferay/common/common.css b/WebContent/VAADIN/themes/liferay/common/common.css index 26a0354ff3..521c4f3ac1 100644 --- a/WebContent/VAADIN/themes/liferay/common/common.css +++ b/WebContent/VAADIN/themes/liferay/common/common.css @@ -33,7 +33,3 @@ div.v-app { font-weight: bold; margin: 1px 0 4px 0; } - -.v-ie6 .v-view { - border-top: none; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/liferay/datefield/datefield.css b/WebContent/VAADIN/themes/liferay/datefield/datefield.css index 4307658449..6040052798 100644 --- a/WebContent/VAADIN/themes/liferay/datefield/datefield.css +++ b/WebContent/VAADIN/themes/liferay/datefield/datefield.css @@ -116,13 +116,6 @@ span.v-datefield-calendarpanel-month { min-width: 22px; } -.v-ie6 .v-datefield-calendarpanel-prevyear button, -.v-ie6 .v-datefield-calendarpanel-nextyear button, -.v-ie7 .v-datefield-calendarpanel-prevyear button, -.v-ie7 .v-datefield-calendarpanel-nextyear button { - width: 22px; -} - .v-datefield-calendarpanel-day { display: block; width: 22px; diff --git a/WebContent/VAADIN/themes/liferay/select/select.css b/WebContent/VAADIN/themes/liferay/select/select.css index 48e35f9baa..66672cc573 100644 --- a/WebContent/VAADIN/themes/liferay/select/select.css +++ b/WebContent/VAADIN/themes/liferay/select/select.css @@ -7,10 +7,6 @@ select { background-color: #fff; } -.v-ie6 select { - font-size: 1em; -} - .v-filterselect-button { width: 24px; height: 24px; diff --git a/WebContent/VAADIN/themes/liferay/tabsheet/close-ie6.png b/WebContent/VAADIN/themes/liferay/tabsheet/close-ie6.png Binary files differdeleted file mode 100644 index fcbbedb6d4..0000000000 --- a/WebContent/VAADIN/themes/liferay/tabsheet/close-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/liferay/tabsheet/tabsheet.css b/WebContent/VAADIN/themes/liferay/tabsheet/tabsheet.css index 4d5c21d7af..7f23edb809 100644 --- a/WebContent/VAADIN/themes/liferay/tabsheet/tabsheet.css +++ b/WebContent/VAADIN/themes/liferay/tabsheet/tabsheet.css @@ -132,7 +132,6 @@ .v-tabsheet-caption-close { background: transparent url(close.png) no-repeat right top; - -background-image: url(close-ie6.png); cursor: default; float: right; margin: 3px -1px 0; diff --git a/WebContent/VAADIN/themes/liferay/tree/arrows_sprites-ie6.png b/WebContent/VAADIN/themes/liferay/tree/arrows_sprites-ie6.png Binary files differdeleted file mode 100644 index c9a0bbd388..0000000000 --- a/WebContent/VAADIN/themes/liferay/tree/arrows_sprites-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/liferay/tree/tree.css b/WebContent/VAADIN/themes/liferay/tree/tree.css index 23fe10f52e..33da398736 100644 --- a/WebContent/VAADIN/themes/liferay/tree/tree.css +++ b/WebContent/VAADIN/themes/liferay/tree/tree.css @@ -1,6 +1,5 @@ .v-tree-node { background: transparent url(arrows_sprites.png) no-repeat -42px 1px; - -background: transparent url(arrows_sprites-ie6.png) no-repeat -42px 1px; } .v-tree-node span { diff --git a/WebContent/VAADIN/themes/liferay/window/window.css b/WebContent/VAADIN/themes/liferay/window/window.css index 6b61d880f1..5ac7c02175 100644 --- a/WebContent/VAADIN/themes/liferay/window/window.css +++ b/WebContent/VAADIN/themes/liferay/window/window.css @@ -10,21 +10,6 @@ background: #fff url(top-left.png) no-repeat; } -.v-ie6 .v-window-wrap, -.v-ie7 .v-window-wrap { - background-position: 1px 1px; -} - -.v-ie6 .v-window-wrap { - border-bottom: none; -} - -.v-ie6 .v-window-footer { - border-bottom: 1px solid #c8c9ca; - margin-top: -1px; - padding-top: 1px; -} - .v-window-outerheader { height: 16px; margin-left: 9px; diff --git a/WebContent/VAADIN/themes/reindeer-tests/styles.css b/WebContent/VAADIN/themes/reindeer-tests/styles.css index 243d1b87d4..7da9e50a46 100644 --- a/WebContent/VAADIN/themes/reindeer-tests/styles.css +++ b/WebContent/VAADIN/themes/reindeer-tests/styles.css @@ -20,6 +20,11 @@ display: none; } +.v-disabled.v-datefield-enabled-readonly-styled, +.v-readonly.v-datefield-enabled-readonly-styled { + padding-right: 0; +} + .popup-style .v-datefield-calendarpanel-header, .v-datefield-popup-popup-style .v-datefield-calendarpanel-time { background: red; diff --git a/WebContent/VAADIN/themes/reindeer/button/button-firefox.css b/WebContent/VAADIN/themes/reindeer/button/button-firefox.css deleted file mode 100644 index 4e8a1f58c9..0000000000 --- a/WebContent/VAADIN/themes/reindeer/button/button-firefox.css +++ /dev/null @@ -1,5 +0,0 @@ -.v-ff2 .v-button .v-button-caption { - display: -moz-inline-box; - padding-top: 6px; - height: 20px; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/reindeer/button/button-ie.css b/WebContent/VAADIN/themes/reindeer/button/button-ie.css index aaac6bf0b6..47d9496e81 100644 --- a/WebContent/VAADIN/themes/reindeer/button/button-ie.css +++ b/WebContent/VAADIN/themes/reindeer/button/button-ie.css @@ -1,75 +1,4 @@ -.v-ie6 .v-nativebutton-link, -.v-ie7 .v-nativebutton-link, .v-ie8 .v-nativebutton-link { padding: 0; text-align: left; } - -/** - * IE6 buttons -------------------------- - */ -.v-ie6 .v-button { - border: 1px solid #b3b3b3; - border-bottom-color: #9a9a9a; - background: #d8d8d8 url(img/right.png) no-repeat 0 -1px; - padding: 0 15px; - height: 23px; -} -.v-ie6 .v-button .v-button-wrap { - background: transparent; - height: 20px; - padding: 3px 0 0; - display: inline; - zoom: 1; -} -.v-ie6 .v-button-primary { - background-image: url(img/primary-right.png); -} -.v-ie6 .v-button-small { - background-image: url(img/small-right.png); - height: 17px; -} -.v-ie6 .v-button-small .v-button-wrap { - height: 17px; - padding: 0; -} -.v-ie6 .v-button.v-pressed { - background: transparent url(img/right-pressed.png) no-repeat 0 -1px; -} -/* Buttons on blue background */ -.v-ie6 .blue .v-button { - border-color: #84949c; - border-top-color: #83939b; - border-bottom-color: #888d91; -} -/* Buttons on black background */ -.v-ie6 .black .v-button { - border: 1px solid #0d0e0f; - background: #202224 url(img/black/right.png) no-repeat 0 -1px; - color: #c9ccce; -} -.v-ie6 .black .v-button-primary { - background-image: url(img/black/primary-right.png); -} -.v-ie6 .black .v-button-small { - background-image: url(img/black/small-right.png); -} -.v-ie6 .black .v-button.v-pressed { - background-image: url(img/black/right-pressed.png); -} - - -/* Link style button */ -.v-ie6 .v-button-link, -.v-ie6 .black .v-button-link { - background: transparent; - border: none; - height: auto; - line-height: normal; - padding: 0; -} -.v-ie6 .v-button-link .v-button-wrap, -.v-ie6 .black .v-button-link .v-button-wrap { - padding: 0; - height: auto; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/reindeer/button/button.css b/WebContent/VAADIN/themes/reindeer/button/button.css index 14da4facc5..1948e5aafb 100644 --- a/WebContent/VAADIN/themes/reindeer/button/button.css +++ b/WebContent/VAADIN/themes/reindeer/button/button.css @@ -7,5 +7,4 @@ @import "button-link-style.css"; /* Browser-specific corrections to the standard implementation */ -@import "button-firefox.css"; @import "button-ie.css";
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/reindeer/common/common.css b/WebContent/VAADIN/themes/reindeer/common/common.css index 50dcdd84ab..ff8ae47036 100644 --- a/WebContent/VAADIN/themes/reindeer/common/common.css +++ b/WebContent/VAADIN/themes/reindeer/common/common.css @@ -44,9 +44,6 @@ height: 16px; background: transparent url(../common/icons/error.png) no-repeat 50%; } -.v-ie6 .v-errorindicator { - background-image: url(../common/icons/error-ie6.png); -} .v-tooltip { background-color: #fffcdd; border: 1px solid #b8b295; diff --git a/WebContent/VAADIN/themes/reindeer/common/icons/bullet-ie6.png b/WebContent/VAADIN/themes/reindeer/common/icons/bullet-ie6.png Binary files differdeleted file mode 100644 index 7ba2e118a6..0000000000 --- a/WebContent/VAADIN/themes/reindeer/common/icons/bullet-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/common/icons/bullet-white-ie6.png b/WebContent/VAADIN/themes/reindeer/common/icons/bullet-white-ie6.png Binary files differdeleted file mode 100644 index 9661802744..0000000000 --- a/WebContent/VAADIN/themes/reindeer/common/icons/bullet-white-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/common/icons/error-ie6.png b/WebContent/VAADIN/themes/reindeer/common/icons/error-ie6.png Binary files differdeleted file mode 100644 index dce7941157..0000000000 --- a/WebContent/VAADIN/themes/reindeer/common/icons/error-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/datefield/datefield.css b/WebContent/VAADIN/themes/reindeer/datefield/datefield.css index 7217d70576..1ececf9fb4 100644 --- a/WebContent/VAADIN/themes/reindeer/datefield/datefield.css +++ b/WebContent/VAADIN/themes/reindeer/datefield/datefield.css @@ -1,3 +1,6 @@ +.v-datefield { + overflow: hidden; +} input.v-textfield-readonly:focus{ background-color: transparent; } @@ -43,14 +46,9 @@ span.v-datefield-calendarpanel-month { .v-datefield-full { min-width: 240px; } -.v-ff2 .v-datefield-month, -.v-ff2 .v-datefield-day, -.v-ff2 .v-datefield-full { - min-width: 254px; -} -.v-datefield-popupcalendar, -.v-ff2 .v-datefield-popupcalendar { +.v-datefield-popupcalendar { min-width: 0; + padding-right: 24px; } .v-datefield-year .v-datefield-calendarpanel { width: 100px; @@ -120,10 +118,6 @@ td.v-datefield-calendarpanel-nextyear { .v-ie .v-datefield-calendarpanel-nextmonth button { border: none; } -.v-ie6 .v-datefield-calendarpanel-prevmonth button, -.v-ie6 .v-datefield-calendarpanel-nextmonth button { - width: 24px; -} .v-datefield-calendarpanel-nextmonth button { background-image: url(img/month-next.png); /** sprite-ref: verticals; sprite-alignment: center */ } @@ -231,21 +225,23 @@ td.v-datefield-calendarpanel-nextyear { -moz-border-radius: 3px; } .v-sa .v-datefield-popup, -.v-ff3 .v-datefield-popup, .v-op .v-datefield-popup { background: rgba(255,255,255,.95); } -.v-datefield-year .v-datefield-textfield { - width: 4em; +.v-has-width > input.v-datefield-textfield { + width: 100%; } -.v-datefield-month .v-datefield-textfield { - width: 5em; +.v-datefield-year > .v-datefield-textfield { + width: 4.5em; } -.v-datefield-day .v-datefield-textfield { +.v-datefield-month > .v-datefield-textfield { width: 5.5em; } -.v-datefield-full .v-datefield-textfield { - width: 12em; +.v-datefield-day > .v-datefield-textfield { + width: 6em; +} +.v-datefield-full >.v-datefield-textfield { + width: 12.5em; } .v-datefield-popupcalendar input.v-datefield-textfield { border-right-width: 0; @@ -253,7 +249,10 @@ td.v-datefield-calendarpanel-nextyear { -moz-border-radius-bottomright: 0; -webkit-border-top-right-radius: 0; -webkit-border-bottom-right-radius: 0; - height: 14px; + height: 23px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .v-datefield.v-readonly input.v-datefield-textfield { border-right-width: 1px; @@ -267,6 +266,7 @@ td.v-datefield-calendarpanel-nextyear { } .v-datefield-popupcalendar .v-datefield-button { width: 24px; + margin-right: -24px; height: 23px; background: transparent; border: none; @@ -289,11 +289,6 @@ td.v-datefield-calendarpanel-nextyear { background-image: url(img/popup-btn-black-pressed.png); /** sprite-ref: black-verticals */ } -/* Small adjustment for IE6 */ -.v-ie6 .v-datefield-popupcalendar .v-datefield-button { - margin-top: 1px; -} - /*------------ * on black background diff --git a/WebContent/VAADIN/themes/reindeer/formlayout/formlayout.css b/WebContent/VAADIN/themes/reindeer/formlayout/formlayout.css index a5d465a91f..b28040a0e9 100644 --- a/WebContent/VAADIN/themes/reindeer/formlayout/formlayout.css +++ b/WebContent/VAADIN/themes/reindeer/formlayout/formlayout.css @@ -6,9 +6,6 @@ height: 16px; background: transparent url(../common/icons/error.png) no-repeat 50%; } -.v-ie6 .v-formlayout-cell .v-errorindicator { - background-image: url(../common/icons/error-ie6.png); -} .v-formlayout-captioncell { text-align: right; white-space: nowrap; @@ -42,10 +39,6 @@ margin-top: 5px; min-height: 20px; } -.v-ie6 .v-form-errormessage { - height: 20px; - background-image: url(../common/icons/error-ie6.png); -} .v-form fieldset { border: none; border-top: 1px solid #babfc0; diff --git a/WebContent/VAADIN/themes/reindeer/panel/panel.css b/WebContent/VAADIN/themes/reindeer/panel/panel.css index 8ce943a7be..23575799ab 100644 --- a/WebContent/VAADIN/themes/reindeer/panel/panel.css +++ b/WebContent/VAADIN/themes/reindeer/panel/panel.css @@ -23,6 +23,7 @@ } .v-panel-content, .white .v-panel-content { + background: #fff; border: 1px solid #dcdcdc; border-bottom: none; border-top: none; @@ -32,13 +33,6 @@ .v-ie9 .v-panel-content { border-top-color: rgba(0,0,0,.07); } -.v-panel-content > div { - background: #fff; - min-height: 100%; -} -.v-ie6 .v-panel-content { - background: #fff; -} .blue .v-panel-deco { border-color: #92a3ac; background: #adc2cd; @@ -64,9 +58,6 @@ display: inline-block; vertical-align: middle; } -.v-ie6 .v-panel-caption .v-errorindicator { - background-image: url(../common/icons/error-ie6.png); -} /* Light style */ .v-panel-light .v-panel-caption-light, @@ -75,11 +66,6 @@ } .v-panel-light .v-panel-content-light { border: none; -} -.v-panel-content-light > div { - background: transparent; -} -.v-ie6 .v-panel-content-light { background: transparent; } .v-panel-light .v-panel-deco-light { diff --git a/WebContent/VAADIN/themes/reindeer/select/img/black/left-black-focus-ie6.png b/WebContent/VAADIN/themes/reindeer/select/img/black/left-black-focus-ie6.png Binary files differdeleted file mode 100644 index 5cf13fac6a..0000000000 --- a/WebContent/VAADIN/themes/reindeer/select/img/black/left-black-focus-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/select/img/black/left-black-ie6.png b/WebContent/VAADIN/themes/reindeer/select/img/black/left-black-ie6.png Binary files differdeleted file mode 100644 index d06d599e0e..0000000000 --- a/WebContent/VAADIN/themes/reindeer/select/img/black/left-black-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/select/img/left-focus-ie6.png b/WebContent/VAADIN/themes/reindeer/select/img/left-focus-ie6.png Binary files differdeleted file mode 100644 index 643aac1bc9..0000000000 --- a/WebContent/VAADIN/themes/reindeer/select/img/left-focus-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/select/img/left-ie6.png b/WebContent/VAADIN/themes/reindeer/select/img/left-ie6.png Binary files differdeleted file mode 100644 index 226aea1ad1..0000000000 --- a/WebContent/VAADIN/themes/reindeer/select/img/left-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/select/select.css b/WebContent/VAADIN/themes/reindeer/select/select.css index b23e7571e2..8962862702 100644 --- a/WebContent/VAADIN/themes/reindeer/select/select.css +++ b/WebContent/VAADIN/themes/reindeer/select/select.css @@ -3,9 +3,7 @@ background-repeat: no-repeat; background-image: url(img/left.png); /** sprite-ref: verticals; sprite-margin-bottom: 1px */ padding-left: 2px; -} -.v-ie6 .v-filterselect { - background-image: url(img/left-ie6.png); /** sprite-ref: verticals; sprite-margin-bottom: 1px */ + padding-right: 25px; /* Space for the button */ } .v-app .v-filterselect-input, .v-window .v-filterselect-input, @@ -13,13 +11,16 @@ background: transparent repeat-x; background-image: url(img/center.png); /** sprite-ref: verticals; sprite-alignment: repeat; sprite-margin-bottom: 1px */ border: none; - height: 16px; + height: 24px; } /* More specific selector to override padding */ .v-app input.v-filterselect-input, .v-window input.v-filterselect-input, .v-popupview-popup input.v-filterselect-input { padding: 4px 0 4px 2px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .v-filterselect-prompt .v-filterselect-input { font-style: normal; @@ -30,9 +31,6 @@ .v-filterselect-focus { background-image: url(img/left-focus.png); /** sprite-ref: verticals; sprite-margin-bottom: 1px */ } -.v-ie6 .v-filterselect-focus { - background-image: url(img/left-focus-ie6.png); /** sprite-ref: verticals; sprite-margin-bottom: 1px */ -} .v-filterselect-focus .v-filterselect-input { background-image: url(img/center-focus.png); /** sprite-ref: verticals; sprite-alignment: repeat */ } @@ -42,6 +40,7 @@ height: 24px; background-image: url(img/right.png); /** sprite-ref: verticals ; sprite-margin-bottom: 1px */ cursor: default; + margin-right: -25px; } .v-filterselect-button:hover { background-image: url(img/right-hover.png); /** sprite-ref: verticals */ @@ -209,9 +208,6 @@ .black .v-filterselect { background-image: url(img/black/left-black.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 1px */ } -.v-ie6 .black .v-filterselect { - background-image: url(img/black/left-black-ie6.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 1px */ -} .v-app .black .v-filterselect-input, .v-window .black .v-filterselect-input, .v-window-black .v-filterselect-input, @@ -222,9 +218,6 @@ .black .v-filterselect-focus { background-image: url(img/black/left-black-focus.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 1px */ } -.v-ie6 .black .v-filterselect-focus { - background-image: url(img/black/left-black-focus-ie6.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 1px */ -} .black .v-filterselect-focus .v-filterselect-input { background-image: url(img/black/center-black-focus.png); /** sprite-ref: black-verticals; sprite-alignment: repeat; sprite-margin-bottom: 1px */ } @@ -265,15 +258,3 @@ background: #151717; color: #c9ccce; } - -/* Twincolselect needs a little tweak in IE6 */ -.v-ie6 .v-select-twincol-buttons .v-button { - padding-left: 12px; - padding-right: 12px; -} - -/* IE6 needs some help identifying when the input is readonly */ -.v-ie6 .v-filterselect.v-readonly, -.v-ie6 .v-filterselect .v-filterselect-input-readonly { - background: transparent; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/reindeer/table/table.css b/WebContent/VAADIN/themes/reindeer/table/table.css index 2e6c597160..9b78d86e34 100644 --- a/WebContent/VAADIN/themes/reindeer/table/table.css +++ b/WebContent/VAADIN/themes/reindeer/table/table.css @@ -25,24 +25,6 @@ line-height: normal; } -.v-ie6 .v-table, -.v-ie6 .v-table-header-wrap, -.v-ie6 .v-table-footer-wrap, -.v-ie6 .v-table-column-selector { - /* The header will overflow the Table due to a bug in IE6 after changes in #3003. To fix this (#7314) - * we need to apply position:relative to the wrappers and selector to make them appear on top of the - * header. We also need to apply it to the table root div to get rid of a really weird IE6 rendering bug - * caused by all this relativeness (see attachment in #7314). - */ - position: relative; -} - -.v-ie6 .v-table.v-disabled, -.v-ie7 .v-table.v-disabled { - /* Fixes ie issue #7324 where disabled shim does not cover table body */ - position: relative; -} - .v-table-footer-wrap, .white .v-table-footer-wrap { text-transform: none; diff --git a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.css b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.css index d0041e586a..dfa83d7088 100644 --- a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.css +++ b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.css @@ -105,8 +105,7 @@ .v-tabsheet-tabs-minimal .v-tabsheet-caption-close { margin-top: 1px; } -.v-ff .v-tabsheet-tabs-minimal .v-tabsheet-caption-close, -.v-ie7 .v-tabsheet-tabs-minimal .v-tabsheet-caption-close { +.v-ff .v-tabsheet-tabs-minimal .v-tabsheet-caption-close { margin-top: -15px; } .v-tabsheet-tabs-minimal .v-tabsheet-caption-close:hover, diff --git a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.css b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.css index 1c22a68a99..3d23fa110a 100644 --- a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.css +++ b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.css @@ -52,13 +52,6 @@ font-size: 14px; font-weight: normal; } -.v-ff .v-tabsheet-caption-close, -.v-ie7 .v-tabsheet-caption-close { - margin-top: -17px; -} -.v-ie6 .v-tabsheet-caption-close { - float: none; -} .v-tabsheet-caption-close:hover { background-image: url(img/close-btn-hover.png); /** sprite-ref: verticals */ } @@ -108,8 +101,7 @@ .v-tabsheet-tabsheetpanel { background: #fff; } -.v-sa .v-tabsheet-content, -.v-ff3 .v-tabsheet-content { +.v-sa .v-tabsheet-content { border-color: rgba(0,0,0,.1); } .blue .v-tabsheet-deco { @@ -123,8 +115,7 @@ background: #e2e2e2; overflow: hidden; } -.v-sa .v-tabsheet-deco, -.v-ff3 .v-tabsheet-deco { +.v-sa .v-tabsheet-deco { border-top-color: rgba(0,0,0,.1); background: rgba(0,0,0,.08); } @@ -151,13 +142,6 @@ height: 16px; background: transparent url(../common/icons/error.png) no-repeat 50%; } -.v-ff2 .v-tabsheet-tabs .v-icon, -.v-ff2 .v-tabsheet-tabs .v-errorindicator { - display: -moz-inline-stack; -} -.v-ie6 .v-tabsheet-tabs .v-errorindicator { - background-image: url(../common/icons/error-ie6.png); -} .v-ie .v-tabsheet-tabs .v-errorindicator { zoom: 1; display: inline; diff --git a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.css b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.css index e440f7fdd1..c7c79d35ee 100644 --- a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.css +++ b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.css @@ -50,8 +50,7 @@ .v-tabsheet-tabs-bar .v-tabsheet-caption-close { margin-top: 1px; } -.v-ff .v-tabsheet-tabs-bar .v-tabsheet-caption-close, -.v-ie7 .v-tabsheet-tabs-bar .v-tabsheet-caption-close { +.v-ff .v-tabsheet-tabs-bar .v-tabsheet-caption-close { margin-top: -14px; } .v-tabsheet-tabs-bar .v-tabsheet-caption-close:hover { diff --git a/WebContent/VAADIN/themes/reindeer/textfield/textfield.css b/WebContent/VAADIN/themes/reindeer/textfield/textfield.css index 4c8ed4251e..09c47dc8d4 100644 --- a/WebContent/VAADIN/themes/reindeer/textfield/textfield.css +++ b/WebContent/VAADIN/themes/reindeer/textfield/textfield.css @@ -20,7 +20,7 @@ -webkit-border-radius: 3px; border-radius: 3px; margin: 0; - height: 15px; + height: 23px; line-height: normal; } .v-textarea, @@ -35,6 +35,10 @@ .v-window textarea.v-textarea { padding: 3px 3px 4px; } +.v-app input.v-textfield.v-connector, +.v-window input.v-textfield.v-connector { + height: 24px; +} .v-app .v-textfield-focus, .v-window .v-textfield-focus, .v-popupview-popup .v-textfield-focus, @@ -62,7 +66,8 @@ textarea.v-textarea-prompt { .v-app textarea.v-textarea-small { font-size: 11px; } -.v-table input.v-textfield { +.v-app .v-table input.v-textfield.v-connector, +.v-window .v-table input.v-textfield.v-connector { padding: 1px 2px; height: auto; line-height: normal; @@ -71,14 +76,6 @@ textarea.v-textarea-prompt { margin-top: -2px; margin-bottom: -2px; } -.v-ie6 .v-table-cell-wrapper input.v-textfield { - margin-top: -2px; - margin-bottom: -2px; -} -.v-ie6 .v-table-cell-wrapper div input.v-textfield { - margin-top: 0; - margin-bottom: 0; -} /* Textfield on black background */ .black .v-textfield, .black .v-textarea { diff --git a/WebContent/VAADIN/themes/reindeer/tree/img/arrows-ie6.png b/WebContent/VAADIN/themes/reindeer/tree/img/arrows-ie6.png Binary files differdeleted file mode 100644 index e016e313a7..0000000000 --- a/WebContent/VAADIN/themes/reindeer/tree/img/arrows-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/tree/tree.css b/WebContent/VAADIN/themes/reindeer/tree/tree.css index 63ac914fdf..f72f61c545 100644 --- a/WebContent/VAADIN/themes/reindeer/tree/tree.css +++ b/WebContent/VAADIN/themes/reindeer/tree/tree.css @@ -1,13 +1,6 @@ .v-tree-node { background: transparent url(img/arrows.png) no-repeat 6px -10px; } -.v-ie6 .v-tree-node { - background-image: url(img/arrows-ie6.png); - background-repeat: no-repeat; -} -.v-ie6 div.v-tree-node-leaf { - background: transparent; -} .v-tree-node-expanded { background-position: -7px 5px; } @@ -32,12 +25,6 @@ .v-tree-node-children { padding-left: 16px; } -/* IMPORTANT keep the offsetWidth (width + padding) of this element the same as the margin-left of v-tree-node-caption */ -.v-ie6 .v-tree-node-ie6compatnode { - width: 14px; - height: 10px; - padding: 1px; -} .v-tree-node-caption.v-tree-node-focused span{ padding-left: 1px; padding-top: 0px; @@ -46,9 +33,6 @@ .v-tree-node-focused span{ border: 1px dotted black; } -.v-ie6 .v-tree-node-ie6compatnode.v-tree-node-focused{ - padding-left: 0px; -} /*************************************** * Drag'n'drop styles ***************************************/ diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/content-bg-ie6.png b/WebContent/VAADIN/themes/reindeer/window/img/black/content-bg-ie6.png Binary files differdeleted file mode 100644 index 8ff06a11ed..0000000000 --- a/WebContent/VAADIN/themes/reindeer/window/img/black/content-bg-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/header-bg-ie6.png b/WebContent/VAADIN/themes/reindeer/window/img/black/header-bg-ie6.png Binary files differdeleted file mode 100644 index ddfc27f6e6..0000000000 --- a/WebContent/VAADIN/themes/reindeer/window/img/black/header-bg-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/resize-ie6.png b/WebContent/VAADIN/themes/reindeer/window/img/black/resize-ie6.png Binary files differdeleted file mode 100644 index 011b64a918..0000000000 --- a/WebContent/VAADIN/themes/reindeer/window/img/black/resize-ie6.png +++ /dev/null diff --git a/WebContent/VAADIN/themes/reindeer/window/window.css b/WebContent/VAADIN/themes/reindeer/window/window.css index 5b3997f444..e1091ef98d 100644 --- a/WebContent/VAADIN/themes/reindeer/window/window.css +++ b/WebContent/VAADIN/themes/reindeer/window/window.css @@ -3,35 +3,17 @@ } .v-window-wrap { border: 1px solid #808386; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .v-sa .v-window-wrap, -.v-ff3 .v-window-wrap, .v-op .v-window-wrap { border-color: rgba(0,0,0,.2); } -.v-ff2 .v-window-wrap, -.v-ie6 .v-window-wrap { - border: none; -} -.v-ff2 .v-window-outerheader, -.v-ie6 .v-window-outerheader { - border: 1px solid #808386; - border-bottom: none; -} -.v-ff2 .v-window-contents, -.v-ie6 .v-window-contents { - border: 1px solid #808386; - border-top: none; - border-bottom: none; -} -.v-ff2 .v-window-footer, -.v-ie6 .v-window-footer { - border: 1px solid #808386; - border-top: none; -} .v-window-outerheader { padding: 12px 32px 0 14px; - height: 25px; + height: 37px; background: black repeat-x; background-image: url(img/header-bg.png); /** sprite-ref: verticals; sprite-alignment: repeat */ } @@ -50,9 +32,6 @@ padding-left: 13px; background: transparent url(../common/icons/error.png) no-repeat 0 50%; } -.v-ie6 .v-window-error .v-window-header { - background-image: url(../common/icons/error-ie6.png); -} .v-window-resizebox { width: 15px; height: 15px; @@ -136,12 +115,6 @@ background: #f7f7f8 repeat-x; background-image: url(img/content-bg-light.png); /** sprite-ref: verticals; sprite-alignment: repeat */ } -.v-ie6 .v-window-light .v-window-wrap2 { - background-image: none; -} - - - /** @@ -156,7 +129,6 @@ overflow: hidden; } .v-sa .v-window-black .v-window-wrap, -.v-ff3 .v-window-black .v-window-wrap, .v-op .v-window-black .v-window-wrap { border-color: rgba(0,0,0,.8); } @@ -166,7 +138,6 @@ -webkit-border-radius: 7px; } .v-sa .v-window-black .v-window-wrap2, -.v-ff3 .v-window-black .v-window-wrap2, .v-op .v-window-black .v-window-wrap2 { background-color: rgba(29,32,33,.9); } @@ -203,12 +174,6 @@ width: 14px; height: 14px; } -.v-ie6 .v-window-black .v-window-resizebox { - background-image: url(img/black/resize-ie6.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 4px */ -} -.v-ie6 .v-window-black .v-window-contents { - background: transparent url(img/black/content-bg-ie6.png) repeat-x; -} /* Must be last to make this image last in the sprites */ .v-window-black .v-window-contents { border: none; diff --git a/WebContent/VAADIN/themes/runo/button/button.css b/WebContent/VAADIN/themes/runo/button/button.css index 75557d8a39..5515db5aec 100644 --- a/WebContent/VAADIN/themes/runo/button/button.css +++ b/WebContent/VAADIN/themes/runo/button/button.css @@ -56,12 +56,6 @@ text-overflow: ellipsis; } -.v-ie7 .v-button .v-button-wrap { - overflow: visible; -} - - - /* Small style */ .v-button-small .v-button-wrap, .v-disabled.v-button-small .v-button-wrap { @@ -160,13 +154,3 @@ .v-checkbox .v-errorindicator { padding-left: 10px; } -.v-ie6 .v-checkbox .v-errorindicator { - padding-right: 4px; - } -.v-ie7 .v-checkbox .v-errorindicator { - padding-right: 7px; - } -.v-ie6 .v-button .v-errorindicator, -.v-ie7 .v-button .v-errorindicator { - padding-right: 5px; - }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/caption/caption.css b/WebContent/VAADIN/themes/runo/caption/caption.css index d5be467822..93d7874665 100644 --- a/WebContent/VAADIN/themes/runo/caption/caption.css +++ b/WebContent/VAADIN/themes/runo/caption/caption.css @@ -6,10 +6,3 @@ height: 16px; background: transparent url(../icons/16/error.png) no-repeat top right; } -.v-ie6 .v-errorindicator { - /* gif for transparency */ - background-image: url(../icons/16/error.gif); -} -.v-ie7 .v-errorindicator { - margin-left: -3px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/datefield/datefield.css b/WebContent/VAADIN/themes/runo/datefield/datefield.css index b9a4efc50e..0bfa060a09 100644 --- a/WebContent/VAADIN/themes/runo/datefield/datefield.css +++ b/WebContent/VAADIN/themes/runo/datefield/datefield.css @@ -143,9 +143,3 @@ td.v-datefield-calendarpanel-month { color: #999; font-style: normal; } -/* IE specific styles */ -.v-ie7 .v-datefield-button { - background-position: right 1px; - height: 25px; - margin: 0; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/formlayout/formlayout.css b/WebContent/VAADIN/themes/runo/formlayout/formlayout.css index fa4a7bde63..466baafd8c 100644 --- a/WebContent/VAADIN/themes/runo/formlayout/formlayout.css +++ b/WebContent/VAADIN/themes/runo/formlayout/formlayout.css @@ -36,9 +36,6 @@ margin-top: 5px; min-height: 20px; } -.v-ie6 .v-form-errormessage { - height: 20px -} .v-form fieldset { border: none; border-top: 1px solid #babfc0; diff --git a/WebContent/VAADIN/themes/runo/panel/panel.css b/WebContent/VAADIN/themes/runo/panel/panel.css index 8fcfcaf100..138fb07f9c 100644 --- a/WebContent/VAADIN/themes/runo/panel/panel.css +++ b/WebContent/VAADIN/themes/runo/panel/panel.css @@ -67,38 +67,12 @@ overflow: hidden; } /* IE specific rules */ -.v-ie6 .v-panel { - background: transparent; -} -.v-ie6 .v-panel-caption { - border: 1px solid #babfc0; - border-bottom: none; - background: #fff; - margin: 0; - padding-left: 18px -} -.v-ie6 .v-panel-nocaption { - border: none; - background: transparent; - margin: 0; - height: 0; -} -.v-ie6 .v-panel-caption-light { - border: none; - background: transparent; -} -.v-ie6 .v-panel-content, -.v-ie7 .v-panel-content, .v-ie8 .v-panel-content { border-bottom: 1px solid #babfc0; } -.v-ie6 .v-panel-content-light, -.v-ie7 .v-panel-content-light, .v-ie8 .v-panel-content-light { border-bottom: none; } -.v-ie6 .v-panel-deco, -.v-ie7 .v-panel-deco, .v-ie8 .v-panel-deco { height: 0; overflow: hidden; diff --git a/WebContent/VAADIN/themes/runo/select/select.css b/WebContent/VAADIN/themes/runo/select/select.css index ad1744288a..5c66cf81db 100644 --- a/WebContent/VAADIN/themes/runo/select/select.css +++ b/WebContent/VAADIN/themes/runo/select/select.css @@ -22,7 +22,7 @@ .v-popupview-popup .v-filterselect .v-filterselect-input { background: transparent url(img/bg-center-filter.png) no-repeat 1px 0; border: none; - height: 20px; + height: 23px; margin: 0; padding: 2px 0 1px 2px; font-size: 13px; @@ -127,12 +127,6 @@ border-top: 1px solid #b6bbbc; } -/* IE6 needs some help identifying when the input is readonly */ -.v-ie6 .v-filterselect.v-readonly, -.v-ie6 .v-filterselect .v-filterselect-input-readonly { - background: transparent; -} - /* Error styles (disabled by default) ---------------------------------- diff --git a/WebContent/VAADIN/themes/runo/slider/slider.css b/WebContent/VAADIN/themes/runo/slider/slider.css index 07b10dfa17..698d15de90 100644 --- a/WebContent/VAADIN/themes/runo/slider/slider.css +++ b/WebContent/VAADIN/themes/runo/slider/slider.css @@ -68,16 +68,3 @@ background-color: #FFE0E0; } */ - -/* IE specific styles */ - -.v-ie6 .v-slider, -.v-ie6 .v-slider-vertical { - margin: 0; -} -.v-ie6 .v-slider .v-slider-handle { - margin: -1px 0; -} -.v-ie6 .v-slider-vertical .v-slider-handle { - margin: 0 -1px; -}
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/splitpanel/splitpanel.css b/WebContent/VAADIN/themes/runo/splitpanel/splitpanel.css index c74ab257ba..d7851c27e6 100644 --- a/WebContent/VAADIN/themes/runo/splitpanel/splitpanel.css +++ b/WebContent/VAADIN/themes/runo/splitpanel/splitpanel.css @@ -6,13 +6,11 @@ .v-splitpanel-hsplitter, .v-splitpanel-hsplitter-locked { width: 6px; - font-size: 1px; /* for IE6 */ } .v-splitpanel-hsplitter div, .v-splitpanel-hsplitter-locked div { width: 6px; - font-size: 1px; /* for IE6 */ position: absolute; top: 0; bottom: 0; @@ -24,35 +22,16 @@ .v-splitpanel-vsplitter, .v-splitpanel-vsplitter-locked { height: 6px; - font-size: 1px; /* for IE6 */ } .v-splitpanel-vsplitter div, .v-splitpanel-vsplitter-locked div { height: 6px; - font-size: 1px; /* for IE6 */ background: #ccd2d0 url(img/bg_ver.png); border: 1px solid #b6bbbc; margin: -1px 0; } -/* IE6 specific styles */ - -.v-ie6 .v-splitpanel-hsplitter div, -.v-ie6 .v-splitpanel-hsplitter-locked div { - height: 99%; -} - -.v-ie6 .v-splitpanel-vsplitter, -.v-ie6 .v-splitpanel-vsplitter-locked { - height: 8px; -} - -.v-ie6 .v-splitpanel-vsplitter div, -.v-ie6 .v-splitpanel-vsplitter-locked div { - margin: 0; -} - /* Rounded style */ .v-splitpanel-hsplitter-rounded div, @@ -72,10 +51,6 @@ .v-splitpanel-vsplitter-rounded-locked div { margin: -1px 4px; } -.v-ie6 .v-splitpanel-hsplitter-rounded div, -.v-ie6 .v-splitpanel-hsplitter-rounded-locked div { - height: 97%; -} /* Small style */ diff --git a/WebContent/VAADIN/themes/runo/table/table.css b/WebContent/VAADIN/themes/runo/table/table.css index 8c82a6f3e8..42f93752be 100644 --- a/WebContent/VAADIN/themes/runo/table/table.css +++ b/WebContent/VAADIN/themes/runo/table/table.css @@ -28,10 +28,6 @@ text-shadow: #ffffff 0 1px 0; margin-left: 4px; } -.v-ie7 .v-table-caption-container-align-right { - margin-left: 0px; - padding-left: 0px; -} .v-table-sort-indicator { width: 0; height: 36px; @@ -158,20 +154,6 @@ tr.v-table-row-odd:hover { .v-table .v-link { display: inline; } -/* IE6 hack */ -.v-ie6 .v-table-scrollposition { - background: transparent; - /* - AlphaImageLoader uses src attribute relative to host page, not CSS - We need multiple different filters because we cannot be sure how host page is served compared to theme resources - TODO: This actually does not work as expected, since only the last filter is applied. Can we chain filters together (i.e. contain all versions on one line)? - */ - filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../../VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale"); - filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale"); - filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale"); - filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/VAADIN/themes/default/table/img/scroll-position-bg.png", sizingMethod="scale"); -} - /* Borderless style */ .v-table-borderless .v-table-header-wrap, diff --git a/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.css b/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.css index 64cd85b61d..7028b3ed16 100644 --- a/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.css +++ b/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.css @@ -132,24 +132,6 @@ padding-top: 12px; }*/ /* IE specific styles */ -.v-ie6 .v-tabsheet-tabs { - height: 46px; -} -.v-ie6 .v-tabsheet-tabitem-selected { - border: 1px solid #babfc0; - border-bottom: none; - background: #fff; - margin-top: 0; - height: 23px; - padding: 18px 14px 6px 15px; - cursor: default; - color: #ee5311; -} -.v-ie6 .v-tabsheet-tabitem-selected .v-caption { - background: transparent; - padding: 0; - margin: 0; -} .v-ie .v-tabsheet-content { border-bottom: none; } @@ -159,7 +141,6 @@ overflow: hidden; margin: 0; } -.v-ie7 .v-tabsheet-deco, .v-ie8 .v-tabsheet-deco, .v-ie9 .v-tabsheet-deco { width: 100%; @@ -267,23 +248,6 @@ margin-left: -3px; padding-left: 3px; }*/ -/* IE specific styles */ -.v-ie6 .v-tabsheet-tabs-light, -.v-ie7 .v-tabsheet-tabs-light { - height: 32px; -} -.v-ie6 .v-tabsheet-tabs-light .v-tabsheet-tabitem-selected, -.v-ie7 .v-tabsheet-tabs-light .v-tabsheet-tabitem-selected { - border: none; - background: #fff url(img/inline-tab-right.png) no-repeat right top; - padding: 0; - height: 32px; -} -.v-ie6 .v-tabsheet-tabs-light .v-tabsheet-tabitem-selected .v-caption, -.v-ie7 .v-tabsheet-tabs-light .v-tabsheet-tabitem-selected .v-caption { - background: transparent url(img/inline-tab-left.png) no-repeat -7px 0; - padding: 9px 11px 0 11px; -} .v-ie .v-tabsheet-deco-light { height: 0; }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/textfield/textfield.css b/WebContent/VAADIN/themes/runo/textfield/textfield.css index f4ac207ea1..af4443c80f 100644 --- a/WebContent/VAADIN/themes/runo/textfield/textfield.css +++ b/WebContent/VAADIN/themes/runo/textfield/textfield.css @@ -12,7 +12,7 @@ input.v-textfield, input[type=text].v-textfield, textarea.v-textarea { font-size: 12px; - height: 16px; + height: 22px; padding: 2px; } textarea.v-textarea { @@ -39,7 +39,7 @@ input.v-textfield-small, input[type=text].v-textfield-small, textarea.v-textarea-small { font-size: 11px; - height: 14px; + height: 18px; line-height: 12px; padding: 1px 2px; }
\ No newline at end of file diff --git a/WebContent/VAADIN/themes/runo/tree/tree.css b/WebContent/VAADIN/themes/runo/tree/tree.css index 03c8a0d829..14061b8afb 100644 --- a/WebContent/VAADIN/themes/runo/tree/tree.css +++ b/WebContent/VAADIN/themes/runo/tree/tree.css @@ -30,12 +30,6 @@ .v-tree-node-children { padding-left: 16px; } -/* IMPORTANT keep the offsetWidth (width + padding) of this element the same as the margin-left of v-tree-node-caption */ -.v-ie6 .v-tree-node-ie6compatnode { - width: 14px; - height: 10px; - padding: 1px; -} .v-tree{ outline:none; } @@ -47,9 +41,6 @@ .v-tree-node-focused span{ border: 1px dotted black; } -.v-ie6 .v-tree-node-ie6compatnode.v-tree-node-focused{ - padding-left: 0px; -} /*************************************** * Drag'n'drop styles ***************************************/ diff --git a/WebContent/VAADIN/themes/runo/window/window.css b/WebContent/VAADIN/themes/runo/window/window.css index 81509146aa..675c8942bf 100644 --- a/WebContent/VAADIN/themes/runo/window/window.css +++ b/WebContent/VAADIN/themes/runo/window/window.css @@ -9,7 +9,7 @@ background: transparent url(img/top-left.png) no-repeat; } .v-window-outerheader { - height: 23px; + height: 49px; margin-left: 9px; padding: 15px 40px 11px 12px; background: transparent url(img/top-right.png) no-repeat right top; @@ -21,13 +21,15 @@ letter-spacing: -0.03em; color: #f14c1a; text-shadow: 0 1px 0 #fff; - /* This element is 100% wide in IE6 */ } -.v-window-contents { +.v-window-contents > div { background: #fff; border: 2px solid #babfc0; border-top: none; border-bottom: none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .v-window div.v-window-footer { height: 8px; @@ -35,12 +37,7 @@ background: transparent url(img/bottom-right.png) no-repeat right bottom; overflow: visible; } -.v-ie7 .v-window-footer { - position: relative; - overflow: visible; -} -.v-window-resizebox, -.v-ie7 .v-window-resizebox { +.v-window-resizebox { position: absolute; /* Needed to position the element over ScrollPanel, which is relatively positioned */ right: 5px; width: 10px; diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js new file mode 100644 index 0000000000..1f5f3fa973 --- /dev/null +++ b/WebContent/VAADIN/vaadinBootstrap.js @@ -0,0 +1,281 @@ +(function() { + var defaults; + var apps = {}; + var themesLoaded = {}; + var widgetsets = {}; + + + var log; + if (typeof console === "undefined" || !window.location.search.match(/[&?]debug(&|$)/)) { + //If no console.log present, just use a no-op + log = function() {}; + } else if (typeof console.log === "function") { + //If it's a function, use it with apply + log = function() { + console.log.apply(console, arguments); + }; + } else { + //In IE, its a native function for which apply is not defined, but it works without a proper 'this' reference + log = console.log; + } + + var loadTheme = function(url) { + if(!themesLoaded[url]) { + log("loadTheme", url); + var stylesheet = document.createElement('link'); + stylesheet.setAttribute('rel', 'stylesheet'); + stylesheet.setAttribute('type', 'text/css'); + stylesheet.setAttribute('href', url + "/styles.css"); + document.getElementsByTagName('head')[0].appendChild(stylesheet); + themesLoaded[url] = true; + } + } + + var isWidgetsetLoaded = function(widgetset) { + var className = widgetset.replace(/\./g, "_"); + return (typeof window[className]) != "undefined"; + } + + var loadWidgetset = function(basePath, widgetset) { + if (widgetsets[widgetset]) { + return; + } + log("load widgetset", basePath, widgetset) + setTimeout(function() { + if (!isWidgetsetLoaded(widgetset)) { + alert("Failed to load the widgetset: " + url); + } + }, 15000); + + var url = basePath + widgetset + "/" + widgetset + ".nocache.js?" + new Date().getTime(); + + var scriptTag = document.createElement('script'); + scriptTag.setAttribute('type', 'text/javascript'); + scriptTag.setAttribute('src', url); + document.getElementsByTagName('head')[0].appendChild(scriptTag); + + widgetsets[widgetset] = { + pendingApps: [] + }; + } + + window.vaadin = window.vaadin || { + setDefaults: function(d) { + if (defaults) { + log("Ignoring new defaults as defaults have already been loaded"); + return; + } + log("Got defaults", d) + defaults = d; + }, + initApplication: function(appId, config) { + if (apps[appId]) { + throw "Application " + appId + " already initialized"; + } + log("init application", appId, config); + + var testbenchId = appId.replace(/-\d+$/, ''); + window.vaadin.clients[testbenchId] = { + isActive: function() { + return true; + } + } + + var getConfig = function(name) { + var value = config[name]; + if (value === undefined) { + value = defaults[name]; + } + return value; + } + + var fetchRootConfig = function() { + log('Fetching root config'); + var url = getConfig('browserDetailsUrl'); + if (!url) { + // No special url defined, use the default URL + url = getConfig('appUri'); + // Add a slash to the end, because ApplicationConiguration.loadFromDOM does so... + if (url.length == 0 || url.substr(url.length-1) !== "/") { + url += '/'; + } + } + url += ((/\?/).test(url) ? "&" : "?") + "browserDetails"; + var rootId = getConfig("rootId"); + if (rootId !== undefined) { + url += "&rootId=" + rootId; + } + + url += '&initialPath=' + encodeURIComponent(getConfig("initialPath")); + url += '&initialParams=' + encodeURIComponent(JSON.stringify(getConfig("initialParams"))); + + url += '&' + vaadin.getBrowserDetailsParameters(appId); + + // Timestamp to avoid caching + url += '&' + (new Date()).getTime(); + + var r = new XMLHttpRequest(); + r.open('POST', url, true); + r.onreadystatechange = function (aEvt) { + if (r.readyState == 4) { + if (r.status == 200){ + log("Got root config response", r.responseText); + var updatedConfig = JSON.parse(r.responseText); + + // Copy new properties to the config object + for (var property in updatedConfig) { + if (updatedConfig.hasOwnProperty(property)) { + config[property] = updatedConfig[property]; + } + } + + // Try bootstrapping again, this time without fetching missing info + bootstrapApp(false); + } else { + log('Error', r.statusText); + } + } + }; + r.send(null); + + log('sending request to ', url); + }; + + //Export public data + var app = { + 'getConfig': getConfig + }; + apps[appId] = app; + + if (!window.name) { + window.name = appId + '-' + Math.random(); + } + + var bootstrapApp = function(mayDefer) { + var themeUri = getConfig('themeUri'); + if (themeUri) { + loadTheme(themeUri); + } + + var widgetsetBase = getConfig('widgetsetBase'); + var widgetset = getConfig('widgetset'); + if (widgetset && widgetsetBase) { + loadWidgetset(widgetsetBase, widgetset); + } + + if (getConfig('uidl') === undefined) { + if (mayDefer) { + fetchRootConfig(); + } else { + throw "May not defer bootstrap any more"; + } + } else { + if (widgetsets[widgetset].callback) { + log("Starting from bootstrap", appId); + widgetsets[widgetset].callback(appId); + } else { + log("Setting pending startup", appId); + widgetsets[widgetset].pendingApps.push(appId); + } + } + } + bootstrapApp(true); + + if (getConfig("debug")) { + // TODO debug state is now global for the entire page, but should somehow only be set for the current application + window.vaadin.debug = true; + } + + return app; + }, + clients: {}, + getApp: function(appId) { + var app = apps[appId]; + return app; + }, + loadTheme: loadTheme, + registerWidgetset: function(widgetset, callback) { + log("Widgetset registered", widgetset) + widgetsets[widgetset].callback = callback; + for(var i = 0; i < widgetsets[widgetset].pendingApps.length; i++) { + var appId = widgetsets[widgetset].pendingApps[i]; + log("Starting from register widgetset", appId); + callback(appId); + } + widgetsets[widgetset].pendingApps = null; + }, + getBrowserDetailsParameters: function(parentElementId) { + // Screen height and width + var url = 'sh=' + window.screen.height; + url += '&sw=' + window.screen.width; + + // Window height and width + var cw = 0; + var ch = 0; + if(typeof(window.innerWidth) == 'number') { + // Modern browsers + cw = window.innerWidth; + ch = window.innerHeight; + } else { + // IE 8 + cw = document.documentElement.clientWidth; + ch = document.documentElement.clientHeight; + } + url += '&cw=' + cw + '&ch=' + ch; + + + var d = new Date(); + + url += '&curdate=' + d.getTime(); + + var tzo1 = d.getTimezoneOffset(); // current offset + var dstDiff = 0; + var rtzo = tzo1; + + for (var m=12;m>0;m--) { + d.setUTCMonth(m); + var tzo2 = d.getTimezoneOffset(); + if (tzo1 != tzo2) { + dstDiff = (tzo1 > tzo2 ? tzo1-tzo2 : tzo2-tzo1); // offset w/o DST + rtzo = (tzo1 > tzo2 ? tzo1 : tzo2); // offset w/o DST + break; + } + } + + // Time zone offset + url += '&tzo=' + tzo1; + + // DST difference + url += '&dstd=' + dstDiff; + + // Raw time zone offset + url += '&rtzo=' + rtzo; + + // DST in effect? + url += '&dston=' + (tzo1 != rtzo); + + var pe = document.getElementById(parentElementId); + if (pe) { + url += '&vw=' + pe.offsetWidth; + url += '&vh=' + pe.offsetHeight; + } + + // Uri fragment + if (location.hash) { + //Remove initial # + url += '&fr=' + encodeURIComponent(location.hash.replace(/^#/, "")); + } + // Window name + if (window.name) { + url += '&wn=' + encodeURIComponent(window.name); + } + + // Detect touch device support + try { document.createEvent("TouchEvent"); url += "&td=1";} catch(e){}; + + return url; + } + }; + + log('Vaadin bootstrap loaded'); +})();
\ No newline at end of file diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml index 73d9951d21..5b250d86f2 100644 --- a/WebContent/WEB-INF/web.xml +++ b/WebContent/WEB-INF/web.xml @@ -22,11 +22,7 @@ <servlet> <servlet-name>VaadinApplicationRunner</servlet-name> - <servlet-class>com.vaadin.terminal.gwt.server.ApplicationRunnerServlet</servlet-class> - <init-param> - <param-name>defaultPackages</param-name> - <param-value>com.vaadin.tests,com.vaadin.tests.tickets,com.vaadin.tests.components,com.vaadin.tests.components.layouts,com.vaadin.tests.components.panel,com.vaadin.tests.components.combobox,com.vaadin.tests.components.popupview,com.vaadin.tests.components.datefield,com.vaadin.tests.components.richtextarea,com.vaadin.tests.components.absolutelayout,com.vaadin.tests.components.embedded,com.vaadin.tests.components.splitpanel,com.vaadin.tests.components.abstractfield,com.vaadin.tests.components.form,com.vaadin.tests.components.table,com.vaadin.tests.components.accordion,com.vaadin.tests.components.label,com.vaadin.tests.components.tabsheet,com.vaadin.tests.components.beanitemcontainer,com.vaadin.tests.components.link,com.vaadin.tests.components.textfield,com.vaadin.tests.components.button,com.vaadin.tests.components.optiongroup,com.vaadin.tests.components.tree,com.vaadin.tests.components.caption,com.vaadin.tests.components.orderedlayout,com.vaadin.tests.components.window,com.vaadin.tests.dd,com.vaadin.tests.validation</param-value> - </init-param> + <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class> </servlet> <!-- For testing GAE - the deployment script changes this to use GAEApplicationServlet --> diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html index 4574766ea9..1b56b7fb9c 100644 --- a/WebContent/release-notes.html +++ b/WebContent/release-notes.html @@ -1,14 +1,14 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> -<head> -<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> -<title>Vaadin Framework @version@</title> -<link rel="stylesheet" type="text/css" href="css/styles.css" /> - -<!--[if lte IE 6]> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Vaadin Framework @version@</title> + <link rel="stylesheet" type="text/css" href="css/styles.css" /> + + <!--[if lte IE 6]> <link rel="stylesheet" type="text/css" href="css/ie.css" /> <![endif]--> -<style type="text/css"> + <style type="text/css"> .nested-list ol { counter-reset: item } @@ -22,352 +22,414 @@ counter-increment: item } </style> -</head> -<!-- /head --> -<body> - - <div id="header"> - <h1>Vaadin – thinking of U and I</h1> - <div id="version"> - <strong>Version @version@</strong> - </div> - </div> - <!-- /header --> - - <div id="content"> - - <p>Version @version@ built on @builddate@.</p> - - <h2 id="tableofcontents">Release Notes for Vaadin Framework - @version@</h2> - <ul> - <li><a href="#overview">Package contents</a> - </li> - <!-- <li><a href="#security-fixes">Security fixes in Vaadin @version-minor@</a> - </li> - --> - <li><a href="#enhancements">Enhancements in Vaadin @version-minor@</a> - </li> - <li><a href="#fixes">Fixes in Vaadin @version@</a> - </li> - <li><a href="#backwardsincompatibilities">Backwards - incompatible changes in Vaadin @version-minor@</a> - </li> - <li><a href="#dependencies">Vaadin @version@ dependencies</a> - </li> - <li><a href="#upgrading">Upgrading to Vaadin @version-minor@</a> - </li> - <li><a href="#knownissues">Known problems and limitations in - Vaadin @version@</a> - </li> - <li><a href="#supportedversions">Supported technologies</a> - </li> - </li> - <li><a href="#vaadinontheweb">Vaadin on the Web</a> - </li> - </ul> - <h2 id="overview">Package Contents</h2> - <p> - <b>Vaadin</b> is a Java framework for building modern web - applications that look great, perform well and make you and your - users happy. <b>Vaadin</b> is available under the Apache 2 license - (see license.html). - </p> - <p> - <b>Vaadin</b> is distributed as a single JAR file. Inside the JAR you - will find: - <ul> - <li>Vaadin server and client side classes (/com)</li> - <li>Vaadin server and client side sources (/com)</li> - <li>The default widget set (/VAADIN/widgetsets)</li> - <li>Themes: Runo, Reindeer and Chameleon (/VAADIN/themes)</li> - <li>Release notes (/release-notes.html)</li> - <li>Licensing information (/license.html)</li> - </ul> - </p> - - <!-- <h2 id="security-fixes">Security fixes in Vaadin @version-minor@</h2>--> - - <h2 id="enhancements">Enhancements in Vaadin @version-minor@</h2> - <p> - <b>TODO: Enhancements</b> - </p> - <p>TOdO: Enhancements.</p> - <h2 id="fixes">Fixes in Vaadin @version@</h2> + </head> + + <body> + <div id="header"> + <h1>Vaadin – thinking of U and I</h1> + <div id="version"> + <strong>Version @version@</strong> + </div> + </div> <!-- /header --> + + <div id="content"> + <p>Version @version@ built on @builddate@.</p> + + <h2 id="tableofcontents">Release Notes for Vaadin Framework @version@</h2> + <ul> + <li><a href="#overview">Package contents</a></li> + <li><a href="#enhancements">Enhancements in Vaadin @version-minor@</a></li> + <li><a href="#changelog">Complete change log for Vaadin @version@</a></li> + <li><a href="#migrating">Migrating from Vaadin 6 to Vaadin 7</a></li> + <li><a href="#dependencies">Vaadin @version@ dependencies</a></li> + <li><a href="#upgrading">Upgrading to Vaadin @version-minor@</a></li> + <li><a href="#supportedversions">Supported technologies</a></li> + <li><a href="#vaadinontheweb">Vaadin on the Web</a></li> + </ul> + + <h2 id="overview">Package Contents</h2> + + <p> + <b>Vaadin</b> is a Java framework for building modern web applications that look + great, perform well and make you and your users happy. <b>Vaadin</b> is available + under the Apache 2 license (see license.html). + </p> + + <p> + <b>Vaadin</b> is distributed as a single JAR file. Inside the JAR you will find: + </p> + + <ul> + <li>Vaadin server and client side classes (<tt>/com</tt>)</li> + <li>Vaadin server and client side sources (<tt>/com</tt>)</li> + <li>The default widget set (<tt>/VAADIN/widgetsets</tt>)</li> + <li>Themes: Runo, Reindeer and Chameleon (<tt>/VAADIN/themes</tt>)</li> + <li>Release notes (<tt>/release-notes.html</tt>)</li> + <li>Licensing information (<tt>/license.html</tt>)</li> + </ul> + + <h2 id="enhancements">Enhancements in Vaadin @version-minor@</h2> + + <p> + @version-minor@ is the second development release of the upcoming Version 7 of the + Vaadin Framework. It introduces the second set of new features in Vaadin 7, for the + purpose of receiving feedback about the changes. + </p> + + <p>The major changes in this second alpha phase are: + + <ul> + <li>Complete overhaul of the client-server communication architecture + <ul> + <li>All add-on components that have widgets need to be ported to Vaadin 7</li> + <li>Integration of a GWT widget is done in a <i>connector</i> class</li> + <li>Component-to-widget mapping now defined on the client-side, in the connector</li> + <li>No more <b style="text-decoration: line-through">Paintable</b> or <b style="text-decoration: line-through">VariableOwner</b> + <li>Server-side component and client-side widget can have a <emphasis>shared state</emphasis> object which is automatically synchronized</li> + <li>Both client-side and server-side can make RPC calls to the other side + <ul> + <li>Communicated in the next request/response</li> + <li>No return values + <li>Typically for communicating events</li> + </ul> + </li> + <li>UIDL is deprecated</li> + <li>Compatibility layer for Vaadin 6 included for easy migration</li> + </ul> + </li> + <li>Get computed style of a component from the browser</li> + <li>Support for border, padding, and margin in core layout components</li> + </ul> + + <p> + The enchancements are described in more detail in the <a + href="https://vaadin.com/wiki/-/wiki/Main/Vaadin+7">mini-tutorials</a> in the + Vaadin Wiki. + </p> + + <h3 id="changelog">ChangeLog</h3> + + <p> + For a complete list of changes in this release, please see the <a + href="http://dev.vaadin.com/query?status=closed&group=resolution&milestone=Vaadin+7.0.0.alpha2">list + of closed tickets</a>. + </p> + + <h2 id="migrating">Migrating from Vaadin 6</h2> + + <p> + All Vaadin 6 applications need some changes when migrating to Vaadin 7. The most + obvious changes are in the application/window API and require extending either + <b>Root</b> or <b>Root.LegacyApplication</b> instead of <b>Application</b>. + </p> + + <p> + Vaadin 6 add-ons (ones that contain widgets) do not work in Vaadin 7 - please + check the add-ons in <a href="http://vaadin.com/directory/">Vaadin Directory</a> + for Vaadin 7 support. + </p> + + <p> + Any custom client-side widgets need to be changed to use the new client-server + communication API or the Vaadin 6 compatibility API. + </p> + + <p> + A detailed list of migration changes are given in the <a + href="http://dev.vaadin.com/wiki/Vaadin7/MigrationGuide">Vaadin 7 Migration + Guide</a>. + </p> + + <h2 id="dependencies">Vaadin @version@ Dependencies</h2> + + <h3>Google Web Toolkit (GWT)</h3> + + <p> + Vaadin uses GWT @gwt-version@ for widget set compilation. GWT can be downloaded + from <a + href="http://code.google.com/webtoolkit/">http://code.google.com/webtoolkit/</a>. + GWT can also be automatically downloaded by the Vaadin Plug-in for Eclipse. Please + note that GWT @gwt-version@ requires the <i>validation-api-1.0.0.GA.jar</i> and + <i>validation-api-1.0.0.GA-sources.jar</i> files in addition to <i>gwt-dev.jar</i> + and <i>gwt-user.jar</i> for widget set compilation. + </p> + + <h3>Bean Validation</h3> + + <p> + If you want to use the bean validation feature in Vaadin 7, you need a Bean + Validation API implementation. You need to install the JAR in the + <tt>WEB-INF/lib</tt> directory. + </p> + + <h2 id="upgrading">Upgrading to Vaadin @version-minor@</h2> + + <h3>Upgrading the Eclipse Plugin</h3> + + <p> + This release requires that you use the <i>experimental</i> Vaadin Plugin for + Eclipse. Its update site is + <tt>http://vaadin.com/eclipse/experimental</tt>. Please see the <a + href="http://vaadin.com/eclipse">installation instructions</a> for more details. + </p> + + <h3>General Upgrading Instructions</h3> + + <p> + When upgrading from an earlier Vaadin version, you must: + </p> - <p> - TODO: Ticket list - </p> - <p> - The <a href="http://dev.vaadin.com/query?status=closed&type=defect&milestone=Vaadin%20@version@">full - details of the defects</a> can be found at dev.vaadin.com. - </p> - - <h2 id="backwardsincompatibilities">Backwards incompatible - changes in Vaadin @version-minor@</h2> - <p>VerticalSplitPanel and HorizontalSplitPanel position is now a float instead of an int to enable defining an exact position when using percentages.</p> - - <h2 id="dependencies">Vaadin @version@ dependencies</h2> - Vaadin uses GWT @gwt-version@ for widget set compilation. GWT can be - downloaded from <a href="http://code.google.com/webtoolkit/">http://code.google.com/webtoolkit/</a>. - GWT can also be automatically downloaded by the Vaadin Plug-in for - Eclipse. Please note that GWT @gwt-version@ requires the <i>validation-api-1.0.0.GA.jar</i> - and <i>validation-api-1.0.0.GA-sources.jar</i> files in addition to <i>gwt-dev.jar</i> - and <i>gwt-user.jar</i> for widget set compilation. - - <h2 id="upgrading">Upgrading to Vaadin @version-minor@</h2> - <p> - When upgrading from an earlier Vaadin version, you must - <ul> - <li>Recompile your classes using the new Vaadin JAR. Binary - compatibility is only guaranteed for maintenance releases of - Vaadin.</li> - <li>Recompile any add-ons you have created using the new Vaadin - JAR.</li> - <li>Recompile your widget set using the new Vaadin JAR and the - newly compiled add-ons.</li> - <li>If you have extracted a theme from the Vaadin JAR, you need - to update it with the theme provided in the new Vaadin JAR.</li> - </ul> - </p> - <p>Remember also to refresh the project in your IDE to ensure that - the new version of everything is in use.</p> - <p>Using the "?debug" URL parameter you can verify that the - version of the servlet (JAR), the theme and the widgetset all match.</p> - <p> - <b>Eclipse</b> users should always check if there is a new version of - the Eclipse Plug-in available. The Eclipse Plug-in can be used to - update the Vaadin version in the project (Project properties » - Vaadin). - </p> - - <p> - <b>Maven</b> users should update the Vaadin dependency version in the - <tt>pom.xml</tt> - unless it is defined as - <tt>LATEST</tt> - . You must also ensure that the GWT dependency uses the correct - version and recompile your project and your widget set. - - </p> - - <b>Liferay and other portal</b> users must install the new - vaadin-@version@.jar as - <t>ROOT/WEB-INF/lib/vaadin.jar</b> in the portal. Additionally the - contents of the <tt>VAADIN</tt> folder from the JAR must be extracted - to the <tt>ROOT/html/VAADIN</tt> directory in the Liferay - installation. If your portal uses custom widgets, install the latest - version of <a - href="http://vaadin.com/directory#addon/vaadin-control-panel-for-liferay">Vaadin - Control Panel for Liferay</a> for easy widget set compilation. - - <h3>Upgrading from Vaadin 6.5 or earlier</h3> - If you are upgrading from 6.5.x or earlier, notice that Vaadin - @version@ uses GWT @gwt-version@. Upgrade your dependencies as - necessary. See <a href="#dependencies">the dependencies</a> section - for more information. - </p> - - <h3 id="widgetupgrade">Upgrading from Vaadin 6.1 or earlier</h3> - - <p> - The way widget sets are created was completely changed in Vaadin 6.2. - Existing projects, where custom widgets (a custom widget set) are - used, must be migrated when upgrading to Vaadin 6.2 or later. - Projects where the default widget set is used do not need migration. - See <a - href="http://vaadin.com/download/release/6.2/6.2.0/release-notes.html">Vaadin - 6.2.0 release notes</a> for more details. - </p> - - <h4 id="gae">Notes and Limitations for Google App Engine</h4> - - <p>The following instructions and limitations apply when you run a - Vaadin application under the Google App Engine.</p> - - <ul> - <li><p> - Applications must use <b>GAEApplicationServlet</b> instead of <b>ApplicationServlet</b> - in - <tt>web.xml</tt> - . - </p> - </li> - - <li><p> - Session support must be enabled in - <tt>appengine-web.xml</tt> - : - </p> <pre> <sessions-enabled>true</sessions-enabled></pre> - </li> - - <li><p>Avoid using the session for storage, usual App Engine - limitations apply (no synchronization, i.e, unreliable).</p> - </li> - - <li><p> - Vaadin uses memcache for mutex, the key is of the form - <tt>_vmutex<sessionid></tt> - . - </p> - </li> - - <li><p> - The Vaadin <b>WebApplicationContext</b> class is serialized - separately into memcache and datastore; the memcache key is - <tt>_vac<sessionid></tt> - and the datastore entity kind is - <tt>_vac</tt> - with identifiers of the type - <tt>_vac<sessionid></tt> - . - </p> - </li> - - <li><p> - DO NOT update application state when serving an <b>ApplicationResource</b> - (e.g <b>ClassResource</b>.<i>getStream()</i>). - </p> - </li> - - <li><p> - AVOID (or be very careful when) updating application state in a <b>TransactionListener</b> - or a <b>HttpServletRequestListener</b> - they are called even when - the application is not locked and won't be serialized (e.g <b>ApplicationResource</b>), - and changes can thus go missing (it should be safe to update things - that can be safely discarded later - i.e valid only for the current - request) - </p> - </li> - - <li><p>The application remains locked during uploads - a - progress bar is not possible</p> - </li> - </ul> - - - <p> - For other known problems, see open tickets at developer site <a - href="http://dev.vaadin.com/">dev.vaadin.com</a>. - </p> - - <h2 id="supportedversions">Supported technologies</h2> - - <p> - Vaadin is based on <b>Java 5</b> and it is also compatible with most - other operating system supporting Java 5 or newer. Vaadin is - supported on the following <b>operating systems</b>: - </p> - - <ul> - <li>Windows (see the <a href="#knownissues">Zip installation - notice above</a>)</li> - <li>Linux</li> - <li>Mac OS X</li> - </ul> - - <p> - Vaadin requires <b>Java Servlet API 2.3</b> but also supports later - versions and should work with any Java application server that - conforms to the standard. The following <b>application servers</b> - are supported: - </p> - - <ul> - <li>Apache Tomcat, version 4.1-7.0</li> - <li>Oracle WebLogic® Server, version 9.2-10.3.5(11gR1)</li> - <li>IBM WebSphere® Application Server, version 6.1-8.0</li> - <li>JBoss Application Server, 3.2.8-7.0</li> - <li>Jetty, version 5.0-7.0</li> - <li>Glassfish, version 2.0-3.1</li> - </ul> - <p> - Vaadin supports JSR-168 and JSR-286 Portlet specifications. All - portals that implement either of the portlet specifications should - work. The following <b>portals</b> are supported: - </p> - <ul> - <li>Liferay Portal 5.2-6.0</li> - <li>GateIn Portal 3.1</li> - <li>eXo Platform 3</li> - <li>Oracle WebLogic® Portal 10gR3</li> - <li>WebSphere Portal 6.1-7.0</li> - </ul> - <p> - Vaadin also supports <b>Google App Engine</b>. - </p> - <p> - Vaadin supports the following <b>browsers</b>: - </p> - - <ul> - <li>Mozilla Firefox 3-10</li> - <li>Internet Explorer 6-9</li> - <li>Safari 4-5</li> - <li>Opera 10-11</li> - <li>Google Chrome 13-16</li> - </ul> - - <p> - Vaadin supports the built-in browsers in the following <b>mobile operating - systems</b>: - </p> - - <ul> - <li>iOS 4-5</li> - <li>Android 2-3</li> - </ul> - - <h2 id="vaadinontheweb">Vaadin on the Web</h2> - <p> - <ul> - <li><a href="http://vaadin.com">vaadin.com - The developer - portal containing everything you need to know about Vaadin</a> - </li> - <li><a href="http://demo.vaadin.com">demo.vaadin.com - A - collection of demos for Vaadin</a></li> - <li><a href="http://vaadin.com/learn">vaadin.com/learn - - Getting started with Vaadin</a></li> - <li><a href="http://vaadin.com/forum">vaadin.com/forum - - Forums for Vaadin related discussions - </li> - <li><a href="http://vaadin.com/book">vaadin.com/book - Book - of Vaadin - everything you need to know about Vaadin - </li> - <li><a href="http://vaadin.com/api">vaadin.com/api - Online - javadocs - </li> - <li><a href="http://vaadin.com/directory">vaadin.com/directory - - Add-ons for Vaadin - </li> - <li><a href="http://dev.vaadin.com">dev.vaadin.com - Bug - tracker - </li> - <li><a - href="http://dev.vaadin.com/svn/versions/@version-minor@">dev.vaadin.com/svn/versions/@version-minor@ - - Source code - </li> - <li><a href="http://vaadin.com/pro-account">vaadin.com/pro-account - - Commercial support and tools for Vaadin development - </li> - <li><a href="http://vaadin.com/services">vaadin.com/services - - Expert services for Vaadin - </li> - <li><a href="http://vaadin.com/company">vaadin.com/company - - Information about the company behind Vaadin - </li> - </ul> - </p> - </div> - <!-- /content--> + <ul> + <li>Recompile your classes using the new Vaadin JAR. Binary + compatibility is only guaranteed for maintenance releases of + Vaadin.</li> + + <li>Recompile any add-ons you have created using the new Vaadin + JAR.</li> + + <li>Recompile your widget set using the new Vaadin JAR and the newly compiled + add-ons.</li> + + <li>If you have extracted a theme from the Vaadin JAR, you need to update it with + the theme provided in the new Vaadin JAR.</li> + </ul> + + <p> + Remember also to refresh the project in your IDE to ensure that the new version of + everything is in use. + </p> + + <p> + Using the "?debug" URL parameter you can verify that the version of the servlet + (JAR), the theme and the widgetset all match. + </p> + + <p> + <b>Eclipse</b> users should always check if there is a new version of + the Eclipse Plug-in available. The Eclipse Plug-in can be used to + update the Vaadin version in the project (Project properties » + Vaadin). + </p> + + <p> + <b>Maven</b> users should update the Vaadin dependency version in the + <tt>pom.xml</tt> unless it is defined as <tt>LATEST</tt> . You must also ensure + that the GWT dependency uses the correct version and recompile your project and + your widget set. + </p> + + <p> + <b>Liferay and other portal</b> users must install the new vaadin-@version@.jar as + <t>ROOT/WEB-INF/lib/vaadin.jar</b> in the portal. Additionally the contents of the + <tt>VAADIN</tt> folder from the JAR must be extracted to the + <tt>ROOT/html/VAADIN</tt> directory in the Liferay installation. If your portal + uses custom widgets, install the latest version of <a + href="http://vaadin.com/directory#addon/vaadin-control-panel-for-liferay">Vaadin + Control Panel for Liferay</a> for easy widget set compilation. + </p> + + <h2 id="gae">Notes and Limitations for Google App Engine</h4> + + <p>The following instructions and limitations apply when you run a Vaadin + application under the Google App Engine.</p> + + <ul> + <li> + <p> + Applications must use <b>GAEApplicationServlet</b> instead of + <b>ApplicationServlet</b> in <tt>web.xml</tt>. + </p> + </li> + + <li> + <p> + Session support must be enabled in + <tt>appengine-web.xml</tt>: + </p> + + <pre> <sessions-enabled>true</sessions-enabled></pre> + </li> + + <li> + <p> + Avoid using the session for storage, usual App Engine limitations apply (no + synchronization, i.e, unreliable). + </p> + </li> + + <li> + <p> + Vaadin uses memcache for mutex, the key is of the form + <tt>_vmutex<sessionid></tt>. + </p> + </li> + + <li> + <p> + The Vaadin <b>WebApplicationContext</b> class is serialized separately into + memcache and datastore; the memcache key is <tt>_vac<sessionid></tt> and + the datastore entity kind is <tt>_vac</tt> with identifiers of the type + <tt>_vac<sessionid></tt>. + </p> + </li> + + <li> + <p> + DO NOT update application state when serving an <b>ApplicationResource</b> + (e.g <b>ClassResource</b>.<i>getStream()</i>). + </p> + </li> + + <li> + <p> + AVOID (or be very careful when) updating application state in a + <b>TransactionListener</b> or a <b>HttpServletRequestListener</b> - they are + called even when the application is not locked and won't be serialized (e.g + <b>ApplicationResource</b>), and changes can thus go missing (it should be + safe to update things that can be safely discarded later - i.e valid only for + the current request) + </p> + </li> + + <li> + <p> + The application remains locked during uploads - a progress bar is not + possible + </p> + </li> + </ul> + + <p> + For other known problems, see open tickets at developer site <a + href="http://dev.vaadin.com/">dev.vaadin.com</a>. + </p> + + <h2 id="supportedversions">Supported Technologies</h2> + + <p> + Vaadin 7 is compatible with <b>Java 5</b> and it is also compatible with most other + operating system supporting Java 5 or newer. However, using Java 6 is recommended, + as it is required by widget set compilation. + </p> + + <p> + Vaadin 7 is supported on the following <b>operating systems</b>: + </p> + + <ul> + <li>Windows</li> + <li>Linux</li> + <li>Mac OS X</li> + </ul> + + <p> + Vaadin 7 requires <b>Java Servlet API 2.4</b> but also supports later versions and + should work with any Java application server that conforms to the standard. The + following <b>application servers</b> are supported: + </p> + + <ul> + <li>Apache Tomcat, version 5.0-7.0</li> + <li>Oracle WebLogic® Server, version 9.2-10.3.5(11gR1)</li> + <li>IBM WebSphere® Application Server, version 6.1-8.0</li> + <li>JBoss Application Server, 4.0.0-7.0</li> + <li>Jetty, version 5.0-7.0</li> + <li>Glassfish, version 2.0-3.1</li> + </ul> + + <p> + Vaadin 7 supports the JSR-286 Portlet specification. All portals that + implement either of the portlet specifications should work. The following + <b>portals</b> are supported: + </p> + + <ul> + <li>Liferay Portal 5.2-6.0</li> + <li>GateIn Portal 3.1</li> + <li>eXo Platform 3</li> + </ul> + + <p> + Vaadin also supports <b>Google App Engine</b>. + </p> + + <p> + Vaadin supports the following <b>browsers</b>: + </p> + + <ul> + <li>Mozilla Firefox 11</li> + <li>Internet Explorer 8-9</li> + <li>Safari 5</li> + <li>Opera 11</li> + <li>Google Chrome 18</li> + </ul> + + <h2 id="vaadinontheweb">Vaadin on the Web</h2> + + <ul> + <li><a href="http://vaadin.com">vaadin.com - The developer + portal containing everything you need to know about Vaadin</a> + </li> + <li><a href="http://demo.vaadin.com">demo.vaadin.com - A + collection of demos for Vaadin</a></li> + <li><a href="http://vaadin.com/learn">vaadin.com/learn - + Getting started with Vaadin</a></li> + <li><a href="http://vaadin.com/forum">vaadin.com/forum - + Forums for Vaadin related discussions</a> + </li> + <li><a href="http://vaadin.com/book">vaadin.com/book - Book + of Vaadin - everything you need to know about Vaadin</a> + </li> + <li><a href="http://vaadin.com/api">vaadin.com/api - Online + javadocs</a> + </li> + <li><a href="http://vaadin.com/directory">vaadin.com/directory + - Add-ons for Vaadin</a> + </li> + + <li><a href="http://vaadin.com/pro-account">vaadin.com/pro-account + - Commercial support and tools for Vaadin development </a> + </li> + <li><a href="http://vaadin.com/services">vaadin.com/services + - Expert services for Vaadin</a> + </li> + <li><a href="http://vaadin.com/company">vaadin.com/company + - Information about the company behind Vaadin</a> + </li> + + <li><a href="http://dev.vaadin.com">dev.vaadin.com - Bug tracker</a></li> + + <li><a + href="http://dev.vaadin.com/wiki/Vaadin/Development/StartingVaadin7Development">How + to get the source code of Vaadin</a> + </li> + </ul> + </div> <!-- /content--> <div id="footer"> <span class="slogan"><strong>vaadin <em>}></em> </strong> thinking of U and I<span> <a href="#top">↑ Back to top</a> - </div> - <!-- /footer --> - -</body> -</html>
\ No newline at end of file + </div> <!-- /footer --> + </body> +</html> + +<!-- Keep this comment at the end of the file +Local variables: +mode: xml +sgml-omittag:nil +sgml-shorttag:nil +sgml-namecase-general:nil +sgml-general-insert-case:lower +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-exposed-tags:nil +sgml-local-catalogs:("/etc/sgml/catalog" "/usr/share/xemacs21/xemacs-packages/etc/psgml-dtds/CATALOG") +sgml-local-ecat-files:("ECAT" "~/sgml/ECAT" "/usr/share/sgml/ECAT" "/usr/local/share/sgml/ECAT" "/usr/local/lib/sgml/ECAT") +End: +--> diff --git a/WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html b/WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html new file mode 100644 index 0000000000..2e280da64e --- /dev/null +++ b/WebContent/statictestfiles/browserfeatures/fullHeightScrollbar.html @@ -0,0 +1,59 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> +<style type="text/css"> +.wrapper { + height: 150px; + width: 150px; + border: 1px solid black; + overflow: auto; + position: relative; +} + +.content { + height: 100%; + width: 250px; + background: grey; +} + +</style> +<script type="text/javascript"> +function disableScrolling() { + var result = document.getElementsByClassName("content"); + for(var i = 0; i < result.length; i++) { + var e = result[i]; + e.style.width = "100%"; + } +} + +function triggerReflow() { + var style = "top"; + var styleValue = "1px"; + var result = document.getElementsByClassName("wrapper"); + for(var i = 0; i < result.length; i++) { + var e = result[i]; + var originalValue = e.style[style]; + e.style[style] = styleValue; + e.offsetWidth; + e.style[style] = originalValue; + } +} +</script> +</head> +<body scroll="auto"> +<p>This test is used to verify how browsers take horizontal scrollbars into account when calculating 100% height and what happens when scrolling is no longer needed. This test tells which browsers need which workarounds for related features.</p> + +<p>Basic situation. +<div class="wrapper"><div class="content"></div></div> +</p> + +<p> +Situation with position: absolute on the inner element. +<div class="wrapper"><div class="content" style="position: absolute"></div></div> +</p> + +<button id="disableScrolling" onclick="disableScrolling()">Disable scrolling</button> +<button id="triggerReflow" onclick="triggerReflow()">Trigger reflow</button> +</body> +</html> diff --git a/build/GWT-VERSION.properties b/build/GWT-VERSION.properties new file mode 100644 index 0000000000..028ad8b4de --- /dev/null +++ b/build/GWT-VERSION.properties @@ -0,0 +1,2 @@ +gwt-version=2.4.0 +gwt-version-dependencies=validation-api-1.0.0.GA.jar, validation-api-1.0.0.GA-sources.jar diff --git a/build/VERSION.properties b/build/VERSION.properties new file mode 100644 index 0000000000..ce706c5d02 --- /dev/null +++ b/build/VERSION.properties @@ -0,0 +1 @@ +version=7.0.0
\ No newline at end of file diff --git a/build/bin/package-diff.py b/build/bin/package-diff.py index f3b0d59562..a9f29e40a9 100644 --- a/build/bin/package-diff.py +++ b/build/bin/package-diff.py @@ -56,7 +56,7 @@ def listJarFiles(jarfile): # JAPI - Java API Differences ################################################################################ def japize(version, jarfile): - cmd = "%s as %s apis %s +com.vaadin, $JAVA_HOME/jre/lib/rt.jar lib/core/**/*.jar 2>/dev/null" % (JAPIZE, version, jarfile) + cmd = "%s as %s apis %s +com.vaadin, $JAVA_HOME/jre/lib/rt.jar 2>/dev/null" % (JAPIZE, version, jarfile) command (cmd) return "%s.japi.gz" % (version) diff --git a/build/build.properties b/build/build.properties index 9e126a4479..a1b285c952 100644 --- a/build/build.properties +++ b/build/build.properties @@ -10,10 +10,8 @@ snapshot.repository.url=http://oss.sonatype.org/content/repositories/vaadin-snap # These are required when compiling WebContent/VAADIN/widgetsets (and also # Java server-side classes). -# Using special -noservlet packages to be able to use a different version of -# the servlet specification than what the GWT JARs include. -lib-gwt-dev=${gwt-dir}/gwt-dev-noservlet.jar -lib-gwt-user=${gwt-dir}/gwt-user-noservlet.jar +lib-gwt-dev=${gwt-dir}/gwt-dev.jar +lib-gwt-user=${gwt-dir}/gwt-user.jar # FIXME: Should use ${gwt-version-dependencies} lib-gwt-validation=${gwt-dir}/validation-api-1.0.0.GA.jar lib-gwt-validation-src=${gwt-dir}/validation-api-1.0.0.GA-sources.jar diff --git a/build/build.xml b/build/build.xml index a6a75b8918..573c799f7d 100644 --- a/build/build.xml +++ b/build/build.xml @@ -2,9 +2,14 @@ <project xmlns:antcontrib="antlib:net.sf.antcontrib" xmlns:artifact="antlib:org.apache.maven.artifact.ant" + xmlns:ivy="antlib:org.apache.ivy.ant" name="Vaadin" basedir="../" default="package-all"> + <property name="project.root" value="."/> + <!-- Import common targets --> + <import file="./common.xml" /> + <!--Call one of package-* targets unless you understand what you are doing. --> <target name="package-all" depends="clean-all, init, build, javadoc, internal-package-war, internal-package-liferay, differences" description="Build public packages."> </target> @@ -17,33 +22,15 @@ <target name="package-liferay-zip" depends="clean-result, init, build, internal-package-liferay"> </target> - - <!-- Locations of Ant task JARs - build properties not yet read at this point --> - <property name="ant.task.jar.antcontrib" value="build/lib/ant-contrib-1.0b3.jar" /> - <property name="ant.task.jar.maven" value="build/lib/maven-ant-tasks-2.0.10.jar" /> - <path id="emma.lib" > - <pathelement location="build/lib/emma_ant.jar" /> - <pathelement location="build/lib/emma-2.0.5312-patched.jar" /> - </path> - - <taskdef resource="emma_ant.properties" classpathref="emma.lib" /> - - <!-- ant contrib required for flow control (for loop, if, property override) --> - <!-- Note that we have to use a namespace to avoid clash when running sub-ant. --> - <taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml"> - <classpath> - <pathelement location="${ant.task.jar.antcontrib}" /> - </classpath> - </taskdef> - - <!-- ant contrib for Maven integration --> - <path id="maven-ant-tasks.classpath" path="${ant.task.jar.maven}" /> - <typedef resource="org/apache/maven/artifact/ant/antlib.xml" - uri="antlib:org.apache.maven.artifact.ant" - classpathref="maven-ant-tasks.classpath" /> + <target name="init-deps" depends="common.init-deps" > + <property name="ivy.resolved" value="1" /> + <ivy:resolve file="build/ivy/ivy.xml" resolveid="common" conf="ss.compile, cs.compile, ss.test.compile"/> + <ivy:cachepath pathid="compile.classpath.server-side" conf="ss.compile"/> + <ivy:cachepath pathid="compile.classpath.client-side" conf="cs.compile"/> + <ivy:cachepath pathid="compile.classpath.server-side-tests" conf="ss.test.compile"/> + </target> - <!-- Clean results - - - - - - - - - - - - - - - - - - - - - - - - - --> <target name="clean-result" depends="build.properties"> @@ -88,23 +75,11 @@ <echo>Java version is ${ant.java.version} as required.</echo> </target> - <!-- Check Servlet API version. --> - <!-- We must use Servlet API 2.3 to catch incompatibilities.. --> - <target name="check-servlet-version"> - <available classpathref="compile.classpath" classname="javax.servlet.Servlet" property="servlet.available"/> - <fail unless="servlet.available" message="Java Servlet API library is not available."/> - <echo>Java Servlet API is available.</echo> - - <available classpathref="compile.classpath" classname="javax.servlet.ServletRequestListener" property="servlet.version.is-2.4"/> - <fail if="servlet.version.is-2.4" message="Java Servlet API 2.4 or later detected. Vaadin must be compiled exactly with Servlet API 2.3."/> - <echo>Java Servlet API specification 2.3 used.</echo> - </target> - <!-- ================================================================== --> <!-- Initialization - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- ================================================================== --> - <target name="init" depends="check-java-version, build.properties"> + <target name="init" depends="init-deps, build.properties"> <!-- Current timestamp in different formats. --> <tstamp> <format property="build.date" pattern="yyyy-MM-dd"/> @@ -157,6 +132,9 @@ <!-- init-nonpackage target before calling this main init target. --> <property name="widgetsets-output-dir" value="${output-dir}/WebContent/VAADIN/widgetsets" /> + <!-- Build helpers --> + <property name="buildhelpers-src" value="build/buildhelpers" /> + <property name="buildhelpers-classes" value="${result-path}/buildhelpers/classes" /> <!-- Create Output Directory Hierarchy --> <mkdir dir="${output-dir}/WebContent" /> @@ -167,31 +145,6 @@ <mkdir dir="${output-dir}/WebContent/WEB-INF" /> <mkdir dir="${output-dir}/WebContent/WEB-INF/lib" /> <mkdir dir="${output-dir}/WebContent/WEB-INF/classes" /> - - <!-- Construct classpath used by java and javadoc compilation --> - <path id="compile.classpath"> - <pathelement path="build/lib/servlet.jar" /> - <fileset dir="lib/core"> - <include name="**/*.jar"/> - - <!-- Exclude these as they contain Servlet API 2.4. --> - <!-- The gwt-*-noservlet.jar are then used instead. --> - <exclude name="**/servlet-api*.jar"/> - <exclude name="**/gwt-dev.jar"/> - <exclude name="**/gwt-user.jar"/> - </fileset> - <fileset dir="lib/tests"> - <include name="**/*.jar"/> - </fileset> - </path> - <path id="compile.classpath.server-side"> - <path refid="compile.classpath"/> - </path> - <path id="compile.classpath.client-side"> - <path refid="compile.classpath"/> - <pathelement path="${lib-gwt-user}" /> - <pathelement path="${lib-gwt-dev}" /> - </path> </target> <target name="internal-package-war"> @@ -204,8 +157,7 @@ <include name="${vaadin-package}/launcher/**" /> </fileset> <fileset dir="${result-classes-junit}"> - <!-- VaadinClasses is used by both JUnit and TestBench tests --> - <include name="**/VaadinClasses*.class" /> + <!-- VaadinClasses and data classes are used by TestBench tests also --> </fileset> <!-- test resources --> <fileset dir="tests/testbench"> @@ -226,6 +178,7 @@ <war warfile="${result-path}/${test-war-filename}"> <fileset dir="${output-dir}/WebContent"> + <exclude name="VAADIN/gwt-unitCache" /> <!-- Already in JAR --> <!-- Not excluded because used from WAR by portal integration tests <exclude name="VAADIN/themes/base/**/*" /> @@ -264,7 +217,11 @@ <include name="reindeer/**/*" /> </patternset> </zipfileset> - + <zipfileset prefix="VAADIN" dir="${output-dir}/WebContent/VAADIN"> + <patternset> + <include name="vaadinBootstrap.js" /> + </patternset> + </zipfileset> </zip> <echo>##teamcity[publishArtifacts '${result-path}/${base-name}-liferay.zip']</echo> @@ -395,28 +352,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <target name="webcontent" depends="preprocess-src,defaulttheme"> - <!-- copy 3rd part libraries used by tests --> - <copy todir="${output-dir}/WebContent/tests/lib"> - <fileset dir="lib/core"> - <include name="jetty/**/*" /> - </fileset> - <fileset dir="build/lib"> - <include name="emma-2.0.5312-patched.jar" /> - </fileset> - </copy> - <!-- Add WebContent --> <echo>Adding VAADIN/themes and META-INF</echo> <copy todir="${output-dir}/WebContent"> <fileset dir="WebContent"> <exclude name="**/.svn" /> - <!-- TODO check what is necessary --> <include name="WEB-INF/lib/hsqldb.jar" /> <include name="VAADIN/themes/**/*" /> + <include name="VAADIN/vaadinBootstrap.js" /> <include name="META-INF/**/*" /> </fileset> </copy> + <!-- Add test files to be included in test war --> + <copy todir="${output-dir}/WebContent"> + <fileset dir="WebContent"> + <include name="statictestfiles/**" /> + </fileset> + </copy> + <!-- Add servlet and portlet configuration files from WebContent --> <copy todir="${output-dir}/WebContent/WEB-INF"> <fileset dir="WebContent/WEB-INF"> @@ -466,7 +420,7 @@ <echo>Compiling src (Server and client side JUnit tests)</echo> <!-- Compile server and client side JUnit tests --> <mkdir dir="${result-classes-junit}" /> - <javac source="1.5" target="1.5" classpathref="compile.classpath.server-side" destdir="${result-classes-junit}" debug="true" encoding="UTF-8" includeantruntime="false"> + <javac source="1.5" target="1.5" classpathref="compile.classpath.server-side-tests" destdir="${result-classes-junit}" debug="true" encoding="UTF-8" includeantruntime="false"> <classpath path="${result-classes-core}"></classpath> <src path="${result-src-junit}"/> </javac> @@ -483,19 +437,20 @@ </target> <target name="compile-helpers" depends="init"> - <javac source="1.5" target="1.5" srcdir="build/buildhelpers" classpath="build/smartsprites/lib/smartsprites-0.2.3-itmill.jar" includeantruntime="false"/> + <mkdir dir="${buildhelpers-classes}" /> + <ivy:cachepath pathid="buildhelpers.dependencies" resolveId="buildhelpers" conf="compile" file="build/ivy/buildhelpers-ivy.xml"/> + <javac source="1.5" target="1.5" includeantruntime="false" srcdir="${buildhelpers-src}" + classpathref="buildhelpers.dependencies" destdir="${buildhelpers-classes}" debug="true" encoding="UTF-8" /> </target> - <target name="defaulttheme" depends="init, compile-helpers"> + <target name="defaulttheme" depends="init, compile-helpers" description="Compile all included themes"> <echo>Combining default themes css files</echo> <java classname="com.vaadin.buildhelpers.CompileDefaultTheme" failonerror="yes" fork="yes"> <arg value="-version" /> <arg value="${version.full}"/> <classpath> - <pathelement location="build/buildhelpers" /> - <fileset dir="build/smartsprites/lib"> - <include name="*.jar"/> - </fileset> + <path location="${buildhelpers-classes}" /> + <path refid="buildhelpers.dependencies" /> </classpath> <jvmarg value="-Djava.awt.headless=true"/> </java> @@ -529,29 +484,25 @@ <!-- The widgetset generator is currently compiled along with rest of server-side Java. --> <target name="compile-widgetset-generator" depends="compile-core"/> - - <path id="widgetset-compile-classpath"> - <pathelement location="${lib-gwt-user}" /> - <pathelement location="${lib-gwt-dev}" /> - <pathelement location="${lib-gwt-validation}" /> - <pathelement location="${lib-gwt-validation-src}" /> - <pathelement location="${result-classes-core}" /> - <pathelement location="${result-src-core}" /> - </path> - - <target name="compile-widgetset" description="Compiles the widgetset given as the first parameter"> + <!-- Compiles the widgetset given as the first parameter --> + <target name="compile-widgetset" depends="init-deps"> <fail unless="widgetset" message="No widgetset parameter set"/> <property name="widgetset-style" value="OBF" /> <property name="widgetset-localWorkers" value="4" /> <property name="widgetset-extraParams" value="" /> <echo>Compiling widgetset ${widgetset}. Output directory: ${widgetsets-output-dir}</echo> + <mkdir dir="${widgetsets-output-dir}"/> <java classname="com.google.gwt.dev.Compiler" failonerror="yes" fork="yes" maxmemory="512m"> - <classpath refid="widgetset-compile-classpath"/> - + <classpath> + <path refid="compile.classpath.client-side" /> + <pathelement location="${result-classes-core}" /> + <pathelement location="${result-src-core}" /> + </classpath> <arg value="-war" /> <arg value="${widgetsets-output-dir}" /> <arg value="-style" /> <arg value="${widgetset-style}" /> + <arg value="-strict" /> <arg value="-localWorkers" /> <arg value="${widgetset-localWorkers}" /> <arg line="${widgetset-extraParams}" /> @@ -568,12 +519,14 @@ <target name="compile-widgetset-default"> <antcall target="compile-widgetset"> + <reference refid="compile.classpath.client-side" /> <param name="widgetset" value="com.vaadin.terminal.gwt.DefaultWidgetSet"/> </antcall> </target> <target name="compile-widgetset-portal-default" unless="compile.only.default-widgetset"> <antcall target="compile-widgetset"> + <reference refid="compile.classpath.client-side" /> <param name="widgetset" value="com.vaadin.portal.gwt.PortalDefaultWidgetSet"/> </antcall> </target> @@ -584,8 +537,8 @@ <target name="compile-client-side" depends="compile-server-side"> <echo>Compiling widget sets in parallel.</echo> <parallel threadsperprocessor="1"> - <antcall target="compile-widgetset-default"/> - <antcall target="compile-widgetset-portal-default"/> + <antcall inheritrefs="true" target="compile-widgetset-default"/> + <antcall inheritrefs="true" target="compile-widgetset-portal-default"/> </parallel> </target> @@ -602,7 +555,7 @@ <target name="widgetsets" depends="init-nonpackage, init, compile-widgetset-generator, compile-client-side"/> <!-- Build each widgetset locally, i.e., not for an installation package. --> - <target name="widgetset-default" depends="init-nonpackage, init, compile-widgetset-generator, compile-widgetset-default"/> + <target name="widgetset-default" depends="init-nonpackage, init, compile-widgetset-generator, compile-widgetset-default" description="Compile the DefaultWidgetSet"/> <target name="widgetset-portal-default" depends="init-nonpackage, init, compile-widgetset-generator, compile-widgetset-portal-default"/> <!-- ================================================================== --> @@ -659,6 +612,7 @@ <include name="VAADIN/themes/liferay/**/*" /> <include name="VAADIN/themes/runo/**/*" /> <include name="VAADIN/themes/reindeer/**/*" /> + <include name="VAADIN/vaadinBootstrap.js" /> <include name="release-notes.html" /> <include name="license.html" /> @@ -672,7 +626,7 @@ <java classname="com.vaadin.buildhelpers.GeneratePackageExports" failonerror="true" fork="yes"> <arg value="${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name}"/> <classpath> - <pathelement location="build/buildhelpers" /> + <pathelement location="${buildhelpers-classes}" /> </classpath> </java> @@ -817,7 +771,7 @@ <tstamp> <format property="nightly.date" pattern="yyyyMMdd"/> </tstamp> - <property name="version.full" value="${version}.${build.tag}-${nightly.date}-c${build.number}"/> + <property name="version.full" value="${version}.${build.tag}-${nightly.date}-${build.number}"/> <echo>Version will be: ${version.full}</echo> @@ -837,14 +791,10 @@ <echo>Installing ${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name} to ${nightly.publish}</echo> <echo>Hopefully you have permissions for the copy operation with SSH.</echo> - <!-- FIXME tries to publish a ZIP; how does the download site handle these? --> - <property name="package.filename" value="${result-path}/${base-name}.zip"/> - <!-- Copy the linux installation package and the JAR. --> <exec executable="scp" searchpath="true" resultproperty="nightly.install.scp.result"> <arg value="-B"/> <arg value="${output-dir}/WebContent/WEB-INF/lib/${lib-jar-name}"/> - <arg value="${package.filename}"/> <arg value="${nightly.publish}"/> </exec> @@ -986,13 +936,12 @@ <pathelement path="${result-classes-core-for-emma-junit}" /> <pathelement path="${result-classes-core}" /> <pathelement path="${result-classes-junit}" /> - <path refid="emma.lib" /> - <path refid="compile.classpath"/> + <path refid="compile.classpath.server-side-tests"></path> </classpath> <jvmarg value="-Demma.coverage.out.file=../${result-path}/unittests.ec" /> <batchtest fork="yes"> - <fileset dir="tests/server-side" includes="**/*.java" excludes="**/Abstract*.java,**/VaadinClasses.java" /> + <fileset dir="tests/server-side" includes="**/*.java" excludes="**/Abstract*.java,com/vaadin/tests/data/bean/*.java,com/vaadin/tests/util/*.java,**/VaadinClasses.java" /> <fileset dir="tests/client-side" includes="**/*.java" excludes="**/Abstract*.java" /> </batchtest> </junit> @@ -1036,8 +985,8 @@ <!-- Convert tests to run multiple times if failed. --> <property name="retries" value="2"/> - - <property name="package.filename" value="${package.filename}"/> + + <property name="package.filename" value="${basedir}/${package.filename}"/> <property name="testing.testarea" value="/tmp/testarea"/> <property name="package.name" value="${package.name}"/> <property name="test-output-dir" value="../build/test-output" /> @@ -1046,6 +995,9 @@ <property name="com.vaadin.testbench.lib.dir" value="${com.vaadin.testbench.lib.dir}"/> <property name="com.vaadin.testbench.debug" value="${com.vaadin.testbench.debug}"/> <property name="com.vaadin.testbench.screenshot.block.error" value="${com.vaadin.testbench.screenshot.block.error}"/> + + <property name="deps.initialized" value="${deps.initialized}"/> + </ant> <emma enabled="${emma.enabled}" > @@ -1062,7 +1014,7 @@ </target> <!-- Assumes java classes have been compiled but depends does not work out well as this is run from a <parallel> task--> - <target name="integration-tests" unless="tests.integration.skip"> + <target name="integration-tests" depends="init-deps" unless="tests.integration.skip"> <!-- Parameters for the test.xml script. --> <fail unless="com.vaadin.testbench.tester.host" message="The 'com.vaadin.testbench.tester.host' property must be defined."/> <fail unless="com.vaadin.testbench.lib.dir" message="The 'com.vaadin.testbench.lib.dir' property must be defined."/> @@ -1083,6 +1035,8 @@ <property name="sshkey.file" value="${sshkey.file}" /> <property name="passphrase" value="${passphrase}" /> <property name="demo.war" value="${tests.war}"/> + + <property name="deps.initialized" value="${deps.initialized}"/> </ant> </target> </project> diff --git a/build/buildhelpers/com/vaadin/buildhelpers/CompileDefaultTheme.java b/build/buildhelpers/com/vaadin/buildhelpers/CompileDefaultTheme.java index 15d2acf6e9..0f7ec4a14b 100644 --- a/build/buildhelpers/com/vaadin/buildhelpers/CompileDefaultTheme.java +++ b/build/buildhelpers/com/vaadin/buildhelpers/CompileDefaultTheme.java @@ -224,9 +224,8 @@ public class CompileDefaultTheme { private static void createSprites(String themeName) throws FileNotFoundException, IOException { String[] parameters = new String[] { "--sprite-png-depth", "AUTO", - "--sprite-png-ie6", "--css-file-suffix", "-sprite", - "--css-file-encoding", "UTF-8", "--root-dir-path", - THEME_DIR + themeName, "--log-level", "WARN" }; + "--css-file-suffix", "-sprite", "--css-file-encoding", "UTF-8", + "--root-dir-path", THEME_DIR + themeName, "--log-level", "WARN" }; org.carrot2.labs.smartsprites.SmartSprites.main(parameters); diff --git a/build/common.xml b/build/common.xml new file mode 100644 index 0000000000..2886a1698f --- /dev/null +++ b/build/common.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> + +<project xmlns:antcontrib="antlib:net.sf.antcontrib" + xmlns:artifact="antlib:org.apache.maven.artifact.ant" + xmlns:ivy="antlib:org.apache.ivy.ant" + name="common" + basedir="../" + default="init-deps" > + + <property name="ivy.install.version" value="2.2.0"/> + <property name="ivy.jar.name" value="ivy-${ivy.install.version}.jar"/> + <property name="ivy.jar.dir" value="${user.home}/.ant/lib" /> + <property name="ivy.jar.file" value="${ivy.jar.dir}/${ivy.jar.name}" /> + + <target name="init-deps" description="Configure Ivy dependency management and load common task definitions" + depends="init-taskdefs" unless="deps.initialized"> + <property name="deps.initialized" value="1" /> + </target> + + <target name="check-ivy-installed"> + <available property="ivy.installed" file="${ivy.jar.file}"/> + <available property="ivy.installed" classname="org.apache.ivy.ant.IvyConfigure" /> + <antcall target="common.ivy-download" /> + </target> + + <target name="ivy-download" unless="ivy.installed"> + <mkdir dir="${ivy.jar.dir}"/> + <get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar" dest="${ivy.jar.file}" usetimestamp="true"/> + </target> + + <target name="ivy-configure" depends="check-ivy-installed" unless="deps.initialized"> + <!-- Ivy task definitions --> + <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpath="${ivy.jar.file}" /> + <!-- Ivy settings --> + <property name="ivy.settings.file" value="${project.root}/build/ivy/ivysettings.xml" /> + <ivy:configure/> + </target> + + <target name="init-taskdefs" depends="ivy-configure" unless="deps.initialized"> + <echo>Loading Ant tasks</echo> + <ivy:resolve file="${project.root}/build/ivy/ivy.xml" conf="taskdefs" /> + <ivy:cachepath pathid="taskdefs.classpath" conf="taskdefs" /> + <taskdef resource="emma_ant.properties" classpathref="taskdefs.classpath" /> + + <!-- ant contrib required for flow control (for loop, if, property override) --> + <!-- Note that we have to use a namespace to avoid clash when running sub-ant. --> + <taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml" + classpathref="taskdefs.classpath" /> + + <!-- ant contrib for Maven integration --> + <taskdef resource="org/apache/maven/artifact/ant/antlib.xml" + uri="antlib:org.apache.maven.artifact.ant" classpathref="taskdefs.classpath" /> + </target> + +</project> diff --git a/build/ivy/buildhelpers-ivy.xml b/build/ivy/buildhelpers-ivy.xml new file mode 100644 index 0000000000..afccd85973 --- /dev/null +++ b/build/ivy/buildhelpers-ivy.xml @@ -0,0 +1,13 @@ +<ivy-module version="2.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation= "http://ant.apache.org/ivy/schemas/ivy.xsd"> + + <info organisation="com.vaadin" module="buildhelpers"/> + <configurations> + <conf name="compile" visibility="private"/> + </configurations> + <publications /> + <dependencies> + <dependency org="com.carrotsearch" name="smartsprites" rev="0.2.3-itmill" conf="compile->compile(*),master(*)"/> + </dependencies> +</ivy-module>
\ No newline at end of file diff --git a/build/ivy/ivy.xml b/build/ivy/ivy.xml new file mode 100644 index 0000000000..ffcf7b19c8 --- /dev/null +++ b/build/ivy/ivy.xml @@ -0,0 +1,46 @@ +<ivy-module version="2.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation= "http://ant.apache.org/ivy/schemas/ivy.xsd"> + + <info organisation="com.vaadin" module="vaadin"/> + <configurations > + <conf name="ss.compile" extends="cs.compile" description="Server side compilation dependencies" visibility="private"/> + <conf name="cs.compile" description="Client side compilation dependencies" visibility="private"/> + <conf name="ss.test.compile" extends="ss.compile" description="Test compilation dependencies" visibility="private"/> + <conf name="taskdefs" description="Ant task definitions" visibility="private" /> + </configurations> + <publications /> + <dependencies defaultconf="ss.compile" defaultconfmapping="ss.compile->master"> + + <!-- Liferay Portal Service --> + <dependency org="com.liferay.portal" name="portal-service" rev="6.0.2" /> + <!--Portlet API version 2.0 (JSR-286) --> + <dependency org="javax.portlet" name="portlet-api" rev="2.0" /> + <!-- Google App Engine --> + <dependency org="com.google.appengine" name="appengine-api-1.0-sdk" rev="1.2.1" /> + + <!-- GWT user with dependencies (validation-api) --> + <dependency org="com.google.gwt" name="gwt-user" rev="2.4.0" conf="cs.compile->master" /> + <dependency org="javax.validation" name="validation-api" rev="1.0.0.GA" conf="cs.compile->master,sources" /> + <!-- GWT dev (incl. servlet-api 2.4 classes) --> + <dependency org="com.google.gwt" name="gwt-dev" rev="2.4.0" conf="cs.compile->master" /> + + <!-- Test frameworks & related --> + <dependency org="junit" name="junit" rev="4.5" conf="ss.test.compile -> master"/> + <dependency org="org.easymock" name="easymock" rev="3.0" conf="ss.test.compile -> master, runtime(*)"/> + <dependency org="org.hsqldb" name="hsqldb" rev="2.2.6" conf="ss.test.compile -> master, runtime(*)"/> + + <!-- Ant tasks --> + <dependency org="ant-contrib" name="ant-contrib" rev="1.0b3" conf="taskdefs ->master"/> + <dependency org="org.apache.maven" name="maven-ant-tasks" rev="2.0.10" conf="taskdefs ->master"/> + + <!-- Emma --> + <dependency org="emma" name="emma_ant" rev="2.0.5312" conf="ss.test.compile,taskdefs ->master"/> + <dependency org="emma" name="emma" rev="2.0.5312-patched" conf="ss.test.compile,taskdefs ->*"/> + + <!-- Bean Validation implementation --> + <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.6.1" conf="ss.test.compile -> default"/> + <dependency org="org.hibernate" name="hibernate-validator" rev="4.2.0.Final" conf="ss.test.compile -> default"/> + </dependencies> + +</ivy-module>
\ No newline at end of file diff --git a/build/ivy/ivysettings.xml b/build/ivy/ivysettings.xml new file mode 100644 index 0000000000..613b8d9ffe --- /dev/null +++ b/build/ivy/ivysettings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ivysettings> + <settings defaultResolver="public" /> + <resolvers> + <ibiblio name="public" m2compatible="true"/> + <url name="gwt-redist"> + <artifact pattern="http://google-web-toolkit.googlecode.com/svn/tools/redist/[organisation]/[artifact](-[revision]).[ext]" /> + </url> + <dual name="custom-smartsprites"> + <filesystem name="smartsprites-ivy"> + <ivy pattern="${basedir}/build/ivy/module/[module]-ivy-[revision].xml" /> + </filesystem> + <url name="smartsprites-artifact"> + <artifact pattern="http://dev.vaadin.com/svn/versions/6.8/build/smartsprites/lib/[artifact](-[revision]).[ext]" /> + </url> + </dual> + </resolvers> + <modules> + <!-- GWT patched Emma --> + <module organisation="emma" name="emma" resolver="gwt-redist"/> + <!-- IT Mill patched SmartSprites --> + <module organisation="com.carrotsearch" name="smartsprites" revision="0.2.3-itmill" resolver="custom-smartsprites"/> + </modules> +</ivysettings>
\ No newline at end of file diff --git a/build/ivy/module/smartsprites-ivy-0.2.3-itmill.xml b/build/ivy/module/smartsprites-ivy-0.2.3-itmill.xml new file mode 100644 index 0000000000..495b6d00c9 --- /dev/null +++ b/build/ivy/module/smartsprites-ivy-0.2.3-itmill.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven"> + <info organisation="com.carrotsearch" + module="smartsprites" + revision="0.2.3-itmill" + status="release" + publication="20111130000000"> + <license name="BSD license" url="http://csssprites.org/smartsprites.LICENSE" /> + <description homepage="http://csssprites.org"> + CSS Sprites Generator Done Right. SmartSprites maintains CSS sprites in your designs, + fully automatically. No tedious copying and pasting to your CSS when adding or changing + sprited images. + </description> + </info> + <configurations> + <conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/> + <conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/> + <conf name="compile" visibility="public" description="this is the default scope, used if none is specified. Compile dependencies are available in all classpaths."/> + <conf name="provided" visibility="public" description="this is much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive."/> + <conf name="runtime" visibility="public" description="this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath." extends="compile"/> + <conf name="test" visibility="private" description="this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases." extends="runtime"/> + <conf name="system" visibility="public" description="this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository."/> + <conf name="sources" visibility="public" description="this configuration contains the source artifact of this module, if any."/> + <conf name="javadoc" visibility="public" description="this configuration contains the javadoc artifact of this module, if any."/> + <conf name="optional" visibility="public" description="contains all optional dependencies"/> + </configurations> + <publications> + <artifact name="smartsprites" type="jar" ext="jar" conf="master"/> + </publications> + <dependencies> + <dependency org="com.google.collections" name="google-collections" rev="0.9" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> + <dependency org="args4j" name="args4j" rev="2.0.9" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> + <dependency org="commons-math" name="commons-math" rev="1.1" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> + <dependency org="commons-io" name="commons-io" rev="1.4" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> + <dependency org="commons-lang" name="commons-lang" rev="2.3" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/> + <dependency org="junit" name="junit" rev="4.4" force="true" conf="test->runtime(*),master(*)"/> + </dependencies> +</ivy-module> diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java index 9fb4cfe7fa..4da1d52c00 100644 --- a/src/com/vaadin/Application.java +++ b/src/com/vaadin/Application.java @@ -4,35 +4,60 @@ package com.vaadin; +import java.io.IOException; import java.io.Serializable; +import java.lang.annotation.Annotation; import java.net.SocketException; import java.net.URL; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.EventListener; import java.util.EventObject; +import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedList; import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; - +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.vaadin.annotations.EagerInit; +import com.vaadin.annotations.Theme; +import com.vaadin.annotations.Widgetset; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ConverterFactory; +import com.vaadin.data.util.converter.DefaultConverterFactory; import com.vaadin.service.ApplicationContext; +import com.vaadin.terminal.AbstractErrorMessage; import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.ParameterHandler; -import com.vaadin.terminal.SystemError; +import com.vaadin.terminal.CombinedRequest; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.RequestHandler; import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.URIHandler; import com.vaadin.terminal.VariableOwner; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedRequest.BrowserDetails; +import com.vaadin.terminal.WrappedResponse; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; import com.vaadin.terminal.gwt.server.ChangeVariablesErrorEvent; -import com.vaadin.terminal.gwt.server.PortletApplicationContext; +import com.vaadin.terminal.gwt.server.ClientConnector; import com.vaadin.terminal.gwt.server.WebApplicationContext; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.AbstractField; +import com.vaadin.ui.Component; +import com.vaadin.ui.Root; +import com.vaadin.ui.Table; import com.vaadin.ui.Window; /** @@ -89,37 +114,317 @@ import com.vaadin.ui.Window; * @since 3.0 */ @SuppressWarnings("serial") -public abstract class Application implements URIHandler, - Terminal.ErrorListener, Serializable { - - private final static Logger logger = Logger.getLogger(Application.class - .getName()); +public class Application implements Terminal.ErrorListener, Serializable { /** - * Id use for the next window that is opened. Access to this must be - * synchronized. + * The name of the parameter that is by default used in e.g. web.xml to + * define the name of the default {@link Root} class. */ - private int nextWindowId = 1; + public static final String ROOT_PARAMETER = "root"; /** - * Application context the application is running in. + * A special application designed to help migrating applications from Vaadin + * 6 to Vaadin 7. The legacy application supports setting a main window, + * adding additional browser level windows and defining the theme for the + * entire application. + * + * @deprecated This class is only intended to ease migration and should not + * be used for new projects. + * + * @since 7.0 */ - private ApplicationContext context; + @Deprecated + public static class LegacyApplication extends Application { + /** + * Ignore initial / and then get everything up to the next / + */ + private static final Pattern WINDOW_NAME_PATTERN = Pattern + .compile("^/?([^/]+).*"); + + private Root.LegacyWindow mainWindow; + private String theme; + + private Map<String, Root.LegacyWindow> legacyRootNames = new HashMap<String, Root.LegacyWindow>(); + + /** + * Sets the main window of this application. Setting window as a main + * window of this application also adds the window to this application. + * + * @param mainWindow + * the root to set as the default window + */ + public void setMainWindow(Root.LegacyWindow mainWindow) { + if (this.mainWindow != null) { + throw new IllegalStateException( + "mainWindow has already been set"); + } + if (mainWindow.getApplication() == null) { + mainWindow.setApplication(this); + } else if (mainWindow.getApplication() != this) { + throw new IllegalStateException( + "mainWindow is attached to another application"); + } + this.mainWindow = mainWindow; + } + + /** + * Gets the mainWindow of the application. + * + * <p> + * The main window is the window attached to the application URL ( + * {@link #getURL()}) and thus which is show by default to the user. + * </p> + * <p> + * Note that each application must have at least one main window. + * </p> + * + * @return the root used as the default window + */ + public Root.LegacyWindow getMainWindow() { + return mainWindow; + } + + /** + * This implementation simulates the way of finding a window for a + * request by extracting a window name from the requested path and + * passes that name to {@link #getWindow(String)}. + * + * {@inheritDoc} + * + * @see #getWindow(String) + * @see Application#getRoot(WrappedRequest) + */ + @Override + public Root.LegacyWindow getRoot(WrappedRequest request) { + String pathInfo = request.getRequestPathInfo(); + String name = null; + if (pathInfo != null && pathInfo.length() > 0) { + Matcher matcher = WINDOW_NAME_PATTERN.matcher(pathInfo); + if (matcher.matches()) { + // Skip the initial slash + name = matcher.group(1); + } + } + Root.LegacyWindow window = getWindow(name); + if (window != null) { + return window; + } + return mainWindow; + } + + /** + * Sets the application's theme. + * <p> + * Note that this theme can be overridden for a specific root with + * {@link Application#getThemeForRoot(Root)}. Setting theme to be + * <code>null</code> selects the default theme. For the available theme + * names, see the contents of the VAADIN/themes directory. + * </p> + * + * @param theme + * the new theme for this application. + */ + public void setTheme(String theme) { + this.theme = theme; + } + + /** + * Gets the application's theme. The application's theme is the default + * theme used by all the roots for which a theme is not explicitly + * defined. If the application theme is not explicitly set, + * <code>null</code> is returned. + * + * @return the name of the application's theme. + */ + public String getTheme() { + return theme; + } + + /** + * This implementation returns the theme that has been set using + * {@link #setTheme(String)} + * <p> + * {@inheritDoc} + */ + @Override + public String getThemeForRoot(Root root) { + return theme; + } + + /** + * <p> + * Gets a root by name. Returns <code>null</code> if the application is + * not running or it does not contain a window corresponding to the + * name. + * </p> + * + * @param name + * the name of the requested window + * @return a root corresponding to the name, or <code>null</code> to use + * the default window + */ + public Root.LegacyWindow getWindow(String name) { + return legacyRootNames.get(name); + } + + /** + * Counter to get unique names for windows with no explicit name + */ + private int namelessRootIndex = 0; + + /** + * Adds a new browser level window to this application. Please note that + * Root doesn't have a name that is used in the URL - to add a named + * window you should instead use {@link #addWindow(Root, String)} + * + * @param root + * the root window to add to the application + * @return returns the name that has been assigned to the window + * + * @see #addWindow(Root, String) + */ + public void addWindow(Root.LegacyWindow root) { + if (root.getName() == null) { + String name = Integer.toString(namelessRootIndex++); + root.setName(name); + } + + legacyRootNames.put(root.getName(), root); + root.setApplication(this); + } + + /** + * Removes the specified window from the application. This also removes + * all name mappings for the window (see + * {@link #addWindow(Root, String) and #getWindowName(Root)}. + * + * <p> + * Note that removing window from the application does not close the + * browser window - the window is only removed from the server-side. + * </p> + * + * @param root + * the root to remove + */ + public void removeWindow(Root.LegacyWindow root) { + for (Entry<String, Root.LegacyWindow> entry : legacyRootNames + .entrySet()) { + if (entry.getValue() == root) { + legacyRootNames.remove(entry.getKey()); + } + } + } + + /** + * Gets the set of windows contained by the application. + * + * <p> + * Note that the returned set of windows can not be modified. + * </p> + * + * @return the unmodifiable collection of windows. + */ + public Collection<Root.LegacyWindow> getWindows() { + return Collections.unmodifiableCollection(legacyRootNames.values()); + } + } /** - * The current user or <code>null</code> if no user has logged in. + * An event sent to {@link #start(ApplicationStartEvent)} when a new + * Application is being started. + * + * @since 7.0 */ - private Object user; + public static class ApplicationStartEvent implements Serializable { + private final URL applicationUrl; + + private final Properties applicationProperties; + + private final ApplicationContext context; + + private final boolean productionMode; + + /** + * @param applicationUrl + * the URL the application should respond to. + * @param applicationProperties + * the Application properties as specified by the deployment + * configuration. + * @param context + * the context application will be running in. + * @param productionMode + * flag indicating whether the application is running in + * production mode. + */ + public ApplicationStartEvent(URL applicationUrl, + Properties applicationProperties, ApplicationContext context, + boolean productionMode) { + this.applicationUrl = applicationUrl; + this.applicationProperties = applicationProperties; + this.context = context; + this.productionMode = productionMode; + } + + /** + * Gets the URL the application should respond to. + * + * @return the URL the application should respond to or + * <code>null</code> if the URL is not defined. + * + * @see Application#getURL() + */ + public URL getApplicationUrl() { + return applicationUrl; + } + + /** + * Gets the Application properties as specified by the deployment + * configuration. + * + * @return the properties configured for the applciation. + * + * @see Application#getProperty(String) + */ + public Properties getApplicationProperties() { + return applicationProperties; + } + + /** + * Gets the context application will be running in. + * + * @return the context application will be running in. + * + * @see Application#getContext() + */ + public ApplicationContext getContext() { + return context; + } + + /** + * Checks whether the application is running in production mode. + * + * @return <code>true</code> if in production mode, else + * <code>false</code> + * + * @see Application#isProductionMode() + */ + public boolean isProductionMode() { + return productionMode; + } + } + + private final static Logger logger = Logger.getLogger(Application.class + .getName()); /** - * Mapping from window name to window instance. + * Application context the application is running in. */ - private final Hashtable<String, Window> windows = new Hashtable<String, Window>(); + private ApplicationContext context; /** - * Main window of the application. + * The current user or <code>null</code> if no user has logged in. */ - private Window mainWindow = null; + private Object user; /** * The application's URL. @@ -127,11 +432,6 @@ public abstract class Application implements URIHandler, private URL applicationUrl; /** - * Name of the theme currently used by the application. - */ - private String theme = null; - - /** * Application status. */ private volatile boolean applicationIsRunning = false; @@ -152,16 +452,6 @@ public abstract class Application implements URIHandler, private LinkedList<UserChangeListener> userChangeListeners = null; /** - * Window attach listeners. - */ - private LinkedList<WindowAttachListener> windowAttachListeners = null; - - /** - * Window detach listeners. - */ - private LinkedList<WindowDetachListener> windowDetachListeners = null; - - /** * Application resource mapping: key <-> resource. */ private final Hashtable<ApplicationResource, String> resourceKeyMap = new Hashtable<ApplicationResource, String>(); @@ -189,237 +479,28 @@ public abstract class Application implements URIHandler, private Terminal.ErrorListener errorHandler = this; /** - * <p> - * Gets a window by name. Returns <code>null</code> if the application is - * not running or it does not contain a window corresponding to the name. - * </p> - * - * <p> - * All windows can be referenced by their names in url - * <code>http://host:port/foo/bar/</code> where - * <code>http://host:port/foo/</code> is the application url as returned by - * getURL() and <code>bar</code> is the name of the window. - * </p> - * - * <p> - * One should note that this method can, as a side effect create new windows - * if needed by the application. This can be achieved by overriding the - * default implementation. - * </p> - * - * <p> - * If for some reason user opens another window with same url that is - * already open, the name is modified by adding a "_N" postfix to the name, - * where N is a running number starting from 1. One can decide to create - * another window-object for those windows (recommended) or to discard the - * postfix. If the user has two browser windows pointing to the same - * window-object on server, synchronization errors are likely to occur. - * </p> - * - * <p> - * If no browser-level windowing is used, all defaults are fine and this - * method can be left as is. In case browser-level windows are needed, it is - * recommended to create new window-objects on this method from their names - * if the super.getWindow() does not find existing windows. See below for - * implementation example: <code><pre> - // If we already have the requested window, use it - Window w = super.getWindow(name); - if (w == null) { - // If no window found, create it - w = new Window(name); - // set windows name to the one requested - w.setName(name); - // add it to this application - addWindow(w); - // ensure use of window specific url - w.open(new ExternalResource(w.getURL().toString())); - // add some content - w.addComponent(new Label("Test window")); - } - return w;</pre></code> - * </p> - * - * <p> - * <strong>Note</strong> that all returned Window objects must be added to - * this application instance. - * - * <p> - * The method should return null if the window does not exists (and is not - * created as a side-effect) or if the application is not running anymore. - * </p> - * - * @param name - * the name of the window. - * @return the window associated with the given URI or <code>null</code> + * The converter factory that is used to provide default converters for the + * application. */ - public Window getWindow(String name) { - - // For closed app, do not give any windows - if (!isRunning()) { - return null; - } - - // Gets the window by name - final Window window = windows.get(name); - - return window; - } - - /** - * Adds a new window to the application. - * - * <p> - * This implicitly invokes the - * {@link com.vaadin.ui.Window#setApplication(Application)} method. - * </p> - * - * <p> - * Note that all application-level windows can be accessed by their names in - * url <code>http://host:port/foo/bar/</code> where - * <code>http://host:port/foo/</code> is the application url as returned by - * getURL() and <code>bar</code> is the name of the window. Also note that - * not all windows should be added to application - one can also add windows - * inside other windows - these windows show as smaller windows inside those - * windows. - * </p> - * - * @param window - * the new <code>Window</code> to add. If the name of the window - * is <code>null</code>, an unique name is automatically given - * for the window. - * @throws IllegalArgumentException - * if a window with the same name as the new window already - * exists in the application. - * @throws NullPointerException - * if the given <code>Window</code> is <code>null</code>. - */ - public void addWindow(Window window) throws IllegalArgumentException, - NullPointerException { - - // Nulls can not be added to application - if (window == null) { - return; - } - - // Check that one is not adding a sub-window to application - if (window.getParent() != null) { - throw new IllegalArgumentException( - "Window was already added inside another window" - + " - it can not be added to application also."); - } - - // Gets the naming proposal from window - String name = window.getName(); - - // Checks that the application does not already contain - // window having the same name - if (name != null && windows.containsKey(name)) { - - // If the window is already added - if (window == windows.get(name)) { - return; - } - - // Otherwise complain - throw new IllegalArgumentException("Window with name '" - + window.getName() - + "' is already present in the application"); - } + private ConverterFactory converterFactory = new DefaultConverterFactory(); - // If the name of the window is null, the window is automatically named - if (name == null) { - boolean accepted = false; - while (!accepted) { + private LinkedList<RequestHandler> requestHandlers = new LinkedList<RequestHandler>(); - // Try another name - synchronized (this) { - name = String.valueOf(nextWindowId); - nextWindowId++; - } - - if (!windows.containsKey(name)) { - accepted = true; - } - } - window.setName(name); - } - - // Adds the window to application - windows.put(name, window); - window.setApplication(this); + private int nextRootId = 0; + private Map<Integer, Root> roots = new HashMap<Integer, Root>(); - fireWindowAttachEvent(window); - - // If no main window is set, declare the window to be main window - if (getMainWindow() == null) { - mainWindow = window; - } - } + private boolean productionMode = true; - /** - * Send information to all listeners about new Windows associated with this - * application. - * - * @param window - */ - private void fireWindowAttachEvent(Window window) { - // Fires the window attach event - if (windowAttachListeners != null) { - final Object[] listeners = windowAttachListeners.toArray(); - final WindowAttachEvent event = new WindowAttachEvent(window); - for (int i = 0; i < listeners.length; i++) { - ((WindowAttachListener) listeners[i]).windowAttached(event); - } - } - } + private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>(); /** - * Removes the specified window from the application. - * - * <p> - * Removing the main window of the Application also sets the main window to - * null. One must another window to be the main window after this with - * {@link #setMainWindow(Window)}. - * </p> - * + * Keeps track of which roots have been inited. * <p> - * Note that removing window from the application does not close the browser - * window - the window is only removed from the server-side. + * TODO Investigate whether this might be derived from the different states + * in getRootForRrequest. * </p> - * - * @param window - * the window to be removed. */ - public void removeWindow(Window window) { - if (window != null && windows.contains(window)) { - - // Removes the window from application - windows.remove(window.getName()); - - // If the window was main window, clear it - if (getMainWindow() == window) { - setMainWindow(null); - } - - // Removes the application from window - if (window.getApplication() == this) { - window.setApplication(null); - } - - fireWindowDetachEvent(window); - } - } - - private void fireWindowDetachEvent(Window window) { - // Fires the window detach event - if (windowDetachListeners != null) { - final Object[] listeners = windowDetachListeners.toArray(); - final WindowDetachEvent event = new WindowDetachEvent(window); - for (int i = 0; i < listeners.length; i++) { - ((WindowDetachListener) listeners[i]).windowDetached(event); - } - } - } + private Set<Integer> initedRoots = new HashSet<Integer>(); /** * Gets the user of the application. @@ -525,20 +606,16 @@ public abstract class Application implements URIHandler, * {@link javax.servlet.ServletContext}. * </p> * - * @param applicationUrl - * the URL the application should respond to. - * @param applicationProperties - * the Application properties as specified by the servlet - * configuration. - * @param context - * the context application will be running in. + * @param event + * the application start event containing details required for + * starting the application. * */ - public void start(URL applicationUrl, Properties applicationProperties, - ApplicationContext context) { - this.applicationUrl = applicationUrl; - properties = applicationProperties; - this.context = context; + public void start(ApplicationStartEvent event) { + applicationUrl = event.getApplicationUrl(); + productionMode = event.isProductionMode(); + properties = event.getApplicationProperties(); + context = event.getContext(); init(); applicationIsRunning = true; } @@ -560,106 +637,14 @@ public abstract class Application implements URIHandler, } /** - * Gets the set of windows contained by the application. - * - * <p> - * Note that the returned set of windows can not be modified. - * </p> - * - * @return the Unmodifiable collection of windows. - */ - public Collection<Window> getWindows() { - return Collections.unmodifiableCollection(windows.values()); - } - - /** * <p> * Main initializer of the application. The <code>init</code> method is * called by the framework when the application is started, and it should - * perform whatever initialization operations the application needs, such as - * creating windows and adding components to them. - * </p> - */ - public abstract void init(); - - /** - * Gets the application's theme. The application's theme is the default - * theme used by all the windows in it that do not explicitly specify a - * theme. If the application theme is not explicitly set, the - * <code>null</code> is returned. - * - * @return the name of the application's theme. - */ - public String getTheme() { - return theme; - } - - /** - * Sets the application's theme. - * <p> - * Note that this theme can be overridden in the the application level - * windows with {@link com.vaadin.ui.Window#setTheme(String)}. Setting theme - * to be <code>null</code> selects the default theme. For the available - * theme names, see the contents of the VAADIN/themes directory. - * </p> - * - * @param theme - * the new theme for this application. - */ - public void setTheme(String theme) { - // Collect list of windows not having the current or future theme - final LinkedList<Window> toBeUpdated = new LinkedList<Window>(); - final String oldAppTheme = getTheme(); - for (final Iterator<Window> i = getWindows().iterator(); i.hasNext();) { - final Window w = i.next(); - final String windowTheme = w.getTheme(); - if ((windowTheme == null) - || (!windowTheme.equals(theme) && windowTheme - .equals(oldAppTheme))) { - toBeUpdated.add(w); - } - } - - // Updates the theme - this.theme = theme; - - // Ask windows to update themselves - for (final Iterator<Window> i = toBeUpdated.iterator(); i.hasNext();) { - i.next().requestRepaint(); - } - } - - /** - * Gets the mainWindow of the application. - * - * <p> - * The main window is the window attached to the application URL ( - * {@link #getURL()}) and thus which is show by default to the user. - * </p> - * <p> - * Note that each application must have at least one main window. - * </p> - * - * @return the main window. - */ - public Window getMainWindow() { - return mainWindow; - } - - /** - * <p> - * Sets the mainWindow. If the main window is not explicitly set, the main - * window defaults to first created window. Setting window as a main window - * of this application also adds the window to this application. + * perform whatever initialization operations the application needs. * </p> - * - * @param mainWindow - * the mainWindow to set. */ - public void setMainWindow(Window mainWindow) { - - addWindow(mainWindow); - this.mainWindow = mainWindow; + public void init() { + // Default implementation does nothing } /** @@ -759,50 +744,6 @@ public abstract class Application implements URIHandler, } /** - * Application URI handling hub. - * - * <p> - * This method gets called by terminal. It has lots of duties like to pass - * uri handler to proper uri handlers registered to windows etc. - * </p> - * - * <p> - * In most situations developers should NOT OVERRIDE this method. Instead - * developers should implement and register uri handlers to windows. - * </p> - * - * @deprecated this method is called be the terminal implementation only and - * might be removed or moved in the future. Instead of - * overriding this method, add your {@link URIHandler} to a top - * level {@link Window} (eg. - * getMainWindow().addUriHanler(handler) instead. - */ - @Deprecated - public DownloadStream handleURI(URL context, String relativeUri) { - - if (this.context.isApplicationResourceURL(context, relativeUri)) { - - // Handles the resource request - final String key = this.context.getURLKey(context, relativeUri); - final ApplicationResource resource = keyResourceMap.get(key); - if (resource != null) { - DownloadStream stream = resource.getStream(); - if (stream != null) { - stream.setCacheTime(resource.getCacheTime()); - return stream; - } else { - return null; - } - } else { - // Resource requests override uri handling - return null; - } - } else { - return null; - } - } - - /** * Gets the default locale for this application. * * By default this is the preferred locale of the user using the @@ -1061,68 +1002,6 @@ public abstract class Application implements URIHandler, } /** - * Adds the window attach listener. - * - * Use this to get notifications each time a window is attached to the - * application with {@link #addWindow(Window)}. - * - * @param listener - * the window attach listener to add. - */ - public void addListener(WindowAttachListener listener) { - if (windowAttachListeners == null) { - windowAttachListeners = new LinkedList<WindowAttachListener>(); - } - windowAttachListeners.add(listener); - } - - /** - * Adds the window detach listener. - * - * Use this to get notifications each time a window is remove from the - * application with {@link #removeWindow(Window)}. - * - * @param listener - * the window detach listener to add. - */ - public void addListener(WindowDetachListener listener) { - if (windowDetachListeners == null) { - windowDetachListeners = new LinkedList<WindowDetachListener>(); - } - windowDetachListeners.add(listener); - } - - /** - * Removes the window attach listener. - * - * @param listener - * the window attach listener to remove. - */ - public void removeListener(WindowAttachListener listener) { - if (windowAttachListeners != null) { - windowAttachListeners.remove(listener); - if (windowAttachListeners.isEmpty()) { - windowAttachListeners = null; - } - } - } - - /** - * Removes the window detach listener. - * - * @param listener - * the window detach listener to remove. - */ - public void removeListener(WindowDetachListener listener) { - if (windowDetachListeners != null) { - windowDetachListeners.remove(listener); - if (windowDetachListeners.isEmpty()) { - windowDetachListeners = null; - } - } - } - - /** * Returns the URL user is redirected to on application close. If the URL is * <code>null</code>, the application is closed normally as defined by the * application running environment. @@ -1200,22 +1079,14 @@ public abstract class Application implements URIHandler, Object owner = null; if (event instanceof VariableOwner.ErrorEvent) { owner = ((VariableOwner.ErrorEvent) event).getVariableOwner(); - } else if (event instanceof URIHandler.ErrorEvent) { - owner = ((URIHandler.ErrorEvent) event).getURIHandler(); - } else if (event instanceof ParameterHandler.ErrorEvent) { - owner = ((ParameterHandler.ErrorEvent) event).getParameterHandler(); } else if (event instanceof ChangeVariablesErrorEvent) { owner = ((ChangeVariablesErrorEvent) event).getComponent(); } // Shows the error in AbstractComponent if (owner instanceof AbstractComponent) { - if (t instanceof ErrorMessage) { - ((AbstractComponent) owner).setComponentError((ErrorMessage) t); - } else { - ((AbstractComponent) owner) - .setComponentError(new SystemError(t)); - } + ((AbstractComponent) owner).setComponentError(AbstractErrorMessage + .getErrorMessageForException(t)); } // also print the error on console @@ -1280,6 +1151,43 @@ public abstract class Application implements URIHandler, } /** + * Gets the {@link ConverterFactory} used to locate a suitable + * {@link Converter} for fields in the application. + * + * See {@link #setConverterFactory(ConverterFactory)} for more details + * + * @return The converter factory used in the application + */ + public ConverterFactory getConverterFactory() { + return converterFactory; + } + + /** + * Sets the {@link ConverterFactory} used to locate a suitable + * {@link Converter} for fields in the application. + * <p> + * The {@link ConverterFactory} is used to find a suitable converter when + * binding data to a UI component and the data type does not match the UI + * component type, e.g. binding a Double to a TextField (which is based on a + * String). + * </p> + * <p> + * The {@link Converter} for an individual field can be overridden using + * {@link AbstractField#setConverter(Converter)} and for individual property + * ids in a {@link Table} using + * {@link Table#setConverter(Object, Converter)}. + * </p> + * <p> + * The converter factory must never be set to null. + * + * @param converterFactory + * The converter factory used in the application + */ + public void setConverterFactory(ConverterFactory converterFactory) { + this.converterFactory = converterFactory; + } + + /** * Contains the system messages used to notify the user about various * critical situations that can occur. * <p> @@ -1906,4 +1814,606 @@ public abstract class Application implements URIHandler, } } -}
\ No newline at end of file + + /** + * Gets a root for a request for which no root is already known. This method + * is called when the framework processes a request that does not originate + * from an existing root instance. This typically happens when a host page + * is requested. + * + * <p> + * Subclasses of Application may override this method to provide custom + * logic for choosing how to create a suitable root or for picking an + * already created root. If an existing root is picked, care should be taken + * to avoid keeping the same root open in multiple browser windows, as that + * will cause the states to go out of sync. + * </p> + * + * <p> + * If {@link BrowserDetails} are required to create a Root, the + * implementation can throw a {@link RootRequiresMoreInformationException} + * exception. In this case, the framework will instruct the browser to send + * the additional details, whereupon this method is invoked again with the + * browser details present in the wrapped request. Throwing the exception if + * the browser details are already available is not supported. + * </p> + * + * <p> + * The default implementation in {@link Application} creates a new instance + * of the Root class returned by {@link #getRootClassName(WrappedRequest)}, + * which in turn uses the {@value #ROOT_PARAMETER} parameter from web.xml. + * If {@link DeploymentConfiguration#getClassLoader()} for the request + * returns a {@link ClassLoader}, it is used for loading the Root class. + * Otherwise the {@link ClassLoader} used to load this class is used. + * </p> + * + * @param request + * the wrapped request for which a root is needed + * @return a root instance to use for the request + * @throws RootRequiresMoreInformationException + * may be thrown by an implementation to indicate that + * {@link BrowserDetails} are required to create a root + * + * @see #getRootClassName(WrappedRequest) + * @see Root + * @see RootRequiresMoreInformationException + * @see WrappedRequest#getBrowserDetails() + * + * @since 7.0 + */ + protected Root getRoot(WrappedRequest request) + throws RootRequiresMoreInformationException { + String rootClassName = getRootClassName(request); + try { + ClassLoader classLoader = request.getDeploymentConfiguration() + .getClassLoader(); + if (classLoader == null) { + classLoader = getClass().getClassLoader(); + } + Class<? extends Root> rootClass = Class.forName(rootClassName, + true, classLoader).asSubclass(Root.class); + try { + Root root = rootClass.newInstance(); + return root; + } catch (Exception e) { + throw new RuntimeException("Could not instantiate root class " + + rootClassName, e); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException("Could not load root class " + + rootClassName, e); + } + } + + /** + * Provides the name of the <code>Root</code> class that should be used for + * a request. The class must have an accessible no-args constructor. + * <p> + * The default implementation uses the {@value #ROOT_PARAMETER} parameter + * from web.xml. + * </p> + * <p> + * This method is mainly used by the default implementation of + * {@link #getRoot(WrappedRequest)}. If you override that method with your + * own functionality, the results of this method might not be used. + * </p> + * + * @param request + * the request for which a new root is required + * @return the name of the root class to use + * + * @since 7.0 + */ + protected String getRootClassName(WrappedRequest request) { + Object rootClassNameObj = properties.get(ROOT_PARAMETER); + if (rootClassNameObj instanceof String) { + return (String) rootClassNameObj; + } else { + throw new RuntimeException("No " + ROOT_PARAMETER + + " defined in web.xml"); + } + } + + /** + * Finds the theme to use for a specific root. If no specific theme is + * required, <code>null</code> is returned. + * + * TODO Tell what the default implementation does once it does something. + * + * @param root + * the root to get a theme for + * @return the name of the theme, or <code>null</code> if the default theme + * should be used + * + * @since 7.0 + */ + public String getThemeForRoot(Root root) { + Theme rootTheme = getAnnotationFor(root.getClass(), Theme.class); + if (rootTheme != null) { + return rootTheme.value(); + } else { + return null; + } + } + + /** + * Finds the widgetset to use for a specific root. If no specific widgetset + * is required, <code>null</code> is returned. + * + * TODO Tell what the default implementation does once it does something. + * + * @param root + * the root to get a widgetset for + * @return the name of the widgetset, or <code>null</code> if the default + * widgetset should be used + * + * @since 7.0 + */ + public String getWidgetsetForRoot(Root root) { + Widgetset rootWidgetset = getAnnotationFor(root.getClass(), + Widgetset.class); + if (rootWidgetset != null) { + return rootWidgetset.value(); + } else { + return null; + } + } + + /** + * Helper to get an annotation for a class. If the annotation is not present + * on the target class, it's superclasses and implemented interfaces are + * also searched for the annotation. + * + * @param type + * the target class from which the annotation should be found + * @param annotationType + * the annotation type to look for + * @return an annotation of the given type, or <code>null</code> if the + * annotation is not present on the class + */ + private static <T extends Annotation> T getAnnotationFor(Class<?> type, + Class<T> annotationType) { + // Find from the class hierarchy + Class<?> currentType = type; + while (currentType != Object.class) { + T annotation = currentType.getAnnotation(annotationType); + if (annotation != null) { + return annotation; + } else { + currentType = currentType.getSuperclass(); + } + } + + // Find from an implemented interface + for (Class<?> iface : type.getInterfaces()) { + T annotation = iface.getAnnotation(annotationType); + if (annotation != null) { + return annotation; + } + } + + return null; + } + + /** + * Handles a request by passing it to each registered {@link RequestHandler} + * in turn until one produces a response. This method is used for requests + * that have not been handled by any specific functionality in the terminal + * implementation (e.g. {@link AbstractApplicationServlet}). + * <p> + * The request handlers are invoked in the revere order in which they were + * added to the application until a response has been produced. This means + * that the most recently added handler is used first and the first request + * handler that was added to the application is invoked towards the end + * unless any previous handler has already produced a response. + * </p> + * + * @param request + * the wrapped request to get information from + * @param response + * the response to which data can be written + * @return returns <code>true</code> if a {@link RequestHandler} has + * produced a response and <code>false</code> if no response has + * been written. + * @throws IOException + * + * @see #addRequestHandler(RequestHandler) + * @see RequestHandler + * + * @since 7.0 + */ + public boolean handleRequest(WrappedRequest request, + WrappedResponse response) throws IOException { + // Use a copy to avoid ConcurrentModificationException + for (RequestHandler handler : new ArrayList<RequestHandler>( + requestHandlers)) { + if (handler.handleRequest(this, request, response)) { + return true; + } + } + // If not handled + return false; + } + + /** + * Adds a request handler to this application. Request handlers can be added + * to provide responses to requests that are not handled by the default + * functionality of the framework. + * <p> + * Handlers are called in reverse order of addition, so the most recently + * added handler will be called first. + * </p> + * + * @param handler + * the request handler to add + * + * @see #handleRequest(WrappedRequest, WrappedResponse) + * @see #removeRequestHandler(RequestHandler) + * + * @since 7.0 + */ + public void addRequestHandler(RequestHandler handler) { + requestHandlers.addFirst(handler); + } + + /** + * Removes a request handler from the application. + * + * @param handler + * the request handler to remove + * + * @since 7.0 + */ + public void removeRequestHandler(RequestHandler handler) { + requestHandlers.remove(handler); + } + + /** + * Gets the request handlers that are registered to the application. The + * iteration order of the returned collection is the same as the order in + * which the request handlers will be invoked when a request is handled. + * + * @return a collection of request handlers, with the iteration order + * according to the order they would be invoked + * + * @see #handleRequest(WrappedRequest, WrappedResponse) + * @see #addRequestHandler(RequestHandler) + * @see #removeRequestHandler(RequestHandler) + * + * @since 7.0 + */ + public Collection<RequestHandler> getRequestHandlers() { + return Collections.unmodifiableCollection(requestHandlers); + } + + /** + * Find an application resource with a given key. + * + * @param key + * The key of the resource + * @return The application resource corresponding to the provided key, or + * <code>null</code> if no resource is registered for the key + * + * @since 7.0 + */ + public ApplicationResource getResource(String key) { + return keyResourceMap.get(key); + } + + /** + * Thread local for keeping track of currently used application instance + * + * @since 7.0 + */ + private static final ThreadLocal<Application> currentApplication = new ThreadLocal<Application>(); + + private boolean rootPreserved = false; + + /** + * Gets the currently used application. The current application is + * automatically defined when processing requests to the server. In other + * cases, (e.g. from background threads), the current application is not + * automatically defined. + * + * @return the current application instance if available, otherwise + * <code>null</code> + * + * @see #setCurrentApplication(Application) + * + * @since 7.0 + */ + public static Application getCurrentApplication() { + return currentApplication.get(); + } + + /** + * Sets the thread local for the current application. This method is used by + * the framework to set the current application whenever a new request is + * processed and it is cleared when the request has been processed. + * <p> + * The application developer can also use this method to define the current + * application outside the normal request handling, e.g. when initiating + * custom background threads. + * </p> + * + * @param application + * + * @see #getCurrentApplication() + * @see ThreadLocal + * + * @since 7.0 + */ + public static void setCurrentApplication(Application application) { + currentApplication.set(application); + } + + /** + * Check whether this application is in production mode. If an application + * is in production mode, certain debugging facilities are not available. + * + * @return the status of the production mode flag + * + * @since 7.0 + */ + public boolean isProductionMode() { + return productionMode; + } + + /** + * Finds the {@link Root} to which a particular request belongs. If the + * request originates from an existing Root, that root is returned. In other + * cases, the method attempts to create and initialize a new root and might + * throw a {@link RootRequiresMoreInformationException} if all required + * information is not available. + * <p> + * Please note that this method can also return a newly created + * <code>Root</code> which has not yet been initialized. You can use + * {@link #isRootInitPending(int)} with the root's id ( + * {@link Root#getRootId()} to check whether the initialization is still + * pending. + * </p> + * + * @param request + * the request for which a root is desired + * @return a root belonging to the request + * @throws RootRequiresMoreInformationException + * if no existing root could be found and creating a new root + * requires additional information from the browser + * + * @see #getRoot(WrappedRequest) + * @see RootRequiresMoreInformationException + * + * @since 7.0 + */ + public Root getRootForRequest(WrappedRequest request) + throws RootRequiresMoreInformationException { + Root root = Root.getCurrentRoot(); + if (root != null) { + return root; + } + Integer rootId = getRootId(request); + + synchronized (this) { + BrowserDetails browserDetails = request.getBrowserDetails(); + boolean hasBrowserDetails = browserDetails != null + && browserDetails.getUriFragment() != null; + + root = roots.get(rootId); + + if (root == null && isRootPreserved()) { + // Check for a known root + if (!retainOnRefreshRoots.isEmpty()) { + + Integer retainedRootId; + if (!hasBrowserDetails) { + throw new RootRequiresMoreInformationException(); + } else { + String windowName = browserDetails.getWindowName(); + retainedRootId = retainOnRefreshRoots.get(windowName); + } + + if (retainedRootId != null) { + rootId = retainedRootId; + root = roots.get(rootId); + } + } + } + + if (root == null) { + // Throws exception if root can not yet be created + root = getRoot(request); + + // Initialize some fields for a newly created root + if (root.getApplication() == null) { + root.setApplication(this); + } + if (root.getRootId() < 0) { + + if (rootId == null) { + // Get the next id if none defined + rootId = Integer.valueOf(nextRootId++); + } + root.setRootId(rootId.intValue()); + roots.put(rootId, root); + } + } + + // Set thread local here so it is available in init + Root.setCurrentRoot(root); + + if (!initedRoots.contains(rootId)) { + boolean initRequiresBrowserDetails = isRootPreserved() + || !root.getClass() + .isAnnotationPresent(EagerInit.class); + if (!initRequiresBrowserDetails || hasBrowserDetails) { + root.doInit(request); + + // Remember that this root has been initialized + initedRoots.add(rootId); + + // init() might turn on preserve so do this afterwards + if (isRootPreserved()) { + // Remember this root + String windowName = request.getBrowserDetails() + .getWindowName(); + retainOnRefreshRoots.put(windowName, rootId); + } + } + } + } // end synchronized block + + return root; + } + + /** + * Internal helper to finds the root id for a request. + * + * @param request + * the request to get the root id for + * @return a root id, or <code>null</code> if no root id is defined + * + * @since 7.0 + */ + private static Integer getRootId(WrappedRequest request) { + if (request instanceof CombinedRequest) { + // Combined requests has the rootid parameter in the second request + CombinedRequest combinedRequest = (CombinedRequest) request; + request = combinedRequest.getSecondRequest(); + } + String rootIdString = request + .getParameter(ApplicationConnection.ROOT_ID_PARAMETER); + Integer rootId = rootIdString == null ? null + : new Integer(rootIdString); + return rootId; + } + + /** + * Sets whether the same Root state should be reused if the framework can + * detect that the application is opened in a browser window where it has + * previously been open. The framework attempts to discover this by checking + * the value of window.name in the browser. + * <p> + * NOTE that you should avoid turning this feature on/off on-the-fly when + * the UI is already shown, as it might not be retained as intended. + * </p> + * + * @param rootPreserved + * <code>true</code>if the same Root instance should be reused + * e.g. when the browser window is refreshed. + */ + public void setRootPreserved(boolean rootPreserved) { + this.rootPreserved = rootPreserved; + if (!rootPreserved) { + retainOnRefreshRoots.clear(); + } + } + + /** + * Checks whether the same Root state should be reused if the framework can + * detect that the application is opened in a browser window where it has + * previously been open. The framework attempts to discover this by checking + * the value of window.name in the browser. + * + * @return <code>true</code>if the same Root instance should be reused e.g. + * when the browser window is refreshed. + */ + public boolean isRootPreserved() { + return rootPreserved; + } + + /** + * Checks whether there's a pending initialization for the root with the + * given id. + * + * @param rootId + * root id to check for + * @return <code>true</code> of the initialization is pending, + * <code>false</code> if the root id is not registered or if the + * root has already been initialized + * + * @see #getRootForRequest(WrappedRequest) + */ + public boolean isRootInitPending(int rootId) { + return !initedRoots.contains(Integer.valueOf(rootId)); + } + + /** + * Gets all the roots of this application. This includes roots that have + * been requested but not yet initialized. Please note, that roots are not + * automatically removed e.g. if the browser window is closed and that there + * is no way to manually remove a root. Inactive roots will thus not be + * released for GC until the entire application is released when the session + * has timed out (unless there are dangling references). Improved support + * for releasing unused roots is planned for an upcoming alpha release of + * Vaadin 7. + * + * @return a collection of roots belonging to this application + * + * @since 7.0 + */ + public Collection<Root> getRoots() { + return Collections.unmodifiableCollection(roots.values()); + } + + private final HashMap<String, ClientConnector> connectorIdToConnector = new HashMap<String, ClientConnector>(); + + private int connectorIdSequence = 0; + + /** + * Generate an id for the given Connector. Connectors must not call this + * method more than once, the first time they need an id. + * + * @param connector + * A connector that has not yet been assigned an id. + * @return A new id for the connector + */ + public String createConnectorId(ClientConnector connector) { + String connectorId = String.valueOf(connectorIdSequence++); + Connector oldReference = connectorIdToConnector.put(connectorId, + connector); + if (oldReference != null) { + throw new RuntimeException( + "An error occured while generating connector ids. A connector with id " + + connectorId + " was already found!"); + } + return connectorId; + } + + /** + * Gets a connector by its id. + * + * @param connectorId + * The connector id to look for + * @return The connector with the given id or null if no connector has the + * given id + */ + public ClientConnector getConnector(String connectorId) { + return connectorIdToConnector.get(connectorId); + } + + /** + * Cleans the connector map from all connectors that are no longer attached + * to the application. This should only be called by the framework. + */ + public void cleanConnectorMap() { + // remove detached components from paintableIdMap so they + // can be GC'ed + Iterator<String> iterator = connectorIdToConnector.keySet().iterator(); + + while (iterator.hasNext()) { + String connectorId = iterator.next(); + Connector connector = connectorIdToConnector.get(connectorId); + if (connector instanceof Component) { + Component component = (Component) connector; + if (component.getApplication() != this) { + // If component is no longer part of this application, + // remove it from the map. If it is re-attached to the + // application at some point it will be re-added to this + // collection when sent to the client. + iterator.remove(); + } + } + } + + } +} diff --git a/src/com/vaadin/RootRequiresMoreInformationException.java b/src/com/vaadin/RootRequiresMoreInformationException.java new file mode 100644 index 0000000000..ed0fa41437 --- /dev/null +++ b/src/com/vaadin/RootRequiresMoreInformationException.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedRequest.BrowserDetails; + +/** + * Exception that is thrown to indicate that creating or initializing the root + * requires information detailed from the web browser ({@link BrowserDetails}) + * to be present. + * + * This exception may not be thrown if that information is already present in + * the current WrappedRequest. + * + * @see Application#getRoot(WrappedRequest) + * @see WrappedRequest#getBrowserDetails() + * + * @since 7.0 + */ +public class RootRequiresMoreInformationException extends Exception { + // Nothing of interest here +} diff --git a/src/com/vaadin/annotations/EagerInit.java b/src/com/vaadin/annotations/EagerInit.java new file mode 100644 index 0000000000..c7c2702d2a --- /dev/null +++ b/src/com/vaadin/annotations/EagerInit.java @@ -0,0 +1,30 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.ui.Root; + +/** + * Indicates that the init method in a Root class can be called before full + * browser details ({@link WrappedRequest#getBrowserDetails()}) are available. + * This will make the UI appear more quickly, as ensuring the availability of + * this information typically requires an additional round trip to the client. + * + * @see Root#init(com.vaadin.terminal.WrappedRequest) + * @see WrappedRequest#getBrowserDetails() + * + * @since 7.0 + * + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface EagerInit { + // No values +} diff --git a/src/com/vaadin/annotations/Theme.java b/src/com/vaadin/annotations/Theme.java new file mode 100644 index 0000000000..7c62b07741 --- /dev/null +++ b/src/com/vaadin/annotations/Theme.java @@ -0,0 +1,24 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.ui.Root; + +/** + * Defines a specific theme for a {@link Root}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Theme { + /** + * @return simple name of the theme + */ + public String value(); +} diff --git a/src/com/vaadin/annotations/Widgetset.java b/src/com/vaadin/annotations/Widgetset.java new file mode 100644 index 0000000000..99113f73f9 --- /dev/null +++ b/src/com/vaadin/annotations/Widgetset.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.ui.Root; + +/** + * Defines a specific theme for a {@link Root}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Widgetset { + /** + * @return name of the widgetset + */ + public String value(); + +} diff --git a/src/com/vaadin/data/Buffered.java b/src/com/vaadin/data/Buffered.java index 28167f71df..1387cb965b 100644 --- a/src/com/vaadin/data/Buffered.java +++ b/src/com/vaadin/data/Buffered.java @@ -7,10 +7,6 @@ package com.vaadin.data; import java.io.Serializable; import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.SystemError; /** * <p> @@ -77,7 +73,11 @@ public interface Buffered extends Serializable { * * @return <code>true</code> if the object is in write-through mode, * <code>false</code> if it's not. + * @deprecated Use {@link #setBuffered(boolean)} instead. Note that + * setReadThrough(true), setWriteThrough(true) equals + * setBuffered(false) */ + @Deprecated public boolean isWriteThrough(); /** @@ -95,7 +95,11 @@ public interface Buffered extends Serializable { * If the implicit commit operation fails because of a * validation error. * + * @deprecated Use {@link #setBuffered(boolean)} instead. Note that + * setReadThrough(true), setWriteThrough(true) equals + * setBuffered(false) */ + @Deprecated public void setWriteThrough(boolean writeThrough) throws SourceException, InvalidValueException; @@ -112,7 +116,11 @@ public interface Buffered extends Serializable { * * @return <code>true</code> if the object is in read-through mode, * <code>false</code> if it's not. + * @deprecated Use {@link #isBuffered(boolean)} instead. Note that + * setReadThrough(true), setWriteThrough(true) equals + * setBuffered(false) */ + @Deprecated public boolean isReadThrough(); /** @@ -127,10 +135,52 @@ public interface Buffered extends Serializable { * @throws SourceException * If the operation fails because of an exception is thrown by * the data source. The cause is included in the exception. + * @deprecated Use {@link #setBuffered(boolean)} instead. Note that + * setReadThrough(true), setWriteThrough(true) equals + * setBuffered(false) */ + @Deprecated public void setReadThrough(boolean readThrough) throws SourceException; /** + * Sets the object's buffered mode to the specified status. + * <p> + * When the object is in buffered mode, an internal buffer will be used to + * store changes until {@link #commit()} is called. Calling + * {@link #discard()} will revert the internal buffer to the value of the + * data source. + * </p> + * <p> + * This is an easier way to use {@link #setReadThrough(boolean)} and + * {@link #setWriteThrough(boolean)} and not as error prone. Changing + * buffered mode will change both the read through and write through state + * of the object. + * </p> + * <p> + * Mixing calls to {@link #setBuffered(boolean)}/{@link #isBuffered()} and + * {@link #setReadThrough(boolean)}/{@link #isReadThrough()} or + * {@link #setWriteThrough(boolean)}/{@link #isWriteThrough()} is generally + * a bad idea. + * </p> + * + * @param buffered + * true if buffered mode should be turned on, false otherwise + * @since 7.0 + */ + public void setBuffered(boolean buffered); + + /** + * Checks the buffered mode of this Object. + * <p> + * This method only returns true if both read and write buffering is used. + * </p> + * + * @return true if buffered mode is on, false otherwise + * @since 7.0 + */ + public boolean isBuffered(); + + /** * Tests if the value stored in the object has been modified since it was * last updated from the data source. * @@ -151,7 +201,7 @@ public interface Buffered extends Serializable { */ @SuppressWarnings("serial") public class SourceException extends RuntimeException implements - ErrorMessage, Serializable { + Serializable { /** Source class implementing the buffered interface */ private final Buffered source; @@ -198,11 +248,7 @@ public interface Buffered extends Serializable { /** * Gets the cause of the exception. * - * @return The cause for the exception. - * @throws MoreThanOneCauseException - * if there is more than one cause for the exception. This - * is possible if the commit operation triggers more than - * one error at the same time. + * @return The (first) cause for the exception, null if no cause. */ @Override public final Throwable getCause() { @@ -230,86 +276,5 @@ public interface Buffered extends Serializable { return source; } - /** - * Gets the error level of this buffered source exception. The level of - * the exception is maximum error level of all the contained causes. - * <p> - * The causes that do not specify error level default to - * <code>ERROR</code> level. Also source exception without any causes - * are of level <code>ERROR</code>. - * </p> - * - * @see com.vaadin.terminal.ErrorMessage#getErrorLevel() - */ - public int getErrorLevel() { - - int level = Integer.MIN_VALUE; - - for (int i = 0; i < causes.length; i++) { - final int causeLevel = (causes[i] instanceof ErrorMessage) ? ((ErrorMessage) causes[i]) - .getErrorLevel() : ErrorMessage.ERROR; - if (causeLevel > level) { - level = causeLevel; - } - } - - return level == Integer.MIN_VALUE ? ErrorMessage.ERROR : level; - } - - /* Documented in super interface */ - public void paint(PaintTarget target) throws PaintException { - target.startTag("error"); - final int level = getErrorLevel(); - if (level > 0 && level <= ErrorMessage.INFORMATION) { - target.addAttribute("level", "info"); - } else if (level <= ErrorMessage.WARNING) { - target.addAttribute("level", "warning"); - } else if (level <= ErrorMessage.ERROR) { - target.addAttribute("level", "error"); - } else if (level <= ErrorMessage.CRITICAL) { - target.addAttribute("level", "critical"); - } else { - target.addAttribute("level", "system"); - } - - // Paint all the exceptions - for (int i = 0; i < causes.length; i++) { - if (causes[i] instanceof ErrorMessage) { - ((ErrorMessage) causes[i]).paint(target); - } else { - new SystemError(causes[i]).paint(target); - } - } - - target.endTag("error"); - - } - - /* Documented in super interface */ - public void addListener(RepaintRequestListener listener) { - } - - /* Documented in super interface */ - public void removeListener(RepaintRequestListener listener) { - } - - /* Documented in super interface */ - public void requestRepaint() { - } - - /* Documented in super interface */ - public void requestRepaintRequests() { - } - - public String getDebugId() { - // TODO Auto-generated method stub - return null; - } - - public void setDebugId(String id) { - throw new UnsupportedOperationException( - "Setting testing id for this Paintable is not implemented"); - } - } } diff --git a/src/com/vaadin/ui/treetable/Collapsible.java b/src/com/vaadin/data/Collapsible.java index bec0ba9ae9..06c96b7ea7 100644 --- a/src/com/vaadin/ui/treetable/Collapsible.java +++ b/src/com/vaadin/data/Collapsible.java @@ -1,15 +1,14 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.ui.treetable; +package com.vaadin.data; -import com.vaadin.data.Container; import com.vaadin.data.Container.Hierarchical; import com.vaadin.data.Container.Ordered; -import com.vaadin.data.Item; /** - * Container needed by large lazy loading hierarchies displayed in TreeTable. + * Container needed by large lazy loading hierarchies displayed e.g. in + * TreeTable. * <p> * Container of this type gets notified when a subtree is opened/closed in a * component displaying its content. This allows container to lazy load subtrees diff --git a/src/com/vaadin/data/Container.java b/src/com/vaadin/data/Container.java index 7f64dc6efa..f722e07741 100644 --- a/src/com/vaadin/data/Container.java +++ b/src/com/vaadin/data/Container.java @@ -121,7 +121,7 @@ public interface Container extends Serializable { * ID of the Property to retrieve * @return Property with the given ID or <code>null</code> */ - public Property getContainerProperty(Object itemId, Object propertyId); + public Property<?> getContainerProperty(Object itemId, Object propertyId); /** * Gets the data type of all Properties identified by the given Property ID. @@ -1101,4 +1101,4 @@ public interface Container extends Serializable { */ public void removeListener(Container.PropertySetChangeListener listener); } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/data/Item.java b/src/com/vaadin/data/Item.java index 3a884a99ab..98b95aecff 100644 --- a/src/com/vaadin/data/Item.java +++ b/src/com/vaadin/data/Item.java @@ -30,7 +30,7 @@ public interface Item extends Serializable { * identifier of the Property to get * @return the Property with the given ID or <code>null</code> */ - public Property getItemProperty(Object id); + public Property<?> getItemProperty(Object id); /** * Gets the collection of IDs of all Properties stored in the Item. diff --git a/src/com/vaadin/data/Property.java b/src/com/vaadin/data/Property.java index 70d57c3aee..9fab642381 100644 --- a/src/com/vaadin/data/Property.java +++ b/src/com/vaadin/data/Property.java @@ -30,12 +30,15 @@ import java.io.Serializable; * needs to be changed through the implementing class. * </p> * + * @param T + * type of values of the property + * * @author Vaadin Ltd * @version * @VERSION@ * @since 3.0 */ -public interface Property extends Serializable { +public interface Property<T> extends Serializable { /** * Gets the value stored in the Property. The returned object is compatible @@ -43,7 +46,7 @@ public interface Property extends Serializable { * * @return the value stored in the Property */ - public Object getValue(); + public T getValue(); /** * Sets the value of the Property. @@ -52,37 +55,18 @@ public interface Property extends Serializable { * missing, one should declare the Property to be in read-only mode and * throw <code>Property.ReadOnlyException</code> in this function. * </p> - * Note : It is not required, but highly recommended to support setting the - * value also as a <code>String</code> in addition to the native type of the - * Property (as given by the <code>getType</code> method). If the - * <code>String</code> conversion fails or is unsupported, the method should - * throw <code>Property.ConversionException</code>. The string conversion - * should at least understand the format returned by the - * <code>toString</code> method of the Property. + * + * Note : Since Vaadin 7.0, setting the value of a non-String property as a + * String is no longer supported. * * @param newValue * New value of the Property. This should be assignable to the - * type returned by getType, but also String type should be - * supported + * type returned by getType * * @throws Property.ReadOnlyException * if the object is in read-only mode - * @throws Property.ConversionException - * if newValue can't be converted into the Property's native - * type directly or through String */ - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException; - - /** - * Returns the value of the Property in human readable textual format. The - * return value should be assignable to the <code>setValue</code> method if - * the Property is not in read-only mode. - * - * @return <code>String</code> representation of the value stored in the - * Property - */ - public String toString(); + public void setValue(Object newValue) throws Property.ReadOnlyException; /** * Returns the type of the Property. The methods <code>getValue</code> and @@ -93,7 +77,7 @@ public interface Property extends Serializable { * * @return type of the Property */ - public Class<?> getType(); + public Class<? extends T> getType(); /** * Tests if the Property is in read-only mode. In read-only mode calls to @@ -118,90 +102,94 @@ public interface Property extends Serializable { public void setReadOnly(boolean newStatus); /** - * <code>Exception</code> object that signals that a requested Property - * modification failed because it's in read-only mode. + * A Property that is capable of handle a transaction that can end in commit + * or rollback. * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 + * Note that this does not refer to e.g. database transactions but rather + * two-phase commit that allows resetting old field values on a form etc. if + * the commit of one of the properties fails after others have already been + * committed. If + * + * @param <T> + * The type of the property + * @author Vaadin Ltd + * @version @version@ + * @since 7.0 */ - @SuppressWarnings("serial") - public class ReadOnlyException extends RuntimeException { + public interface Transactional<T> extends Property<T> { /** - * Constructs a new <code>ReadOnlyException</code> without a detail - * message. + * Starts a transaction. + * + * <p> + * If the value is set during a transaction the value must not replace + * the original value until {@link #commit()} is called. Still, + * {@link #getValue()} must return the current value set in the + * transaction. Calling {@link #rollback()} while in a transaction must + * rollback the value to what it was before the transaction started. + * </p> + * <p> + * {@link ValueChangeEvent}s must not be emitted for internal value + * changes during a transaction. If the value changes as a result of + * {@link #commit()}, a {@link ValueChangeEvent} should be emitted. + * </p> */ - public ReadOnlyException() { - } + public void startTransaction(); /** - * Constructs a new <code>ReadOnlyException</code> with the specified - * detail message. - * - * @param msg - * the detail message + * Commits and ends the transaction that is in progress. + * <p> + * If the value is changed as a result of this operation, a + * {@link ValueChangeEvent} is emitted if such are supported. + * <p> + * This method has no effect if there is no transaction is in progress. + * <p> + * This method must never throw an exception. */ - public ReadOnlyException(String msg) { - super(msg); - } + public void commit(); + + /** + * Aborts and rolls back the transaction that is in progress. + * <p> + * The value is reset to the value before the transaction started. No + * {@link ValueChangeEvent} is emitted as a result of this. + * <p> + * This method has no effect if there is no transaction is in progress. + * <p> + * This method must never throw an exception. + */ + public void rollback(); } /** - * An exception that signals that the value passed to the - * <code>setValue</code> method couldn't be converted to the native type of - * the Property. + * <code>Exception</code> object that signals that a requested Property + * modification failed because it's in read-only mode. * - * @author Vaadin Ltd + * @author Vaadin Ltd. * @version * @VERSION@ * @since 3.0 */ @SuppressWarnings("serial") - public class ConversionException extends RuntimeException { + public class ReadOnlyException extends RuntimeException { /** - * Constructs a new <code>ConversionException</code> without a detail + * Constructs a new <code>ReadOnlyException</code> without a detail * message. */ - public ConversionException() { + public ReadOnlyException() { } /** - * Constructs a new <code>ConversionException</code> with the specified + * Constructs a new <code>ReadOnlyException</code> with the specified * detail message. * * @param msg * the detail message */ - public ConversionException(String msg) { + public ReadOnlyException(String msg) { super(msg); } - - /** - * Constructs a new <code>ConversionException</code> from another - * exception. - * - * @param cause - * The cause of the the conversion failure - */ - public ConversionException(Throwable cause) { - super(cause); - } - - /** - * Constructs a new <code>ConversionException</code> with the specified - * detail message and cause. - * - * @param message - * the detail message - * @param cause - * The cause of the the conversion failure - */ - public ConversionException(String message, Throwable cause) { - super(message, cause); - } } /** diff --git a/src/com/vaadin/data/Validator.java b/src/com/vaadin/data/Validator.java index fc4cdf5b42..768a02babe 100644 --- a/src/com/vaadin/data/Validator.java +++ b/src/com/vaadin/data/Validator.java @@ -6,9 +6,6 @@ package com.vaadin.data; import java.io.Serializable; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; /** @@ -20,15 +17,20 @@ import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; * value. * </p> * <p> - * {@link #isValid(Object)} and {@link #validate(Object)} can be used to check - * if a value is valid. {@link #isValid(Object)} and {@link #validate(Object)} - * must use the same validation logic so that iff {@link #isValid(Object)} - * returns false, {@link #validate(Object)} throws an - * {@link InvalidValueException}. + * {@link #validate(Object)} can be used to check if a value is valid. An + * {@link InvalidValueException} with an appropriate validation error message is + * thrown if the value is not valid. * </p> * <p> * Validators must not have any side effects. * </p> + * <p> + * Since Vaadin 7, the method isValid(Object) does not exist in the interface - + * {@link #validate(Object)} should be used instead, and the exception caught + * where applicable. Concrete classes implementing {@link Validator} can still + * internally implement and use isValid(Object) for convenience or to ease + * migration from earlier Vaadin versions. + * </p> * * @author Vaadin Ltd. * @version @@ -50,18 +52,6 @@ public interface Validator extends Serializable { public void validate(Object value) throws Validator.InvalidValueException; /** - * Tests if the given value is valid. This method must be symmetric with - * {@link #validate(Object)} so that {@link #validate(Object)} throws an - * error iff this method returns false. - * - * @param value - * the value to check - * @return <code>true</code> if the value is valid, <code>false</code> - * otherwise. - */ - public boolean isValid(Object value); - - /** * Exception that is thrown by a {@link Validator} when a value is invalid. * * <p> @@ -76,8 +66,7 @@ public interface Validator extends Serializable { * @since 3.0 */ @SuppressWarnings("serial") - public class InvalidValueException extends RuntimeException implements - ErrorMessage { + public class InvalidValueException extends RuntimeException { /** * Array of one or more validation errors that are causing this @@ -141,104 +130,16 @@ public interface Validator extends Serializable { return true; } - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.ErrorMessage#getErrorLevel() - */ - public final int getErrorLevel() { - return ErrorMessage.ERROR; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.Paintable#paint(com.vaadin.terminal.PaintTarget) - */ - public void paint(PaintTarget target) throws PaintException { - target.startTag("error"); - target.addAttribute("level", "error"); - - // Error message - final String message = getHtmlMessage(); - if (message != null) { - target.addText(message); - } - - // Paint all the causes - for (int i = 0; i < causes.length; i++) { - causes[i].paint(target); - } - - target.endTag("error"); - } - /** * Returns the message of the error in HTML. * * Note that this API may change in future versions. */ - protected String getHtmlMessage() { + public String getHtmlMessage() { return AbstractApplicationServlet .safeEscapeForHtml(getLocalizedMessage()); } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.ErrorMessage#addListener(com.vaadin.terminal. - * Paintable.RepaintRequestListener) - */ - public void addListener(RepaintRequestListener listener) { - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.ErrorMessage#removeListener(com.vaadin.terminal - * .Paintable.RepaintRequestListener) - */ - public void removeListener(RepaintRequestListener listener) { - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.ErrorMessage#requestRepaint() - */ - public void requestRepaint() { - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Paintable#requestRepaintRequests() - */ - public void requestRepaintRequests() { - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Paintable#getDebugId() - */ - public String getDebugId() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Paintable#setDebugId(java.lang.String) - */ - public void setDebugId(String id) { - throw new UnsupportedOperationException( - "InvalidValueException cannot have a debug id"); - } - /** * Returns the {@code InvalidValueExceptions} that caused this * exception. diff --git a/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java new file mode 100644 index 0000000000..b8efa5b1e4 --- /dev/null +++ b/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java @@ -0,0 +1,157 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.fieldgroup; + +import java.lang.reflect.Method; + +import com.vaadin.data.Item; +import com.vaadin.data.util.BeanItem; +import com.vaadin.data.validator.BeanValidator; +import com.vaadin.ui.Field; + +public class BeanFieldGroup<T> extends FieldGroup { + + private Class<T> beanType; + + private static Boolean beanValidationImplementationAvailable = null; + + public BeanFieldGroup(Class<T> beanType) { + this.beanType = beanType; + } + + @Override + protected Class<?> getPropertyType(Object propertyId) { + if (getItemDataSource() != null) { + return super.getPropertyType(propertyId); + } else { + // Data source not set so we need to figure out the type manually + /* + * toString should never really be needed as propertyId should be of + * form "fieldName" or "fieldName.subField[.subField2]" but the + * method declaration comes from parent. + */ + java.lang.reflect.Field f; + try { + f = getField(beanType, propertyId.toString()); + return f.getType(); + } catch (SecurityException e) { + throw new BindException("Cannot determine type of propertyId '" + + propertyId + "'.", e); + } catch (NoSuchFieldException e) { + throw new BindException("Cannot determine type of propertyId '" + + propertyId + "'. The propertyId was not found in " + + beanType.getName(), e); + } + } + } + + private static java.lang.reflect.Field getField(Class<?> cls, + String propertyId) throws SecurityException, NoSuchFieldException { + if (propertyId.contains(".")) { + String[] parts = propertyId.split("\\.", 2); + // Get the type of the field in the "cls" class + java.lang.reflect.Field field1 = getField(cls, parts[0]); + // Find the rest from the sub type + return getField(field1.getType(), parts[1]); + } else { + try { + // Try to find the field directly in the given class + java.lang.reflect.Field field1 = cls + .getDeclaredField(propertyId); + return field1; + } catch (NoSuchFieldError e) { + // Try super classes until we reach Object + Class<?> superClass = cls.getSuperclass(); + if (superClass != Object.class) { + return getField(superClass, propertyId); + } else { + throw e; + } + } + } + } + + /** + * Helper method for setting the data source directly using a bean. This + * method wraps the bean in a {@link BeanItem} and calls + * {@link #setItemDataSource(Item)}. + * + * @param bean + * The bean to use as data source. + */ + public void setItemDataSource(T bean) { + setItemDataSource(new BeanItem(bean)); + } + + @Override + public void setItemDataSource(Item item) { + if (!(item instanceof BeanItem)) { + throw new RuntimeException(getClass().getSimpleName() + + " only supports BeanItems as item data source"); + } + super.setItemDataSource(item); + } + + @Override + public BeanItem<T> getItemDataSource() { + return (BeanItem<T>) super.getItemDataSource(); + } + + @Override + public void bind(Field field, Object propertyId) { + if (getItemDataSource() != null) { + // The data source is set so the property must be found in the item. + // If it is not we try to add it. + try { + getItemProperty(propertyId); + } catch (BindException e) { + // Not found, try to add a nested property; + // BeanItem property ids are always strings so this is safe + getItemDataSource().addNestedProperty((String) propertyId); + } + } + + super.bind(field, propertyId); + } + + @Override + protected void configureField(Field<?> field) { + super.configureField(field); + // Add Bean validators if there are annotations + if (isBeanValidationImplementationAvailable()) { + BeanValidator validator = new BeanValidator(beanType, + getPropertyId(field).toString()); + field.addValidator(validator); + if (field.getLocale() != null) { + validator.setLocale(field.getLocale()); + } + } + } + + /** + * Checks whether a bean validation implementation (e.g. Hibernate Validator + * or Apache Bean Validation) is available. + * + * TODO move this method to some more generic location + * + * @return true if a JSR-303 bean validation implementation is available + */ + protected static boolean isBeanValidationImplementationAvailable() { + if (beanValidationImplementationAvailable != null) { + return beanValidationImplementationAvailable; + } + try { + Class<?> validationClass = Class + .forName("javax.validation.Validation"); + Method buildFactoryMethod = validationClass + .getMethod("buildDefaultValidatorFactory"); + Object factory = buildFactoryMethod.invoke(null); + beanValidationImplementationAvailable = (factory != null); + } catch (Exception e) { + // no bean validation implementation available + beanValidationImplementationAvailable = false; + } + return beanValidationImplementationAvailable; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/data/fieldgroup/Caption.java b/src/com/vaadin/data/fieldgroup/Caption.java new file mode 100644 index 0000000000..b990b720cd --- /dev/null +++ b/src/com/vaadin/data/fieldgroup/Caption.java @@ -0,0 +1,15 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.fieldgroup; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Caption { + String value(); +} diff --git a/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java b/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java new file mode 100644 index 0000000000..569f643998 --- /dev/null +++ b/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java @@ -0,0 +1,156 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.fieldgroup; + +import java.util.EnumSet; + +import com.vaadin.data.Item; +import com.vaadin.data.fieldgroup.FieldGroup.BindException; +import com.vaadin.ui.AbstractSelect; +import com.vaadin.ui.AbstractTextField; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Field; +import com.vaadin.ui.ListSelect; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.OptionGroup; +import com.vaadin.ui.RichTextArea; +import com.vaadin.ui.Table; +import com.vaadin.ui.TextField; + +public class DefaultFieldGroupFieldFactory implements FieldGroupFieldFactory { + + public static final Object CAPTION_PROPERTY_ID = "Caption"; + + public <T extends Field> T createField(Class<?> type, Class<T> fieldType) { + if (Enum.class.isAssignableFrom(type)) { + return createEnumField(type, fieldType); + } else if (Boolean.class.isAssignableFrom(type) + || boolean.class.isAssignableFrom(type)) { + return createBooleanField(fieldType); + } + if (AbstractTextField.class.isAssignableFrom(fieldType)) { + return fieldType.cast(createAbstractTextField(fieldType + .asSubclass(AbstractTextField.class))); + } else if (fieldType == RichTextArea.class) { + return fieldType.cast(createRichTextArea()); + } + return createDefaultField(type, fieldType); + } + + protected RichTextArea createRichTextArea() { + RichTextArea rta = new RichTextArea(); + rta.setImmediate(true); + + return rta; + } + + private <T extends Field> T createEnumField(Class<?> type, + Class<T> fieldType) { + if (AbstractSelect.class.isAssignableFrom(fieldType)) { + AbstractSelect s = createCompatibleSelect((Class<? extends AbstractSelect>) fieldType); + populateWithEnumData(s, (Class<? extends Enum>) type); + return (T) s; + } + + return null; + } + + protected AbstractSelect createCompatibleSelect( + Class<? extends AbstractSelect> fieldType) { + AbstractSelect select; + if (fieldType.isAssignableFrom(ListSelect.class)) { + select = new ListSelect(); + select.setMultiSelect(false); + } else if (fieldType.isAssignableFrom(NativeSelect.class)) { + select = new NativeSelect(); + } else if (fieldType.isAssignableFrom(OptionGroup.class)) { + select = new OptionGroup(); + select.setMultiSelect(false); + } else if (fieldType.isAssignableFrom(Table.class)) { + Table t = new Table(); + t.setSelectable(true); + select = t; + } else { + select = new ComboBox(null); + } + select.setImmediate(true); + select.setNullSelectionAllowed(false); + + return select; + } + + protected <T extends Field> T createBooleanField(Class<T> fieldType) { + if (fieldType.isAssignableFrom(CheckBox.class)) { + CheckBox cb = new CheckBox(null); + cb.setImmediate(true); + return (T) cb; + } else if (AbstractTextField.class.isAssignableFrom(fieldType)) { + return (T) createAbstractTextField((Class<? extends AbstractTextField>) fieldType); + } + + return null; + } + + protected <T extends AbstractTextField> T createAbstractTextField( + Class<T> fieldType) { + if (fieldType == AbstractTextField.class) { + fieldType = (Class<T>) TextField.class; + } + try { + T field = fieldType.newInstance(); + field.setImmediate(true); + return field; + } catch (Exception e) { + throw new BindException("Could not create a field of type " + + fieldType, e); + } + } + + /** + * Fallback when no specific field has been created. Typically returns a + * TextField. + * + * @param <T> + * The type of field to create + * @param type + * The type of data that should be edited + * @param fieldType + * The type of field to create + * @return A field capable of editing the data or null if no field could be + * created + */ + protected <T extends Field> T createDefaultField(Class<?> type, + Class<T> fieldType) { + if (fieldType.isAssignableFrom(TextField.class)) { + return fieldType.cast(createAbstractTextField(TextField.class)); + } + return null; + } + + /** + * Populates the given select with all the enums in the given {@link Enum} + * class. Uses {@link Enum}.toString() for caption. + * + * @param select + * The select to populate + * @param enumClass + * The Enum class to use + */ + protected void populateWithEnumData(AbstractSelect select, + Class<? extends Enum> enumClass) { + select.removeAllItems(); + for (Object p : select.getContainerPropertyIds()) { + select.removeContainerProperty(p); + } + select.addContainerProperty(CAPTION_PROPERTY_ID, String.class, ""); + select.setItemCaptionPropertyId(CAPTION_PROPERTY_ID); + @SuppressWarnings("unchecked") + EnumSet<?> enumSet = EnumSet.allOf(enumClass); + for (Object r : enumSet) { + Item newItem = select.addItem(r); + newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(r.toString()); + } + } +} diff --git a/src/com/vaadin/data/fieldgroup/FieldGroup.java b/src/com/vaadin/data/fieldgroup/FieldGroup.java new file mode 100644 index 0000000000..3df19f5bc9 --- /dev/null +++ b/src/com/vaadin/data/fieldgroup/FieldGroup.java @@ -0,0 +1,978 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.fieldgroup; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.logging.Logger; + +import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.util.TransactionalPropertyWrapper; +import com.vaadin.tools.ReflectTools; +import com.vaadin.ui.DefaultFieldFactory; +import com.vaadin.ui.Field; +import com.vaadin.ui.Form; + +/** + * FieldGroup provides an easy way of binding fields to data and handling + * commits of these fields. + * <p> + * The functionality of FieldGroup is similar to {@link Form} but + * {@link FieldGroup} does not handle layouts in any way. The typical use case + * is to create a layout outside the FieldGroup and then use FieldGroup to bind + * the fields to a data source. + * </p> + * <p> + * {@link FieldGroup} is not a UI component so it cannot be added to a layout. + * Using the buildAndBind methods {@link FieldGroup} can create fields for you + * using a FieldGroupFieldFactory but you still have to add them to the correct + * position in your layout. + * </p> + * + * @author Vaadin Ltd + * @version @version@ + * @since 7.0 + */ +public class FieldGroup implements Serializable { + + private static final Logger logger = Logger.getLogger(FieldGroup.class + .getName()); + + private Item itemDataSource; + private boolean buffered = true; + + private boolean enabled = true; + private boolean readOnly = false; + + private HashMap<Object, Field<?>> propertyIdToField = new HashMap<Object, Field<?>>(); + private LinkedHashMap<Field<?>, Object> fieldToPropertyId = new LinkedHashMap<Field<?>, Object>(); + private List<CommitHandler> commitHandlers = new ArrayList<CommitHandler>(); + + /** + * The field factory used by builder methods. + */ + private FieldGroupFieldFactory fieldFactory = new DefaultFieldGroupFieldFactory(); + + /** + * Constructs a field binder. Use {@link #setItemDataSource(Item)} to set a + * data source for the field binder. + * + */ + public FieldGroup() { + + } + + /** + * Constructs a field binder that uses the given data source. + * + * @param itemDataSource + * The data source to bind the fields to + */ + public FieldGroup(Item itemDataSource) { + setItemDataSource(itemDataSource); + } + + /** + * Updates the item that is used by this FieldBinder. Rebinds all fields to + * the properties in the new item. + * + * @param itemDataSource + * The new item to use + */ + public void setItemDataSource(Item itemDataSource) { + this.itemDataSource = itemDataSource; + + for (Field<?> f : fieldToPropertyId.keySet()) { + bind(f, fieldToPropertyId.get(f)); + } + } + + /** + * Gets the item used by this FieldBinder. Note that you must call + * {@link #commit()} for the item to be updated unless buffered mode has + * been switched off. + * + * @see #setBuffered(boolean) + * @see #commit() + * + * @return The item used by this FieldBinder + */ + public Item getItemDataSource() { + return itemDataSource; + } + + /** + * Checks the buffered mode for the bound fields. + * <p> + * + * @see #setBuffered(boolean) for more details on buffered mode + * + * @see Field#isBuffered() + * @return true if buffered mode is on, false otherwise + * + */ + public boolean isBuffered() { + return buffered; + } + + /** + * Sets the buffered mode for the bound fields. + * <p> + * When buffered mode is on the item will not be updated until + * {@link #commit()} is called. If buffered mode is off the item will be + * updated once the fields are updated. + * </p> + * <p> + * The default is to use buffered mode. + * </p> + * + * @see Field#setBuffered(boolean) + * @param buffered + * true to turn on buffered mode, false otherwise + */ + public void setBuffered(boolean buffered) { + if (buffered == this.buffered) { + return; + } + + this.buffered = buffered; + for (Field<?> field : getFields()) { + field.setBuffered(buffered); + } + } + + /** + * Returns the enabled status for the fields. + * <p> + * Note that this will not accurately represent the enabled status of all + * fields if you change the enabled status of the fields through some other + * method than {@link #setEnabled(boolean)}. + * + * @return true if the fields are enabled, false otherwise + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Updates the enabled state of all bound fields. + * + * @param fieldsEnabled + * true to enable all bound fields, false to disable them + */ + public void setEnabled(boolean fieldsEnabled) { + enabled = fieldsEnabled; + for (Field<?> field : getFields()) { + field.setEnabled(fieldsEnabled); + } + } + + /** + * Returns the read only status for the fields. + * <p> + * Note that this will not accurately represent the read only status of all + * fields if you change the read only status of the fields through some + * other method than {@link #setReadOnly(boolean)}. + * + * @return true if the fields are set to read only, false otherwise + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * Updates the read only state of all bound fields. + * + * @param fieldsReadOnly + * true to set all bound fields to read only, false to set them + * to read write + */ + public void setReadOnly(boolean fieldsReadOnly) { + readOnly = fieldsReadOnly; + } + + /** + * Returns a collection of all fields that have been bound. + * <p> + * The fields are not returned in any specific order. + * </p> + * + * @return A collection with all bound Fields + */ + public Collection<Field<?>> getFields() { + return fieldToPropertyId.keySet(); + } + + /** + * Binds the field with the given propertyId from the current item. If an + * item has not been set then the binding is postponed until the item is set + * using {@link #setItemDataSource(Item)}. + * <p> + * This method also adds validators when applicable. + * </p> + * + * @param field + * The field to bind + * @param propertyId + * The propertyId to bind to the field + * @throws BindException + * If the property id is already bound to another field by this + * field binder + */ + public void bind(Field<?> field, Object propertyId) throws BindException { + if (propertyIdToField.containsKey(propertyId) + && propertyIdToField.get(propertyId) != field) { + throw new BindException("Property id " + propertyId + + " is already bound to another field"); + } + fieldToPropertyId.put(field, propertyId); + propertyIdToField.put(propertyId, field); + if (itemDataSource == null) { + // Will be bound when data source is set + return; + } + + field.setPropertyDataSource(wrapInTransactionalProperty(getItemProperty(propertyId))); + configureField(field); + } + + private <T> Property.Transactional<T> wrapInTransactionalProperty( + Property<T> itemProperty) { + return new TransactionalPropertyWrapper<T>(itemProperty); + } + + /** + * Gets the property with the given property id from the item. + * + * @param propertyId + * The id if the property to find + * @return The property with the given id from the item + * @throws BindException + * If the property was not found in the item or no item has been + * set + */ + protected Property<?> getItemProperty(Object propertyId) + throws BindException { + Item item = getItemDataSource(); + if (item == null) { + throw new BindException("Could not lookup property with id " + + propertyId + " as no item has been set"); + } + Property<?> p = item.getItemProperty(propertyId); + if (p == null) { + throw new BindException("A property with id " + propertyId + + " was not found in the item"); + } + return p; + } + + /** + * Detaches the field from its property id and removes it from this + * FieldBinder. + * <p> + * Note that the field is not detached from its property data source if it + * is no longer connected to the same property id it was bound to using this + * FieldBinder. + * + * @param field + * The field to detach + * @throws BindException + * If the field is not bound by this field binder or not bound + * to the correct property id + */ + public void unbind(Field<?> field) throws BindException { + Object propertyId = fieldToPropertyId.get(field); + if (propertyId == null) { + throw new BindException( + "The given field is not part of this FieldBinder"); + } + + Property fieldDataSource = field.getPropertyDataSource(); + if (fieldDataSource instanceof TransactionalPropertyWrapper) { + fieldDataSource = ((TransactionalPropertyWrapper) fieldDataSource) + .getWrappedProperty(); + } + if (fieldDataSource == getItemProperty(propertyId)) { + field.setPropertyDataSource(null); + } + fieldToPropertyId.remove(field); + propertyIdToField.remove(propertyId); + } + + /** + * Configures a field with the settings set for this FieldBinder. + * <p> + * By default this updates the buffered, read only and enabled state of the + * field. Also adds validators when applicable. + * + * @param field + * The field to update + */ + protected void configureField(Field<?> field) { + field.setBuffered(isBuffered()); + + field.setEnabled(isEnabled()); + field.setReadOnly(isReadOnly()); + } + + /** + * Gets the type of the property with the given property id. + * + * @param propertyId + * The propertyId. Must be find + * @return The type of the property + */ + protected Class<?> getPropertyType(Object propertyId) throws BindException { + if (getItemDataSource() == null) { + throw new BindException( + "Property type for '" + + propertyId + + "' could not be determined. No item data source has been set."); + } + Property<?> p = getItemDataSource().getItemProperty(propertyId); + if (p == null) { + throw new BindException( + "Property type for '" + + propertyId + + "' could not be determined. No property with that id was found."); + } + + return p.getType(); + } + + /** + * Returns a collection of all property ids that have been bound to fields. + * <p> + * Note that this will return property ids even before the item has been + * set. In that case it returns the property ids that will be bound once the + * item is set. + * </p> + * <p> + * No guarantee is given for the order of the property ids + * </p> + * + * @return A collection of bound property ids + */ + public Collection<Object> getBoundPropertyIds() { + return Collections.unmodifiableCollection(propertyIdToField.keySet()); + } + + /** + * Returns a collection of all property ids that exist in the item set using + * {@link #setItemDataSource(Item)} but have not been bound to fields. + * <p> + * Will always return an empty collection before an item has been set using + * {@link #setItemDataSource(Item)}. + * </p> + * <p> + * No guarantee is given for the order of the property ids + * </p> + * + * @return A collection of property ids that have not been bound to fields + */ + public Collection<Object> getUnboundPropertyIds() { + if (getItemDataSource() == null) { + return new ArrayList<Object>(); + } + List<Object> unboundPropertyIds = new ArrayList<Object>(); + unboundPropertyIds.addAll(getItemDataSource().getItemPropertyIds()); + unboundPropertyIds.removeAll(propertyIdToField.keySet()); + return unboundPropertyIds; + } + + /** + * Commits all changes done to the bound fields. + * <p> + * Calls all {@link CommitHandler}s before and after committing the field + * changes to the item data source. The whole commit is aborted and state is + * restored to what it was before commit was called if any + * {@link CommitHandler} throws a CommitException or there is a problem + * committing the fields + * + * @throws CommitException + * If the commit was aborted + */ + public void commit() throws CommitException { + if (!isBuffered()) { + // Not using buffered mode, nothing to do + return; + } + for (Field<?> f : fieldToPropertyId.keySet()) { + ((Property.Transactional<?>) f.getPropertyDataSource()) + .startTransaction(); + } + try { + firePreCommitEvent(); + // Commit the field values to the properties + for (Field<?> f : fieldToPropertyId.keySet()) { + f.commit(); + } + firePostCommitEvent(); + + // Commit the properties + for (Field<?> f : fieldToPropertyId.keySet()) { + ((Property.Transactional<?>) f.getPropertyDataSource()) + .commit(); + } + + } catch (Exception e) { + for (Field<?> f : fieldToPropertyId.keySet()) { + try { + ((Property.Transactional<?>) f.getPropertyDataSource()) + .rollback(); + } catch (Exception rollbackException) { + // FIXME: What to do ? + } + } + + throw new CommitException("Commit failed", e); + } + + } + + /** + * Sends a preCommit event to all registered commit handlers + * + * @throws CommitException + * If the commit should be aborted + */ + private void firePreCommitEvent() throws CommitException { + CommitHandler[] handlers = commitHandlers + .toArray(new CommitHandler[commitHandlers.size()]); + + for (CommitHandler handler : handlers) { + handler.preCommit(new CommitEvent(this)); + } + } + + /** + * Sends a postCommit event to all registered commit handlers + * + * @throws CommitException + * If the commit should be aborted + */ + private void firePostCommitEvent() throws CommitException { + CommitHandler[] handlers = commitHandlers + .toArray(new CommitHandler[commitHandlers.size()]); + + for (CommitHandler handler : handlers) { + handler.postCommit(new CommitEvent(this)); + } + } + + /** + * Discards all changes done to the bound fields. + * <p> + * Only has effect if buffered mode is used. + * + */ + public void discard() { + for (Field<?> f : fieldToPropertyId.keySet()) { + try { + f.discard(); + } catch (Exception e) { + // TODO: handle exception + // What can we do if discard fails other than try to discard all + // other fields? + } + } + } + + /** + * Returns the field that is bound to the given property id + * + * @param propertyId + * The property id to use to lookup the field + * @return The field that is bound to the property id or null if no field is + * bound to that property id + */ + public Field<?> getField(Object propertyId) { + return propertyIdToField.get(propertyId); + } + + /** + * Returns the property id that is bound to the given field + * + * @param field + * The field to use to lookup the property id + * @return The property id that is bound to the field or null if the field + * is not bound to any property id by this FieldBinder + */ + public Object getPropertyId(Field<?> field) { + return fieldToPropertyId.get(field); + } + + /** + * Adds a commit handler. + * <p> + * The commit handler is called before the field values are committed to the + * item ( {@link CommitHandler#preCommit(CommitEvent)}) and after the item + * has been updated ({@link CommitHandler#postCommit(CommitEvent)}). If a + * {@link CommitHandler} throws a CommitException the whole commit is + * aborted and the fields retain their old values. + * + * @param commitHandler + * The commit handler to add + */ + public void addCommitHandler(CommitHandler commitHandler) { + commitHandlers.add(commitHandler); + } + + /** + * Removes the given commit handler. + * + * @see #addCommitHandler(CommitHandler) + * + * @param commitHandler + * The commit handler to remove + */ + public void removeCommitHandler(CommitHandler commitHandler) { + commitHandlers.remove(commitHandler); + } + + /** + * Returns a list of all commit handlers for this {@link FieldGroup}. + * <p> + * Use {@link #addCommitHandler(CommitHandler)} and + * {@link #removeCommitHandler(CommitHandler)} to register or unregister a + * commit handler. + * + * @return A collection of commit handlers + */ + protected Collection<CommitHandler> getCommitHandlers() { + return Collections.unmodifiableCollection(commitHandlers); + } + + /** + * CommitHandlers are used by {@link FieldGroup#commit()} as part of the + * commit transactions. CommitHandlers can perform custom operations as part + * of the commit and cause the commit to be aborted by throwing a + * {@link CommitException}. + */ + public interface CommitHandler extends Serializable { + /** + * Called before changes are committed to the field and the item is + * updated. + * <p> + * Throw a {@link CommitException} to abort the commit. + * + * @param commitEvent + * An event containing information regarding the commit + * @throws CommitException + * if the commit should be aborted + */ + public void preCommit(CommitEvent commitEvent) throws CommitException; + + /** + * Called after changes are committed to the fields and the item is + * updated.. + * <p> + * Throw a {@link CommitException} to abort the commit. + * + * @param commitEvent + * An event containing information regarding the commit + * @throws CommitException + * if the commit should be aborted + */ + public void postCommit(CommitEvent commitEvent) throws CommitException; + } + + /** + * FIXME javadoc + * + */ + public static class CommitEvent implements Serializable { + private FieldGroup fieldBinder; + + private CommitEvent(FieldGroup fieldBinder) { + this.fieldBinder = fieldBinder; + } + + /** + * Returns the field binder that this commit relates to + * + * @return The FieldBinder that is being committed. + */ + public FieldGroup getFieldBinder() { + return fieldBinder; + } + + } + + /** + * Checks the validity of the bound fields. + * <p> + * Call the {@link Field#validate()} for the fields to get the individual + * error messages. + * + * @return true if all bound fields are valid, false otherwise. + */ + public boolean isValid() { + try { + for (Field<?> field : getFields()) { + field.validate(); + } + return true; + } catch (InvalidValueException e) { + return false; + } + } + + /** + * Checks if any bound field has been modified. + * + * @return true if at least on field has been modified, false otherwise + */ + public boolean isModified() { + for (Field<?> field : getFields()) { + if (field.isModified()) { + return true; + } + } + return false; + } + + /** + * Gets the field factory for the {@link FieldGroup}. The field factory is + * only used when {@link FieldGroup} creates a new field. + * + * @return The field factory in use + * + */ + public FieldGroupFieldFactory getFieldFactory() { + return fieldFactory; + } + + /** + * Sets the field factory for the {@link FieldGroup}. The field factory is + * only used when {@link FieldGroup} creates a new field. + * + * @param fieldFactory + * The field factory to use + */ + public void setFieldFactory(FieldGroupFieldFactory fieldFactory) { + this.fieldFactory = fieldFactory; + } + + /** + * Binds member fields found in the given object. + * <p> + * This method processes all (Java) member fields whose type extends + * {@link Field} and that can be mapped to a property id. Property id + * mapping is done based on the field name or on a @{@link PropertyId} + * annotation on the field. All non-null fields for which a property id can + * be determined are bound to the property id. + * </p> + * <p> + * For example: + * + * <pre> + * public class MyForm extends VerticalLayout { + * private TextField firstName = new TextField("First name"); + * @PropertyId("last") + * private TextField lastName = new TextField("Last name"); + * private TextField age = new TextField("Age"); ... } + * + * MyForm myForm = new MyForm(); + * ... + * fieldGroup.bindMemberFields(myForm); + * </pre> + * + * </p> + * This binds the firstName TextField to a "firstName" property in the item, + * lastName TextField to a "last" property and the age TextField to a "age" + * property. + * + * @param objectWithMemberFields + * The object that contains (Java) member fields to bind + * @throws BindException + * If there is a problem binding a field + */ + public void bindMemberFields(Object objectWithMemberFields) + throws BindException { + buildAndBindMemberFields(objectWithMemberFields, false); + } + + /** + * Binds member fields found in the given object and builds member fields + * that have not been initialized. + * <p> + * This method processes all (Java) member fields whose type extends + * {@link Field} and that can be mapped to a property id. Property id + * mapping is done based on the field name or on a @{@link PropertyId} + * annotation on the field. Fields that are not initialized (null) are built + * using the field factory. All non-null fields for which a property id can + * be determined are bound to the property id. + * </p> + * <p> + * For example: + * + * <pre> + * public class MyForm extends VerticalLayout { + * private TextField firstName = new TextField("First name"); + * @PropertyId("last") + * private TextField lastName = new TextField("Last name"); + * private TextField age; + * + * MyForm myForm = new MyForm(); + * ... + * fieldGroup.buildAndBindMemberFields(myForm); + * </pre> + * + * </p> + * <p> + * This binds the firstName TextField to a "firstName" property in the item, + * lastName TextField to a "last" property and builds an age TextField using + * the field factory and then binds it to the "age" property. + * </p> + * + * @param objectWithMemberFields + * The object that contains (Java) member fields to build and + * bind + * @throws BindException + * If there is a problem binding or building a field + */ + public void buildAndBindMemberFields(Object objectWithMemberFields) + throws BindException { + buildAndBindMemberFields(objectWithMemberFields, true); + } + + /** + * Binds member fields found in the given object and optionally builds + * member fields that have not been initialized. + * <p> + * This method processes all (Java) member fields whose type extends + * {@link Field} and that can be mapped to a property id. Property id + * mapping is done based on the field name or on a @{@link PropertyId} + * annotation on the field. Fields that are not initialized (null) are built + * using the field factory is buildFields is true. All non-null fields for + * which a property id can be determined are bound to the property id. + * </p> + * + * @param objectWithMemberFields + * The object that contains (Java) member fields to build and + * bind + * @throws BindException + * If there is a problem binding or building a field + */ + protected void buildAndBindMemberFields(Object objectWithMemberFields, + boolean buildFields) throws BindException { + Class<?> objectClass = objectWithMemberFields.getClass(); + + for (java.lang.reflect.Field memberField : objectClass + .getDeclaredFields()) { + + if (!Field.class.isAssignableFrom(memberField.getType())) { + // Process next field + continue; + } + + PropertyId propertyIdAnnotation = memberField + .getAnnotation(PropertyId.class); + + Class<? extends Field> fieldType = (Class<? extends Field>) memberField + .getType(); + + Object propertyId = null; + if (propertyIdAnnotation != null) { + // @PropertyId(propertyId) always overrides property id + propertyId = propertyIdAnnotation.value(); + } else { + propertyId = memberField.getName(); + } + + // Ensure that the property id exists + Class<?> propertyType; + + try { + propertyType = getPropertyType(propertyId); + } catch (BindException e) { + // Property id was not found, skip this field + continue; + } + + Field<?> field; + try { + // Get the field from the object + field = (Field<?>) ReflectTools.getJavaFieldValue( + objectWithMemberFields, memberField); + } catch (Exception e) { + // If we cannot determine the value, just skip the field and try + // the next one + continue; + } + + if (field == null && buildFields) { + Caption captionAnnotation = memberField + .getAnnotation(Caption.class); + String caption; + if (captionAnnotation != null) { + caption = captionAnnotation.value(); + } else { + caption = DefaultFieldFactory + .createCaptionByPropertyId(propertyId); + } + + // Create the component (Field) + field = build(caption, propertyType, fieldType); + + // Store it in the field + try { + ReflectTools.setJavaFieldValue(objectWithMemberFields, + memberField, field); + } catch (IllegalArgumentException e) { + throw new BindException("Could not assign value to field '" + + memberField.getName() + "'", e); + } catch (IllegalAccessException e) { + throw new BindException("Could not assign value to field '" + + memberField.getName() + "'", e); + } catch (InvocationTargetException e) { + throw new BindException("Could not assign value to field '" + + memberField.getName() + "'", e); + } + } + + if (field != null) { + // Bind it to the property id + bind(field, propertyId); + } + } + } + + public static class CommitException extends Exception { + + public CommitException() { + super(); + // TODO Auto-generated constructor stub + } + + public CommitException(String message, Throwable cause) { + super(message, cause); + // TODO Auto-generated constructor stub + } + + public CommitException(String message) { + super(message); + // TODO Auto-generated constructor stub + } + + public CommitException(Throwable cause) { + super(cause); + // TODO Auto-generated constructor stub + } + + } + + public static class BindException extends RuntimeException { + + public BindException(String message) { + super(message); + } + + public BindException(String message, Throwable t) { + super(message, t); + } + + } + + /** + * Builds a field and binds it to the given property id using the field + * binder. + * + * @param propertyId + * The property id to bind to. Must be present in the field + * finder. + * @throws BindException + * If there is a problem while building or binding + * @return The created and bound field + */ + public Field<?> buildAndBind(Object propertyId) throws BindException { + String caption = DefaultFieldFactory + .createCaptionByPropertyId(propertyId); + return buildAndBind(caption, propertyId); + } + + /** + * Builds a field using the given caption and binds it to the given property + * id using the field binder. + * + * @param caption + * The caption for the field + * @param propertyId + * The property id to bind to. Must be present in the field + * finder. + * @throws BindException + * If there is a problem while building or binding + * @return The created and bound field. Can be any type of {@link Field}. + */ + public Field<?> buildAndBind(String caption, Object propertyId) + throws BindException { + Class<?> type = getPropertyType(propertyId); + return buildAndBind(caption, propertyId, Field.class); + + } + + /** + * Builds a field using the given caption and binds it to the given property + * id using the field binder. Ensures the new field is of the given type. + * + * @param caption + * The caption for the field + * @param propertyId + * The property id to bind to. Must be present in the field + * finder. + * @throws BindException + * If the field could not be created + * @return The created and bound field. Can be any type of {@link Field}. + */ + + public <T extends Field> T buildAndBind(String caption, Object propertyId, + Class<T> fieldType) throws BindException { + Class<?> type = getPropertyType(propertyId); + + T field = build(caption, type, fieldType); + bind(field, propertyId); + + return field; + } + + /** + * Creates a field based on the given data type. + * <p> + * The data type is the type that we want to edit using the field. The field + * type is the type of field we want to create, can be {@link Field} if any + * Field is good. + * </p> + * + * @param caption + * The caption for the new field + * @param dataType + * The data model type that we want to edit using the field + * @param fieldType + * The type of field that we want to create + * @return A Field capable of editing the given type + * @throws BindException + * If the field could not be created + */ + protected <T extends Field> T build(String caption, Class<?> dataType, + Class<T> fieldType) throws BindException { + T field = getFieldFactory().createField(dataType, fieldType); + if (field == null) { + throw new BindException("Unable to build a field of type " + + fieldType.getName() + " for editing " + + dataType.getName()); + } + + field.setCaption(caption); + return field; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java b/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java new file mode 100644 index 0000000000..80c012cbdc --- /dev/null +++ b/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java @@ -0,0 +1,31 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.fieldgroup; + +import java.io.Serializable; + +import com.vaadin.ui.Field; + +/** + * Factory interface for creating new Field-instances based on the data type + * that should be edited. + * + * @author Vaadin Ltd. + * @version @version@ + * @since 7.0 + */ +public interface FieldGroupFieldFactory extends Serializable { + /** + * Creates a field based on the data type that we want to edit + * + * @param dataType + * The type that we want to edit using the field + * @param fieldType + * The type of field we want to create. If set to {@link Field} + * then any type of field is accepted + * @return A field that can be assigned to the given fieldType and that is + * capable of editing the given type of data + */ + <T extends Field> T createField(Class<?> dataType, Class<T> fieldType); +} diff --git a/src/com/vaadin/data/fieldgroup/PropertyId.java b/src/com/vaadin/data/fieldgroup/PropertyId.java new file mode 100644 index 0000000000..268047401d --- /dev/null +++ b/src/com/vaadin/data/fieldgroup/PropertyId.java @@ -0,0 +1,15 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.fieldgroup; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface PropertyId { + String value(); +} diff --git a/src/com/vaadin/data/util/AbstractBeanContainer.java b/src/com/vaadin/data/util/AbstractBeanContainer.java index 6260e05518..bed3ca0450 100644 --- a/src/com/vaadin/data/util/AbstractBeanContainer.java +++ b/src/com/vaadin/data/util/AbstractBeanContainer.java @@ -104,8 +104,9 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends + " not found"); } try { - Property property = pd.createProperty(bean); - return (IDTYPE) property.getValue(); + Property<IDTYPE> property = (Property<IDTYPE>) pd + .createProperty(bean); + return property.getValue(); } catch (MethodException e) { throw new IllegalArgumentException(e); } @@ -256,7 +257,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends * @see com.vaadin.data.Container#getContainerProperty(java.lang.Object, * java.lang.Object) */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { Item item = getItem(itemId); if (item == null) { return null; @@ -371,7 +372,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends * The id of the property */ private void addValueChangeListener(Item item, Object propertyId) { - Property property = item.getItemProperty(propertyId); + Property<?> property = item.getItemProperty(propertyId); if (property instanceof ValueChangeNotifier) { // avoid multiple notifications for the same property if // multiple filters are in use @@ -390,7 +391,7 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends * The id of the property */ private void removeValueChangeListener(Item item, Object propertyId) { - Property property = item.getItemProperty(propertyId); + Property<?> property = item.getItemProperty(propertyId); if (property instanceof ValueChangeNotifier) { ((ValueChangeNotifier) property).removeListener(this); } @@ -754,9 +755,9 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends } model.put(propertyId, propertyDescriptor); - for (BeanItem item : itemIdToItem.values()) { - item.addItemProperty(propertyId, propertyDescriptor - .createProperty((BEANTYPE) item.getBean())); + for (BeanItem<BEANTYPE> item : itemIdToItem.values()) { + item.addItemProperty(propertyId, + propertyDescriptor.createProperty(item.getBean())); } // Sends a change event @@ -775,7 +776,6 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends * @see NestedMethodProperty * * @param propertyId - * @param propertyType * @return true if the property was added */ public boolean addNestedContainerProperty(String propertyId) { @@ -783,6 +783,41 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends propertyId, type)); } + /** + * Adds a nested container properties for all sub-properties of a named + * property to the container. The named property itself is removed from the + * model as its subproperties are added. + * + * All intermediate getters must exist and must return non-null values when + * the property value is accessed. + * + * @see NestedMethodProperty + * @see #addNestedContainerProperty(String) + * + * @param propertyId + */ + @SuppressWarnings("unchecked") + public void addNestedContainerBean(String propertyId) { + Class<?> propertyType = getType(propertyId); + LinkedHashMap<String, VaadinPropertyDescriptor<Object>> pds = BeanItem + .getPropertyDescriptors((Class<Object>) propertyType); + for (String subPropertyId : pds.keySet()) { + String qualifiedPropertyId = propertyId + "." + subPropertyId; + NestedPropertyDescriptor<BEANTYPE> pd = new NestedPropertyDescriptor<BEANTYPE>( + qualifiedPropertyId, (Class<BEANTYPE>) type); + model.put(qualifiedPropertyId, pd); + model.remove(propertyId); + for (BeanItem<BEANTYPE> item : itemIdToItem.values()) { + item.addItemProperty(propertyId, + pd.createProperty(item.getBean())); + item.removeItemProperty(propertyId); + } + } + + // Sends a change event + fireContainerPropertySetChange(); + } + @Override public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException { diff --git a/src/com/vaadin/data/util/AbstractProperty.java b/src/com/vaadin/data/util/AbstractProperty.java index f9c6faacf1..3b6db3807e 100644 --- a/src/com/vaadin/data/util/AbstractProperty.java +++ b/src/com/vaadin/data/util/AbstractProperty.java @@ -17,7 +17,7 @@ import com.vaadin.data.Property; * * @since 6.6 */ -public abstract class AbstractProperty implements Property, +public abstract class AbstractProperty<T> implements Property<T>, Property.ValueChangeNotifier, Property.ReadOnlyStatusChangeNotifier { /** @@ -56,18 +56,17 @@ public abstract class AbstractProperty implements Property, /** * Returns the value of the <code>Property</code> in human readable textual - * format. The return value should be assignable to the - * <code>setValue</code> method if the Property is not in read-only mode. + * format. * * @return String representation of the value stored in the Property + * @deprecated use {@link #getValue()} instead and possibly toString on that */ + @Deprecated @Override public String toString() { - final Object value = getValue(); - if (value == null) { - return null; - } - return value.toString(); + throw new UnsupportedOperationException( + "Use Property.getValue() instead of " + getClass() + + ".toString()"); } /* Events */ @@ -76,8 +75,8 @@ public abstract class AbstractProperty implements Property, * An <code>Event</code> object specifying the Property whose read-only * status has been changed. */ - protected class ReadOnlyStatusChangeEvent extends java.util.EventObject - implements Property.ReadOnlyStatusChangeEvent { + protected static class ReadOnlyStatusChangeEvent extends + java.util.EventObject implements Property.ReadOnlyStatusChangeEvent { /** * Constructs a new read-only status change event for this object. @@ -144,8 +143,8 @@ public abstract class AbstractProperty implements Property, * An <code>Event</code> object specifying the Property whose value has been * changed. */ - private class ValueChangeEvent extends java.util.EventObject implements - Property.ValueChangeEvent { + private static class ValueChangeEvent extends java.util.EventObject + implements Property.ValueChangeEvent { /** * Constructs a new value change event for this object. diff --git a/src/com/vaadin/data/util/BeanItem.java b/src/com/vaadin/data/util/BeanItem.java index ed59baa9f8..94439471f5 100644 --- a/src/com/vaadin/data/util/BeanItem.java +++ b/src/com/vaadin/data/util/BeanItem.java @@ -12,9 +12,11 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** * A wrapper class for adding the Item interface to any Java Bean. @@ -162,7 +164,7 @@ public class BeanItem<BT> extends PropertysetItem { final Method getMethod = pd.getReadMethod(); if ((getMethod != null) && getMethod.getDeclaringClass() != Object.class) { - VaadinPropertyDescriptor<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor( + VaadinPropertyDescriptor<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor<BT>( pd.getName(), pd.getPropertyType(), pd.getReadMethod(), pd.getWriteMethod()); pdMap.put(pd.getName(), vaadinPropertyDescriptor); @@ -213,6 +215,49 @@ public class BeanItem<BT> extends PropertysetItem { } /** + * Expands nested bean properties by replacing a top-level property with + * some or all of its sub-properties. The expansion is not recursive. + * + * @param propertyId + * property id for the property whose sub-properties are to be + * expanded, + * @param subPropertyIds + * sub-properties to expand, all sub-properties are expanded if + * not specified + */ + public void expandProperty(String propertyId, String... subPropertyIds) { + Set<String> subPropertySet = new HashSet<String>( + Arrays.asList(subPropertyIds)); + + if (0 == subPropertyIds.length) { + // Enumerate all sub-properties + Class<?> propertyType = getItemProperty(propertyId).getType(); + Map<String, ?> pds = getPropertyDescriptors(propertyType); + subPropertySet.addAll(pds.keySet()); + } + + for (String subproperty : subPropertySet) { + String qualifiedPropertyId = propertyId + "." + subproperty; + addNestedProperty(qualifiedPropertyId); + } + + removeItemProperty(propertyId); + } + + /** + * Adds a nested property to the item. + * + * @param nestedPropertyId + * property id to add. This property must not exist in the item + * already and must of of form "field1.field2" where field2 is a + * field in the object referenced to by field1 + */ + public void addNestedProperty(String nestedPropertyId) { + addItemProperty(nestedPropertyId, new NestedMethodProperty<Object>( + getBean(), nestedPropertyId)); + } + + /** * Gets the underlying JavaBean object. * * @return the bean object. diff --git a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java index e5972f697e..91950f5d4f 100644 --- a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java +++ b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java @@ -641,7 +641,7 @@ public class ContainerHierarchicalWrapper implements Container.Hierarchical, * Container Don't add a JavaDoc comment here, we use the default * documentation from implemented interface. */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { return container.getContainerProperty(itemId, propertyId); } diff --git a/src/com/vaadin/data/util/ContainerOrderedWrapper.java b/src/com/vaadin/data/util/ContainerOrderedWrapper.java index 1600699362..f333edecf4 100644 --- a/src/com/vaadin/data/util/ContainerOrderedWrapper.java +++ b/src/com/vaadin/data/util/ContainerOrderedWrapper.java @@ -437,7 +437,7 @@ public class ContainerOrderedWrapper implements Container.Ordered, * Container Don't add a JavaDoc comment here, we use the default * documentation from implemented interface. */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { return container.getContainerProperty(itemId, propertyId); } diff --git a/src/com/vaadin/data/util/DefaultItemSorter.java b/src/com/vaadin/data/util/DefaultItemSorter.java index 9b834f4a2e..47db5d7507 100644 --- a/src/com/vaadin/data/util/DefaultItemSorter.java +++ b/src/com/vaadin/data/util/DefaultItemSorter.java @@ -122,8 +122,8 @@ public class DefaultItemSorter implements ItemSorter { Item item1, Item item2) { // Get the properties to compare - final Property property1 = item1.getItemProperty(propertyId); - final Property property2 = item2.getItemProperty(propertyId); + final Property<?> property1 = item1.getItemProperty(propertyId); + final Property<?> property2 = item2.getItemProperty(propertyId); // Get the values to compare final Object value1 = (property1 == null) ? null : property1.getValue(); diff --git a/src/com/vaadin/data/util/FilesystemContainer.java b/src/com/vaadin/data/util/FilesystemContainer.java index 8e9873334b..7100286712 100644 --- a/src/com/vaadin/data/util/FilesystemContainer.java +++ b/src/com/vaadin/data/util/FilesystemContainer.java @@ -459,7 +459,7 @@ public class FilesystemContainer implements Container.Hierarchical { * the property's ID. * @return the requested property's value, or <code>null</code> */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { if (!(itemId instanceof File)) { return null; @@ -609,7 +609,7 @@ public class FilesystemContainer implements Container.Hierarchical { * Gets the specified property of this file. Don't add a JavaDoc comment * here, we use the default documentation from implemented interface. */ - public Property getItemProperty(Object id) { + public Property<?> getItemProperty(Object id) { return getContainerProperty(file, id); } diff --git a/src/com/vaadin/ui/treetable/HierarchicalContainerOrderedWrapper.java b/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapper.java index f826c59bf7..b7eac3e378 100644 --- a/src/com/vaadin/ui/treetable/HierarchicalContainerOrderedWrapper.java +++ b/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapper.java @@ -1,18 +1,20 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.ui.treetable; +package com.vaadin.data.util; import java.util.Collection; import com.vaadin.data.Container.Hierarchical; -import com.vaadin.data.util.ContainerOrderedWrapper; -@SuppressWarnings({ "serial", "unchecked" }) /** - * Helper for TreeTable. Does the same thing as ContainerOrderedWrapper - * to fit into table but retains Hierarchical feature. + * A wrapper class for adding external ordering to containers not implementing + * the {@link com.vaadin.data.Container.Ordered} interface while retaining + * {@link Hierarchical} features. + * + * @see ContainerOrderedWrapper */ +@SuppressWarnings({ "serial" }) public class HierarchicalContainerOrderedWrapper extends ContainerOrderedWrapper implements Hierarchical { diff --git a/src/com/vaadin/data/util/IndexedContainer.java b/src/com/vaadin/data/util/IndexedContainer.java index 9728c79864..1e0a2fae1a 100644 --- a/src/com/vaadin/data/util/IndexedContainer.java +++ b/src/com/vaadin/data/util/IndexedContainer.java @@ -5,7 +5,6 @@ package com.vaadin.data.util; import java.io.Serializable; -import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -76,7 +75,7 @@ public class IndexedContainer extends /** * Set of properties that are read-only. */ - private HashSet<Property> readOnlyProperties = new HashSet<Property>(); + private HashSet<Property<?>> readOnlyProperties = new HashSet<Property<?>>(); /** * List of all Property value change event listeners listening all the @@ -150,7 +149,7 @@ public class IndexedContainer extends * @see com.vaadin.data.Container#getContainerProperty(java.lang.Object, * java.lang.Object) */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { if (!containsId(itemId)) { return null; } @@ -425,7 +424,7 @@ public class IndexedContainer extends * @VERSION@ * @since 3.0 */ - public class ItemSetChangeEvent extends BaseItemSetChangeEvent { + public static class ItemSetChangeEvent extends BaseItemSetChangeEvent { private final int addedItemIndex; @@ -455,7 +454,7 @@ public class IndexedContainer extends * @VERSION@ * @since 3.0 */ - private class PropertyValueChangeEvent extends EventObject implements + private static class PropertyValueChangeEvent extends EventObject implements Property.ValueChangeEvent, Serializable { private PropertyValueChangeEvent(Property source) { @@ -680,7 +679,7 @@ public class IndexedContainer extends * * @see com.vaadin.data.Item#getItemProperty(java.lang.Object) */ - public Property getItemProperty(Object id) { + public Property<?> getItemProperty(Object id) { return new IndexedContainerProperty(itemId, id); } @@ -691,8 +690,8 @@ public class IndexedContainer extends /** * Gets the <code>String</code> representation of the contents of the * Item. The format of the string is a space separated catenation of the - * <code>String</code> representations of the Properties contained by - * the Item. + * <code>String</code> representations of the values of the Properties + * contained by the Item. * * @return <code>String</code> representation of the Item contents */ @@ -702,7 +701,7 @@ public class IndexedContainer extends for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) { final Object propertyId = i.next(); - retValue += getItemProperty(propertyId).toString(); + retValue += getItemProperty(propertyId).getValue(); if (i.hasNext()) { retValue += " "; } @@ -786,7 +785,7 @@ public class IndexedContainer extends * @VERSION@ * @since 3.0 */ - private class IndexedContainerProperty implements Property, + private class IndexedContainerProperty implements Property<Object>, Property.ValueChangeNotifier { /** @@ -865,8 +864,7 @@ public class IndexedContainer extends * * @see com.vaadin.data.Property#setValue(java.lang.Object) */ - public void setValue(Object newValue) - throws Property.ReadOnlyException, Property.ConversionException { + public void setValue(Object newValue) throws Property.ReadOnlyException { // Gets the Property set final Map<Object, Object> propertySet = items.get(itemId); @@ -877,22 +875,8 @@ public class IndexedContainer extends } else if (getType().isAssignableFrom(newValue.getClass())) { propertySet.put(propertyId, newValue); } else { - try { - - // Gets the string constructor - final Constructor<?> constr = getType().getConstructor( - new Class[] { String.class }); - - // Creates new object from the string - propertySet.put(propertyId, constr - .newInstance(new Object[] { newValue.toString() })); - - } catch (final java.lang.Exception e) { - throw new Property.ConversionException( - "Conversion for value '" + newValue + "' of class " - + newValue.getClass().getName() + " to " - + getType().getName() + " failed", e); - } + throw new IllegalArgumentException("Value is of invalid type, " + + getType().getName() + " expected"); } // update the container filtering if this property is being filtered @@ -910,14 +894,14 @@ public class IndexedContainer extends * * @return <code>String</code> representation of the value stored in the * Property + * @deprecated use {@link #getValue()} instead and possibly toString on + * that */ + @Deprecated @Override public String toString() { - final Object value = getValue(); - if (value == null) { - return null; - } - return value.toString(); + throw new UnsupportedOperationException( + "Use Property.getValue() instead of IndexedContainerProperty.toString()"); } /** @@ -1038,7 +1022,7 @@ public class IndexedContainer extends getPropertySetChangeListeners()) : null); nc.propertyValueChangeListeners = propertyValueChangeListeners != null ? (LinkedList<Property.ValueChangeListener>) propertyValueChangeListeners .clone() : null; - nc.readOnlyProperties = readOnlyProperties != null ? (HashSet<Property>) readOnlyProperties + nc.readOnlyProperties = readOnlyProperties != null ? (HashSet<Property<?>>) readOnlyProperties .clone() : null; nc.singlePropertyValueChangeListeners = singlePropertyValueChangeListeners != null ? (Hashtable<Object, Map<Object, List<Property.ValueChangeListener>>>) singlePropertyValueChangeListeners .clone() : null; @@ -1097,4 +1081,4 @@ public class IndexedContainer extends removeFilter(filter); } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/data/util/MethodProperty.java b/src/com/vaadin/data/util/MethodProperty.java index ff258d3e0f..4fc5531320 100644 --- a/src/com/vaadin/data/util/MethodProperty.java +++ b/src/com/vaadin/data/util/MethodProperty.java @@ -5,7 +5,6 @@ package com.vaadin.data.util; import java.io.IOException; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.logging.Level; @@ -47,7 +46,7 @@ import com.vaadin.util.SerializerHelper; * @since 3.0 */ @SuppressWarnings("serial") -public class MethodProperty<T> extends AbstractProperty { +public class MethodProperty<T> extends AbstractProperty<T> { private static final Logger logger = Logger.getLogger(MethodProperty.class .getName()); @@ -170,7 +169,7 @@ public class MethodProperty<T> extends AbstractProperty { @SuppressWarnings("unchecked") public MethodProperty(Object instance, String beanPropertyName) { - final Class beanClass = instance.getClass(); + final Class<?> beanClass = instance.getClass(); // Assure that the first letter is upper cased (it is a common // mistake to write firstName, not FirstName). @@ -349,7 +348,7 @@ public class MethodProperty<T> extends AbstractProperty { } // Tests the parameter types - final Class[] c = m[i].getParameterTypes(); + final Class<?>[] c = m[i].getParameterTypes(); if (c.length != getArgs.length) { // not the right amount of parameters, try next method @@ -398,7 +397,7 @@ public class MethodProperty<T> extends AbstractProperty { } // Checks parameter compatibility - final Class[] c = m[i].getParameterTypes(); + final Class<?>[] c = m[i].getParameterTypes(); if (c.length != setArgs.length) { // not the right amount of parameters, try next method @@ -474,7 +473,9 @@ public class MethodProperty<T> extends AbstractProperty { * {@link #setValue(Object newValue)} is called. */ @SuppressWarnings("unchecked") - public MethodProperty(Class type, Object instance, Method getMethod, + // cannot use "Class<? extends T>" because of automatic primitive type + // conversions + public MethodProperty(Class<?> type, Object instance, Method getMethod, Method setMethod, Object[] getArgs, Object[] setArgs, int setArgumentIndex) { @@ -495,13 +496,13 @@ public class MethodProperty<T> extends AbstractProperty { } // Gets the return type from get method - type = convertPrimitiveType(type); + Class<? extends T> convertedType = (Class<? extends T>) convertPrimitiveType(type); this.getMethod = getMethod; this.setMethod = setMethod; setArguments(getArgs, setArgs, setArgumentIndex); this.instance = instance; - this.type = type; + this.type = convertedType; } /** @@ -569,8 +570,7 @@ public class MethodProperty<T> extends AbstractProperty { * * @return type of the Property */ - @SuppressWarnings("unchecked") - public final Class getType() { + public final Class<? extends T> getType() { return type; } @@ -593,9 +593,9 @@ public class MethodProperty<T> extends AbstractProperty { * * @return the value of the Property */ - public Object getValue() { + public T getValue() { try { - return getMethod.invoke(instance, getArgs); + return (T) getMethod.invoke(instance, getArgs); } catch (final Throwable e) { throw new MethodException(this, e); } @@ -629,61 +629,33 @@ public class MethodProperty<T> extends AbstractProperty { } /** - * Sets the value of the property. This method supports setting from - * <code>String</code>s if either <code>String</code> is directly assignable - * to property type, or the type class contains a string constructor. + * Sets the value of the property. + * + * Note that since Vaadin 7, no conversions are performed and the value must + * be of the correct type. * * @param newValue * the New value of the property. * @throws <code>Property.ReadOnlyException</code> if the object is in * read-only mode. - * @throws <code>Property.ConversionException</code> if - * <code>newValue</code> can't be converted into the Property's - * native type directly or through <code>String</code>. * @see #invokeSetMethod(Object) */ @SuppressWarnings("unchecked") - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException { + public void setValue(Object newValue) throws Property.ReadOnlyException { // Checks the mode if (isReadOnly()) { throw new Property.ReadOnlyException(); } - Object value = convertValue(newValue, type); - - invokeSetMethod(value); - fireValueChange(); - } - - /** - * Convert a value to the given type, using a constructor of the type that - * takes a single String parameter (toString() for the value) if necessary. - * - * @param value - * to convert - * @param type - * type into which the value should be converted - * @return converted value - */ - static Object convertValue(Object value, Class<?> type) { - if (null == value || type.isAssignableFrom(value.getClass())) { - return value; + // Checks the type of the value + if (newValue != null && !type.isAssignableFrom(newValue.getClass())) { + throw new IllegalArgumentException( + "Invalid value type for ObjectProperty."); } - // convert using a string constructor - try { - // Gets the string constructor - final Constructor constr = type - .getConstructor(new Class[] { String.class }); - - // Create a new object from the string - return constr.newInstance(new Object[] { value.toString() }); - - } catch (final java.lang.Exception e) { - throw new Property.ConversionException(e); - } + invokeSetMethod((T) newValue); + fireValueChange(); } /** @@ -692,7 +664,7 @@ public class MethodProperty<T> extends AbstractProperty { * * @param value */ - protected void invokeSetMethod(Object value) { + protected void invokeSetMethod(T value) { try { // Construct a temporary argument array only if needed diff --git a/src/com/vaadin/data/util/MethodPropertyDescriptor.java b/src/com/vaadin/data/util/MethodPropertyDescriptor.java index f0c879766b..10faa7a0f3 100644 --- a/src/com/vaadin/data/util/MethodPropertyDescriptor.java +++ b/src/com/vaadin/data/util/MethodPropertyDescriptor.java @@ -123,9 +123,9 @@ public class MethodPropertyDescriptor<BT> implements return propertyType; } - public Property createProperty(Object bean) { + public Property<?> createProperty(Object bean) { return new MethodProperty<Object>(propertyType, bean, readMethod, writeMethod); } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/data/util/NestedMethodProperty.java b/src/com/vaadin/data/util/NestedMethodProperty.java index 8f5a17af16..d7b0f44912 100644 --- a/src/com/vaadin/data/util/NestedMethodProperty.java +++ b/src/com/vaadin/data/util/NestedMethodProperty.java @@ -26,7 +26,7 @@ import com.vaadin.data.util.MethodProperty.MethodException; * * @since 6.6 */ -public class NestedMethodProperty extends AbstractProperty { +public class NestedMethodProperty<T> extends AbstractProperty<T> { // needed for de-serialization private String propertyName; @@ -43,7 +43,7 @@ public class NestedMethodProperty extends AbstractProperty { */ private Object instance; - private Class<?> type; + private Class<? extends T> type; /* Special serialization to handle method references */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { @@ -158,13 +158,14 @@ public class NestedMethodProperty extends AbstractProperty { } catch (final NoSuchMethodException skipped) { } - this.type = MethodProperty.convertPrimitiveType(type); + this.type = (Class<? extends T>) MethodProperty + .convertPrimitiveType(type); this.propertyName = propertyName; this.getMethods = getMethods; this.setMethod = setMethod; } - public Class<?> getType() { + public Class<? extends T> getType() { return type; } @@ -179,42 +180,41 @@ public class NestedMethodProperty extends AbstractProperty { * * @return the value of the Property */ - public Object getValue() { + public T getValue() { try { Object object = instance; for (Method m : getMethods) { object = m.invoke(object); } - return object; + return (T) object; } catch (final Throwable e) { throw new MethodException(this, e); } } /** - * Sets the value of the property. This method supports setting from - * <code>String</code>s if either <code>String</code> is directly assignable - * to property type, or the type class contains a string constructor. + * Sets the value of the property. The new value must be assignable to the + * type of this property. * * @param newValue * the New value of the property. * @throws <code>Property.ReadOnlyException</code> if the object is in * read-only mode. - * @throws <code>Property.ConversionException</code> if - * <code>newValue</code> can't be converted into the Property's - * native type directly or through <code>String</code>. * @see #invokeSetMethod(Object) */ - public void setValue(Object newValue) throws ReadOnlyException, - ConversionException { + public void setValue(Object newValue) throws ReadOnlyException { // Checks the mode if (isReadOnly()) { throw new Property.ReadOnlyException(); } - Object value = MethodProperty.convertValue(newValue, type); + // Checks the type of the value + if (newValue != null && !type.isAssignableFrom(newValue.getClass())) { + throw new IllegalArgumentException( + "Invalid value type for NestedMethodProperty."); + } - invokeSetMethod(value); + invokeSetMethod((T) newValue); fireValueChange(); } @@ -224,7 +224,7 @@ public class NestedMethodProperty extends AbstractProperty { * * @param value */ - protected void invokeSetMethod(Object value) { + protected void invokeSetMethod(T value) { try { Object object = instance; for (int i = 0; i < getMethods.size() - 1; i++) { diff --git a/src/com/vaadin/data/util/NestedPropertyDescriptor.java b/src/com/vaadin/data/util/NestedPropertyDescriptor.java index abdb9e0cd3..6404f6361d 100644 --- a/src/com/vaadin/data/util/NestedPropertyDescriptor.java +++ b/src/com/vaadin/data/util/NestedPropertyDescriptor.java @@ -37,7 +37,8 @@ public class NestedPropertyDescriptor<BT> implements public NestedPropertyDescriptor(String name, Class<BT> beanType) throws IllegalArgumentException { this.name = name; - NestedMethodProperty property = new NestedMethodProperty(beanType, name); + NestedMethodProperty<?> property = new NestedMethodProperty<Object>( + beanType, name); this.propertyType = property.getType(); } @@ -49,8 +50,8 @@ public class NestedPropertyDescriptor<BT> implements return propertyType; } - public Property createProperty(BT bean) { - return new NestedMethodProperty(bean, name); + public Property<?> createProperty(BT bean) { + return new NestedMethodProperty<Object>(bean, name); } } diff --git a/src/com/vaadin/data/util/ObjectProperty.java b/src/com/vaadin/data/util/ObjectProperty.java index 4319ea7716..9c60b9146e 100644 --- a/src/com/vaadin/data/util/ObjectProperty.java +++ b/src/com/vaadin/data/util/ObjectProperty.java @@ -4,8 +4,6 @@ package com.vaadin.data.util; -import java.lang.reflect.Constructor; - import com.vaadin.data.Property; /** @@ -19,7 +17,7 @@ import com.vaadin.data.Property; * @since 3.0 */ @SuppressWarnings("serial") -public class ObjectProperty<T> extends AbstractProperty { +public class ObjectProperty<T> extends AbstractProperty<T> { /** * The value contained by the Property. @@ -48,9 +46,8 @@ public class ObjectProperty<T> extends AbstractProperty { /** * Creates a new instance of ObjectProperty with the given value and type. * - * Any value of type Object is accepted because, if the type class contains - * a string constructor, the toString of the value is used to create the new - * value. See {@link #setValue(Object)}. + * Since Vaadin 7, only values of the correct type are accepted, and no + * automatic conversions are performed. * * @param value * the Initial value of the Property. @@ -58,7 +55,7 @@ public class ObjectProperty<T> extends AbstractProperty { * the type of the value. The value must be assignable to given * type. */ - public ObjectProperty(Object value, Class<T> type) { + public ObjectProperty(T value, Class<T> type) { // Set the values this.type = type; @@ -69,7 +66,7 @@ public class ObjectProperty<T> extends AbstractProperty { * Creates a new instance of ObjectProperty with the given value, type and * read-only mode status. * - * Any value of type Object is accepted, see + * Since Vaadin 7, only the correct type of values is accepted, see * {@link #ObjectProperty(Object, Class)}. * * @param value @@ -80,7 +77,7 @@ public class ObjectProperty<T> extends AbstractProperty { * @param readOnly * Sets the read-only mode. */ - public ObjectProperty(Object value, Class<T> type, boolean readOnly) { + public ObjectProperty(T value, Class<T> type, boolean readOnly) { this(value, type); setReadOnly(readOnly); } @@ -108,49 +105,34 @@ public class ObjectProperty<T> extends AbstractProperty { } /** - * Sets the value of the property. This method supports setting from - * <code>String</code> if either <code>String</code> is directly assignable - * to property type, or the type class contains a string constructor. + * Sets the value of the property. + * + * Note that since Vaadin 7, no conversions are performed and the value must + * be of the correct type. * * @param newValue * the New value of the property. * @throws <code>Property.ReadOnlyException</code> if the object is in * read-only mode - * @throws <code>Property.ConversionException</code> if the newValue can't - * be converted into the Property's native type directly or through - * <code>String</code> */ - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException { + @SuppressWarnings("unchecked") + public void setValue(Object newValue) throws Property.ReadOnlyException { // Checks the mode if (isReadOnly()) { throw new Property.ReadOnlyException(); } - // Tries to assign the compatible value directly - if (newValue == null || type.isAssignableFrom(newValue.getClass())) { - @SuppressWarnings("unchecked") - // the cast is safe after an isAssignableFrom check - T value = (T) newValue; - this.value = value; - } else { - try { - - // Gets the string constructor - final Constructor<T> constr = getType().getConstructor( - new Class[] { String.class }); - - // Creates new object from the string - value = constr - .newInstance(new Object[] { newValue.toString() }); - - } catch (final java.lang.Exception e) { - throw new Property.ConversionException(e); - } + // Checks the type of the value + if (newValue != null && !type.isAssignableFrom(newValue.getClass())) { + throw new IllegalArgumentException("Invalid value type " + + newValue.getClass().getName() + + " for ObjectProperty of type " + type.getName() + "."); } + // the cast is safe after an isAssignableFrom check + this.value = (T) newValue; + fireValueChange(); } - } diff --git a/src/com/vaadin/data/util/PropertyFormatter.java b/src/com/vaadin/data/util/PropertyFormatter.java index 1491f9a25e..a63973535b 100644 --- a/src/com/vaadin/data/util/PropertyFormatter.java +++ b/src/com/vaadin/data/util/PropertyFormatter.java @@ -4,6 +4,7 @@ package com.vaadin.data.util; import com.vaadin.data.Property; +import com.vaadin.data.util.converter.Converter; /** * Formatting proxy for a {@link Property}. @@ -29,16 +30,22 @@ import com.vaadin.data.Property; * standard "1.0" notation with more zeroes. * </p> * + * @param T + * type of the underlying property (a PropertyFormatter is always a + * Property<String>) + * + * @deprecated Since 7.0 replaced by {@link Converter} * @author Vaadin Ltd. * @since 5.3.0 */ @SuppressWarnings("serial") -public abstract class PropertyFormatter extends AbstractProperty implements - Property.Viewer, Property.ValueChangeListener, +@Deprecated +public abstract class PropertyFormatter<T> extends AbstractProperty<String> + implements Property.Viewer, Property.ValueChangeListener, Property.ReadOnlyStatusChangeListener { /** Datasource that stores the actual value. */ - Property dataSource; + Property<T> dataSource; /** * Construct a new {@code PropertyFormatter} that is not connected to any @@ -57,7 +64,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements * @param propertyDataSource * to connect this property to. */ - public PropertyFormatter(Property propertyDataSource) { + public PropertyFormatter(Property<T> propertyDataSource) { setPropertyDataSource(propertyDataSource); } @@ -68,7 +75,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements * @return the current data source as a Property, or <code>null</code> if * none defined. */ - public Property getPropertyDataSource() { + public Property<T> getPropertyDataSource() { return dataSource; } @@ -99,7 +106,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements .removeListener(this); } readOnly = isReadOnly(); - prevValue = toString(); + prevValue = getValue(); } dataSource = newDataSource; @@ -117,7 +124,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements if (isReadOnly() != readOnly) { fireReadOnlyStatusChange(); } - String newVal = toString(); + String newVal = getValue(); if ((prevValue == null && newVal != null) || (prevValue != null && !prevValue.equals(newVal))) { fireValueChange(); @@ -125,7 +132,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements } /* Documented in the interface */ - public Class getType() { + public Class<String> getType() { return String.class; } @@ -135,22 +142,8 @@ public abstract class PropertyFormatter extends AbstractProperty implements * @return If the datasource returns null, this is null. Otherwise this is * String given by format(). */ - public Object getValue() { - return toString(); - } - - /** - * Get the formatted value. - * - * @return If the datasource returns null, this is null. Otherwise this is - * String given by format(). - */ - @Override - public String toString() { - if (dataSource == null) { - return null; - } - Object value = dataSource.getValue(); + public String getValue() { + T value = dataSource == null ? null : dataSource.getValue(); if (value == null) { return null; } @@ -173,7 +166,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements * datasource. * @return */ - abstract public String format(Object value); + abstract public String format(T value); /** * Parse string and convert it to format compatible with datasource. @@ -187,7 +180,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements * Any type of exception can be thrown to indicate that the * conversion was not succesful. */ - abstract public Object parse(String formattedValue) throws Exception; + abstract public T parse(String formattedValue) throws Exception; /** * Sets the Property's read-only mode to the specified status. @@ -202,8 +195,7 @@ public abstract class PropertyFormatter extends AbstractProperty implements } } - public void setValue(Object newValue) throws ReadOnlyException, - ConversionException { + public void setValue(Object newValue) throws ReadOnlyException { if (dataSource == null) { return; } @@ -215,13 +207,11 @@ public abstract class PropertyFormatter extends AbstractProperty implements } else { try { dataSource.setValue(parse(newValue.toString())); - if (!newValue.equals(toString())) { + if (!newValue.equals(getValue())) { fireValueChange(); } - } catch (ConversionException e) { - throw e; } catch (Exception e) { - throw new ConversionException(e); + throw new IllegalArgumentException("Could not parse value", e); } } } diff --git a/src/com/vaadin/data/util/PropertysetItem.java b/src/com/vaadin/data/util/PropertysetItem.java index 04a7c66257..3270fa31f9 100644 --- a/src/com/vaadin/data/util/PropertysetItem.java +++ b/src/com/vaadin/data/util/PropertysetItem.java @@ -34,7 +34,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, /** * Mapping from property id to property. */ - private HashMap<Object, Property> map = new HashMap<Object, Property>(); + private HashMap<Object, Property<?>> map = new HashMap<Object, Property<?>>(); /** * List of all property ids to maintain the order. @@ -57,7 +57,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, * the identifier of the Property to get. * @return the Property with the given ID or <code>null</code> */ - public Property getItemProperty(Object id) { + public Property<?> getItemProperty(Object id) { return map.get(id); } @@ -143,7 +143,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, for (final Iterator<?> i = getItemPropertyIds().iterator(); i.hasNext();) { final Object propertyId = i.next(); - retValue += getItemProperty(propertyId).toString(); + retValue += getItemProperty(propertyId).getValue(); if (i.hasNext()) { retValue += " "; } @@ -163,7 +163,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, * @VERSION@ * @since 3.0 */ - private class PropertySetChangeEvent extends EventObject implements + private static class PropertySetChangeEvent extends EventObject implements Item.PropertySetChangeEvent { private PropertySetChangeEvent(Item source) { @@ -262,7 +262,7 @@ public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, npsi.list = list != null ? (LinkedList<Object>) list.clone() : null; npsi.propertySetChangeListeners = propertySetChangeListeners != null ? (LinkedList<PropertySetChangeListener>) propertySetChangeListeners .clone() : null; - npsi.map = (HashMap<Object, Property>) map.clone(); + npsi.map = (HashMap<Object, Property<?>>) map.clone(); return npsi; } diff --git a/src/com/vaadin/data/util/QueryContainer.java b/src/com/vaadin/data/util/QueryContainer.java index 2281343c30..7fef63e7f1 100644 --- a/src/com/vaadin/data/util/QueryContainer.java +++ b/src/com/vaadin/data/util/QueryContainer.java @@ -136,7 +136,8 @@ public class QueryContainer implements Container, Container.Ordered, for (int i = 1; i <= count; i++) { final String columnName = metadata.getColumnName(i); list.add(columnName); - final Property p = getContainerProperty(new Integer(1), columnName); + final Property<?> p = getContainerProperty(new Integer(1), + columnName); propertyTypes.put(columnName, p == null ? Object.class : p.getType()); } @@ -228,7 +229,7 @@ public class QueryContainer implements Container, Container.Ordered, * otherwise. */ - public synchronized Property getContainerProperty(Object itemId, + public synchronized Property<?> getContainerProperty(Object itemId, Object propertyId) { if (!(itemId instanceof Integer && propertyId instanceof String)) { return null; @@ -531,7 +532,7 @@ public class QueryContainer implements Container, Container.Ordered, * identifier of the Property to get * @return the Property with the given ID or <code>null</code> */ - public Property getItemProperty(Object propertyId) { + public Property<?> getItemProperty(Object propertyId) { return getContainerProperty(id, propertyId); } diff --git a/src/com/vaadin/data/util/TextFileProperty.java b/src/com/vaadin/data/util/TextFileProperty.java index cfa8d4fabf..5ebba98062 100644 --- a/src/com/vaadin/data/util/TextFileProperty.java +++ b/src/com/vaadin/data/util/TextFileProperty.java @@ -26,7 +26,7 @@ import java.nio.charset.Charset; * */ @SuppressWarnings("serial") -public class TextFileProperty extends AbstractProperty { +public class TextFileProperty extends AbstractProperty<String> { private File file; private Charset charset = null; @@ -64,7 +64,7 @@ public class TextFileProperty extends AbstractProperty { * * @see com.vaadin.data.Property#getType() */ - public Class<?> getType() { + public Class<String> getType() { return String.class; } @@ -73,7 +73,7 @@ public class TextFileProperty extends AbstractProperty { * * @see com.vaadin.data.Property#getValue() */ - public Object getValue() { + public String getValue() { if (file == null) { return null; } diff --git a/src/com/vaadin/data/util/TransactionalPropertyWrapper.java b/src/com/vaadin/data/util/TransactionalPropertyWrapper.java new file mode 100644 index 0000000000..06ec0935c3 --- /dev/null +++ b/src/com/vaadin/data/util/TransactionalPropertyWrapper.java @@ -0,0 +1,107 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.util; + +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeNotifier; + +/** + * Wrapper class that helps implement two-phase commit for a non-transactional + * property. + * + * When accessing the property through the wrapper, getting and setting the + * property value take place immediately. However, the wrapper keeps track of + * the old value of the property so that it can be set for the property in case + * of a roll-back. This can result in the underlying property value changing + * multiple times (first based on modifications made by the application, then + * back upon roll-back). + * + * Value change events on the {@link TransactionalPropertyWrapper} are only + * fired at the end of a successful transaction, whereas listeners attached to + * the underlying property may receive multiple value change events. + * + * @see com.vaadin.data.Property.Transactional + * + * @author Vaadin Ltd + * @version @version@ + * @since 7.0 + * + * @param <T> + */ +public class TransactionalPropertyWrapper<T> extends AbstractProperty<T> + implements ValueChangeNotifier, Property.Transactional<T> { + + private Property<T> wrappedProperty; + private boolean inTransaction = false; + private boolean valueChangePending; + private T valueBeforeTransaction; + + public TransactionalPropertyWrapper(Property<T> wrappedProperty) { + this.wrappedProperty = wrappedProperty; + if (wrappedProperty instanceof ValueChangeNotifier) { + ((ValueChangeNotifier) wrappedProperty) + .addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + fireValueChange(); + } + }); + } + } + + public Class getType() { + return wrappedProperty.getType(); + } + + public T getValue() { + return wrappedProperty.getValue(); + } + + public void setValue(Object newValue) throws ReadOnlyException { + // Causes a value change to be sent to this listener which in turn fires + // a new value change event for this property + wrappedProperty.setValue(newValue); + } + + public void startTransaction() { + inTransaction = true; + valueBeforeTransaction = getValue(); + } + + public void commit() { + endTransaction(); + } + + public void rollback() { + try { + wrappedProperty.setValue(valueBeforeTransaction); + } finally { + valueChangePending = false; + endTransaction(); + } + } + + protected void endTransaction() { + inTransaction = false; + valueBeforeTransaction = null; + if (valueChangePending) { + fireValueChange(); + } + } + + @Override + protected void fireValueChange() { + if (inTransaction) { + valueChangePending = true; + } else { + super.fireValueChange(); + } + } + + public Property<T> getWrappedProperty() { + return wrappedProperty; + } + +} diff --git a/src/com/vaadin/data/util/VaadinPropertyDescriptor.java b/src/com/vaadin/data/util/VaadinPropertyDescriptor.java index 2a28671881..ee1e525540 100644 --- a/src/com/vaadin/data/util/VaadinPropertyDescriptor.java +++ b/src/com/vaadin/data/util/VaadinPropertyDescriptor.java @@ -39,5 +39,5 @@ public interface VaadinPropertyDescriptor<BT> extends Serializable { * @param bean * @return */ - public Property createProperty(BT bean); -}
\ No newline at end of file + public Property<?> createProperty(BT bean); +} diff --git a/src/com/vaadin/data/util/converter/Converter.java b/src/com/vaadin/data/util/converter/Converter.java new file mode 100644 index 0000000000..b8c15e8cdc --- /dev/null +++ b/src/com/vaadin/data/util/converter/Converter.java @@ -0,0 +1,159 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.io.Serializable; +import java.util.Locale; + +/** + * Interface that implements conversion between a model and a presentation type. + * <p> + * Typically {@link #convertToPresentation(Object, Locale)} and + * {@link #convertToModel(Object, Locale)} should be symmetric so that chaining + * these together returns the original result for all input but this is not a + * requirement. + * </p> + * <p> + * Converters must not have any side effects (never update UI from inside a + * converter). + * </p> + * <p> + * All Converters must be stateless and thread safe. + * </p> + * <p> + * If conversion of a value fails, a {@link ConversionException} is thrown. + * </p> + * + * @param <MODEL> + * The model type. Must be compatible with what + * {@link #getModelType()} returns. + * @param <PRESENTATION> + * The presentation type. Must be compatible with what + * {@link #getPresentationType()} returns. + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 + */ +public interface Converter<PRESENTATION, MODEL> extends Serializable { + + /** + * Converts the given value from target type to source type. + * <p> + * A converter can optionally use locale to do the conversion. + * </p> + * A converter should in most cases be symmetric so chaining + * {@link #convertToPresentation(Object, Locale)} and + * {@link #convertToModel(Object, Locale)} should return the original value. + * + * @param value + * The value to convert, compatible with the target type. Can be + * null + * @param locale + * The locale to use for conversion. Can be null. + * @return The converted value compatible with the source type + * @throws ConversionException + * If the value could not be converted + */ + public MODEL convertToModel(PRESENTATION value, Locale locale) + throws ConversionException; + + /** + * Converts the given value from source type to target type. + * <p> + * A converter can optionally use locale to do the conversion. + * </p> + * A converter should in most cases be symmetric so chaining + * {@link #convertToPresentation(Object, Locale)} and + * {@link #convertToModel(Object, Locale)} should return the original value. + * + * @param value + * The value to convert, compatible with the target type. Can be + * null + * @param locale + * The locale to use for conversion. Can be null. + * @return The converted value compatible with the source type + * @throws ConversionException + * If the value could not be converted + */ + public PRESENTATION convertToPresentation(MODEL value, Locale locale) + throws ConversionException; + + /** + * The source type of the converter. + * + * Values of this type can be passed to + * {@link #convertToPresentation(Object, Locale)}. + * + * @return The source type + */ + public Class<MODEL> getModelType(); + + /** + * The target type of the converter. + * + * Values of this type can be passed to + * {@link #convertToModel(Object, Locale)}. + * + * @return The target type + */ + public Class<PRESENTATION> getPresentationType(); + + /** + * An exception that signals that the value passed to + * {@link Converter#convertToPresentation(Object, Locale)} or + * {@link Converter#convertToModel(Object, Locale)} could not be converted. + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ + public static class ConversionException extends RuntimeException { + + /** + * Constructs a new <code>ConversionException</code> without a detail + * message. + */ + public ConversionException() { + } + + /** + * Constructs a new <code>ConversionException</code> with the specified + * detail message. + * + * @param msg + * the detail message + */ + public ConversionException(String msg) { + super(msg); + } + + /** + * Constructs a new {@code ConversionException} with the specified + * cause. + * + * @param cause + * The cause of the the exception + */ + public ConversionException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new <code>ConversionException</code> with the specified + * detail message and cause. + * + * @param message + * the detail message + * @param cause + * The cause of the the exception + */ + public ConversionException(String message, Throwable cause) { + super(message, cause); + } + } + +} diff --git a/src/com/vaadin/data/util/converter/ConverterFactory.java b/src/com/vaadin/data/util/converter/ConverterFactory.java new file mode 100644 index 0000000000..ed4ab41ac0 --- /dev/null +++ b/src/com/vaadin/data/util/converter/ConverterFactory.java @@ -0,0 +1,23 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.io.Serializable; + +/** + * Factory interface for providing Converters based on a presentation type and a + * model type. + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 + * + */ +public interface ConverterFactory extends Serializable { + public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> createConverter( + Class<PRESENTATION> presentationType, Class<MODEL> modelType); + +} diff --git a/src/com/vaadin/data/util/converter/DateToLongConverter.java b/src/com/vaadin/data/util/converter/DateToLongConverter.java new file mode 100644 index 0000000000..537800f617 --- /dev/null +++ b/src/com/vaadin/data/util/converter/DateToLongConverter.java @@ -0,0 +1,68 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.util.Date; +import java.util.Locale; + +/** + * A converter that converts from {@link Long} to {@link Date} and back. + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class DateToLongConverter implements Converter<Date, Long> { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, + * java.util.Locale) + */ + public Long convertToModel(Date value, Locale locale) { + if (value == null) { + return null; + } + + return value.getTime(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + public Date convertToPresentation(Long value, Locale locale) { + if (value == null) { + return null; + } + + return new Date(value); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getModelType() + */ + public Class<Long> getModelType() { + return Long.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getPresentationType() + */ + public Class<Date> getPresentationType() { + return Date.class; + } + +} diff --git a/src/com/vaadin/data/util/converter/DefaultConverterFactory.java b/src/com/vaadin/data/util/converter/DefaultConverterFactory.java new file mode 100644 index 0000000000..3ad7b6a85b --- /dev/null +++ b/src/com/vaadin/data/util/converter/DefaultConverterFactory.java @@ -0,0 +1,100 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.util.Date; +import java.util.logging.Logger; + +import com.vaadin.Application; + +/** + * Default implementation of {@link ConverterFactory}. Provides converters for + * standard types like {@link String}, {@link Double} and {@link Date}. </p> + * <p> + * Custom converters can be provided by extending this class and using + * {@link Application#setConverterFactory(ConverterFactory)}. + * </p> + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class DefaultConverterFactory implements ConverterFactory { + + private final static Logger log = Logger + .getLogger(DefaultConverterFactory.class.getName()); + + public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> createConverter( + Class<PRESENTATION> presentationType, Class<MODEL> modelType) { + Converter<PRESENTATION, MODEL> converter = findConverter( + presentationType, modelType); + if (converter != null) { + log.finest(getClass().getName() + " created a " + + converter.getClass()); + return converter; + } + + // Try to find a reverse converter + Converter<MODEL, PRESENTATION> reverseConverter = findConverter( + modelType, presentationType); + if (reverseConverter != null) { + log.finest(getClass().getName() + " created a reverse " + + reverseConverter.getClass()); + return new ReverseConverter<PRESENTATION, MODEL>(reverseConverter); + } + + log.finest(getClass().getName() + " could not find a converter for " + + presentationType.getName() + " to " + modelType.getName() + + " conversion"); + return null; + + } + + protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter( + Class<PRESENTATION> presentationType, Class<MODEL> modelType) { + if (presentationType == String.class) { + // TextField converters and more + Converter<PRESENTATION, MODEL> converter = (Converter<PRESENTATION, MODEL>) createStringConverter(modelType); + if (converter != null) { + return converter; + } + } else if (presentationType == Date.class) { + // DateField converters and more + Converter<PRESENTATION, MODEL> converter = (Converter<PRESENTATION, MODEL>) createDateConverter(modelType); + if (converter != null) { + return converter; + } + } + + return null; + + } + + protected Converter<Date, ?> createDateConverter(Class<?> sourceType) { + if (Long.class.isAssignableFrom(sourceType)) { + return new DateToLongConverter(); + } else { + return null; + } + } + + protected Converter<String, ?> createStringConverter(Class<?> sourceType) { + if (Double.class.isAssignableFrom(sourceType)) { + return new StringToDoubleConverter(); + } else if (Integer.class.isAssignableFrom(sourceType)) { + return new StringToIntegerConverter(); + } else if (Boolean.class.isAssignableFrom(sourceType)) { + return new StringToBooleanConverter(); + } else if (Number.class.isAssignableFrom(sourceType)) { + return new StringToNumberConverter(); + } else if (Date.class.isAssignableFrom(sourceType)) { + return new StringToDateConverter(); + } else { + return null; + } + } + +} diff --git a/src/com/vaadin/data/util/converter/ReverseConverter.java b/src/com/vaadin/data/util/converter/ReverseConverter.java new file mode 100644 index 0000000000..1c561f29e8 --- /dev/null +++ b/src/com/vaadin/data/util/converter/ReverseConverter.java @@ -0,0 +1,80 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.util.Locale; + +/** + * A converter that wraps another {@link Converter} and reverses source and + * target types. + * + * @param <MODEL> + * The source type + * @param <PRESENTATION> + * The target type + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class ReverseConverter<PRESENTATION, MODEL> implements + Converter<PRESENTATION, MODEL> { + + private Converter<MODEL, PRESENTATION> realConverter; + + /** + * Creates a converter from source to target based on a converter that + * converts from target to source. + * + * @param converter + * The converter to use in a reverse fashion + */ + public ReverseConverter(Converter<MODEL, PRESENTATION> converter) { + this.realConverter = converter; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#convertToModel(java + * .lang.Object, java.util.Locale) + */ + public MODEL convertToModel(PRESENTATION value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + return realConverter.convertToPresentation(value, locale); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + public PRESENTATION convertToPresentation(MODEL value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + return realConverter.convertToModel(value, locale); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getSourceType() + */ + public Class<MODEL> getModelType() { + return realConverter.getPresentationType(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getTargetType() + */ + public Class<PRESENTATION> getPresentationType() { + return realConverter.getModelType(); + } + +} diff --git a/src/com/vaadin/data/util/converter/StringToBooleanConverter.java b/src/com/vaadin/data/util/converter/StringToBooleanConverter.java new file mode 100644 index 0000000000..96a3a3d071 --- /dev/null +++ b/src/com/vaadin/data/util/converter/StringToBooleanConverter.java @@ -0,0 +1,104 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.util.Locale; + +/** + * A converter that converts from {@link String} to {@link Boolean} and back. + * The String representation is given by Boolean.toString(). + * <p> + * Leading and trailing white spaces are ignored when converting from a String. + * </p> + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class StringToBooleanConverter implements Converter<String, Boolean> { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, + * java.util.Locale) + */ + public Boolean convertToModel(String value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + // Remove leading and trailing white space + value = value.trim(); + + if (getTrueString().equals(value)) { + return true; + } else if (getFalseString().equals(value)) { + return false; + } else { + throw new ConversionException("Cannot convert " + value + " to " + + getModelType().getName()); + } + } + + /** + * Gets the string representation for true. Default is "true". + * + * @return the string representation for true + */ + protected String getTrueString() { + return Boolean.TRUE.toString(); + } + + /** + * Gets the string representation for false. Default is "false". + * + * @return the string representation for false + */ + protected String getFalseString() { + return Boolean.FALSE.toString(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + public String convertToPresentation(Boolean value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + if (value) { + return getTrueString(); + } else { + return getFalseString(); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getModelType() + */ + public Class<Boolean> getModelType() { + return Boolean.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getPresentationType() + */ + public Class<String> getPresentationType() { + return String.class; + } + +} diff --git a/src/com/vaadin/data/util/converter/StringToDateConverter.java b/src/com/vaadin/data/util/converter/StringToDateConverter.java new file mode 100644 index 0000000000..6f3c2e47f6 --- /dev/null +++ b/src/com/vaadin/data/util/converter/StringToDateConverter.java @@ -0,0 +1,108 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.text.DateFormat; +import java.text.ParsePosition; +import java.util.Date; +import java.util.Locale; + +/** + * A converter that converts from {@link Date} to {@link String} and back. Uses + * the given locale and {@link DateFormat} for formatting and parsing. + * <p> + * Leading and trailing white spaces are ignored when converting from a String. + * </p> + * <p> + * Override and overwrite {@link #getFormat(Locale)} to use a different format. + * </p> + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class StringToDateConverter implements Converter<String, Date> { + + /** + * Returns the format used by {@link #convertToPresentation(Date, Locale)} + * and {@link #convertToModel(String, Locale)}. + * + * @param locale + * The locale to use + * @return A DateFormat instance + */ + protected DateFormat getFormat(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + + DateFormat f = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, + DateFormat.MEDIUM, locale); + f.setLenient(false); + return f; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, + * java.util.Locale) + */ + public Date convertToModel(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + // Remove leading and trailing white space + value = value.trim(); + + ParsePosition parsePosition = new ParsePosition(0); + Date parsedValue = getFormat(locale).parse(value, parsePosition); + if (parsePosition.getIndex() != value.length()) { + throw new ConversionException("Could not convert '" + value + + "' to " + getModelType().getName()); + } + + return parsedValue; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + public String convertToPresentation(Date value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + + return getFormat(locale).format(value); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getModelType() + */ + public Class<Date> getModelType() { + return Date.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getPresentationType() + */ + public Class<String> getPresentationType() { + return String.class; + } + +} diff --git a/src/com/vaadin/data/util/converter/StringToDoubleConverter.java b/src/com/vaadin/data/util/converter/StringToDoubleConverter.java new file mode 100644 index 0000000000..60a38f4127 --- /dev/null +++ b/src/com/vaadin/data/util/converter/StringToDoubleConverter.java @@ -0,0 +1,103 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +/** + * A converter that converts from {@link String} to {@link Double} and back. + * Uses the given locale and a {@link NumberFormat} instance for formatting and + * parsing. + * <p> + * Leading and trailing white spaces are ignored when converting from a String. + * </p> + * <p> + * Override and overwrite {@link #getFormat(Locale)} to use a different format. + * </p> + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class StringToDoubleConverter implements Converter<String, Double> { + + /** + * Returns the format used by {@link #convertToPresentation(Double, Locale)} + * and {@link #convertToModel(String, Locale)}. + * + * @param locale + * The locale to use + * @return A NumberFormat instance + */ + protected NumberFormat getFormat(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + + return NumberFormat.getNumberInstance(locale); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, + * java.util.Locale) + */ + public Double convertToModel(String value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + // Remove leading and trailing white space + value = value.trim(); + + ParsePosition parsePosition = new ParsePosition(0); + Number parsedValue = getFormat(locale).parse(value, parsePosition); + if (parsePosition.getIndex() != value.length()) { + throw new ConversionException("Could not convert '" + value + + "' to " + getModelType().getName()); + } + return parsedValue.doubleValue(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + public String convertToPresentation(Double value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + return getFormat(locale).format(value); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getModelType() + */ + public Class<Double> getModelType() { + return Double.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getPresentationType() + */ + public Class<String> getPresentationType() { + return String.class; + } +} diff --git a/src/com/vaadin/data/util/converter/StringToIntegerConverter.java b/src/com/vaadin/data/util/converter/StringToIntegerConverter.java new file mode 100644 index 0000000000..e55feec3b6 --- /dev/null +++ b/src/com/vaadin/data/util/converter/StringToIntegerConverter.java @@ -0,0 +1,84 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +/** + * A converter that converts from {@link String} to {@link Integer} and back. + * Uses the given locale and a {@link NumberFormat} instance for formatting and + * parsing. + * <p> + * Override and overwrite {@link #getFormat(Locale)} to use a different format. + * </p> + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class StringToIntegerConverter implements Converter<String, Integer> { + + /** + * Returns the format used by + * {@link #convertToPresentation(Integer, Locale)} and + * {@link #convertToModel(String, Locale)}. + * + * @param locale + * The locale to use + * @return A NumberFormat instance + */ + protected NumberFormat getFormat(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + return NumberFormat.getIntegerInstance(locale); + } + + public Integer convertToModel(String value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + // Remove leading and trailing white space + value = value.trim(); + + // Parse and detect errors. If the full string was not used, it is + // an error. + ParsePosition parsePosition = new ParsePosition(0); + Number parsedValue = getFormat(locale).parse(value, parsePosition); + if (parsePosition.getIndex() != value.length()) { + throw new ConversionException("Could not convert '" + value + + "' to " + getModelType().getName()); + } + + if (parsedValue == null) { + // Convert "" to null + return null; + } + return parsedValue.intValue(); + } + + public String convertToPresentation(Integer value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + return getFormat(locale).format(value); + } + + public Class<Integer> getModelType() { + return Integer.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + +} diff --git a/src/com/vaadin/data/util/converter/StringToNumberConverter.java b/src/com/vaadin/data/util/converter/StringToNumberConverter.java new file mode 100644 index 0000000000..d1816007e7 --- /dev/null +++ b/src/com/vaadin/data/util/converter/StringToNumberConverter.java @@ -0,0 +1,107 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.util.converter; + +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +/** + * A converter that converts from {@link Number} to {@link String} and back. + * Uses the given locale and {@link NumberFormat} for formatting and parsing. + * <p> + * Override and overwrite {@link #getFormat(Locale)} to use a different format. + * </p> + * + * @author Vaadin Ltd + * @version + * @VERSION@ + * @since 7.0 + */ +public class StringToNumberConverter implements Converter<String, Number> { + + /** + * Returns the format used by {@link #convertToPresentation(Number, Locale)} + * and {@link #convertToModel(String, Locale)}. + * + * @param locale + * The locale to use + * @return A NumberFormat instance + */ + protected NumberFormat getFormat(Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + + return NumberFormat.getNumberInstance(locale); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, + * java.util.Locale) + */ + public Number convertToModel(String value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + // Remove leading and trailing white space + value = value.trim(); + + // Parse and detect errors. If the full string was not used, it is + // an error. + ParsePosition parsePosition = new ParsePosition(0); + Number parsedValue = getFormat(locale).parse(value, parsePosition); + if (parsePosition.getIndex() != value.length()) { + throw new ConversionException("Could not convert '" + value + + "' to " + getModelType().getName()); + } + + if (parsedValue == null) { + // Convert "" to null + return null; + } + return parsedValue; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang + * .Object, java.util.Locale) + */ + public String convertToPresentation(Number value, Locale locale) + throws ConversionException { + if (value == null) { + return null; + } + + return getFormat(locale).format(value); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getModelType() + */ + public Class<Number> getModelType() { + return Number.class; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.converter.Converter#getPresentationType() + */ + public Class<String> getPresentationType() { + return String.class; + } + +} diff --git a/src/com/vaadin/data/util/filter/Compare.java b/src/com/vaadin/data/util/filter/Compare.java index fe7d908c93..111d95f055 100644 --- a/src/com/vaadin/data/util/filter/Compare.java +++ b/src/com/vaadin/data/util/filter/Compare.java @@ -228,7 +228,7 @@ public abstract class Compare implements Filter { } public boolean passesFilter(Object itemId, Item item) { - final Property p = item.getItemProperty(getPropertyId()); + final Property<?> p = item.getItemProperty(getPropertyId()); if (null == p) { return false; } diff --git a/src/com/vaadin/data/util/filter/IsNull.java b/src/com/vaadin/data/util/filter/IsNull.java index 0ae00d2e09..aad71a7c80 100644 --- a/src/com/vaadin/data/util/filter/IsNull.java +++ b/src/com/vaadin/data/util/filter/IsNull.java @@ -35,7 +35,7 @@ public final class IsNull implements Filter { public boolean passesFilter(Object itemId, Item item) throws UnsupportedOperationException { - final Property p = item.getItemProperty(getPropertyId()); + final Property<?> p = item.getItemProperty(getPropertyId()); if (null == p) { return false; } diff --git a/src/com/vaadin/data/util/filter/SimpleStringFilter.java b/src/com/vaadin/data/util/filter/SimpleStringFilter.java index 243571582e..6203251045 100644 --- a/src/com/vaadin/data/util/filter/SimpleStringFilter.java +++ b/src/com/vaadin/data/util/filter/SimpleStringFilter.java @@ -40,12 +40,16 @@ public final class SimpleStringFilter implements Filter { } public boolean passesFilter(Object itemId, Item item) { - final Property p = item.getItemProperty(propertyId); - if (p == null || p.toString() == null) { + final Property<?> p = item.getItemProperty(propertyId); + if (p == null) { return false; } - final String value = ignoreCase ? p.toString().toLowerCase() : p - .toString(); + Object propertyValue = p.getValue(); + if (propertyValue == null) { + return false; + } + final String value = ignoreCase ? propertyValue.toString() + .toLowerCase() : propertyValue.toString(); if (onlyMatchPrefix) { if (!value.startsWith(filterString)) { return false; diff --git a/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java b/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java index 85ff60d5d9..d84a164bfa 100644 --- a/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java +++ b/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java @@ -3,7 +3,6 @@ */ package com.vaadin.data.util.sqlcontainer; -import java.lang.reflect.Constructor; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; @@ -69,8 +68,7 @@ final public class ColumnProperty implements Property { return value; } - public void setValue(Object newValue) throws ReadOnlyException, - ConversionException { + public void setValue(Object newValue) throws ReadOnlyException { if (newValue == null && !nullable) { throw new NotNullableException( "Null values are not allowed for this property."); @@ -109,19 +107,9 @@ final public class ColumnProperty implements Property { } } - /* - * If the type is not correct, try to generate it through a possibly - * existing String constructor. - */ if (!getType().isAssignableFrom(newValue.getClass())) { - try { - final Constructor<?> constr = getType().getConstructor( - new Class[] { String.class }); - newValue = constr.newInstance(new Object[] { newValue - .toString() }); - } catch (Exception e) { - throw new ConversionException(e); - } + throw new IllegalArgumentException( + "Illegal value type for ColumnProperty"); } /* @@ -168,13 +156,17 @@ final public class ColumnProperty implements Property { return propertyId; } + /** + * Returns the value of the Property in human readable textual format. + * + * @see java.lang.Object#toString() + * @deprecated get the string representation from the value + */ + @Deprecated @Override public String toString() { - Object val = getValue(); - if (val == null) { - return null; - } - return val.toString(); + throw new UnsupportedOperationException( + "Use ColumnProperty.getValue() instead of ColumnProperty.toString()"); } public void setOwner(RowItem owner) { diff --git a/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java b/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java index 248b159aa9..adfd439ac8 100644 --- a/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java +++ b/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java @@ -3,6 +3,8 @@ */ package com.vaadin.data.util.sqlcontainer; +import com.vaadin.data.util.sqlcontainer.query.TableQuery; + /** * An OptimisticLockException is thrown when trying to update or delete a row * that has been changed since last read from the database. @@ -12,7 +14,7 @@ package com.vaadin.data.util.sqlcontainer; * configuration. In order to turn on optimistic locking, you need to specify * the version column in your TableQuery instance. * - * @see com.vaadin.addon.sqlcontainer.query.TableQuery#setVersionColumn(String) + * @see TableQuery#setVersionColumn(String) * * @author Jonatan Kronqvist / Vaadin Ltd */ diff --git a/src/com/vaadin/data/util/sqlcontainer/RowItem.java b/src/com/vaadin/data/util/sqlcontainer/RowItem.java index 3bd73bc48f..adededb65c 100644 --- a/src/com/vaadin/data/util/sqlcontainer/RowItem.java +++ b/src/com/vaadin/data/util/sqlcontainer/RowItem.java @@ -48,7 +48,7 @@ public final class RowItem implements Item { this.id = id; } - public Property getItemProperty(Object id) { + public Property<?> getItemProperty(Object id) { if (id instanceof String && id != null) { for (ColumnProperty cp : properties) { if (id.equals(cp.getPropertyId())) { @@ -113,7 +113,8 @@ public final class RowItem implements Item { s.append("|"); s.append(propId.toString()); s.append(":"); - s.append(getItemProperty(propId).toString()); + Object value = getItemProperty(propId).getValue(); + s.append((null != value) ? value.toString() : null); } return s.toString(); } diff --git a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index 7eb67437e0..3bf33defd5 100644 --- a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ b/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java @@ -227,7 +227,7 @@ public class SQLContainer implements Container, Container.Filterable, * @see com.vaadin.data.Container#getContainerProperty(java.lang.Object, * java.lang.Object) */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { Item item = getItem(itemId); if (item == null) { return null; @@ -1435,7 +1435,7 @@ public class SQLContainer implements Container, Container.Filterable, * Simple ItemSetChangeEvent implementation. */ @SuppressWarnings("serial") - public class ItemSetChangeEvent extends EventObject implements + public static class ItemSetChangeEvent extends EventObject implements Container.ItemSetChangeEvent { private ItemSetChangeEvent(SQLContainer source) { @@ -1640,4 +1640,4 @@ public class SQLContainer implements Container, Container.Filterable, } } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java b/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java index 7dcab29611..56a8455a16 100644 --- a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java +++ b/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java @@ -178,15 +178,14 @@ public class FreeformQuery implements QueryDelegate { /** * Fetches the results for the query. This implementation always fetches the - * entire record set, ignoring the offset and pagelength parameters. In + * entire record set, ignoring the offset and page length parameters. In * order to support lazy loading of records, you must supply a * FreeformQueryDelegate that implements the * FreeformQueryDelegate.getQueryString(int,int) method. * * @throws SQLException * - * @see com.vaadin.addon.sqlcontainer.query.FreeformQueryDelegate#getQueryString(int, - * int) {@inheritDoc} + * @see FreeformQueryDelegate#getQueryString(int, int) */ @SuppressWarnings("deprecation") public ResultSet getResults(int offset, int pagelength) throws SQLException { @@ -249,8 +248,8 @@ public class FreeformQuery implements QueryDelegate { * (non-Javadoc) * * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#setFilters(java.util - * .List) + * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#setFilters(java + * .util.List) */ public void setFilters(List<Filter> filters) throws UnsupportedOperationException { @@ -262,6 +261,13 @@ public class FreeformQuery implements QueryDelegate { } } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#setOrderBy(java + * .util.List) + */ public void setOrderBy(List<OrderBy> orderBys) throws UnsupportedOperationException { if (delegate != null) { @@ -272,6 +278,13 @@ public class FreeformQuery implements QueryDelegate { } } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#storeRow(com.vaadin + * .data.util.sqlcontainer.RowItem) + */ public int storeRow(RowItem row) throws SQLException { if (activeConnection == null) { throw new IllegalStateException("No transaction is active!"); @@ -287,6 +300,13 @@ public class FreeformQuery implements QueryDelegate { } } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#removeRow(com.vaadin + * .data.util.sqlcontainer.RowItem) + */ public boolean removeRow(RowItem row) throws SQLException { if (activeConnection == null) { throw new IllegalStateException("No transaction is active!"); @@ -302,6 +322,12 @@ public class FreeformQuery implements QueryDelegate { } } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#beginTransaction() + */ public synchronized void beginTransaction() throws UnsupportedOperationException, SQLException { if (activeConnection != null) { @@ -311,6 +337,11 @@ public class FreeformQuery implements QueryDelegate { activeConnection.setAutoCommit(false); } + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#commit() + */ public synchronized void commit() throws UnsupportedOperationException, SQLException { if (activeConnection == null) { @@ -323,6 +354,11 @@ public class FreeformQuery implements QueryDelegate { activeConnection = null; } + /* + * (non-Javadoc) + * + * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#rollback() + */ public synchronized void rollback() throws UnsupportedOperationException, SQLException { if (activeConnection == null) { @@ -333,6 +369,13 @@ public class FreeformQuery implements QueryDelegate { activeConnection = null; } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#getPrimaryKeyColumns + * () + */ public List<String> getPrimaryKeyColumns() { return primaryKeyColumns; } @@ -357,9 +400,8 @@ public class FreeformQuery implements QueryDelegate { * getContainsRowQueryString method in FreeformQueryDelegate and this will * be used instead of the logic. * - * @see com.vaadin.addon.sqlcontainer.query.FreeformQueryDelegate#getContainsRowQueryString(Object...) + * @see FreeformQueryDelegate#getContainsRowQueryString(Object...) * - * {@inheritDoc} */ @SuppressWarnings("deprecation") public boolean containsRowWithKey(Object... keys) throws SQLException { diff --git a/src/com/vaadin/data/validator/AbstractStringValidator.java b/src/com/vaadin/data/validator/AbstractStringValidator.java index 3bc66b3a73..5267cc7b7b 100644 --- a/src/com/vaadin/data/validator/AbstractStringValidator.java +++ b/src/com/vaadin/data/validator/AbstractStringValidator.java @@ -4,9 +4,7 @@ package com.vaadin.data.validator; /** - * Validator base class for validating strings. See - * {@link com.vaadin.data.validator.AbstractValidator} for more information. - * + * Validator base class for validating strings. * <p> * To include the value that failed validation in the exception message you can * use "{0}" in the error message. This will be replaced with the failed value @@ -15,12 +13,11 @@ package com.vaadin.data.validator; * </p> * * @author Vaadin Ltd. - * @version - * @VERSION@ + * @version @VERSION@ * @since 5.4 */ @SuppressWarnings("serial") -public abstract class AbstractStringValidator extends AbstractValidator { +public abstract class AbstractStringValidator extends AbstractValidator<String> { /** * Constructs a validator for strings. @@ -38,35 +35,8 @@ public abstract class AbstractStringValidator extends AbstractValidator { super(errorMessage); } - /** - * Tests if the given value is a valid string. - * <p> - * Null values are always accepted. Values that are not {@link String}s are - * converted using {@link #toString()}. Then {@link #isValidString(String)} - * is used to validate the value. - * </p> - * - * @param value - * the value to check - * @return true if the value (or its toString()) is a valid string, false - * otherwise - */ - public boolean isValid(Object value) { - if (value == null) { - return true; - } - if (!(value instanceof String)) { - value = String.valueOf(value); - } - return isValidString((String) value); + @Override + public Class<String> getType() { + return String.class; } - - /** - * Checks if the given string is valid. - * - * @param value - * String to check. Can never be null. - * @return true if the string is valid, false otherwise - */ - protected abstract boolean isValidString(String value); } diff --git a/src/com/vaadin/data/validator/AbstractValidator.java b/src/com/vaadin/data/validator/AbstractValidator.java index 5c8dd9b31a..27eaaca485 100644 --- a/src/com/vaadin/data/validator/AbstractValidator.java +++ b/src/com/vaadin/data/validator/AbstractValidator.java @@ -7,8 +7,8 @@ import com.vaadin.data.Validator; /** * Abstract {@link com.vaadin.data.Validator Validator} implementation that - * provides a basic Validator implementation except the {@link #isValid(Object)} - * method. Sub-classes need to implement the {@link #isValid(Object)} method. + * provides a basic Validator implementation except the + * {@link #isValidValue(Object)} method. * <p> * To include the value that failed validation in the exception message you can * use "{0}" in the error message. This will be replaced with the failed value @@ -21,14 +21,20 @@ import com.vaadin.data.Validator; * {@link InvalidValueException#getHtmlMessage()} and throw such exceptions from * {@link #validate(Object)}. * </p> + * <p> + * Since Vaadin 7, subclasses can either implement {@link #validate(Object)} + * directly or implement {@link #isValidValue(Object)} when migrating legacy + * applications. To check validity, {@link #validate(Object)} should be used. + * </p> * + * @param <T> + * The type * @author Vaadin Ltd. * @version * @VERSION@ * @since 5.4 */ -@SuppressWarnings("serial") -public abstract class AbstractValidator implements Validator { +public abstract class AbstractValidator<T> implements Validator { /** * Error message that is included in an {@link InvalidValueException} if @@ -47,14 +53,65 @@ public abstract class AbstractValidator implements Validator { this.errorMessage = errorMessage; } + /** + * Since Vaadin 7, subclasses of AbstractValidator should override + * {@link #isValidValue(Object)} or {@link #validate(Object)} instead of + * {@link #isValid(Object)}. {@link #validate(Object)} should normally be + * used to check values. + * + * @param value + * @return true if the value is valid + */ + public boolean isValid(Object value) { + try { + validate(value); + return true; + } catch (InvalidValueException e) { + return false; + } + } + + /** + * Internally check the validity of a value. This method can be used to + * perform validation in subclasses if customization of the error message is + * not needed. Otherwise, subclasses should override + * {@link #validate(Object)} and the return value of this method is ignored. + * + * This method should not be called from outside the validator class itself. + * + * @param value + * @return + */ + protected abstract boolean isValidValue(T value); + public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { - String message = getErrorMessage().replace("{0}", String.valueOf(value)); + // isValidType ensures that value can safely be cast to TYPE + if (!isValidType(value) || !isValidValue((T) value)) { + String message = getErrorMessage().replace("{0}", + String.valueOf(value)); throw new InvalidValueException(message); } } /** + * Checks the type of the value to validate to ensure it conforms with + * getType. Enables sub classes to handle the specific type instead of + * Object. + * + * @param value + * The value to check + * @return true if the value can safely be cast to the type specified by + * {@link #getType()} + */ + protected boolean isValidType(Object value) { + if (value == null) { + return true; + } + + return getType().isAssignableFrom(value.getClass()); + } + + /** * Returns the message to be included in the exception in case the value * does not validate. * @@ -76,4 +133,6 @@ public abstract class AbstractValidator implements Validator { public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } + + public abstract Class<T> getType(); } diff --git a/src/com/vaadin/data/validator/BeanValidator.java b/src/com/vaadin/data/validator/BeanValidator.java new file mode 100644 index 0000000000..817df85248 --- /dev/null +++ b/src/com/vaadin/data/validator/BeanValidator.java @@ -0,0 +1,173 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.data.validator; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.MessageInterpolator.Context; +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import javax.validation.metadata.ConstraintDescriptor; + +import com.vaadin.data.Validator; + +/** + * Vaadin {@link Validator} using the JSR-303 (javax.validation) + * annotation-based bean validation. + * + * The annotations of the fields of the beans are used to determine the + * validation to perform. + * + * Note that a JSR-303 implementation (e.g. Hibernate Validator or Apache Bean + * Validation - formerly agimatec validation) must be present on the project + * classpath when using bean validation. + * + * @since 7.0 + * + * @author Petri Hakala + * @author Henri Sara + */ +public class BeanValidator implements Validator { + + private static final long serialVersionUID = 1L; + private static ValidatorFactory factory; + + private transient javax.validation.Validator javaxBeanValidator; + private String propertyName; + private Class<?> beanClass; + private Locale locale; + + /** + * Simple implementation of a message interpolator context that returns + * fixed values. + */ + protected static class SimpleContext implements Context, Serializable { + + private final Object value; + private final ConstraintDescriptor<?> descriptor; + + /** + * Create a simple immutable message interpolator context. + * + * @param value + * value being validated + * @param descriptor + * ConstraintDescriptor corresponding to the constraint being + * validated + */ + public SimpleContext(Object value, ConstraintDescriptor<?> descriptor) { + this.value = value; + this.descriptor = descriptor; + } + + public ConstraintDescriptor<?> getConstraintDescriptor() { + return descriptor; + } + + public Object getValidatedValue() { + return value; + } + + } + + /** + * Creates a Vaadin {@link Validator} utilizing JSR-303 bean validation. + * + * @param beanClass + * bean class based on which the validation should be performed + * @param propertyName + * property to validate + */ + public BeanValidator(Class<?> beanClass, String propertyName) { + this.beanClass = beanClass; + this.propertyName = propertyName; + locale = Locale.getDefault(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.Validator#validate(java.lang.Object) + */ + public void validate(final Object value) throws InvalidValueException { + Set<?> violations = getJavaxBeanValidator().validateValue(beanClass, + propertyName, value); + if (violations.size() > 0) { + List<String> exceptions = new ArrayList<String>(); + for (Object v : violations) { + final ConstraintViolation<?> violation = (ConstraintViolation<?>) v; + String msg = getJavaxBeanValidatorFactory() + .getMessageInterpolator().interpolate( + violation.getMessageTemplate(), + new SimpleContext(value, violation + .getConstraintDescriptor()), locale); + exceptions.add(msg); + } + StringBuilder b = new StringBuilder(); + for (int i = 0; i < exceptions.size(); i++) { + if (i != 0) { + b.append("<br/>"); + } + b.append(exceptions.get(i)); + } + throw new InvalidValueException(b.toString()); + } + } + + /** + * Sets the locale used for validation error messages. + * + * Revalidation is not automatically triggered by setting the locale. + * + * @param locale + */ + public void setLocale(Locale locale) { + this.locale = locale; + } + + /** + * Gets the locale used for validation error messages. + * + * @return locale used for validation + */ + public Locale getLocale() { + return locale; + } + + /** + * Returns the underlying JSR-303 bean validator factory used. A factory is + * created using {@link Validation} if necessary. + * + * @return {@link ValidatorFactory} to use + */ + protected static ValidatorFactory getJavaxBeanValidatorFactory() { + if (factory == null) { + factory = Validation.buildDefaultValidatorFactory(); + } + + return factory; + } + + /** + * Returns a shared Validator instance to use. An instance is created using + * the validator factory if necessary and thereafter reused by the + * {@link BeanValidator} instance. + * + * @return the JSR-303 {@link javax.validation.Validator} to use + */ + protected javax.validation.Validator getJavaxBeanValidator() { + if (javaxBeanValidator == null) { + javaxBeanValidator = getJavaxBeanValidatorFactory().getValidator(); + } + + return javaxBeanValidator; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/data/validator/CompositeValidator.java b/src/com/vaadin/data/validator/CompositeValidator.java index 6227a3a2d8..956d773032 100644 --- a/src/com/vaadin/data/validator/CompositeValidator.java +++ b/src/com/vaadin/data/validator/CompositeValidator.java @@ -19,37 +19,44 @@ import com.vaadin.data.Validator; * <code>AND</code> and <code>OR</code>. * * @author Vaadin Ltd. - * @version - * @VERSION@ + * @version @VERSION@ * @since 3.0 */ @SuppressWarnings("serial") -public class CompositeValidator extends AbstractValidator { +public class CompositeValidator implements Validator { - /** - * The validators are combined with <code>AND</code> clause: validity of the - * composite implies validity of the all validators it is composed of must - * be valid. - */ - public static final int MODE_AND = 0; + public enum CombinationMode { + /** + * The validators are combined with <code>AND</code> clause: validity of + * the composite implies validity of the all validators it is composed + * of must be valid. + */ + AND, + /** + * The validators are combined with <code>OR</code> clause: validity of + * the composite implies that some of validators it is composed of must + * be valid. + */ + OR; + } /** - * The validators are combined with <code>OR</code> clause: validity of the - * composite implies that some of validators it is composed of must be - * valid. + * @deprecated from 7.0, use {@link CombinationMode#AND} instead   */ - public static final int MODE_OR = 1; - + @Deprecated + public static final CombinationMode MODE_AND = CombinationMode.AND; /** - * The validators are combined with and clause: validity of the composite - * implies validity of the all validators it is composed of + * @deprecated from 7.0, use {@link CombinationMode#OR} instead   */ - public static final int MODE_DEFAULT = MODE_AND; + @Deprecated + public static final CombinationMode MODE_OR = CombinationMode.OR; + + private String errorMessage; /** * Operation mode. */ - private int mode = MODE_DEFAULT; + private CombinationMode mode = CombinationMode.AND; /** * List of contained validators. @@ -61,14 +68,17 @@ public class CompositeValidator extends AbstractValidator { * message. */ public CompositeValidator() { - super(""); + this(CombinationMode.AND, ""); } /** * Constructs a composite validator in given mode. + * + * @param mode + * @param errorMessage */ - public CompositeValidator(int mode, String errorMessage) { - super(errorMessage); + public CompositeValidator(CombinationMode mode, String errorMessage) { + setErrorMessage(errorMessage); setMode(mode); } @@ -91,16 +101,15 @@ public class CompositeValidator extends AbstractValidator { * @throws Validator.InvalidValueException * if the value is not valid. */ - @Override public void validate(Object value) throws Validator.InvalidValueException { switch (mode) { - case MODE_AND: + case AND: for (Validator validator : validators) { validator.validate(value); } return; - case MODE_OR: + case OR: Validator.InvalidValueException first = null; for (Validator v : validators) { try { @@ -122,65 +131,32 @@ public class CompositeValidator extends AbstractValidator { throw first; } } - throw new IllegalStateException( - "The validator is in unsupported operation mode"); - } - - /** - * Checks the validity of the the given value. The value is valid, if: - * <ul> - * <li><code>MODE_AND</code>: All of the sub-validators are valid - * <li><code>MODE_OR</code>: Any of the sub-validators are valid - * </ul> - * - * @param value - * the value to check. - */ - public boolean isValid(Object value) { - switch (mode) { - case MODE_AND: - for (Validator v : validators) { - if (!v.isValid(value)) { - return false; - } - } - return true; - - case MODE_OR: - for (Validator v : validators) { - if (v.isValid(value)) { - return true; - } - } - return false; - } - throw new IllegalStateException( - "The valitor is in unsupported operation mode"); } /** * Gets the mode of the validator. * - * @return Operation mode of the validator: <code>MODE_AND</code> or - * <code>MODE_OR</code>. + * @return Operation mode of the validator: {@link CombinationMode#AND} or + * {@link CombinationMode#OR}. */ - public final int getMode() { + public final CombinationMode getMode() { return mode; } /** * Sets the mode of the validator. The valid modes are: * <ul> - * <li><code>MODE_AND</code> (default) - * <li><code>MODE_OR</code> + * <li>{@link CombinationMode#AND} (default) + * <li>{@link CombinationMode#OR} * </ul> * * @param mode * the mode to set. */ - public void setMode(int mode) { - if (mode != MODE_AND && mode != MODE_OR) { - throw new IllegalArgumentException("Mode " + mode + " unsupported"); + public void setMode(CombinationMode mode) { + if (mode == null) { + throw new IllegalArgumentException( + "The validator can't be set to null"); } this.mode = mode; } @@ -189,10 +165,9 @@ public class CompositeValidator extends AbstractValidator { * Gets the error message for the composite validator. If the error message * is null, original error messages of the sub-validators are used instead. */ - @Override public String getErrorMessage() { - if (super.getErrorMessage() != null) { - return super.getErrorMessage(); + if (errorMessage != null) { + return errorMessage; } // TODO Return composite error message @@ -240,11 +215,14 @@ public class CompositeValidator extends AbstractValidator { * validators of given type null is returned. * </p> * + * @param validatorType + * The type of validators to return + * * @return Collection<Validator> of validators compatible with given type - * that must apply or null if none fould. + * that must apply or null if none found. */ public Collection<Validator> getSubValidators(Class validatorType) { - if (mode != MODE_AND) { + if (mode != CombinationMode.AND) { return null; } @@ -266,4 +244,15 @@ public class CompositeValidator extends AbstractValidator { return found.isEmpty() ? null : found; } + /** + * Sets the message to be included in the exception in case the value does + * not validate. The exception message is typically shown to the end user. + * + * @param errorMessage + * the error message. + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + } diff --git a/src/com/vaadin/data/validator/DateRangeValidator.java b/src/com/vaadin/data/validator/DateRangeValidator.java new file mode 100644 index 0000000000..24f3d3ce10 --- /dev/null +++ b/src/com/vaadin/data/validator/DateRangeValidator.java @@ -0,0 +1,51 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.validator; + +import java.util.Date; + +import com.vaadin.ui.DateField.Resolution; + +/** + * Validator for validating that a Date is inside a given range. + * + * <p> + * Note that the comparison is done directly on the Date object so take care + * that the hours/minutes/seconds/milliseconds of the min/max values are + * properly set. + * </p> + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 + */ +public class DateRangeValidator extends RangeValidator<Date> { + + /** + * Creates a validator for checking that an Date is within a given range. + * <p> + * By default the range is inclusive i.e. both minValue and maxValue are + * valid values. Use {@link #setMinValueIncluded(boolean)} or + * {@link #setMaxValueIncluded(boolean)} to change it. + * </p> + * <p> + * Note that the comparison is done directly on the Date object so take care + * that the hours/minutes/seconds/milliseconds of the min/max values are + * properly set. + * </p> + * + * @param errorMessage + * the message to display in case the value does not validate. + * @param minValue + * The minimum value to accept or null for no limit + * @param maxValue + * The maximum value to accept or null for no limit + */ + public DateRangeValidator(String errorMessage, Date minValue, + Date maxValue, Resolution resolution) { + super(errorMessage, Date.class, minValue, maxValue); + } + +} diff --git a/src/com/vaadin/data/validator/DoubleRangeValidator.java b/src/com/vaadin/data/validator/DoubleRangeValidator.java new file mode 100644 index 0000000000..05ae2f827e --- /dev/null +++ b/src/com/vaadin/data/validator/DoubleRangeValidator.java @@ -0,0 +1,37 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.validator; + +/** + * Validator for validating that a {@link Double} is inside a given range. + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 + */ +@SuppressWarnings("serial") +public class DoubleRangeValidator extends RangeValidator<Double> { + + /** + * Creates a validator for checking that an Double is within a given range. + * + * By default the range is inclusive i.e. both minValue and maxValue are + * valid values. Use {@link #setMinValueIncluded(boolean)} or + * {@link #setMaxValueIncluded(boolean)} to change it. + * + * + * @param errorMessage + * the message to display in case the value does not validate. + * @param minValue + * The minimum value to accept or null for no limit + * @param maxValue + * The maximum value to accept or null for no limit + */ + public DoubleRangeValidator(String errorMessage, Double minValue, + Double maxValue) { + super(errorMessage, Double.class, minValue, maxValue); + } + +} diff --git a/src/com/vaadin/data/validator/DoubleValidator.java b/src/com/vaadin/data/validator/DoubleValidator.java index e90919c17d..18f1909add 100644 --- a/src/com/vaadin/data/validator/DoubleValidator.java +++ b/src/com/vaadin/data/validator/DoubleValidator.java @@ -12,7 +12,9 @@ package com.vaadin.data.validator; * @version * @VERSION@ * @since 5.4 + * @deprecated in Vaadin 7.0. Use an Double converter on the field instead. */ +@Deprecated @SuppressWarnings("serial") public class DoubleValidator extends AbstractStringValidator { @@ -22,13 +24,17 @@ public class DoubleValidator extends AbstractStringValidator { * * @param errorMessage * the message to display in case the value does not validate. + * @deprecated in Vaadin 7.0. Use a Double converter on the field instead + * and/or use a {@link DoubleRangeValidator} for validating that + * the value is inside a given range. */ + @Deprecated public DoubleValidator(String errorMessage) { super(errorMessage); } @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { try { Double.parseDouble(value); return true; @@ -37,4 +43,16 @@ public class DoubleValidator extends AbstractStringValidator { } } + @Override + public void validate(Object value) throws InvalidValueException { + if (value != null && value instanceof Double) { + // Allow Doubles to pass through the validator for easier + // migration. Otherwise a TextField connected to an double property + // with a DoubleValidator will fail. + return; + } + + super.validate(value); + } + } diff --git a/src/com/vaadin/data/validator/IntegerRangeValidator.java b/src/com/vaadin/data/validator/IntegerRangeValidator.java new file mode 100644 index 0000000000..c171dd97d8 --- /dev/null +++ b/src/com/vaadin/data/validator/IntegerRangeValidator.java @@ -0,0 +1,37 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.validator; + +/** + * Validator for validating that an {@link Integer} is inside a given range. + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 5.4 + */ +@SuppressWarnings("serial") +public class IntegerRangeValidator extends RangeValidator<Integer> { + + /** + * Creates a validator for checking that an Integer is within a given range. + * + * By default the range is inclusive i.e. both minValue and maxValue are + * valid values. Use {@link #setMinValueIncluded(boolean)} or + * {@link #setMaxValueIncluded(boolean)} to change it. + * + * + * @param errorMessage + * the message to display in case the value does not validate. + * @param minValue + * The minimum value to accept or null for no limit + * @param maxValue + * The maximum value to accept or null for no limit + */ + public IntegerRangeValidator(String errorMessage, Integer minValue, + Integer maxValue) { + super(errorMessage, Integer.class, minValue, maxValue); + } + +} diff --git a/src/com/vaadin/data/validator/IntegerValidator.java b/src/com/vaadin/data/validator/IntegerValidator.java index 50b45b90ce..88ae9f3f0b 100644 --- a/src/com/vaadin/data/validator/IntegerValidator.java +++ b/src/com/vaadin/data/validator/IntegerValidator.java @@ -12,8 +12,10 @@ package com.vaadin.data.validator; * @version * @VERSION@ * @since 5.4 + * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead. */ @SuppressWarnings("serial") +@Deprecated public class IntegerValidator extends AbstractStringValidator { /** @@ -22,14 +24,18 @@ public class IntegerValidator extends AbstractStringValidator { * * @param errorMessage * the message to display in case the value does not validate. + * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead + * and/or use an {@link IntegerRangeValidator} for validating + * that the value is inside a given range. */ + @Deprecated public IntegerValidator(String errorMessage) { super(errorMessage); } @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { try { Integer.parseInt(value); return true; @@ -38,4 +44,15 @@ public class IntegerValidator extends AbstractStringValidator { } } + @Override + public void validate(Object value) throws InvalidValueException { + if (value != null && value instanceof Integer) { + // Allow Integers to pass through the validator for easier + // migration. Otherwise a TextField connected to an integer property + // with an IntegerValidator will fail. + return; + } + + super.validate(value); + } } diff --git a/src/com/vaadin/data/validator/NullValidator.java b/src/com/vaadin/data/validator/NullValidator.java index 77f9a606b4..62b2580d48 100644 --- a/src/com/vaadin/data/validator/NullValidator.java +++ b/src/com/vaadin/data/validator/NullValidator.java @@ -51,17 +51,6 @@ public class NullValidator implements Validator { } /** - * Tests if the given value is valid. - * - * @param value - * the value to validate. - * @returns <code>true</code> for valid value, otherwise <code>false</code>. - */ - public boolean isValid(Object value) { - return onlyNullAllowed ? value == null : value != null; - } - - /** * Returns <code>true</code> if nulls are allowed otherwise * <code>false</code>. */ diff --git a/src/com/vaadin/data/validator/RangeValidator.java b/src/com/vaadin/data/validator/RangeValidator.java new file mode 100644 index 0000000000..433271274f --- /dev/null +++ b/src/com/vaadin/data/validator/RangeValidator.java @@ -0,0 +1,186 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.data.validator; + +/** + * An base implementation for validating any objects that implement + * {@link Comparable}. + * + * Verifies that the value is of the given type and within the (optionally) + * given limits. Typically you want to use a sub class of this like + * {@link IntegerRangeValidator}, {@link DoubleRangeValidator} or + * {@link DateRangeValidator} in applications. + * <p> + * Note that {@link RangeValidator} always accept null values. Make a field + * required to ensure that no empty values are accepted or override + * {@link #isValidValue(Comparable)}. + * </p> + * + * @param <T> + * The type of Number to validate. Must implement Comparable so that + * minimum and maximum checks work. + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 + */ +public class RangeValidator<T extends Comparable> extends AbstractValidator<T> { + + private T minValue = null; + private boolean minValueIncluded = true; + private T maxValue = null; + private boolean maxValueIncluded = true; + private Class<T> type; + + /** + * Creates a new range validator of the given type. + * + * @param errorMessage + * The error message to use if validation fails + * @param type + * The type of object the validator can validate. + * @param minValue + * The minimum value that should be accepted or null for no limit + * @param maxValue + * The maximum value that should be accepted or null for no limit + */ + public RangeValidator(String errorMessage, Class<T> type, T minValue, + T maxValue) { + super(errorMessage); + this.type = type; + this.minValue = minValue; + this.maxValue = maxValue; + } + + /** + * Checks if the minimum value is part of the accepted range + * + * @return true if the minimum value is part of the range, false otherwise + */ + public boolean isMinValueIncluded() { + return minValueIncluded; + } + + /** + * Sets if the minimum value is part of the accepted range + * + * @param minValueIncluded + * true if the minimum value should be part of the range, false + * otherwise + */ + public void setMinValueIncluded(boolean minValueIncluded) { + this.minValueIncluded = minValueIncluded; + } + + /** + * Checks if the maximum value is part of the accepted range + * + * @return true if the maximum value is part of the range, false otherwise + */ + public boolean isMaxValueIncluded() { + return maxValueIncluded; + } + + /** + * Sets if the maximum value is part of the accepted range + * + * @param maxValueIncluded + * true if the maximum value should be part of the range, false + * otherwise + */ + public void setMaxValueIncluded(boolean maxValueIncluded) { + this.maxValueIncluded = maxValueIncluded; + } + + /** + * Gets the minimum value of the range + * + * @return the minimum value + */ + public T getMinValue() { + return minValue; + } + + /** + * Sets the minimum value of the range. Use + * {@link #setMinValueIncluded(boolean)} to control whether this value is + * part of the range or not. + * + * @param minValue + * the minimum value + */ + public void setMinValue(T minValue) { + this.minValue = minValue; + } + + /** + * Gets the maximum value of the range + * + * @return the maximum value + */ + public T getMaxValue() { + return maxValue; + } + + /** + * Sets the maximum value of the range. Use + * {@link #setMaxValueIncluded(boolean)} to control whether this value is + * part of the range or not. + * + * @param maxValue + * the maximum value + */ + public void setMaxValue(T maxValue) { + this.maxValue = maxValue; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object + * ) + */ + @Override + protected boolean isValidValue(T value) { + if (value == null) { + return true; + } + + if (getMinValue() != null) { + // Ensure that the min limit is ok + int result = value.compareTo(getMinValue()); + if (result < 0) { + // value less than min value + return false; + } else if (result == 0 && !isMinValueIncluded()) { + // values equal and min value not included + return false; + } + } + if (getMaxValue() != null) { + // Ensure that the Max limit is ok + int result = value.compareTo(getMaxValue()); + if (result > 0) { + // value greater than max value + return false; + } else if (result == 0 && !isMaxValueIncluded()) { + // values equal and max value not included + return false; + } + } + return true; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.data.validator.AbstractValidator#getType() + */ + @Override + public Class<T> getType() { + return type; + } + +} diff --git a/src/com/vaadin/data/validator/RegexpValidator.java b/src/com/vaadin/data/validator/RegexpValidator.java index 684de7697c..8143d54c97 100644 --- a/src/com/vaadin/data/validator/RegexpValidator.java +++ b/src/com/vaadin/data/validator/RegexpValidator.java @@ -62,8 +62,15 @@ public class RegexpValidator extends AbstractStringValidator { this.complete = complete; } + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object + * ) + */ @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { if (complete) { return getMatcher(value).matches(); } else { diff --git a/src/com/vaadin/data/validator/StringLengthValidator.java b/src/com/vaadin/data/validator/StringLengthValidator.java index d7edea216d..54b2d28f58 100644 --- a/src/com/vaadin/data/validator/StringLengthValidator.java +++ b/src/com/vaadin/data/validator/StringLengthValidator.java @@ -14,11 +14,11 @@ package com.vaadin.data.validator; * @since 3.0 */ @SuppressWarnings("serial") -public class StringLengthValidator extends AbstractValidator { +public class StringLengthValidator extends AbstractStringValidator { - private int minLength = -1; + private Integer minLength = null; - private int maxLength = -1; + private Integer maxLength = null; private boolean allowNull = true; @@ -33,21 +33,25 @@ public class StringLengthValidator extends AbstractValidator { } /** - * Creates a new StringLengthValidator with a given error message, - * permissable lengths and null-string allowance. + * Creates a new StringLengthValidator with a given error message and + * minimum and maximum length limits. * * @param errorMessage * the message to display in case the value does not validate. * @param minLength - * the minimum permissible length of the string. + * the minimum permissible length of the string or null for no + * limit. A negative value for no limit is also supported for + * backwards compatibility. * @param maxLength - * the maximum permissible length of the string. + * the maximum permissible length of the string or null for no + * limit. A negative value for no limit is also supported for + * backwards compatibility. * @param allowNull * Are null strings permissible? This can be handled better by * setting a field as required or not. */ - public StringLengthValidator(String errorMessage, int minLength, - int maxLength, boolean allowNull) { + public StringLengthValidator(String errorMessage, Integer minLength, + Integer maxLength, boolean allowNull) { this(errorMessage); setMinLength(minLength); setMaxLength(maxLength); @@ -61,17 +65,14 @@ public class StringLengthValidator extends AbstractValidator { * the value to validate. * @return <code>true</code> for valid value, otherwise <code>false</code>. */ - public boolean isValid(Object value) { + @Override + protected boolean isValidValue(String value) { if (value == null) { return allowNull; } - final String s = value.toString(); - if (s == null) { - return allowNull; - } - final int len = s.length(); - if ((minLength >= 0 && len < minLength) - || (maxLength >= 0 && len > maxLength)) { + final int len = value.length(); + if ((minLength != null && minLength > -1 && len < minLength) + || (maxLength != null && maxLength > -1 && len > maxLength)) { return false; } return true; @@ -91,18 +92,18 @@ public class StringLengthValidator extends AbstractValidator { /** * Gets the maximum permissible length of the string. * - * @return the maximum length of the string. + * @return the maximum length of the string or null if there is no limit */ - public final int getMaxLength() { + public Integer getMaxLength() { return maxLength; } /** * Gets the minimum permissible length of the string. * - * @return the minimum length of the string. + * @return the minimum length of the string or null if there is no limit */ - public final int getMinLength() { + public Integer getMinLength() { return minLength; } @@ -119,12 +120,9 @@ public class StringLengthValidator extends AbstractValidator { * Sets the maximum permissible length of the string. * * @param maxLength - * the length to set. + * the maximum length to accept or null for no limit */ - public void setMaxLength(int maxLength) { - if (maxLength < -1) { - maxLength = -1; - } + public void setMaxLength(Integer maxLength) { this.maxLength = maxLength; } @@ -132,12 +130,9 @@ public class StringLengthValidator extends AbstractValidator { * Sets the minimum permissible length. * * @param minLength - * the length to set. + * the minimum length to accept or null for no limit */ - public void setMinLength(int minLength) { - if (minLength < -1) { - minLength = -1; - } + public void setMinLength(Integer minLength) { this.minLength = minLength; } diff --git a/src/com/vaadin/event/ActionManager.java b/src/com/vaadin/event/ActionManager.java index 13496c1deb..08e9c85043 100644 --- a/src/com/vaadin/event/ActionManager.java +++ b/src/com/vaadin/event/ActionManager.java @@ -11,6 +11,7 @@ import com.vaadin.event.Action.Handler; import com.vaadin.terminal.KeyMapper; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; +import com.vaadin.terminal.VariableOwner; import com.vaadin.ui.Component; /** @@ -37,7 +38,7 @@ public class ActionManager implements Action.Container, Action.Handler, protected HashSet<Handler> actionHandlers = null; /** Action mapper */ - protected KeyMapper actionMapper = null; + protected KeyMapper<Action> actionMapper = null; protected Component viewer; @@ -47,7 +48,8 @@ public class ActionManager implements Action.Container, Action.Handler, } - public <T extends Component & Container> ActionManager(T viewer) { + public <T extends Component & Container & VariableOwner> ActionManager( + T viewer) { this.viewer = viewer; } @@ -57,7 +59,8 @@ public class ActionManager implements Action.Container, Action.Handler, } } - public <T extends Component & Container> void setViewer(T viewer) { + public <T extends Component & Container & VariableOwner> void setViewer( + T viewer) { if (viewer == this.viewer) { return; } @@ -151,9 +154,9 @@ public class ActionManager implements Action.Container, Action.Handler, * removed but still exist on client side */ if (!actions.isEmpty() || clientHasActions) { - actionMapper = new KeyMapper(); + actionMapper = new KeyMapper<Action>(); - paintTarget.addVariable(viewer, "action", ""); + paintTarget.addVariable((VariableOwner) viewer, "action", ""); paintTarget.startTag("actions"); for (final Action a : actions) { @@ -195,7 +198,7 @@ public class ActionManager implements Action.Container, Action.Handler, public void handleActions(Map<String, Object> variables, Container sender) { if (variables.containsKey("action") && actionMapper != null) { final String key = (String) variables.get("action"); - final Action action = (Action) actionMapper.get(key); + final Action action = actionMapper.get(key); final Object target = variables.get("actiontarget"); if (action != null) { handleAction(action, sender, target); diff --git a/src/com/vaadin/event/FieldEvents.java b/src/com/vaadin/event/FieldEvents.java index 28fd6bb4f7..20e9fabb36 100644 --- a/src/com/vaadin/event/FieldEvents.java +++ b/src/com/vaadin/event/FieldEvents.java @@ -8,8 +8,10 @@ import java.io.Serializable; import java.lang.reflect.Method; import com.vaadin.terminal.gwt.client.EventId; +import com.vaadin.terminal.gwt.client.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.tools.ReflectTools; import com.vaadin.ui.Component; +import com.vaadin.ui.Component.Event; import com.vaadin.ui.Field; import com.vaadin.ui.Field.ValueChangeEvent; import com.vaadin.ui.TextField; @@ -247,4 +249,25 @@ public interface FieldEvents { public void removeListener(TextChangeListener listener); } + + public static abstract class FocusAndBlurServerRpcImpl implements + FocusAndBlurServerRpc { + + private Component component; + + public FocusAndBlurServerRpcImpl(Component component) { + this.component = component; + } + + protected abstract void fireEvent(Event event); + + public void blur() { + fireEvent(new BlurEvent(component)); + } + + public void focus() { + fireEvent(new FocusEvent(component)); + } + }; + } diff --git a/src/com/vaadin/event/ItemClickEvent.java b/src/com/vaadin/event/ItemClickEvent.java index c503f8f9c9..bb41398e8d 100644 --- a/src/com/vaadin/event/ItemClickEvent.java +++ b/src/com/vaadin/event/ItemClickEvent.java @@ -6,7 +6,6 @@ package com.vaadin.event; import java.io.Serializable; import java.lang.reflect.Method; -import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.event.MouseEvents.ClickEvent; @@ -84,19 +83,6 @@ public class ItemClickEvent extends ClickEvent implements Serializable { } /** - * Components implementing - * - * @link {@link Container} interface may support emitting - * {@link ItemClickEvent}s. - * - * @deprecated Use {@link ItemClickNotifier} instead. ItemClickSource was - * deprecated in version 6.5. - */ - @Deprecated - public interface ItemClickSource extends ItemClickNotifier { - } - - /** * The interface for adding and removing <code>ItemClickEvent</code> * listeners. By implementing this interface a class explicitly announces * that it will generate an <code>ItemClickEvent</code> when one of its diff --git a/src/com/vaadin/event/LayoutEvents.java b/src/com/vaadin/event/LayoutEvents.java index 2dda15fbf5..960fff00c0 100644 --- a/src/com/vaadin/event/LayoutEvents.java +++ b/src/com/vaadin/event/LayoutEvents.java @@ -7,9 +7,11 @@ import java.io.Serializable; import java.lang.reflect.Method; import com.vaadin.event.MouseEvents.ClickEvent; +import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.terminal.gwt.client.MouseEventDetails; import com.vaadin.tools.ReflectTools; import com.vaadin.ui.Component; +import com.vaadin.ui.ComponentContainer; public interface LayoutEvents { @@ -120,5 +122,17 @@ public interface LayoutEvents { return childComponent; } + public static LayoutClickEvent createEvent(ComponentContainer layout, + MouseEventDetails mouseDetails, Connector clickedConnector) { + Component clickedComponent = (Component) clickedConnector; + Component childComponent = clickedComponent; + while (childComponent != null + && childComponent.getParent() != layout) { + childComponent = childComponent.getParent(); + } + + return new LayoutClickEvent(layout, mouseDetails, clickedComponent, + childComponent); + } } }
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/ClientCriterion.java b/src/com/vaadin/event/dd/acceptcriteria/ClientCriterion.java index 920112360e..8b64106be7 100644 --- a/src/com/vaadin/event/dd/acceptcriteria/ClientCriterion.java +++ b/src/com/vaadin/event/dd/acceptcriteria/ClientCriterion.java @@ -9,13 +9,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterion; -import com.vaadin.ui.ClientWidget; /** * An annotation type used to point the client side counterpart for server side - * a {@link AcceptCriterion} class. Usage is pretty similar to - * {@link ClientWidget} which is used with Vaadin components that have a - * specialized client side counterpart. + * a {@link AcceptCriterion} class. * <p> * Annotations are used at GWT compilation phase, so remember to rebuild your * widgetset if you do changes for {@link ClientCriterion} mappings. diff --git a/src/com/vaadin/external/json/JSONArray.java b/src/com/vaadin/external/json/JSONArray.java new file mode 100644 index 0000000000..2307749ffc --- /dev/null +++ b/src/com/vaadin/external/json/JSONArray.java @@ -0,0 +1,963 @@ +package com.vaadin.external.json; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.IOException; +import java.io.Serializable; +import java.io.Writer; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +/** + * A JSONArray is an ordered sequence of values. Its external text form is a + * string wrapped in square brackets with commas separating the values. The + * internal form is an object having <code>get</code> and <code>opt</code> + * methods for accessing the values by index, and <code>put</code> methods for + * adding or replacing values. The values can be any of these types: + * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, + * <code>Number</code>, <code>String</code>, or the + * <code>JSONObject.NULL object</code>. + * <p> + * The constructor can convert a JSON text into a Java object. The + * <code>toString</code> method converts to JSON text. + * <p> + * A <code>get</code> method returns a value if one can be found, and throws an + * exception if one cannot be found. An <code>opt</code> method returns a + * default value instead of throwing an exception, and so is useful for + * obtaining optional values. + * <p> + * The generic <code>get()</code> and <code>opt()</code> methods return an + * object which you can cast or query for type. There are also typed + * <code>get</code> and <code>opt</code> methods that do type checking and type + * coercion for you. + * <p> + * The texts produced by the <code>toString</code> methods strictly conform to + * JSON syntax rules. The constructors are more forgiving in the texts they will + * accept: + * <ul> + * <li>An extra <code>,</code> <small>(comma)</small> may appear just + * before the closing bracket.</li> + * <li>The <code>null</code> value will be inserted when there is <code>,</code> + * <small>(comma)</small> elision.</li> + * <li>Strings may be quoted with <code>'</code> <small>(single + * quote)</small>.</li> + * <li>Strings do not need to be quoted at all if they do not begin with a quote + * or single quote, and if they do not contain leading or trailing spaces, and + * if they do not contain any of these characters: + * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and + * if they are not the reserved words <code>true</code>, <code>false</code>, or + * <code>null</code>.</li> + * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as + * well as by <code>,</code> <small>(comma)</small>.</li> + * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li> + * </ul> + * + * @author JSON.org + * @version 2011-08-25 + */ +public class JSONArray implements Serializable { + + /** + * The arrayList where the JSONArray's properties are kept. + */ + private ArrayList myArrayList; + + /** + * Construct an empty JSONArray. + */ + public JSONArray() { + myArrayList = new ArrayList(); + } + + /** + * Construct a JSONArray from a JSONTokener. + * + * @param x + * A JSONTokener + * @throws JSONException + * If there is a syntax error. + */ + public JSONArray(JSONTokener x) throws JSONException { + this(); + if (x.nextClean() != '[') { + throw x.syntaxError("A JSONArray text must start with '['"); + } + if (x.nextClean() != ']') { + x.back(); + for (;;) { + if (x.nextClean() == ',') { + x.back(); + myArrayList.add(JSONObject.NULL); + } else { + x.back(); + myArrayList.add(x.nextValue()); + } + switch (x.nextClean()) { + case ';': + case ',': + if (x.nextClean() == ']') { + return; + } + x.back(); + break; + case ']': + return; + default: + throw x.syntaxError("Expected a ',' or ']'"); + } + } + } + } + + /** + * Construct a JSONArray from a source JSON text. + * + * @param source + * A string that begins with <code>[</code> <small>(left + * bracket)</small> and ends with <code>]</code> + * <small>(right bracket)</small>. + * @throws JSONException + * If there is a syntax error. + */ + public JSONArray(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONArray from a Collection. + * + * @param collection + * A Collection. + */ + public JSONArray(Collection collection) { + myArrayList = new ArrayList(); + if (collection != null) { + Iterator iter = collection.iterator(); + while (iter.hasNext()) { + myArrayList.add(JSONObject.wrap(iter.next())); + } + } + } + + /** + * Construct a JSONArray from an array + * + * @throws JSONException + * If not an array. + */ + public JSONArray(Object array) throws JSONException { + this(); + if (array.getClass().isArray()) { + int length = Array.getLength(array); + for (int i = 0; i < length; i += 1) { + this.put(JSONObject.wrap(Array.get(array, i))); + } + } else { + throw new JSONException( + "JSONArray initial value should be a string or collection or array."); + } + } + + /** + * Get the object value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return An object value. + * @throws JSONException + * If there is no value for the index. + */ + public Object get(int index) throws JSONException { + Object object = opt(index); + if (object == null) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + return object; + } + + /** + * Get the boolean value associated with an index. The string values "true" + * and "false" are converted to boolean. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The truth. + * @throws JSONException + * If there is no value for the index or if the value is not + * convertible to boolean. + */ + public boolean getBoolean(int index) throws JSONException { + Object object = get(index); + if (object.equals(Boolean.FALSE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw new JSONException("JSONArray[" + index + "] is not a boolean."); + } + + /** + * Get the double value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a number. + */ + public double getDouble(int index) throws JSONException { + Object object = get(index); + try { + return object instanceof Number ? ((Number) object).doubleValue() + : Double.parseDouble((String) object); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the int value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value is not a number. + */ + public int getInt(int index) throws JSONException { + Object object = get(index); + try { + return object instanceof Number ? ((Number) object).intValue() + : Integer.parseInt((String) object); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the JSONArray associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A JSONArray value. + * @throws JSONException + * If there is no value for the index. or if the value is not a + * JSONArray + */ + public JSONArray getJSONArray(int index) throws JSONException { + Object object = get(index); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw new JSONException("JSONArray[" + index + "] is not a JSONArray."); + } + + /** + * Get the JSONObject associated with an index. + * + * @param index + * subscript + * @return A JSONObject value. + * @throws JSONException + * If there is no value for the index or if the value is not a + * JSONObject + */ + public JSONObject getJSONObject(int index) throws JSONException { + Object object = get(index); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw new JSONException("JSONArray[" + index + "] is not a JSONObject."); + } + + /** + * Get the long value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a number. + */ + public long getLong(int index) throws JSONException { + Object object = get(index); + try { + return object instanceof Number ? ((Number) object).longValue() + : Long.parseLong((String) object); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the string associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A string value. + * @throws JSONException + * If there is no string value for the index. + */ + public String getString(int index) throws JSONException { + Object object = get(index); + if (object instanceof String) { + return (String) object; + } + throw new JSONException("JSONArray[" + index + "] not a string."); + } + + /** + * Determine if the value is null. + * + * @param index + * The index must be between 0 and length() - 1. + * @return true if the value at the index is null, or if there is no value. + */ + public boolean isNull(int index) { + return JSONObject.NULL.equals(opt(index)); + } + + /** + * Make a string from the contents of this JSONArray. The + * <code>separator</code> string is inserted between each element. Warning: + * This method assumes that the data structure is acyclical. + * + * @param separator + * A string that will be inserted between the elements. + * @return a string. + * @throws JSONException + * If the array contains an invalid number. + */ + public String join(String separator) throws JSONException { + int len = length(); + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < len; i += 1) { + if (i > 0) { + sb.append(separator); + } + sb.append(JSONObject.valueToString(myArrayList.get(i))); + } + return sb.toString(); + } + + /** + * Get the number of elements in the JSONArray, included nulls. + * + * @return The length (or size). + */ + public int length() { + return myArrayList.size(); + } + + /** + * Get the optional object value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return An object value, or null if there is no object at that index. + */ + public Object opt(int index) { + return (index < 0 || index >= length()) ? null : myArrayList.get(index); + } + + /** + * Get the optional boolean value associated with an index. It returns false + * if there is no value at that index, or if the value is not Boolean.TRUE + * or the String "true". + * + * @param index + * The index must be between 0 and length() - 1. + * @return The truth. + */ + public boolean optBoolean(int index) { + return optBoolean(index, false); + } + + /** + * Get the optional boolean value associated with an index. It returns the + * defaultValue if there is no value at that index or if it is not a Boolean + * or the String "true" or "false" (case insensitive). + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * A boolean default. + * @return The truth. + */ + public boolean optBoolean(int index, boolean defaultValue) { + try { + return getBoolean(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional double value associated with an index. NaN is returned + * if there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public double optDouble(int index) { + return optDouble(index, Double.NaN); + } + + /** + * Get the optional double value associated with an index. The defaultValue + * is returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * subscript + * @param defaultValue + * The default value. + * @return The value. + */ + public double optDouble(int index, double defaultValue) { + try { + return getDouble(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional int value associated with an index. Zero is returned if + * there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public int optInt(int index) { + return optInt(index, 0); + } + + /** + * Get the optional int value associated with an index. The defaultValue is + * returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public int optInt(int index, int defaultValue) { + try { + return getInt(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional JSONArray associated with an index. + * + * @param index + * subscript + * @return A JSONArray value, or null if the index has no value, or if the + * value is not a JSONArray. + */ + public JSONArray optJSONArray(int index) { + Object o = opt(index); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get the optional JSONObject associated with an index. Null is returned if + * the key is not found, or null if the index has no value, or if the value + * is not a JSONObject. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A JSONObject value. + */ + public JSONObject optJSONObject(int index) { + Object o = opt(index); + return o instanceof JSONObject ? (JSONObject) o : null; + } + + /** + * Get the optional long value associated with an index. Zero is returned if + * there is no value for the index, or if the value is not a number and + * cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + */ + public long optLong(int index) { + return optLong(index, 0); + } + + /** + * Get the optional long value associated with an index. The defaultValue is + * returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public long optLong(int index, long defaultValue) { + try { + return getLong(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional string value associated with an index. It returns an + * empty string if there is no value at that index. If the value is not a + * string and is not null, then it is coverted to a string. + * + * @param index + * The index must be between 0 and length() - 1. + * @return A String value. + */ + public String optString(int index) { + return optString(index, ""); + } + + /** + * Get the optional string associated with an index. The defaultValue is + * returned if the key is not found. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return A String value. + */ + public String optString(int index, String defaultValue) { + Object object = opt(index); + return JSONObject.NULL.equals(object) ? object.toString() + : defaultValue; + } + + /** + * Append a boolean value. This increases the array's length by one. + * + * @param value + * A boolean value. + * @return this. + */ + public JSONArray put(boolean value) { + put(value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param value + * A Collection value. + * @return this. + */ + public JSONArray put(Collection value) { + put(new JSONArray(value)); + return this; + } + + /** + * Append a double value. This increases the array's length by one. + * + * @param value + * A double value. + * @throws JSONException + * if the value is not finite. + * @return this. + */ + public JSONArray put(double value) throws JSONException { + Double d = new Double(value); + JSONObject.testValidity(d); + put(d); + return this; + } + + /** + * Append an int value. This increases the array's length by one. + * + * @param value + * An int value. + * @return this. + */ + public JSONArray put(int value) { + put(new Integer(value)); + return this; + } + + /** + * Append an long value. This increases the array's length by one. + * + * @param value + * A long value. + * @return this. + */ + public JSONArray put(long value) { + put(new Long(value)); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject which + * is produced from a Map. + * + * @param value + * A Map value. + * @return this. + */ + public JSONArray put(Map value) { + put(new JSONObject(value)); + return this; + } + + /** + * Append an object value. This increases the array's length by one. + * + * @param value + * An object value. The value should be a Boolean, Double, + * Integer, JSONArray, JSONObject, Long, or String, or the + * JSONObject.NULL object. + * @return this. + */ + public JSONArray put(Object value) { + myArrayList.add(value); + return this; + } + + /** + * Put or replace a boolean value in the JSONArray. If the index is greater + * than the length of the JSONArray, then null elements will be added as + * necessary to pad it out. + * + * @param index + * The subscript. + * @param value + * A boolean value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, boolean value) throws JSONException { + put(index, value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param index + * The subscript. + * @param value + * A Collection value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is not finite. + */ + public JSONArray put(int index, Collection value) throws JSONException { + put(index, new JSONArray(value)); + return this; + } + + /** + * Put or replace a double value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A double value. + * @return this. + * @throws JSONException + * If the index is negative or if the value is not finite. + */ + public JSONArray put(int index, double value) throws JSONException { + put(index, new Double(value)); + return this; + } + + /** + * Put or replace an int value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * An int value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, int value) throws JSONException { + put(index, new Integer(value)); + return this; + } + + /** + * Put or replace a long value. If the index is greater than the length of + * the JSONArray, then null elements will be added as necessary to pad it + * out. + * + * @param index + * The subscript. + * @param value + * A long value. + * @return this. + * @throws JSONException + * If the index is negative. + */ + public JSONArray put(int index, long value) throws JSONException { + put(index, new Long(value)); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject that + * is produced from a Map. + * + * @param index + * The subscript. + * @param value + * The Map value. + * @return this. + * @throws JSONException + * If the index is negative or if the the value is an invalid + * number. + */ + public JSONArray put(int index, Map value) throws JSONException { + put(index, new JSONObject(value)); + return this; + } + + /** + * Put or replace an object value in the JSONArray. If the index is greater + * than the length of the JSONArray, then null elements will be added as + * necessary to pad it out. + * + * @param index + * The subscript. + * @param value + * The value to put into the array. The value should be a + * Boolean, Double, Integer, JSONArray, JSONObject, Long, or + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the index is negative or if the the value is an invalid + * number. + */ + public JSONArray put(int index, Object value) throws JSONException { + JSONObject.testValidity(value); + if (index < 0) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + if (index < length()) { + myArrayList.set(index, value); + } else { + while (index != length()) { + put(JSONObject.NULL); + } + put(value); + } + return this; + } + + /** + * Remove an index and close the hole. + * + * @param index + * The index of the element to be removed. + * @return The value that was associated with the index, or null if there + * was no value. + */ + public Object remove(int index) { + Object o = opt(index); + myArrayList.remove(index); + return o; + } + + /** + * Produce a JSONObject by combining a JSONArray of names with the values of + * this JSONArray. + * + * @param names + * A JSONArray containing a list of key strings. These will be + * paired with the values. + * @return A JSONObject, or null if there are no names or if this JSONArray + * has no values. + * @throws JSONException + * If any of the names are null. + */ + public JSONObject toJSONObject(JSONArray names) throws JSONException { + if (names == null || names.length() == 0 || length() == 0) { + return null; + } + JSONObject jo = new JSONObject(); + for (int i = 0; i < names.length(); i += 1) { + jo.put(names.getString(i), opt(i)); + } + return jo; + } + + /** + * Make a JSON text of this JSONArray. For compactness, no unnecessary + * whitespace is added. If it is not possible to produce a syntactically + * correct JSON text then null will be returned instead. This could occur if + * the array contains an invalid number. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @return a printable, displayable, transmittable representation of the + * array. + */ + @Override + public String toString() { + try { + return '[' + join(",") + ']'; + } catch (Exception e) { + return null; + } + } + + /** + * Make a prettyprinted JSON text of this JSONArray. Warning: This method + * assumes that the data structure is acyclical. + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @return a printable, displayable, transmittable representation of the + * object, beginning with <code>[</code> <small>(left + * bracket)</small> and ending with <code>]</code> + * <small>(right bracket)</small>. + * @throws JSONException + */ + public String toString(int indentFactor) throws JSONException { + return toString(indentFactor, 0); + } + + /** + * Make a prettyprinted JSON text of this JSONArray. Warning: This method + * assumes that the data structure is acyclical. + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indention of the top level. + * @return a printable, displayable, transmittable representation of the + * array. + * @throws JSONException + */ + String toString(int indentFactor, int indent) throws JSONException { + int len = length(); + if (len == 0) { + return "[]"; + } + int i; + StringBuffer sb = new StringBuffer("["); + if (len == 1) { + sb.append(JSONObject.valueToString(myArrayList.get(0), + indentFactor, indent)); + } else { + int newindent = indent + indentFactor; + sb.append('\n'); + for (i = 0; i < len; i += 1) { + if (i > 0) { + sb.append(",\n"); + } + for (int j = 0; j < newindent; j += 1) { + sb.append(' '); + } + sb.append(JSONObject.valueToString(myArrayList.get(i), + indentFactor, newindent)); + } + sb.append('\n'); + for (i = 0; i < indent; i += 1) { + sb.append(' '); + } + } + sb.append(']'); + return sb.toString(); + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. For + * compactness, no whitespace is added. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer) throws JSONException { + try { + boolean b = false; + int len = length(); + + writer.write('['); + + for (int i = 0; i < len; i += 1) { + if (b) { + writer.write(','); + } + Object v = myArrayList.get(i); + if (v instanceof JSONObject) { + ((JSONObject) v).write(writer); + } else if (v instanceof JSONArray) { + ((JSONArray) v).write(writer); + } else { + writer.write(JSONObject.valueToString(v)); + } + b = true; + } + writer.write(']'); + return writer; + } catch (IOException e) { + throw new JSONException(e); + } + } +}
\ No newline at end of file diff --git a/src/com/vaadin/external/json/JSONException.java b/src/com/vaadin/external/json/JSONException.java new file mode 100644 index 0000000000..fecc38974e --- /dev/null +++ b/src/com/vaadin/external/json/JSONException.java @@ -0,0 +1,31 @@ +package com.vaadin.external.json; + +/** + * The JSONException is thrown by the JSON.org classes when things are amiss. + * + * @author JSON.org + * @version 2010-12-24 + */ +public class JSONException extends Exception { + private static final long serialVersionUID = 0; + private Throwable cause; + + /** + * Constructs a JSONException with an explanatory message. + * + * @param message + * Detail about the reason for the exception. + */ + public JSONException(String message) { + super(message); + } + + public JSONException(Throwable cause) { + super(cause.getMessage()); + this.cause = cause; + } + + public Throwable getCause() { + return this.cause; + } +} diff --git a/src/com/vaadin/external/json/JSONObject.java b/src/com/vaadin/external/json/JSONObject.java new file mode 100644 index 0000000000..ba772933be --- /dev/null +++ b/src/com/vaadin/external/json/JSONObject.java @@ -0,0 +1,1693 @@ +package com.vaadin.external.json; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.IOException; +import java.io.Serializable; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * A JSONObject is an unordered collection of name/value pairs. Its external + * form is a string wrapped in curly braces with colons between the names and + * values, and commas between the values and names. The internal form is an + * object having <code>get</code> and <code>opt</code> methods for accessing the + * values by name, and <code>put</code> methods for adding or replacing values + * by name. The values can be any of these types: <code>Boolean</code>, + * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>, + * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject + * constructor can be used to convert an external form JSON text into an + * internal form whose values can be retrieved with the <code>get</code> and + * <code>opt</code> methods, or to convert values into a JSON text using the + * <code>put</code> and <code>toString</code> methods. A <code>get</code> method + * returns a value if one can be found, and throws an exception if one cannot be + * found. An <code>opt</code> method returns a default value instead of throwing + * an exception, and so is useful for obtaining optional values. + * <p> + * The generic <code>get()</code> and <code>opt()</code> methods return an + * object, which you can cast or query for type. There are also typed + * <code>get</code> and <code>opt</code> methods that do type checking and type + * coercion for you. The opt methods differ from the get methods in that they do + * not throw. Instead, they return a specified value, such as null. + * <p> + * The <code>put</code> methods add or replace values in an object. For example, + * + * <pre> + * myString = new JSONObject().put("JSON", "Hello, World!").toString(); + * </pre> + * + * produces the string <code>{"JSON": "Hello, World"}</code>. + * <p> + * The texts produced by the <code>toString</code> methods strictly conform to + * the JSON syntax rules. The constructors are more forgiving in the texts they + * will accept: + * <ul> + * <li>An extra <code>,</code> <small>(comma)</small> may appear just + * before the closing brace.</li> + * <li>Strings may be quoted with <code>'</code> <small>(single + * quote)</small>.</li> + * <li>Strings do not need to be quoted at all if they do not begin with a quote + * or single quote, and if they do not contain leading or trailing spaces, and + * if they do not contain any of these characters: + * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and + * if they are not the reserved words <code>true</code>, <code>false</code>, or + * <code>null</code>.</li> + * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as by + * <code>:</code>.</li> + * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as + * well as by <code>,</code> <small>(comma)</small>.</li> + * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li> + * </ul> + * + * @author JSON.org + * @version 2011-10-16 + */ +public class JSONObject implements Serializable { + + /** + * JSONObject.NULL is equivalent to the value that JavaScript calls null, + * whilst Java's null is equivalent to the value that JavaScript calls + * undefined. + */ + private static final class Null implements Serializable { + + /** + * There is only intended to be a single instance of the NULL object, so + * the clone method returns itself. + * + * @return NULL. + */ + @Override + protected final Object clone() { + return this; + } + + /** + * A Null object is equal to the null value and to itself. + * + * @param object + * An object to test for nullness. + * @return true if the object parameter is the JSONObject.NULL object or + * null. + */ + @Override + public boolean equals(Object object) { + return object == null || object == this; + } + + /** + * Get the "null" string value. + * + * @return The string "null". + */ + @Override + public String toString() { + return "null"; + } + } + + /** + * The map where the JSONObject's properties are kept. + */ + private Map map; + + /** + * It is sometimes more convenient and less ambiguous to have a + * <code>NULL</code> object than to use Java's <code>null</code> value. + * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>. + * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>. + */ + public static final Object NULL = new Null(); + + /** + * Construct an empty JSONObject. + */ + public JSONObject() { + map = new HashMap(); + } + + /** + * Construct a JSONObject from a subset of another JSONObject. An array of + * strings is used to identify the keys that should be copied. Missing keys + * are ignored. + * + * @param jo + * A JSONObject. + * @param names + * An array of strings. + * @throws JSONException + * @exception JSONException + * If a value is a non-finite number or if a name is + * duplicated. + */ + public JSONObject(JSONObject jo, String[] names) { + this(); + for (int i = 0; i < names.length; i += 1) { + try { + putOnce(names[i], jo.opt(names[i])); + } catch (Exception ignore) { + } + } + } + + /** + * Construct a JSONObject from a JSONTokener. + * + * @param x + * A JSONTokener object containing the source string. + * @throws JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(JSONTokener x) throws JSONException { + this(); + char c; + String key; + + if (x.nextClean() != '{') { + throw x.syntaxError("A JSONObject text must begin with '{'"); + } + for (;;) { + c = x.nextClean(); + switch (c) { + case 0: + throw x.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + default: + x.back(); + key = x.nextValue().toString(); + } + + // The key is followed by ':'. We will also tolerate '=' or '=>'. + + c = x.nextClean(); + if (c == '=') { + if (x.next() != '>') { + x.back(); + } + } else if (c != ':') { + throw x.syntaxError("Expected a ':' after a key"); + } + putOnce(key, x.nextValue()); + + // Pairs are separated by ','. We will also tolerate ';'. + + switch (x.nextClean()) { + case ';': + case ',': + if (x.nextClean() == '}') { + return; + } + x.back(); + break; + case '}': + return; + default: + throw x.syntaxError("Expected a ',' or '}'"); + } + } + } + + /** + * Construct a JSONObject from a Map. + * + * @param map + * A map object that can be used to initialize the contents of + * the JSONObject. + * @throws JSONException + */ + public JSONObject(Map map) { + this.map = new HashMap(); + if (map != null) { + Iterator i = map.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry e = (Map.Entry) i.next(); + Object value = e.getValue(); + if (value != null) { + this.map.put(e.getKey(), wrap(value)); + } + } + } + } + + /** + * Construct a JSONObject from an Object using bean getters. It reflects on + * all of the public methods of the object. For each of the methods with no + * parameters and a name starting with <code>"get"</code> or + * <code>"is"</code> followed by an uppercase letter, the method is invoked, + * and a key and the value returned from the getter method are put into the + * new JSONObject. + * + * The key is formed by removing the <code>"get"</code> or <code>"is"</code> + * prefix. If the second remaining character is not upper case, then the + * first character is converted to lower case. + * + * For example, if an object has a method named <code>"getName"</code>, and + * if the result of calling <code>object.getName()</code> is + * <code>"Larry Fine"</code>, then the JSONObject will contain + * <code>"name": "Larry Fine"</code>. + * + * @param bean + * An object that has getter methods that should be used to make + * a JSONObject. + */ + public JSONObject(Object bean) { + this(); + populateMap(bean); + } + + /** + * Construct a JSONObject from an Object, using reflection to find the + * public members. The resulting JSONObject's keys will be the strings from + * the names array, and the values will be the field values associated with + * those keys in the object. If a key is not found or not visible, then it + * will not be copied into the new JSONObject. + * + * @param object + * An object that has fields that should be used to make a + * JSONObject. + * @param names + * An array of strings, the names of the fields to be obtained + * from the object. + */ + public JSONObject(Object object, String names[]) { + this(); + Class c = object.getClass(); + for (int i = 0; i < names.length; i += 1) { + String name = names[i]; + try { + putOpt(name, c.getField(name).get(object)); + } catch (Exception ignore) { + } + } + } + + /** + * Construct a JSONObject from a source JSON text string. This is the most + * commonly used JSONObject constructor. + * + * @param source + * A string beginning with <code>{</code> <small>(left + * brace)</small> and ending with <code>}</code> + * <small>(right brace)</small>. + * @exception JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONObject from a ResourceBundle. + * + * @param baseName + * The ResourceBundle base name. + * @param locale + * The Locale to load the ResourceBundle for. + * @throws JSONException + * If any JSONExceptions are detected. + */ + public JSONObject(String baseName, Locale locale) throws JSONException { + this(); + ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, + Thread.currentThread().getContextClassLoader()); + + // Iterate through the keys in the bundle. + + Enumeration keys = bundle.getKeys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (key instanceof String) { + + // Go through the path, ensuring that there is a nested + // JSONObject for each + // segment except the last. Add the value using the last + // segment's name into + // the deepest nested JSONObject. + + String[] path = ((String) key).split("\\."); + int last = path.length - 1; + JSONObject target = this; + for (int i = 0; i < last; i += 1) { + String segment = path[i]; + JSONObject nextTarget = target.optJSONObject(segment); + if (nextTarget == null) { + nextTarget = new JSONObject(); + target.put(segment, nextTarget); + } + target = nextTarget; + } + target.put(path[last], bundle.getString((String) key)); + } + } + } + + /** + * Accumulate values under a key. It is similar to the put method except + * that if there is already an object stored under the key then a JSONArray + * is stored under the key to hold all of the accumulated values. If there + * is already a JSONArray, then the new value is appended to it. In + * contrast, the put method replaces the previous value. + * + * If only one value is accumulated that is not a JSONArray, then the result + * will be the same as using put. But if multiple values are accumulated, + * then the result will be like append. + * + * @param key + * A key string. + * @param value + * An object to be accumulated under the key. + * @return this. + * @throws JSONException + * If the value is an invalid number or if the key is null. + */ + public JSONObject accumulate(String key, Object value) throws JSONException { + testValidity(value); + Object object = opt(key); + if (object == null) { + put(key, value instanceof JSONArray ? new JSONArray().put(value) + : value); + } else if (object instanceof JSONArray) { + ((JSONArray) object).put(value); + } else { + put(key, new JSONArray().put(object).put(value)); + } + return this; + } + + /** + * Append values to the array under a key. If the key does not exist in the + * JSONObject, then the key is put in the JSONObject with its value being a + * JSONArray containing the value parameter. If the key was already + * associated with a JSONArray, then the value parameter is appended to it. + * + * @param key + * A key string. + * @param value + * An object to be accumulated under the key. + * @return this. + * @throws JSONException + * If the key is null or if the current value associated with + * the key is not a JSONArray. + */ + public JSONObject append(String key, Object value) throws JSONException { + testValidity(value); + Object object = opt(key); + if (object == null) { + put(key, new JSONArray().put(value)); + } else if (object instanceof JSONArray) { + put(key, ((JSONArray) object).put(value)); + } else { + throw new JSONException("JSONObject[" + key + + "] is not a JSONArray."); + } + return this; + } + + /** + * Produce a string from a double. The string "null" will be returned if the + * number is not finite. + * + * @param d + * A double. + * @return A String. + */ + public static String doubleToString(double d) { + if (Double.isInfinite(d) || Double.isNaN(d)) { + return "null"; + } + + // Shave off trailing zeros and decimal point, if possible. + + String string = Double.toString(d); + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get the value object associated with a key. + * + * @param key + * A key string. + * @return The object associated with the key. + * @throws JSONException + * if the key is not found. + */ + public Object get(String key) throws JSONException { + if (key == null) { + throw new JSONException("Null key."); + } + Object object = opt(key); + if (object == null) { + throw new JSONException("JSONObject[" + quote(key) + "] not found."); + } + return object; + } + + /** + * Get the boolean value associated with a key. + * + * @param key + * A key string. + * @return The truth. + * @throws JSONException + * if the value is not a Boolean or the String "true" or + * "false". + */ + public boolean getBoolean(String key) throws JSONException { + Object object = get(key); + if (object.equals(Boolean.FALSE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw new JSONException("JSONObject[" + quote(key) + + "] is not a Boolean."); + } + + /** + * Get the double value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value is not a Number + * object and cannot be converted to a number. + */ + public double getDouble(String key) throws JSONException { + Object object = get(key); + try { + return object instanceof Number ? ((Number) object).doubleValue() + : Double.parseDouble((String) object); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] is not a number."); + } + } + + /** + * Get the int value associated with a key. + * + * @param key + * A key string. + * @return The integer value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an integer. + */ + public int getInt(String key) throws JSONException { + Object object = get(key); + try { + return object instanceof Number ? ((Number) object).intValue() + : Integer.parseInt((String) object); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] is not an int."); + } + } + + /** + * Get the JSONArray value associated with a key. + * + * @param key + * A key string. + * @return A JSONArray which is the value. + * @throws JSONException + * if the key is not found or if the value is not a JSONArray. + */ + public JSONArray getJSONArray(String key) throws JSONException { + Object object = get(key); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw new JSONException("JSONObject[" + quote(key) + + "] is not a JSONArray."); + } + + /** + * Get the JSONObject value associated with a key. + * + * @param key + * A key string. + * @return A JSONObject which is the value. + * @throws JSONException + * if the key is not found or if the value is not a JSONObject. + */ + public JSONObject getJSONObject(String key) throws JSONException { + Object object = get(key); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw new JSONException("JSONObject[" + quote(key) + + "] is not a JSONObject."); + } + + /** + * Get the long value associated with a key. + * + * @param key + * A key string. + * @return The long value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to a long. + */ + public long getLong(String key) throws JSONException { + Object object = get(key); + try { + return object instanceof Number ? ((Number) object).longValue() + : Long.parseLong((String) object); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] is not a long."); + } + } + + /** + * Get an array of field names from a JSONObject. + * + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(JSONObject jo) { + int length = jo.length(); + if (length == 0) { + return null; + } + Iterator iterator = jo.keys(); + String[] names = new String[length]; + int i = 0; + while (iterator.hasNext()) { + names[i] = (String) iterator.next(); + i += 1; + } + return names; + } + + /** + * Get an array of field names from an Object. + * + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(Object object) { + if (object == null) { + return null; + } + Class klass = object.getClass(); + Field[] fields = klass.getFields(); + int length = fields.length; + if (length == 0) { + return null; + } + String[] names = new String[length]; + for (int i = 0; i < length; i += 1) { + names[i] = fields[i].getName(); + } + return names; + } + + /** + * Get the string associated with a key. + * + * @param key + * A key string. + * @return A string which is the value. + * @throws JSONException + * if there is no string value for the key. + */ + public String getString(String key) throws JSONException { + Object object = get(key); + if (object instanceof String) { + return (String) object; + } + throw new JSONException("JSONObject[" + quote(key) + "] not a string."); + } + + /** + * Determine if the JSONObject contains a specific key. + * + * @param key + * A key string. + * @return true if the key exists in the JSONObject. + */ + public boolean has(String key) { + return map.containsKey(key); + } + + /** + * Increment a property of a JSONObject. If there is no such property, + * create one with a value of 1. If there is such a property, and if it is + * an Integer, Long, Double, or Float, then add one to it. + * + * @param key + * A key string. + * @return this. + * @throws JSONException + * If there is already a property with this name that is not an + * Integer, Long, Double, or Float. + */ + public JSONObject increment(String key) throws JSONException { + Object value = opt(key); + if (value == null) { + put(key, 1); + } else if (value instanceof Integer) { + put(key, ((Integer) value).intValue() + 1); + } else if (value instanceof Long) { + put(key, ((Long) value).longValue() + 1); + } else if (value instanceof Double) { + put(key, ((Double) value).doubleValue() + 1); + } else if (value instanceof Float) { + put(key, ((Float) value).floatValue() + 1); + } else { + throw new JSONException("Unable to increment [" + quote(key) + "]."); + } + return this; + } + + /** + * Determine if the value associated with the key is null or if there is no + * value. + * + * @param key + * A key string. + * @return true if there is no value associated with the key or if the value + * is the JSONObject.NULL object. + */ + public boolean isNull(String key) { + return JSONObject.NULL.equals(opt(key)); + } + + /** + * Get an enumeration of the keys of the JSONObject. + * + * @return An iterator of the keys. + */ + public Iterator keys() { + return map.keySet().iterator(); + } + + /** + * Get the number of keys stored in the JSONObject. + * + * @return The number of keys in the JSONObject. + */ + public int length() { + return map.size(); + } + + /** + * Produce a JSONArray containing the names of the elements of this + * JSONObject. + * + * @return A JSONArray containing the key strings, or null if the JSONObject + * is empty. + */ + public JSONArray names() { + JSONArray ja = new JSONArray(); + Iterator keys = keys(); + while (keys.hasNext()) { + ja.put(keys.next()); + } + return ja.length() == 0 ? null : ja; + } + + /** + * Produce a string from a Number. + * + * @param number + * A Number + * @return A String. + * @throws JSONException + * If n is a non-finite number. + */ + public static String numberToString(Number number) throws JSONException { + if (number == null) { + throw new JSONException("Null pointer"); + } + testValidity(number); + + // Shave off trailing zeros and decimal point, if possible. + + String string = number.toString(); + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get an optional value associated with a key. + * + * @param key + * A key string. + * @return An object which is the value, or null if there is no value. + */ + public Object opt(String key) { + return key == null ? null : map.get(key); + } + + /** + * Get an optional boolean associated with a key. It returns false if there + * is no such key, or if the value is not Boolean.TRUE or the String "true". + * + * @param key + * A key string. + * @return The truth. + */ + public boolean optBoolean(String key) { + return optBoolean(key, false); + } + + /** + * Get an optional boolean associated with a key. It returns the + * defaultValue if there is no such key, or if it is not a Boolean or the + * String "true" or "false" (case insensitive). + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return The truth. + */ + public boolean optBoolean(String key, boolean defaultValue) { + try { + return getBoolean(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional double associated with a key, or NaN if there is no such + * key or if its value is not a number. If the value is a string, an attempt + * will be made to evaluate it as a number. + * + * @param key + * A string which is the key. + * @return An object which is the value. + */ + public double optDouble(String key) { + return optDouble(key, Double.NaN); + } + + /** + * Get an optional double associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public double optDouble(String key, double defaultValue) { + try { + return getDouble(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional int value associated with a key, or zero if there is no + * such key or if the value is not a number. If the value is a string, an + * attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public int optInt(String key) { + return optInt(key, 0); + } + + /** + * Get an optional int value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public int optInt(String key, int defaultValue) { + try { + return getInt(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional JSONArray associated with a key. It returns null if there + * is no such key, or if its value is not a JSONArray. + * + * @param key + * A key string. + * @return A JSONArray which is the value. + */ + public JSONArray optJSONArray(String key) { + Object o = opt(key); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get an optional JSONObject associated with a key. It returns null if + * there is no such key, or if its value is not a JSONObject. + * + * @param key + * A key string. + * @return A JSONObject which is the value. + */ + public JSONObject optJSONObject(String key) { + Object object = opt(key); + return object instanceof JSONObject ? (JSONObject) object : null; + } + + /** + * Get an optional long value associated with a key, or zero if there is no + * such key or if the value is not a number. If the value is a string, an + * attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @return An object which is the value. + */ + public long optLong(String key) { + return optLong(key, 0); + } + + /** + * Get an optional long value associated with a key, or the default if there + * is no such key or if the value is not a number. If the value is a string, + * an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public long optLong(String key, long defaultValue) { + try { + return getLong(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional string associated with a key. It returns an empty string + * if there is no such key. If the value is not a string and is not null, + * then it is converted to a string. + * + * @param key + * A key string. + * @return A string which is the value. + */ + public String optString(String key) { + return optString(key, ""); + } + + /** + * Get an optional string associated with a key. It returns the defaultValue + * if there is no such key. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return A string which is the value. + */ + public String optString(String key, String defaultValue) { + Object object = opt(key); + return NULL.equals(object) ? defaultValue : object.toString(); + } + + private void populateMap(Object bean) { + Class klass = bean.getClass(); + + // If klass is a System class then set includeSuperClass to false. + + boolean includeSuperClass = klass.getClassLoader() != null; + + Method[] methods = (includeSuperClass) ? klass.getMethods() : klass + .getDeclaredMethods(); + for (int i = 0; i < methods.length; i += 1) { + try { + Method method = methods[i]; + if (Modifier.isPublic(method.getModifiers())) { + String name = method.getName(); + String key = ""; + if (name.startsWith("get")) { + if (name.equals("getClass") + || name.equals("getDeclaringClass")) { + key = ""; + } else { + key = name.substring(3); + } + } else if (name.startsWith("is")) { + key = name.substring(2); + } + if (key.length() > 0 + && Character.isUpperCase(key.charAt(0)) + && method.getParameterTypes().length == 0) { + if (key.length() == 1) { + key = key.toLowerCase(); + } else if (!Character.isUpperCase(key.charAt(1))) { + key = key.substring(0, 1).toLowerCase() + + key.substring(1); + } + + Object result = method.invoke(bean, (Object[]) null); + if (result != null) { + map.put(key, wrap(result)); + } + } + } + } catch (Exception ignore) { + } + } + } + + /** + * Put a key/boolean pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A boolean which is the value. + * @return this. + * @throws JSONException + * If the key is null. + */ + public JSONObject put(String key, boolean value) throws JSONException { + put(key, value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a + * JSONArray which is produced from a Collection. + * + * @param key + * A key string. + * @param value + * A Collection value. + * @return this. + * @throws JSONException + */ + public JSONObject put(String key, Collection value) throws JSONException { + put(key, new JSONArray(value)); + return this; + } + + /** + * Put a key/double pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A double which is the value. + * @return this. + * @throws JSONException + * If the key is null or if the number is invalid. + */ + public JSONObject put(String key, double value) throws JSONException { + put(key, new Double(value)); + return this; + } + + /** + * Put a key/int pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * An int which is the value. + * @return this. + * @throws JSONException + * If the key is null. + */ + public JSONObject put(String key, int value) throws JSONException { + put(key, new Integer(value)); + return this; + } + + /** + * Put a key/long pair in the JSONObject. + * + * @param key + * A key string. + * @param value + * A long which is the value. + * @return this. + * @throws JSONException + * If the key is null. + */ + public JSONObject put(String key, long value) throws JSONException { + put(key, new Long(value)); + return this; + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a + * JSONObject which is produced from a Map. + * + * @param key + * A key string. + * @param value + * A Map value. + * @return this. + * @throws JSONException + */ + public JSONObject put(String key, Map value) throws JSONException { + put(key, new JSONObject(value)); + return this; + } + + /** + * Put a key/value pair in the JSONObject. If the value is null, then the + * key will be removed from the JSONObject if it is present. + * + * @param key + * A key string. + * @param value + * An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is non-finite number or if the key is null. + */ + public JSONObject put(String key, Object value) throws JSONException { + if (key == null) { + throw new JSONException("Null key."); + } + if (value != null) { + testValidity(value); + map.put(key, value); + } else { + remove(key); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value + * are both non-null, and only if there is not already a member with that + * name. + * + * @param key + * @param value + * @return his. + * @throws JSONException + * if the key is a duplicate + */ + public JSONObject putOnce(String key, Object value) throws JSONException { + if (key != null && value != null) { + if (opt(key) != null) { + throw new JSONException("Duplicate key \"" + key + "\""); + } + put(key, value); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value + * are both non-null. + * + * @param key + * A key string. + * @param value + * An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException + * If the value is a non-finite number. + */ + public JSONObject putOpt(String key, Object value) throws JSONException { + if (key != null && value != null) { + put(key, value); + } + return this; + } + + /** + * Produce a string in double quotes with backslash sequences in all the + * right places. A backslash will be inserted within </, producing <\/, + * allowing JSON text to be delivered in HTML. In JSON text, a string cannot + * contain a control character or an unescaped quote or backslash. + * + * @param string + * A String + * @return A String correctly formatted for insertion in a JSON text. + */ + public static String quote(String string) { + if (string == null || string.length() == 0) { + return "\"\""; + } + + char b; + char c = 0; + String hhhh; + int i; + int len = string.length(); + StringBuffer sb = new StringBuffer(len + 4); + + sb.append('"'); + for (i = 0; i < len; i += 1) { + b = c; + c = string.charAt(i); + switch (c) { + case '\\': + case '"': + sb.append('\\'); + sb.append(c); + break; + case '/': + if (b == '<') { + sb.append('\\'); + } + sb.append(c); + break; + case '\b': + sb.append("\\b"); + break; + case '\t': + sb.append("\\t"); + break; + case '\n': + sb.append("\\n"); + break; + case '\f': + sb.append("\\f"); + break; + case '\r': + sb.append("\\r"); + break; + default: + if (c < ' ' || (c >= '\u0080' && c < '\u00a0') + || (c >= '\u2000' && c < '\u2100')) { + hhhh = "000" + Integer.toHexString(c); + sb.append("\\u" + hhhh.substring(hhhh.length() - 4)); + } else { + sb.append(c); + } + } + } + sb.append('"'); + return sb.toString(); + } + + /** + * Remove a name and its value, if present. + * + * @param key + * The name to be removed. + * @return The value that was associated with the name, or null if there was + * no value. + */ + public Object remove(String key) { + return map.remove(key); + } + + /** + * Try to convert a string into a number, boolean, or null. If the string + * can't be converted, return the string. + * + * @param string + * A String. + * @return A simple JSON value. + */ + public static Object stringToValue(String string) { + Double d; + if (string.equals("")) { + return string; + } + if (string.equalsIgnoreCase("true")) { + return Boolean.TRUE; + } + if (string.equalsIgnoreCase("false")) { + return Boolean.FALSE; + } + if (string.equalsIgnoreCase("null")) { + return JSONObject.NULL; + } + + /* + * If it might be a number, try converting it. We support the + * non-standard 0x- convention. If a number cannot be produced, then the + * value will just be a string. Note that the 0x-, plus, and implied + * string conventions are non-standard. A JSON parser may accept + * non-JSON forms as long as it accepts all correct JSON forms. + */ + + char b = string.charAt(0); + if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') { + if (b == '0' && string.length() > 2 + && (string.charAt(1) == 'x' || string.charAt(1) == 'X')) { + try { + return new Integer( + Integer.parseInt(string.substring(2), 16)); + } catch (Exception ignore) { + } + } + try { + if (string.indexOf('.') > -1 || string.indexOf('e') > -1 + || string.indexOf('E') > -1) { + d = Double.valueOf(string); + if (!d.isInfinite() && !d.isNaN()) { + return d; + } + } else { + Long myLong = new Long(string); + if (myLong.longValue() == myLong.intValue()) { + return new Integer(myLong.intValue()); + } else { + return myLong; + } + } + } catch (Exception ignore) { + } + } + return string; + } + + /** + * Throw an exception if the object is a NaN or infinite number. + * + * @param o + * The object to test. + * @throws JSONException + * If o is a non-finite number. + */ + public static void testValidity(Object o) throws JSONException { + if (o != null) { + if (o instanceof Double) { + if (((Double) o).isInfinite() || ((Double) o).isNaN()) { + throw new JSONException( + "JSON does not allow non-finite numbers."); + } + } else if (o instanceof Float) { + if (((Float) o).isInfinite() || ((Float) o).isNaN()) { + throw new JSONException( + "JSON does not allow non-finite numbers."); + } + } + } + } + + /** + * Produce a JSONArray containing the values of the members of this + * JSONObject. + * + * @param names + * A JSONArray containing a list of key strings. This determines + * the sequence of the values in the result. + * @return A JSONArray of values. + * @throws JSONException + * If any of the values are non-finite numbers. + */ + public JSONArray toJSONArray(JSONArray names) throws JSONException { + if (names == null || names.length() == 0) { + return null; + } + JSONArray ja = new JSONArray(); + for (int i = 0; i < names.length(); i += 1) { + ja.put(opt(names.getString(i))); + } + return ja; + } + + /** + * Make a JSON text of this JSONObject. For compactness, no whitespace is + * added. If this would not result in a syntactically correct JSON text, + * then null will be returned instead. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with <code>{</code> <small>(left + * brace)</small> and ending with <code>}</code> <small>(right + * brace)</small>. + */ + @Override + public String toString() { + try { + Iterator keys = keys(); + StringBuffer sb = new StringBuffer("{"); + + while (keys.hasNext()) { + if (sb.length() > 1) { + sb.append(','); + } + Object o = keys.next(); + sb.append(quote(o.toString())); + sb.append(':'); + sb.append(valueToString(map.get(o))); + } + sb.append('}'); + return sb.toString(); + } catch (Exception e) { + return null; + } + } + + /** + * Make a prettyprinted JSON text of this JSONObject. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with <code>{</code> <small>(left + * brace)</small> and ending with <code>}</code> <small>(right + * brace)</small>. + * @throws JSONException + * If the object contains an invalid number. + */ + public String toString(int indentFactor) throws JSONException { + return toString(indentFactor, 0); + } + + /** + * Make a prettyprinted JSON text of this JSONObject. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indentation of the top level. + * @return a printable, displayable, transmittable representation of the + * object, beginning with <code>{</code> <small>(left + * brace)</small> and ending with <code>}</code> <small>(right + * brace)</small>. + * @throws JSONException + * If the object contains an invalid number. + */ + String toString(int indentFactor, int indent) throws JSONException { + int i; + int length = length(); + if (length == 0) { + return "{}"; + } + Iterator keys = keys(); + int newindent = indent + indentFactor; + Object object; + StringBuffer sb = new StringBuffer("{"); + if (length == 1) { + object = keys.next(); + sb.append(quote(object.toString())); + sb.append(": "); + sb.append(valueToString(map.get(object), indentFactor, indent)); + } else { + while (keys.hasNext()) { + object = keys.next(); + if (sb.length() > 1) { + sb.append(",\n"); + } else { + sb.append('\n'); + } + for (i = 0; i < newindent; i += 1) { + sb.append(' '); + } + sb.append(quote(object.toString())); + sb.append(": "); + sb.append(valueToString(map.get(object), indentFactor, + newindent)); + } + if (sb.length() > 1) { + sb.append('\n'); + for (i = 0; i < indent; i += 1) { + sb.append(' '); + } + } + } + sb.append('}'); + return sb.toString(); + } + + /** + * Make a JSON text of an Object value. If the object has an + * value.toJSONString() method, then that method will be used to produce the + * JSON text. The method is required to produce a strictly conforming text. + * If the object does not contain a toJSONString method (which is the most + * common case), then a text will be produced by other means. If the value + * is an array or Collection, then a JSONArray will be made from it and its + * toJSONString method will be called. If the value is a MAP, then a + * JSONObject will be made from it and its toJSONString method will be + * called. Otherwise, the value's toString method will be called, and the + * result will be quoted. + * + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @param value + * The value to be serialized. + * @return a printable, displayable, transmittable representation of the + * object, beginning with <code>{</code> <small>(left + * brace)</small> and ending with <code>}</code> <small>(right + * brace)</small>. + * @throws JSONException + * If the value is or contains an invalid number. + */ + public static String valueToString(Object value) throws JSONException { + if (value == null || value.equals(null)) { + return "null"; + } + if (value instanceof JSONString) { + Object object; + try { + object = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + if (object instanceof String) { + return (String) object; + } + throw new JSONException("Bad value from toJSONString: " + object); + } + if (value instanceof Number) { + return numberToString((Number) value); + } + if (value instanceof Boolean || value instanceof JSONObject + || value instanceof JSONArray) { + return value.toString(); + } + if (value instanceof Map) { + return new JSONObject((Map) value).toString(); + } + if (value instanceof Collection) { + return new JSONArray((Collection) value).toString(); + } + if (value.getClass().isArray()) { + return new JSONArray(value).toString(); + } + return quote(value.toString()); + } + + /** + * Make a prettyprinted JSON text of an object value. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @param value + * The value to be serialized. + * @param indentFactor + * The number of spaces to add to each level of indentation. + * @param indent + * The indentation of the top level. + * @return a printable, displayable, transmittable representation of the + * object, beginning with <code>{</code> <small>(left + * brace)</small> and ending with <code>}</code> <small>(right + * brace)</small>. + * @throws JSONException + * If the object contains an invalid number. + */ + static String valueToString(Object value, int indentFactor, int indent) + throws JSONException { + if (value == null || value.equals(null)) { + return "null"; + } + try { + if (value instanceof JSONString) { + Object o = ((JSONString) value).toJSONString(); + if (o instanceof String) { + return (String) o; + } + } + } catch (Exception ignore) { + } + if (value instanceof Number) { + return numberToString((Number) value); + } + if (value instanceof Boolean) { + return value.toString(); + } + if (value instanceof JSONObject) { + return ((JSONObject) value).toString(indentFactor, indent); + } + if (value instanceof JSONArray) { + return ((JSONArray) value).toString(indentFactor, indent); + } + if (value instanceof Map) { + return new JSONObject((Map) value).toString(indentFactor, indent); + } + if (value instanceof Collection) { + return new JSONArray((Collection) value).toString(indentFactor, + indent); + } + if (value.getClass().isArray()) { + return new JSONArray(value).toString(indentFactor, indent); + } + return quote(value.toString()); + } + + /** + * Wrap an object, if necessary. If the object is null, return the NULL + * object. If it is an array or collection, wrap it in a JSONArray. If it is + * a map, wrap it in a JSONObject. If it is a standard property (Double, + * String, et al) then it is already wrapped. Otherwise, if it comes from + * one of the java packages, turn it into a string. And if it doesn't, try + * to wrap it in a JSONObject. If the wrapping fails, then null is returned. + * + * @param object + * The object to wrap + * @return The wrapped value + */ + public static Object wrap(Object object) { + try { + if (object == null) { + return NULL; + } + if (object instanceof JSONObject || object instanceof JSONArray + || NULL.equals(object) || object instanceof JSONString + || object instanceof Byte || object instanceof Character + || object instanceof Short || object instanceof Integer + || object instanceof Long || object instanceof Boolean + || object instanceof Float || object instanceof Double + || object instanceof String) { + return object; + } + + if (object instanceof Collection) { + return new JSONArray((Collection) object); + } + if (object.getClass().isArray()) { + return new JSONArray(object); + } + if (object instanceof Map) { + return new JSONObject((Map) object); + } + Package objectPackage = object.getClass().getPackage(); + String objectPackageName = objectPackage != null ? objectPackage + .getName() : ""; + if (objectPackageName.startsWith("java.") + || objectPackageName.startsWith("javax.") + || object.getClass().getClassLoader() == null) { + return object.toString(); + } + return new JSONObject(object); + } catch (Exception exception) { + return null; + } + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. For + * compactness, no whitespace is added. + * <p> + * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer) throws JSONException { + try { + boolean commanate = false; + Iterator keys = keys(); + writer.write('{'); + + while (keys.hasNext()) { + if (commanate) { + writer.write(','); + } + Object key = keys.next(); + writer.write(quote(key.toString())); + writer.write(':'); + Object value = map.get(key); + if (value instanceof JSONObject) { + ((JSONObject) value).write(writer); + } else if (value instanceof JSONArray) { + ((JSONArray) value).write(writer); + } else { + writer.write(valueToString(value)); + } + commanate = true; + } + writer.write('}'); + return writer; + } catch (IOException exception) { + throw new JSONException(exception); + } + } +}
\ No newline at end of file diff --git a/src/com/vaadin/external/json/JSONString.java b/src/com/vaadin/external/json/JSONString.java new file mode 100644 index 0000000000..cc7e4d8c07 --- /dev/null +++ b/src/com/vaadin/external/json/JSONString.java @@ -0,0 +1,21 @@ +package com.vaadin.external.json; + +import java.io.Serializable; + +/** + * The <code>JSONString</code> interface allows a <code>toJSONString()</code> + * method so that a class can change the behavior of + * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, and + * <code>JSONWriter.value(</code>Object<code>)</code>. The + * <code>toJSONString</code> method will be used instead of the default behavior + * of using the Object's <code>toString()</code> method and quoting the result. + */ +public interface JSONString extends Serializable { + /** + * The <code>toJSONString</code> method allows a class to produce its own + * JSON serialization. + * + * @return A strictly syntactically correct JSON text. + */ + public String toJSONString(); +} diff --git a/src/com/vaadin/external/json/JSONStringer.java b/src/com/vaadin/external/json/JSONStringer.java new file mode 100644 index 0000000000..e4ccc8e195 --- /dev/null +++ b/src/com/vaadin/external/json/JSONStringer.java @@ -0,0 +1,83 @@ +package com.vaadin.external.json; + +/* + Copyright (c) 2006 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +import java.io.StringWriter; + +/** + * JSONStringer provides a quick and convenient way of producing JSON text. The + * texts produced strictly conform to JSON syntax rules. No whitespace is added, + * so the results are ready for transmission or storage. Each instance of + * JSONStringer can produce one JSON text. + * <p> + * A JSONStringer instance provides a <code>value</code> method for appending + * values to the text, and a <code>key</code> method for adding keys before + * values in objects. There are <code>array</code> and <code>endArray</code> + * methods that make and bound array values, and <code>object</code> and + * <code>endObject</code> methods which make and bound object values. All of + * these methods return the JSONWriter instance, permitting cascade style. For + * example, + * + * <pre> + * myString = new JSONStringer().object().key("JSON").value("Hello, World!") + * .endObject().toString(); + * </pre> + * + * which produces the string + * + * <pre> + * {"JSON":"Hello, World!"} + * </pre> + * <p> + * The first method called must be <code>array</code> or <code>object</code>. + * There are no methods for adding commas or colons. JSONStringer adds them for + * you. Objects and arrays can be nested up to 20 levels deep. + * <p> + * This can sometimes be easier than using a JSONObject to build a string. + * + * @author JSON.org + * @version 2008-09-18 + */ +public class JSONStringer extends JSONWriter { + /** + * Make a fresh JSONStringer. It can be used to build one JSON text. + */ + public JSONStringer() { + super(new StringWriter()); + } + + /** + * Return the JSON text. This method is used to obtain the product of the + * JSONStringer instance. It will return <code>null</code> if there was a + * problem in the construction of the JSON text (such as the calls to + * <code>array</code> were not properly balanced with calls to + * <code>endArray</code>). + * + * @return The JSON text. + */ + public String toString() { + return this.mode == 'd' ? this.writer.toString() : null; + } +} diff --git a/src/com/vaadin/external/json/JSONTokener.java b/src/com/vaadin/external/json/JSONTokener.java new file mode 100644 index 0000000000..c3531cae1d --- /dev/null +++ b/src/com/vaadin/external/json/JSONTokener.java @@ -0,0 +1,451 @@ +package com.vaadin.external.json; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Serializable; +import java.io.StringReader; + +/* + Copyright (c) 2002 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +/** + * A JSONTokener takes a source string and extracts characters and tokens from + * it. It is used by the JSONObject and JSONArray constructors to parse JSON + * source strings. + * + * @author JSON.org + * @version 2010-12-24 + */ +public class JSONTokener implements Serializable { + + private int character; + private boolean eof; + private int index; + private int line; + private char previous; + private Reader reader; + private boolean usePrevious; + + /** + * Construct a JSONTokener from a Reader. + * + * @param reader + * A reader. + */ + public JSONTokener(Reader reader) { + this.reader = reader.markSupported() ? reader : new BufferedReader( + reader); + eof = false; + usePrevious = false; + previous = 0; + index = 0; + character = 1; + line = 1; + } + + /** + * Construct a JSONTokener from an InputStream. + */ + public JSONTokener(InputStream inputStream) throws JSONException { + this(new InputStreamReader(inputStream)); + } + + /** + * Construct a JSONTokener from a string. + * + * @param s + * A source string. + */ + public JSONTokener(String s) { + this(new StringReader(s)); + } + + /** + * Back up one character. This provides a sort of lookahead capability, so + * that you can test for a digit or letter before attempting to parse the + * next number or identifier. + */ + public void back() throws JSONException { + if (usePrevious || index <= 0) { + throw new JSONException("Stepping back two steps is not supported"); + } + index -= 1; + character -= 1; + usePrevious = true; + eof = false; + } + + /** + * Get the hex value of a character (base16). + * + * @param c + * A character between '0' and '9' or between 'A' and 'F' or + * between 'a' and 'f'. + * @return An int between 0 and 15, or -1 if c was not a hex digit. + */ + public static int dehexchar(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + return c - ('A' - 10); + } + if (c >= 'a' && c <= 'f') { + return c - ('a' - 10); + } + return -1; + } + + public boolean end() { + return eof && !usePrevious; + } + + /** + * Determine if the source string still contains characters that next() can + * consume. + * + * @return true if not yet at the end of the source. + */ + public boolean more() throws JSONException { + next(); + if (end()) { + return false; + } + back(); + return true; + } + + /** + * Get the next character in the source string. + * + * @return The next character, or 0 if past the end of the source string. + */ + public char next() throws JSONException { + int c; + if (usePrevious) { + usePrevious = false; + c = previous; + } else { + try { + c = reader.read(); + } catch (IOException exception) { + throw new JSONException(exception); + } + + if (c <= 0) { // End of stream + eof = true; + c = 0; + } + } + index += 1; + if (previous == '\r') { + line += 1; + character = c == '\n' ? 0 : 1; + } else if (c == '\n') { + line += 1; + character = 0; + } else { + character += 1; + } + previous = (char) c; + return previous; + } + + /** + * Consume the next character, and check that it matches a specified + * character. + * + * @param c + * The character to match. + * @return The character. + * @throws JSONException + * if the character does not match. + */ + public char next(char c) throws JSONException { + char n = next(); + if (n != c) { + throw syntaxError("Expected '" + c + "' and instead saw '" + n + + "'"); + } + return n; + } + + /** + * Get the next n characters. + * + * @param n + * The number of characters to take. + * @return A string of n characters. + * @throws JSONException + * Substring bounds error if there are not n characters + * remaining in the source string. + */ + public String next(int n) throws JSONException { + if (n == 0) { + return ""; + } + + char[] chars = new char[n]; + int pos = 0; + + while (pos < n) { + chars[pos] = next(); + if (end()) { + throw syntaxError("Substring bounds error"); + } + pos += 1; + } + return new String(chars); + } + + /** + * Get the next char in the string, skipping whitespace. + * + * @throws JSONException + * @return A character, or 0 if there are no more characters. + */ + public char nextClean() throws JSONException { + for (;;) { + char c = next(); + if (c == 0 || c > ' ') { + return c; + } + } + } + + /** + * Return the characters up to the next close quote character. Backslash + * processing is done. The formal JSON format does not allow strings in + * single quotes, but an implementation is allowed to accept them. + * + * @param quote + * The quoting character, either <code>"</code> + * <small>(double quote)</small> or <code>'</code> + * <small>(single quote)</small>. + * @return A String. + * @throws JSONException + * Unterminated string. + */ + public String nextString(char quote) throws JSONException { + char c; + StringBuffer sb = new StringBuffer(); + for (;;) { + c = next(); + switch (c) { + case 0: + case '\n': + case '\r': + throw syntaxError("Unterminated string"); + case '\\': + c = next(); + switch (c) { + case 'b': + sb.append('\b'); + break; + case 't': + sb.append('\t'); + break; + case 'n': + sb.append('\n'); + break; + case 'f': + sb.append('\f'); + break; + case 'r': + sb.append('\r'); + break; + case 'u': + sb.append((char) Integer.parseInt(next(4), 16)); + break; + case '"': + case '\'': + case '\\': + case '/': + sb.append(c); + break; + default: + throw syntaxError("Illegal escape."); + } + break; + default: + if (c == quote) { + return sb.toString(); + } + sb.append(c); + } + } + } + + /** + * Get the text up but not including the specified character or the end of + * line, whichever comes first. + * + * @param delimiter + * A delimiter character. + * @return A string. + */ + public String nextTo(char delimiter) throws JSONException { + StringBuffer sb = new StringBuffer(); + for (;;) { + char c = next(); + if (c == delimiter || c == 0 || c == '\n' || c == '\r') { + if (c != 0) { + back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + /** + * Get the text up but not including one of the specified delimiter + * characters or the end of line, whichever comes first. + * + * @param delimiters + * A set of delimiter characters. + * @return A string, trimmed. + */ + public String nextTo(String delimiters) throws JSONException { + char c; + StringBuffer sb = new StringBuffer(); + for (;;) { + c = next(); + if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') { + if (c != 0) { + back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + /** + * Get the next value. The value can be a Boolean, Double, Integer, + * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. + * + * @throws JSONException + * If syntax error. + * + * @return An object. + */ + public Object nextValue() throws JSONException { + char c = nextClean(); + String string; + + switch (c) { + case '"': + case '\'': + return nextString(c); + case '{': + back(); + return new JSONObject(this); + case '[': + back(); + return new JSONArray(this); + } + + /* + * Handle unquoted text. This could be the values true, false, or null, + * or it can be a number. An implementation (such as this one) is + * allowed to also accept non-standard forms. + * + * Accumulate characters until we reach the end of the text or a + * formatting character. + */ + + StringBuffer sb = new StringBuffer(); + while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { + sb.append(c); + c = next(); + } + back(); + + string = sb.toString().trim(); + if (string.equals("")) { + throw syntaxError("Missing value"); + } + return JSONObject.stringToValue(string); + } + + /** + * Skip characters until the next character is the requested character. If + * the requested character is not found, no characters are skipped. + * + * @param to + * A character to skip to. + * @return The requested character, or zero if the requested character is + * not found. + */ + public char skipTo(char to) throws JSONException { + char c; + try { + int startIndex = index; + int startCharacter = character; + int startLine = line; + reader.mark(Integer.MAX_VALUE); + do { + c = next(); + if (c == 0) { + reader.reset(); + index = startIndex; + character = startCharacter; + line = startLine; + return c; + } + } while (c != to); + } catch (IOException exc) { + throw new JSONException(exc); + } + + back(); + return c; + } + + /** + * Make a JSONException to signal a syntax error. + * + * @param message + * The error message. + * @return A JSONException object, suitable for throwing + */ + public JSONException syntaxError(String message) { + return new JSONException(message + toString()); + } + + /** + * Make a printable string of this JSONTokener. + * + * @return " at {index} [character {character} line {line}]" + */ + @Override + public String toString() { + return " at " + index + " [character " + character + " line " + line + + "]"; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/external/json/JSONWriter.java b/src/com/vaadin/external/json/JSONWriter.java new file mode 100644 index 0000000000..5f9ddeeae2 --- /dev/null +++ b/src/com/vaadin/external/json/JSONWriter.java @@ -0,0 +1,355 @@ +package com.vaadin.external.json; + +import java.io.IOException; +import java.io.Serializable; +import java.io.Writer; + +/* + Copyright (c) 2006 JSON.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + The Software shall be used for Good, not Evil. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + +/** + * JSONWriter provides a quick and convenient way of producing JSON text. The + * texts produced strictly conform to JSON syntax rules. No whitespace is added, + * so the results are ready for transmission or storage. Each instance of + * JSONWriter can produce one JSON text. + * <p> + * A JSONWriter instance provides a <code>value</code> method for appending + * values to the text, and a <code>key</code> method for adding keys before + * values in objects. There are <code>array</code> and <code>endArray</code> + * methods that make and bound array values, and <code>object</code> and + * <code>endObject</code> methods which make and bound object values. All of + * these methods return the JSONWriter instance, permitting a cascade style. For + * example, + * + * <pre> + * new JSONWriter(myWriter).object().key("JSON").value("Hello, World!") + * .endObject(); + * </pre> + * + * which writes + * + * <pre> + * {"JSON":"Hello, World!"} + * </pre> + * <p> + * The first method called must be <code>array</code> or <code>object</code>. + * There are no methods for adding commas or colons. JSONWriter adds them for + * you. Objects and arrays can be nested up to 20 levels deep. + * <p> + * This can sometimes be easier than using a JSONObject to build a string. + * + * @author JSON.org + * @version 2011-11-14 + */ +public class JSONWriter implements Serializable { + private static final int maxdepth = 200; + + /** + * The comma flag determines if a comma should be output before the next + * value. + */ + private boolean comma; + + /** + * The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k' + * (key), 'o' (object). + */ + protected char mode; + + /** + * The object/array stack. + */ + private final JSONObject stack[]; + + /** + * The stack top index. A value of 0 indicates that the stack is empty. + */ + private int top; + + /** + * The writer that will receive the output. + */ + protected Writer writer; + + /** + * Make a fresh JSONWriter. It can be used to build one JSON text. + */ + public JSONWriter(Writer w) { + comma = false; + mode = 'i'; + stack = new JSONObject[maxdepth]; + top = 0; + writer = w; + } + + /** + * Append a value. + * + * @param string + * A string value. + * @return this + * @throws JSONException + * If the value is out of sequence. + */ + private JSONWriter append(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null pointer"); + } + if (mode == 'o' || mode == 'a') { + try { + if (comma && mode == 'a') { + writer.write(','); + } + writer.write(string); + } catch (IOException e) { + throw new JSONException(e); + } + if (mode == 'o') { + mode = 'k'; + } + comma = true; + return this; + } + throw new JSONException("Value out of sequence."); + } + + /** + * Begin appending a new array. All values until the balancing + * <code>endArray</code> will be appended to this array. The + * <code>endArray</code> method must be called to mark the array's end. + * + * @return this + * @throws JSONException + * If the nesting is too deep, or if the object is started in + * the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter array() throws JSONException { + if (mode == 'i' || mode == 'o' || mode == 'a') { + push(null); + append("["); + comma = false; + return this; + } + throw new JSONException("Misplaced array."); + } + + /** + * End something. + * + * @param mode + * Mode + * @param c + * Closing character + * @return this + * @throws JSONException + * If unbalanced. + */ + private JSONWriter end(char mode, char c) throws JSONException { + if (this.mode != mode) { + throw new JSONException(mode == 'a' ? "Misplaced endArray." + : "Misplaced endObject."); + } + pop(mode); + try { + writer.write(c); + } catch (IOException e) { + throw new JSONException(e); + } + comma = true; + return this; + } + + /** + * End an array. This method most be called to balance calls to + * <code>array</code>. + * + * @return this + * @throws JSONException + * If incorrectly nested. + */ + public JSONWriter endArray() throws JSONException { + return end('a', ']'); + } + + /** + * End an object. This method most be called to balance calls to + * <code>object</code>. + * + * @return this + * @throws JSONException + * If incorrectly nested. + */ + public JSONWriter endObject() throws JSONException { + return end('k', '}'); + } + + /** + * Append a key. The key will be associated with the next value. In an + * object, every value must be preceded by a key. + * + * @param string + * A key string. + * @return this + * @throws JSONException + * If the key is out of place. For example, keys do not belong + * in arrays or if the key is null. + */ + public JSONWriter key(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null key."); + } + if (mode == 'k') { + try { + stack[top - 1].putOnce(string, Boolean.TRUE); + if (comma) { + writer.write(','); + } + writer.write(JSONObject.quote(string)); + writer.write(':'); + comma = false; + mode = 'o'; + return this; + } catch (IOException e) { + throw new JSONException(e); + } + } + throw new JSONException("Misplaced key."); + } + + /** + * Begin appending a new object. All keys and values until the balancing + * <code>endObject</code> will be appended to this object. The + * <code>endObject</code> method must be called to mark the object's end. + * + * @return this + * @throws JSONException + * If the nesting is too deep, or if the object is started in + * the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter object() throws JSONException { + if (mode == 'i') { + mode = 'o'; + } + if (mode == 'o' || mode == 'a') { + append("{"); + push(new JSONObject()); + comma = false; + return this; + } + throw new JSONException("Misplaced object."); + + } + + /** + * Pop an array or object scope. + * + * @param c + * The scope to close. + * @throws JSONException + * If nesting is wrong. + */ + private void pop(char c) throws JSONException { + if (top <= 0) { + throw new JSONException("Nesting error."); + } + char m = stack[top - 1] == null ? 'a' : 'k'; + if (m != c) { + throw new JSONException("Nesting error."); + } + top -= 1; + mode = top == 0 ? 'd' : stack[top - 1] == null ? 'a' : 'k'; + } + + /** + * Push an array or object scope. + * + * @param c + * The scope to open. + * @throws JSONException + * If nesting is too deep. + */ + private void push(JSONObject jo) throws JSONException { + if (top >= maxdepth) { + throw new JSONException("Nesting too deep."); + } + stack[top] = jo; + mode = jo == null ? 'a' : 'k'; + top += 1; + } + + /** + * Append either the value <code>true</code> or the value <code>false</code> + * . + * + * @param b + * A boolean. + * @return this + * @throws JSONException + */ + public JSONWriter value(boolean b) throws JSONException { + return append(b ? "true" : "false"); + } + + /** + * Append a double value. + * + * @param d + * A double. + * @return this + * @throws JSONException + * If the number is not finite. + */ + public JSONWriter value(double d) throws JSONException { + return this.value(new Double(d)); + } + + /** + * Append a long value. + * + * @param l + * A long. + * @return this + * @throws JSONException + */ + public JSONWriter value(long l) throws JSONException { + return append(Long.toString(l)); + } + + /** + * Append an object value. + * + * @param object + * The object to append. It can be null, or a Boolean, Number, + * String, JSONObject, or JSONArray, or an object that implements + * JSONString. + * @return this + * @throws JSONException + * If the value is out of sequence. + */ + public JSONWriter value(Object object) throws JSONException { + return append(JSONObject.valueToString(object)); + } +} diff --git a/src/com/vaadin/external/json/README b/src/com/vaadin/external/json/README new file mode 100644 index 0000000000..ca6dc11764 --- /dev/null +++ b/src/com/vaadin/external/json/README @@ -0,0 +1,68 @@ +JSON in Java [package org.json] + +Douglas Crockford +douglas@crockford.com + +2011-02-02 + + +JSON is a light-weight, language independent, data interchange format. +See http://www.JSON.org/ + +The files in this package implement JSON encoders/decoders in Java. +It also includes the capability to convert between JSON and XML, HTTP +headers, Cookies, and CDL. + +This is a reference implementation. There is a large number of JSON packages +in Java. Perhaps someday the Java community will standardize on one. Until +then, choose carefully. + +The license includes this restriction: "The software shall be used for good, +not evil." If your conscience cannot live with that, then choose a different +package. + +The package compiles on Java 1.2 thru Java 1.4. + + +JSONObject.java: The JSONObject can parse text from a String or a JSONTokener +to produce a map-like object. The object provides methods for manipulating its +contents, and for producing a JSON compliant object serialization. + +JSONArray.java: The JSONObject can parse text from a String or a JSONTokener +to produce a vector-like object. The object provides methods for manipulating +its contents, and for producing a JSON compliant array serialization. + +JSONTokener.java: The JSONTokener breaks a text into a sequence of individual +tokens. It can be constructed from a String, Reader, or InputStream. + +JSONException.java: The JSONException is the standard exception type thrown +by this package. + + +JSONString.java: The JSONString interface requires a toJSONString method, +allowing an object to provide its own serialization. + +JSONStringer.java: The JSONStringer provides a convenient facility for +building JSON strings. + +JSONWriter.java: The JSONWriter provides a convenient facility for building +JSON text through a writer. + + +CDL.java: CDL provides support for converting between JSON and comma +delimited lists. + +Cookie.java: Cookie provides support for converting between JSON and cookies. + +CookieList.java: CookieList provides support for converting between JSON and +cookie lists. + +HTTP.java: HTTP provides support for converting between JSON and HTTP headers. + +HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers. + +XML.java: XML provides support for converting between JSON and XML. + +JSONML.java: JSONML provides support for converting between JSONML and XML. + +XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text.
\ No newline at end of file diff --git a/src/com/vaadin/terminal/AbstractErrorMessage.java b/src/com/vaadin/terminal/AbstractErrorMessage.java new file mode 100644 index 0000000000..1a625fc0e6 --- /dev/null +++ b/src/com/vaadin/terminal/AbstractErrorMessage.java @@ -0,0 +1,169 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.data.Buffered; +import com.vaadin.data.Validator; +import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; + +/** + * Base class for component error messages. + * + * This class is used on the server side to construct the error messages to send + * to the client. + * + * @since 7.0 + */ +public abstract class AbstractErrorMessage implements ErrorMessage { + + public enum ContentMode { + /** + * Content mode, where the error contains only plain text. + */ + TEXT, + /** + * Content mode, where the error contains preformatted text. + */ + PREFORMATTED, + /** + * Content mode, where the error contains XHTML. + */ + XHTML; + } + + /** + * Content mode. + */ + private ContentMode mode = ContentMode.TEXT; + + /** + * Message in content mode. + */ + private String message; + + /** + * Error level. + */ + private ErrorLevel level = ErrorLevel.ERROR; + + private List<ErrorMessage> causes = new ArrayList<ErrorMessage>(); + + protected AbstractErrorMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + protected void setMessage(String message) { + this.message = message; + } + + /* Documented in interface */ + public ErrorLevel getErrorLevel() { + return level; + } + + protected void setErrorLevel(ErrorLevel level) { + this.level = level; + } + + protected ContentMode getMode() { + return mode; + } + + protected void setMode(ContentMode mode) { + this.mode = mode; + } + + protected List<ErrorMessage> getCauses() { + return causes; + } + + protected void addCause(ErrorMessage cause) { + causes.add(cause); + } + + public String getFormattedHtmlMessage() { + String result = null; + switch (getMode()) { + case TEXT: + result = AbstractApplicationServlet.safeEscapeForHtml(getMessage()); + break; + case PREFORMATTED: + result = "<pre>" + + AbstractApplicationServlet + .safeEscapeForHtml(getMessage()) + "</pre>"; + break; + case XHTML: + result = getMessage(); + break; + } + // if no message, combine the messages of all children + if (null == result && null != getCauses() && getCauses().size() > 0) { + StringBuilder sb = new StringBuilder(); + for (ErrorMessage cause : getCauses()) { + String childMessage = cause.getFormattedHtmlMessage(); + if (null != childMessage) { + sb.append("<div>"); + sb.append(childMessage); + sb.append("</div>\n"); + } + } + if (sb.length() > 0) { + result = sb.toString(); + } + } + // still no message? use an empty string for backwards compatibility + if (null == result) { + result = ""; + } + return result; + } + + // TODO replace this with a helper method elsewhere? + public static ErrorMessage getErrorMessageForException(Throwable t) { + if (null == t) { + return null; + } else if (t instanceof ErrorMessage) { + // legacy case for custom error messages + return (ErrorMessage) t; + } else if (t instanceof Validator.InvalidValueException) { + UserError error = new UserError( + ((Validator.InvalidValueException) t).getHtmlMessage(), + ContentMode.XHTML, ErrorLevel.ERROR); + for (Validator.InvalidValueException nestedException : ((Validator.InvalidValueException) t) + .getCauses()) { + error.addCause(getErrorMessageForException(nestedException)); + } + return error; + } else if (t instanceof Buffered.SourceException) { + // no message, only the causes to be painted + UserError error = new UserError(null); + // in practice, this was always ERROR in Vaadin 6 unless tweaked in + // custom exceptions implementing ErrorMessage + error.setErrorLevel(ErrorLevel.ERROR); + // causes + for (Throwable nestedException : ((Buffered.SourceException) t) + .getCauses()) { + error.addCause(getErrorMessageForException(nestedException)); + } + return error; + } else { + return new SystemError(t); + } + } + + /* Documented in superclass */ + @Override + public String toString() { + return getMessage(); + } + +} diff --git a/src/com/vaadin/terminal/CombinedRequest.java b/src/com/vaadin/terminal/CombinedRequest.java new file mode 100644 index 0000000000..ccef6d8963 --- /dev/null +++ b/src/com/vaadin/terminal/CombinedRequest.java @@ -0,0 +1,167 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import com.vaadin.Application; +import com.vaadin.external.json.JSONArray; +import com.vaadin.external.json.JSONException; +import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.gwt.server.WebApplicationContext; +import com.vaadin.terminal.gwt.server.WebBrowser; + +/** + * A {@link WrappedRequest} with path and parameters from one request and + * {@link WrappedRequest.BrowserDetails} extracted from another request. + * + * This class is intended to be used for a two request initialization where the + * first request fetches the actual application page and the second request + * contains information extracted from the browser using javascript. + * + */ +public class CombinedRequest implements WrappedRequest { + + private final WrappedRequest secondRequest; + private Map<String, String[]> parameterMap; + + /** + * Creates a new combined request based on the second request and some + * details from the first request. + * + * @param secondRequest + * the second request which will be used as the foundation of the + * combined request + * @throws JSONException + * if the initialParams parameter can not be decoded + */ + public CombinedRequest(WrappedRequest secondRequest) throws JSONException { + this.secondRequest = secondRequest; + + HashMap<String, String[]> map = new HashMap<String, String[]>(); + JSONObject initialParams = new JSONObject( + secondRequest.getParameter("initialParams")); + for (Iterator<?> keys = initialParams.keys(); keys.hasNext();) { + String name = (String) keys.next(); + JSONArray jsonValues = initialParams.getJSONArray(name); + String[] values = new String[jsonValues.length()]; + for (int i = 0; i < values.length; i++) { + values[i] = jsonValues.getString(i); + } + map.put(name, values); + } + + parameterMap = Collections.unmodifiableMap(map); + + } + + public String getParameter(String parameter) { + String[] strings = getParameterMap().get(parameter); + if (strings == null || strings.length == 0) { + return null; + } else { + return strings[0]; + } + } + + public Map<String, String[]> getParameterMap() { + return parameterMap; + } + + public int getContentLength() { + return secondRequest.getContentLength(); + } + + public InputStream getInputStream() throws IOException { + return secondRequest.getInputStream(); + } + + public Object getAttribute(String name) { + return secondRequest.getAttribute(name); + } + + public void setAttribute(String name, Object value) { + secondRequest.setAttribute(name, value); + } + + public String getRequestPathInfo() { + return secondRequest.getParameter("initialPath"); + } + + public int getSessionMaxInactiveInterval() { + return secondRequest.getSessionMaxInactiveInterval(); + } + + public Object getSessionAttribute(String name) { + return secondRequest.getSessionAttribute(name); + } + + public void setSessionAttribute(String name, Object attribute) { + secondRequest.setSessionAttribute(name, attribute); + } + + public String getContentType() { + return secondRequest.getContentType(); + } + + public BrowserDetails getBrowserDetails() { + return new BrowserDetails() { + public String getUriFragment() { + String fragment = secondRequest.getParameter("fr"); + if (fragment == null) { + return ""; + } else { + return fragment; + } + } + + public String getWindowName() { + return secondRequest.getParameter("wn"); + } + + public WebBrowser getWebBrowser() { + WebApplicationContext context = (WebApplicationContext) Application + .getCurrentApplication().getContext(); + return context.getBrowser(); + } + }; + } + + /** + * Gets the original second request. This can be used e.g. if a request + * parameter from the second request is required. + * + * @return the original second wrapped request + */ + public WrappedRequest getSecondRequest() { + return secondRequest; + } + + public Locale getLocale() { + return secondRequest.getLocale(); + } + + public String getRemoteAddr() { + return secondRequest.getRemoteAddr(); + } + + public boolean isSecure() { + return secondRequest.isSecure(); + } + + public String getHeader(String name) { + return secondRequest.getHeader(name); + } + + public DeploymentConfiguration getDeploymentConfiguration() { + return secondRequest.getDeploymentConfiguration(); + } +} diff --git a/src/com/vaadin/terminal/CompositeErrorMessage.java b/src/com/vaadin/terminal/CompositeErrorMessage.java index aae231739e..b82b622f54 100644 --- a/src/com/vaadin/terminal/CompositeErrorMessage.java +++ b/src/com/vaadin/terminal/CompositeErrorMessage.java @@ -4,11 +4,8 @@ package com.vaadin.terminal; -import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; -import java.util.List; /** * Class for combining multiple error messages together. @@ -19,17 +16,7 @@ import java.util.List; * @since 3.0 */ @SuppressWarnings("serial") -public class CompositeErrorMessage implements ErrorMessage, Serializable { - - /** - * Array of all the errors. - */ - private final List<ErrorMessage> errors; - - /** - * Level of the error. - */ - private int level; +public class CompositeErrorMessage extends AbstractErrorMessage { /** * Constructor for CompositeErrorMessage. @@ -39,14 +26,14 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable { * ignored, but at least one message is required. */ public CompositeErrorMessage(ErrorMessage[] errorMessages) { - errors = new ArrayList<ErrorMessage>(errorMessages.length); - level = Integer.MIN_VALUE; + super(null); + setErrorLevel(ErrorLevel.INFORMATION); for (int i = 0; i < errorMessages.length; i++) { addErrorMessage(errorMessages[i]); } - if (errors.size() == 0) { + if (getCauses().size() == 0) { throw new IllegalArgumentException( "Composite error message must have at least one error"); } @@ -62,30 +49,21 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable { */ public CompositeErrorMessage( Collection<? extends ErrorMessage> errorMessages) { - errors = new ArrayList<ErrorMessage>(errorMessages.size()); - level = Integer.MIN_VALUE; + super(null); + setErrorLevel(ErrorLevel.INFORMATION); for (final Iterator<? extends ErrorMessage> i = errorMessages .iterator(); i.hasNext();) { addErrorMessage(i.next()); } - if (errors.size() == 0) { + if (getCauses().size() == 0) { throw new IllegalArgumentException( "Composite error message must have at least one error"); } } /** - * The error level is the largest error level in - * - * @see com.vaadin.terminal.ErrorMessage#getErrorLevel() - */ - public final int getErrorLevel() { - return level; - } - - /** * Adds a error message into this composite message. Updates the level * field. * @@ -93,11 +71,10 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable { * the error message to be added. Duplicate errors are ignored. */ private void addErrorMessage(ErrorMessage error) { - if (error != null && !errors.contains(error)) { - errors.add(error); - final int l = error.getErrorLevel(); - if (l > level) { - level = l; + if (error != null && !getCauses().contains(error)) { + addCause(error); + if (error.getErrorLevel().intValue() > getErrorLevel().intValue()) { + setErrorLevel(error.getErrorLevel()); } } } @@ -108,55 +85,7 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable { * @return the error iterator. */ public Iterator<ErrorMessage> iterator() { - return errors.iterator(); - } - - /** - * @see com.vaadin.terminal.Paintable#paint(com.vaadin.terminal.PaintTarget) - */ - public void paint(PaintTarget target) throws PaintException { - - if (errors.size() == 1) { - (errors.iterator().next()).paint(target); - } else { - target.startTag("error"); - - if (level > 0 && level <= ErrorMessage.INFORMATION) { - target.addAttribute("level", "info"); - } else if (level <= ErrorMessage.WARNING) { - target.addAttribute("level", "warning"); - } else if (level <= ErrorMessage.ERROR) { - target.addAttribute("level", "error"); - } else if (level <= ErrorMessage.CRITICAL) { - target.addAttribute("level", "critical"); - } else { - target.addAttribute("level", "system"); - } - - // Paint all the exceptions - for (final Iterator<ErrorMessage> i = errors.iterator(); i - .hasNext();) { - i.next().paint(target); - } - - target.endTag("error"); - } - } - - /* Documented in super interface */ - public void addListener(RepaintRequestListener listener) { - } - - /* Documented in super interface */ - public void removeListener(RepaintRequestListener listener) { - } - - /* Documented in super interface */ - public void requestRepaint() { - } - - /* Documented in super interface */ - public void requestRepaintRequests() { + return getCauses().iterator(); } /** @@ -168,7 +97,8 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable { public String toString() { String retval = "["; int pos = 0; - for (final Iterator<ErrorMessage> i = errors.iterator(); i.hasNext();) { + for (final Iterator<ErrorMessage> i = getCauses().iterator(); i + .hasNext();) { if (pos > 0) { retval += ","; } @@ -179,13 +109,4 @@ public class CompositeErrorMessage implements ErrorMessage, Serializable { return retval; } - - public String getDebugId() { - return null; - } - - public void setDebugId(String id) { - throw new UnsupportedOperationException( - "Setting testing id for this Paintable is not implemented"); - } } diff --git a/src/com/vaadin/terminal/DeploymentConfiguration.java b/src/com/vaadin/terminal/DeploymentConfiguration.java new file mode 100644 index 0000000000..02a3f0200f --- /dev/null +++ b/src/com/vaadin/terminal/DeploymentConfiguration.java @@ -0,0 +1,86 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.io.Serializable; + +/** + * Provide deployment specific settings that are required outside terminal + * specific code. + * + * @author Vaadin Ltd. + * + * @since 7.0 + */ +public interface DeploymentConfiguration extends Serializable { + + /** + * Gets the base URL of the location of Vaadin's static files. + * + * @param request + * the request for which the location should be determined + * + * @return a string with the base URL for static files + */ + public String getStaticFileLocation(WrappedRequest request); + + /** + * Gets the widgetset that is configured for this deployment, e.g. from a + * parameter in web.xml. + * + * @param request + * the request for which a widgetset is required + * @return the name of the widgetset + */ + public String getConfiguredWidgetset(WrappedRequest request); + + /** + * Gets the theme that is configured for this deployment, e.g. from a portal + * parameter or just some sensible default value. + * + * @param request + * the request for which a theme is required + * @return the name of the theme + */ + public String getConfiguredTheme(WrappedRequest request); + + /** + * Checks whether the Vaadin application will be rendered on its own in the + * browser or whether it will be included into some other context. A + * standalone application may do things that might interfere with other + * parts of a page, e.g. changing the page title and requesting focus upon + * loading. + * + * @param request + * the request for which the application is loaded + * @return a boolean indicating whether the application should be standalone + */ + public boolean isStandalone(WrappedRequest request); + + /** + * Gets a configured property. The properties are typically read from e.g. + * web.xml or from system properties of the JVM. + * + * @param propertyName + * The simple of the property, in some contexts, lookup might be + * performed using variations of the provided name. + * @param defaultValue + * the default value that should be used if no value has been + * defined + * @return the property value, or the passed default value if no property + * value is found + */ + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue); + + /** + * Get the class loader to use for loading classes loaded by name, e.g. + * custom Root classes. <code>null</code> indicates that the default class + * loader should be used. + * + * @return the class loader to use, or <code>null</code> + */ + public ClassLoader getClassLoader(); +} diff --git a/src/com/vaadin/terminal/DownloadStream.java b/src/com/vaadin/terminal/DownloadStream.java index 2db2a1f20d..9853b0eee2 100644 --- a/src/com/vaadin/terminal/DownloadStream.java +++ b/src/com/vaadin/terminal/DownloadStream.java @@ -4,12 +4,18 @@ package com.vaadin.terminal; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import javax.servlet.http.HttpServletResponse; + +import com.vaadin.terminal.gwt.server.Constants; + /** * Downloadable stream. * @@ -198,9 +204,132 @@ public class DownloadStream implements Serializable { * * @param bufferSize * the size of the buffer in bytes. + * + * @since 7.0 */ public void setBufferSize(int bufferSize) { this.bufferSize = bufferSize; } + /** + * Writes this download stream to a wrapped response. This takes care of + * setting response headers according to what is defined in this download + * stream ({@link #getContentType()}, {@link #getCacheTime()}, + * {@link #getFileName()}) and transferring the data from the stream ( + * {@link #getStream()}) to the response. Defined parameters ( + * {@link #getParameterNames()}) are also included as headers in the + * response. If there's is a parameter named <code>Location</code>, a + * redirect (302 Moved temporarily) is sent instead of the contents of this + * stream. + * + * @param response + * the wrapped response to write this download stream to + * @throws IOException + * passed through from the wrapped response + * + * @since 7.0 + */ + public void writeTo(WrappedResponse response) throws IOException { + if (getParameter("Location") != null) { + response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); + response.setHeader("Location", getParameter("Location")); + return; + } + + // Download from given stream + final InputStream data = getStream(); + if (data != null) { + + OutputStream out = null; + try { + // Sets content type + response.setContentType(getContentType()); + + // Sets cache headers + response.setCacheTime(getCacheTime()); + + // Copy download stream parameters directly + // to HTTP headers. + final Iterator<String> i = getParameterNames(); + if (i != null) { + while (i.hasNext()) { + final String param = i.next(); + response.setHeader(param, getParameter(param)); + } + } + + // suggest local filename from DownloadStream if + // Content-Disposition + // not explicitly set + String contentDispositionValue = getParameter("Content-Disposition"); + if (contentDispositionValue == null) { + contentDispositionValue = "filename=\"" + getFileName() + + "\""; + response.setHeader("Content-Disposition", + contentDispositionValue); + } + + int bufferSize = getBufferSize(); + if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) { + bufferSize = Constants.DEFAULT_BUFFER_SIZE; + } + final byte[] buffer = new byte[bufferSize]; + int bytesRead = 0; + + out = response.getOutputStream(); + + long totalWritten = 0; + while ((bytesRead = data.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + + totalWritten += bytesRead; + if (totalWritten >= buffer.length) { + // Avoid chunked encoding for small resources + out.flush(); + } + } + } finally { + tryToCloseStream(out); + tryToCloseStream(data); + } + } + } + + /** + * Helper method that tries to close an output stream and ignores any + * exceptions. + * + * @param out + * the output stream to close, <code>null</code> is also + * supported + */ + static void tryToCloseStream(OutputStream out) { + try { + // try to close output stream (e.g. file handle) + if (out != null) { + out.close(); + } + } catch (IOException e1) { + // NOP + } + } + + /** + * Helper method that tries to close an input stream and ignores any + * exceptions. + * + * @param in + * the input stream to close, <code>null</code> is also supported + */ + static void tryToCloseStream(InputStream in) { + try { + // try to close output stream (e.g. file handle) + if (in != null) { + in.close(); + } + } catch (IOException e1) { + // NOP + } + } + } diff --git a/src/com/vaadin/terminal/ErrorMessage.java b/src/com/vaadin/terminal/ErrorMessage.java index b3be407743..60a0780a72 100644 --- a/src/com/vaadin/terminal/ErrorMessage.java +++ b/src/com/vaadin/terminal/ErrorMessage.java @@ -15,66 +15,112 @@ import java.io.Serializable; * @VERSION@ * @since 3.0 */ -public interface ErrorMessage extends Paintable, Serializable { +public interface ErrorMessage extends Serializable { + + public enum ErrorLevel { + /** + * Error code for informational messages. + */ + INFORMATION("info", 0), + /** + * Error code for warning messages. + */ + WARNING("warning", 1), + /** + * Error code for regular error messages. + */ + ERROR("error", 2), + /** + * Error code for critical error messages. + */ + CRITICAL("critical", 3), + /** + * Error code for system errors and bugs. + */ + SYSTEMERROR("system", 4); + + String text; + int errorLevel; + + private ErrorLevel(String text, int errorLevel) { + this.text = text; + this.errorLevel = errorLevel; + } + + /** + * Textual representation for server-client communication of level + * + * @return String for error severity + */ + public String getText() { + return text; + } + + /** + * Integer representation of error severity for comparison + * + * @return integer for error severity + */ + public int intValue() { + return errorLevel; + } + + @Override + public String toString() { + return text; + } + + } /** - * Error code for system errors and bugs. + * @deprecated from 7.0, use {@link ErrorLevel#SYSTEMERROR} instead   */ - public static final int SYSTEMERROR = 5000; + @Deprecated + public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEMERROR; /** - * Error code for critical error messages. + * @deprecated from 7.0, use {@link ErrorLevel#CRITICAL} instead   */ - public static final int CRITICAL = 4000; + @Deprecated + public static final ErrorLevel CRITICAL = ErrorLevel.CRITICAL; /** - * Error code for regular error messages. + * @deprecated from 7.0, use {@link ErrorLevel#ERROR} instead   */ - public static final int ERROR = 3000; + + @Deprecated + public static final ErrorLevel ERROR = ErrorLevel.ERROR; /** - * Error code for warning messages. + * @deprecated from 7.0, use {@link ErrorLevel#WARNING} instead   */ - public static final int WARNING = 2000; + @Deprecated + public static final ErrorLevel WARNING = ErrorLevel.WARNING; /** - * Error code for informational messages. + * @deprecated from 7.0, use {@link ErrorLevel#INFORMATION} instead   */ - public static final int INFORMATION = 1000; + @Deprecated + public static final ErrorLevel INFORMATION = ErrorLevel.INFORMATION; /** * Gets the errors level. * * @return the level of error as an integer. */ - public int getErrorLevel(); + public ErrorLevel getErrorLevel(); /** - * Error messages are inmodifiable and thus listeners are not needed. This - * method should be implemented as empty. + * Returns the HTML formatted message to show in as the error message on the + * client. * - * @param listener - * the listener to be added. - * @see com.vaadin.terminal.Paintable#addListener(Paintable.RepaintRequestListener) - */ - public void addListener(RepaintRequestListener listener); - - /** - * Error messages are inmodifiable and thus listeners are not needed. This - * method should be implemented as empty. + * This method should perform any necessary escaping to avoid XSS attacks. * - * @param listener - * the listener to be removed. - * @see com.vaadin.terminal.Paintable#removeListener(Paintable.RepaintRequestListener) - */ - public void removeListener(RepaintRequestListener listener); - - /** - * Error messages are inmodifiable and thus listeners are not needed. This - * method should be implemented as empty. + * TODO this API may still change to use a separate data transfer object * - * @see com.vaadin.terminal.Paintable#requestRepaint() + * @return HTML formatted string for the error message + * @since 7.0 */ - public void requestRepaint(); + public String getFormattedHtmlMessage(); } diff --git a/src/com/vaadin/terminal/KeyMapper.java b/src/com/vaadin/terminal/KeyMapper.java index d44cd0de3a..3f19692ef1 100644 --- a/src/com/vaadin/terminal/KeyMapper.java +++ b/src/com/vaadin/terminal/KeyMapper.java @@ -5,7 +5,7 @@ package com.vaadin.terminal; import java.io.Serializable; -import java.util.Hashtable; +import java.util.HashMap; /** * <code>KeyMapper</code> is the simple two-way map for generating textual keys @@ -16,14 +16,13 @@ import java.util.Hashtable; * @VERSION@ * @since 3.0 */ -@SuppressWarnings("serial") -public class KeyMapper implements Serializable { +public class KeyMapper<V> implements Serializable { private int lastKey = 0; - private final Hashtable<Object, String> objectKeyMap = new Hashtable<Object, String>(); + private final HashMap<V, String> objectKeyMap = new HashMap<V, String>(); - private final Hashtable<String, Object> keyObjectMap = new Hashtable<String, Object>(); + private final HashMap<String, V> keyObjectMap = new HashMap<String, V>(); /** * Gets key for an object. @@ -31,7 +30,7 @@ public class KeyMapper implements Serializable { * @param o * the object. */ - public String key(Object o) { + public String key(V o) { if (o == null) { return "null"; @@ -58,8 +57,7 @@ public class KeyMapper implements Serializable { * the name with the desired value. * @return the object with the key. */ - public Object get(String key) { - + public V get(String key) { return keyObjectMap.get(key); } @@ -69,7 +67,7 @@ public class KeyMapper implements Serializable { * @param removeobj * the object to be removed. */ - public void remove(Object removeobj) { + public void remove(V removeobj) { final String key = objectKeyMap.get(removeobj); if (key != null) { diff --git a/src/com/vaadin/terminal/LegacyPaint.java b/src/com/vaadin/terminal/LegacyPaint.java new file mode 100644 index 0000000000..ea93e3db7f --- /dev/null +++ b/src/com/vaadin/terminal/LegacyPaint.java @@ -0,0 +1,85 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal; + +import java.io.Serializable; + +import com.vaadin.terminal.PaintTarget.PaintStatus; +import com.vaadin.ui.Component; +import com.vaadin.ui.HasComponents; + +public class LegacyPaint implements Serializable { + /** + * + * <p> + * Paints the Paintable into a UIDL stream. This method creates the UIDL + * sequence describing it and outputs it to the given UIDL stream. + * </p> + * + * <p> + * It is called when the contents of the component should be painted in + * response to the component first being shown or having been altered so + * that its visual representation is changed. + * </p> + * + * <p> + * <b>Do not override this to paint your component.</b> Override + * {@link #paintContent(PaintTarget)} instead. + * </p> + * + * + * @param target + * the target UIDL stream where the component should paint itself + * to. + * @throws PaintException + * if the paint operation failed. + */ + public static void paint(Component component, PaintTarget target) + throws PaintException { + // Only paint content of visible components. + if (!isVisibleInContext(component)) { + return; + } + + final String tag = target.getTag(component); + final PaintStatus status = target.startPaintable(component, tag); + if (PaintStatus.CACHED == status) { + // nothing to do but flag as cached and close the paintable tag + target.addAttribute("cached", true); + } else { + // Paint the contents of the component + if (component instanceof Vaadin6Component) { + ((Vaadin6Component) component).paintContent(target); + } + + } + target.endPaintable(component); + + } + + /** + * Checks if the component is visible and its parent is visible, + * recursively. + * <p> + * This is only a helper until paint is moved away from this class. + * + * @return + */ + protected static boolean isVisibleInContext(Component c) { + HasComponents p = c.getParent(); + while (p != null) { + if (!p.isVisible()) { + return false; + } + p = p.getParent(); + } + if (c.getParent() != null && !c.getParent().isComponentVisible(c)) { + return false; + } + + // All parents visible, return this state + return c.isVisible(); + } + +} diff --git a/src/com/vaadin/terminal/PaintTarget.java b/src/com/vaadin/terminal/PaintTarget.java index 68f68e2b51..9cfa324133 100644 --- a/src/com/vaadin/terminal/PaintTarget.java +++ b/src/com/vaadin/terminal/PaintTarget.java @@ -9,6 +9,7 @@ import java.util.Map; import com.vaadin.terminal.StreamVariable.StreamingStartEvent; import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.server.ClientConnector; /** * This interface defines the methods for painting XML to the UIDL stream. @@ -37,6 +38,26 @@ public interface PaintTarget extends Serializable { throws PaintException; /** + * Result of starting to paint a Paintable ( + * {@link PaintTarget#startPaintable(ClientConnector, String)}). + * + * @since 7.0 + */ + public enum PaintStatus { + /** + * Painting started, addVariable() and addAttribute() etc. methods may + * be called. + */ + PAINTING, + /** + * A previously unpainted or painted {@link Paintable} has been queued + * be created/update later in a separate change in the same set of + * changes. + */ + CACHED + }; + + /** * Prints element start tag of a paintable section. Starts a paintable * section using the given tag. The PaintTarget may implement a caching * scheme, that checks the paintable has actually changed or can a cached @@ -46,43 +67,45 @@ public interface PaintTarget extends Serializable { * omit the content and close the tag, in which case cached content should * be used. * </p> + * <p> + * This method may also add only a reference to the paintable and queue the + * paintable to be painted separately. + * </p> + * <p> + * Each paintable being painted should be closed by a matching + * {@link #endPaintable(ClientConnector)} regardless of the + * {@link PaintStatus} returned. + * </p> * * @param paintable * the paintable to start. * @param tag * the name of the start tag. - * @return <code>true</code> if paintable found in cache, <code>false</code> - * otherwise. + * @return {@link PaintStatus} - ready to paint or already cached on the + * client (also used for sub paintables that are painted later + * separately) * @throws PaintException * if the paint operation failed. * @see #startTag(String) - * @since 3.1 + * @since 7.0 (previously using startTag(Paintable, String)) */ - public boolean startTag(Paintable paintable, String tag) + public PaintStatus startPaintable(ClientConnector paintable, String tag) throws PaintException; /** - * Paints a component reference as an attribute to current tag. This method - * is meant to enable component interactions on client side. With reference - * the client side component can communicate directly to other component. + * Prints paintable element end tag. * - * Note! This was experimental api and got replaced by - * {@link #addAttribute(String, Paintable)} and - * {@link #addVariable(VariableOwner, String, Paintable)}. + * Calls to {@link #startPaintable(ClientConnector, String)}should be + * matched by {@link #endPaintable(ClientConnector)}. If the parent tag is + * closed before every child tag is closed a PaintException is raised. * * @param paintable - * the Paintable to reference - * @param referenceName + * the paintable to close. * @throws PaintException - * - * @since 5.2 - * @deprecated use {@link #addAttribute(String, Paintable)} or - * {@link #addVariable(VariableOwner, String, Paintable)} - * instead + * if the paint operation failed. + * @since 7.0 (previously using engTag(String)) */ - @Deprecated - public void paintReference(Paintable paintable, String referenceName) - throws PaintException; + public void endPaintable(ClientConnector paintable) throws PaintException; /** * Prints element start tag. @@ -266,7 +289,7 @@ public interface PaintTarget extends Serializable { * the Paintable to be referenced on client side * @throws PaintException */ - public void addAttribute(String name, Paintable value) + public void addAttribute(String name, ClientConnector value) throws PaintException; /** @@ -398,8 +421,8 @@ public interface PaintTarget extends Serializable { * @throws PaintException * if the paint oparation fails */ - public void addVariable(VariableOwner owner, String name, Paintable value) - throws PaintException; + public void addVariable(VariableOwner owner, String name, + ClientConnector value) throws PaintException; /** * Adds a upload stream type variable. @@ -470,14 +493,15 @@ public interface PaintTarget extends Serializable { /** * @return the "tag" string used in communication to present given - * {@link Paintable} type. Terminal may define how to present - * paintable. + * {@link ClientConnector} type. Terminal may define how to present + * the connector. */ - public String getTag(Paintable paintable); + public String getTag(ClientConnector paintable); /** * @return true if a full repaint has been requested. E.g. refresh in a * browser window or such. */ public boolean isFullRepaint(); + } diff --git a/src/com/vaadin/terminal/Paintable.java b/src/com/vaadin/terminal/Paintable.java deleted file mode 100644 index d043cb2606..0000000000 --- a/src/com/vaadin/terminal/Paintable.java +++ /dev/null @@ -1,147 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.util.EventObject; - -/** - * Interface implemented by all classes that can be painted. Classes - * implementing this interface know how to output themselves to a UIDL stream - * and that way describing to the terminal how it should be displayed in the UI. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Paintable extends java.util.EventListener, Serializable { - - /** - * <p> - * Paints the Paintable into a UIDL stream. This method creates the UIDL - * sequence describing it and outputs it to the given UIDL stream. - * </p> - * - * <p> - * It is called when the contents of the component should be painted in - * response to the component first being shown or having been altered so - * that its visual representation is changed. - * </p> - * - * @param target - * the target UIDL stream where the component should paint itself - * to. - * @throws PaintException - * if the paint operation failed. - */ - public void paint(PaintTarget target) throws PaintException; - - /** - * Requests that the paintable should be repainted as soon as possible. - */ - public void requestRepaint(); - - /** - * Adds an unique id for component that get's transferred to terminal for - * testing purposes. Keeping identifiers unique throughout the Application - * instance is on programmers responsibility. - * <p> - * Note, that with the current terminal implementation the identifier cannot - * be changed while the component is visible. This means that the identifier - * should be set before the component is painted for the first time and kept - * the same while visible in the client. - * - * @param id - * A short (< 20 chars) alphanumeric id - */ - public void setDebugId(String id); - - /** - * Get's currently set debug identifier - * - * @return current debug id, null if not set - */ - public String getDebugId(); - - /** - * Repaint request event is thrown when the paintable needs to be repainted. - * This is typically done when the <code>paint</code> method would return - * dissimilar UIDL from the previous call of the method. - */ - @SuppressWarnings("serial") - public class RepaintRequestEvent extends EventObject { - - /** - * Constructs a new event. - * - * @param source - * the paintable needing repaint. - */ - public RepaintRequestEvent(Paintable source) { - super(source); - } - - /** - * Gets the paintable needing repainting. - * - * @return Paintable for which the <code>paint</code> method will return - * dissimilar UIDL from the previous call of the method. - */ - public Paintable getPaintable() { - return (Paintable) getSource(); - } - } - - /** - * Listens repaint requests. The <code>repaintRequested</code> method is - * called when the paintable needs to be repainted. This is typically done - * when the <code>paint</code> method would return dissimilar UIDL from the - * previous call of the method. - */ - public interface RepaintRequestListener extends Serializable { - - /** - * Receives repaint request events. - * - * @param event - * the repaint request event specifying the paintable source. - */ - public void repaintRequested(RepaintRequestEvent event); - } - - /** - * Adds repaint request listener. In order to assure that no repaint - * requests are missed, the new repaint listener should paint the paintable - * right after adding itself as listener. - * - * @param listener - * the listener to be added. - */ - public void addListener(RepaintRequestListener listener); - - /** - * Removes repaint request listener. - * - * @param listener - * the listener to be removed. - */ - public void removeListener(RepaintRequestListener listener); - - /** - * Request sending of repaint events on any further visible changes. - * Normally the paintable only send up to one repaint request for listeners - * after paint as the paintable as the paintable assumes that the listeners - * already know about the repaint need. This method resets the assumtion. - * Paint implicitly does the assumtion reset functionality implemented by - * this method. - * <p> - * This method is normally used only by the terminals to note paintables - * about implicit repaints (painting the component without actually invoking - * paint method). - * </p> - */ - public void requestRepaintRequests(); -} diff --git a/src/com/vaadin/terminal/ParameterHandler.java b/src/com/vaadin/terminal/ParameterHandler.java deleted file mode 100644 index ef8a952e0e..0000000000 --- a/src/com/vaadin/terminal/ParameterHandler.java +++ /dev/null @@ -1,59 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.util.Map; - -import com.vaadin.ui.Window; - -/** - * {@code ParameterHandler} is implemented by classes capable of handling - * external parameters. - * - * <p> - * What parameters are provided depend on what the {@link Terminal} provides and - * if the application is deployed as a servlet or portlet. URL GET parameters - * are typically provided to the {@link #handleParameters(Map)} method. - * </p> - * <p> - * A {@code ParameterHandler} must be registered to a {@code Window} using - * {@link Window#addParameterHandler(ParameterHandler)} to be called when - * parameters are available. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface ParameterHandler extends Serializable { - - /** - * Handles the given parameters. All parameters names are of type - * {@link String} and the values are {@link String} arrays. - * - * @param parameters - * an unmodifiable map which contains the parameter names and - * values - * - */ - public void handleParameters(Map<String, String[]> parameters); - - /** - * An ErrorEvent implementation for ParameterHandler. - */ - public interface ErrorEvent extends Terminal.ErrorEvent { - - /** - * Gets the ParameterHandler that caused the error. - * - * @return the ParameterHandler that caused the error - */ - public ParameterHandler getParameterHandler(); - - } - -} diff --git a/src/com/vaadin/terminal/RequestHandler.java b/src/com/vaadin/terminal/RequestHandler.java new file mode 100644 index 0000000000..f37201715d --- /dev/null +++ b/src/com/vaadin/terminal/RequestHandler.java @@ -0,0 +1,36 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.io.IOException; +import java.io.Serializable; + +import com.vaadin.Application; + +/** + * Handler for producing a response to non-UIDL requests. Handlers can be added + * to applications using {@link Application#addRequestHandler(RequestHandler)} + */ +public interface RequestHandler extends Serializable { + + /** + * Handles a non-UIDL request. If a response is written, this method should + * return <code>false</code> to indicate that no more request handlers + * should be invoked for the request. + * + * @param application + * The application to which the request belongs + * @param request + * The request to handle + * @param response + * The response object to which a response can be written. + * @return true if a response has been written and no further request + * handlers should be called, otherwise false + * @throws IOException + */ + boolean handleRequest(Application application, WrappedRequest request, + WrappedResponse response) throws IOException; + +} diff --git a/src/com/vaadin/terminal/Scrollable.java b/src/com/vaadin/terminal/Scrollable.java index dac35c7704..472954c556 100644 --- a/src/com/vaadin/terminal/Scrollable.java +++ b/src/com/vaadin/terminal/Scrollable.java @@ -9,8 +9,7 @@ import java.io.Serializable; /** * <p> * This interface is implemented by all visual objects that can be scrolled - * programmatically from the server-side, or for which it is possible to know - * the scroll position on the server-side. The unit of scrolling is pixel. + * programmatically from the server-side. The unit of scrolling is pixel. * </p> * * @author Vaadin Ltd. @@ -40,17 +39,10 @@ public interface Scrollable extends Serializable { * scrolled right. * </p> * - * <p> - * The method only has effect if programmatic scrolling is enabled for the - * scrollable. Some implementations may require enabling programmatic before - * this method can be used. See {@link #setScrollable(boolean)} for more - * information. - * </p> - * - * @param pixelsScrolled + * @param scrollLeft * the xOffset. */ - public void setScrollLeft(int pixelsScrolled); + public void setScrollLeft(int scrollLeft); /** * Gets scroll top offset. @@ -73,13 +65,6 @@ public interface Scrollable extends Serializable { * </p> * * <p> - * The method only has effect if programmatic scrolling is enabled for the - * scrollable. Some implementations may require enabling programmatic before - * this method can be used. See {@link #setScrollable(boolean)} for more - * information. - * </p> - * - * <p> * The scrolling position is limited by the current height of the content * area. If the position is below the height, it is scrolled to the bottom. * However, if the same response also adds height to the content area, @@ -87,44 +72,9 @@ public interface Scrollable extends Serializable { * area. * </p> * - * @param pixelsScrolled + * @param scrollTop * the yOffset. */ - public void setScrollTop(int pixelsScrolled); - - /** - * Is programmatic scrolling enabled. - * - * <p> - * Whether programmatic scrolling with {@link #setScrollLeft(int)} and - * {@link #setScrollTop(int)} is enabled. - * </p> - * - * @return <code>true</code> if the scrolling is enabled, otherwise - * <code>false</code>. - */ - public boolean isScrollable(); - - /** - * Enables or disables programmatic scrolling. - * - * <p> - * Enables setting the scroll position with {@link #setScrollLeft(int)} and - * {@link #setScrollTop(int)}. Implementations of the interface may have - * programmatic scrolling disabled by default, in which case you need to - * enable it to use the mentioned methods. - * </p> - * - * <p> - * Notice that this does <i>not</i> control whether scroll bars are shown - * for a scrollable component. That normally happens automatically when the - * content grows too big for the component, relying on the "overflow: auto" - * property in CSS. - * </p> - * - * @param isScrollingEnabled - * true if the scrolling is allowed. - */ - public void setScrollable(boolean isScrollingEnabled); + public void setScrollTop(int scrollTop); } diff --git a/src/com/vaadin/terminal/Sizeable.java b/src/com/vaadin/terminal/Sizeable.java index f5dc28b74c..e3c98e0fa9 100644 --- a/src/com/vaadin/terminal/Sizeable.java +++ b/src/com/vaadin/terminal/Sizeable.java @@ -18,71 +18,127 @@ import java.io.Serializable; public interface Sizeable extends Serializable { /** - * Unit code representing pixels. + * @deprecated from 7.0, use {@link Unit#PIXELS} instead   */ - public static final int UNITS_PIXELS = 0; + @Deprecated + public static final Unit UNITS_PIXELS = Unit.PIXELS; /** - * Unit code representing points (1/72nd of an inch). + * @deprecated from 7.0, use {@link Unit#POINTS} instead   */ - public static final int UNITS_POINTS = 1; + @Deprecated + public static final Unit UNITS_POINTS = Unit.POINTS; /** - * Unit code representing picas (12 points). + * @deprecated from 7.0, use {@link Unit#PICAS} instead   */ - public static final int UNITS_PICAS = 2; + @Deprecated + public static final Unit UNITS_PICAS = Unit.PICAS; /** - * Unit code representing the font-size of the relevant font. + * @deprecated from 7.0, use {@link Unit#EM} instead   */ - public static final int UNITS_EM = 3; + @Deprecated + public static final Unit UNITS_EM = Unit.EM; /** - * Unit code representing the x-height of the relevant font. + * @deprecated from 7.0, use {@link Unit#EX} instead   */ - public static final int UNITS_EX = 4; + @Deprecated + public static final Unit UNITS_EX = Unit.EX; /** - * Unit code representing millimeters. + * @deprecated from 7.0, use {@link Unit#MM} instead   */ - public static final int UNITS_MM = 5; + @Deprecated + public static final Unit UNITS_MM = Unit.MM; /** - * Unit code representing centimeters. + * @deprecated from 7.0, use {@link Unit#CM} instead   */ - public static final int UNITS_CM = 6; + @Deprecated + public static final Unit UNITS_CM = Unit.CM; /** - * Unit code representing inches. + * @deprecated from 7.0, use {@link Unit#INCH} instead   */ - public static final int UNITS_INCH = 7; + @Deprecated + public static final Unit UNITS_INCH = Unit.INCH; /** - * Unit code representing in percentage of the containing element defined by - * terminal. + * @deprecated from 7.0, use {@link Unit#PERCENTAGE} instead   */ - public static final int UNITS_PERCENTAGE = 8; + @Deprecated + public static final Unit UNITS_PERCENTAGE = Unit.PERCENTAGE; public static final float SIZE_UNDEFINED = -1; - /** - * Textual representations of units symbols. Supported units and their - * symbols are: - * <ul> - * <li>{@link #UNITS_PIXELS}: "px"</li> - * <li>{@link #UNITS_POINTS}: "pt"</li> - * <li>{@link #UNITS_PICAS}: "pc"</li> - * <li>{@link #UNITS_EM}: "em"</li> - * <li>{@link #UNITS_EX}: "ex"</li> - * <li>{@link #UNITS_MM}: "mm"</li> - * <li>{@link #UNITS_CM}. "cm"</li> - * <li>{@link #UNITS_INCH}: "in"</li> - * <li>{@link #UNITS_PERCENTAGE}: "%"</li> - * </ul> - * These can be used like <code>Sizeable.UNIT_SYMBOLS[UNITS_PIXELS]</code>. - */ - public static final String[] UNIT_SYMBOLS = { "px", "pt", "pc", "em", "ex", - "mm", "cm", "in", "%" }; + public enum Unit { + /** + * Unit code representing pixels. + */ + PIXELS("px"), + /** + * Unit code representing points (1/72nd of an inch). + */ + POINTS("pt"), + /** + * Unit code representing picas (12 points). + */ + PICAS("pc"), + /** + * Unit code representing the font-size of the relevant font. + */ + EM("em"), + /** + * Unit code representing the x-height of the relevant font. + */ + EX("ex"), + /** + * Unit code representing millimeters. + */ + MM("mm"), + /** + * Unit code representing centimeters. + */ + CM("cm"), + /** + * Unit code representing inches. + */ + INCH("in"), + /** + * Unit code representing in percentage of the containing element + * defined by terminal. + */ + PERCENTAGE("%"); + + private String symbol; + + private Unit(String symbol) { + this.symbol = symbol; + } + + public String getSymbol() { + return symbol; + } + + @Override + public String toString() { + return symbol; + } + + public static Unit getUnitFromSymbol(String symbol) { + if (symbol == null) { + return Unit.PIXELS; // Defaults to pixels + } + for (Unit unit : Unit.values()) { + if (symbol.equals(unit.getSymbol())) { + return unit; + } + } + return Unit.PIXELS; // Defaults to pixels + } + } /** * Gets the width of the object. Negative number implies unspecified size @@ -93,21 +149,6 @@ public interface Sizeable extends Serializable { public float getWidth(); /** - * Sets the width of the object. Negative number implies unspecified size - * (terminal is free to set the size). - * - * @param width - * the width of the object in units specified by widthUnits - * property. - * @deprecated Consider using {@link #setWidth(String)} instead. This method - * works, but is error-prone since the unit must be set - * separately (and components might have different default - * unit). - */ - @Deprecated - public void setWidth(float width); - - /** * Gets the height of the object. Negative number implies unspecified size * (terminal is free to set the size). * @@ -116,57 +157,18 @@ public interface Sizeable extends Serializable { public float getHeight(); /** - * Sets the height of the object. Negative number implies unspecified size - * (terminal is free to set the size). - * - * @param height - * the height of the object in units specified by heightUnits - * property. - * @deprecated Consider using {@link #setHeight(String)} or - * {@link #setHeight(float, int)} instead. This method works, - * but is error-prone since the unit must be set separately (and - * components might have different default unit). - */ - @Deprecated - public void setHeight(float height); - - /** * Gets the width property units. * * @return units used in width property. */ - public int getWidthUnits(); - - /** - * Sets the width property units. - * - * @param units - * the units used in width property. - * @deprecated Consider setting width and unit simultaneously using - * {@link #setWidth(String)} or {@link #setWidth(float, int)}, - * which is less error-prone. - */ - @Deprecated - public void setWidthUnits(int units); + public Unit getWidthUnits(); /** * Gets the height property units. * * @return units used in height property. */ - public int getHeightUnits(); - - /** - * Sets the height property units. - * - * @param units - * the units used in height property. - * @deprecated Consider setting height and unit simultaneously using - * {@link #setHeight(String)} or {@link #setHeight(float, int)}, - * which is less error-prone. - */ - @Deprecated - public void setHeightUnits(int units); + public Unit getHeightUnits(); /** * Sets the height of the component using String presentation. @@ -193,13 +195,9 @@ public interface Sizeable extends Serializable { * @param width * the width of the object. * @param unit - * the unit used for the width. Possible values include - * {@link #UNITS_PIXELS}, {@link #UNITS_POINTS}, - * {@link #UNITS_PICAS}, {@link #UNITS_EM}, {@link #UNITS_EX}, - * {@link #UNITS_MM}, {@link #UNITS_CM}, {@link #UNITS_INCH}, - * {@link #UNITS_PERCENTAGE}. + * the unit used for the width. */ - public void setWidth(float width, int unit); + public void setWidth(float width, Unit unit); /** * Sets the height of the object. Negative number implies unspecified size @@ -208,13 +206,9 @@ public interface Sizeable extends Serializable { * @param height * the height of the object. * @param unit - * the unit used for the width. Possible values include - * {@link #UNITS_PIXELS}, {@link #UNITS_POINTS}, - * {@link #UNITS_PICAS}, {@link #UNITS_EM}, {@link #UNITS_EX}, - * {@link #UNITS_MM}, {@link #UNITS_CM}, {@link #UNITS_INCH}, - * {@link #UNITS_PERCENTAGE}. + * the unit used for the width. */ - public void setHeight(float height, int unit); + public void setHeight(float height, Unit unit); /** * Sets the width of the component using String presentation. diff --git a/src/com/vaadin/terminal/SystemError.java b/src/com/vaadin/terminal/SystemError.java index ce1483dbb5..bae135ee6b 100644 --- a/src/com/vaadin/terminal/SystemError.java +++ b/src/com/vaadin/terminal/SystemError.java @@ -4,16 +4,12 @@ package com.vaadin.terminal; -import java.io.PrintWriter; -import java.io.StringWriter; - import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; /** - * <code>SystemError</code> is a runtime exception caused by error in system. - * The system error can be shown to the user as it implements - * <code>ErrorMessage</code> interface, but contains technical information such - * as stack trace and exception. + * <code>SystemError</code> is an error message for a problem caused by error in + * system, not the user application code. The system error can contain technical + * information such as stack trace and exception. * * SystemError does not support HTML in error messages or stack traces. If HTML * messages are required, use {@link UserError} or a custom implementation of @@ -25,13 +21,7 @@ import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; * @since 3.0 */ @SuppressWarnings("serial") -public class SystemError extends RuntimeException implements ErrorMessage { - - /** - * The cause of the system error. The cause is stored separately as JDK 1.3 - * does not support causes natively. - */ - private Throwable cause = null; +public class SystemError extends AbstractErrorMessage { /** * Constructor for SystemError with error message specified. @@ -41,6 +31,9 @@ public class SystemError extends RuntimeException implements ErrorMessage { */ public SystemError(String message) { super(message); + setErrorLevel(ErrorLevel.SYSTEMERROR); + setMode(ContentMode.XHTML); + setMessage(getHtmlMessage()); } /** @@ -52,8 +45,8 @@ public class SystemError extends RuntimeException implements ErrorMessage { * the throwable causing the system error. */ public SystemError(String message, Throwable cause) { - super(message); - this.cause = cause; + this(message); + addCause(AbstractErrorMessage.getErrorMessageForException(cause)); } /** @@ -63,31 +56,7 @@ public class SystemError extends RuntimeException implements ErrorMessage { * the throwable causing the system error. */ public SystemError(Throwable cause) { - this.cause = cause; - } - - /** - * @see com.vaadin.terminal.ErrorMessage#getErrorLevel() - */ - public final int getErrorLevel() { - return ErrorMessage.SYSTEMERROR; - } - - /** - * @see com.vaadin.terminal.Paintable#paint(com.vaadin.terminal.PaintTarget) - */ - public void paint(PaintTarget target) throws PaintException { - - target.startTag("error"); - target.addAttribute("level", "system"); - - String message = getHtmlMessage(); - - target.addXMLSection("div", message, - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); - - target.endTag("error"); - + this(null, cause); } /** @@ -96,61 +65,18 @@ public class SystemError extends RuntimeException implements ErrorMessage { * Note that this API may change in future versions. */ protected String getHtmlMessage() { + // TODO wrapping div with namespace? See the old code: + // target.addXMLSection("div", message, + // "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); + StringBuilder sb = new StringBuilder(); - final String message = getLocalizedMessage(); - if (message != null) { + if (getMessage() != null) { sb.append("<h2>"); - sb.append(AbstractApplicationServlet.safeEscapeForHtml(message)); + sb.append(AbstractApplicationServlet + .safeEscapeForHtml(getMessage())); sb.append("</h2>"); } - - // Paint the exception - if (cause != null) { - sb.append("<h3>Exception</h3>"); - final StringWriter buffer = new StringWriter(); - cause.printStackTrace(new PrintWriter(buffer)); - sb.append("<pre>"); - sb.append(AbstractApplicationServlet.safeEscapeForHtml(buffer - .toString())); - sb.append("</pre>"); - } return sb.toString(); } - /** - * Gets cause for the error. - * - * @return the cause. - * @see java.lang.Throwable#getCause() - */ - @Override - public Throwable getCause() { - return cause; - } - - /* Documented in super interface */ - public void addListener(RepaintRequestListener listener) { - } - - /* Documented in super interface */ - public void removeListener(RepaintRequestListener listener) { - } - - /* Documented in super interface */ - public void requestRepaint() { - } - - /* Documented in super interface */ - public void requestRepaintRequests() { - } - - public String getDebugId() { - return null; - } - - public void setDebugId(String id) { - throw new UnsupportedOperationException( - "Setting testing id for this Paintable is not implemented"); - } - } diff --git a/src/com/vaadin/terminal/URIHandler.java b/src/com/vaadin/terminal/URIHandler.java deleted file mode 100644 index b3fea0e3bf..0000000000 --- a/src/com/vaadin/terminal/URIHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.net.URL; - -/** - * A URIHandler is used for handling URI:s requested by the user and can - * optionally provide a {@link DownloadStream}. If a {@link DownloadStream} is - * returned by {@link #handleURI(URL, String)}, the stream is sent to the - * client. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface URIHandler extends Serializable { - - /** - * Handles a given URI. If the URI handler to emit a downloadable stream it - * should return a {@code DownloadStream} object. - * - * @param context - * the base URL - * @param relativeUri - * a URI relative to {@code context} - * @return A downloadable stream or null if no stream is provided - */ - public DownloadStream handleURI(URL context, String relativeUri); - - /** - * An {@code ErrorEvent} implementation for URIHandler. - */ - public interface ErrorEvent extends Terminal.ErrorEvent { - - /** - * Gets the URIHandler that caused this error. - * - * @return the URIHandler that caused the error - */ - public URIHandler getURIHandler(); - - } -} diff --git a/src/com/vaadin/terminal/UserError.java b/src/com/vaadin/terminal/UserError.java index 170d76610b..baaf331fa0 100644 --- a/src/com/vaadin/terminal/UserError.java +++ b/src/com/vaadin/terminal/UserError.java @@ -4,8 +4,6 @@ package com.vaadin.terminal; -import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; - /** * <code>UserError</code> is a controlled error occurred in application. User * errors are occur in normal usage of the application and guide the user. @@ -16,43 +14,25 @@ import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; * @since 3.0 */ @SuppressWarnings("serial") -public class UserError implements ErrorMessage { - - /** - * Content mode, where the error contains only plain text. - */ - public static final int CONTENT_TEXT = 0; +public class UserError extends AbstractErrorMessage { /** - * Content mode, where the error contains preformatted text. + * @deprecated from 7.0, use {@link ContentMode#TEXT} instead   */ - public static final int CONTENT_PREFORMATTED = 1; + @Deprecated + public static final ContentMode CONTENT_TEXT = ContentMode.TEXT; /** - * Formatted content mode, where the contents is XML restricted to the UIDL - * 1.0 formatting markups. + * @deprecated from 7.0, use {@link ContentMode#PREFORMATTED} instead   */ - public static final int CONTENT_UIDL = 2; + @Deprecated + public static final ContentMode CONTENT_PREFORMATTED = ContentMode.PREFORMATTED; /** - * Content mode, where the error contains XHTML. + * @deprecated from 7.0, use {@link ContentMode#XHTML} instead   */ - public static final int CONTENT_XHTML = 3; - - /** - * Content mode. - */ - private int mode = CONTENT_TEXT; - - /** - * Message in content mode. - */ - private final String msg; - - /** - * Error level. - */ - private int level = ErrorMessage.ERROR; + @Deprecated + public static final ContentMode CONTENT_XHTML = ContentMode.XHTML; /** * Creates a textual error message of level ERROR. @@ -61,105 +41,20 @@ public class UserError implements ErrorMessage { * the text of the error message. */ public UserError(String textErrorMessage) { - msg = textErrorMessage; + super(textErrorMessage); } - /** - * Creates a error message with level and content mode. - * - * @param message - * the error message. - * @param contentMode - * the content Mode. - * @param errorLevel - * the level of error. - */ - public UserError(String message, int contentMode, int errorLevel) { - - // Check the parameters - if (contentMode < 0 || contentMode > 2) { - throw new java.lang.IllegalArgumentException( - "Unsupported content mode: " + contentMode); + public UserError(String message, ContentMode contentMode, + ErrorLevel errorLevel) { + super(message); + if (contentMode == null) { + contentMode = ContentMode.TEXT; } - - msg = message; - mode = contentMode; - level = errorLevel; - } - - /* Documented in interface */ - public int getErrorLevel() { - return level; - } - - /* Documented in interface */ - public void addListener(RepaintRequestListener listener) { - } - - /* Documented in interface */ - public void removeListener(RepaintRequestListener listener) { - } - - /* Documented in interface */ - public void requestRepaint() { - } - - /* Documented in interface */ - public void paint(PaintTarget target) throws PaintException { - - target.startTag("error"); - - // Error level - if (level >= ErrorMessage.SYSTEMERROR) { - target.addAttribute("level", "system"); - } else if (level >= ErrorMessage.CRITICAL) { - target.addAttribute("level", "critical"); - } else if (level >= ErrorMessage.ERROR) { - target.addAttribute("level", "error"); - } else if (level >= ErrorMessage.WARNING) { - target.addAttribute("level", "warning"); - } else { - target.addAttribute("level", "info"); - } - - // Paint the message - switch (mode) { - case CONTENT_TEXT: - target.addText(AbstractApplicationServlet.safeEscapeForHtml(msg)); - break; - case CONTENT_UIDL: - target.addUIDL(msg); - break; - case CONTENT_PREFORMATTED: - target.addText("<pre>" - + AbstractApplicationServlet.safeEscapeForHtml(msg) - + "</pre>"); - break; - case CONTENT_XHTML: - target.addText(msg); - break; + if (errorLevel == null) { + errorLevel = ErrorLevel.ERROR; } - - target.endTag("error"); - } - - /* Documented in interface */ - public void requestRepaintRequests() { - } - - /* Documented in superclass */ - @Override - public String toString() { - return msg; - } - - public String getDebugId() { - return null; - } - - public void setDebugId(String id) { - throw new UnsupportedOperationException( - "Setting testing id for this Paintable is not implemented"); + setMode(contentMode); + setErrorLevel(errorLevel); } } diff --git a/src/com/vaadin/terminal/Vaadin6Component.java b/src/com/vaadin/terminal/Vaadin6Component.java new file mode 100644 index 0000000000..59cbf956ca --- /dev/null +++ b/src/com/vaadin/terminal/Vaadin6Component.java @@ -0,0 +1,44 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal; + +import java.util.EventListener; + +import com.vaadin.ui.Component; + +/** + * Interface provided to ease porting of Vaadin 6 components to Vaadin 7. By + * implementing this interface your Component will be able to use + * {@link #paintContent(PaintTarget)} and + * {@link #changeVariables(Object, java.util.Map)} just like in Vaadin 6. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public interface Vaadin6Component extends VariableOwner, Component, + EventListener { + + /** + * <p> + * Paints the Paintable into a UIDL stream. This method creates the UIDL + * sequence describing it and outputs it to the given UIDL stream. + * </p> + * + * <p> + * It is called when the contents of the component should be painted in + * response to the component first being shown or having been altered so + * that its visual representation is changed. + * </p> + * + * @param target + * the target UIDL stream where the component should paint itself + * to. + * @throws PaintException + * if the paint operation failed. + */ + public void paintContent(PaintTarget target) throws PaintException; + +} diff --git a/src/com/vaadin/terminal/VariableOwner.java b/src/com/vaadin/terminal/VariableOwner.java index 49e2179ece..c52e04c008 100644 --- a/src/com/vaadin/terminal/VariableOwner.java +++ b/src/com/vaadin/terminal/VariableOwner.java @@ -20,7 +20,10 @@ import java.util.Map; * @version * @VERSION@ * @since 3.0 + * @deprecated in 7.0. Only provided to ease porting of Vaadin 6 components. Do + * not implement this directly, implement {@link Vaadin6Component}. */ +@Deprecated public interface VariableOwner extends Serializable { /** diff --git a/src/com/vaadin/terminal/WrappedRequest.java b/src/com/vaadin/terminal/WrappedRequest.java new file mode 100644 index 0000000000..a27213d921 --- /dev/null +++ b/src/com/vaadin/terminal/WrappedRequest.java @@ -0,0 +1,277 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Locale; +import java.util.Map; + +import javax.portlet.PortletRequest; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.annotations.EagerInit; +import com.vaadin.terminal.gwt.server.WebBrowser; +import com.vaadin.ui.Root; + +/** + * A generic request to the server, wrapping a more specific request type, e.g. + * HttpServletReqest or PortletRequest. + * + * @since 7.0 + */ +public interface WrappedRequest extends Serializable { + + /** + * Detailed information extracted from the browser. + * + * @see WrappedRequest#getBrowserDetails() + */ + public interface BrowserDetails extends Serializable { + /** + * Gets the URI hash fragment for the request. This is typically used to + * encode navigation within an application. + * + * @return the URI hash fragment + */ + public String getUriFragment(); + + /** + * Gets the value of window.name from the browser. This can be used to + * keep track of the specific window between browser reloads. + * + * @return the string value of window.name in the browser + */ + public String getWindowName(); + + /** + * Gets a reference to the {@link WebBrowser} object containing + * additional information, e.g. screen size and the time zone offset. + * + * @return the web browser object + */ + public WebBrowser getWebBrowser(); + } + + /** + * Gets the named request parameter This is typically a HTTP GET or POST + * parameter, though other request types might have other ways of + * representing parameters. + * + * @see javax.servlet.ServletRequest#getParameter(String) + * @see javax.portlet.PortletRequest#getParameter(String) + * + * @param parameter + * the name of the parameter + * @return The paramter value, or <code>null</code> if no parameter with the + * given name is present + */ + public String getParameter(String parameter); + + /** + * Gets all the parameters of the request. + * + * @see #getParameter(String) + * + * @see javax.servlet.ServletRequest#getParameterMap() + * @see javax.portlet.PortletRequest#getParameter(String) + * + * @return A mapping of parameter names to arrays of parameter values + */ + public Map<String, String[]> getParameterMap(); + + /** + * Returns the length of the request content that can be read from the input + * stream returned by {@link #getInputStream()}. + * + * @see javax.servlet.ServletRequest#getContentLength() + * @see javax.portlet.ClientDataRequest#getContentLength() + * + * @return content length in bytes + */ + public int getContentLength(); + + /** + * Returns an input stream from which the request content can be read. The + * request content length can be obtained with {@link #getContentLength()} + * without reading the full stream contents. + * + * @see javax.servlet.ServletRequest#getInputStream() + * @see javax.portlet.ClientDataRequest#getPortletInputStream() + * + * @return the input stream from which the contents of the request can be + * read + * @throws IOException + * if the input stream can not be opened + */ + public InputStream getInputStream() throws IOException; + + /** + * Gets a request attribute. + * + * @param name + * the name of the attribute + * @return the value of the attribute, or <code>null</code> if there is no + * attribute with the given name + * + * @see javax.servlet.ServletRequest#getAttribute(String) + * @see javax.portlet.PortletRequest#getAttribute(String) + */ + public Object getAttribute(String name); + + /** + * Defines a request attribute. + * + * @param name + * the name of the attribute + * @param value + * the attribute value + * + * @see javax.servlet.ServletRequest#setAttribute(String, Object) + * @see javax.portlet.PortletRequest#setAttribute(String, Object) + */ + public void setAttribute(String name, Object value); + + /** + * Gets the path of the requested resource relative to the application. The + * path be <code>null</code> if no path information is available. Does + * always start with / if the path isn't <code>null</code>. + * + * @return a string with the path relative to the application. + * + * @see javax.servlet.http.HttpServletRequest#getPathInfo() + */ + public String getRequestPathInfo(); + + /** + * Returns the maximum time interval, in seconds, that the session + * associated with this request will be kept open between client accesses. + * + * @return an integer specifying the number of seconds the session + * associated with this request remains open between client requests + * + * @see javax.servlet.http.HttpSession#getMaxInactiveInterval() + * @see javax.portlet.PortletSession#getMaxInactiveInterval() + */ + public int getSessionMaxInactiveInterval(); + + /** + * Gets an attribute from the session associated with this request. + * + * @param name + * the name of the attribute + * @return the attribute value, or <code>null</code> if the attribute is not + * defined in the session + * + * @see javax.servlet.http.HttpSession#getAttribute(String) + * @see javax.portlet.PortletSession#getAttribute(String) + */ + public Object getSessionAttribute(String name); + + /** + * Saves an attribute value in the session associated with this request. + * + * @param name + * the name of the attribute + * @param attribute + * the attribute value + * + * @see javax.servlet.http.HttpSession#setAttribute(String, Object) + * @see javax.portlet.PortletSession#setAttribute(String, Object) + */ + public void setSessionAttribute(String name, Object attribute); + + /** + * Returns the MIME type of the body of the request, or null if the type is + * not known. + * + * @return a string containing the name of the MIME type of the request, or + * null if the type is not known + * + * @see javax.servlet.ServletRequest#getContentType() + * @see javax.portlet.ResourceRequest#getContentType() + * + */ + public String getContentType(); + + /** + * Gets detailed information about the browser from which the request + * originated. This consists of information that is not available from + * normal HTTP requests, but requires additional information to be extracted + * for instance using javascript in the browser. + * + * This information is only guaranteed to be available in some special + * cases, for instance when {@link Application#getRoot} is called again + * after throwing {@link RootRequiresMoreInformationException} or in + * {@link Root#init(WrappedRequest)} for a Root class not annotated with + * {@link EagerInit} + * + * @return the browser details, or <code>null</code> if details are not + * available + * + * @see BrowserDetails + */ + public BrowserDetails getBrowserDetails(); + + /** + * Gets locale information from the query, e.g. using the Accept-Language + * header. + * + * @return the preferred Locale + * + * @see ServletRequest#getLocale() + * @see PortletRequest#getLocale() + */ + public Locale getLocale(); + + /** + * Returns the IP address from which the request came. This might also be + * the address of a proxy between the server and the original requester. + * + * @return a string containing the IP address, or <code>null</code> if the + * address is not available + * + * @see ServletRequest#getRemoteAddr() + */ + public String getRemoteAddr(); + + /** + * Checks whether the request was made using a secure channel, e.g. using + * https. + * + * @return a boolean indicating if the request is secure + * + * @see ServletRequest#isSecure() + * @see PortletRequest#isSecure() + */ + public boolean isSecure(); + + /** + * Gets the value of a request header, e.g. a http header for a + * {@link HttpServletRequest}. + * + * @param headerName + * the name of the header + * @return the header value, or <code>null</code> if the header is not + * present in the request + * + * @see HttpServletRequest#getHeader(String) + */ + public String getHeader(String headerName); + + /** + * Gets the deployment configuration for the context of this request. + * + * @return the deployment configuration + * + * @see DeploymentConfiguration + */ + public DeploymentConfiguration getDeploymentConfiguration(); + +} diff --git a/src/com/vaadin/terminal/WrappedResponse.java b/src/com/vaadin/terminal/WrappedResponse.java new file mode 100644 index 0000000000..995133a269 --- /dev/null +++ b/src/com/vaadin/terminal/WrappedResponse.java @@ -0,0 +1,147 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.Serializable; + +import javax.portlet.MimeResponse; +import javax.portlet.PortletResponse; +import javax.portlet.ResourceResponse; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +/** + * A generic response from the server, wrapping a more specific response type, + * e.g. HttpServletResponse or PortletResponse. + * + * @since 7.0 + */ +public interface WrappedResponse extends Serializable { + + /** + * Sets the (http) status code for the response. If you want to include an + * error message along the status code, use {@link #sendError(int, String)} + * instead. + * + * @param statusCode + * the status code to set + * @see HttpServletResponse#setStatus(int) + * + * @see ResourceResponse#HTTP_STATUS_CODE + */ + public void setStatus(int statusCode); + + /** + * Sets the content type of this response. If the content type including a + * charset is set before {@link #getWriter()} is invoked, the returned + * PrintWriter will automatically use the defined charset. + * + * @param contentType + * a string specifying the MIME type of the content + * + * @see ServletResponse#setContentType(String) + * @see MimeResponse#setContentType(String) + */ + public void setContentType(String contentType); + + /** + * Sets the value of a generic response header. If the header had already + * been set, the new value overwrites the previous one. + * + * @param name + * the name of the header + * @param value + * the header value. + * + * @see HttpServletResponse#setHeader(String, String) + * @see PortletResponse#setProperty(String, String) + */ + public void setHeader(String name, String value); + + /** + * Properly formats a timestamp as a date header. If the header had already + * been set, the new value overwrites the previous one. + * + * @param name + * the name of the header + * @param timestamp + * the number of milliseconds since epoch + * + * @see HttpServletResponse#setDateHeader(String, long) + */ + public void setDateHeader(String name, long timestamp); + + /** + * Returns a <code>OutputStream</code> for writing binary data in the + * response. + * <p> + * Either this method or getWriter() may be called to write the response, + * not both. + * + * @return a <code>OutputStream</code> for writing binary data + * @throws IOException + * if an input or output exception occurred + * + * @see #getWriter() + * @see ServletResponse#getOutputStream() + * @see MimeResponse#getPortletOutputStream() + */ + public OutputStream getOutputStream() throws IOException; + + /** + * Returns a <code>PrintWriter</code> object that can send character text to + * the client. The PrintWriter uses the character encoding defined using + * setContentType. + * <p> + * Either this method or getOutputStream() may be called to write the + * response, not both. + * + * @return a <code>PrintWriter</code> for writing character text + * @throws IOException + * if an input or output exception occurred + * + * @see #getOutputStream() + * @see ServletResponse#getWriter() + * @see MimeResponse#getWriter() + */ + public PrintWriter getWriter() throws IOException; + + /** + * Sets cache time in milliseconds, -1 means no cache at all. All required + * headers related to caching in the response are set based on the time. + * + * @param milliseconds + * Cache time in milliseconds + */ + public void setCacheTime(long milliseconds); + + /** + * Sends an error response to the client using the specified status code and + * clears the buffer. In some configurations, this can cause a predefined + * error page to be displayed. + * + * @param errorCode + * the HTTP status code + * @param message + * a message to accompany the error + * @throws IOException + * if an input or output exception occurs + * + * @see HttpServletResponse#sendError(int, String) + */ + public void sendError(int errorCode, String message) throws IOException; + + /** + * Gets the deployment configuration for the context of this response. + * + * @return the deployment configuration + * + * @see DeploymentConfiguration + */ + public DeploymentConfiguration getDeploymentConfiguration(); +} diff --git a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml index cebfd8a679..f65b4c51e7 100644 --- a/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml +++ b/src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml @@ -1,6 +1,6 @@ <module> - <!-- This GWT module defines the Vaadin DefaultWidgetSet. This is the module - you want to extend when creating an extended widget set, or when creating + <!-- This GWT module defines the Vaadin DefaultWidgetSet. This is the module + you want to extend when creating an extended widget set, or when creating a specialized widget set with a subset of the components. --> <!-- Hint for WidgetSetBuilder not to automatically update the file --> @@ -10,26 +10,34 @@ <inherits name="com.google.gwt.http.HTTP" /> + <inherits name="com.google.gwt.json.JSON" /> + + <inherits + name="com.vaadin.terminal.gwt.DefaultWidgetSetBrowserSpecificOverrides" /> + <source path="client" /> - <!-- Use own Scheduler implementation to be able to track if commands are + <!-- Use own Scheduler implementation to be able to track if commands are running --> <replace-with class="com.vaadin.terminal.gwt.client.VSchedulerImpl"> <when-type-is class="com.google.gwt.core.client.impl.SchedulerImpl" /> </replace-with> - + + + <!-- Generators for serializators for classes used in communication between + server and client --> + <generate-with + class="com.vaadin.terminal.gwt.widgetsetutils.SerializerMapGenerator"> + <when-type-is + class="com.vaadin.terminal.gwt.client.communication.SerializerMap" /> + </generate-with> + <replace-with class="com.vaadin.terminal.gwt.client.VDebugConsole"> <when-type-is class="com.vaadin.terminal.gwt.client.Console" /> </replace-with> - <!-- Use our own history impl for IE to workaround #2931. --> - <replace-with class="com.vaadin.terminal.gwt.client.HistoryImplIEVaadin"> - <when-type-is class="com.google.gwt.user.client.impl.HistoryImpl" /> - <when-property-is name="user.agent" value="ie6" /> - </replace-with> - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator"> + class="com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator"> <when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap" /> </generate-with> @@ -39,47 +47,31 @@ class="com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterionFactory" /> </generate-with> - <!-- Fall through to this rule for everything but IE --> - <replace-with - class="com.vaadin.terminal.gwt.client.ui.UploadIFrameOnloadStrategy"> - <when-type-is - class="com.vaadin.terminal.gwt.client.ui.UploadIFrameOnloadStrategy" /> - </replace-with> - - <replace-with - class="com.vaadin.terminal.gwt.client.ui.UploadIFrameOnloadStrategyIE"> - <when-type-is - class="com.vaadin.terminal.gwt.client.ui.UploadIFrameOnloadStrategy" /> - <any> - <when-property-is name="user.agent" value="ie6" /> - <when-property-is name="user.agent" value="ie8" /> - </any> - </replace-with> + <!-- Generate client side proxies for client to server RPC interfaces --> + <generate-with + class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyGenerator"> + <when-type-assignable + class="com.vaadin.terminal.gwt.client.communication.ServerRpc" /> + </generate-with> - <!-- Fall through to this rule for everything but IE --> - <replace-with - class="com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper"> - <when-type-is - class="com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper" /> - </replace-with> + <!-- Generate client side proxies for client to server RPC interfaces --> + <generate-with + class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyCreatorGenerator"> + <when-type-assignable + class="com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator" /> + </generate-with> - <replace-with - class="com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapperIE"> - <when-type-is - class="com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper" /> - <any> - <when-property-is name="user.agent" value="ie6" /> - <when-property-is name="user.agent" value="ie8" /> - </any> - </replace-with> - - <!-- Workaround for #6682. Remove when fixed in GWT. --> - <replace-with class="com.google.gwt.dom.client.VaadinDOMImplSafari"> - <when-type-is class="com.google.gwt.dom.client.DOMImpl" /> - <when-property-is name="user.agent" value="safari" /> - </replace-with> + <!-- Generate client side RPC manager for server to client RPC --> + <generate-with + class="com.vaadin.terminal.gwt.widgetsetutils.RpcManagerGenerator"> + <when-type-assignable + class="com.vaadin.terminal.gwt.client.communication.RpcManager" /> + </generate-with> <entry-point class="com.vaadin.terminal.gwt.client.ApplicationConfiguration" /> + <!-- Use the new cross site linker to get a nocache.js without document.write --> + <add-linker name="xsiframe" /> + </module> diff --git a/src/com/vaadin/terminal/gwt/DefaultWidgetSetBrowserSpecificOverrides.gwt.xml b/src/com/vaadin/terminal/gwt/DefaultWidgetSetBrowserSpecificOverrides.gwt.xml new file mode 100644 index 0000000000..b5ab61df64 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/DefaultWidgetSetBrowserSpecificOverrides.gwt.xml @@ -0,0 +1,53 @@ +<module> + <!-- This GWT module defines the browser specific overrides used by Vaadin --> + + <!-- Hint for WidgetSetBuilder not to automatically update the file --> + <!-- WS Compiler: manually edited --> + + <!-- Fall through to this rule for everything but IE --> + <replace-with + class="com.vaadin.terminal.gwt.client.ui.upload.UploadIFrameOnloadStrategy"> + <when-type-is + class="com.vaadin.terminal.gwt.client.ui.upload.UploadIFrameOnloadStrategy" /> + </replace-with> + + <replace-with + class="com.vaadin.terminal.gwt.client.ui.upload.UploadIFrameOnloadStrategyIE"> + <when-type-is + class="com.vaadin.terminal.gwt.client.ui.upload.UploadIFrameOnloadStrategy" /> + <any> + <when-property-is name="user.agent" value="ie8" /> + </any> + </replace-with> + + <!-- Fall through to this rule for everything but IE --> + <replace-with class="com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper"> + <when-type-is class="com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper" /> + </replace-with> + + <replace-with class="com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapperIE"> + <when-type-is class="com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper" /> + <any> + <when-property-is name="user.agent" value="ie8" /> + </any> + </replace-with> + + <!-- Fall through to this rule for everything but IE --> + <replace-with class="com.vaadin.terminal.gwt.client.LayoutManager"> + <when-type-is class="com.vaadin.terminal.gwt.client.LayoutManager" /> + </replace-with> + + <replace-with class="com.vaadin.terminal.gwt.client.LayoutManagerIE8"> + <when-type-is class="com.vaadin.terminal.gwt.client.LayoutManager" /> + <any> + <when-property-is name="user.agent" value="ie8" /> + </any> + </replace-with> + + <!-- Workaround for #6682. Remove when fixed in GWT. --> + <replace-with class="com.google.gwt.dom.client.VaadinDOMImplSafari"> + <when-type-is class="com.google.gwt.dom.client.DOMImpl" /> + <when-property-is name="user.agent" value="safari" /> + </replace-with> + +</module> diff --git a/src/com/vaadin/terminal/gwt/client/AbstractFieldState.java b/src/com/vaadin/terminal/gwt/client/AbstractFieldState.java new file mode 100644 index 0000000000..3a66a01f23 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/AbstractFieldState.java @@ -0,0 +1,137 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.vaadin.terminal.gwt.client.ui.TabIndexState; +import com.vaadin.ui.AbstractField; + +/** + * Shared state for {@link AbstractField}. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public class AbstractFieldState extends ComponentState implements TabIndexState { + private boolean propertyReadOnly = false; + private boolean hideErrors = false; + private boolean required = false; + private boolean modified = false; + + /** + * The tab order number of this field. + */ + private int tabIndex = 0; + + /** + * Checks if the property data source for the Field is in read only mode. + * This affects the read only state of the field itself. + * + * @return true if there is a property data source and it is set to read + * only, false otherwise + */ + public boolean isPropertyReadOnly() { + return propertyReadOnly; + } + + /** + * Sets the read only state of the property data source. + * + * @param propertyReadOnly + * true if the property data source if read only, false otherwise + */ + public void setPropertyReadOnly(boolean propertyReadOnly) { + this.propertyReadOnly = propertyReadOnly; + } + + /** + * Returns true if the component will hide any errors even if the error + * message is set. + * + * @return true if error messages are disabled + */ + public boolean isHideErrors() { + return hideErrors; + } + + /** + * Sets whether the component should hide any errors even if the error + * message is set. + * + * This is used e.g. on forms to hide error messages for invalid fields + * before the first user actions. + * + * @param hideErrors + * true if error messages should be hidden + */ + public void setHideErrors(boolean hideErrors) { + this.hideErrors = hideErrors; + } + + /** + * Is the field required. Required fields must filled by the user. + * + * See AbstractField#isRequired() for more information. + * + * @return <code>true</code> if the field is required, otherwise + * <code>false</code>. + */ + public boolean isRequired() { + return required; + } + + /** + * Sets the field required. Required fields must filled by the user. + * + * See AbstractField#setRequired(boolean) for more information. + * + * @param required + * Is the field required. + */ + public void setRequired(boolean required) { + this.required = required; + } + + /** + * Has the contents of the field been modified, i.e. has the value been + * updated after it was read from the data source. + * + * @return true if the field has been modified, false otherwise + */ + public boolean isModified() { + return modified; + } + + /** + * Setter for the modified flag, toggled when the contents of the field is + * modified by the user. + * + * @param modified + * the new modified state + * + */ + public void setModified(boolean modified) { + this.modified = modified; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ComponentState#getTabIndex() + */ + public int getTabIndex() { + return tabIndex; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ui.TabIndexState#setTabIndex(int) + */ + public void setTabIndex(int tabIndex) { + this.tabIndex = tabIndex; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java index a60fb808a1..170e949116 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java @@ -5,22 +5,180 @@ package com.vaadin.terminal.gwt.client; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.GWT.UncaughtExceptionHandler; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; -import com.vaadin.terminal.gwt.client.ui.VUnknownComponent; +import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector; public class ApplicationConfiguration implements EntryPoint { /** + * Helper class for reading configuration options from the bootstap + * javascript + * + * @since 7.0 + */ + private static class JsoConfiguration extends JavaScriptObject { + protected JsoConfiguration() { + // JSO Constructor + } + + /** + * Reads a configuration parameter as a string. Please note that the + * javascript value of the parameter should also be a string, or else an + * undefined exception may be thrown. + * + * @param name + * name of the configuration parameter + * @return value of the configuration parameter, or <code>null</code> if + * not defined + */ + private native String getConfigString(String name) + /*-{ + var value = this.getConfig(name); + if (value === null || value === undefined) { + return null; + } else { + return value +""; + } + }-*/; + + /** + * Reads a configuration parameter as a boolean object. Please note that + * the javascript value of the parameter should also be a boolean, or + * else an undefined exception may be thrown. + * + * @param name + * name of the configuration parameter + * @return boolean value of the configuration paramter, or + * <code>null</code> if no value is defined + */ + private native Boolean getConfigBoolean(String name) + /*-{ + var value = this.getConfig(name); + if (value === null || value === undefined) { + return null; + } else { + return @java.lang.Boolean::valueOf(Z)(value); + } + }-*/; + + /** + * Reads a configuration parameter as an integer object. Please note + * that the javascript value of the parameter should also be an integer, + * or else an undefined exception may be thrown. + * + * @param name + * name of the configuration parameter + * @return integer value of the configuration paramter, or + * <code>null</code> if no value is defined + */ + private native Integer getConfigInteger(String name) + /*-{ + var value = this.getConfig(name); + if (value === null || value === undefined) { + return null; + } else { + return @java.lang.Integer::valueOf(I)(value); + } + }-*/; + + /** + * Reads a configuration parameter as an {@link ErrorMessage} object. + * Please note that the javascript value of the parameter should also be + * an object with appropriate fields, or else an undefined exception may + * be thrown when calling this method or when calling methods on the + * returned object. + * + * @param name + * name of the configuration parameter + * @return error message with the given name, or <code>null</code> if no + * value is defined + */ + private native ErrorMessage getConfigError(String name) + /*-{ + return this.getConfig(name); + }-*/; + + /** + * Returns a native javascript object containing version information + * from the server. + * + * @return a javascript object with the version information + */ + private native JavaScriptObject getVersionInfoJSObject() + /*-{ + return this.getConfig("versionInfo"); + }-*/; + + /** + * Gets the version of the Vaadin framework used on the server. + * + * @return a string with the version + * + * @see com.vaadin.terminal.gwt.server.AbstractApplicationServlet#VERSION + */ + private native String getVaadinVersion() + /*-{ + return this.getConfig("versionInfo").vaadinVersion; + }-*/; + + /** + * Gets the version of the application running on the server. + * + * @return a string with the application version + * + * @see com.vaadin.Application#getVersion() + */ + private native String getApplicationVersion() + /*-{ + return this.getConfig("versionInfo").applicationVersion; + }-*/; + + private native String getUIDL() + /*-{ + return this.getConfig("uidl"); + }-*/; + } + + /** + * Wraps a native javascript object containing fields for an error message + * + * @since 7.0 + */ + public static final class ErrorMessage extends JavaScriptObject { + + protected ErrorMessage() { + // JSO constructor + } + + public final native String getCaption() + /*-{ + return this.caption; + }-*/; + + public final native String getMessage() + /*-{ + return this.message; + }-*/; + + public final native String getUrl() + /*-{ + return this.url; + }-*/; + } + + /** * Builds number. For example 0-custom_tag in 5.0.0-custom_tag. */ public static final String VERSION; @@ -39,34 +197,30 @@ public class ApplicationConfiguration implements EntryPoint { private String id; private String themeUri; private String appUri; - private JavaScriptObject versionInfo; - private String windowName; + private int rootId; private boolean standalone; - private String communicationErrorCaption; - private String communicationErrorMessage; - private String communicationErrorUrl; - private String authorizationErrorCaption; - private String authorizationErrorMessage; - private String authorizationErrorUrl; - private String requiredWidgetset; + private ErrorMessage communicationError; + private ErrorMessage authorizationError; private boolean useDebugIdInDom = true; private boolean usePortletURLs = false; private String portletUidlURLBase; - private HashMap<String, String> unknownComponents; + private HashMap<Integer, String> unknownComponents; - private Class<? extends Paintable>[] classes = new Class[1024]; + private Class<? extends ComponentConnector>[] classes = new Class[1024]; - private String windowId; + private boolean browserDetailsSent = false; static// TODO consider to make this hashmap per application LinkedList<Command> callbacks = new LinkedList<Command>(); private static int widgetsLoading; - private static ArrayList<ApplicationConnection> unstartedApplications = new ArrayList<ApplicationConnection>(); private static ArrayList<ApplicationConnection> runningApplications = new ArrayList<ApplicationConnection>(); + private Map<Integer, Integer> componentInheritanceMap = new HashMap<Integer, Integer>(); + private Map<Integer, String> tagToServerSideClassName = new HashMap<Integer, String>(); + public boolean usePortletURLs() { return usePortletURLs; } @@ -89,6 +243,13 @@ public class ApplicationConfiguration implements EntryPoint { return appUri; } + public String getThemeName() { + String uri = getThemeUri(); + String themeName = uri.substring(uri.lastIndexOf('/')); + themeName = themeName.replaceAll("[^a-zA-Z0-9]", ""); + return themeName; + } + public String getThemeUri() { return themeUri; } @@ -98,6 +259,16 @@ public class ApplicationConfiguration implements EntryPoint { } /** + * Gets the initial UIDL from the DOM, if it was provided during the init + * process. + * + * @return + */ + public String getUIDL() { + return getJsoConfiguration(id).getUIDL(); + } + + /** * @return true if the application is served by std. Vaadin servlet and is * considered to be the only or main content of the host page. */ @@ -105,174 +276,99 @@ public class ApplicationConfiguration implements EntryPoint { return standalone; } - public void setInitialWindowName(String name) { - windowName = name; - } - - public String getInitialWindowName() { - return windowName; + /** + * Gets the root if of this application instance. The root id should be + * included in every request originating from this instance in order to + * associate it with the right Root instance on the server. + * + * @return the root id + */ + public int getRootId() { + return rootId; } public JavaScriptObject getVersionInfoJSObject() { - return versionInfo; + return getJsoConfiguration(id).getVersionInfoJSObject(); } - public String getCommunicationErrorCaption() { - return communicationErrorCaption; + public ErrorMessage getCommunicationError() { + return communicationError; } - public String getCommunicationErrorMessage() { - return communicationErrorMessage; + public ErrorMessage getAuthorizationError() { + return authorizationError; } - public String getCommunicationErrorUrl() { - return communicationErrorUrl; - } + /** + * Reads the configuration values defined by the bootstrap javascript. + */ + private void loadFromDOM() { + JsoConfiguration jsoConfiguration = getJsoConfiguration(id); + appUri = jsoConfiguration.getConfigString("appUri"); + if (appUri != null && !appUri.endsWith("/")) { + appUri += '/'; + } + themeUri = jsoConfiguration.getConfigString("themeUri"); + rootId = jsoConfiguration.getConfigInteger("rootId").intValue(); - public String getAuthorizationErrorCaption() { - return authorizationErrorCaption; - } + // null -> true + useDebugIdInDom = jsoConfiguration.getConfigBoolean("useDebugIdInDom") != Boolean.FALSE; - public String getAuthorizationErrorMessage() { - return authorizationErrorMessage; - } + // null -> false + usePortletURLs = jsoConfiguration.getConfigBoolean("usePortletURLs") == Boolean.TRUE; - public String getAuthorizationErrorUrl() { - return authorizationErrorUrl; - } + portletUidlURLBase = jsoConfiguration + .getConfigString("portletUidlURLBase"); - public String getRequiredWidgetset() { - return requiredWidgetset; - } + // null -> false + standalone = jsoConfiguration.getConfigBoolean("standalone") == Boolean.TRUE; - private native void loadFromDOM() - /*-{ + communicationError = jsoConfiguration.getConfigError("comErrMsg"); + authorizationError = jsoConfiguration.getConfigError("authErrMsg"); - var id = this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::id; - if($wnd.vaadin.vaadinConfigurations && $wnd.vaadin.vaadinConfigurations[id]) { - var jsobj = $wnd.vaadin.vaadinConfigurations[id]; - var uri = jsobj.appUri; - if(uri != null && uri[uri.length -1] != "/") { - uri = uri + "/"; - } - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::appUri = uri; - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::themeUri = jsobj.themeUri; - if(jsobj.windowName) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::windowName = jsobj.windowName; - } - if('useDebugIdInDom' in jsobj && typeof(jsobj.useDebugIdInDom) == "boolean") { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::useDebugIdInDom = jsobj.useDebugIdInDom; - } - if(jsobj.versionInfo) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::versionInfo = jsobj.versionInfo; - } - if(jsobj.comErrMsg) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::communicationErrorCaption = jsobj.comErrMsg.caption; - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::communicationErrorMessage = jsobj.comErrMsg.message; - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::communicationErrorUrl = jsobj.comErrMsg.url; - } - if(jsobj.authErrMsg) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::authorizationErrorCaption = jsobj.authErrMsg.caption; - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::authorizationErrorMessage = jsobj.authErrMsg.message; - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::authorizationErrorUrl = jsobj.authErrMsg.url; - } - if (jsobj.usePortletURLs) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::usePortletURLs = jsobj.usePortletURLs; - } - if (jsobj.portletUidlURLBase) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::portletUidlURLBase = jsobj.portletUidlURLBase; - } - if (jsobj.standalone) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::standalone = true; - } - if (jsobj.widgetset) { - this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::requiredWidgetset = jsobj.widgetset; - } - } else { - $wnd.alert("Vaadin app failed to initialize: " + this.id); + // boostrap sets initPending to false if it has sent the browser details + if (jsoConfiguration.getConfigBoolean("initPending") == Boolean.FALSE) { + setBrowserDetailsSent(); } - }-*/; + } /** - * Inits the ApplicationConfiguration by reading the DOM and instantiating - * ApplicationConnections accordingly. Call {@link #startNextApplication()} - * to actually start the applications. + * Starts the application with a given id by reading the configuration + * options stored by the bootstrap javascript. * - * @param widgetset - * the widgetset that is running the apps + * @param applicationId + * id of the application to load, this is also the id of the html + * element into which the application should be rendered. */ - public static void initConfigurations() { - - ArrayList<String> appIds = new ArrayList<String>(); - loadAppIdListFromDOM(appIds); - - for (Iterator<String> it = appIds.iterator(); it.hasNext();) { - String appId = it.next(); - ApplicationConfiguration appConf = getConfigFromDOM(appId); - if (canStartApplication(appConf)) { + public static void startApplication(final String applicationId) { + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + public void execute() { + ApplicationConfiguration appConf = getConfigFromDOM(applicationId); ApplicationConnection a = GWT .create(ApplicationConnection.class); a.init(widgetSet, appConf); - unstartedApplications.add(a); - consumeApplication(appId); - } else { - VConsole.log("Application " - + appId - + " was not started. Provided widgetset did not match with this module."); + a.start(); + runningApplications.add(a); } - } - + }); } - /** - * Marks an applicatin with given id to be initialized. Suggesting other - * modules should not try to start this application anymore. - * - * @param appId - */ - private native static void consumeApplication(String appId) - /*-{ - $wnd.vaadin.vaadinConfigurations[appId].initialized = true; - }-*/; - - private static boolean canStartApplication(ApplicationConfiguration appConf) { - return appConf.getRequiredWidgetset() == null - || appConf.getRequiredWidgetset().equals(GWT.getModuleName()); + public static List<ApplicationConnection> getRunningApplications() { + return runningApplications; } /** - * Starts the next unstarted application. The WidgetSet should call this - * once to start the first application; after that, each application should - * call this once it has started. This ensures that the applications are - * started synchronously, which is neccessary to avoid session-id problems. + * Gets the configuration object for a specific application from the + * bootstrap javascript. * - * @return true if an unstarted application was found + * @param appId + * the id of the application to get configuration data for + * @return a native javascript object containing the configuration data */ - public static boolean startNextApplication() { - if (unstartedApplications.size() > 0) { - ApplicationConnection a = unstartedApplications.remove(0); - a.start(); - runningApplications.add(a); - return true; - } else { - deferredWidgetLoader = new DeferredWidgetLoader(); - return false; - } - } - - public static List<ApplicationConnection> getRunningApplications() { - return runningApplications; - } - - private native static void loadAppIdListFromDOM(ArrayList<String> list) + private native static JsoConfiguration getJsoConfiguration(String appId) /*-{ - var j; - for(j in $wnd.vaadin.vaadinConfigurations) { - if(!$wnd.vaadin.vaadinConfigurations[j].initialized) { - list.@java.util.Collection::add(Ljava/lang/Object;)(j); - } - } + return $wnd.vaadin.getApp(appId); }-*/; public static ApplicationConfiguration getConfigFromDOM(String appId) { @@ -282,27 +378,34 @@ public class ApplicationConfiguration implements EntryPoint { return conf; } - public native String getServletVersion() - /*-{ - return this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::versionInfo.vaadinVersion; - }-*/; + public String getServletVersion() { + return getJsoConfiguration(id).getVaadinVersion(); + } - public native String getApplicationVersion() - /*-{ - return this.@com.vaadin.terminal.gwt.client.ApplicationConfiguration::versionInfo.applicationVersion; - }-*/; + public String getApplicationVersion() { + return getJsoConfiguration(id).getApplicationVersion(); + } public boolean useDebugIdInDOM() { return useDebugIdInDom; } - public Class<? extends Paintable> getWidgetClassByEncodedTag(String tag) { + public Class<? extends ComponentConnector> getWidgetClassByEncodedTag( + int tag) { try { - int parseInt = Integer.parseInt(tag); - return classes[parseInt]; + return classes[tag]; } catch (Exception e) { // component was not present in mappings - return VUnknownComponent.class; + return UnknownComponentConnector.class; + } + } + + public void addComponentInheritanceInfo(ValueMap valueMap) { + JsArrayString keyArray = valueMap.getKeyArray(); + for (int i = 0; i < keyArray.length(); i++) { + String key = keyArray.get(i); + int value = valueMap.getInt(key); + componentInheritanceMap.put(Integer.parseInt(key), value); } } @@ -311,27 +414,31 @@ public class ApplicationConfiguration implements EntryPoint { for (int i = 0; i < keyArray.length(); i++) { String key = keyArray.get(i).intern(); int value = valueMap.getInt(key); - classes[value] = widgetSet.getImplementationByClassName(key); - if (classes[value] == VUnknownComponent.class) { + tagToServerSideClassName.put(value, key); + } + + for (int i = 0; i < keyArray.length(); i++) { + String key = keyArray.get(i).intern(); + int value = valueMap.getInt(key); + classes[value] = widgetSet.getConnectorClassByTag(value, this); + if (classes[value] == UnknownComponentConnector.class) { if (unknownComponents == null) { - unknownComponents = new HashMap<String, String>(); + unknownComponents = new HashMap<Integer, String>(); } - unknownComponents.put("" + value, key); - } else if (key == "com.vaadin.ui.Window") { - windowId = "" + value; + unknownComponents.put(value, key); } } } - /** - * @return the integer value that is used to code top level windows - * "com.vaadin.ui.Window" - */ - String getEncodedWindowTag() { - return windowId; + public Integer getParentTag(int tag) { + return componentInheritanceMap.get(tag); } - String getUnknownServerClassNameByEncodedTagName(String tag) { + public String getServerSideClassNameForTag(Integer tag) { + return tagToServerSideClassName.get(tag); + } + + String getUnknownServerClassNameByTag(int tag) { if (unknownComponents != null) { return unknownComponents.get(tag); } @@ -398,7 +505,7 @@ public class ApplicationConfiguration implements EntryPoint { public void run() { pending = false; if (!isBusy()) { - Class<? extends Paintable> nextType = getNextType(); + Class<? extends ComponentConnector> nextType = getNextType(); if (nextType == null) { // ensured that all widgets are loaded deferredWidgetLoader = null; @@ -411,8 +518,8 @@ public class ApplicationConfiguration implements EntryPoint { } } - private Class<? extends Paintable> getNextType() { - Class<? extends Paintable>[] deferredLoadedWidgets = widgetSet + private Class<? extends ComponentConnector> getNextType() { + Class<? extends ComponentConnector>[] deferredLoadedWidgets = widgetSet .getDeferredLoadedWidgets(); if (deferredLoadedWidgets.length <= nextWidgetIndex) { return null; @@ -443,10 +550,6 @@ public class ApplicationConfiguration implements EntryPoint { public void onModuleLoad() { - // Enable IE6 Background image caching - if (BrowserInfo.get().isIE6()) { - enableIE6BackgroundImageCache(); - } // Prepare VConsole for debugging if (isDebugMode()) { Console console = GWT.create(Console.class); @@ -472,21 +575,22 @@ public class ApplicationConfiguration implements EntryPoint { } }); - initConfigurations(); - startNextApplication(); + registerCallback(GWT.getModuleName()); + deferredWidgetLoader = new DeferredWidgetLoader(); } - // From ImageSrcIE6 - private static native void enableIE6BackgroundImageCache() + /** + * Registers that callback that the bootstrap javascript uses to start + * applications once the widgetset is loaded and all required information is + * available + * + * @param widgetsetName + * the name of this widgetset + */ + public native static void registerCallback(String widgetsetName) /*-{ - // Fix IE background image refresh bug, present through IE6 - // see http://www.mister-pixel.com/#Content__state=is_that_simple - // this only works with IE6 SP1+ - try { - $doc.execCommand("BackgroundImageCache", false, true); - } catch (e) { - // ignore error on other browsers - } + var callbackHandler = @com.vaadin.terminal.gwt.client.ApplicationConfiguration::startApplication(Ljava/lang/String;); + $wnd.vaadin.registerWidgetset(widgetsetName, callbackHandler); }-*/; /** @@ -518,4 +622,25 @@ public class ApplicationConfiguration implements EntryPoint { return re.test(uri); }-*/; + /** + * Checks whether information from the web browser (e.g. uri fragment and + * screen size) has been sent to the server. + * + * @return <code>true</code> if browser information has already been sent + * + * @see ApplicationConnection#getNativeBrowserDetailsParameters(String) + */ + public boolean isBrowserDetailsSent() { + return browserDetailsSent; + } + + /** + * Registers that the browser details have been sent. + * {@link #isBrowserDetailsSent()} will return + * <code> after this method has been invoked. + */ + public void setBrowserDetailsSent() { + browserDetailsSent = true; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index de7ad83b54..be6d578112 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -5,44 +5,53 @@ package com.vaadin.terminal.gwt.client; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; +import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONString; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; 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.History; import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.FocusWidget; -import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize; -import com.vaadin.terminal.gwt.client.RenderInformation.Size; -import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage; +import com.vaadin.terminal.gwt.client.communication.JsonDecoder; +import com.vaadin.terminal.gwt.client.communication.JsonEncoder; +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; +import com.vaadin.terminal.gwt.client.communication.RpcManager; +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; import com.vaadin.terminal.gwt.client.ui.VContextMenu; -import com.vaadin.terminal.gwt.client.ui.VNotification; -import com.vaadin.terminal.gwt.client.ui.VNotification.HideEvent; -import com.vaadin.terminal.gwt.client.ui.VView; import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; +import com.vaadin.terminal.gwt.client.ui.notification.VNotification; +import com.vaadin.terminal.gwt.client.ui.notification.VNotification.HideEvent; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; +import com.vaadin.terminal.gwt.client.ui.window.WindowConnector; import com.vaadin.terminal.gwt.server.AbstractCommunicationManager; /** @@ -50,12 +59,10 @@ import com.vaadin.terminal.gwt.server.AbstractCommunicationManager; * communication with its server side counterpart * {@link AbstractCommunicationManager}. * - * Client-side widgets receive updates from the corresponding server-side - * components as calls to - * {@link Paintable#updateFromUIDL(UIDL, ApplicationConnection)} (not to be - * confused with the server side interface {@link com.vaadin.terminal.Paintable} - * ). Any client-side changes (typically resulting from user actions) are sent - * back to the server as variable changes (see {@link #updateVariable()}). + * Client-side connectors receive updates from the corresponding server-side + * connector (typically component) as state updates or RPC calls. The connector + * has the possibility to communicate back with its server side counter part + * through RPC calls. * * TODO document better * @@ -65,27 +72,29 @@ public class ApplicationConnection { // This indicates the whole page is generated by us (not embedded) public static final String GENERATED_BODY_CLASSNAME = "v-generated-body"; - private static final String MODIFIED_CLASSNAME = "v-modified"; + public static final String MODIFIED_CLASSNAME = "v-modified"; public static final String DISABLED_CLASSNAME = "v-disabled"; - private static final String REQUIRED_CLASSNAME_EXT = "-required"; + public static final String REQUIRED_CLASSNAME_EXT = "-required"; - private static final String ERROR_CLASSNAME_EXT = "-error"; + public static final String ERROR_CLASSNAME_EXT = "-error"; - public static final char VAR_RECORD_SEPARATOR = '\u001e'; - - public static final char VAR_FIELD_SEPARATOR = '\u001f'; + public static final String UPDATE_VARIABLE_INTERFACE = "v"; + public static final String UPDATE_VARIABLE_METHOD = "v"; public static final char VAR_BURST_SEPARATOR = '\u001d'; - public static final char VAR_ARRAYITEM_SEPARATOR = '\u001c'; - public static final char VAR_ESCAPE_CHARACTER = '\u001b'; public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key"; /** + * Name of the parameter used to transmit root ids back and forth + */ + public static final String ROOT_ID_PARAMETER = "rootId"; + + /** * @deprecated use UIDL_SECURITY_TOKEN_ID instead */ @Deprecated @@ -93,9 +102,6 @@ public class ApplicationConnection { public static final String PARAM_UNLOADBURST = "onunloadburst"; - public static final String ATTRIBUTE_DESCRIPTION = "description"; - public static final String ATTRIBUTE_ERROR = "error"; - /** * A string that, if found in a non-JSON response to a UIDL request, will * cause the browser to refresh the page. If followed by a colon, optional @@ -117,15 +123,14 @@ public class ApplicationConnection { */ public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh"; + private final boolean debugLogging = false; + // will hold the UIDL security key (for XSS protection) once received private String uidlSecurityKey = "init"; private final HashMap<String, String> resourcesMap = new HashMap<String, String>(); - private final ArrayList<String> pendingVariables = new ArrayList<String>(); - - private final ComponentDetailMap idToPaintableDetail = ComponentDetailMap - .create(); + private ArrayList<MethodInvocation> pendingInvocations = new ArrayList<MethodInvocation>(); private WidgetSet widgetSet; @@ -136,17 +141,19 @@ public class ApplicationConnection { private Timer loadTimer3; private Element loadElement; - private final VView view; + private final RootConnector rootConnector; protected boolean applicationRunning = false; private boolean hasActiveRequest = false; + protected boolean cssLoaded = false; + /** Parameters for this application connection loaded from the web-page */ private ApplicationConfiguration configuration; /** List of pending variable change bursts that must be submitted in order */ - private final ArrayList<ArrayList<String>> pendingVariableBursts = new ArrayList<ArrayList<String>>(); + private final ArrayList<ArrayList<MethodInvocation>> pendingBursts = new ArrayList<ArrayList<MethodInvocation>>(); /** Timer for automatic refirect to SessionExpiredURL */ private Timer redirectTimer; @@ -154,21 +161,42 @@ public class ApplicationConnection { /** redirectTimer scheduling interval in seconds */ private int sessionExpirationInterval; - private ArrayList<Paintable> relativeSizeChanges = new ArrayList<Paintable>();; - private ArrayList<Paintable> componentCaptionSizeChanges = new ArrayList<Paintable>();; + private ArrayList<Widget> componentCaptionSizeChanges = new ArrayList<Widget>(); private Date requestStartTime; private boolean validatingLayouts = false; - private Set<Paintable> zeroWidthComponents = null; + private Set<ComponentConnector> zeroWidthComponents = null; - private Set<Paintable> zeroHeightComponents = null; + private Set<ComponentConnector> zeroHeightComponents = null; - private Set<String> unregistryBag = new HashSet<String>(); + private final LayoutManager layoutManager; + + private final RpcManager rpcManager; + + public static class MultiStepDuration extends Duration { + private int previousStep = elapsedMillis(); + + public void logDuration(String message) { + logDuration(message, 0); + } + + public void logDuration(String message, int minDuration) { + int currentTime = elapsedMillis(); + int stepDuration = currentTime - previousStep; + if (stepDuration >= minDuration) { + VConsole.log(message + ": " + stepDuration + " ms"); + } + previousStep = currentTime; + } + } public ApplicationConnection() { - view = GWT.create(VView.class); + rootConnector = GWT.create(RootConnector.class); + rpcManager = GWT.create(RpcManager.class); + layoutManager = GWT.create(LayoutManager.class); + layoutManager.setConnection(this); } public void init(WidgetSet widgetSet, ApplicationConfiguration cnf) { @@ -186,7 +214,6 @@ public class ApplicationConnection { this.widgetSet = widgetSet; configuration = cnf; - windowName = configuration.getInitialWindowName(); ComponentLocator componentLocator = new ComponentLocator(this); @@ -198,7 +225,7 @@ public class ApplicationConnection { initializeClientHooks(); - view.init(cnf.getRootPanelId(), this); + rootConnector.init(cnf.getRootPanelId(), this); showLoadingIndicator(); } @@ -209,10 +236,19 @@ public class ApplicationConnection { * failed to start. This ensures that the applications are started in order, * to avoid session-id problems. * - * @return */ public void start() { - repaintAll(); + String jsonText = configuration.getUIDL(); + if (jsonText == null) { + // inital UIDL not in DOM, request later + repaintAll(); + } else { + // Update counter so TestBench knows something is still going on + hasActiveRequest = true; + + // initial UIDL provided in DOM, continue as if returned by request + handleJSONText(jsonText, -1); + } } private native void initializeTestbenchHooks( @@ -224,14 +260,13 @@ public class ApplicationConnection { return ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::hasActiveRequest()() || ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::isExecutingDeferredCommands()(); }); - var vi = ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::getVersionInfo()(); if (vi) { client.getVersionInfo = function() { return vi; } } - + client.getProfilingData = $entry(function() { var pd = [ ap.@com.vaadin.terminal.gwt.client.ApplicationConnection::lastProcessingTime, @@ -248,10 +283,6 @@ public class ApplicationConnection { return componentLocator.@com.vaadin.terminal.gwt.client.ComponentLocator::getPathForElement(Lcom/google/gwt/user/client/Element;)(element); }); - if (!$wnd.vaadin.clients) { - $wnd.vaadin.clients = {}; - } - $wnd.vaadin.clients[TTAppId] = client; }-*/; @@ -379,36 +410,31 @@ public class ApplicationConnection { private String getRepaintAllParameters() { // collect some client side data that will be sent to server on // initial uidl request - int clientHeight = Window.getClientHeight(); - int clientWidth = Window.getClientWidth(); - com.google.gwt.dom.client.Element pe = view.getElement() - .getParentElement(); - int offsetHeight = pe.getOffsetHeight(); - int offsetWidth = pe.getOffsetWidth(); - int screenWidth = BrowserInfo.get().getScreenWidth(); - int screenHeight = BrowserInfo.get().getScreenHeight(); - int tzOffset = BrowserInfo.get().getTimezoneOffset(); - int rtzOffset = BrowserInfo.get().getRawTimezoneOffset(); - int dstDiff = BrowserInfo.get().getDSTSavings(); - boolean dstInEffect = BrowserInfo.get().isDSTInEffect(); - long curDate = BrowserInfo.get().getCurrentDate().getTime(); + String nativeBootstrapParameters = getNativeBrowserDetailsParameters(getConfiguration() + .getRootPanelId()); String widgetsetVersion = ApplicationConfiguration.VERSION; - String token = History.getToken(); - // TODO figure out how client and view size could be used better on // server. screen size can be accessed via Browser object, but other // values currently only via transaction listener. - String parameters = "repaintAll=1&" + "sh=" + screenHeight + "&sw=" - + screenWidth + "&cw=" + clientWidth + "&ch=" + clientHeight - + "&vw=" + offsetWidth + "&vh=" + offsetHeight + "&fr=" + token - + "&tzo=" + tzOffset + "&rtzo=" + rtzOffset + "&dstd=" - + dstDiff + "&dston=" + dstInEffect + "&curdate=" + curDate - + "&wsver=" + widgetsetVersion - + (BrowserInfo.get().isTouchDevice() ? "&td=1" : ""); + String parameters = "repaintAll=1&" + nativeBootstrapParameters + + "&wsver=" + widgetsetVersion; return parameters; } + /** + * Gets the browser detail parameters that are sent by the bootstrap + * javascript for two-request initialization. + * + * @param parentElementId + * @return + */ + private static native String getNativeBrowserDetailsParameters( + String parentElementId) + /*-{ + return $wnd.vaadin.getBrowserDetailsParameters(parentElementId); + }-*/; + protected void repaintAll() { String repainAllParameters = getRepaintAllParameters(); makeUidlRequest("", repainAllParameters, false); @@ -427,11 +453,11 @@ public class ApplicationConnection { * Sends a request to the server to print details to console that will help * developer to locate component in the source code. * - * @param paintable + * @param componentConnector */ - void highlightComponent(Paintable paintable) { + void highlightComponent(ComponentConnector componentConnector) { String params = getRepaintAllParameters() + "&highlightComponent=" - + getPid(paintable); + + componentConnector.getConnectorId(); makeUidlRequest("", params, false); } @@ -465,9 +491,8 @@ public class ApplicationConnection { if (extraParams != null && extraParams.length() > 0) { uri = addGetParameters(uri, extraParams); } - if (windowName != null && windowName.length() > 0) { - uri = addGetParameters(uri, "windowName=" + windowName); - } + uri = addGetParameters(uri, + ROOT_ID_PARAMETER + "=" + configuration.getRootId()); doUidlRequest(uri, payload, forceSync); @@ -491,10 +516,6 @@ public class ApplicationConnection { public void onError(Request request, Throwable exception) { showCommunicationError(exception.getMessage(), -1); endRequest(); - if (!applicationRunning) { - // start failed, let's try to start the next app - ApplicationConfiguration.startNextApplication(); - } } public void onResponseReceived(Request request, @@ -578,30 +599,10 @@ public class ApplicationConnection { } } - final Date start = new Date(); // for(;;);[realjson] final String jsonText = response.getText().substring(9, response.getText().length() - 1); - final ValueMap json; - try { - json = parseJSONResponse(jsonText); - } catch (final Exception e) { - endRequest(); - showCommunicationError(e.getMessage() - + " - Original JSON-text:" + jsonText, - statusCode); - return; - } - - VConsole.log("JSON parsing took " - + (new Date().getTime() - start.getTime()) + "ms"); - if (applicationRunning) { - handleReceivedJSONMessage(start, jsonText, json); - } else { - applicationRunning = true; - handleWhenCSSLoaded(jsonText, json); - ApplicationConfiguration.startNextApplication(); - } + handleJSONText(jsonText, statusCode); } }; @@ -626,6 +627,35 @@ public class ApplicationConnection { } /** + * Handles received UIDL JSON text, parsing it, and passing it on to the + * appropriate handlers, while logging timiing information. + * + * @param jsonText + * @param statusCode + */ + private void handleJSONText(String jsonText, int statusCode) { + final Date start = new Date(); + final ValueMap json; + try { + json = parseJSONResponse(jsonText); + } catch (final Exception e) { + endRequest(); + showCommunicationError(e.getMessage() + " - Original JSON-text:" + + jsonText, statusCode); + return; + } + + VConsole.log("JSON parsing took " + + (new Date().getTime() - start.getTime()) + "ms"); + if (applicationRunning) { + handleReceivedJSONMessage(start, jsonText, json); + } else { + applicationRunning = true; + handleWhenCSSLoaded(jsonText, json); + } + } + + /** * Sends an asynchronous UIDL request to the server using the given URI. * * @param uri @@ -674,9 +704,7 @@ public class ApplicationConnection { protected void handleWhenCSSLoaded(final String jsonText, final ValueMap json) { - int heightOfLoadElement = DOM.getElementPropertyInt(loadElement, - "offsetHeight"); - if (heightOfLoadElement == 0 && cssWaits < MAX_CSS_WAITS) { + if (!isCSSLoaded() && cssWaits < MAX_CSS_WAITS) { (new Timer() { @Override public void run() { @@ -688,6 +716,7 @@ public class ApplicationConnection { + "(.v-loading-indicator height == 0)"); cssWaits++; } else { + cssLoaded = true; handleReceivedJSONMessage(new Date(), jsonText, json); if (cssWaits >= MAX_CSS_WAITS) { VConsole.error("CSS files may have not loaded properly."); @@ -696,19 +725,14 @@ public class ApplicationConnection { } /** - * Shows the communication error notification. + * Checks whether or not the CSS is loaded. By default checks the size of + * the loading indicator element. * - * @param details - * Optional details for debugging. - * - * @deprecated Use the method with errorCode instead + * @return */ - @Deprecated - protected void showCommunicationError(String details) { - VConsole.error("Communication error: " + details); - showError(details, configuration.getCommunicationErrorCaption(), - configuration.getCommunicationErrorMessage(), - configuration.getCommunicationErrorUrl()); + protected boolean isCSSLoaded() { + return cssLoaded + || DOM.getElementPropertyInt(loadElement, "offsetHeight") != 0; } /** @@ -717,11 +741,14 @@ public class ApplicationConnection { * @param details * Optional details for debugging. * @param statusCode - * The http error code during the problematic request or -1 if - * error happened before response was received. + * The status code returned for the request + * */ protected void showCommunicationError(String details, int statusCode) { - showCommunicationError(details); + VConsole.error("Communication error: " + details); + ErrorMessage communicationError = configuration.getCommunicationError(); + showError(details, communicationError.getCaption(), + communicationError.getMessage(), communicationError.getUrl()); } /** @@ -732,9 +759,9 @@ public class ApplicationConnection { */ protected void showAuthenticationError(String details) { VConsole.error("Authentication error: " + details); - showError(details, configuration.getAuthorizationErrorCaption(), - configuration.getAuthorizationErrorMessage(), - configuration.getAuthorizationErrorUrl()); + ErrorMessage authorizationError = configuration.getAuthorizationError(); + showError(details, authorizationError.getCaption(), + authorizationError.getMessage(), authorizationError.getUrl()); } /** @@ -831,14 +858,14 @@ public class ApplicationConnection { * change set if it exists. */ private void checkForPendingVariableBursts() { - cleanVariableBurst(pendingVariables); - if (pendingVariableBursts.size() > 0) { - for (Iterator<ArrayList<String>> iterator = pendingVariableBursts + cleanVariableBurst(pendingInvocations); + if (pendingBursts.size() > 0) { + for (Iterator<ArrayList<MethodInvocation>> iterator = pendingBursts .iterator(); iterator.hasNext();) { cleanVariableBurst(iterator.next()); } - ArrayList<String> nextBurst = pendingVariableBursts.get(0); - pendingVariableBursts.remove(0); + ArrayList<MethodInvocation> nextBurst = pendingBursts.get(0); + pendingBursts.remove(0); buildAndSendVariableBurst(nextBurst, false); } } @@ -849,15 +876,13 @@ public class ApplicationConnection { * * @param variableBurst */ - private void cleanVariableBurst(ArrayList<String> variableBurst) { - for (int i = 1; i < variableBurst.size(); i += 2) { - String id = variableBurst.get(i); - id = id.substring(0, id.indexOf(VAR_FIELD_SEPARATOR)); - if (!idToPaintableDetail.containsKey(id) && !id.startsWith("DD")) { + private void cleanVariableBurst(ArrayList<MethodInvocation> variableBurst) { + for (int i = 1; i < variableBurst.size(); i++) { + String id = variableBurst.get(i).getConnectorId(); + if (!getConnectorMap().hasConnector(id) + && !getConnectorMap().isDragAndDropPaintable(id)) { // variable owner does not exist anymore - variableBurst.remove(i - 1); - variableBurst.remove(i - 1); - i -= 2; + variableBurst.remove(i); VConsole.log("Removed variable from removed component: " + id); } } @@ -868,7 +893,7 @@ public class ApplicationConnection { if (loadElement == null) { loadElement = DOM.createDiv(); DOM.setStyleAttribute(loadElement, "position", "absolute"); - DOM.appendChild(view.getElement(), loadElement); + DOM.appendChild(rootConnector.getWidget().getElement(), loadElement); VConsole.log("inserting load indicator"); } DOM.setElementProperty(loadElement, "className", "v-loading-indicator"); @@ -898,12 +923,14 @@ public class ApplicationConnection { private void hideLoadingIndicator() { if (loadTimer != null) { loadTimer.cancel(); - if (loadTimer2 != null) { - loadTimer2.cancel(); - loadTimer3.cancel(); - } loadTimer = null; } + if (loadTimer2 != null) { + loadTimer2.cancel(); + loadTimer3.cancel(); + loadTimer2 = null; + loadTimer3 = null; + } if (loadElement != null) { DOM.setStyleAttribute(loadElement, "display", "none"); } @@ -962,6 +989,7 @@ public class ApplicationConnection { protected void handleUIDLMessage(final Date start, final String jsonText, final ValueMap json) { + VConsole.log("Handling message from server"); // Handle redirect if (json.containsKey("redirect")) { String url = json.getValueMap("redirect").getString("url"); @@ -970,10 +998,13 @@ public class ApplicationConnection { return; } + final MultiStepDuration handleUIDLDuration = new MultiStepDuration(); + // Get security key if (json.containsKey(UIDL_SECURITY_TOKEN_ID)) { uidlSecurityKey = json.getString(UIDL_SECURITY_TOKEN_ID); } + VConsole.log(" * Handling resources from server"); if (json.containsKey("resources")) { ValueMap resources = json.getValueMap("resources"); @@ -984,12 +1015,27 @@ public class ApplicationConnection { resourcesMap.put(key, resources.getAsString(key)); } } + handleUIDLDuration.logDuration( + " * Handling resources from server completed", 10); + + VConsole.log(" * Handling type inheritance map from server"); + + if (json.containsKey("typeInheritanceMap")) { + configuration.addComponentInheritanceInfo(json + .getValueMap("typeInheritanceMap")); + } + handleUIDLDuration.logDuration( + " * Handling type inheritance map from server completed", 10); + + VConsole.log("Handling type mappings from server"); if (json.containsKey("typeMappings")) { configuration.addComponentMappings( json.getValueMap("typeMappings"), widgetSet); } + handleUIDLDuration.logDuration( + " * Handling type mappings from server completed", 10); /* * Hook for TestBench to get details about server status */ @@ -999,27 +1045,42 @@ public class ApplicationConnection { Command c = new Command() { public void execute() { - VConsole.dirUIDL(json, configuration); + handleUIDLDuration.logDuration(" * Loading widgets completed", + 10); + + MultiStepDuration updateDuration = new MultiStepDuration(); + + if (debugLogging) { + VConsole.log(" * Dumping UIDL to the console"); + VConsole.dirUIDL(json, configuration); + + updateDuration.logDuration( + " * Dumping UIDL to the console completed", 10); + } if (json.containsKey("locales")) { + VConsole.log(" * Handling locales"); // Store locale data JsArray<ValueMap> valueMapArray = json .getJSValueMapArray("locales"); LocaleService.addLocales(valueMapArray); } + updateDuration.logDuration(" * Handling locales completed", 10); + boolean repaintAll = false; ValueMap meta = null; if (json.containsKey("meta")) { + VConsole.log(" * Handling meta information"); meta = json.getValueMap("meta"); if (meta.containsKey("repaintAll")) { repaintAll = true; - view.clear(); - idToPaintableDetail.clear(); + rootConnector.getWidget().clear(); + getConnectorMap().clear(); if (meta.containsKey("invalidLayouts")) { validatingLayouts = true; - zeroWidthComponents = new HashSet<Paintable>(); - zeroHeightComponents = new HashSet<Paintable>(); + zeroWidthComponents = new HashSet<ComponentConnector>(); + zeroHeightComponents = new HashSet<ComponentConnector>(); } } if (meta.containsKey("timedRedirect")) { @@ -1036,60 +1097,61 @@ public class ApplicationConnection { } } + updateDuration.logDuration( + " * Handling meta information completed", 10); + if (redirectTimer != null) { redirectTimer.schedule(1000 * sessionExpirationInterval); } - // Process changes - JsArray<ValueMap> changes = json.getJSValueMapArray("changes"); - - ArrayList<Paintable> updatedWidgets = new ArrayList<Paintable>(); - relativeSizeChanges.clear(); componentCaptionSizeChanges.clear(); - int length = changes.length(); - for (int i = 0; i < length; i++) { - try { - final UIDL change = changes.get(i).cast(); - final UIDL uidl = change.getChildUIDL(0); - // TODO optimize - final Paintable paintable = getPaintable(uidl.getId()); - if (paintable != null) { - paintable.updateFromUIDL(uidl, - ApplicationConnection.this); - // paintable may have changed during render to - // another - // implementation, use the new one for updated - // widgets map - updatedWidgets.add(idToPaintableDetail.get( - uidl.getId()).getComponent()); - } else { - if (!uidl.getTag().equals( - configuration.getEncodedWindowTag())) { - VConsole.error("Received update for " - + uidl.getTag() - + ", but there is no such paintable (" - + uidl.getId() + ") rendered."); - } else { - String pid = uidl.getId(); - if (!idToPaintableDetail.containsKey(pid)) { - registerPaintable(pid, view); - } - // VView does not call updateComponent so we - // register any event listeners here - ComponentDetail cd = idToPaintableDetail - .get(pid); - cd.registerEventListenersFromUIDL(uidl); - - // Finally allow VView to update itself - view.updateFromUIDL(uidl, - ApplicationConnection.this); - } - } - } catch (final Throwable e) { - VConsole.error(e); - } - } + int startProcessing = updateDuration.elapsedMillis(); + + // Ensure that all connectors that we are about to update exist + createConnectorsIfNeeded(json); + + updateDuration.logDuration(" * Creating connectors completed", + 10); + + // Update states, do not fire events + Collection<StateChangeEvent> pendingStateChangeEvents = updateConnectorState(json); + + updateDuration.logDuration( + " * Update of connector states completed", 10); + + // Update hierarchy, do not fire events + Collection<ConnectorHierarchyChangeEvent> pendingHierarchyChangeEvents = updateConnectorHierarchy(json); + + updateDuration.logDuration( + " * Update of connector hierarchy completed", 10); + + // Fire hierarchy change events + sendHierarchyChangeEvents(pendingHierarchyChangeEvents); + + updateDuration.logDuration( + " * Hierarchy state change event processing completed", + 10); + + // Fire state change events. + sendStateChangeEvents(pendingStateChangeEvents); + + updateDuration.logDuration( + " * State change event processing completed", 10); + + // Update of legacy (UIDL) style connectors + updateVaadin6StyleConnectors(json); + + updateDuration + .logDuration( + " * Vaadin 6 style connector updates (updateFromUidl) completed", + 10); + + // Handle any RPC invocations done on the server side + handleRpcInvocations(json); + + updateDuration.logDuration( + " * Processing of RPC invocations completed", 10); if (json.containsKey("dd")) { // response contains data for drag and drop service @@ -1097,28 +1159,26 @@ public class ApplicationConnection { json.getValueMap("dd")); } - // Check which widgets' size has been updated - Set<Paintable> sizeUpdatedWidgets = new HashSet<Paintable>(); + updateDuration + .logDuration( + " * Processing of drag and drop server response completed", + 10); - updatedWidgets.addAll(relativeSizeChanges); - sizeUpdatedWidgets.addAll(componentCaptionSizeChanges); + unregisterRemovedConnectors(); - for (Paintable paintable : updatedWidgets) { - ComponentDetail detail = idToPaintableDetail - .get(getPid(paintable)); - Widget widget = (Widget) paintable; - Size oldSize = detail.getOffsetSize(); - Size newSize = new Size(widget.getOffsetWidth(), - widget.getOffsetHeight()); + updateDuration.logDuration( + " * Unregistering of removed components completed", 10); - if (oldSize == null || !oldSize.equals(newSize)) { - sizeUpdatedWidgets.add(paintable); - detail.setOffsetSize(newSize); - } + VConsole.log("handleUIDLMessage: " + + (updateDuration.elapsedMillis() - startProcessing) + + " ms"); - } + LayoutManager layoutManager = getLayoutManager(); + layoutManager.setEverythingNeedsMeasure(); + layoutManager.layoutNow(); - Util.componentSizeUpdated(sizeUpdatedWidgets); + updateDuration + .logDuration(" * Layout processing completed", 10); if (meta != null) { if (meta.containsKey("appError")) { @@ -1162,15 +1222,7 @@ public class ApplicationConnection { } } - if (repaintAll) { - /* - * idToPaintableDetail is already cleanded at the start of - * the changeset handling, bypass cleanup. - */ - unregistryBag.clear(); - } else { - purgeUnregistryBag(); - } + updateDuration.logDuration(" * Error handling completed", 10); // TODO build profiling for widget impl loading time @@ -1181,213 +1233,383 @@ public class ApplicationConnection { VConsole.log(" Processing time was " + String.valueOf(lastProcessingTime) + "ms for " + jsonText.length() + " characters of JSON"); - VConsole.log("Referenced paintables: " - + idToPaintableDetail.size()); + VConsole.log("Referenced paintables: " + connectorMap.size()); endRequest(); } - }; - ApplicationConfiguration.runWhenWidgetsLoaded(c); - } - /** - * This method assures that all pending variable changes are sent to server. - * Method uses synchronized xmlhttprequest and does not return before the - * changes are sent. No UIDL updates are processed and thus UI is left in - * inconsistent state. This method should be called only when closing - * windows - normally sendPendingVariableChanges() should be used. - */ - public void sendPendingVariableChangesSync() { - if (applicationRunning) { - pendingVariableBursts.add(pendingVariables); - ArrayList<String> nextBurst = pendingVariableBursts.get(0); - pendingVariableBursts.remove(0); - buildAndSendVariableBurst(nextBurst, true); - } - } + /** + * Sends the state change events created while updating the state + * information. + * + * This must be called after hierarchy change listeners have been + * called. At least caption updates for the parent are strange if + * fired from state change listeners and thus calls the parent + * BEFORE the parent is aware of the child (through a + * ConnectorHierarchyChangedEvent) + * + * @param pendingStateChangeEvents + * The events to send + */ + private void sendStateChangeEvents( + Collection<StateChangeEvent> pendingStateChangeEvents) { + VConsole.log(" * Sending state change events"); - // Redirect browser, null reloads current page - private static native void redirect(String url) - /*-{ - if (url) { - $wnd.location = url; - } else { - $wnd.location.reload(false); - } - }-*/; + for (StateChangeEvent sce : pendingStateChangeEvents) { + try { + sce.getConnector().fireEvent(sce); + } catch (final Throwable e) { + VConsole.error(e); + } + } - public void registerPaintable(String pid, Paintable paintable) { - ComponentDetail componentDetail = new ComponentDetail(this, pid, - paintable); - idToPaintableDetail.put(pid, componentDetail); - setPid(((Widget) paintable).getElement(), pid); - } + } - private native void setPid(Element el, String pid) - /*-{ - el.tkPid = pid; - }-*/; + private void unregisterRemovedConnectors() { + int unregistered = 0; + List<ServerConnector> currentConnectors = new ArrayList<ServerConnector>( + connectorMap.getConnectors()); + for (ServerConnector c : currentConnectors) { + if (c instanceof ComponentConnector) { + ComponentConnector cc = (ComponentConnector) c; + if (cc.getParent() != null) { + if (!cc.getParent().getChildren().contains(cc)) { + VConsole.error("ERROR: Connector is connected to a parent but the parent does not contain the connector"); + } + } else if ((cc instanceof RootConnector && cc == getRootConnector())) { + // RootConnector for this connection, leave as-is + } else if (cc instanceof WindowConnector + && getRootConnector().hasSubWindow( + (WindowConnector) cc)) { + // Sub window attached to this RootConnector, leave + // as-is + } else { + // The connector has been detached from the + // hierarchy, unregister it and any possible + // children. The RootConnector should never be + // unregistered even though it has no parent. + connectorMap.unregisterConnector(cc); + unregistered++; + } + } - /** - * Gets the paintableId for a specific paintable (a.k.a Vaadin Widget). - * <p> - * The paintableId is used in the UIDL to identify a specific widget - * instance, effectively linking the widget with it's server side Component. - * </p> - * - * @param paintable - * the paintable who's id is needed - * @return the id for the given paintable - */ - public String getPid(Paintable paintable) { - return getPid(((Widget) paintable).getElement()); - } + } - /** - * Gets the paintableId using a DOM element - the element should be the main - * element for a paintable otherwise no id will be found. Use - * {@link #getPid(Paintable)} instead whenever possible. - * - * @see #getPid(Paintable) - * @param el - * element of the paintable whose pid is desired - * @return the pid of the element's paintable, if it's a paintable - */ - public native String getPid(Element el) - /*-{ - return el.tkPid; - }-*/; + VConsole.log("* Unregistered " + unregistered + " connectors"); + } - /** - * Gets the main element for the paintable with the given id. The revers of - * {@link #getPid(Element)}. - * - * @param pid - * the pid of the widget whose element is desired - * @return the element for the paintable corresponding to the pid - */ - public Element getElementByPid(String pid) { - return ((Widget) getPaintable(pid)).getElement(); - } + private void createConnectorsIfNeeded(ValueMap json) { + VConsole.log(" * Creating connectors (if needed)"); - /** - * Unregisters the given paintable; always use after removing a paintable. - * This method does not remove the paintable from the DOM, but marks the - * paintable so that ApplicationConnection may clean up its references to - * it. Removing the widget from DOM is component containers responsibility. - * - * @param p - * the paintable to remove - */ - public void unregisterPaintable(Paintable p) { + if (!json.containsKey("types")) { + return; + } - // add to unregistry que + ValueMap types = json.getValueMap("types"); + JsArrayString keyArray = types.getKeyArray(); + for (int i = 0; i < keyArray.length(); i++) { + try { + String connectorId = keyArray.get(i); + int connectorType = Integer.parseInt(types + .getString((connectorId))); + ServerConnector connector = connectorMap + .getConnector(connectorId); + if (connector != null) { + continue; + } - if (p == null) { - VConsole.error("WARN: Trying to unregister null paintable"); - return; - } - String id = getPid(p); - if (id == null) { - /* - * Uncomment the following to debug unregistring components. No - * paintables with null id should end here. At least one exception - * is our VScrollTableRow, that is hacked to fake it self as a - * Paintable to build support for sizing easier. - */ - // if (!(p instanceof VScrollTableRow)) { - // VConsole.log("Trying to unregister Paintable not created by Application Connection."); - // } - if (p instanceof HasWidgets) { - unregisterChildPaintables((HasWidgets) p); + Class<? extends ComponentConnector> connectorClass = configuration + .getWidgetClassByEncodedTag(connectorType); + + // Connector does not exist so we must create it + if (connectorClass != RootConnector.class) { + // create, initialize and register the paintable + getConnector(connectorId, connectorType); + } else { + // First RootConnector update. Before this the + // RootConnector has been created but not + // initialized as the connector id has not been + // known + connectorMap.registerConnector(connectorId, + rootConnector); + rootConnector.doInit(connectorId, + ApplicationConnection.this); + } + } catch (final Throwable e) { + VConsole.error(e); + } + } } - } else { - unregistryBag.add(id); - if (p instanceof HasWidgets) { - unregisterChildPaintables((HasWidgets) p); + + private void updateVaadin6StyleConnectors(ValueMap json) { + JsArray<ValueMap> changes = json.getJSValueMapArray("changes"); + int length = changes.length(); + + VConsole.log(" * Passing UIDL to Vaadin 6 style connectors"); + // update paintables + for (int i = 0; i < length; i++) { + try { + final UIDL change = changes.get(i).cast(); + final UIDL uidl = change.getChildUIDL(0); + String connectorId = uidl.getId(); + + final ComponentConnector legacyConnector = (ComponentConnector) connectorMap + .getConnector(connectorId); + if (legacyConnector instanceof Paintable) { + ((Paintable) legacyConnector).updateFromUIDL(uidl, + ApplicationConnection.this); + } else if (legacyConnector == null) { + VConsole.error("Received update for " + + uidl.getTag() + + ", but there is no such paintable (" + + connectorId + ") rendered."); + } else { + VConsole.error("Server sent Vaadin 6 style updates for " + + Util.getConnectorString(legacyConnector) + + " but this is not a Vaadin 6 Paintable"); + } + + } catch (final Throwable e) { + VConsole.error(e); + } + } } - } - } - private void purgeUnregistryBag() { - for (String id : unregistryBag) { - ComponentDetail componentDetail = idToPaintableDetail.get(id); - if (componentDetail == null) { - /* - * this should never happen, but it does :-( See e.g. - * com.vaadin.tests.components.accordion.RemoveTabs (with test - * script) - */ - VConsole.error("ApplicationConnetion tried to unregister component (id=" - + id - + ") that is never registered (or already unregistered)"); - continue; + private void sendHierarchyChangeEvents( + Collection<ConnectorHierarchyChangeEvent> pendingHierarchyChangeEvents) { + if (pendingHierarchyChangeEvents.isEmpty()) { + return; + } + + VConsole.log(" * Sending hierarchy change events"); + for (ConnectorHierarchyChangeEvent event : pendingHierarchyChangeEvents) { + try { + event.getConnector().fireEvent(event); + } catch (final Throwable e) { + VConsole.error(e); + } + } + } - // check if can be cleaned - Widget component = (Widget) componentDetail.getComponent(); - if (!component.isAttached()) { - // clean reference from ac to paintable - idToPaintableDetail.remove(id); + + private Collection<StateChangeEvent> updateConnectorState( + ValueMap json) { + ArrayList<StateChangeEvent> events = new ArrayList<StateChangeEvent>(); + VConsole.log(" * Updating connector states"); + if (!json.containsKey("state")) { + return events; + } + // set states for all paintables mentioned in "state" + ValueMap states = json.getValueMap("state"); + JsArrayString keyArray = states.getKeyArray(); + for (int i = 0; i < keyArray.length(); i++) { + try { + String connectorId = keyArray.get(i); + ServerConnector connector = connectorMap + .getConnector(connectorId); + if (null != connector) { + + JSONArray stateDataAndType = new JSONArray( + states.getJavaScriptObject(connectorId)); + + Object state = JsonDecoder.decodeValue( + stateDataAndType, connectorMap, + ApplicationConnection.this); + + connector.setState((SharedState) state); + StateChangeEvent event = GWT + .create(StateChangeEvent.class); + event.setConnector(connector); + events.add(event); + } + } catch (final Throwable e) { + VConsole.error(e); + } + } + + return events; } - /* - * else NOP : same component has been reattached to another parent - * or replaced by another component implementation. + + /** + * Updates the connector hierarchy and returns a list of events that + * should be fired after update of the hierarchy and the state is + * done. + * + * @param json + * The JSON containing the hierarchy information + * @return A collection of events that should be fired when update + * of hierarchy and state is complete */ - } + private Collection<ConnectorHierarchyChangeEvent> updateConnectorHierarchy( + ValueMap json) { + List<ConnectorHierarchyChangeEvent> events = new LinkedList<ConnectorHierarchyChangeEvent>(); - unregistryBag.clear(); - } + VConsole.log(" * Updating connector hierarchy"); + if (!json.containsKey("hierarchy")) { + return events; + } + + ValueMap hierarchies = json.getValueMap("hierarchy"); + JsArrayString hierarchyKeys = hierarchies.getKeyArray(); + for (int i = 0; i < hierarchyKeys.length(); i++) { + try { + String connectorId = hierarchyKeys.get(i); + ServerConnector connector = connectorMap + .getConnector(connectorId); + if (!(connector instanceof ComponentContainerConnector)) { + VConsole.error("Retrieved a hierarchy update for a connector (" + + connectorId + + ") that is not a ComponentContainerConnector"); + continue; + } + ComponentContainerConnector ccc = (ComponentContainerConnector) connector; + + JsArrayString childConnectorIds = hierarchies + .getJSStringArray(connectorId); + int childConnectorSize = childConnectorIds.length(); + + List<ServerConnector> newChildren = new ArrayList<ServerConnector>(); + for (int connectorIndex = 0; connectorIndex < childConnectorSize; connectorIndex++) { + String childConnectorId = childConnectorIds + .get(connectorIndex); + ComponentConnector childConnector = (ComponentConnector) connectorMap + .getConnector(childConnectorId); + if (childConnector == null) { + VConsole.error("Hierarchy claims that " + + childConnectorId + " is a child for " + + connectorId + " (" + + connector.getClass().getName() + + ") but no connector with id " + + childConnectorId + + " has been registered"); + continue; + } + newChildren.add(childConnector); + if (childConnector.getParent() != ccc) { + // Avoid extra calls to setParent + childConnector.setParent(ccc); + } + } + + // TODO This check should be done on the server side in + // the future so the hierarchy update is only sent when + // something actually has changed + List<ComponentConnector> oldChildren = ccc + .getChildren(); + boolean actuallyChanged = !Util.collectionsEquals( + oldChildren, newChildren); + + if (!actuallyChanged) { + continue; + } + + // Fire change event if the hierarchy has changed + ConnectorHierarchyChangeEvent event = GWT + .create(ConnectorHierarchyChangeEvent.class); + event.setOldChildren(oldChildren); + event.setConnector(ccc); + ccc.setChildren((List) newChildren); + events.add(event); + + // Remove parent for children that are no longer + // attached to this (avoid updating children if they + // have already been assigned to a new parent) + for (ComponentConnector oldChild : oldChildren) { + if (oldChild.getParent() != ccc) { + continue; + } + + // TODO This could probably be optimized + if (!newChildren.contains(oldChild)) { + oldChild.setParent(null); + } + } + } catch (final Throwable e) { + VConsole.error(e); + } + } + return events; - /** - * Unregisters a paintable and all it's child paintables recursively. Use - * when after removing a paintable that contains other paintables. Does not - * unregister the given container itself. Does not actually remove the - * paintable from the DOM. - * - * @see #unregisterPaintable(Paintable) - * @param container - */ - public void unregisterChildPaintables(HasWidgets container) { - final Iterator<Widget> it = container.iterator(); - while (it.hasNext()) { - final Widget w = it.next(); - if (w instanceof Paintable) { - unregisterPaintable((Paintable) w); - } else if (w instanceof HasWidgets) { - unregisterChildPaintables((HasWidgets) w); } - } + + private void handleRpcInvocations(ValueMap json) { + if (json.containsKey("rpc")) { + VConsole.log(" * Performing server to client RPC calls"); + + JSONArray rpcCalls = new JSONArray( + json.getJavaScriptObject("rpc")); + + int rpcLength = rpcCalls.size(); + for (int i = 0; i < rpcLength; i++) { + try { + JSONArray rpcCall = (JSONArray) rpcCalls.get(i); + MethodInvocation invocation = parseMethodInvocation(rpcCall); + VConsole.log("Server to client RPC call: " + + invocation); + rpcManager.applyInvocation(invocation, + getConnectorMap()); + } catch (final Throwable e) { + VConsole.error(e); + } + } + } + + } + + }; + ApplicationConfiguration.runWhenWidgetsLoaded(c); } - /** - * Returns Paintable element by its id - * - * @param id - * Paintable ID - */ - public Paintable getPaintable(String id) { - ComponentDetail componentDetail = idToPaintableDetail.get(id); - if (componentDetail == null) { - return null; - } else { - return componentDetail.getComponent(); + private MethodInvocation parseMethodInvocation(JSONArray rpcCall) { + String connectorId = ((JSONString) rpcCall.get(0)).stringValue(); + String interfaceName = ((JSONString) rpcCall.get(1)).stringValue(); + String methodName = ((JSONString) rpcCall.get(2)).stringValue(); + JSONArray parametersJson = (JSONArray) rpcCall.get(3); + Object[] parameters = new Object[parametersJson.size()]; + for (int j = 0; j < parametersJson.size(); ++j) { + parameters[j] = JsonDecoder.decodeValue( + (JSONArray) parametersJson.get(j), getConnectorMap(), this); } + return new MethodInvocation(connectorId, interfaceName, methodName, + parameters); } - private void addVariableToQueue(String paintableId, String variableName, - String encodedValue, boolean immediate, char type) { - final String id = paintableId + VAR_FIELD_SEPARATOR + variableName - + VAR_FIELD_SEPARATOR + type; - for (int i = 1; i < pendingVariables.size(); i += 2) { - if ((pendingVariables.get(i)).equals(id)) { - pendingVariables.remove(i - 1); - pendingVariables.remove(i - 1); - break; - } - } - pendingVariables.add(encodedValue); - pendingVariables.add(id); + // Redirect browser, null reloads current page + private static native void redirect(String url) + /*-{ + if (url) { + $wnd.location = url; + } else { + $wnd.location.reload(false); + } + }-*/; + + private void addVariableToQueue(String connectorId, String variableName, + Object value, boolean immediate) { + // note that type is now deduced from value + // TODO could eliminate invocations of same shared variable setter + addMethodInvocationToQueue(new MethodInvocation(connectorId, + UPDATE_VARIABLE_INTERFACE, UPDATE_VARIABLE_METHOD, + new Object[] { variableName, value }), immediate); + } + + /** + * Adds an explicit RPC method invocation to the send queue. + * + * @since 7.0 + * + * @param invocation + * RPC method invocation + * @param immediate + * true to trigger sending within a short time window (possibly + * combining subsequent calls to a single request), false to let + * the framework delay sending of RPC calls and variable changes + * until the next immediate change + */ + public void addMethodInvocationToQueue(MethodInvocation invocation, + boolean immediate) { + pendingInvocations.add(invocation); if (immediate) { sendPendingVariableChanges(); } @@ -1403,20 +1625,32 @@ public class ApplicationConnection { * "burst" to queue that will be purged after current request is handled. * */ - @SuppressWarnings("unchecked") public void sendPendingVariableChanges() { + if (!deferedSendPending) { + deferedSendPending = true; + Scheduler.get().scheduleDeferred(sendPendingCommand); + } + } + + private final ScheduledCommand sendPendingCommand = new ScheduledCommand() { + public void execute() { + deferedSendPending = false; + doSendPendingVariableChanges(); + } + }; + private boolean deferedSendPending = false; + + @SuppressWarnings("unchecked") + private void doSendPendingVariableChanges() { if (applicationRunning) { if (hasActiveRequest()) { // skip empty queues if there are pending bursts to be sent - if (pendingVariables.size() > 0 - || pendingVariableBursts.size() == 0) { - ArrayList<String> burst = (ArrayList<String>) pendingVariables - .clone(); - pendingVariableBursts.add(burst); - pendingVariables.clear(); + if (pendingInvocations.size() > 0 || pendingBursts.size() == 0) { + pendingBursts.add(pendingInvocations); + pendingInvocations = new ArrayList<MethodInvocation>(); } } else { - buildAndSendVariableBurst(pendingVariables, false); + buildAndSendVariableBurst(pendingInvocations, false); } } } @@ -1428,39 +1662,64 @@ public class ApplicationConnection { * at the same time. This is ok as we can assume that DOM will never be * updated after this. * - * @param pendingVariables - * Vector of variable changes to send + * @param pendingInvocations + * List of RPC method invocations to send * @param forceSync * Should we use synchronous request? */ - private void buildAndSendVariableBurst(ArrayList<String> pendingVariables, - boolean forceSync) { + private void buildAndSendVariableBurst( + ArrayList<MethodInvocation> pendingInvocations, boolean forceSync) { final StringBuffer req = new StringBuffer(); - while (!pendingVariables.isEmpty()) { + while (!pendingInvocations.isEmpty()) { if (ApplicationConfiguration.isDebugMode()) { - Util.logVariableBurst(this, pendingVariables); + Util.logVariableBurst(this, pendingInvocations); } - for (int i = 0; i < pendingVariables.size(); i++) { - if (i > 0) { - if (i % 2 == 0) { - req.append(VAR_RECORD_SEPARATOR); - } else { - req.append(VAR_FIELD_SEPARATOR); - } + + JSONArray reqJson = new JSONArray(); + + for (MethodInvocation invocation : pendingInvocations) { + JSONArray invocationJson = new JSONArray(); + invocationJson.set(0, + new JSONString(invocation.getConnectorId())); + invocationJson.set(1, + new JSONString(invocation.getInterfaceName())); + invocationJson.set(2, + new JSONString(invocation.getMethodName())); + JSONArray paramJson = new JSONArray(); + for (int i = 0; i < invocation.getParameters().length; ++i) { + // TODO non-static encoder? type registration? + paramJson.set(i, JsonEncoder.encode( + invocation.getParameters()[i], getConnectorMap(), + this)); } - req.append(pendingVariables.get(i)); + invocationJson.set(3, paramJson); + reqJson.set(reqJson.size(), invocationJson); } - pendingVariables.clear(); - // Append all the busts to this synchronous request - if (forceSync && !pendingVariableBursts.isEmpty()) { - pendingVariables = pendingVariableBursts.get(0); - pendingVariableBursts.remove(0); + // escape burst separators (if any) + req.append(escapeBurstContents(reqJson.toString())); + + pendingInvocations.clear(); + // Append all the bursts to this synchronous request + if (forceSync && !pendingBursts.isEmpty()) { + pendingInvocations = pendingBursts.get(0); + pendingBursts.remove(0); req.append(VAR_BURST_SEPARATOR); } } - makeUidlRequest(req.toString(), "", forceSync); + + // Include the browser detail parameters if they aren't already sent + String extraParams; + if (!getConfiguration().isBrowserDetailsSent()) { + extraParams = getNativeBrowserDetailsParameters(getConfiguration() + .getRootPanelId()); + getConfiguration().setBrowserDetailsSent(); + } else { + extraParams = ""; + } + + makeUidlRequest(req.toString(), extraParams, forceSync); } /** @@ -1481,9 +1740,8 @@ public class ApplicationConnection { * true if the update is to be sent as soon as possible */ public void updateVariable(String paintableId, String variableName, - Paintable newValue, boolean immediate) { - String pid = (newValue != null) ? getPid(newValue) : null; - addVariableToQueue(paintableId, variableName, pid, immediate, 'p'); + ServerConnector newValue, boolean immediate) { + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1506,8 +1764,7 @@ public class ApplicationConnection { public void updateVariable(String paintableId, String variableName, String newValue, boolean immediate) { - addVariableToQueue(paintableId, variableName, - escapeVariableValue(newValue), immediate, 's'); + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1530,8 +1787,7 @@ public class ApplicationConnection { public void updateVariable(String paintableId, String variableName, int newValue, boolean immediate) { - addVariableToQueue(paintableId, variableName, "" + newValue, immediate, - 'i'); + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1554,8 +1810,7 @@ public class ApplicationConnection { public void updateVariable(String paintableId, String variableName, long newValue, boolean immediate) { - addVariableToQueue(paintableId, variableName, "" + newValue, immediate, - 'l'); + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1578,8 +1833,7 @@ public class ApplicationConnection { public void updateVariable(String paintableId, String variableName, float newValue, boolean immediate) { - addVariableToQueue(paintableId, variableName, "" + newValue, immediate, - 'f'); + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1602,8 +1856,7 @@ public class ApplicationConnection { public void updateVariable(String paintableId, String variableName, double newValue, boolean immediate) { - addVariableToQueue(paintableId, variableName, "" + newValue, immediate, - 'd'); + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1626,8 +1879,7 @@ public class ApplicationConnection { public void updateVariable(String paintableId, String variableName, boolean newValue, boolean immediate) { - addVariableToQueue(paintableId, variableName, newValue ? "true" - : "false", immediate, 'b'); + addVariableToQueue(paintableId, variableName, newValue, immediate); } /** @@ -1642,56 +1894,14 @@ public class ApplicationConnection { * the id of the paintable that owns the variable * @param variableName * the name of the variable - * @param newValue - * the new value to be sent + * @param map + * the new values to be sent * @param immediate * true if the update is to be sent as soon as possible */ public void updateVariable(String paintableId, String variableName, Map<String, Object> map, boolean immediate) { - final StringBuffer buf = new StringBuffer(); - Iterator<String> iterator = map.keySet().iterator(); - while (iterator.hasNext()) { - String key = iterator.next(); - Object value = map.get(key); - char transportType = getTransportType(value); - buf.append(transportType); - buf.append(escapeVariableValue(key)); - buf.append(VAR_ARRAYITEM_SEPARATOR); - if (transportType == 'p') { - buf.append(getPid((Paintable) value)); - } else { - buf.append(escapeVariableValue(String.valueOf(value))); - } - - if (iterator.hasNext()) { - buf.append(VAR_ARRAYITEM_SEPARATOR); - } - } - - addVariableToQueue(paintableId, variableName, buf.toString(), - immediate, 'm'); - } - - private char getTransportType(Object value) { - if (value instanceof String) { - return 's'; - } else if (value instanceof Paintable) { - return 'p'; - } else if (value instanceof Boolean) { - return 'b'; - } else if (value instanceof Integer) { - return 'i'; - } else if (value instanceof Float) { - return 'f'; - } else if (value instanceof Double) { - return 'd'; - } else if (value instanceof Long) { - return 'l'; - } else if (value instanceof Enum) { - return 's'; // transported as string representation - } - return 'u'; + addVariableToQueue(paintableId, variableName, map, immediate); } /** @@ -1707,25 +1917,14 @@ public class ApplicationConnection { * the id of the paintable that owns the variable * @param variableName * the name of the variable - * @param newValue + * @param values * the new value to be sent * @param immediate * true if the update is to be sent as soon as possible */ public void updateVariable(String paintableId, String variableName, String[] values, boolean immediate) { - final StringBuffer buf = new StringBuffer(); - if (values != null) { - for (int i = 0; i < values.length; i++) { - buf.append(escapeVariableValue(values[i])); - // there will be an extra separator at the end to differentiate - // between an empty array and one containing an empty string - // only - buf.append(VAR_ARRAYITEM_SEPARATOR); - } - } - addVariableToQueue(paintableId, variableName, buf.toString(), - immediate, 'c'); + addVariableToQueue(paintableId, variableName, values, immediate); } /** @@ -1742,44 +1941,25 @@ public class ApplicationConnection { * the id of the paintable that owns the variable * @param variableName * the name of the variable - * @param newValue + * @param values * the new value to be sent * @param immediate * true if the update is to be sent as soon as possible */ public void updateVariable(String paintableId, String variableName, Object[] values, boolean immediate) { - final StringBuffer buf = new StringBuffer(); - if (values != null) { - for (int i = 0; i < values.length; i++) { - if (i > 0) { - buf.append(VAR_ARRAYITEM_SEPARATOR); - } - Object value = values[i]; - char transportType = getTransportType(value); - // first char tells the type in array - buf.append(transportType); - if (transportType == 'p') { - buf.append(getPid((Paintable) value)); - } else { - buf.append(escapeVariableValue(String.valueOf(value))); - } - } - } - addVariableToQueue(paintableId, variableName, buf.toString(), - immediate, 'a'); + addVariableToQueue(paintableId, variableName, values, immediate); } /** - * Encode burst, record, field and array item separator characters in a - * String for transport over the network. This protects from separator - * injection attacks. + * Encode burst separator characters in a String for transport over the + * network. This protects from separator injection attacks. * * @param value * to encode * @return encoded value */ - protected String escapeVariableValue(String value) { + protected String escapeBurstContents(String value) { final StringBuilder result = new StringBuilder(); for (int i = 0; i < value.length(); ++i) { char character = value.charAt(i); @@ -1787,9 +1967,6 @@ public class ApplicationConnection { case VAR_ESCAPE_CHARACTER: // fall-through - escape character is duplicated case VAR_BURST_SEPARATOR: - case VAR_RECORD_SEPARATOR: - case VAR_FIELD_SEPARATOR: - case VAR_ARRAYITEM_SEPARATOR: result.append(VAR_ESCAPE_CHARACTER); // encode as letters for easier reading result.append(((char) (character + 0x30))); @@ -1803,288 +1980,6 @@ public class ApplicationConnection { return result.toString(); } - /** - * Update generic component features. - * - * <h2>Selecting correct implementation</h2> - * - * <p> - * The implementation of a component depends on many properties, including - * styles, component features, etc. Sometimes the user changes those - * properties after the component has been created. Calling this method in - * the beginning of your updateFromUIDL -method automatically replaces your - * component with more appropriate if the requested implementation changes. - * </p> - * - * <h2>Caption, icon, error messages and description</h2> - * - * <p> - * Component can delegate management of caption, icon, error messages and - * description to parent layout. This is optional an should be decided by - * component author - * </p> - * - * <h2>Component visibility and disabling</h2> - * - * This method will manage component visibility automatically and if - * component is an instanceof FocusWidget, also handle component disabling - * when needed. - * - * @param component - * Widget to be updated, expected to implement an instance of - * Paintable - * @param uidl - * UIDL to be painted - * @param manageCaption - * True if you want to delegate caption, icon, description and - * error message management to parent. - * - * @return Returns true iff no further painting is needed by caller - */ - public boolean updateComponent(Widget component, UIDL uidl, - boolean manageCaption) { - String pid = getPid(component.getElement()); - if (pid == null) { - VConsole.error("Trying to update an unregistered component: " - + Util.getSimpleName(component)); - return true; - } - - ComponentDetail componentDetail = idToPaintableDetail.get(pid); - - if (componentDetail == null) { - VConsole.error("ComponentDetail not found for " - + Util.getSimpleName(component) + " with PID " + pid - + ". This should not happen."); - return true; - } - - // If the server request that a cached instance should be used, do - // nothing - if (uidl.getBooleanAttribute("cached")) { - return true; - } - - // register the listened events by the server-side to the event-handler - // of the component - componentDetail.registerEventListenersFromUIDL(uidl); - - // Visibility - boolean visible = !uidl.getBooleanAttribute("invisible"); - boolean wasVisible = component.isVisible(); - component.setVisible(visible); - if (wasVisible != visible) { - // Changed invisibile <-> visible - if (wasVisible && manageCaption) { - // Must hide caption when component is hidden - final Container parent = Util.getLayout(component); - if (parent != null) { - parent.updateCaption((Paintable) component, uidl); - } - - } - } - - String id = uidl.getId(); - if (configuration.useDebugIdInDOM() && id.startsWith("PID_")) { - // PIDs with a debug id have form "PID_[seq]S[debugid]" where [seq] - // is either empty or a sequential integer used to uniquify - // different Paintables having the same debug id. See #5109. - DOM.setElementProperty(component.getElement(), "id", - id.substring(id.indexOf('S') + 1)); - } - - if (!visible) { - // component is invisible, delete old size to notify parent, if - // later make visible - componentDetail.setOffsetSize(null); - return true; - } - - // Switch to correct implementation if needed - if (!widgetSet.isCorrectImplementation(component, uidl, configuration)) { - final Widget w = (Widget) widgetSet.createWidget(uidl, - configuration); - // deferred binding check TODO change isCorrectImplementation to use - // stored detected class, making this innecessary - if (w.getClass() != component.getClass()) { - final Container parent = Util.getLayout(component); - if (parent != null) { - parent.replaceChildComponent(component, w); - unregisterPaintable((Paintable) component); - registerPaintable(uidl.getId(), (Paintable) w); - ((Paintable) w).updateFromUIDL(uidl, this); - return true; - } - } - } - - boolean enabled = !uidl.getBooleanAttribute("disabled"); - if (uidl.hasAttribute("tabindex") && component instanceof Focusable) { - ((Focusable) component).setTabIndex(uidl - .getIntAttribute("tabindex")); - } - /* - * Disabled state may affect (override) tabindex so the order must be - * first setting tabindex, then enabled state. - */ - if (component instanceof FocusWidget) { - FocusWidget fw = (FocusWidget) component; - fw.setEnabled(enabled); - } - - TooltipInfo tooltipInfo = componentDetail.getTooltipInfo(null); - // Update tooltip - if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) { - tooltipInfo - .setTitle(uidl.getStringAttribute(ATTRIBUTE_DESCRIPTION)); - } else { - tooltipInfo.setTitle(null); - } - - // add error classname to components w/ error - if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { - tooltipInfo.setErrorUidl(uidl.getErrors()); - } else { - tooltipInfo.setErrorUidl(null); - } - - // Style names - component.setStyleName(getStyleName(component.getStylePrimaryName(), - uidl, component instanceof Field)); - - // Set captions - if (manageCaption) { - final Container parent = Util.getLayout(component); - if (parent != null) { - parent.updateCaption((Paintable) component, uidl); - } - } - /* - * updateComponentSize need to be after caption update so caption can be - * taken into account - */ - - updateComponentSize(componentDetail, uidl); - - return false; - } - - /** - * Generates the style name for the widget based on the given primary style - * name (typically returned by Widget.getPrimaryStyleName()) and the UIDL. - * An additional "modified" style name can be added if the field parameter - * is set to true. - * - * @param primaryStyleName - * @param uidl - * @param isField - * @return - */ - public static String getStyleName(String primaryStyleName, UIDL uidl, - boolean field) { - boolean enabled = !uidl.getBooleanAttribute("disabled"); - - StringBuffer styleBuf = new StringBuffer(); - styleBuf.append(primaryStyleName); - - // first disabling and read-only status - if (!enabled) { - styleBuf.append(" "); - styleBuf.append(DISABLED_CLASSNAME); - } - if (uidl.getBooleanAttribute("readonly")) { - styleBuf.append(" "); - styleBuf.append("v-readonly"); - } - - // add additional styles as css classes, prefixed with component default - // stylename - if (uidl.hasAttribute("style")) { - final String[] styles = uidl.getStringAttribute("style").split(" "); - for (int i = 0; i < styles.length; i++) { - styleBuf.append(" "); - styleBuf.append(primaryStyleName); - styleBuf.append("-"); - styleBuf.append(styles[i]); - styleBuf.append(" "); - styleBuf.append(styles[i]); - } - } - - // add modified classname to Fields - if (field && uidl.hasAttribute("modified")) { - styleBuf.append(" "); - styleBuf.append(MODIFIED_CLASSNAME); - } - - if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { - styleBuf.append(" "); - styleBuf.append(primaryStyleName); - styleBuf.append(ERROR_CLASSNAME_EXT); - } - // add required style to required components - if (uidl.hasAttribute("required")) { - styleBuf.append(" "); - styleBuf.append(primaryStyleName); - styleBuf.append(REQUIRED_CLASSNAME_EXT); - } - - return styleBuf.toString(); - - } - - private void updateComponentSize(ComponentDetail cd, UIDL uidl) { - String w = uidl.hasAttribute("width") ? uidl - .getStringAttribute("width") : ""; - - String h = uidl.hasAttribute("height") ? uidl - .getStringAttribute("height") : ""; - - float relativeWidth = Util.parseRelativeSize(w); - float relativeHeight = Util.parseRelativeSize(h); - - // First update maps so they are correct in the setHeight/setWidth calls - if (relativeHeight >= 0.0 || relativeWidth >= 0.0) { - // One or both is relative - FloatSize relativeSize = new FloatSize(relativeWidth, - relativeHeight); - if (cd.getRelativeSize() == null && cd.getOffsetSize() != null) { - // The component has changed from absolute size to relative size - relativeSizeChanges.add(cd.getComponent()); - } - cd.setRelativeSize(relativeSize); - } else if (relativeHeight < 0.0 && relativeWidth < 0.0) { - if (cd.getRelativeSize() != null) { - // The component has changed from relative size to absolute size - relativeSizeChanges.add(cd.getComponent()); - } - cd.setRelativeSize(null); - } - - Widget component = (Widget) cd.getComponent(); - // Set absolute sizes - if (relativeHeight < 0.0) { - component.setHeight(h); - } - if (relativeWidth < 0.0) { - component.setWidth(w); - } - - // Set relative sizes - if (relativeHeight >= 0.0 || relativeWidth >= 0.0) { - // One or both is relative - handleComponentRelativeSize(cd); - } - - } - - /** - * Traverses recursively child widgets until ContainerResizedListener child - * widget is found. They will delegate it further if needed. - * - * @param container - */ private boolean runningLayout = false; /** @@ -2106,11 +2001,11 @@ public class ApplicationConnection { * development. Published to JavaScript. */ public void forceLayout() { - Set<Paintable> set = new HashSet<Paintable>(); - for (ComponentDetail cd : idToPaintableDetail.values()) { - set.add(cd.getComponent()); - } - Util.componentSizeUpdated(set); + Duration duration = new Duration(); + + layoutManager.forceLayout(); + + VConsole.log("forceLayout in " + duration.elapsedMillis() + " ms"); } private void internalRunDescendentsLayout(HasWidgets container) { @@ -2120,7 +2015,7 @@ public class ApplicationConnection { while (childWidgets.hasNext()) { final Widget child = childWidgets.next(); - if (child instanceof Paintable) { + if (getConnectorMap().isConnector(child)) { if (handleComponentRelativeSize(child)) { /* @@ -2151,131 +2046,8 @@ public class ApplicationConnection { * @param child * @return true if the child has a relative size */ - private boolean handleComponentRelativeSize(ComponentDetail cd) { - if (cd == null) { - return false; - } - boolean debugSizes = false; - - FloatSize relativeSize = cd.getRelativeSize(); - if (relativeSize == null) { - return false; - } - Widget widget = (Widget) cd.getComponent(); - - boolean horizontalScrollBar = false; - boolean verticalScrollBar = false; - - Container parent = Util.getLayout(widget); - RenderSpace renderSpace; - - // Parent-less components (like sub-windows) are relative to browser - // window. - if (parent == null) { - renderSpace = new RenderSpace(Window.getClientWidth(), - Window.getClientHeight()); - } else { - renderSpace = parent.getAllocatedSpace(widget); - } - - if (relativeSize.getHeight() >= 0) { - if (renderSpace != null) { - - if (renderSpace.getScrollbarSize() > 0) { - if (relativeSize.getWidth() > 100) { - horizontalScrollBar = true; - } else if (relativeSize.getWidth() < 0 - && renderSpace.getWidth() > 0) { - int offsetWidth = widget.getOffsetWidth(); - int width = renderSpace.getWidth(); - if (offsetWidth > width) { - horizontalScrollBar = true; - } - } - } - - int height = renderSpace.getHeight(); - if (horizontalScrollBar) { - height -= renderSpace.getScrollbarSize(); - } - if (validatingLayouts && height <= 0) { - zeroHeightComponents.add(cd.getComponent()); - } - - height = (int) (height * relativeSize.getHeight() / 100.0); - - if (height < 0) { - height = 0; - } - - if (debugSizes) { - VConsole.log("Widget " + Util.getSimpleName(widget) + "/" - + getPid(widget.getElement()) + " relative height " - + relativeSize.getHeight() + "% of " - + renderSpace.getHeight() + "px (reported by " - - + Util.getSimpleName(parent) + "/" - + (parent == null ? "?" : parent.hashCode()) - + ") : " + height + "px"); - } - widget.setHeight(height + "px"); - } else { - widget.setHeight(relativeSize.getHeight() + "%"); - VConsole.error(Util.getLayout(widget).getClass().getName() - + " did not produce allocatedSpace for " - + widget.getClass().getName()); - } - } - - if (relativeSize.getWidth() >= 0) { - - if (renderSpace != null) { - - int width = renderSpace.getWidth(); - - if (renderSpace.getScrollbarSize() > 0) { - if (relativeSize.getHeight() > 100) { - verticalScrollBar = true; - } else if (relativeSize.getHeight() < 0 - && renderSpace.getHeight() > 0 - && widget.getOffsetHeight() > renderSpace - .getHeight()) { - verticalScrollBar = true; - } - } - - if (verticalScrollBar) { - width -= renderSpace.getScrollbarSize(); - } - if (validatingLayouts && width <= 0) { - zeroWidthComponents.add(cd.getComponent()); - } - - width = (int) (width * relativeSize.getWidth() / 100.0); - - if (width < 0) { - width = 0; - } - - if (debugSizes) { - VConsole.log("Widget " + Util.getSimpleName(widget) + "/" - + getPid(widget.getElement()) + " relative width " - + relativeSize.getWidth() + "% of " - + renderSpace.getWidth() + "px (reported by " - + Util.getSimpleName(parent) + "/" - + (parent == null ? "?" : getPid(parent)) + ") : " - + width + "px"); - } - widget.setWidth(width + "px"); - } else { - widget.setWidth(relativeSize.getWidth() + "%"); - VConsole.error(Util.getLayout(widget).getClass().getName() - + " did not produce allocatedSpace for " - + widget.getClass().getName()); - } - } - - return true; + private boolean handleComponentRelativeSize(ComponentConnector paintable) { + return false; } /** @@ -2284,57 +2056,61 @@ public class ApplicationConnection { * @param child * @return true if the child has a relative size */ - public boolean handleComponentRelativeSize(Widget child) { - return handleComponentRelativeSize(idToPaintableDetail.get(getPid(child - .getElement()))); + public boolean handleComponentRelativeSize(Widget widget) { + return handleComponentRelativeSize(connectorMap.getConnector(widget)); } - /** - * Gets the specified Paintables relative size (percent). - * - * @param widget - * the paintable whose size is needed - * @return the the size if the paintable is relatively sized, -1 otherwise - */ - public FloatSize getRelativeSize(Widget widget) { - return idToPaintableDetail.get(getPid(widget.getElement())) - .getRelativeSize(); + @Deprecated + public ComponentConnector getPaintable(UIDL uidl) { + return getConnector(uidl.getId(), Integer.parseInt(uidl.getTag())); } /** - * Get either existing or new Paintable for given UIDL. + * Get either an existing ComponentConnector or create a new + * ComponentConnector with the given type and id. * - * If corresponding Paintable has been previously painted, return it. - * Otherwise create and register a new Paintable from UIDL. Caller must - * update the returned Paintable from UIDL after it has been connected to - * parent. + * If a ComponentConnector with the given id already exists, returns it. + * Otherwise creates and registers a new ComponentConnector of the given + * type. * - * @param uidl - * UIDL to create Paintable from. - * @return Either existing or new Paintable corresponding to UIDL. - */ - public Paintable getPaintable(UIDL uidl) { - final String id = uidl.getId(); - Paintable w = getPaintable(id); - if (w != null) { - return w; - } else { - w = widgetSet.createWidget(uidl, configuration); - registerPaintable(id, w); - return w; - + * @param connectorId + * Id of the paintable + * @param connectorType + * Type of the connector, as passed from the server side + * + * @return Either an existing ComponentConnector or a new ComponentConnector + * of the given type + */ + public ComponentConnector getConnector(String connectorId, int connectorType) { + if (!connectorMap.hasConnector(connectorId)) { + return createAndRegisterConnector(connectorId, connectorType); } + return (ComponentConnector) connectorMap.getConnector(connectorId); } /** - * Returns a Paintable element by its root element + * Creates a new ComponentConnector with the given type and id. + * + * Creates and registers a new ComponentConnector of the given type. Should + * never be called with the connector id of an existing connector. + * + * @param connectorId + * Id of the new connector + * @param connectorType + * Type of the connector, as passed from the server side * - * @param element - * Root element of the paintable + * @return A new ComponentConnector of the given type */ - public Paintable getPaintable(Element element) { - return getPaintable(getPid(element)); + private ComponentConnector createAndRegisterConnector(String connectorId, + int connectorType) { + // Create and register a new connector with the given type + ComponentConnector p = widgetSet.createWidget(connectorType, + configuration); + connectorMap.registerConnector(connectorId, p); + p.doInit(connectorId, this); + + return p; } /** @@ -2427,16 +2203,12 @@ public class ApplicationConnection { * Updating TooltipInfo is done in updateComponent method. * */ - public TooltipInfo getTooltipTitleInfo(Paintable titleOwner, Object key) { + public TooltipInfo getTooltipTitleInfo(ComponentConnector titleOwner, + Object key) { if (null == titleOwner) { return null; } - ComponentDetail cd = idToPaintableDetail.get(getPid(titleOwner)); - if (null != cd) { - return cd.getTooltipInfo(key); - } else { - return null; - } + return connectorMap.getTooltipInfo(titleOwner, key); } private final VTooltip tooltip = new VTooltip(this); @@ -2451,7 +2223,7 @@ public class ApplicationConnection { * @param event * @param owner */ - public void handleTooltipEvent(Event event, Paintable owner) { + public void handleTooltipEvent(Event event, ComponentConnector owner) { tooltip.handleTooltipEvent(event, owner, null); } @@ -2469,73 +2241,13 @@ public class ApplicationConnection { * the key for tooltip if this is "additional" tooltip, null for * components "main tooltip" */ - public void handleTooltipEvent(Event event, Paintable owner, Object key) { + public void handleTooltipEvent(Event event, ComponentConnector owner, + Object key) { tooltip.handleTooltipEvent(event, owner, key); } - /** - * Adds PNG-fix conditionally (only for IE6) to the specified IMG -element. - * - * @param el - * the IMG element to fix - */ - public void addPngFix(Element el) { - BrowserInfo b = BrowserInfo.get(); - if (b.isIE6()) { - Util.addPngFix(el); - } - } - - /* - * Helper to run layout functions triggered by child components with a - * decent interval. - */ - private final Timer layoutTimer = new Timer() { - - private boolean isPending = false; - - @Override - public void schedule(int delayMillis) { - if (!isPending) { - super.schedule(delayMillis); - isPending = true; - } - } - - @Override - public void run() { - VConsole.log("Running re-layout of " + view.getClass().getName()); - runDescendentsLayout(view); - isPending = false; - } - }; - - /** - * Components can call this function to run all layout functions. This is - * usually done, when component knows that its size has changed. - */ - public void requestLayoutPhase() { - layoutTimer.schedule(500); - } - - private String windowName = null; - - /** - * Reset the name of the current browser-window. This should reflect the - * window-name used in the server, but might be different from the - * window-object target-name on client. - * - * @param stringAttribute - * New name for the window. - */ - public void setWindowName(String newName) { - windowName = newName; - } - - protected String getWindowName() { - return windowName; - } + private ConnectorMap connectorMap = GWT.create(ConnectorMap.class); protected String getUidlSecurityKey() { return uidlSecurityKey; @@ -2548,17 +2260,17 @@ public class ApplicationConnection { * @param component * the Paintable whose caption has changed */ - public void captionSizeUpdated(Paintable component) { - componentCaptionSizeChanges.add(component); + public void captionSizeUpdated(Widget widget) { + componentCaptionSizeChanges.add(widget); } /** - * Gets the main view, a.k.a top-level window. + * Gets the main view * * @return the main view */ - public VView getView() { - return view; + public RootConnector getRootConnector() { + return rootConnector; } /** @@ -2567,7 +2279,7 @@ public class ApplicationConnection { * this method. * <p> * Component must also pipe events to - * {@link #handleTooltipEvent(Event, Paintable, Object)} method. + * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} method. * <p> * This method can also be used to deregister tooltips by using null as * tooltip @@ -2577,17 +2289,16 @@ public class ApplicationConnection { * @param key * key assosiated with given tooltip. Can be any object. For * example a related dom element. Same key must be given for - * {@link #handleTooltipEvent(Event, Paintable, Object)} method. + * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} + * method. * * @param tooltip * the TooltipInfo object containing details shown in tooltip, * null if deregistering tooltip */ - public void registerTooltip(Paintable paintable, Object key, + public void registerTooltip(ComponentConnector paintable, Object key, TooltipInfo tooltip) { - ComponentDetail componentDetail = idToPaintableDetail - .get(getPid(paintable)); - componentDetail.putAdditionalTooltip(key, tooltip); + connectorMap.registerTooltip(paintable, key, tooltip); } /** @@ -2606,14 +2317,18 @@ public class ApplicationConnection { * before the component is updated so the value is correct if called from * updatedFromUIDL. * + * @param paintable + * The connector to register event listeners for * @param eventIdentifier * The identifier for the event * @return true if at least one listener has been registered on server side * for the event identified by eventIdentifier. + * @deprecated Use {@link ComponentState#hasEventListener(String)} instead */ - public boolean hasEventListeners(Paintable paintable, String eventIdentifier) { - return idToPaintableDetail.get(getPid(paintable)).hasEventListeners( - eventIdentifier); + @Deprecated + public boolean hasEventListeners(ComponentConnector paintable, + String eventIdentifier) { + return paintable.hasEventListener(eventIdentifier); } /** @@ -2657,4 +2372,71 @@ public class ApplicationConnection { return uri; } + ConnectorMap getConnectorMap() { + return connectorMap; + } + + @Deprecated + public void unregisterPaintable(ServerConnector p) { + System.out.println("unregisterPaintable (unnecessarily) called for " + + Util.getConnectorString(p)); + // connectorMap.unregisterConnector(p); + } + + public VTooltip getVTooltip() { + return tooltip; + } + + @Deprecated + public void handleTooltipEvent(Event event, Widget owner, Object key) { + handleTooltipEvent(event, getConnectorMap().getConnector(owner), key); + } + + /** + * Method provided for backwards compatibility. Duties previously done by + * this method is now handled by the state change event handler in + * AbstractComponentConnector. The only function this method has is to + * return true if the UIDL is a "cached" update. + * + * @param component + * @param uidl + * @param manageCaption + * @return + */ + @Deprecated + public boolean updateComponent(Widget component, UIDL uidl, + boolean manageCaption) { + ComponentConnector connector = getConnectorMap() + .getConnector(component); + if (!AbstractComponentConnector.isRealUpdate(uidl)) { + return true; + } + + if (!manageCaption) { + VConsole.error(Util.getConnectorString(connector) + + " called updateComponent with manageCaption=false. The parameter was ignored - override delegateCaption() to return false instead. It is however not recommended to use caption this way at all."); + } + return false; + } + + @Deprecated + public void handleTooltipEvent(Event event, Widget owner) { + handleTooltipEvent(event, getConnectorMap().getConnector(owner)); + + } + + @Deprecated + public void registerTooltip(Widget owner, Object key, TooltipInfo info) { + registerTooltip(getConnectorMap().getConnector(owner), key, info); + } + + @Deprecated + public boolean hasEventListeners(Widget widget, String eventIdentifier) { + return hasEventListeners(getConnectorMap().getConnector(widget), + eventIdentifier); + } + + LayoutManager getLayoutManager() { + return layoutManager; + } } diff --git a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java index 844b4f2e96..ef1dc481b1 100644 --- a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java +++ b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java @@ -4,8 +4,6 @@ package com.vaadin.terminal.gwt.client; -import java.util.Date; - import com.google.gwt.user.client.ui.RootPanel; /** @@ -66,11 +64,11 @@ public class BrowserInfo { browserDetails.setIEMode(documentMode); } } - + if (browserDetails.isChrome()) { - touchDevice = detectChromeTouchDevice(); + touchDevice = detectChromeTouchDevice(); } else { - touchDevice = detectTouchDevice(); + touchDevice = detectTouchDevice(); } } @@ -78,7 +76,7 @@ public class BrowserInfo { /*-{ try { document.createEvent("TouchEvent");return true;} catch(e){return false;}; }-*/; - + private native boolean detectChromeTouchDevice() /*-{ return ("ontouchstart" in window); @@ -202,14 +200,6 @@ public class BrowserInfo { return isSafari() && browserDetails.getBrowserMajorVersion() == 4; } - public boolean isIE6() { - return isIE() && browserDetails.getBrowserMajorVersion() == 6; - } - - public boolean isIE7() { - return isIE() && browserDetails.getBrowserMajorVersion() == 7; - } - public boolean isIE8() { return isIE() && browserDetails.getBrowserMajorVersion() == 8; } @@ -230,23 +220,6 @@ public class BrowserInfo { return browserDetails.isWebKit(); } - public boolean isFF2() { - // FIXME: Should use browserVersion - return browserDetails.isFirefox() - && browserDetails.getBrowserEngineVersion() == 1.8; - } - - public boolean isFF3() { - // FIXME: Should use browserVersion - return browserDetails.isFirefox() - && browserDetails.getBrowserEngineVersion() == 1.9; - } - - public boolean isFF4() { - return browserDetails.isFirefox() - && browserDetails.getBrowserMajorVersion() == 4; - } - /** * Returns the Gecko version if the browser is Gecko based. The Gecko * version for Firefox 2 is 1.8 and 1.9 for Firefox 3. @@ -321,92 +294,22 @@ public class BrowserInfo { }-*/; /** - * Get's the timezone offset from GMT in minutes, as reported by the - * browser. DST affects this value. - * - * @return offset to GMT in minutes - */ - public native int getTimezoneOffset() - /*-{ - return new Date().getTimezoneOffset(); - }-*/; - - /** - * Gets the timezone offset from GMT in minutes, as reported by the browser - * AND adjusted to ignore daylight savings time. DST does not affect this - * value. - * - * @return offset to GMT in minutes - */ - public native int getRawTimezoneOffset() - /*-{ - var d = new Date(); - var tzo1 = d.getTimezoneOffset(); // current offset - - for (var m=12;m>0;m--) { - d.setUTCMonth(m); - var tzo2 = d.getTimezoneOffset(); - if (tzo1 != tzo2) { - // NOTE js indicates this 'backwards' (e.g -180) - return (tzo1 > tzo2 ? tzo1 : tzo2); // offset w/o DST - } - } - - return tzo1; // no DST - - }-*/; - - /** - * Gets the difference in minutes between the browser's GMT timezone and - * DST. - * - * @return the amount of minutes that the timezone shifts when DST is in - * effect - */ - public native int getDSTSavings() - /*-{ - var d = new Date(); - var tzo1 = d.getTimezoneOffset(); // current offset - - for (var m=12;m>0;m--) { - d.setUTCMonth(m); - var tzo2 = d.getTimezoneOffset(); - if (tzo1 != tzo2) { - // NOTE js indicates this 'backwards' (e.g -180) - return (tzo1 > tzo2 ? tzo1-tzo2 : tzo2-tzo1); // offset w/o DST - } - } - - return 0; // no DST - }-*/; - - /** - * Determines whether daylight savings time (DST) is currently in effect in - * the region of the browser or not. - * - * @return true if the browser resides at a location that currently is in - * DST + * @return true if the browser runs on a touch based device. */ - public boolean isDSTInEffect() { - return getTimezoneOffset() != getRawTimezoneOffset(); + public boolean isTouchDevice() { + return touchDevice; } /** - * Returns the current date and time of the browser. This will not be - * entirely accurate due to varying network latencies, but should provide a - * close-enough value for most cases. + * Indicates whether the browser might require juggling to properly update + * sizes inside elements with overflow: auto. * - * @return the current date and time of the browser. - */ - public Date getCurrentDate() { - return new Date(); - } - - /** - * @return true if the browser runs on a touch based device. + * @return <code>true</code> if the browser requires the workaround, + * otherwise <code>false</code> */ - public boolean isTouchDevice() { - return touchDevice; + public boolean requiresOverflowAutoFix() { + return (getWebkitVersion() > 0 || getOperaVersion() >= 11) + && Util.getNativeScrollbarSize() > 0; } } diff --git a/src/com/vaadin/terminal/gwt/client/ComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ComponentConnector.java new file mode 100644 index 0000000000..5f9171084e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ComponentConnector.java @@ -0,0 +1,130 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +import com.google.gwt.user.client.ui.Widget; + +/** + * An interface used by client-side widgets or paintable parts to receive + * updates from the corresponding server-side components in the form of + * {@link UIDL}. + * + * Updates can be sent back to the server using the + * {@link ApplicationConnection#updateVariable()} methods. + */ +public interface ComponentConnector extends ServerConnector { + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.VPaintable#getState() + */ + public ComponentState getState(); + + /** + * Returns the widget for this {@link ComponentConnector} + */ + public Widget getWidget(); + + public LayoutManager getLayoutManager(); + + /** + * Returns <code>true</code> if the width of this paintable is currently + * undefined. If the width is undefined, the actual width of the paintable + * is defined by its contents. + * + * @return <code>true</code> if the width is undefined, else + * <code>false</code> + */ + public boolean isUndefinedWidth(); + + /** + * Returns <code>true</code> if the height of this paintable is currently + * undefined. If the height is undefined, the actual height of the paintable + * is defined by its contents. + * + * @return <code>true</code> if the height is undefined, else + * <code>false</code> + */ + public boolean isUndefinedHeight(); + + /** + * Returns <code>true</code> if the width of this paintable is currently + * relative. If the width is relative, the actual width of the paintable is + * a percentage of the size allocated to it by its parent. + * + * @return <code>true</code> if the width is undefined, else + * <code>false</code> + */ + public boolean isRelativeWidth(); + + /** + * Returns <code>true</code> if the height of this paintable is currently + * relative. If the height is relative, the actual height of the paintable + * is a percentage of the size allocated to it by its parent. + * + * @return <code>true</code> if the width is undefined, else + * <code>false</code> + */ + public boolean isRelativeHeight(); + + /** + * Returns the parent of this connector. Can be null for only the root + * connector. + * + * @return The parent of this connector, as set by + * {@link #setParent(ComponentContainerConnector)}. + */ + public ComponentContainerConnector getParent(); + + /** + * Sets the parent for this connector. This method should only be called by + * the framework to ensure that the connector hierarchy on the client side + * and the server side are in sync. + * <p> + * Note that calling this method does not fire a + * {@link ConnectorHierarchyChangeEvent}. The event is fired only when the + * whole hierarchy has been updated. + * + * @param parent + * The new parent of the connector + */ + public void setParent(ComponentContainerConnector parent); + + /** + * Checks if the connector is read only. + * + * @deprecated This belongs in AbstractFieldConnector, see #8514 + * @return true + */ + @Deprecated + public boolean isReadOnly(); + + public boolean hasEventListener(String eventIdentifier); + + /** + * Return true if parent handles caption, false if the paintable handles the + * caption itself. + * + * <p> + * This should always return true and all components should let the parent + * handle the caption and use other attributes for internal texts in the + * component + * </p> + * + * @return true if caption handling is delegated to the parent, false if + * parent should not be allowed to render caption + */ + public boolean delegateCaptionHandling(); + + /** + * Sets the enabled state of the widget associated to this connector. + * + * @param widgetEnabled + * true if the widget should be enabled, false otherwise + */ + public void setWidgetEnabled(boolean widgetEnabled); + +} diff --git a/src/com/vaadin/terminal/gwt/client/ComponentContainerConnector.java b/src/com/vaadin/terminal/gwt/client/ComponentContainerConnector.java new file mode 100644 index 0000000000..05334e8049 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ComponentContainerConnector.java @@ -0,0 +1,74 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +import java.util.List; + +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.ui.HasWidgets; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler; + +/** + * An interface used by client-side connectors whose widget is a component + * container (implements {@link HasWidgets}). + */ +public interface ComponentContainerConnector extends ComponentConnector { + + /** + * Update child components caption, description and error message. + * + * <p> + * Each component is responsible for maintaining its caption, description + * and error message. In most cases components doesn't want to do that and + * those elements reside outside of the component. Because of this layouts + * must provide service for it's childen to show those elements for them. + * </p> + * + * @param connector + * Child component for which service is requested. + */ + void updateCaption(ComponentConnector connector); + + /** + * Returns the children for this connector. + * <p> + * The children for this connector are defined as all + * {@link ComponentConnector}s whose parent is this + * {@link ComponentContainerConnector}. + * </p> + * + * @return A collection of children for this connector. An empty collection + * if there are no children. Never returns null. + */ + public List<ComponentConnector> getChildren(); + + /** + * Sets the children for this connector. This method should only be called + * by the framework to ensure that the connector hierarchy on the client + * side and the server side are in sync. + * <p> + * Note that calling this method does not call + * {@link #connectorHierarchyChanged(ConnectorHierarchyChangeEvent)}. The + * event method is called only when the hierarchy has been updated for all + * connectors. + * + * @param children + * The new child connectors + */ + public void setChildren(List<ComponentConnector> children); + + /** + * Adds a handler that is called whenever the child hierarchy of this + * connector has been updated by the server. + * + * @param handler + * The handler that should be added. + * @return A handler registration reference that can be used to unregister + * the handler + */ + public HandlerRegistration addConnectorHierarchyChangeHandler( + ConnectorHierarchyChangeHandler handler); + +} diff --git a/src/com/vaadin/terminal/gwt/client/ComponentDetail.java b/src/com/vaadin/terminal/gwt/client/ComponentDetail.java index 7fc93b2a3e..686cb640a4 100644 --- a/src/com/vaadin/terminal/gwt/client/ComponentDetail.java +++ b/src/com/vaadin/terminal/gwt/client/ComponentDetail.java @@ -5,20 +5,12 @@ package com.vaadin.terminal.gwt.client; import java.util.HashMap; -import com.google.gwt.core.client.JsArrayString; -import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize; -import com.vaadin.terminal.gwt.client.RenderInformation.Size; - class ComponentDetail { - private Paintable component; private TooltipInfo tooltipInfo = new TooltipInfo(); - private String pid; - public ComponentDetail(ApplicationConnection client, String pid, - Paintable component) { - this.component = component; - this.pid = pid; + public ComponentDetail() { + } /** @@ -48,54 +40,8 @@ class ComponentDetail { this.tooltipInfo = tooltipInfo; } - private FloatSize relativeSize; - private Size offsetSize; private HashMap<Object, TooltipInfo> additionalTooltips; - /** - * @return the pid - */ - String getPid() { - return pid; - } - - /** - * @return the component - */ - Paintable getComponent() { - return component; - } - - /** - * @return the relativeSize - */ - FloatSize getRelativeSize() { - return relativeSize; - } - - /** - * @param relativeSize - * the relativeSize to set - */ - void setRelativeSize(FloatSize relativeSize) { - this.relativeSize = relativeSize; - } - - /** - * @return the offsetSize - */ - Size getOffsetSize() { - return offsetSize; - } - - /** - * @param offsetSize - * the offsetSize to set - */ - void setOffsetSize(Size offsetSize) { - this.offsetSize = offsetSize; - } - public void putAdditionalTooltip(Object key, TooltipInfo tooltip) { if (tooltip == null && additionalTooltips != null) { additionalTooltips.remove(key); @@ -107,38 +53,4 @@ class ComponentDetail { } } - private JsArrayString eventListeners; - - /** - * Stores the event listeners registered on server-side and passed along in - * the UIDL. - * - * @param componentUIDL - * The UIDL for the component - * @since 6.2 - */ - native void registerEventListenersFromUIDL(UIDL uidl) - /*-{ - this.@com.vaadin.terminal.gwt.client.ComponentDetail::eventListeners = uidl[1].eventListeners; - }-*/; - - /** - * Checks if there is a registered server side listener for the event. - * - * @param eventIdentifier - * The identifier for the event - * @return true if at least one listener has been registered on server side - * for the event identified by eventIdentifier. - */ - public boolean hasEventListeners(String eventIdentifier) { - if (eventListeners != null) { - int l = eventListeners.length(); - for (int i = 0; i < l; i++) { - if (eventListeners.get(i).equals(eventIdentifier)) { - return true; - } - } - } - return false; - } } diff --git a/src/com/vaadin/terminal/gwt/client/ComponentLocator.java b/src/com/vaadin/terminal/gwt/client/ComponentLocator.java index b71b5fdeb5..d847d49e6f 100644 --- a/src/com/vaadin/terminal/gwt/client/ComponentLocator.java +++ b/src/com/vaadin/terminal/gwt/client/ComponentLocator.java @@ -5,6 +5,7 @@ package com.vaadin.terminal.gwt.client; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -12,8 +13,12 @@ import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ui.SubPartAware; -import com.vaadin.terminal.gwt.client.ui.VView; -import com.vaadin.terminal.gwt.client.ui.VWindow; +import com.vaadin.terminal.gwt.client.ui.gridlayout.VGridLayout; +import com.vaadin.terminal.gwt.client.ui.orderedlayout.VMeasuringOrderedLayout; +import com.vaadin.terminal.gwt.client.ui.root.VRoot; +import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheetPanel; +import com.vaadin.terminal.gwt.client.ui.window.VWindow; +import com.vaadin.terminal.gwt.client.ui.window.WindowConnector; /** * ComponentLocator provides methods for generating a String locator for a given @@ -78,7 +83,7 @@ public class ComponentLocator { Element e = targetElement; while (true) { - pid = client.getPid(e); + pid = ConnectorMap.get(client).getConnectorId(e); if (pid != null) { break; } @@ -94,7 +99,8 @@ public class ComponentLocator { // If we found a Paintable then we use that as reference. We should // find the Paintable for all but very special cases (like // overlays). - w = (Widget) client.getPaintable(pid); + w = ((ComponentConnector) ConnectorMap.get(client) + .getConnector(pid)).getWidget(); /* * Still if the Paintable contains a widget that implements @@ -364,18 +370,14 @@ public class ComponentLocator { return null; } - String pid = client.getPid(w.getElement()); - if (isStaticPid(pid)) { - return pid; - } - - if (w instanceof VView) { + if (w instanceof VRoot) { return ""; } else if (w instanceof VWindow) { - VWindow win = (VWindow) w; - ArrayList<VWindow> subWindowList = client.getView() - .getSubWindowList(); - int indexOfSubWindow = subWindowList.indexOf(win); + Connector windowConnector = ConnectorMap.get(client) + .getConnector(w); + List<WindowConnector> subWindowList = client.getRootConnector() + .getSubWindows(); + int indexOfSubWindow = subWindowList.indexOf(windowConnector); return PARENTCHILD_SEPARATOR + "VWindow[" + indexOfSubWindow + "]"; } else if (w instanceof RootPanel) { return ROOT_ID; @@ -434,10 +436,25 @@ public class ComponentLocator { if (part.equals(ROOT_ID)) { w = RootPanel.get(); } else if (part.equals("")) { - w = client.getView(); + w = client.getRootConnector().getWidget(); } else if (w == null) { - // Must be static pid (PID_*) - w = (Widget) client.getPaintable(part); + String id = part; + // Must be old static pid (PID_S*) + ComponentConnector connector = (ComponentConnector) ConnectorMap + .get(client).getConnector(id); + if (connector == null) { + // Lookup by debugId + // TODO Optimize this + connector = findConnectorById(client.getRootConnector(), + id.substring(5)); + } + + if (connector != null) { + w = connector.getWidget(); + } else { + // Not found + return null; + } } else if (part.startsWith("domChild[")) { // The target widget has been found and the rest identifies the // element @@ -455,6 +472,67 @@ public class ComponentLocator { int widgetPosition = Integer.parseInt(indexString.substring(0, indexString.length() - 1)); + // AbsolutePanel in GridLayout has been removed -> skip it + if (w instanceof VGridLayout + && "AbsolutePanel".equals(widgetClassName)) { + continue; + } + + if (w instanceof VTabsheetPanel && widgetPosition != 0) { + // TabSheetPanel now only contains 1 connector => the index + // is always 0 which indicates the widget in the active tab + widgetPosition = 0; + } + + /* + * The new grid and ordered layotus do not contain + * ChildComponentContainer widgets. This is instead simulated by + * constructing a path step that would find the desired widget + * from the layout and injecting it as the next search step + * (which would originally have found the widget inside the + * ChildComponentContainer) + */ + if ((w instanceof VMeasuringOrderedLayout || w instanceof VGridLayout) + && "ChildComponentContainer".equals(widgetClassName) + && i + 1 < parts.length) { + + HasWidgets layout = (HasWidgets) w; + + String nextPart = parts[i + 1]; + String[] nextSplit = nextPart.split("\\[", 2); + String nextWidgetClassName = nextSplit[0]; + + // Find the n:th child and count the number of children with + // the same type before it + int nextIndex = 0; + for (Widget child : layout) { + boolean matchingType = nextWidgetClassName.equals(Util + .getSimpleName(child)); + if (matchingType && widgetPosition == 0) { + // This is the n:th child that we looked for + break; + } else if (widgetPosition < 0) { + // Error if we're past the desired position without + // a match + return null; + } else if (matchingType) { + // If this was another child of the expected type, + // increase the count for the next step + nextIndex++; + } + + // Don't count captions + if (!(child instanceof VCaption)) { + widgetPosition--; + } + } + + // Advance to the next step, this time checking for the + // actual child widget + parts[i + 1] = nextWidgetClassName + '[' + nextIndex + ']'; + continue; + } + // Locate the child Iterator<? extends Widget> iterator; @@ -463,7 +541,14 @@ public class ComponentLocator { * compatibility */ if (widgetClassName.equals("VWindow")) { - iterator = client.getView().getSubWindowList().iterator(); + List<WindowConnector> windows = client.getRootConnector() + .getSubWindows(); + List<VWindow> windowWidgets = new ArrayList<VWindow>( + windows.size()); + for (WindowConnector wc : windows) { + windowWidgets.add(wc.getWidget()); + } + iterator = windowWidgets.iterator(); } else if (widgetClassName.equals("VContextMenu")) { return client.getContextMenu(); } else { @@ -503,19 +588,23 @@ public class ComponentLocator { return w; } - /** - * Checks if the given pid is a static pid. - * - * @param pid - * The pid to check - * @return true if the pid is a static pid, false otherwise - */ - private boolean isStaticPid(String pid) { - if (pid == null) { - return false; + private ComponentConnector findConnectorById(ComponentConnector root, + String id) { + if (root instanceof ComponentConnector + && id.equals(root.getState().getDebugId())) { + return root; + } + if (root instanceof ComponentContainerConnector) { + ComponentContainerConnector ccc = (ComponentContainerConnector) root; + for (ComponentConnector child : ccc.getChildren()) { + ComponentConnector found = findConnectorById(child, id); + if (found != null) { + return found; + } + } } - return pid.startsWith("PID_"); + return null; } } diff --git a/src/com/vaadin/terminal/gwt/client/ComponentState.java b/src/com/vaadin/terminal/gwt/client/ComponentState.java new file mode 100644 index 0000000000..10cd14251b --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ComponentState.java @@ -0,0 +1,406 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.client.communication.URLReference; +import com.vaadin.ui.Component; + +/** + * Default shared state implementation for UI components. + * + * State classes of concrete components should extend this class. + * + * @since 7.0 + */ +public class ComponentState extends SharedState { + private String height = ""; + private String width = ""; + private boolean readOnly = false; + private boolean immediate = false; + private boolean enabled = true; + private String description = ""; + // Note: for the caption, there is a difference between null and an empty + // string! + private String caption = null; + private boolean visible = true; + private URLReference icon = null; + private List<String> styles = null; + private String debugId = null; + /** + * A set of event identifiers with registered listeners. + */ + private Set<String> registeredEventListeners = null; + + // HTML formatted error message for the component + // TODO this could be an object with more information, but currently the UI + // only uses the message + private String errorMessage = null; + + /** + * Returns the component height as set by the server. + * + * Can be relative (containing the percent sign) or absolute, or empty + * string for undefined height. + * + * @return component height as defined by the server, not null + */ + public String getHeight() { + if (height == null) { + return ""; + } + return height; + } + + /** + * Sets the height of the component in the server format. + * + * Can be relative (containing the percent sign) or absolute, or null or + * empty string for undefined height. + * + * @param height + * component height + */ + public void setHeight(String height) { + this.height = height; + } + + /** + * Returns true if the component height is undefined, false if defined + * (absolute or relative). + * + * @return true if component height is undefined + */ + public boolean isUndefinedHeight() { + return "".equals(getHeight()); + } + + /** + * Returns the component width as set by the server. + * + * Can be relative (containing the percent sign) or absolute, or empty + * string for undefined height. + * + * @return component width as defined by the server, not null + */ + public String getWidth() { + if (width == null) { + return ""; + } + return width; + } + + /** + * Sets the width of the component in the server format. + * + * Can be relative (containing the percent sign) or absolute, or null or + * empty string for undefined width. + * + * @param width + * component width + */ + public void setWidth(String width) { + this.width = width; + } + + /** + * Returns true if the component width is undefined, false if defined + * (absolute or relative). + * + * @return true if component width is undefined + */ + public boolean isUndefinedWidth() { + return "".equals(getWidth()); + } + + /** + * Returns true if the component is in read-only mode. + * + * @see com.vaadin.ui.Component#isReadOnly() + * + * @return true if the component is in read-only mode + */ + public boolean isReadOnly() { + return readOnly; + } + + /** + * Sets or resets the read-only mode for a component. + * + * @see com.vaadin.ui.Component#setReadOnly() + * + * @param readOnly + * new mode for the component + */ + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + /** + * Returns true if the component is in immediate mode. + * + * @see com.vaadin.terminal.VariableOwner#isImmediate() + * + * @return true if the component is in immediate mode + */ + public boolean isImmediate() { + return immediate; + } + + /** + * Sets or resets the immediate mode for a component. + * + * @see com.vaadin.terminal.VariableOwner#setImmediate() + * + * @param immediate + * new mode for the component + */ + public void setImmediate(boolean immediate) { + this.immediate = immediate; + } + + /** + * Returns true if the component has user-defined styles. + * + * @return true if the component has user-defined styles + */ + public boolean hasStyles() { + return styles != null && !styles.isEmpty(); + } + + /** + * Returns true if the component is enabled. + * + * @see com.vaadin.ui.Component#isEnabled() + * + * @return true if the component is enabled + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Enables or disables the component. + * + * @see com.vaadin.ui.Component#setEnabled(boolean) + * + * @param enabled + * new mode for the component + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * Gets the description of the component (typically shown as tooltip). + * + * @see com.vaadin.ui.AbstractComponent#getDescription() + * + * @return component description (not null, can be empty string) + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of the component (typically shown as tooltip). + * + * @see com.vaadin.ui.AbstractComponent#setDescription(String) + * + * @param description + * new component description (can be null) + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Returns true if the component has a description. + * + * @return true if the component has a description + */ + public boolean hasDescription() { + return getDescription() != null && !"".equals(getDescription()); + } + + /** + * Gets the caption of the component (typically shown by the containing + * layout). + * + * @see com.vaadin.ui.Component#getCaption() + * + * @return component caption - can be null (no caption) or empty string + * (reserve space for an empty caption) + */ + public String getCaption() { + return caption; + } + + /** + * Sets the caption of the component (typically shown by the containing + * layout). + * + * @see com.vaadin.ui.Component#setCaption(String) + * + * @param caption + * new component caption - can be null (no caption) or empty + * string (reserve space for an empty caption) + */ + public void setCaption(String caption) { + this.caption = caption; + } + + /** + * Returns the visibility state of the component. Note that this state is + * related to the component only, not its parent. This might differ from + * what {@link Component#isVisible()} returns as this takes the hierarchy + * into account. + * + * @return The visibility state. + */ + public boolean isVisible() { + return visible; + } + + /** + * Sets the visibility state of the component. + * + * @param visible + * The new visibility state. + */ + public void setVisible(boolean visible) { + this.visible = visible; + } + + public URLReference getIcon() { + return icon; + } + + public void setIcon(URLReference icon) { + this.icon = icon; + } + + /** + * Gets the style names for the component. + * + * @return A List of style names or null if no styles have been set. + */ + public List<String> getStyles() { + return styles; + } + + /** + * Sets the style names for the component. + * + * @param styles + * A list containing style names + */ + public void setStyles(List<String> styles) { + this.styles = styles; + } + + /** + * Gets the debug id for the component. The debugId is added as DOM id for + * the component. + * + * @return The debug id for the component or null if not set + */ + public String getDebugId() { + return debugId; + } + + /** + * Sets the debug id for the component. The debugId is added as DOM id for + * the component. + * + * @param debugId + * The new debugId for the component or null for no debug id + * + */ + public void setDebugId(String debugId) { + this.debugId = debugId; + } + + /** + * Gets the identifiers for the event listeners that have been registered + * for the component (using an event id) + * + * @return A set of event identifiers or null if no identifiers have been + * registered + */ + public Set<String> getRegisteredEventListeners() { + return registeredEventListeners; + } + + /** + * Sets the identifiers for the event listeners that have been registered + * for the component (using an event id) + * + * @param registeredEventListeners + * The new set of identifiers or null if no identifiers have been + * registered + */ + public void setRegisteredEventListeners(Set<String> registeredEventListeners) { + this.registeredEventListeners = registeredEventListeners; + } + + /** + * Adds an event listener id. + * + * @param eventListenerId + * The event identifier to add + */ + public void addRegisteredEventListener(String eventListenerId) { + if (registeredEventListeners == null) { + registeredEventListeners = new HashSet<String>(); + } + registeredEventListeners.add(eventListenerId); + + } + + /** + * Removes an event listener id. + * + * @param eventListenerId + * The event identifier to remove + */ + public void removeRegisteredEventListener(String eventIdentifier) { + if (registeredEventListeners == null) { + return; + } + registeredEventListeners.remove(eventIdentifier); + if (registeredEventListeners.size() == 0) { + registeredEventListeners = null; + } + } + + /** + * Returns the current error message for the component. + * + * @return HTML formatted error message to show for the component or null if + * none + */ + public String getErrorMessage() { + return errorMessage; + } + + /** + * Sets the current error message for the component. + * + * TODO this could use an object with more details about the error + * + * @param errorMessage + * HTML formatted error message to show for the component or null + * for none + */ + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ComputedStyle.java b/src/com/vaadin/terminal/gwt/client/ComputedStyle.java index e994e47d63..bedb217c63 100644 --- a/src/com/vaadin/terminal/gwt/client/ComputedStyle.java +++ b/src/com/vaadin/terminal/gwt/client/ComputedStyle.java @@ -4,7 +4,7 @@ package com.vaadin.terminal.gwt.client; import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.user.client.Element; +import com.google.gwt.dom.client.Element; public class ComputedStyle { diff --git a/src/com/vaadin/terminal/gwt/client/Connector.java b/src/com/vaadin/terminal/gwt/client/Connector.java new file mode 100644 index 0000000000..1c61052735 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/Connector.java @@ -0,0 +1,49 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import java.io.Serializable; + +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.server.ClientConnector; + +/** + * Interface implemented by all classes that are capable of communicating with + * the server or the client side. + * <p> + * A connector consists of a shared state (server sets the state and + * automatically communicates changes to the client) and the possibility to do + * RPC calls either from the server to the client or from the client to the + * server. + * </p> + * <p> + * No classes should implement this interface directly, client side classes + * wanting to communicate with server side should implement + * {@link ServerConnector} and server side classes should implement + * {@link ClientConnector}. + * </p> + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + */ +public interface Connector extends Serializable { + /** + * Gets the current shared state of the connector. + * + * @since 7.0. + * @return state The shared state object. Can be any sub type of + * {@link SharedState}. Never null. + */ + public SharedState getState(); + + /** + * Returns the id for this connector. This is set by the framework and does + * not change during the lifetime of a connector. + * + * @return The id for the connector. + */ + public String getConnectorId(); + +} diff --git a/src/com/vaadin/terminal/gwt/client/ConnectorHierarchyChangeEvent.java b/src/com/vaadin/terminal/gwt/client/ConnectorHierarchyChangeEvent.java new file mode 100644 index 0000000000..aa41caf75d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ConnectorHierarchyChangeEvent.java @@ -0,0 +1,97 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import java.io.Serializable; +import java.util.List; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler; +import com.vaadin.terminal.gwt.client.communication.AbstractServerConnectorEvent; + +/** + * Event for containing data related to a change in the {@link ServerConnector} + * hierarchy. A {@link ConnectorHierarchyChangedEvent} is fired when an update + * from the server has been fully processed and all hierarchy updates have been + * completed. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public class ConnectorHierarchyChangeEvent extends + AbstractServerConnectorEvent<ConnectorHierarchyChangeHandler> { + /** + * Type of this event, used by the event bus. + */ + public static final Type<ConnectorHierarchyChangeHandler> TYPE = new Type<ConnectorHierarchyChangeHandler>(); + + List<ComponentConnector> oldChildren; + private ComponentContainerConnector parent; + + public ConnectorHierarchyChangeEvent() { + } + + /** + * Returns a collection of the old children for the connector. This was the + * state before the update was received from the server. + * + * @return A collection of old child connectors. Never returns null. + */ + public List<ComponentConnector> getOldChildren() { + return oldChildren; + } + + /** + * Sets the collection of the old children for the connector. + * + * @param oldChildren + * The old child connectors. Must not be null. + */ + public void setOldChildren(List<ComponentConnector> oldChildren) { + this.oldChildren = oldChildren; + } + + /** + * Returns the {@link ComponentContainerConnector} for which this event + * occurred. + * + * @return The {@link ComponentContainerConnector} whose child collection + * has changed. Never returns null. + */ + public ComponentContainerConnector getParent() { + return parent; + } + + /** + * Sets the {@link ComponentContainerConnector} for which this event + * occurred. + * + * @param The + * {@link ComponentContainerConnector} whose child collection has + * changed. + */ + public void setParent(ComponentContainerConnector parent) { + this.parent = parent; + } + + public interface ConnectorHierarchyChangeHandler extends Serializable, + EventHandler { + public void onConnectorHierarchyChange( + ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent); + } + + @Override + public void dispatch(ConnectorHierarchyChangeHandler handler) { + handler.onConnectorHierarchyChange(this); + } + + @Override + public GwtEvent.Type<ConnectorHierarchyChangeHandler> getAssociatedType() { + return TYPE; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ConnectorMap.java b/src/com/vaadin/terminal/gwt/client/ConnectorMap.java new file mode 100644 index 0000000000..e57776cf1c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ConnectorMap.java @@ -0,0 +1,250 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.ui.Widget; + +public class ConnectorMap { + + private Map<String, ServerConnector> idToConnector = new HashMap<String, ServerConnector>(); + + public static ConnectorMap get(ApplicationConnection applicationConnection) { + return applicationConnection.getConnectorMap(); + } + + @Deprecated + private final ComponentDetailMap idToComponentDetail = ComponentDetailMap + .create(); + + /** + * Returns a {@link ServerConnector} by its id + * + * @param id + * The connector id + * @return A connector or null if a connector with the given id has not been + * registered + */ + public ServerConnector getConnector(String connectorId) { + return idToConnector.get(connectorId); + } + + /** + * Returns a {@link ComponentConnector} element by its root element + * + * @param element + * Root element of the {@link ComponentConnector} + * @return A connector or null if a connector with the given id has not been + * registered + */ + public ComponentConnector getConnector(Element element) { + return (ComponentConnector) getConnector(getConnectorId(element)); + } + + /** + * FIXME: What does this even do and why? + * + * @param pid + * @return + */ + public boolean isDragAndDropPaintable(String pid) { + return (pid.startsWith("DD")); + } + + /** + * Checks if a connector with the given id has been registered. + * + * @param connectorId + * The id to check for + * @return true if a connector has been registered with the given id, false + * otherwise + */ + public boolean hasConnector(String connectorId) { + return idToConnector.containsKey(connectorId); + } + + /** + * Removes all registered connectors + */ + public void clear() { + idToConnector.clear(); + idToComponentDetail.clear(); + } + + /** + * Retrieves the connector whose widget matches the parameter. + * + * @param widget + * The widget + * @return A connector with {@literal widget} as its root widget or null if + * no connector was found + */ + public ComponentConnector getConnector(Widget widget) { + return getConnector(widget.getElement()); + } + + public void registerConnector(String id, ServerConnector connector) { + ComponentDetail componentDetail = GWT.create(ComponentDetail.class); + idToComponentDetail.put(id, componentDetail); + idToConnector.put(id, connector); + if (connector instanceof ComponentConnector) { + ComponentConnector pw = (ComponentConnector) connector; + setConnectorId(pw.getWidget().getElement(), id); + } + } + + private native void setConnectorId(Element el, String id) + /*-{ + el.tkPid = id; + }-*/; + + /** + * Gets the connector id using a DOM element - the element should be the + * root element for a connector, otherwise no id will be found. Use + * {@link #getConnectorId(ServerConnector)} instead whenever possible. + * + * @see #getConnectorId(ServerConnector) + * @param el + * element of the connector whose id is desired + * @return the id of the element's connector, if it's a connector + */ + native String getConnectorId(Element el) + /*-{ + return el.tkPid; + }-*/; + + /** + * Gets the main element for the connector with the given id. The reverse of + * {@link #getConnectorId(Element)}. + * + * @param connectorId + * the id of the widget whose element is desired + * @return the element for the connector corresponding to the id + */ + public Element getElement(String connectorId) { + ServerConnector p = getConnector(connectorId); + if (p instanceof ComponentConnector) { + return ((ComponentConnector) p).getWidget().getElement(); + } + + return null; + } + + /** + * Unregisters the given connector; always use after removing a connector. + * This method does not remove the connector from the DOM, but marks the + * connector so that ApplicationConnection may clean up its references to + * it. Removing the widget from DOM is component containers responsibility. + * + * @param connector + * the connector to remove + */ + public void unregisterConnector(ServerConnector connector) { + if (connector == null) { + VConsole.error("Trying to unregister null connector"); + return; + } + + String connectorId = connector.getConnectorId(); + + idToComponentDetail.remove(connectorId); + idToConnector.remove(connectorId); + connector.onUnregister(); + + if (connector instanceof ComponentContainerConnector) { + for (ComponentConnector child : ((ComponentContainerConnector) connector) + .getChildren()) { + if (child.getParent() == connector) { + // Only unregister children that are actually connected to + // this parent. For instance when moving connectors from one + // layout to another and removing the first layout it will + // still contain references to its old children, which are + // now attached to another connector. + unregisterConnector(child); + } + } + } + } + + /** + * Gets all registered {@link ComponentConnector} instances + * + * @return An array of all registered {@link ComponentConnector} instances + */ + public ComponentConnector[] getComponentConnectors() { + ArrayList<ComponentConnector> result = new ArrayList<ComponentConnector>(); + + for (ServerConnector connector : getConnectors()) { + if (connector instanceof ComponentConnector) { + result.add((ComponentConnector) connector); + } + } + + return result.toArray(new ComponentConnector[result.size()]); + } + + @Deprecated + private ComponentDetail getComponentDetail( + ComponentConnector componentConnector) { + return idToComponentDetail.get(componentConnector.getConnectorId()); + } + + public int size() { + return idToConnector.size(); + } + + /** + * FIXME: Should be moved to VAbstractPaintableWidget + * + * @param paintable + * @return + */ + @Deprecated + public TooltipInfo getTooltipInfo(ComponentConnector paintable, Object key) { + return getComponentDetail(paintable).getTooltipInfo(key); + } + + @Deprecated + public TooltipInfo getWidgetTooltipInfo(Widget widget, Object key) { + return getTooltipInfo(getConnector(widget), key); + } + + public Collection<? extends ServerConnector> getConnectors() { + return Collections.unmodifiableCollection(idToConnector.values()); + } + + /** + * FIXME: Should not be here + * + * @param componentConnector + * @return + */ + @Deprecated + public void registerTooltip(ComponentConnector componentConnector, + Object key, TooltipInfo tooltip) { + getComponentDetail(componentConnector).putAdditionalTooltip(key, + tooltip); + + } + + /** + * Tests if the widget is the root widget of a {@link ComponentConnector}. + * + * @param widget + * The widget to test + * @return true if the widget is the root widget of a + * {@link ComponentConnector}, false otherwise + */ + public boolean isConnector(Widget w) { + return getConnectorId(w.getElement()) != null; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/Console.java b/src/com/vaadin/terminal/gwt/client/Console.java index 483ab8e0fd..8db145342a 100644 --- a/src/com/vaadin/terminal/gwt/client/Console.java +++ b/src/com/vaadin/terminal/gwt/client/Console.java @@ -22,8 +22,8 @@ public interface Console { public abstract void printLayoutProblems(ValueMap meta, ApplicationConnection applicationConnection, - Set<Paintable> zeroHeightComponents, - Set<Paintable> zeroWidthComponents); + Set<ComponentConnector> zeroHeightComponents, + Set<ComponentConnector> zeroWidthComponents); public abstract void setQuietMode(boolean quietDebugMode); diff --git a/src/com/vaadin/terminal/gwt/client/Container.java b/src/com/vaadin/terminal/gwt/client/Container.java deleted file mode 100644 index 83f104886f..0000000000 --- a/src/com/vaadin/terminal/gwt/client/Container.java +++ /dev/null @@ -1,71 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client; - -import java.util.Set; - -import com.google.gwt.user.client.ui.Widget; - -public interface Container extends Paintable { - - /** - * Replace child of this layout with another component. - * - * Each layout must be able to switch children. To to this, one must just - * give references to a current and new child. - * - * @param oldComponent - * Child to be replaced - * @param newComponent - * Child that replaces the oldComponent - */ - void replaceChildComponent(Widget oldComponent, Widget newComponent); - - /** - * Is a given component child of this layout. - * - * @param component - * Component to test. - * @return true iff component is a child of this layout. - */ - boolean hasChildComponent(Widget component); - - /** - * Update child components caption, description and error message. - * - * <p> - * Each component is responsible for maintaining its caption, description - * and error message. In most cases components doesn't want to do that and - * those elements reside outside of the component. Because of this layouts - * must provide service for it's childen to show those elements for them. - * </p> - * - * @param component - * Child component for which service is requested. - * @param uidl - * UIDL of the child component. - */ - void updateCaption(Paintable component, UIDL uidl); - - /** - * Called when a child components size has been updated in the rendering - * phase. - * - * @param children - * Set of child widgets whose size have changed - * @return true if the size of the Container remains the same, false if the - * event need to be propagated to the Containers parent - */ - boolean requestLayout(Set<Paintable> children); - - /** - * Returns the size currently allocated for the child component. - * - * @param child - * @return - */ - RenderSpace getAllocatedSpace(Widget child); - -} diff --git a/src/com/vaadin/terminal/gwt/client/DateTimeService.java b/src/com/vaadin/terminal/gwt/client/DateTimeService.java index c0151d2819..45ba4a7452 100644 --- a/src/com/vaadin/terminal/gwt/client/DateTimeService.java +++ b/src/com/vaadin/terminal/gwt/client/DateTimeService.java @@ -8,7 +8,7 @@ import java.util.Date; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.LocaleInfo; -import com.vaadin.terminal.gwt.client.ui.VDateField; +import com.vaadin.terminal.gwt.client.ui.datefield.VDateField; /** * This class provides date/time parsing services to all components on the diff --git a/src/com/vaadin/terminal/gwt/client/DirectionalManagedLayout.java b/src/com/vaadin/terminal/gwt/client/DirectionalManagedLayout.java new file mode 100644 index 0000000000..296fbb22ff --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/DirectionalManagedLayout.java @@ -0,0 +1,12 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.vaadin.terminal.gwt.client.ui.ManagedLayout; + +public interface DirectionalManagedLayout extends ManagedLayout { + public void layoutVertically(); + + public void layoutHorizontally(); +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/EventHelper.java b/src/com/vaadin/terminal/gwt/client/EventHelper.java index 600baf8c9d..95f5125f1b 100644 --- a/src/com/vaadin/terminal/gwt/client/EventHelper.java +++ b/src/com/vaadin/terminal/gwt/client/EventHelper.java @@ -6,10 +6,12 @@ package com.vaadin.terminal.gwt.client; import static com.vaadin.terminal.gwt.client.EventId.BLUR; import static com.vaadin.terminal.gwt.client.EventId.FOCUS; +import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.DomEvent.Type; +import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.dom.client.HasBlurHandlers; -import com.google.gwt.event.dom.client.HasFocusHandlers; +import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; /** @@ -40,38 +42,56 @@ import com.google.gwt.event.shared.HandlerRegistration; */ public class EventHelper { - public static HandlerRegistration updateFocusHandler(Paintable paintable, - ApplicationConnection client, - HandlerRegistration handlerRegistration) { - if (client.hasEventListeners(paintable, FOCUS)) { - if (handlerRegistration == null) { - handlerRegistration = ((HasFocusHandlers) paintable) - .addFocusHandler((FocusHandler) paintable); - } - return handlerRegistration; - } else if (handlerRegistration != null) { - handlerRegistration.removeHandler(); - handlerRegistration = null; + /** + * Adds or removes a focus handler depending on if the connector has focus + * listeners on the server side or not. + * + * @param connector + * The connector to update. Must implement focusHandler. + * @param handlerRegistration + * The old registration reference or null no handler has been + * registered previously + * @return a new registration handler that can be used to unregister the + * handler later + */ + public static <T extends ComponentConnector & FocusHandler> HandlerRegistration updateFocusHandler( + T connector, HandlerRegistration handlerRegistration) { + return updateHandler(connector, FOCUS, handlerRegistration, + FocusEvent.getType()); + } - } - return null; + /** + * Adds or removes a blur handler depending on if the connector has blur + * listeners on the server side or not. + * + * @param connector + * The connector to update. Must implement BlurHandler. + * @param handlerRegistration + * The old registration reference or null no handler has been + * registered previously + * @return a new registration handler that can be used to unregister the + * handler later + */ + public static <T extends ComponentConnector & BlurHandler> HandlerRegistration updateBlurHandler( + T connector, HandlerRegistration handlerRegistration) { + return updateHandler(connector, BLUR, handlerRegistration, + BlurEvent.getType()); } - public static HandlerRegistration updateBlurHandler(Paintable paintable, - ApplicationConnection client, - HandlerRegistration handlerRegistration) { - if (client.hasEventListeners(paintable, BLUR)) { + private static <H extends EventHandler> HandlerRegistration updateHandler( + ComponentConnector connector, String eventIdentifier, + HandlerRegistration handlerRegistration, Type<H> type) { + if (connector.hasEventListener(eventIdentifier)) { if (handlerRegistration == null) { - handlerRegistration = ((HasBlurHandlers) paintable) - .addBlurHandler((BlurHandler) paintable); + handlerRegistration = connector.getWidget().addDomHandler( + (H) connector, type); } - return handlerRegistration; } else if (handlerRegistration != null) { handlerRegistration.removeHandler(); handlerRegistration = null; - } - return null; + return handlerRegistration; + } } diff --git a/src/com/vaadin/terminal/gwt/client/EventId.java b/src/com/vaadin/terminal/gwt/client/EventId.java index ae2f5ddeb3..d3ef2e4e7e 100644 --- a/src/com/vaadin/terminal/gwt/client/EventId.java +++ b/src/com/vaadin/terminal/gwt/client/EventId.java @@ -6,5 +6,4 @@ package com.vaadin.terminal.gwt.client; public interface EventId { public static final String BLUR = "blur"; public static final String FOCUS = "focus"; - public static final String LAYOUT_CLICK = "layout_click"; } diff --git a/src/com/vaadin/terminal/gwt/client/FastStringSet.java b/src/com/vaadin/terminal/gwt/client/FastStringSet.java new file mode 100644 index 0000000000..05ed8addc8 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/FastStringSet.java @@ -0,0 +1,60 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArrayString; + +public final class FastStringSet extends JavaScriptObject { + protected FastStringSet() { + // JSO constructor + } + + public native boolean contains(String string) + /*-{ + return this.hasOwnProperty(string); + }-*/; + + public native void add(String string) + /*-{ + this[string] = true; + }-*/; + + public native void addAll(JsArrayString array) + /*-{ + for(var i = 0; i < array.length; i++) { + this[array[i]] = true; + } + }-*/; + + public native JsArrayString dump() + /*-{ + var array = []; + for(var string in this) { + if (this.hasOwnProperty(string)) { + array.push(string); + } + } + return array; + }-*/; + + public native void remove(String string) + /*-{ + delete this[string]; + }-*/; + + public native boolean isEmpty() + /*-{ + for(var string in this) { + if (this.hasOwnProperty(string)) { + return false; + } + } + return true; + }-*/; + + public static FastStringSet create() { + return JavaScriptObject.createObject().cast(); + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java b/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java deleted file mode 100644 index 0571959339..0000000000 --- a/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java +++ /dev/null @@ -1,192 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.terminal.gwt.client; - -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.impl.HistoryImpl; - -/** - * A slightly modified version of GWT's HistoryImplIE6 to bypass bug #2931. Also - * combined with HistoryImplFrame. - * - * This class should be removed if GWT issue 3890 gets resolved. (Also remember - * to removed deferred binding rule from .gwt.xml file). - */ -public class HistoryImplIEVaadin extends HistoryImpl { - - private static native Element findHistoryFrame() - /*-{ - return $doc.getElementById('__gwt_historyFrame'); - }-*/; - - private static native Element getTokenElement(Element historyFrame) - /*-{ - // Initialize the history iframe. If '__gwt_historyToken' already exists, then - // we're probably backing into the app, so _don't_ set the iframe's location. - if (historyFrame.contentWindow) { - var doc = historyFrame.contentWindow.document; - return doc.getElementById('__gwt_historyToken'); - } - }-*/; - - protected Element historyFrame; - - @Override - protected final void nativeUpdate(String historyToken) { - /* - * Must update the location hash since it isn't already correct. - */ - updateHash(historyToken); - navigateFrame(historyToken); - } - - @Override - protected final void nativeUpdateOnEvent(String historyToken) { - updateHash(historyToken); - } - - /** - * Sanitizes an untrusted string to be used in an HTML context. NOTE: This - * method of escaping strings should only be used on Internet Explorer. - * - * @param maybeHtml - * untrusted string that may contain html - * @return sanitized string - */ - private static String escapeHtml(String maybeHtml) { - final Element div = DOM.createDiv(); - DOM.setInnerText(div, maybeHtml); - return DOM.getInnerHTML(div); - } - - /** - * For IE6, reading from $wnd.location.hash drops part of the fragment if - * the fragment contains a '?'. To avoid this bug, we use location.href - * instead. - */ - private static native String getLocationHash() - /*-{ - var href = $wnd.location.href; - var hashLoc = href.lastIndexOf("#"); - return (hashLoc > 0) ? href.substring(hashLoc) : ""; - }-*/; - - @Override - public boolean init() { - historyFrame = findHistoryFrame(); - if (historyFrame == null) { - return false; - } - - initHistoryToken(); - - // Initialize the history iframe. If a token element already exists, - // then - // we're probably backing into the app, so _don't_ create a new item. - Element tokenElement = getTokenElement(historyFrame); - if (tokenElement != null) { - setToken(getTokenElementContent(tokenElement)); - } else { - navigateFrame(getToken()); - } - - injectGlobalHandler(); - - initUrlCheckTimer(); - return true; - } - - protected native String getTokenElementContent(Element tokenElement) - /*-{ - return tokenElement.innerText; - }-*/; - - protected native void initHistoryToken() - /*-{ - // Assume an empty token. - var token = ''; - // Get the initial token from the url's hash component. - var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()(); - if (hash.length > 0) { - try { - token = this.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1)); - } catch (e) { - // Clear the bad hash (this can't have been a valid token). - $wnd.location.hash = ''; - } - } - @com.google.gwt.user.client.impl.HistoryImpl::setToken(Ljava/lang/String;)(token); - }-*/; - - protected native void injectGlobalHandler() - /*-{ - var historyImplRef = this; - - $wnd.__gwt_onHistoryLoad = $entry(function(token) { - historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::newItemOnEvent(Ljava/lang/String;)(token); - }); - }-*/; - - protected native void navigateFrame(String token) - /*-{ - var escaped = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::escapeHtml(Ljava/lang/String;)(token); - var doc = this.@com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::historyFrame.contentWindow.document; - doc.open(); - doc.write('<html><body onload="if(parent.__gwt_onHistoryLoad)parent.__gwt_onHistoryLoad(__gwt_historyToken.innerText)"><div id="__gwt_historyToken">' + escaped + '</div></body></html>'); - doc.close(); - }-*/; - - protected native void updateHash(String token) - /*-{ - $wnd.location.hash = this.@com.google.gwt.user.client.impl.HistoryImpl::encodeFragment(Ljava/lang/String;)(token); - }-*/; - - private native void initUrlCheckTimer() - /*-{ - // This is the URL check timer. It detects when an unexpected change - // occurs in the document's URL (e.g. when the user enters one manually - // or selects a 'favorite', but only the #hash part changes). When this - // occurs, we _must_ reload the page. This is because IE has a really - // nasty bug that totally mangles its history stack and causes the location - // bar in the UI to stop working under these circumstances. - var historyImplRef = this; - var urlChecker = function() { - $wnd.setTimeout(urlChecker, 250); - var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()(); - if (hash.length > 0) { - var token = ''; - try { - token = historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1)); - } catch (e) { - // If there's a bad hash, always reload. This could only happen if - // if someone entered or linked to a bad url. - $wnd.location.reload(); - } - - var historyToken = @com.google.gwt.user.client.impl.HistoryImpl::getToken()(); - if (token != historyToken) { - $wnd.location.reload(); - } - } - }; - urlChecker(); - }-*/; - -} diff --git a/src/com/vaadin/terminal/gwt/client/LayoutManager.java b/src/com/vaadin/terminal/gwt/client/LayoutManager.java new file mode 100644 index 0000000000..9390c719fc --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/LayoutManager.java @@ -0,0 +1,1191 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.core.client.Duration; +import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Overflow; +import com.google.gwt.user.client.Timer; +import com.vaadin.terminal.gwt.client.MeasuredSize.MeasureResult; +import com.vaadin.terminal.gwt.client.ui.ManagedLayout; +import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +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.layout.LayoutDependencyTree; +import com.vaadin.terminal.gwt.client.ui.notification.VNotification; + +public class LayoutManager { + private static final String LOOP_ABORT_MESSAGE = "Aborting layout after 100 passes. This would probably be an infinite loop."; + + private static final boolean debugLogging = false; + + private ApplicationConnection connection; + private final Set<Element> measuredNonConnectorElements = new HashSet<Element>(); + private final MeasuredSize nullSize = new MeasuredSize(); + + private LayoutDependencyTree currentDependencyTree; + + private final Collection<ManagedLayout> needsHorizontalLayout = new HashSet<ManagedLayout>(); + private final Collection<ManagedLayout> needsVerticalLayout = new HashSet<ManagedLayout>(); + + private final Collection<ComponentConnector> needsMeasure = new HashSet<ComponentConnector>(); + + private Collection<ComponentConnector> pendingOverflowFixes = new HashSet<ComponentConnector>(); + + private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>(); + private final Set<Element> listenersToFire = new HashSet<Element>(); + + private boolean layoutPending = false; + private Timer layoutTimer = new Timer() { + @Override + public void run() { + cancel(); + layoutNow(); + } + }; + private boolean everythingNeedsMeasure = false; + + public void setConnection(ApplicationConnection connection) { + if (this.connection != null) { + throw new RuntimeException( + "LayoutManager connection can never be changed"); + } + this.connection = connection; + } + + /** + * Gets the layout manager associated with the given + * {@link ApplicationConnection}. + * + * @param connection + * the application connection to get a layout manager for + * @return the layout manager associated with the provided application + * connection + */ + public static LayoutManager get(ApplicationConnection connection) { + return connection.getLayoutManager(); + } + + /** + * Registers that a ManagedLayout is depending on the size of an Element. + * This causes this layout manager to measure the element in the beginning + * of every layout phase and call the appropriate layout method of the + * managed layout if the size of the element has changed. + * + * @param owner + * the ManagedLayout that depends on an element + * @param element + * the Element that should be measured + */ + public void registerDependency(ManagedLayout owner, Element element) { + MeasuredSize measuredSize = ensureMeasured(element); + setNeedsLayout(owner); + measuredSize.addDependent(owner.getConnectorId()); + } + + private MeasuredSize ensureMeasured(Element element) { + MeasuredSize measuredSize = getMeasuredSize(element, null); + if (measuredSize == null) { + measuredSize = new MeasuredSize(); + + if (ConnectorMap.get(connection).getConnector(element) == null) { + measuredNonConnectorElements.add(element); + } + setMeasuredSize(element, measuredSize); + } + return measuredSize; + } + + private boolean needsMeasure(Element e) { + if (connection.getConnectorMap().getConnectorId(e) != null) { + return true; + } else if (elementResizeListeners.containsKey(e)) { + return true; + } else if (getMeasuredSize(e, nullSize).hasDependents()) { + return true; + } else { + return false; + } + } + + /** + * Assigns a measured size to an element. Method defined as protected to + * allow separate implementation for IE8 in which delete not always works. + * + * @param element + * the dom element to attach the measured size to + * @param measuredSize + * the measured size to attach to the element. If + * <code>null</code>, any previous measured size is removed. + */ + protected native void setMeasuredSize(Element element, + MeasuredSize measuredSize) + /*-{ + if (measuredSize) { + element.vMeasuredSize = measuredSize; + } else { + delete element.vMeasuredSize; + } + }-*/; + + private static native final MeasuredSize getMeasuredSize(Element element, + MeasuredSize defaultSize) + /*-{ + return element.vMeasuredSize || defaultSize; + }-*/; + + private final MeasuredSize getMeasuredSize(ComponentConnector connector) { + Element element = connector.getWidget().getElement(); + MeasuredSize measuredSize = getMeasuredSize(element, null); + if (measuredSize == null) { + measuredSize = new MeasuredSize(); + setMeasuredSize(element, measuredSize); + } + return measuredSize; + } + + /** + * Registers that a ManagedLayout is no longer depending on the size of an + * Element. + * + * @see #registerDependency(ManagedLayout, Element) + * + * @param owner + * the ManagedLayout no longer depends on an element + * @param element + * the Element that that no longer needs to be measured + */ + public void unregisterDependency(ManagedLayout owner, Element element) { + MeasuredSize measuredSize = getMeasuredSize(element, null); + if (measuredSize == null) { + return; + } + measuredSize.removeDependent(owner.getConnectorId()); + stopMeasuringIfUnecessary(element); + } + + public boolean isLayoutRunning() { + return currentDependencyTree != null; + } + + private void countLayout(Map<ManagedLayout, Integer> layoutCounts, + ManagedLayout layout) { + Integer count = layoutCounts.get(layout); + if (count == null) { + count = Integer.valueOf(0); + } else { + count = Integer.valueOf(count.intValue() + 1); + } + layoutCounts.put(layout, count); + if (count.intValue() > 2) { + VConsole.error(Util.getConnectorString(layout) + + " has been layouted " + count.intValue() + " times"); + } + } + + private void layoutLater() { + if (!layoutPending) { + layoutPending = true; + layoutTimer.schedule(100); + } + } + + public void layoutNow() { + if (isLayoutRunning()) { + throw new IllegalStateException( + "Can't start a new layout phase before the previous layout phase ends."); + } + layoutPending = false; + try { + currentDependencyTree = new LayoutDependencyTree(); + doLayout(); + } finally { + currentDependencyTree = null; + } + } + + private void doLayout() { + VConsole.log("Starting layout phase"); + + Map<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>(); + + int passes = 0; + Duration totalDuration = new Duration(); + + for (ManagedLayout layout : needsHorizontalLayout) { + currentDependencyTree.setNeedsHorizontalLayout(layout, true); + } + for (ManagedLayout layout : needsVerticalLayout) { + currentDependencyTree.setNeedsVerticalLayout(layout, true); + } + needsHorizontalLayout.clear(); + needsVerticalLayout.clear(); + + for (ComponentConnector connector : needsMeasure) { + currentDependencyTree.setNeedsMeasure(connector, true); + } + needsMeasure.clear(); + + measureNonConnectors(); + + VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms"); + + while (true) { + Duration passDuration = new Duration(); + passes++; + + int measuredConnectorCount = measureConnectors( + currentDependencyTree, everythingNeedsMeasure); + everythingNeedsMeasure = false; + if (measuredConnectorCount == 0) { + VConsole.log("No more changes in pass " + passes); + break; + } + + int measureTime = passDuration.elapsedMillis(); + VConsole.log(" Measured " + measuredConnectorCount + + " elements in " + measureTime + " ms"); + + if (!listenersToFire.isEmpty()) { + for (Element element : listenersToFire) { + Collection<ElementResizeListener> listeners = elementResizeListeners + .get(element); + ElementResizeListener[] array = listeners + .toArray(new ElementResizeListener[listeners.size()]); + ElementResizeEvent event = new ElementResizeEvent(this, + element); + for (ElementResizeListener listener : array) { + try { + listener.onElementResize(event); + } catch (RuntimeException e) { + VConsole.error(e); + } + } + } + int measureListenerTime = passDuration.elapsedMillis(); + VConsole.log(" Fired resize listeners for " + + listenersToFire.size() + " elements in " + + (measureListenerTime - measureTime) + " ms"); + measureTime = measuredConnectorCount; + listenersToFire.clear(); + } + + FastStringSet updatedSet = FastStringSet.create(); + + while (currentDependencyTree.hasHorizontalConnectorToLayout() + || currentDependencyTree.hasVerticaConnectorToLayout()) { + for (ManagedLayout layout : currentDependencyTree + .getHorizontalLayoutTargets()) { + if (layout instanceof DirectionalManagedLayout) { + currentDependencyTree + .markAsHorizontallyLayouted(layout); + DirectionalManagedLayout cl = (DirectionalManagedLayout) layout; + try { + cl.layoutHorizontally(); + } catch (RuntimeException e) { + VConsole.log(e); + } + countLayout(layoutCounts, cl); + } else { + currentDependencyTree + .markAsHorizontallyLayouted(layout); + currentDependencyTree.markAsVerticallyLayouted(layout); + SimpleManagedLayout rr = (SimpleManagedLayout) layout; + try { + rr.layout(); + } catch (RuntimeException e) { + VConsole.log(e); + } + countLayout(layoutCounts, rr); + } + if (debugLogging) { + updatedSet.add(layout.getConnectorId()); + } + } + + for (ManagedLayout layout : currentDependencyTree + .getVerticalLayoutTargets()) { + if (layout instanceof DirectionalManagedLayout) { + currentDependencyTree.markAsVerticallyLayouted(layout); + DirectionalManagedLayout cl = (DirectionalManagedLayout) layout; + try { + cl.layoutVertically(); + } catch (RuntimeException e) { + VConsole.log(e); + } + countLayout(layoutCounts, cl); + } else { + currentDependencyTree + .markAsHorizontallyLayouted(layout); + currentDependencyTree.markAsVerticallyLayouted(layout); + SimpleManagedLayout rr = (SimpleManagedLayout) layout; + try { + rr.layout(); + } catch (RuntimeException e) { + VConsole.log(e); + } + countLayout(layoutCounts, rr); + } + if (debugLogging) { + updatedSet.add(layout.getConnectorId()); + } + } + } + + if (debugLogging) { + JsArrayString changedCids = updatedSet.dump(); + + StringBuilder b = new StringBuilder(" "); + b.append(changedCids.length()); + b.append(" requestLayout invocations in "); + b.append(passDuration.elapsedMillis() - measureTime); + b.append(" ms"); + if (changedCids.length() < 30) { + for (int i = 0; i < changedCids.length(); i++) { + if (i != 0) { + b.append(", "); + } else { + b.append(": "); + } + String connectorString = changedCids.get(i); + if (changedCids.length() < 10) { + ServerConnector connector = ConnectorMap.get( + connection).getConnector(connectorString); + connectorString = Util + .getConnectorString(connector); + } + b.append(connectorString); + } + } + VConsole.log(b.toString()); + } + + VConsole.log("Pass " + passes + " completed in " + + passDuration.elapsedMillis() + " ms"); + + if (passes > 100) { + VConsole.log(LOOP_ABORT_MESSAGE); + VNotification.createNotification(VNotification.DELAY_FOREVER) + .show(LOOP_ABORT_MESSAGE, VNotification.CENTERED, + "error"); + break; + } + } + + int postLayoutStart = totalDuration.elapsedMillis(); + for (ComponentConnector connector : connection.getConnectorMap() + .getComponentConnectors()) { + if (connector instanceof PostLayoutListener) { + ((PostLayoutListener) connector).postLayout(); + } + } + VConsole.log("Invoke post layout listeners in " + + (totalDuration.elapsedMillis() - postLayoutStart) + " ms"); + + VConsole.log("Total layout phase time: " + + totalDuration.elapsedMillis() + "ms"); + } + + private void logConnectorStatus(int connectorId) { + currentDependencyTree + .logDependencyStatus((ComponentConnector) ConnectorMap.get( + connection).getConnector(Integer.toString(connectorId))); + } + + private int measureConnectors(LayoutDependencyTree layoutDependencyTree, + boolean measureAll) { + if (!pendingOverflowFixes.isEmpty()) { + Duration duration = new Duration(); + + HashMap<Element, String> originalOverflows = new HashMap<Element, String>(); + + HashSet<ComponentConnector> delayedOverflowFixes = new HashSet<ComponentConnector>(); + + // First set overflow to hidden (and save previous value so it can + // be restored later) + for (ComponentConnector componentConnector : pendingOverflowFixes) { + // Delay the overflow fix if the involved connectors might still + // change + if (!currentDependencyTree + .noMoreChangesExpected(componentConnector) + || !currentDependencyTree + .noMoreChangesExpected(componentConnector + .getParent())) { + delayedOverflowFixes.add(componentConnector); + continue; + } + + if (debugLogging) { + VConsole.log("Doing overflow fix for " + + Util.getConnectorString(componentConnector) + + " in " + + Util.getConnectorString(componentConnector + .getParent())); + } + + Element parentElement = componentConnector.getWidget() + .getElement().getParentElement(); + Style style = parentElement.getStyle(); + String originalOverflow = style.getOverflow(); + + if (originalOverflow != null + && !originalOverflows.containsKey(parentElement)) { + // Store original value for restore, but only the first time + // the value is changed + originalOverflows.put(parentElement, originalOverflow); + } + + style.setOverflow(Overflow.HIDDEN); + } + + pendingOverflowFixes.removeAll(delayedOverflowFixes); + + // Then ensure all scrolling elements are reflowed by measuring + for (ComponentConnector componentConnector : pendingOverflowFixes) { + componentConnector.getWidget().getElement().getParentElement() + .getOffsetHeight(); + } + + // Finally restore old overflow value and update bookkeeping + for (ComponentConnector componentConnector : pendingOverflowFixes) { + Element parentElement = componentConnector.getWidget() + .getElement().getParentElement(); + parentElement.getStyle().setProperty("overflow", + originalOverflows.get(parentElement)); + + layoutDependencyTree.setNeedsMeasure(componentConnector, true); + } + if (!pendingOverflowFixes.isEmpty()) { + VConsole.log("Did overflow fix for " + + pendingOverflowFixes.size() + " elements in " + + duration.elapsedMillis() + " ms"); + } + pendingOverflowFixes = delayedOverflowFixes; + } + + int measureCount = 0; + if (measureAll) { + ComponentConnector[] connectors = ConnectorMap.get(connection) + .getComponentConnectors(); + for (ComponentConnector connector : connectors) { + measueConnector(connector); + } + for (ComponentConnector connector : connectors) { + layoutDependencyTree.setNeedsMeasure(connector, false); + } + measureCount += connectors.length; + } + + while (layoutDependencyTree.hasConnectorsToMeasure()) { + Collection<ComponentConnector> measureTargets = layoutDependencyTree + .getMeasureTargets(); + for (ComponentConnector connector : measureTargets) { + measueConnector(connector); + measureCount++; + } + for (ComponentConnector connector : measureTargets) { + layoutDependencyTree.setNeedsMeasure(connector, false); + } + } + return measureCount; + } + + private void measueConnector(ComponentConnector connector) { + Element element = connector.getWidget().getElement(); + MeasuredSize measuredSize = getMeasuredSize(connector); + MeasureResult measureResult = measuredAndUpdate(element, measuredSize); + + if (measureResult.isChanged()) { + onConnectorChange(connector, measureResult.isWidthChanged(), + measureResult.isHeightChanged()); + } + } + + private void onConnectorChange(ComponentConnector connector, + boolean widthChanged, boolean heightChanged) { + setNeedsOverflowFix(connector); + if (heightChanged) { + currentDependencyTree.markHeightAsChanged(connector); + } + if (widthChanged) { + currentDependencyTree.markWidthAsChanged(connector); + } + } + + private void setNeedsOverflowFix(ComponentConnector connector) { + // IE9 doesn't need the original fix, but for some reason it needs this + if (BrowserInfo.get().requiresOverflowAutoFix() + || BrowserInfo.get().isIE9()) { + ComponentConnector scrollingBoundary = currentDependencyTree + .getScrollingBoundary(connector); + if (scrollingBoundary != null) { + pendingOverflowFixes.add(scrollingBoundary); + } + } + } + + private void measureNonConnectors() { + for (Element element : measuredNonConnectorElements) { + measuredAndUpdate(element, getMeasuredSize(element, null)); + } + VConsole.log("Measured " + measuredNonConnectorElements.size() + + " non connector elements"); + } + + private MeasureResult measuredAndUpdate(Element element, + MeasuredSize measuredSize) { + MeasureResult measureResult = measuredSize.measure(element); + if (measureResult.isChanged()) { + notifyListenersAndDepdendents(element, + measureResult.isWidthChanged(), + measureResult.isHeightChanged()); + } + return measureResult; + } + + private void notifyListenersAndDepdendents(Element element, + boolean widthChanged, boolean heightChanged) { + assert widthChanged || heightChanged; + + MeasuredSize measuredSize = getMeasuredSize(element, nullSize); + JsArrayString dependents = measuredSize.getDependents(); + for (int i = 0; i < dependents.length(); i++) { + String pid = dependents.get(i); + ManagedLayout dependent = (ManagedLayout) connection + .getConnectorMap().getConnector(pid); + if (dependent != null) { + if (heightChanged) { + currentDependencyTree.setNeedsVerticalLayout(dependent, + true); + } + if (widthChanged) { + currentDependencyTree.setNeedsHorizontalLayout(dependent, + true); + } + } + } + if (elementResizeListeners.containsKey(element)) { + listenersToFire.add(element); + } + } + + private static boolean isManagedLayout(ComponentConnector connector) { + return connector instanceof ManagedLayout; + } + + public void forceLayout() { + ConnectorMap connectorMap = connection.getConnectorMap(); + ComponentConnector[] componentConnectors = connectorMap + .getComponentConnectors(); + for (ComponentConnector connector : componentConnectors) { + if (connector instanceof ManagedLayout) { + setNeedsLayout((ManagedLayout) connector); + } + } + setEverythingNeedsMeasure(); + layoutNow(); + } + + /** + * Marks that a ManagedLayout should be layouted in the next layout phase + * even if none of the elements managed by the layout have been resized. + * + * @param layout + * the managed layout that should be layouted + */ + public final void setNeedsLayout(ManagedLayout layout) { + setNeedsHorizontalLayout(layout); + setNeedsVerticalLayout(layout); + } + + /** + * Marks that a ManagedLayout should be layouted horizontally in the next + * layout phase even if none of the elements managed by the layout have been + * resized horizontally. + * + * For SimpleManagedLayout which is always layouted in both directions, this + * has the same effect as {@link #setNeedsLayout(ManagedLayout)}. + * + * @param layout + * the managed layout that should be layouted + */ + public final void setNeedsHorizontalLayout(ManagedLayout layout) { + needsHorizontalLayout.add(layout); + } + + /** + * Marks that a ManagedLayout should be layouted vertically in the next + * layout phase even if none of the elements managed by the layout have been + * resized vertically. + * + * For SimpleManagedLayout which is always layouted in both directions, this + * has the same effect as {@link #setNeedsLayout(ManagedLayout)}. + * + * @param layout + * the managed layout that should be layouted + */ + public final void setNeedsVerticalLayout(ManagedLayout layout) { + needsVerticalLayout.add(layout); + } + + /** + * Gets the outer height (including margins, paddings and borders) of the + * given element, provided that it has been measured. These elements are + * guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * -1 is returned if the element has not been measured. If 0 is returned, it + * might indicate that the element is not attached to the DOM. + * + * @param element + * the element to get the measured size for + * @return the measured outer height (including margins, paddings and + * borders) of the element in pixels. + */ + public final int getOuterHeight(Element element) { + return getMeasuredSize(element, nullSize).getOuterHeight(); + } + + /** + * Gets the outer width (including margins, paddings and borders) of the + * given element, provided that it has been measured. These elements are + * guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * -1 is returned if the element has not been measured. If 0 is returned, it + * might indicate that the element is not attached to the DOM. + * + * @param element + * the element to get the measured size for + * @return the measured outer width (including margins, paddings and + * borders) of the element in pixels. + */ + public final int getOuterWidth(Element element) { + return getMeasuredSize(element, nullSize).getOuterWidth(); + } + + /** + * Gets the inner height (excluding margins, paddings and borders) of the + * given element, provided that it has been measured. These elements are + * guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * -1 is returned if the element has not been measured. If 0 is returned, it + * might indicate that the element is not attached to the DOM. + * + * @param element + * the element to get the measured size for + * @return the measured inner height (excluding margins, paddings and + * borders) of the element in pixels. + */ + public final int getInnerHeight(Element element) { + return getMeasuredSize(element, nullSize).getInnerHeight(); + } + + /** + * Gets the inner width (excluding margins, paddings and borders) of the + * given element, provided that it has been measured. These elements are + * guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * -1 is returned if the element has not been measured. If 0 is returned, it + * might indicate that the element is not attached to the DOM. + * + * @param element + * the element to get the measured size for + * @return the measured inner width (excluding margins, paddings and + * borders) of the element in pixels. + */ + public final int getInnerWidth(Element element) { + return getMeasuredSize(element, nullSize).getInnerWidth(); + } + + /** + * Gets the border height (top border + bottom border) of the given element, + * provided that it has been measured. These elements are guaranteed to be + * measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured border height (top border + bottom border) of the + * element in pixels. + */ + public final int getBorderHeight(Element element) { + return getMeasuredSize(element, nullSize).getBorderHeight(); + } + + /** + * Gets the padding height (top padding + bottom padding) of the given + * element, provided that it has been measured. These elements are + * guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured padding height (top padding + bottom padding) of the + * element in pixels. + */ + public int getPaddingHeight(Element element) { + return getMeasuredSize(element, nullSize).getPaddingHeight(); + } + + /** + * Gets the border width (left border + right border) of the given element, + * provided that it has been measured. These elements are guaranteed to be + * measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured border width (left border + right border) of the + * element in pixels. + */ + public int getBorderWidth(Element element) { + return getMeasuredSize(element, nullSize).getBorderWidth(); + } + + /** + * Gets the padding width (left padding + right padding) of the given + * element, provided that it has been measured. These elements are + * guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured padding width (left padding + right padding) of the + * element in pixels. + */ + public int getPaddingWidth(Element element) { + return getMeasuredSize(element, nullSize).getPaddingWidth(); + } + + /** + * Gets the top padding of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured top padding of the element in pixels. + */ + public int getPaddingTop(Element element) { + return getMeasuredSize(element, nullSize).getPaddingTop(); + } + + /** + * Gets the left padding of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured left padding of the element in pixels. + */ + public int getPaddingLeft(Element element) { + return getMeasuredSize(element, nullSize).getPaddingLeft(); + } + + /** + * Gets the bottom padding of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured bottom padding of the element in pixels. + */ + public int getPaddingBottom(Element element) { + return getMeasuredSize(element, nullSize).getPaddingBottom(); + } + + /** + * Gets the right padding of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured right padding of the element in pixels. + */ + public int getPaddingRight(Element element) { + return getMeasuredSize(element, nullSize).getPaddingRight(); + } + + /** + * Gets the top margin of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured top margin of the element in pixels. + */ + public int getMarginTop(Element element) { + return getMeasuredSize(element, nullSize).getMarginTop(); + } + + /** + * Gets the right margin of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured right margin of the element in pixels. + */ + public int getMarginRight(Element element) { + return getMeasuredSize(element, nullSize).getMarginRight(); + } + + /** + * Gets the bottom margin of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured bottom margin of the element in pixels. + */ + public int getMarginBottom(Element element) { + return getMeasuredSize(element, nullSize).getMarginBottom(); + } + + /** + * Gets the left margin of the given element, provided that it has been + * measured. These elements are guaranteed to be measured: + * <ul> + * <li>ManagedLayotus and their child Connectors + * <li>Elements for which there is at least one ElementResizeListener + * <li>Elements for which at least one ManagedLayout has registered a + * dependency + * </ul> + * + * A negative number is returned if the element has not been measured. If 0 + * is returned, it might indicate that the element is not attached to the + * DOM. + * + * @param element + * the element to get the measured size for + * @return the measured left margin of the element in pixels. + */ + public int getMarginLeft(Element element) { + return getMeasuredSize(element, nullSize).getMarginLeft(); + } + + /** + * Registers the outer height (including margins, borders and paddings) of a + * component. This can be used as an optimization by ManagedLayouts; by + * informing the LayoutManager about what size a component will have, the + * layout propagation can continue directly without first measuring the + * potentially resized elements. + * + * @param component + * the component for which the size is reported + * @param outerHeight + * the new outer height (including margins, borders and paddings) + * of the component in pixels + */ + public void reportOuterHeight(ComponentConnector component, int outerHeight) { + MeasuredSize measuredSize = getMeasuredSize(component); + if (isLayoutRunning()) { + boolean heightChanged = measuredSize.setOuterHeight(outerHeight); + + if (heightChanged) { + onConnectorChange(component, false, true); + notifyListenersAndDepdendents(component.getWidget() + .getElement(), false, true); + } + currentDependencyTree.setNeedsVerticalMeasure(component, false); + } else if (measuredSize.getOuterHeight() != outerHeight) { + setNeedsMeasure(component); + } + } + + /** + * Registers the height reserved for a relatively sized component. This can + * be used as an optimization by ManagedLayouts; by informing the + * LayoutManager about what size a component will have, the layout + * propagation can continue directly without first measuring the potentially + * resized elements. + * + * @param component + * the relatively sized component for which the size is reported + * @param assignedHeight + * the inner height of the relatively sized component's parent + * element in pixels + */ + public void reportHeightAssignedToRelative(ComponentConnector component, + int assignedHeight) { + assert component.isRelativeHeight(); + + float percentSize = parsePercent(component.getState().getHeight()); + int effectiveHeight = Math.round(assignedHeight * (percentSize / 100)); + + reportOuterHeight(component, effectiveHeight); + } + + /** + * Registers the width reserved for a relatively sized component. This can + * be used as an optimization by ManagedLayouts; by informing the + * LayoutManager about what size a component will have, the layout + * propagation can continue directly without first measuring the potentially + * resized elements. + * + * @param component + * the relatively sized component for which the size is reported + * @param assignedWidth + * the inner width of the relatively sized component's parent + * element in pixels + */ + public void reportWidthAssignedToRelative(ComponentConnector component, + int assignedWidth) { + assert component.isRelativeWidth(); + + float percentSize = parsePercent(component.getState().getWidth()); + int effectiveWidth = Math.round(assignedWidth * (percentSize / 100)); + + reportOuterWidth(component, effectiveWidth); + } + + private static float parsePercent(String size) { + return Float.parseFloat(size.substring(0, size.length() - 1)); + } + + /** + * Registers the outer width (including margins, borders and paddings) of a + * component. This can be used as an optimization by ManagedLayouts; by + * informing the LayoutManager about what size a component will have, the + * layout propagation can continue directly without first measuring the + * potentially resized elements. + * + * @param component + * the component for which the size is reported + * @param outerWidth + * the new outer width (including margins, borders and paddings) + * of the component in pixels + */ + public void reportOuterWidth(ComponentConnector component, int outerWidth) { + MeasuredSize measuredSize = getMeasuredSize(component); + if (isLayoutRunning()) { + boolean widthChanged = measuredSize.setOuterWidth(outerWidth); + + if (widthChanged) { + onConnectorChange(component, true, false); + notifyListenersAndDepdendents(component.getWidget() + .getElement(), true, false); + } + currentDependencyTree.setNeedsHorizontalMeasure(component, false); + } else if (measuredSize.getOuterWidth() != outerWidth) { + setNeedsMeasure(component); + } + } + + /** + * Adds a listener that will be notified whenever the size of a specific + * element changes. Adding a listener to an element also ensures that all + * sizes for that element will be available starting from the next layout + * phase. + * + * @param element + * the element that should be checked for size changes + * @param listener + * an ElementResizeListener that will be informed whenever the + * size of the target element has changed + */ + public void addElementResizeListener(Element element, + ElementResizeListener listener) { + Collection<ElementResizeListener> listeners = elementResizeListeners + .get(element); + if (listeners == null) { + listeners = new HashSet<ElementResizeListener>(); + elementResizeListeners.put(element, listeners); + ensureMeasured(element); + } + listeners.add(listener); + } + + /** + * Removes an element resize listener from the provided element. This might + * cause this LayoutManager to stop tracking the size of the element if no + * other sources are interested in the size. + * + * @param element + * the element to which the element resize listener was + * previously added + * @param listener + * the ElementResizeListener that should no longer get informed + * about size changes to the target element. + */ + public void removeElementResizeListener(Element element, + ElementResizeListener listener) { + Collection<ElementResizeListener> listeners = elementResizeListeners + .get(element); + if (listeners != null) { + listeners.remove(listener); + if (listeners.isEmpty()) { + elementResizeListeners.remove(element); + stopMeasuringIfUnecessary(element); + } + } + } + + private void stopMeasuringIfUnecessary(Element element) { + if (!needsMeasure(element)) { + measuredNonConnectorElements.remove(element); + setMeasuredSize(element, null); + } + } + + /** + * Informs this LayoutManager that the size of a component might have + * changed. If there is no upcoming layout phase, a new layout phase is + * scheduled. This method should be used whenever a size might have changed + * from outside of Vaadin's normal update phase, e.g. when an icon has been + * loaded or when the user resizes some part of the UI using the mouse. + * + * @param component + * the component whose size might have changed. + */ + public void setNeedsMeasure(ComponentConnector component) { + if (isLayoutRunning()) { + currentDependencyTree.setNeedsMeasure(component, true); + } else { + needsMeasure.add(component); + layoutLater(); + } + } + + public void setEverythingNeedsMeasure() { + everythingNeedsMeasure = true; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/LayoutManagerIE8.java b/src/com/vaadin/terminal/gwt/client/LayoutManagerIE8.java new file mode 100644 index 0000000000..2b677985b5 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/LayoutManagerIE8.java @@ -0,0 +1,23 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.google.gwt.dom.client.Element; + +public class LayoutManagerIE8 extends LayoutManager { + + @Override + protected native void setMeasuredSize(Element element, + MeasuredSize measuredSize) + // IE8 cannot do delete element.vMeasuredSize, at least in the case when + // element is not attached to the document (e.g. when a caption is removed) + /*-{ + if (measuredSize) { + element.vMeasuredSize = measuredSize; + } else { + element.vMeasuredSize = undefined; + } + }-*/; + +} diff --git a/src/com/vaadin/terminal/gwt/client/MeasuredSize.java b/src/com/vaadin/terminal/gwt/client/MeasuredSize.java new file mode 100644 index 0000000000..97822fa8ec --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/MeasuredSize.java @@ -0,0 +1,228 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.google.gwt.core.client.JsArrayString; +import com.google.gwt.dom.client.Element; + +public class MeasuredSize { + public static class MeasureResult { + private final boolean widthChanged; + private final boolean heightChanged; + + private MeasureResult(boolean widthChanged, boolean heightChanged) { + this.widthChanged = widthChanged; + this.heightChanged = heightChanged; + } + + public boolean isHeightChanged() { + return heightChanged; + } + + public boolean isWidthChanged() { + return widthChanged; + } + + public boolean isChanged() { + return heightChanged || widthChanged; + } + } + + private int width = -1; + private int height = -1; + + private int[] paddings = new int[4]; + private int[] borders = new int[4]; + private int[] margins = new int[4]; + + private FastStringSet dependents = FastStringSet.create(); + + public int getOuterHeight() { + return height; + } + + public int getOuterWidth() { + return width; + } + + public void addDependent(String pid) { + dependents.add(pid); + } + + public void removeDependent(String pid) { + dependents.remove(pid); + } + + public boolean hasDependents() { + return !dependents.isEmpty(); + } + + public JsArrayString getDependents() { + return dependents.dump(); + } + + private static int sumWidths(int[] sizes) { + return sizes[1] + sizes[3]; + } + + private static int sumHeights(int[] sizes) { + return sizes[0] + sizes[2]; + } + + public int getInnerHeight() { + return height - sumHeights(margins) - sumHeights(borders) + - sumHeights(paddings); + } + + public int getInnerWidth() { + return width - sumWidths(margins) - sumWidths(borders) + - sumWidths(paddings); + } + + public boolean setOuterHeight(int height) { + if (this.height != height) { + this.height = height; + return true; + } else { + return false; + } + } + + public boolean setOuterWidth(int width) { + if (this.width != width) { + this.width = width; + return true; + } else { + return false; + } + } + + public int getBorderHeight() { + return sumHeights(borders); + } + + public int getBorderWidth() { + return sumWidths(borders); + } + + public int getPaddingHeight() { + return sumHeights(paddings); + } + + public int getPaddingWidth() { + return sumWidths(paddings); + } + + public int getMarginHeight() { + return sumHeights(margins); + } + + public int getMarginWidth() { + return sumWidths(margins); + } + + public int getMarginTop() { + return margins[0]; + } + + public int getMarginRight() { + return margins[1]; + } + + public int getMarginBottom() { + return margins[2]; + } + + public int getMarginLeft() { + return margins[3]; + } + + public int getBorderTop() { + return margins[0]; + } + + public int getBorderRight() { + return margins[1]; + } + + public int getBorderBottom() { + return margins[2]; + } + + public int getBorderLeft() { + return margins[3]; + } + + public int getPaddingTop() { + return paddings[0]; + } + + public int getPaddingRight() { + return paddings[1]; + } + + public int getPaddingBottom() { + return paddings[2]; + } + + public int getPaddingLeft() { + return paddings[3]; + } + + public MeasureResult measure(Element element) { + boolean heightChanged = false; + boolean widthChanged = false; + + ComputedStyle computedStyle = new ComputedStyle(element); + int[] paddings = computedStyle.getPadding(); + if (!heightChanged && hasHeightChanged(this.paddings, paddings)) { + heightChanged = true; + } + if (!widthChanged && hasWidthChanged(this.paddings, paddings)) { + widthChanged = true; + } + this.paddings = paddings; + + int[] margins = computedStyle.getMargin(); + if (!heightChanged && hasHeightChanged(this.margins, margins)) { + heightChanged = true; + } + if (!widthChanged && hasWidthChanged(this.margins, margins)) { + widthChanged = true; + } + this.margins = margins; + + int[] borders = computedStyle.getBorder(); + if (!heightChanged && hasHeightChanged(this.borders, borders)) { + heightChanged = true; + } + if (!widthChanged && hasWidthChanged(this.borders, borders)) { + widthChanged = true; + } + this.borders = borders; + + int requiredHeight = Util.getRequiredHeight(element); + int marginHeight = sumHeights(margins); + if (setOuterHeight(requiredHeight + marginHeight)) { + heightChanged = true; + } + + int requiredWidth = Util.getRequiredWidth(element); + int marginWidth = sumWidths(margins); + if (setOuterWidth(requiredWidth + marginWidth)) { + widthChanged = true; + } + + return new MeasureResult(widthChanged, heightChanged); + } + + private static boolean hasWidthChanged(int[] sizes1, int[] sizes2) { + return sizes1[1] != sizes2[1] || sizes1[3] != sizes2[3]; + } + + private static boolean hasHeightChanged(int[] sizes1, int[] sizes2) { + return sizes1[0] != sizes2[0] || sizes1[2] != sizes2[2]; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java b/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java index 260dfa6fff..f5ff707eed 100644 --- a/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java +++ b/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java @@ -5,19 +5,18 @@ package com.vaadin.terminal.gwt.client; import java.io.Serializable; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.user.client.Event; - /** * Helper class to store and transfer mouse event details. */ public class MouseEventDetails implements Serializable { - public static final int BUTTON_LEFT = Event.BUTTON_LEFT; - public static final int BUTTON_MIDDLE = Event.BUTTON_MIDDLE; - public static final int BUTTON_RIGHT = Event.BUTTON_RIGHT; + // From com.google.gwt.dom.client.NativeEvent + public static final int BUTTON_LEFT = 1; + public static final int BUTTON_MIDDLE = 4; + public static final int BUTTON_RIGHT = 2; private static final char DELIM = ','; + // From com.google.gwt.user.client.Event + private static final int ONDBLCLICK = 0x00002; private int button; private int clientX; @@ -66,26 +65,47 @@ public class MouseEventDetails implements Serializable { return relativeY; } - public MouseEventDetails(NativeEvent evt) { - this(evt, null); + public void setButton(int button) { + this.button = button; } - public MouseEventDetails(NativeEvent evt, Element relativeToElement) { - type = Event.getTypeInt(evt.getType()); - clientX = Util.getTouchOrMouseClientX(evt); - clientY = Util.getTouchOrMouseClientY(evt); - button = evt.getButton(); - altKey = evt.getAltKey(); - ctrlKey = evt.getCtrlKey(); - metaKey = evt.getMetaKey(); - shiftKey = evt.getShiftKey(); - if (relativeToElement != null) { - relativeX = getRelativeX(clientX, relativeToElement); - relativeY = getRelativeY(clientY, relativeToElement); - } + public void setClientX(int clientX) { + this.clientX = clientX; + } + + public void setClientY(int clientY) { + this.clientY = clientY; + } + + public void setAltKey(boolean altKey) { + this.altKey = altKey; + } + + public void setCtrlKey(boolean ctrlKey) { + this.ctrlKey = ctrlKey; + } + + public void setMetaKey(boolean metaKey) { + this.metaKey = metaKey; + } + + public void setShiftKey(boolean shiftKey) { + this.shiftKey = shiftKey; + } + + public void setType(int type) { + this.type = type; } - private MouseEventDetails() { + public void setRelativeX(int relativeX) { + this.relativeX = relativeX; + } + + public void setRelativeY(int relativeY) { + this.relativeY = relativeY; + } + + public MouseEventDetails() { } @Override @@ -128,22 +148,12 @@ public class MouseEventDetails implements Serializable { return ""; } - public Class<MouseEventDetails> getType() { - return MouseEventDetails.class; + public int getType() { + return type; } public boolean isDoubleClick() { - return type == Event.ONDBLCLICK; - } - - private static int getRelativeX(int clientX, Element target) { - return clientX - target.getAbsoluteLeft() + target.getScrollLeft() - + target.getOwnerDocument().getScrollLeft(); - } - - private static int getRelativeY(int clientY, Element target) { - return clientY - target.getAbsoluteTop() + target.getScrollTop() - + target.getOwnerDocument().getScrollTop(); + return type == ONDBLCLICK; } } diff --git a/src/com/vaadin/terminal/gwt/client/MouseEventDetailsBuilder.java b/src/com/vaadin/terminal/gwt/client/MouseEventDetailsBuilder.java new file mode 100644 index 0000000000..58dd488351 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/MouseEventDetailsBuilder.java @@ -0,0 +1,74 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.user.client.Event; + +/** + * Helper class for constructing a MouseEventDetails object from a + * {@link NativeEvent}. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public class MouseEventDetailsBuilder { + + /** + * Construct a {@link MouseEventDetails} object from the given event + * + * @param evt + * The event to use as a source for the details + * @return a MouseEventDetails containing information from the event + */ + public static MouseEventDetails buildMouseEventDetails(NativeEvent evt) { + return buildMouseEventDetails(evt, null); + } + + /** + * Construct a {@link MouseEventDetails} object from the given event + * + * @param evt + * The event to use as a source for the details + * @param relativeToElement + * The element whose position + * {@link MouseEventDetails#getRelativeX()} and + * {@link MouseEventDetails#getRelativeY()} are relative to. + * @return a MouseEventDetails containing information from the event + */ + public static MouseEventDetails buildMouseEventDetails(NativeEvent evt, + Element relativeToElement) { + MouseEventDetails mouseEventDetails = new MouseEventDetails(); + mouseEventDetails.setType(Event.getTypeInt(evt.getType())); + mouseEventDetails.setClientX(Util.getTouchOrMouseClientX(evt)); + mouseEventDetails.setClientY(Util.getTouchOrMouseClientY(evt)); + mouseEventDetails.setButton(evt.getButton()); + mouseEventDetails.setAltKey(evt.getAltKey()); + mouseEventDetails.setCtrlKey(evt.getCtrlKey()); + mouseEventDetails.setMetaKey(evt.getMetaKey()); + mouseEventDetails.setShiftKey(evt.getShiftKey()); + if (relativeToElement != null) { + mouseEventDetails.setRelativeX(getRelativeX( + mouseEventDetails.getClientX(), relativeToElement)); + mouseEventDetails.setRelativeY(getRelativeY( + mouseEventDetails.getClientY(), relativeToElement)); + } + return mouseEventDetails; + + } + + private static int getRelativeX(int clientX, Element target) { + return clientX - target.getAbsoluteLeft() + target.getScrollLeft() + + target.getOwnerDocument().getScrollLeft(); + } + + private static int getRelativeY(int clientY, Element target) { + return clientY - target.getAbsoluteTop() + target.getScrollTop() + + target.getOwnerDocument().getScrollTop(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/NullConsole.java b/src/com/vaadin/terminal/gwt/client/NullConsole.java index 12df4b323b..2d15ffd46c 100644 --- a/src/com/vaadin/terminal/gwt/client/NullConsole.java +++ b/src/com/vaadin/terminal/gwt/client/NullConsole.java @@ -32,8 +32,8 @@ public class NullConsole implements Console { public void printLayoutProblems(ValueMap meta, ApplicationConnection applicationConnection, - Set<Paintable> zeroHeightComponents, - Set<Paintable> zeroWidthComponents) { + Set<ComponentConnector> zeroHeightComponents, + Set<ComponentConnector> zeroWidthComponents) { } public void log(Throwable e) { @@ -41,7 +41,8 @@ public class NullConsole implements Console { } public void error(Throwable e) { - GWT.log(e.getMessage(), e); + // Borrow exception handling from VDebugConsole + VDebugConsole.handleError(e, this); } public void setQuietMode(boolean quietDebugMode) { diff --git a/src/com/vaadin/terminal/gwt/client/Paintable.java b/src/com/vaadin/terminal/gwt/client/Paintable.java index 62abeab5a0..c9e3ef79cc 100644 --- a/src/com/vaadin/terminal/gwt/client/Paintable.java +++ b/src/com/vaadin/terminal/gwt/client/Paintable.java @@ -12,6 +12,7 @@ package com.vaadin.terminal.gwt.client; * Updates can be sent back to the server using the * {@link ApplicationConnection#updateVariable()} methods. */ +@Deprecated public interface Paintable { public void updateFromUIDL(UIDL uidl, ApplicationConnection client); diff --git a/src/com/vaadin/terminal/gwt/client/ServerConnector.java b/src/com/vaadin/terminal/gwt/client/ServerConnector.java new file mode 100644 index 0000000000..b331f1f07d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ServerConnector.java @@ -0,0 +1,104 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client; + +import java.util.Collection; + +import com.google.gwt.event.shared.GwtEvent; +import com.google.web.bindery.event.shared.HandlerRegistration; +import com.vaadin.terminal.gwt.client.communication.ClientRpc; +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; + +/** + * Interface implemented by all client side classes that can be communicate with + * the server. Classes implementing this interface are initialized by the + * framework when needed and have the ability to communicate with the server. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + */ +public interface ServerConnector extends Connector { + + /** + * Sets a new state for the connector. + * + * @param state + * The new state + * @deprecated This should be removed. Framework should update what is + * returned by getState() instead of setting a new state object. + * Note that this must be done either so that setState accepts a + * state object once (first time received from the server) or + * getState() in AbstractConnector uses a generated class to + * create the state object (like RpcProy.craete()) + */ + @Deprecated + public void setState(SharedState state); + + /** + * Gets ApplicationConnection instance that created this connector. + * + * @return The ApplicationConnection as set by + * {@link #doInit(String, ApplicationConnection)} + */ + public ApplicationConnection getConnection(); + + /** + * Tests whether the connector is enabled or not. This method checks that + * the connector is enabled in context, i.e. if the parent connector is + * disabled, this method must return false. + * + * @return true if the connector is enabled, false otherwise + */ + public boolean isEnabled(); + + /** + * + * Called once by the framework to initialize the connector. + * <p> + * Note that the shared state is not yet available at this point nor any + * hierarchy information. + */ + public void doInit(String connectorId, ApplicationConnection connection); + + /** + * For internal use by the framework: returns the registered RPC + * implementations for an RPC interface identifier. + * + * TODO interface identifier type or format may change + * + * @param rpcInterfaceId + * RPC interface identifier: fully qualified interface type name + * @return RPC interface implementations registered for an RPC interface, + * not null + */ + public <T extends ClientRpc> Collection<T> getRpcImplementations( + String rpcInterfaceId); + + /** + * Adds a handler that is called whenever some part of the state has been + * updated by the server. + * + * @param handler + * The handler that should be added. + * @return A handler registration reference that can be used to unregister + * the handler + */ + public HandlerRegistration addStateChangeHandler(StateChangeHandler handler); + + /** + * Sends the given event to all registered handlers. + * + * @param event + * The event to send. + */ + public void fireEvent(GwtEvent<?> event); + + /** + * Event called when connector has been unregistered. + */ + public void onUnregister(); + +} diff --git a/src/com/vaadin/terminal/gwt/client/SimpleTree.java b/src/com/vaadin/terminal/gwt/client/SimpleTree.java index 017884c94f..350e0d707d 100644 --- a/src/com/vaadin/terminal/gwt/client/SimpleTree.java +++ b/src/com/vaadin/terminal/gwt/client/SimpleTree.java @@ -28,6 +28,7 @@ public class SimpleTree extends ComplexPanel { Style style = getElement().getStyle(); style.setProperty("whiteSpace", "nowrap"); style.setPadding(3, Unit.PX); + style.setPaddingLeft(12, Unit.PX); style = handle.getStyle(); style.setDisplay(Display.NONE); @@ -43,7 +44,7 @@ public class SimpleTree extends ComplexPanel { getElement().appendChild(handle); getElement().appendChild(text); style = children.getStyle(); - style.setPaddingLeft(20, Unit.PX); + style.setPaddingLeft(9, Unit.PX); style.setDisplay(Display.NONE); getElement().appendChild(children); @@ -109,7 +110,7 @@ public class SimpleTree extends ComplexPanel { protected void add(Widget child, Element container) { super.add(child, container); handle.getStyle().setDisplay(Display.INLINE_BLOCK); - + getElement().getStyle().setPaddingLeft(3, Unit.PX); } } diff --git a/src/com/vaadin/terminal/gwt/client/TooltipInfo.java b/src/com/vaadin/terminal/gwt/client/TooltipInfo.java index 6f8ddd5237..fb33a56c56 100644 --- a/src/com/vaadin/terminal/gwt/client/TooltipInfo.java +++ b/src/com/vaadin/terminal/gwt/client/TooltipInfo.java @@ -7,7 +7,7 @@ public class TooltipInfo { private String title; - private UIDL errorUidl; + private String errorMessageHtml; public TooltipInfo() { } @@ -24,12 +24,12 @@ public class TooltipInfo { this.title = title; } - public UIDL getErrorUidl() { - return errorUidl; + public String getErrorMessage() { + return errorMessageHtml; } - public void setErrorUidl(UIDL errorUidl) { - this.errorUidl = errorUidl; + public void setErrorMessage(String errorMessage) { + errorMessageHtml = errorMessage; } } diff --git a/src/com/vaadin/terminal/gwt/client/UIDL.java b/src/com/vaadin/terminal/gwt/client/UIDL.java index a6298af8d1..a523016b60 100644 --- a/src/com/vaadin/terminal/gwt/client/UIDL.java +++ b/src/com/vaadin/terminal/gwt/client/UIDL.java @@ -16,7 +16,7 @@ import com.vaadin.ui.Component; /** * When a component is updated, it's client side widget's - * {@link Paintable#updateFromUIDL(UIDL, ApplicationConnection) + * {@link ComponentConnector#updateFromUIDL(UIDL, ApplicationConnection) * updateFromUIDL()} will be called with the updated ("changes") UIDL received * from the server. * <p> @@ -55,7 +55,7 @@ public final class UIDL extends JavaScriptObject { * AbstractComponent.paintContent()}. Note that if the UIDL corresponds to a * Paintable, a component identifier will be returned instead - this is used * internally and is not needed within - * {@link Paintable#updateFromUIDL(UIDL, ApplicationConnection) + * {@link ComponentConnector#updateFromUIDL(UIDL, ApplicationConnection) * updateFromUIDL()}. * * @return the name for this section @@ -493,17 +493,6 @@ public final class UIDL extends JavaScriptObject { return this.length - 2; }-*/; - /** - * Shorthand that returns the component errors as UIDL. Only applicable for - * Paintables. - * - * @return the error UIDL if available - */ - public native UIDL getErrors() - /*-{ - return this[1]['error']; - }-*/; - native boolean isMapAttribute(String name) /*-{ return typeof this[1][name] == "object"; @@ -516,9 +505,10 @@ public final class UIDL extends JavaScriptObject { * the name of the attribute * @return the Paintable referenced by the attribute, if it exists */ - public Paintable getPaintableAttribute(String name, + public ServerConnector getPaintableAttribute(String name, ApplicationConnection connection) { - return connection.getPaintable(getStringAttribute(name)); + return ConnectorMap.get(connection).getConnector( + getStringAttribute(name)); } /** @@ -528,9 +518,10 @@ public final class UIDL extends JavaScriptObject { * the name of the variable * @return the Paintable referenced by the variable, if it exists */ - public Paintable getPaintableVariable(String name, + public ServerConnector getPaintableVariable(String name, ApplicationConnection connection) { - return connection.getPaintable(getStringVariable(name)); + return ConnectorMap.get(connection).getConnector( + getStringVariable(name)); } /** diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java index b9baf362e4..bfe63caefd 100644 --- a/src/com/vaadin/terminal/gwt/client/Util.java +++ b/src/com/vaadin/terminal/gwt/client/Util.java @@ -5,16 +5,13 @@ package com.vaadin.terminal.gwt.client; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; +import java.util.Arrays; +import java.util.Collection; import java.util.Iterator; -import java.util.Map; -import java.util.Set; +import java.util.List; -import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; @@ -26,12 +23,12 @@ 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.EventListener; -import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize; +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; public class Util { @@ -67,30 +64,6 @@ public class Util { return el; }-*/; - private static final int LAZY_SIZE_CHANGE_TIMEOUT = 400; - private static Set<Paintable> latelyChangedWidgets = new HashSet<Paintable>(); - - private static Timer lazySizeChangeTimer = new Timer() { - private boolean lazySizeChangeTimerScheduled = false; - - @Override - public void run() { - componentSizeUpdated(latelyChangedWidgets); - latelyChangedWidgets.clear(); - lazySizeChangeTimerScheduled = false; - } - - @Override - public void schedule(int delayMillis) { - if (lazySizeChangeTimerScheduled) { - cancel(); - } else { - lazySizeChangeTimerScheduled = true; - } - super.schedule(delayMillis); - } - }; - /** * This helper method can be called if components size have been changed * outside rendering phase. It notifies components parent about the size @@ -106,61 +79,37 @@ public class Util { * @param widget * @param lazy * run componentSizeUpdated lazyly - */ - public static void notifyParentOfSizeChange(Paintable widget, boolean lazy) { - if (lazy) { - latelyChangedWidgets.add(widget); - lazySizeChangeTimer.schedule(LAZY_SIZE_CHANGE_TIMEOUT); - } else { - Set<Paintable> widgets = new HashSet<Paintable>(); - widgets.add(widget); - Util.componentSizeUpdated(widgets); - } - } - - /** - * Called when the size of one or more widgets have changed during - * rendering. Finds parent container and notifies them of the size change. * - * @param paintables + * @deprecated since 7.0, use + * {@link LayoutManager#setNeedsMeasure(ComponentConnector)} + * instead */ - public static void componentSizeUpdated(Set<Paintable> paintables) { - if (paintables.isEmpty()) { - return; + @Deprecated + public static void notifyParentOfSizeChange(Widget widget, boolean lazy) { + ComponentConnector connector = findConnectorFor(widget); + if (connector != null) { + connector.getLayoutManager().setNeedsMeasure(connector); + if (!lazy) { + connector.getLayoutManager().layoutNow(); + } } + } - Map<Container, Set<Paintable>> childWidgets = new HashMap<Container, Set<Paintable>>(); - - for (Paintable paintable : paintables) { - Widget widget = (Widget) paintable; - if (!widget.isAttached()) { + private static ComponentConnector findConnectorFor(Widget widget) { + List<ApplicationConnection> runningApplications = ApplicationConfiguration + .getRunningApplications(); + for (ApplicationConnection applicationConnection : runningApplications) { + ConnectorMap connectorMap = applicationConnection.getConnectorMap(); + ComponentConnector connector = connectorMap.getConnector(widget); + if (connector == null) { continue; } - - // ApplicationConnection.getConsole().log( - // "Widget " + Util.getSimpleName(widget) + " size updated"); - Widget parent = widget.getParent(); - while (parent != null && !(parent instanceof Container)) { - parent = parent.getParent(); - } - if (parent != null) { - Set<Paintable> set = childWidgets.get(parent); - if (set == null) { - set = new HashSet<Paintable>(); - childWidgets.put((Container) parent, set); - } - set.add(paintable); - } - } - - Set<Paintable> parentChanges = new HashSet<Paintable>(); - for (Container parent : childWidgets.keySet()) { - if (!parent.requestLayout(childWidgets.get(parent))) { - parentChanges.add(parent); + if (connector.getConnection() == applicationConnection) { + return connector; } } - componentSizeUpdated(parentChanges); + return null; } public static float parseRelativeSize(String size) { @@ -176,68 +125,6 @@ public class Util { } } - /** - * Returns closest parent Widget in hierarchy that implements Container - * interface - * - * @param component - * @return closest parent Container - */ - public static Container getLayout(Widget component) { - Widget parent = component.getParent(); - while (parent != null && !(parent instanceof Container)) { - parent = parent.getParent(); - } - if (parent != null) { - assert ((Container) parent).hasChildComponent(component); - - return (Container) parent; - } - return null; - } - - /** - * Detects if current browser is IE. - * - * @deprecated use BrowserInfo class instead - * - * @return true if IE - */ - @Deprecated - public static boolean isIE() { - return BrowserInfo.get().isIE(); - } - - /** - * Detects if current browser is IE6. - * - * @deprecated use BrowserInfo class instead - * - * @return true if IE6 - */ - @Deprecated - public static boolean isIE6() { - return BrowserInfo.get().isIE6(); - } - - /** - * @deprecated use BrowserInfo class instead - * @return - */ - @Deprecated - public static boolean isIE7() { - return BrowserInfo.get().isIE7(); - } - - /** - * @deprecated use BrowserInfo class instead - * @return - */ - @Deprecated - public static boolean isFF2() { - return BrowserInfo.get().isFF2(); - } - private static final Element escapeHtmlHelper = DOM.createDiv(); /** @@ -249,8 +136,8 @@ public class Util { public static String escapeHTML(String html) { DOM.setInnerText(escapeHtmlHelper, html); String escapedText = DOM.getInnerHTML(escapeHtmlHelper); - if (BrowserInfo.get().isIE() && BrowserInfo.get().getIEVersion() < 9) { - // #7478 IE6-IE8 "incorrectly" returns "<br>" for newlines set using + if (BrowserInfo.get().isIE8()) { + // #7478 IE8 "incorrectly" returns "<br>" for newlines set using // setInnerText. The same for " " which is converted to " " escapedText = escapedText.replaceAll("<(BR|br)>", "\n"); escapedText = escapedText.replaceAll(" ", " "); @@ -275,48 +162,6 @@ public class Util { } /** - * Adds transparent PNG fix to image element; only use for IE6. - * - * @param el - * IMG element - */ - public native static void addPngFix(Element el) - /*-{ - el.attachEvent("onload", $entry(function() { - @com.vaadin.terminal.gwt.client.Util::doIE6PngFix(Lcom/google/gwt/user/client/Element;)(el); - }),false); - }-*/; - - private native static void doPngFix(Element el, String blankImageUrl) - /*-{ - var src = el.src; - if (src.indexOf(".png") < 1) return; - var w = el.width || 16; - var h = el.height || 16; - if(h==30 || w==28) { - setTimeout(function(){ - el.style.height = el.height + "px"; - el.style.width = el.width + "px"; - el.src = blankImageUrl; - },10); - } else { - el.src = blankImageUrl; - el.style.height = h + "px"; - el.style.width = w + "px"; - } - el.style.padding = "0"; - el.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+src+"', sizingMethod='crop')"; - }-*/; - - public static void doIE6PngFix(Element el) { - String blankImageUrl = GWT.getModuleBaseURL() + "ie6pngfix/blank.gif"; - String src = el.getAttribute("src"); - if (src != null && !src.equals(blankImageUrl)) { - doPngFix(el, blankImageUrl); - } - } - - /** * Clones given element as in JavaScript. * * Deprecate this if there appears similar method into GWT someday. @@ -334,11 +179,7 @@ public class Util { public static int measureHorizontalPaddingAndBorder(Element element, int paddingGuess) { String originalWidth = DOM.getStyleAttribute(element, "width"); - String originalOverflow = ""; - if (BrowserInfo.get().isIE6()) { - originalOverflow = DOM.getStyleAttribute(element, "overflow"); - DOM.setStyleAttribute(element, "overflow", "hidden"); - } + int originalOffsetWidth = element.getOffsetWidth(); int widthGuess = (originalOffsetWidth - paddingGuess); if (widthGuess < 1) { @@ -348,9 +189,7 @@ public class Util { int padding = element.getOffsetWidth() - widthGuess; DOM.setStyleAttribute(element, "width", originalWidth); - if (BrowserInfo.get().isIE6()) { - DOM.setStyleAttribute(element, "overflow", originalOverflow); - } + return padding; } @@ -378,23 +217,19 @@ public class Util { int offsetWidth = element.getOffsetWidth(); int offsetHeight = element.getOffsetHeight(); - if (!BrowserInfo.get().isIE7()) { - if (offsetHeight < 1) { - offsetHeight = 1; - } - if (offsetWidth < 1) { - offsetWidth = 10; - } - element.getStyle().setPropertyPx("height", offsetHeight); + if (offsetHeight < 1) { + offsetHeight = 1; + } + if (offsetWidth < 1) { + offsetWidth = 10; } + element.getStyle().setPropertyPx("height", offsetHeight); element.getStyle().setPropertyPx("width", offsetWidth); borders = element.getOffsetWidth() - element.getClientWidth(); element.getStyle().setProperty("width", width); - if (!BrowserInfo.get().isIE7()) { - element.getStyle().setProperty("height", height); - } + element.getStyle().setProperty("height", height); } else { borders = element.getOffsetWidth() - element.getPropertyInt("clientWidth"); @@ -412,7 +247,6 @@ public class Util { int offsetWidth = element.getOffsetWidth(); int offsetHeight = element.getOffsetHeight(); - // if (BrowserInfo.get().isIE6()) { if (offsetHeight < 1) { offsetHeight = 1; } @@ -420,7 +254,6 @@ public class Util { offsetWidth = 10; } element.getStyle().setPropertyPx("width", offsetWidth); - // } element.getStyle().setPropertyPx("height", offsetHeight); @@ -428,9 +261,7 @@ public class Util { - element.getPropertyInt("clientHeight"); element.getStyle().setProperty("height", height); - // if (BrowserInfo.get().isIE6()) { element.getStyle().setProperty("width", width); - // } } else { borders = element.getOffsetHeight() - element.getPropertyInt("clientHeight"); @@ -602,8 +433,7 @@ public class Util { public static void runWebkitOverflowAutoFix(final Element elem) { // Add max version if fix lands sometime to Webkit // Starting from Opera 11.00, also a problem in Opera - if ((BrowserInfo.get().getWebkitVersion() > 0 || BrowserInfo.get() - .getOperaVersion() >= 11) && getNativeScrollbarSize() > 0) { + if (BrowserInfo.get().requiresOverflowAutoFix()) { final String originalOverflow = elem.getStyle().getProperty( "overflow"); if ("hidden".equals(originalOverflow)) { @@ -662,39 +492,28 @@ public class Util { } /** - * Parses the UIDL parameter and fetches the relative size of the component. - * If a dimension is not specified as relative it will return -1. If the - * UIDL does not contain width or height specifications this will return + * Parses shared state and fetches the relative size of the component. If a + * dimension is not specified as relative it will return -1. If the shared + * state does not contain width or height specifications this will return * null. * - * @param uidl + * @param state * @return */ - public static FloatSize parseRelativeSize(UIDL uidl) { - boolean hasAttribute = false; - String w = ""; - String h = ""; - if (uidl.hasAttribute("width")) { - hasAttribute = true; - w = uidl.getStringAttribute("width"); - } - if (uidl.hasAttribute("height")) { - hasAttribute = true; - h = uidl.getStringAttribute("height"); - } - - if (!hasAttribute) { + public static FloatSize parseRelativeSize(ComponentState state) { + if (state.isUndefinedHeight() && state.isUndefinedWidth()) { return null; } - float relativeWidth = Util.parseRelativeSize(w); - float relativeHeight = Util.parseRelativeSize(h); + float relativeWidth = Util.parseRelativeSize(state.getWidth()); + float relativeHeight = Util.parseRelativeSize(state.getHeight()); FloatSize relativeSize = new FloatSize(relativeWidth, relativeHeight); return relativeSize; } + @Deprecated public static boolean isCached(UIDL uidl) { return uidl.getBooleanAttribute("cached"); } @@ -714,27 +533,8 @@ public class Util { } public static void updateRelativeChildrenAndSendSizeUpdateEvent( - ApplicationConnection client, HasWidgets container) { - updateRelativeChildrenAndSendSizeUpdateEvent(client, container, - (Paintable) container); - } - - public static void updateRelativeChildrenAndSendSizeUpdateEvent( - ApplicationConnection client, HasWidgets container, Paintable widget) { - /* - * Relative sized children must be updated first so the component has - * the correct outer dimensions when signaling a size change to the - * parent. - */ - Iterator<Widget> childIterator = container.iterator(); - while (childIterator.hasNext()) { - Widget w = childIterator.next(); - client.handleComponentRelativeSize(w); - } - - HashSet<Paintable> widgets = new HashSet<Paintable>(); - widgets.add(widget); - Util.componentSizeUpdated(widgets); + ApplicationConnection client, HasWidgets container, Widget widget) { + notifyParentOfSizeChange(widget, false); } public static native int getRequiredWidth( @@ -823,92 +623,13 @@ public class Util { }-*/; /** - * IE7 sometimes "forgets" to render content. This function runs a hack to - * workaround the bug if needed. This happens easily in framset. See #3295. - */ - public static void runIE7ZeroSizedBodyFix() { - if (BrowserInfo.get().isIE7()) { - int offsetWidth = RootPanel.getBodyElement().getOffsetWidth(); - if (offsetWidth == 0) { - shakeBodyElement(); - } - } - } - - /** - * Does some very small adjustments to body element. We need this just to - * overcome some IE bugs. - */ - public static void shakeBodyElement() { - final DivElement shaker = Document.get().createDivElement(); - RootPanel.getBodyElement().insertBefore(shaker, - RootPanel.getBodyElement().getFirstChildElement()); - shaker.getStyle().setPropertyPx("height", 0); - shaker.setInnerHTML(" "); - RootPanel.getBodyElement().removeChild(shaker); - - } - - /** - * Locates the child component of <literal>parent</literal> which contains - * the element <literal>element</literal>. The child component is also - * returned if "element" is part of its caption. If - * <literal>element</literal> is not part of any child component, null is - * returned. - * - * This method returns the immediate child of the parent that contains the - * element. See - * {@link #getPaintableForElement(ApplicationConnection, Container, Element)} - * for the deepest nested paintable of parent that contains the element. - * - * @param client - * A reference to ApplicationConnection - * @param parent - * The widget that contains <literal>element</literal>. - * @param element - * An element that is a sub element of the parent - * @return The Paintable which the element is a part of. Null if the element - * does not belong to a child. - */ - public static Paintable getChildPaintableForElement( - ApplicationConnection client, Container parent, Element element) { - Element rootElement = ((Widget) parent).getElement(); - while (element != null && element != rootElement) { - Paintable paintable = client.getPaintable(element); - if (paintable == null) { - String ownerPid = VCaption.getCaptionOwnerPid(element); - if (ownerPid != null) { - paintable = client.getPaintable(ownerPid); - } - } - - if (paintable != null) { - try { - if (parent.hasChildComponent((Widget) paintable)) { - return paintable; - } - } catch (ClassCastException e) { - // We assume everything is a widget however there is no need - // to crash everything if there is a paintable that is not. - } - } - - element = (Element) element.getParentElement(); - } - - return null; - } - - /** * Locates the nested child component of <literal>parent</literal> which * contains the element <literal>element</literal>. The child component is * also returned if "element" is part of its caption. If * <literal>element</literal> is not part of any child component, null is * returned. * - * This method returns the deepest nested Paintable. See - * {@link #getChildPaintableForElement(ApplicationConnection, Container, Element)} - * for the immediate child component of parent that contains the element. + * This method returns the deepest nested VPaintableWidget. * * @param client * A reference to ApplicationConnection @@ -916,18 +637,20 @@ public class Util { * The widget that contains <literal>element</literal>. * @param element * An element that is a sub element of the parent - * @return The Paintable which the element is a part of. Null if the element - * does not belong to a child. + * @return The VPaintableWidget which the element is a part of. Null if the + * element does not belong to a child. */ - public static Paintable getPaintableForElement( + public static ComponentConnector getConnectorForElement( ApplicationConnection client, Widget parent, Element element) { Element rootElement = parent.getElement(); while (element != null && element != rootElement) { - Paintable paintable = client.getPaintable(element); + ComponentConnector paintable = ConnectorMap.get(client) + .getConnector(element); if (paintable == null) { String ownerPid = VCaption.getCaptionOwnerPid(element); if (ownerPid != null) { - paintable = client.getPaintable(ownerPid); + paintable = (ComponentConnector) ConnectorMap.get(client) + .getConnector(ownerPid); } } @@ -965,6 +688,24 @@ public class Util { }-*/; /** + * Helper method to find the nearest parent paintable instance by traversing + * the DOM upwards from given element. + * + * @param element + * the element to start from + */ + public static ComponentConnector findPaintable( + ApplicationConnection client, Element element) { + Widget widget = Util.findWidget(element, null); + ConnectorMap vPaintableMap = ConnectorMap.get(client); + while (widget != null && !vPaintableMap.isConnector(widget)) { + widget = widget.getParent(); + } + return vPaintableMap.getConnector(widget); + + } + + /** * Helper method to find first instance of given Widget type found by * traversing DOM upwards from given element. * @@ -1071,14 +812,34 @@ public class Util { return idx; } - private static void printPaintablesVariables(ArrayList<String[]> vars, - String id, ApplicationConnection c) { - Paintable paintable = c.getPaintable(id); + private static void printPaintablesInvocations( + ArrayList<MethodInvocation> invocations, String id, + ApplicationConnection c) { + ComponentConnector paintable = (ComponentConnector) ConnectorMap.get(c) + .getConnector(id); if (paintable != null) { VConsole.log("\t" + id + " (" + paintable.getClass() + ") :"); - for (String[] var : vars) { - VConsole.log("\t\t" + var[1] + " (" + var[2] + ")" + " : " - + var[0]); + for (MethodInvocation invocation : invocations) { + Object[] parameters = invocation.getParameters(); + String formattedParams = null; + if (ApplicationConnection.UPDATE_VARIABLE_METHOD + .equals(invocation.getMethodName()) + && parameters.length == 2) { + // name, value + Object value = parameters[1]; + // TODO paintables inside lists/maps get rendered as + // components in the debug console + String formattedValue = value instanceof ServerConnector ? ((ServerConnector) value) + .getConnectorId() : String.valueOf(value); + formattedParams = parameters[0] + " : " + formattedValue; + } + if (null == formattedParams) { + formattedParams = (null != parameters) ? Arrays + .toString(parameters) : null; + } + VConsole.log("\t\t" + invocation.getInterfaceName() + "." + + invocation.getMethodName() + "(" + formattedParams + + ")"); } } else { VConsole.log("\t" + id + ": Warning: no corresponding paintable!"); @@ -1086,31 +847,25 @@ public class Util { } static void logVariableBurst(ApplicationConnection c, - ArrayList<String> loggedBurst) { + ArrayList<MethodInvocation> loggedBurst) { try { VConsole.log("Variable burst to be sent to server:"); String curId = null; - ArrayList<String[]> vars = new ArrayList<String[]>(); + ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>(); for (int i = 0; i < loggedBurst.size(); i++) { - String value = loggedBurst.get(i++); - String[] split = loggedBurst - .get(i) - .split(String - .valueOf(ApplicationConnection.VAR_FIELD_SEPARATOR)); - String id = split[0]; + String id = loggedBurst.get(i).getConnectorId(); if (curId == null) { curId = id; } else if (!curId.equals(id)) { - printPaintablesVariables(vars, curId, c); - vars.clear(); + printPaintablesInvocations(invocations, curId, c); + invocations.clear(); curId = id; } - split[0] = value; - vars.add(split); + invocations.add(loggedBurst.get(i)); } - if (!vars.isEmpty()) { - printPaintablesVariables(vars, curId, c); + if (!invocations.isEmpty()) { + printPaintablesInvocations(invocations, curId, c); } } catch (Exception e) { VConsole.error(e); @@ -1334,4 +1089,49 @@ public class Util { boolean touchEvent = Util.isTouchEvent(event); return touchEvent || event.getButton() == Event.BUTTON_LEFT; } + + /** + * Performs a shallow comparison of the collections. + * + * @param collection1 + * The first collection + * @param collection2 + * The second collection + * @return true if the collections contain the same elements in the same + * order, false otherwise + */ + public static boolean collectionsEquals(Collection collection1, + Collection collection2) { + if (collection1 == null) { + return collection2 == null; + } + if (collection2 == null) { + return false; + } + Iterator<Object> collection1Iterator = collection1.iterator(); + Iterator<Object> collection2Iterator = collection2.iterator(); + + while (collection1Iterator.hasNext()) { + if (!collection2Iterator.hasNext()) { + return false; + } + Object collection1Object = collection1Iterator.next(); + Object collection2Object = collection2Iterator.next(); + if (collection1Object != collection2Object) { + return false; + } + } + if (collection2Iterator.hasNext()) { + return false; + } + + return true; + } + + public static String getConnectorString(ServerConnector p) { + if (p == null) { + return "null"; + } + return getSimpleName(p) + " (" + p.getConnectorId() + ")"; + } } diff --git a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java index aaef981bab..89e106f063 100644 --- a/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java +++ b/src/com/vaadin/terminal/gwt/client/VBrowserDetails.java @@ -22,6 +22,9 @@ public class VBrowserDetails implements Serializable { private boolean isWebKit = false; private boolean isPresto = false; + private boolean isChromeFrameCapable = false; + private boolean isChromeFrame = false; + private boolean isSafari = false; private boolean isChrome = false; private boolean isFirefox = false; @@ -59,6 +62,10 @@ public class VBrowserDetails implements Serializable { && (userAgent.indexOf("webtv") == -1); isFirefox = userAgent.indexOf(" firefox/") != -1; + // chromeframe + isChromeFrameCapable = userAgent.indexOf("chromeframe") != -1; + isChromeFrame = isChromeFrameCapable && !isChrome; + // Rendering engine version try { if (isGecko) { @@ -210,6 +217,24 @@ public class VBrowserDetails implements Serializable { } /** + * Tests if the browser is capable of running ChromeFrame. + * + * @return true if it has ChromeFrame, false otherwise + */ + public boolean isChromeFrameCapable() { + return isChromeFrameCapable; + } + + /** + * Tests if the browser is running ChromeFrame. + * + * @return true if it is ChromeFrame, false otherwise + */ + public boolean isChromeFrame() { + return isChromeFrame; + } + + /** * Tests if the browser is Opera. * * @return true if it is Opera, false otherwise @@ -302,4 +327,30 @@ public class VBrowserDetails implements Serializable { return isLinux; } + /** + * Checks if the browser is so old that it simply won't work with a Vaadin + * application. NOTE that the browser might still be capable of running + * Crome Frame, so you might still want to check + * {@link #isChromeFrameCapable()} if this returns true. + * + * @return true if the browser won't work, false if not the browser is + * supported or might work + */ + public boolean isTooOldToFunctionProperly() { + if (isIE() && getBrowserMajorVersion() < 8) { + return true; + } + if (isSafari() && getBrowserMajorVersion() < 5) { + return true; + } + if (isFirefox() && getBrowserMajorVersion() < 4) { + return true; + } + if (isOpera() && getBrowserMajorVersion() < 11) { + return true; + } + + return false; + } + } diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java index c4b61d2544..6f3fcf2c3a 100644 --- a/src/com/vaadin/terminal/gwt/client/VCaption.java +++ b/src/com/vaadin/terminal/gwt/client/VCaption.java @@ -8,13 +8,14 @@ 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.HTML; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; import com.vaadin.terminal.gwt.client.ui.Icon; public class VCaption extends HTML { public static final String CLASSNAME = "v-caption"; - private final Paintable owner; + private final ComponentConnector owner; private Element errorIndicatorElement; @@ -24,38 +25,52 @@ public class VCaption extends HTML { private Element captionText; - private Element clearElement; - private final ApplicationConnection client; private boolean placedAfterComponent = false; - private boolean iconOnloadHandled = false; private int maxWidth = -1; - protected static final String ATTRIBUTE_ICON = "icon"; - protected static final String ATTRIBUTE_CAPTION = "caption"; - protected static final String ATTRIBUTE_DESCRIPTION = "description"; - protected static final String ATTRIBUTE_REQUIRED = "required"; - protected static final String ATTRIBUTE_ERROR = "error"; - protected static final String ATTRIBUTE_HIDEERRORS = "hideErrors"; + private enum InsertPosition { + ICON, CAPTION, REQUIRED, ERROR + } - private static final String CLASSNAME_CLEAR = CLASSNAME + "-clearelem"; + /** + * Creates a caption that is not linked to a {@link ComponentConnector}. + * + * When using this constructor, {@link #getOwner()} returns null. + * + * @param client + * ApplicationConnection + * @deprecated all captions should be associated with a paintable widget and + * be updated from shared state, not UIDL + */ + @Deprecated + public VCaption(ApplicationConnection client) { + super(); + this.client = client; + owner = null; + + setStyleName(CLASSNAME); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + + } /** + * Creates a caption for a {@link ComponentConnector}. * * @param component - * optional owner of caption. If not set, getOwner will return - * null + * owner of caption, not null * @param client + * ApplicationConnection */ - public VCaption(Paintable component, ApplicationConnection client) { + public VCaption(ComponentConnector component, ApplicationConnection client) { super(); this.client = client; owner = component; if (client != null && owner != null) { - setOwnerPid(getElement(), client.getPid(owner)); + setOwnerPid(getElement(), owner.getConnectorId()); } setStyleName(CLASSNAME); @@ -66,13 +81,13 @@ public class VCaption extends HTML { /** * Updates the caption from UIDL. * - * @param uidl + * This method may only be called when the caption has an owner - otherwise, + * use {@link #updateCaptionWithoutOwner(UIDL, String, boolean, boolean)}. + * * @return true if the position where the caption should be placed has * changed */ - public boolean updateCaption(UIDL uidl) { - setVisible(!uidl.getBooleanAttribute("invisible")); - + public boolean updateCaption() { boolean wasPlacedAfterComponent = placedAfterComponent; // Caption is placed after component unless there is some part which @@ -80,25 +95,27 @@ public class VCaption extends HTML { placedAfterComponent = true; String style = CLASSNAME; - if (uidl.hasAttribute("style")) { - final String[] styles = uidl.getStringAttribute("style").split(" "); - for (int i = 0; i < styles.length; i++) { - style += " " + CLASSNAME + "-" + styles[i]; + if (owner.getState().hasStyles()) { + for (String customStyle : owner.getState().getStyles()) { + style += " " + CLASSNAME + "-" + customStyle; } } - - if (uidl.hasAttribute("disabled")) { + if (!owner.isEnabled()) { style += " " + ApplicationConnection.DISABLED_CLASSNAME; } - setStyleName(style); - boolean hasIcon = uidl.hasAttribute(ATTRIBUTE_ICON); - boolean hasText = uidl.hasAttribute(ATTRIBUTE_CAPTION); - boolean hasDescription = uidl.hasAttribute(ATTRIBUTE_DESCRIPTION); - boolean showRequired = uidl.getBooleanAttribute(ATTRIBUTE_REQUIRED); - boolean showError = uidl.hasAttribute(ATTRIBUTE_ERROR) - && !uidl.getBooleanAttribute(ATTRIBUTE_HIDEERRORS); + boolean hasIcon = owner.getState().getIcon() != null; + boolean showRequired = false; + boolean showError = owner.getState().getErrorMessage() != null; + if (owner.getState() instanceof AbstractFieldState) { + AbstractFieldState abstractFieldState = (AbstractFieldState) owner + .getState(); + showError = showError && !abstractFieldState.isHideErrors(); + } + if (owner instanceof AbstractFieldConnector) { + showRequired = ((AbstractFieldConnector) owner).isRequired(); + } if (hasIcon) { if (icon == null) { @@ -107,13 +124,12 @@ public class VCaption extends HTML { icon.setHeight("0"); DOM.insertChild(getElement(), icon.getElement(), - getInsertPosition(ATTRIBUTE_ICON)); + getInsertPosition(InsertPosition.ICON)); } // Icon forces the caption to be above the component placedAfterComponent = false; - iconOnloadHandled = false; - icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON)); + icon.setUri(owner.getState().getIcon().getURL()); } else if (icon != null) { // Remove existing @@ -121,7 +137,7 @@ public class VCaption extends HTML { icon = null; } - if (hasText) { + if (owner.getState().getCaption() != null) { // A caption text should be shown if the attribute is set // If the caption is null the ATTRIBUTE_CAPTION should not be set to // avoid ending up here. @@ -131,11 +147,11 @@ public class VCaption extends HTML { captionText.setClassName("v-captiontext"); DOM.insertChild(getElement(), captionText, - getInsertPosition(ATTRIBUTE_CAPTION)); + getInsertPosition(InsertPosition.CAPTION)); } // Update caption text - String c = uidl.getStringAttribute(ATTRIBUTE_CAPTION); + String c = owner.getState().getCaption(); // A text forces the caption to be above the component. placedAfterComponent = false; if (c == null || c.trim().equals("")) { @@ -158,12 +174,10 @@ public class VCaption extends HTML { captionText = null; } - if (hasDescription) { - if (captionText != null) { - addStyleDependentName("hasdescription"); - } else { - removeStyleDependentName("hasdescription"); - } + if (owner.getState().hasDescription() && captionText != null) { + addStyleDependentName("hasdescription"); + } else { + removeStyleDependentName("hasdescription"); } if (showRequired) { @@ -174,7 +188,7 @@ public class VCaption extends HTML { DOM.setInnerText(requiredFieldIndicator, "*"); DOM.insertChild(getElement(), requiredFieldIndicator, - getInsertPosition(ATTRIBUTE_REQUIRED)); + getInsertPosition(InsertPosition.REQUIRED)); } } else if (requiredFieldIndicator != null) { // Remove existing @@ -190,7 +204,7 @@ public class VCaption extends HTML { "v-errorindicator"); DOM.insertChild(getElement(), errorIndicatorElement, - getInsertPosition(ATTRIBUTE_ERROR)); + getInsertPosition(InsertPosition.ERROR)); } } else if (errorIndicatorElement != null) { // Remove existing @@ -198,25 +212,19 @@ public class VCaption extends HTML { errorIndicatorElement = null; } - if (clearElement == null) { - clearElement = DOM.createDiv(); - clearElement.setClassName(CLASSNAME_CLEAR); - getElement().appendChild(clearElement); - } - return (wasPlacedAfterComponent != placedAfterComponent); } - private int getInsertPosition(String element) { + private int getInsertPosition(InsertPosition element) { int pos = 0; - if (element.equals(ATTRIBUTE_ICON)) { + if (InsertPosition.ICON.equals(element)) { return pos; } if (icon != null) { pos++; } - if (element.equals(ATTRIBUTE_CAPTION)) { + if (InsertPosition.CAPTION.equals(element)) { return pos; } @@ -224,19 +232,115 @@ public class VCaption extends HTML { pos++; } - if (element.equals(ATTRIBUTE_REQUIRED)) { + if (InsertPosition.REQUIRED.equals(element)) { return pos; } if (requiredFieldIndicator != null) { pos++; } - // if (element.equals(ATTRIBUTE_ERROR)) { + // if (InsertPosition.ERROR.equals(element)) { // } return pos; } + @Deprecated + public boolean updateCaptionWithoutOwner(String caption, boolean disabled, + boolean hasDescription, boolean hasError, String iconURL) { + boolean wasPlacedAfterComponent = placedAfterComponent; + + // Caption is placed after component unless there is some part which + // moves it above. + placedAfterComponent = true; + + String style = VCaption.CLASSNAME; + if (disabled) { + style += " " + ApplicationConnection.DISABLED_CLASSNAME; + } + setStyleName(style); + if (hasDescription) { + if (captionText != null) { + addStyleDependentName("hasdescription"); + } else { + removeStyleDependentName("hasdescription"); + } + } + boolean hasIcon = iconURL != null; + + if (hasIcon) { + if (icon == null) { + icon = new Icon(client); + icon.setWidth("0"); + icon.setHeight("0"); + + DOM.insertChild(getElement(), icon.getElement(), + getInsertPosition(InsertPosition.ICON)); + } + // Icon forces the caption to be above the component + placedAfterComponent = false; + + icon.setUri(iconURL); + + } else if (icon != null) { + // Remove existing + DOM.removeChild(getElement(), icon.getElement()); + icon = null; + } + + if (caption != null) { + // A caption text should be shown if the attribute is set + // If the caption is null the ATTRIBUTE_CAPTION should not be set to + // avoid ending up here. + + if (captionText == null) { + captionText = DOM.createDiv(); + captionText.setClassName("v-captiontext"); + + DOM.insertChild(getElement(), captionText, + getInsertPosition(InsertPosition.CAPTION)); + } + + // Update caption text + // A text forces the caption to be above the component. + placedAfterComponent = false; + if (caption.trim().equals("")) { + // This is required to ensure that the caption uses space in all + // browsers when it is set to the empty string. If there is an + // icon, error indicator or required indicator they will ensure + // that space is reserved. + if (!hasIcon && !hasError) { + captionText.setInnerHTML(" "); + } + } else { + DOM.setInnerText(captionText, caption); + } + + } else if (captionText != null) { + // Remove existing + DOM.removeChild(getElement(), captionText); + captionText = null; + } + + if (hasError) { + if (errorIndicatorElement == null) { + errorIndicatorElement = DOM.createDiv(); + DOM.setInnerHTML(errorIndicatorElement, " "); + DOM.setElementProperty(errorIndicatorElement, "className", + "v-errorindicator"); + + DOM.insertChild(getElement(), errorIndicatorElement, + getInsertPosition(InsertPosition.ERROR)); + } + } else if (errorIndicatorElement != null) { + // Remove existing + getElement().removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + + return (wasPlacedAfterComponent != placedAfterComponent); + } + @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); @@ -246,16 +350,10 @@ public class VCaption extends HTML { } if (DOM.eventGetType(event) == Event.ONLOAD - && icon.getElement() == target && !iconOnloadHandled) { + && icon.getElement() == target) { icon.setWidth(""); icon.setHeight(""); - /* - * IE6 pngFix causes two onload events to be fired and we want to - * react only to the first one - */ - iconOnloadHandled = true; - // if max width defined, recalculate if (maxWidth != -1) { setMaxWidth(maxWidth); @@ -272,24 +370,21 @@ public class VCaption extends HTML { * the responsibility of reacting to ONLOAD from VCaption to layouts */ if (owner != null) { - Util.notifyParentOfSizeChange(owner, true); + Util.notifyParentOfSizeChange(owner.getWidget(), true); } else { VConsole.log("Warning: Icon load event was not propagated because VCaption owner is unknown."); } } } - public static boolean isNeeded(UIDL uidl) { - if (uidl.getStringAttribute(ATTRIBUTE_CAPTION) != null) { - return true; - } - if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { + public static boolean isNeeded(ComponentState state) { + if (state.getCaption() != null) { return true; } - if (uidl.hasAttribute(ATTRIBUTE_ICON)) { + if (state.getIcon() != null) { return true; } - if (uidl.hasAttribute(ATTRIBUTE_REQUIRED)) { + if (state.getErrorMessage() != null) { return true; } @@ -301,7 +396,7 @@ public class VCaption extends HTML { * * @return owner Widget */ - public Paintable getOwner() { + public ComponentConnector getOwner() { return owner; } diff --git a/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java b/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java index dbecf96dd0..a8dabb8652 100644 --- a/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java +++ b/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java @@ -5,28 +5,35 @@ package com.vaadin.terminal.gwt.client; import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.Widget; public class VCaptionWrapper extends FlowPanel { public static final String CLASSNAME = "v-captionwrapper"; VCaption caption; - Paintable widget; + ComponentConnector wrappedConnector; - public VCaptionWrapper(Paintable toBeWrapped, ApplicationConnection client) { + /** + * Creates a new caption wrapper panel. + * + * @param toBeWrapped + * paintable that the caption is associated with, not null + * @param client + * ApplicationConnection + */ + public VCaptionWrapper(ComponentConnector toBeWrapped, + ApplicationConnection client) { caption = new VCaption(toBeWrapped, client); add(caption); - widget = toBeWrapped; - add((Widget) widget); + wrappedConnector = toBeWrapped; + add(wrappedConnector.getWidget()); setStyleName(CLASSNAME); } - public void updateCaption(UIDL uidl) { - caption.updateCaption(uidl); - setVisible(!uidl.getBooleanAttribute("invisible")); + public void updateCaption() { + caption.updateCaption(); } - public Paintable getPaintable() { - return widget; + public ComponentConnector getWrappedConnector() { + return wrappedConnector; } } diff --git a/src/com/vaadin/terminal/gwt/client/VConsole.java b/src/com/vaadin/terminal/gwt/client/VConsole.java index a01fa16558..dee8529a84 100644 --- a/src/com/vaadin/terminal/gwt/client/VConsole.java +++ b/src/com/vaadin/terminal/gwt/client/VConsole.java @@ -82,8 +82,8 @@ public class VConsole { public static void printLayoutProblems(ValueMap meta, ApplicationConnection applicationConnection, - Set<Paintable> zeroHeightComponents, - Set<Paintable> zeroWidthComponents) { + Set<ComponentConnector> zeroHeightComponents, + Set<ComponentConnector> zeroWidthComponents) { impl.printLayoutProblems(meta, applicationConnection, zeroHeightComponents, zeroWidthComponents); } diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java index 19b478b098..5eaf78f255 100644 --- a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java +++ b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java @@ -4,6 +4,9 @@ package com.vaadin.terminal.gwt.client; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -19,6 +22,8 @@ import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.MouseOutEvent; +import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.UmbrellaException; import com.google.gwt.http.client.Request; @@ -27,6 +32,7 @@ import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.gwt.http.client.UrlBuilder; +import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -48,6 +54,9 @@ import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.notification.VNotification; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; +import com.vaadin.terminal.gwt.client.ui.window.WindowConnector; /** * A helper console for client side development. The debug console can also be @@ -90,17 +99,17 @@ public class VDebugConsole extends VOverlay implements Console { for (ApplicationConnection a : ApplicationConfiguration .getRunningApplications()) { - Paintable paintable = Util.getPaintableForElement(a, - a.getView(), eventTarget); - if (paintable == null) { - paintable = Util.getPaintableForElement(a, + ComponentConnector connector = Util.getConnectorForElement( + a, a.getRootConnector().getWidget(), eventTarget); + if (connector == null) { + connector = Util.getConnectorForElement(a, RootPanel.get(), eventTarget); } - if (paintable != null) { - String pid = a.getPid(paintable); - VUIDLBrowser.highlight(paintable); + if (connector != null) { + String pid = connector.getConnectorId(); + VUIDLBrowser.highlight(connector); label.setText("Currently focused :" - + paintable.getClass() + " ID:" + pid); + + connector.getClass() + " ID:" + pid); event.cancel(); event.consume(); event.getNativeEvent().stopPropagation(); @@ -119,10 +128,10 @@ public class VDebugConsole extends VOverlay implements Console { .getClientY()); for (ApplicationConnection a : ApplicationConfiguration .getRunningApplications()) { - Paintable paintable = Util.getPaintableForElement(a, - a.getView(), eventTarget); + ComponentConnector paintable = Util.getConnectorForElement( + a, a.getRootConnector().getWidget(), eventTarget); if (paintable == null) { - paintable = Util.getPaintableForElement(a, + paintable = Util.getConnectorForElement(a, RootPanel.get(), eventTarget); } @@ -150,6 +159,7 @@ public class VDebugConsole extends VOverlay implements Console { private Button analyzeLayout = new Button("AL"); private Button savePosition = new Button("S"); private Button highlight = new Button("H"); + private Button connectorStats = new Button("CS"); private CheckBox hostedMode = new CheckBox("GWT"); private CheckBox autoScroll = new CheckBox("Autoscroll "); private HorizontalPanel actions; @@ -336,11 +346,13 @@ public class VDebugConsole extends VOverlay implements Console { if (msg == null) { msg = "null"; } + msg = addTimestamp(msg); // remoteLog(msg); logToDebugWindow(msg, false); GWT.log(msg); consoleLog(msg); + System.out.println(msg); } private List<String> msgQueue = new LinkedList<String>(); @@ -426,11 +438,22 @@ public class VDebugConsole extends VOverlay implements Console { if (msg == null) { msg = "null"; } - + msg = addTimestamp(msg); logToDebugWindow(msg, true); GWT.log(msg); consoleErr(msg); + System.out.println(msg); + + } + + DateTimeFormat timestampFormat = DateTimeFormat.getFormat("HH:mm:ss:SSS"); + + @SuppressWarnings("deprecation") + private String addTimestamp(String msg) { + Date date = new Date(); + String timestamp = timestampFormat.format(date); + return timestamp + " " + msg; } /* @@ -496,8 +519,8 @@ public class VDebugConsole extends VOverlay implements Console { }-*/; public void printLayoutProblems(ValueMap meta, ApplicationConnection ac, - Set<Paintable> zeroHeightComponents, - Set<Paintable> zeroWidthComponents) { + Set<ComponentConnector> zeroHeightComponents, + Set<ComponentConnector> zeroWidthComponents) { JsArray<ValueMap> valueMapArray = meta .getJSValueMapArray("invalidLayouts"); int size = valueMapArray.length(); @@ -534,9 +557,10 @@ public class VDebugConsole extends VOverlay implements Console { } private void printClientSideDetectedIssues( - Set<Paintable> zeroHeightComponents, ApplicationConnection ac) { - for (final Paintable paintable : zeroHeightComponents) { - final Container layout = Util.getLayout((Widget) paintable); + Set<ComponentConnector> zeroHeightComponents, + ApplicationConnection ac) { + for (final ComponentConnector paintable : zeroHeightComponents) { + final Widget layout = paintable.getParent().getWidget(); VerticalPanel errorDetails = new VerticalPanel(); errorDetails.add(new Label("" + Util.getSimpleName(paintable) @@ -546,7 +570,7 @@ public class VDebugConsole extends VOverlay implements Console { emphasisInUi.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { if (paintable != null) { - Element element2 = ((Widget) layout).getElement(); + Element element2 = layout.getElement(); Widget.setStyleName(element2, "invalidlayout", emphasisInUi.getValue()); } @@ -560,7 +584,8 @@ public class VDebugConsole extends VOverlay implements Console { private void printLayoutError(ValueMap valueMap, SimpleTree root, final ApplicationConnection ac) { final String pid = valueMap.getString("id"); - final Paintable paintable = ac.getPaintable(pid); + final ComponentConnector paintable = (ComponentConnector) ConnectorMap + .get(ac).getConnector(pid); SimpleTree errorNode = new SimpleTree(); VerticalPanel errorDetails = new VerticalPanel(); @@ -578,7 +603,7 @@ public class VDebugConsole extends VOverlay implements Console { emphasisInUi.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { if (paintable != null) { - Element element2 = ((Widget) paintable).getElement(); + Element element2 = paintable.getWidget().getElement(); Widget.setStyleName(element2, "invalidlayout", emphasisInUi.getValue()); } @@ -614,15 +639,34 @@ public class VDebugConsole extends VOverlay implements Console { } public void error(Throwable e) { + handleError(e, this); + } + + static void handleError(Throwable e, Console target) { if (e instanceof UmbrellaException) { UmbrellaException ue = (UmbrellaException) e; for (Throwable t : ue.getCauses()) { - error(t); + target.error(t); } return; } - error(Util.getSimpleName(e) + ": " + e.getMessage()); + String exceptionText = Util.getSimpleName(e); + String message = e.getMessage(); + if (message != null && message.length() != 0) { + exceptionText += ": " + e.getMessage(); + } + target.error(exceptionText); GWT.log(e.getMessage(), e); + if (!GWT.isProdMode()) { + e.printStackTrace(); + } + try { + VNotification.createNotification(VNotification.DELAY_FOREVER).show( + "<h1>Uncaught client side exception</h1><br />" + + exceptionText, VNotification.CENTERED, "error"); + } catch (Exception e2) { + // Just swallow this exception + } } public void init() { @@ -661,6 +705,8 @@ public class VDebugConsole extends VOverlay implements Console { actions.add(forceLayout); actions.add(analyzeLayout); actions.add(highlight); + actions.add(connectorStats); + connectorStats.setTitle("Show connector statistics for client"); highlight .setTitle("Select a component and print details about it to the server log and client side console."); actions.add(savePosition); @@ -788,6 +834,15 @@ public class VDebugConsole extends VOverlay implements Console { }); } + connectorStats.addClickHandler(new ClickHandler() { + + public void onClick(ClickEvent event) { + for (ApplicationConnection a : ApplicationConfiguration + .getRunningApplications()) { + dumpConnectorInfo(a); + } + } + }); log("Starting Vaadin client side engine. Widgetset: " + GWT.getModuleName()); @@ -802,6 +857,93 @@ public class VDebugConsole extends VOverlay implements Console { } + protected void dumpConnectorInfo(ApplicationConnection a) { + RootConnector root = a.getRootConnector(); + log("================"); + log("Connector hierarchy for Root: " + root.getState().getCaption() + + " (" + root.getConnectorId() + ")"); + Set<ComponentConnector> connectorsInHierarchy = new HashSet<ComponentConnector>(); + SimpleTree rootHierachy = dumpConnectorHierarchy(root, "", + connectorsInHierarchy); + if (panel.isAttached()) { + rootHierachy.open(true); + panel.add(rootHierachy); + } + + ConnectorMap connectorMap = a.getConnectorMap(); + Collection<? extends ServerConnector> registeredConnectors = connectorMap + .getConnectors(); + log("Sub windows:"); + Set<ComponentConnector> subWindowHierarchyConnectors = new HashSet<ComponentConnector>(); + for (WindowConnector wc : root.getSubWindows()) { + SimpleTree windowHierachy = dumpConnectorHierarchy(wc, "", + subWindowHierarchyConnectors); + if (panel.isAttached()) { + windowHierachy.open(true); + panel.add(windowHierachy); + } + } + log("Registered connectors not in hierarchy (should be empty):"); + for (ServerConnector registeredConnector : registeredConnectors) { + + if (connectorsInHierarchy.contains(registeredConnector)) { + continue; + } + + if (subWindowHierarchyConnectors.contains(registeredConnector)) { + continue; + } + error(getConnectorString(registeredConnector)); + + } + log("Unregistered connectors in hierarchy (should be empty):"); + for (ServerConnector hierarchyConnector : connectorsInHierarchy) { + if (!connectorMap.hasConnector(hierarchyConnector.getConnectorId())) { + error(getConnectorString(hierarchyConnector)); + } + + } + + log("================"); + + } + + private SimpleTree dumpConnectorHierarchy( + final ComponentConnector connector, String indent, + Set<ComponentConnector> connectors) { + SimpleTree simpleTree = new SimpleTree(getConnectorString(connector)) { + @Override + protected void select(ClickEvent event) { + super.select(event); + VUIDLBrowser.highlight(connector); + } + }; + simpleTree.addDomHandler(new MouseOutHandler() { + public void onMouseOut(MouseOutEvent event) { + VUIDLBrowser.deHiglight(); + } + }, MouseOutEvent.getType()); + connectors.add(connector); + + String msg = indent + "* " + getConnectorString(connector); + GWT.log(msg); + consoleLog(msg); + System.out.println(msg); + + if (connector instanceof ComponentContainerConnector) { + for (ComponentConnector c : ((ComponentContainerConnector) connector) + .getChildren()) { + simpleTree.add(dumpConnectorHierarchy(c, indent + " ", + connectors)); + } + } + return simpleTree; + } + + private static String getConnectorString(ServerConnector connector) { + return Util.getConnectorString(connector); + } + public void setQuietMode(boolean quietDebugMode) { quietMode = quietDebugMode; } diff --git a/src/com/vaadin/terminal/gwt/client/VErrorMessage.java b/src/com/vaadin/terminal/gwt/client/VErrorMessage.java index 58bdccaf55..add6ee4780 100644 --- a/src/com/vaadin/terminal/gwt/client/VErrorMessage.java +++ b/src/com/vaadin/terminal/gwt/client/VErrorMessage.java @@ -4,8 +4,6 @@ package com.vaadin.terminal.gwt.client; -import java.util.Iterator; - import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.FlowPanel; @@ -20,30 +18,13 @@ public class VErrorMessage extends FlowPanel { setStyleName(CLASSNAME); } - public void updateFromUIDL(UIDL uidl) { + public void updateMessage(String htmlErrorMessage) { clear(); - if (uidl.getChildCount() == 0) { + if (htmlErrorMessage == null || htmlErrorMessage.length() == 0) { add(new HTML(" ")); } else { - for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext();) { - final Object child = it.next(); - if (child instanceof String) { - final String errorMessage = (String) child; - add(new HTML(errorMessage)); - } else { - try { - final VErrorMessage childError = new VErrorMessage(); - childError.updateFromUIDL((UIDL) child); - add(childError); - } catch (Exception e) { - // TODO XML type error, check if this can even happen - // anymore?? - final UIDL.XML xml = (UIDL.XML) child; - add(new HTML(xml.getXMLAsString())); - - } - } - } + // pre-formatted on the server as div per child + add(new HTML(htmlErrorMessage)); } } diff --git a/src/com/vaadin/terminal/gwt/client/VTooltip.java b/src/com/vaadin/terminal/gwt/client/VTooltip.java index 974e2f1f32..70f4a0de0a 100644 --- a/src/com/vaadin/terminal/gwt/client/VTooltip.java +++ b/src/com/vaadin/terminal/gwt/client/VTooltip.java @@ -27,7 +27,7 @@ public class VTooltip extends VOverlay { private static final int QUICK_OPEN_DELAY = 100; VErrorMessage em = new VErrorMessage(); Element description = DOM.createDiv(); - private Paintable tooltipOwner; + private ComponentConnector tooltipOwner; private boolean closing = false; private boolean opening = false; @@ -56,9 +56,9 @@ public class VTooltip extends VOverlay { */ private void show(TooltipInfo info) { boolean hasContent = false; - if (info.getErrorUidl() != null) { + if (info.getErrorMessage() != null) { em.setVisible(true); - em.updateFromUIDL(info.getErrorUidl()); + em.updateMessage(info.getErrorMessage()); hasContent = true; } else { em.setVisible(false); @@ -115,7 +115,7 @@ public class VTooltip extends VOverlay { } } - public void showTooltip(Paintable owner, Event event, Object key) { + public void showTooltip(ComponentConnector owner, Event event, Object key) { if (closing && tooltipOwner == owner && tooltipKey == key) { // return to same tooltip, cancel closing closeTimer.cancel(); @@ -212,7 +212,8 @@ public class VTooltip extends VOverlay { } - public void handleTooltipEvent(Event event, Paintable owner, Object key) { + public void handleTooltipEvent(Event event, ComponentConnector owner, + Object key) { final int type = DOM.eventGetType(event); if ((VTooltip.TOOLTIP_EVENTS & type) == type) { if (type == Event.ONMOUSEOVER) { diff --git a/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java b/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java index 95d2fd0b5f..9fa973dc29 100644 --- a/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java +++ b/src/com/vaadin/terminal/gwt/client/VUIDLBrowser.java @@ -24,9 +24,8 @@ import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ui.VUnknownComponent; -import com.vaadin.terminal.gwt.client.ui.VView; -import com.vaadin.terminal.gwt.client.ui.VWindow; +import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector; +import com.vaadin.terminal.gwt.client.ui.window.VWindow; public class VUIDLBrowser extends SimpleTree { private static final String HELP = "Shift click handle to open recursively. Click components to hightlight them on client side. Shift click components to highlight them also on the server side."; @@ -47,7 +46,9 @@ public class VUIDLBrowser extends SimpleTree { } Set<String> keySet = u.getKeySet(); for (String key : keySet) { - if (key.equals("changes")) { + if (key.equals("state")) { + // TODO print updated shared states + } else if (key.equals("changes")) { JsArray<UIDL> jsValueMapArray = u.getJSValueMapArray("changes") .cast(); for (int i = 0; i < jsValueMapArray.length(); i++) { @@ -77,8 +78,7 @@ public class VUIDLBrowser extends SimpleTree { try { String name = uidl.getTag(); try { - Integer.parseInt(name); - name = getNodeName(uidl, conf, name); + name = getNodeName(uidl, conf, Integer.parseInt(name)); } catch (Exception e) { // NOP } @@ -97,15 +97,12 @@ public class VUIDLBrowser extends SimpleTree { } private String getNodeName(UIDL uidl, ApplicationConfiguration conf, - String name) { - Class<? extends Paintable> widgetClassByDecodedTag = conf - .getWidgetClassByEncodedTag(name); - if (widgetClassByDecodedTag == VUnknownComponent.class) { - return conf.getUnknownServerClassNameByEncodedTagName(name) + int tag) { + Class<? extends ComponentConnector> widgetClassByDecodedTag = conf + .getWidgetClassByEncodedTag(tag); + if (widgetClassByDecodedTag == UnknownComponentConnector.class) { + return conf.getUnknownServerClassNameByTag(tag) + "(NO CLIENT IMPLEMENTATION FOUND)"; - } else if (widgetClassByDecodedTag == VView.class - && uidl.hasAttribute("sub")) { - return "com.vaadin.terminal.gwt.ui.VWindow"; } else { return widgetClassByDecodedTag.getName(); } @@ -130,8 +127,8 @@ public class VUIDLBrowser extends SimpleTree { // same // host page for (ApplicationConnection applicationConnection : runningApplications) { - Paintable paintable = applicationConnection.getPaintable(uidl - .getId()); + ComponentConnector paintable = (ComponentConnector) ConnectorMap + .get(applicationConnection).getConnector(uidl.getId()); highlight(paintable); if (event != null && event.getNativeEvent().getShiftKey()) { applicationConnection.highlightComponent(paintable); @@ -146,8 +143,7 @@ public class VUIDLBrowser extends SimpleTree { String nodeName = uidl.getTag(); try { - Integer.parseInt(nodeName); - nodeName = getNodeName(uidl, conf, nodeName); + nodeName = getNodeName(uidl, conf, Integer.parseInt(nodeName)); } catch (Exception e) { // NOP } @@ -201,7 +197,7 @@ public class VUIDLBrowser extends SimpleTree { tmp.addItem(name + "=" + value); } if (tmp != null) { - add(tmp); + add(tmp); } } catch (final Exception e) { // Ignored, no variables @@ -243,9 +239,9 @@ public class VUIDLBrowser extends SimpleTree { } } - static void highlight(Paintable paintable) { - Widget w = (Widget) paintable; - if (w != null) { + static void highlight(ComponentConnector paintable) { + if (paintable != null) { + Widget w = paintable.getWidget(); Style style = highlight.getStyle(); style.setTop(w.getAbsoluteTop(), Unit.PX); style.setLeft(w.getAbsoluteLeft(), Unit.PX); @@ -261,4 +257,4 @@ public class VUIDLBrowser extends SimpleTree { } } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/terminal/gwt/client/ValueMap.java b/src/com/vaadin/terminal/gwt/client/ValueMap.java index 8d14ef57ce..5deb5feb55 100644 --- a/src/com/vaadin/terminal/gwt/client/ValueMap.java +++ b/src/com/vaadin/terminal/gwt/client/ValueMap.java @@ -101,4 +101,9 @@ public final class ValueMap extends JavaScriptObject { return '' + this[name]; }-*/; + native JavaScriptObject getJavaScriptObject(String name) + /*-{ + return this[name]; + }-*/; + }
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java b/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java index a5c75d27dd..dd69883d58 100644 --- a/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java +++ b/src/com/vaadin/terminal/gwt/client/WidgetInstantiator.java @@ -7,5 +7,5 @@ package com.vaadin.terminal.gwt.client; * A helper class used by WidgetMap implementation. Used by the generated code. */ interface WidgetInstantiator { - public Paintable get(); + public ComponentConnector get(); } diff --git a/src/com/vaadin/terminal/gwt/client/WidgetMap.java b/src/com/vaadin/terminal/gwt/client/WidgetMap.java index 51dac20132..af84a11ced 100644 --- a/src/com/vaadin/terminal/gwt/client/WidgetMap.java +++ b/src/com/vaadin/terminal/gwt/client/WidgetMap.java @@ -5,19 +5,61 @@ package com.vaadin.terminal.gwt.client; import java.util.HashMap; +import com.vaadin.terminal.gwt.widgetsetutils.WidgetMapGenerator; + +/** + * Abstract class mapping between {@link ComponentConnector} instances and their + * instances. + * + * A concrete implementation of this class is generated by + * {@link WidgetMapGenerator} or one of its subclasses during widgetset + * compilation. + */ abstract class WidgetMap { protected static HashMap<Class, WidgetInstantiator> instmap = new HashMap<Class, WidgetInstantiator>(); - public Paintable instantiate(Class<? extends Paintable> classType) { + /** + * Create a new instance of a connector based on its type. + * + * @param classType + * {@link ComponentConnector} class to instantiate + * @return new instance of the connector + */ + public ComponentConnector instantiate( + Class<? extends ComponentConnector> classType) { return instmap.get(classType).get(); } - public abstract Class<? extends Paintable> getImplementationByServerSideClassName( + /** + * Return the connector class to use for a fully qualified server side + * component class name. + * + * @param fullyqualifiedName + * fully qualified name of the server side component class + * @return component connector class to use + */ + public abstract Class<? extends ComponentConnector> getConnectorClassForServerSideClassName( String fullyqualifiedName); - public abstract Class<? extends Paintable>[] getDeferredLoadedWidgets(); + /** + * Return the connector classes to load after the initial widgetset load and + * start. + * + * @return component connector class to load after the initial widgetset + * loading + */ + public abstract Class<? extends ComponentConnector>[] getDeferredLoadedWidgets(); - public abstract void ensureInstantiator(Class<? extends Paintable> classType); + /** + * Make sure the code for a (deferred or lazy) component connector type has + * been loaded, triggering the load and waiting for its completion if + * necessary. + * + * @param classType + * component connector class + */ + public abstract void ensureInstantiator( + Class<? extends ComponentConnector> classType); } diff --git a/src/com/vaadin/terminal/gwt/client/WidgetSet.java b/src/com/vaadin/terminal/gwt/client/WidgetSet.java index fb77775549..e47837296d 100644 --- a/src/com/vaadin/terminal/gwt/client/WidgetSet.java +++ b/src/com/vaadin/terminal/gwt/client/WidgetSet.java @@ -6,18 +6,7 @@ package com.vaadin.terminal.gwt.client; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ui.VButton; -import com.vaadin.terminal.gwt.client.ui.VCheckBox; -import com.vaadin.terminal.gwt.client.ui.VFilterSelect; -import com.vaadin.terminal.gwt.client.ui.VListSelect; -import com.vaadin.terminal.gwt.client.ui.VPasswordField; -import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal; -import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical; -import com.vaadin.terminal.gwt.client.ui.VTextArea; -import com.vaadin.terminal.gwt.client.ui.VTextField; -import com.vaadin.terminal.gwt.client.ui.VUnknownComponent; -import com.vaadin.terminal.gwt.client.ui.VView; -import com.vaadin.terminal.gwt.client.ui.VWindow; +import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector; public class WidgetSet { @@ -30,94 +19,61 @@ public class WidgetSet { /** * Create an uninitialized component that best matches given UIDL. The - * component must be a {@link Widget} that implements {@link Paintable}. + * component must be a {@link Widget} that implements + * {@link ComponentConnector}. * - * @param uidl - * UIDL to be painted with returned component. + * @param tag + * component type tag for the component to create * @param client * the application connection that whishes to instantiate widget * * @return New uninitialized and unregistered component that can paint given * UIDL. */ - public Paintable createWidget(UIDL uidl, ApplicationConfiguration conf) { + public ComponentConnector createWidget(int tag, + ApplicationConfiguration conf) { /* * Yes, this (including the generated code in WidgetMap) may look very * odd code, but due the nature of GWT, we cannot do this any cleaner. * Luckily this is mostly written by WidgetSetGenerator, here are just * some hacks. Extra instantiation code is needed if client side widget * has no "native" counterpart on client side. - * - * TODO should try to get rid of these exceptions here */ - final Class<? extends Paintable> classType = resolveWidgetType(uidl, - conf); - if (classType == null || classType == VUnknownComponent.class) { - String serverSideName = conf - .getUnknownServerClassNameByEncodedTagName(uidl.getTag()); - VUnknownComponent c = GWT.create(VUnknownComponent.class); + Class<? extends ComponentConnector> classType = resolveInheritedWidgetType( + conf, tag); + + if (classType == null || classType == UnknownComponentConnector.class) { + String serverSideName = conf.getUnknownServerClassNameByTag(tag); + UnknownComponentConnector c = GWT + .create(UnknownComponentConnector.class); c.setServerSideClassName(serverSideName); return c; - } else if (VWindow.class == classType) { - return GWT.create(VWindow.class); } else { /* * let the auto generated code instantiate this type */ return widgetMap.instantiate(classType); } + } + private Class<? extends ComponentConnector> resolveInheritedWidgetType( + ApplicationConfiguration conf, int tag) { + Class<? extends ComponentConnector> classType = null; + Integer t = tag; + do { + classType = resolveWidgetType(t, conf); + t = conf.getParentTag(t); + } while (classType == null && t != null); + return classType; } - protected Class<? extends Paintable> resolveWidgetType(UIDL uidl, + protected Class<? extends ComponentConnector> resolveWidgetType(int tag, ApplicationConfiguration conf) { - final String tag = uidl.getTag(); - - Class<? extends Paintable> widgetClass = conf + Class<? extends ComponentConnector> widgetClass = conf .getWidgetClassByEncodedTag(tag); - // add our historical quirks - - if (widgetClass == VButton.class && uidl.hasAttribute("type")) { - return VCheckBox.class; - } else if (widgetClass == VView.class && uidl.hasAttribute("sub")) { - return VWindow.class; - } else if (widgetClass == VFilterSelect.class) { - if (uidl.hasAttribute("type")) { - final String type = uidl.getStringAttribute("type").intern(); - if ("legacy-multi" == type) { - return VListSelect.class; - } - } - } else if (widgetClass == VTextField.class) { - if (uidl.hasAttribute("multiline")) { - return VTextArea.class; - } else if (uidl.hasAttribute("secret")) { - return VPasswordField.class; - } - } else if (widgetClass == VSplitPanelHorizontal.class - && uidl.hasAttribute("vertical")) { - return VSplitPanelVertical.class; - } - return widgetClass; - - } - - /** - * Test if the given component implementation conforms to UIDL. - * - * @param currentWidget - * Current implementation of the component - * @param uidl - * UIDL to test against - * @return true iff createWidget would return a new component of the same - * class than currentWidget - */ - public boolean isCorrectImplementation(Widget currentWidget, UIDL uidl, - ApplicationConfiguration conf) { - return currentWidget.getClass() == resolveWidgetType(uidl, conf); } /** @@ -125,44 +81,29 @@ public class WidgetSet { * limitation, widgetset must have function that returns Class by its fully * qualified name. * - * @param fullyQualifiedName + * @param tag * @param applicationConfiguration * @return */ - public Class<? extends Paintable> getImplementationByClassName( - String fullyqualifiedName) { - if (fullyqualifiedName == null) { - return VUnknownComponent.class; - } - Class<? extends Paintable> implementationByServerSideClassName = widgetMap - .getImplementationByServerSideClassName(fullyqualifiedName); - - /* - * Also ensure that our historical quirks have their instantiators - * loaded. Without these, legacy code will throw NPEs when e.g. a Select - * is in multiselect mode, causing the clientside implementation to - * *actually* be VListSelect, when the annotation says VFilterSelect - */ - if (fullyqualifiedName.equals("com.vaadin.ui.Button")) { - loadImplementation(VCheckBox.class); - } else if (fullyqualifiedName.equals("com.vaadin.ui.Select")) { - loadImplementation(VListSelect.class); - } else if (fullyqualifiedName.equals("com.vaadin.ui.TextField")) { - loadImplementation(VTextArea.class); - loadImplementation(VPasswordField.class); - } else if (fullyqualifiedName.equals("com.vaadin.ui.SplitPanel")) { - loadImplementation(VSplitPanelVertical.class); - } - - return implementationByServerSideClassName; - + public Class<? extends ComponentConnector> getConnectorClassByTag(int tag, + ApplicationConfiguration conf) { + Class<? extends ComponentConnector> connectorClass = null; + Integer t = tag; + do { + String serverSideClassName = conf.getServerSideClassNameForTag(t); + connectorClass = widgetMap + .getConnectorClassForServerSideClassName(serverSideClassName); + t = conf.getParentTag(t); + } while (connectorClass == UnknownComponentConnector.class && t != null); + + return connectorClass; } - public Class<? extends Paintable>[] getDeferredLoadedWidgets() { + public Class<? extends ComponentConnector>[] getDeferredLoadedWidgets() { return widgetMap.getDeferredLoadedWidgets(); } - public void loadImplementation(Class<? extends Paintable> nextType) { + public void loadImplementation(Class<? extends ComponentConnector> nextType) { widgetMap.ensureInstantiator(nextType); } diff --git a/src/com/vaadin/terminal/gwt/client/communication/AbstractServerConnectorEvent.java b/src/com/vaadin/terminal/gwt/client/communication/AbstractServerConnectorEvent.java new file mode 100644 index 0000000000..b465e3ad7e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/AbstractServerConnectorEvent.java @@ -0,0 +1,33 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.terminal.gwt.client.ServerConnector; + +public abstract class AbstractServerConnectorEvent<H extends EventHandler> + extends GwtEvent<H> { + private ServerConnector connector; + + protected AbstractServerConnectorEvent() { + } + + public ServerConnector getConnector() { + return connector; + } + + public void setConnector(ServerConnector connector) { + this.connector = connector; + } + + /** + * Sends this event to the given handler. + * + * @param handler + * The handler to dispatch. + */ + @Override + public abstract void dispatch(H handler); +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/ClientRpc.java b/src/com/vaadin/terminal/gwt/client/communication/ClientRpc.java new file mode 100644 index 0000000000..45dbe69454 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/ClientRpc.java @@ -0,0 +1,23 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; + +/** + * Interface to be extended by all server to client RPC interfaces. + * + * On the server side, proxies of the interface can be obtained from + * AbstractComponent. On the client, RPC implementations can be registered with + * AbstractConnector.registerRpc(). + * + * Note: Currently, each RPC interface may not contain multiple methods with the + * same name, even if their parameter lists would differ. + * + * @since 7.0 + */ +public interface ClientRpc extends Serializable { + +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/FieldRpc.java b/src/com/vaadin/terminal/gwt/client/communication/FieldRpc.java new file mode 100644 index 0000000000..de464f1fb9 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/FieldRpc.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +public class FieldRpc { + public interface FocusServerRpc extends ServerRpc { + public void focus(); + } + + public interface BlurServerRpc extends ServerRpc { + public void blur(); + } + + public interface FocusAndBlurServerRpc extends FocusServerRpc, + BlurServerRpc { + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java b/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java new file mode 100644 index 0000000000..0270de316e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/InitializableServerRpc.java @@ -0,0 +1,26 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import com.vaadin.terminal.gwt.client.ServerConnector; + +/** + * Initialization support for client to server RPC interfaces. + * + * This is in a separate interface used by the GWT generator class. The init + * method is not in {@link ServerRpc} because then also server side proxies + * would have to implement the initialization method. + * + * @since 7.0 + */ +public interface InitializableServerRpc extends ServerRpc { + /** + * Associates the RPC proxy with a connector. Called by generated code. + * Should never be called manually. + * + * @param connector + * The connector the ServerRPC instance is assigned to. + */ + public void initRpc(ServerConnector connector); +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java new file mode 100644 index 0000000000..c626d31d0a --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java @@ -0,0 +1,60 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import com.google.gwt.json.client.JSONObject; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.server.JsonCodec; + +/** + * Implementors of this interface knows how to serialize an Object of a given + * type to JSON and how to deserialize the JSON back into an object. + * + * The {@link #serialize(Object, ConnectorMap)} and + * {@link #deserialize(JSONObject, ConnectorMap)} methods must be symmetric so + * they can be chained and produce the original result (or an equal result). + * + * Each {@link JSONSerializer} implementation can handle an object of a single + * type - see {@link SerializerMap}. + * + * @since 7.0 + */ +public interface JSONSerializer<T> { + + /** + * Creates and deserializes an object received from the server. Must be + * compatible with {@link #serialize(Object, ConnectorMap)} and also with + * the server side + * {@link JsonCodec#encode(Object, com.vaadin.terminal.gwt.server.PaintableIdMapper)} + * . + * + * @param jsonValue + * JSON map from property name to property value + * @param idMapper + * mapper from paintable id to paintable, used to decode + * references to paintables + * @return A deserialized object + */ + T deserialize(JSONObject jsonValue, ConnectorMap idMapper, + ApplicationConnection connection); + + /** + * Serialize the given object into JSON. Must be compatible with + * {@link #deserialize(JSONObject, ConnectorMap)} and also with the server + * side + * {@link JsonCodec#decode(com.vaadin.external.json.JSONArray, com.vaadin.terminal.gwt.server.PaintableIdMapper)} + * + * @param value + * The object to serialize + * @param idMapper + * mapper from paintable id to paintable, used to decode + * references to paintables + * @return A JSON serialized version of the object + */ + JSONObject serialize(T value, ConnectorMap idMapper, + ApplicationConnection connection); + +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java new file mode 100644 index 0000000000..2b58c13f3e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -0,0 +1,171 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONString; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.ServerConnector; + +/** + * Client side decoder for decodeing shared state and other values from JSON + * received from the server. + * + * Currently, basic data types as well as Map, String[] and Object[] are + * supported, where maps and Object[] can contain other supported data types. + * + * TODO extensible type support + * + * @since 7.0 + */ +public class JsonDecoder { + static SerializerMap serializerMap = GWT.create(SerializerMap.class); + + /** + * Decode a JSON array with two elements (type and value) into a client-side + * type, recursively if necessary. + * + * @param jsonArray + * JSON array with two elements + * @param idMapper + * mapper between connector ID and {@link ServerConnector} + * objects + * @param connection + * reference to the current ApplicationConnection + * @return decoded value (does not contain JSON types) + */ + public static Object decodeValue(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { + String type = ((JSONString) jsonArray.get(0)).stringValue(); + return decodeValue(type, jsonArray.get(1), idMapper, connection); + } + + private static Object decodeValue(String variableType, Object value, + ConnectorMap idMapper, ApplicationConnection connection) { + Object val = null; + // TODO type checks etc. + if (JsonEncoder.VTYPE_NULL.equals(variableType)) { + val = null; + } else if (JsonEncoder.VTYPE_ARRAY.equals(variableType)) { + val = decodeArray((JSONArray) value, idMapper, connection); + } else if (JsonEncoder.VTYPE_MAP.equals(variableType)) { + val = decodeMap((JSONObject) value, idMapper, connection); + } else if (JsonEncoder.VTYPE_MAP_CONNECTOR.equals(variableType)) { + val = decodeConnectorMap((JSONObject) value, idMapper, connection); + } else if (JsonEncoder.VTYPE_LIST.equals(variableType)) { + val = decodeList((JSONArray) value, idMapper, connection); + } else if (JsonEncoder.VTYPE_SET.equals(variableType)) { + val = decodeSet((JSONArray) value, idMapper, connection); + } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(variableType)) { + val = decodeStringArray((JSONArray) value); + } else if (JsonEncoder.VTYPE_STRING.equals(variableType)) { + val = ((JSONString) value).stringValue(); + } else if (JsonEncoder.VTYPE_INTEGER.equals(variableType)) { + // TODO handle properly + val = Integer.valueOf(String.valueOf(value)); + } else if (JsonEncoder.VTYPE_LONG.equals(variableType)) { + // TODO handle properly + val = Long.valueOf(String.valueOf(value)); + } else if (JsonEncoder.VTYPE_FLOAT.equals(variableType)) { + // TODO handle properly + val = Float.valueOf(String.valueOf(value)); + } else if (JsonEncoder.VTYPE_DOUBLE.equals(variableType)) { + // TODO handle properly + val = Double.valueOf(String.valueOf(value)); + } else if (JsonEncoder.VTYPE_BOOLEAN.equals(variableType)) { + // TODO handle properly + val = Boolean.valueOf(String.valueOf(value)); + } else if (JsonEncoder.VTYPE_CONNECTOR.equals(variableType)) { + val = idMapper.getConnector(((JSONString) value).stringValue()); + } else { + // object, class name as type + JSONSerializer serializer = serializerMap + .getSerializer(variableType); + // TODO handle case with no serializer found + Object object = serializer.deserialize((JSONObject) value, + idMapper, connection); + return object; + } + + return val; + } + + private static Map<String, Object> decodeMap(JSONObject jsonMap, + ConnectorMap idMapper, ApplicationConnection connection) { + HashMap<String, Object> map = new HashMap<String, Object>(); + Iterator<String> it = jsonMap.keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + map.put(key, + decodeValue((JSONArray) jsonMap.get(key), idMapper, + connection)); + } + return map; + } + + private static Map<Connector, Object> decodeConnectorMap( + JSONObject jsonMap, ConnectorMap idMapper, + ApplicationConnection connection) { + HashMap<Connector, Object> map = new HashMap<Connector, Object>(); + Iterator<String> it = jsonMap.keySet().iterator(); + while (it.hasNext()) { + String connectorId = it.next(); + Connector connector = idMapper.getConnector(connectorId); + map.put(connector, + decodeValue((JSONArray) jsonMap.get(connectorId), idMapper, + connection)); + } + return map; + } + + private static String[] decodeStringArray(JSONArray jsonArray) { + int size = jsonArray.size(); + List<String> tokens = new ArrayList<String>(size); + for (int i = 0; i < size; ++i) { + tokens.add(String.valueOf(jsonArray.get(i))); + } + return tokens.toArray(new String[tokens.size()]); + } + + private static Object[] decodeArray(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { + List<Object> list = decodeList(jsonArray, idMapper, connection); + return list.toArray(new Object[list.size()]); + } + + private static List<Object> decodeList(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { + List<Object> tokens = new ArrayList<Object>(); + for (int i = 0; i < jsonArray.size(); ++i) { + // each entry always has two elements: type and value + JSONArray entryArray = (JSONArray) jsonArray.get(i); + tokens.add(decodeValue(entryArray, idMapper, connection)); + } + return tokens; + } + + private static Set<Object> decodeSet(JSONArray jsonArray, + ConnectorMap idMapper, ApplicationConnection connection) { + Set<Object> tokens = new HashSet<Object>(); + for (int i = 0; i < jsonArray.size(); ++i) { + // each entry always has two elements: type and value + JSONArray entryArray = (JSONArray) jsonArray.get(i); + tokens.add(decodeValue(entryArray, idMapper, connection)); + } + return tokens; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java new file mode 100644 index 0000000000..fdc06b0e21 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java @@ -0,0 +1,207 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONBoolean; +import com.google.gwt.json.client.JSONNull; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONString; +import com.google.gwt.json.client.JSONValue; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ConnectorMap; + +/** + * Encoder for converting RPC parameters and other values to JSON for transfer + * between the client and the server. + * + * Currently, basic data types as well as Map, String[] and Object[] are + * supported, where maps and Object[] can contain other supported data types. + * + * TODO extensible type support + * + * @since 7.0 + */ +public class JsonEncoder { + + public static final String VTYPE_CONNECTOR = "c"; + public static final String VTYPE_BOOLEAN = "b"; + public static final String VTYPE_DOUBLE = "d"; + public static final String VTYPE_FLOAT = "f"; + public static final String VTYPE_LONG = "l"; + public static final String VTYPE_INTEGER = "i"; + public static final String VTYPE_STRING = "s"; + public static final String VTYPE_ARRAY = "a"; + public static final String VTYPE_STRINGARRAY = "S"; + public static final String VTYPE_MAP = "m"; + // Hack to support Map<Connector,?>. Should be replaced by generic support + // for any object as key (#8602) + @Deprecated + public static final String VTYPE_MAP_CONNECTOR = "M"; + public static final String VTYPE_LIST = "L"; + public static final String VTYPE_SET = "q"; + public static final String VTYPE_NULL = "n"; + + /** + * Encode a value to a JSON representation for transport from the client to + * the server. + * + * @param value + * value to convert + * @param connectorMap + * mapper from connectors to connector IDs + * @param connection + * @return JSON representation of the value + */ + public static JSONValue encode(Object value, ConnectorMap connectorMap, + ApplicationConnection connection) { + if (null == value) { + return combineTypeAndValue(VTYPE_NULL, JSONNull.getInstance()); + } else if (value instanceof String[]) { + String[] array = (String[]) value; + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < array.length; ++i) { + jsonArray.set(i, new JSONString(array[i])); + } + return combineTypeAndValue(VTYPE_STRINGARRAY, jsonArray); + } else if (value instanceof String) { + return combineTypeAndValue(VTYPE_STRING, new JSONString( + (String) value)); + } else if (value instanceof Boolean) { + return combineTypeAndValue(VTYPE_BOOLEAN, + JSONBoolean.getInstance((Boolean) value)); + } else if (value instanceof Object[]) { + return encodeObjectArray((Object[]) value, connectorMap, connection); + } else if (value instanceof Map) { + Map<Object, Object> map = (Map<Object, Object>) value; + JSONObject jsonMap = new JSONObject(); + String type = VTYPE_MAP; + for (Object mapKey : map.keySet()) { + Object mapValue = map.get(mapKey); + if (mapKey instanceof Connector) { + mapKey = ((Connector) mapKey).getConnectorId(); + type = VTYPE_MAP_CONNECTOR; + } + + if (!(mapKey instanceof String)) { + throw new RuntimeException( + "Only Map<String,?> and Map<Connector,?> is currently supported." + + " Failed map used " + + mapKey.getClass().getName() + " as keys"); + } + jsonMap.put((String) mapKey, + encode(mapValue, connectorMap, connection)); + } + return combineTypeAndValue(type, jsonMap); + } else if (value instanceof Connector) { + Connector connector = (Connector) value; + return combineTypeAndValue(VTYPE_CONNECTOR, new JSONString( + connector.getConnectorId())); + } else if (value instanceof Collection) { + return encodeCollection((Collection) value, connectorMap, + connection); + } else { + String transportType = getTransportType(value); + if (transportType != null) { + return combineTypeAndValue(transportType, + new JSONString(String.valueOf(value))); + } else { + // Try to find a generated serializer object, class name is the + // type + transportType = value.getClass().getName(); + JSONSerializer serializer = JsonDecoder.serializerMap + .getSerializer(transportType); + + // TODO handle case with no serializer found + return combineTypeAndValue(transportType, + serializer.serialize(value, connectorMap, connection)); + } + } + } + + private static JSONValue encodeObjectArray(Object[] array, + ConnectorMap connectorMap, ApplicationConnection connection) { + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < array.length; ++i) { + // TODO handle object graph loops? + jsonArray.set(i, encode(array[i], connectorMap, connection)); + } + return combineTypeAndValue(VTYPE_ARRAY, jsonArray); + } + + private static JSONValue encodeCollection(Collection collection, + ConnectorMap connectorMap, ApplicationConnection connection) { + JSONArray jsonArray = new JSONArray(); + int idx = 0; + for (Object o : collection) { + JSONValue encodedObject = encode(o, connectorMap, connection); + jsonArray.set(idx++, encodedObject); + } + if (collection instanceof Set) { + return combineTypeAndValue(VTYPE_SET, jsonArray); + } else if (collection instanceof List) { + return combineTypeAndValue(VTYPE_LIST, jsonArray); + } else { + throw new RuntimeException("Unsupport collection type: " + + collection.getClass().getName()); + } + + } + + private static JSONValue combineTypeAndValue(String type, JSONValue value) { + JSONArray outerArray = new JSONArray(); + outerArray.set(0, new JSONString(type)); + outerArray.set(1, value); + return outerArray; + } + + /** + * Returns the transport type for the given value. Only returns a transport + * type for internally handled values. + * + * @param value + * The value that should be transported + * @return One of the JsonEncode.VTYPE_ constants or null if the value + * cannot be transported using an internally handled type. + */ + private static String getTransportType(Object value) { + if (value == null) { + return VTYPE_NULL; + } else if (value instanceof String) { + return VTYPE_STRING; + } else if (value instanceof Connector) { + return VTYPE_CONNECTOR; + } else if (value instanceof Boolean) { + return VTYPE_BOOLEAN; + } else if (value instanceof Integer) { + return VTYPE_INTEGER; + } else if (value instanceof Float) { + return VTYPE_FLOAT; + } else if (value instanceof Double) { + return VTYPE_DOUBLE; + } else if (value instanceof Long) { + return VTYPE_LONG; + } else if (value instanceof List) { + return VTYPE_LIST; + } else if (value instanceof Set) { + return VTYPE_SET; + } else if (value instanceof Enum) { + return VTYPE_STRING; // transported as string representation + } else if (value instanceof String[]) { + return VTYPE_STRINGARRAY; + } else if (value instanceof Object[]) { + return VTYPE_ARRAY; + } else if (value instanceof Map) { + return VTYPE_MAP; + } + return null; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java b/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java new file mode 100644 index 0000000000..e61775a640 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/MethodInvocation.java @@ -0,0 +1,62 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * Information needed by the framework to send an RPC method invocation from the + * client to the server or vice versa. + * + * @since 7.0 + */ +public class MethodInvocation implements Serializable { + + private final String connectorId; + private final String interfaceName; + private final String methodName; + private Object[] parameters; + + public MethodInvocation(String connectorId, String interfaceName, + String methodName) { + this.connectorId = connectorId; + this.interfaceName = interfaceName; + this.methodName = methodName; + } + + public MethodInvocation(String connectorId, String interfaceName, + String methodName, Object[] parameters) { + this(connectorId, interfaceName, methodName); + setParameters(parameters); + } + + public String getConnectorId() { + return connectorId; + } + + public String getInterfaceName() { + return interfaceName; + } + + public String getMethodName() { + return methodName; + } + + public Object[] getParameters() { + return parameters; + } + + public void setParameters(Object[] parameters) { + this.parameters = parameters; + } + + @Override + public String toString() { + return connectorId + ":" + interfaceName + "." + methodName + "(" + + Arrays.toString(parameters) + ")"; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java b/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java new file mode 100644 index 0000000000..302e6eaa55 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java @@ -0,0 +1,32 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; + +import com.vaadin.terminal.gwt.client.ConnectorMap; + +/** + * Client side RPC manager that can invoke methods based on RPC calls received + * from the server. + * + * A GWT generator is used to create an implementation of this class at + * run-time. + * + * @since 7.0 + */ +public interface RpcManager extends Serializable { + /** + * Perform server to client RPC invocation. + * + * @param invocation + * method to invoke + * @param connectorMap + * mapper used to find Connector for the method call and any + * connectors referenced in parameters + */ + public void applyInvocation(MethodInvocation invocation, + ConnectorMap connectorMap); +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java b/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java new file mode 100644 index 0000000000..113ec1f1b1 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/RpcProxy.java @@ -0,0 +1,37 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import com.google.gwt.core.client.GWT; +import com.vaadin.terminal.gwt.client.ServerConnector; + +/** + * Class for creating proxy instances for Client to Server RPC. + * + * @since 7.0 + */ +public class RpcProxy { + + private static RpcProxyCreator impl = GWT.create(RpcProxyCreator.class); + + /** + * Create a proxy class for the given Rpc interface and assign it to the + * given connector. + * + * @param rpcInterface + * The rpc interface to construct a proxy for + * @param connector + * The connector this proxy is connected to + * @return A proxy class used for calling Rpc methods. + */ + public static <T extends ServerRpc> T create(Class<T> rpcInterface, + ServerConnector connector) { + return impl.create(rpcInterface, connector); + } + + public interface RpcProxyCreator { + <T extends ServerRpc> T create(Class<T> rpcInterface, + ServerConnector connector); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/SerializerMap.java b/src/com/vaadin/terminal/gwt/client/communication/SerializerMap.java new file mode 100644 index 0000000000..0750474d24 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/SerializerMap.java @@ -0,0 +1,34 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import com.vaadin.terminal.gwt.widgetsetutils.SerializerMapGenerator; + +/** + * Provide a mapping from a type (communicated between the server and the + * client) and a {@link JSONSerializer} instance. + * + * An implementation of this class is created at GWT compilation time by + * {@link SerializerMapGenerator}, so this interface can be instantiated with + * GWT.create(). + * + * @since 7.0 + */ +public interface SerializerMap { + + /** + * Returns a serializer instance for a given type. + * + * @param type + * type communicated on between the server and the client + * (currently fully qualified class name) + * @return serializer instance, not null + * @throws RuntimeException + * if no serializer is found + */ + // TODO better error handling in javadoc and in generator + public JSONSerializer getSerializer(String type); + +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/ServerRpc.java b/src/com/vaadin/terminal/gwt/client/communication/ServerRpc.java new file mode 100644 index 0000000000..664c4a391c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/ServerRpc.java @@ -0,0 +1,15 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; + +/** + * Interface to be extended by all client to server RPC interfaces. + * + * @since 7.0 + */ +public interface ServerRpc extends Serializable { +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/SharedState.java b/src/com/vaadin/terminal/gwt/client/communication/SharedState.java new file mode 100644 index 0000000000..266d6bcbf2 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/SharedState.java @@ -0,0 +1,41 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; + +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ServerConnector; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; + +/** + * Interface to be implemented by all shared state classes used to communicate + * basic information about a {@link Connector} from server to client. + * + * Shared state classes have to be declared in client side packages to be + * accessible both for server and client code. They can be static nested classes + * of a {@link ServerConnector}. + * + * Shared state objects are only sent from the server to the client, and any + * modifications from the client should be performed via an RPC call that + * modifies the authoritative state on the server. + * + * A shared state class should be a bean with getters and setters for each + * field. Supported data types are simple Java types, other beans and maps and + * arrays of these. + * + * On the client side the connector should override + * {@link AbstractComponentConnector#createState()} to create the correct state + * class and {@link AbstractComponentConnector#getState()} override the return + * type. + * + * Subclasses of a {@link Connector} using shared state should also provide a + * subclass of the shared state class of the parent class to extend the state. A + * single {@link Connector} can only have one shared state object. + * + * @since 7.0 + */ +public class SharedState implements Serializable { +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java b/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java new file mode 100644 index 0000000000..39ecbc022c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/StateChangeEvent.java @@ -0,0 +1,34 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; + +import com.google.gwt.event.shared.EventHandler; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; + +public class StateChangeEvent extends + AbstractServerConnectorEvent<StateChangeHandler> { + /** + * Type of this event, used by the event bus. + */ + public static final Type<StateChangeHandler> TYPE = new Type<StateChangeHandler>(); + + @Override + public Type<StateChangeHandler> getAssociatedType() { + return TYPE; + } + + public StateChangeEvent() { + } + + @Override + public void dispatch(StateChangeHandler listener) { + listener.onStateChanged(this); + } + + public interface StateChangeHandler extends Serializable, EventHandler { + public void onStateChanged(StateChangeEvent stateChangeEvent); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/communication/URLReference.java b/src/com/vaadin/terminal/gwt/client/communication/URLReference.java new file mode 100644 index 0000000000..569c4eff47 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference.java @@ -0,0 +1,31 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import java.io.Serializable; + +public class URLReference implements Serializable { + + private String URL; + + /** + * Returns the URL that this object refers to. + * <p> + * Note that the URL can use special protocols like theme:// + * + * @return The URL for this reference or null if unknown. + */ + public String getURL() { + return URL; + } + + /** + * Sets the URL that this object refers to + * + * @param URL + */ + public void setURL(String URL) { + this.URL = URL; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java new file mode 100644 index 0000000000..4fefc7f845 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java @@ -0,0 +1,32 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.communication; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ConnectorMap; + +public class URLReference_Serializer implements JSONSerializer<URLReference> { + + public URLReference deserialize(JSONObject jsonValue, + ConnectorMap idMapper, ApplicationConnection connection) { + URLReference reference = GWT.create(URLReference.class); + JSONArray jsonURL = (JSONArray) jsonValue.get("URL"); + String URL = (String) JsonDecoder.decodeValue(jsonURL, idMapper, + connection); + reference.setURL(connection.translateVaadinUri(URL)); + return reference; + } + + public JSONObject serialize(URLReference value, ConnectorMap idMapper, + ApplicationConnection connection) { + JSONObject json = new JSONObject(); + json.put("URL", + JsonEncoder.encode(value.getURL(), idMapper, connection)); + return json; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java new file mode 100644 index 0000000000..31204aa0c6 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java @@ -0,0 +1,161 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.ContextMenuEvent; +import com.google.gwt.event.dom.client.ContextMenuHandler; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; +import com.google.gwt.event.dom.client.MouseUpEvent; +import com.google.gwt.event.dom.client.MouseUpHandler; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Element; +import com.vaadin.terminal.gwt.client.ComponentConnector; + +public abstract class AbstractClickEventHandler implements DoubleClickHandler, + ContextMenuHandler, MouseUpHandler { + + private HandlerRegistration doubleClickHandlerRegistration; + private HandlerRegistration mouseUpHandlerRegistration; + private HandlerRegistration contextMenuHandlerRegistration; + + protected ComponentConnector connector; + private String clickEventIdentifier; + + public AbstractClickEventHandler(ComponentConnector connector, + String clickEventIdentifier) { + this.connector = connector; + this.clickEventIdentifier = clickEventIdentifier; + } + + public void handleEventHandlerRegistration() { + // Handle registering/unregistering of click handler depending on if + // server side listeners have been added or removed. + if (hasEventListener()) { + if (mouseUpHandlerRegistration == null) { + mouseUpHandlerRegistration = registerHandler(this, + MouseUpEvent.getType()); + contextMenuHandlerRegistration = registerHandler(this, + ContextMenuEvent.getType()); + doubleClickHandlerRegistration = registerHandler(this, + DoubleClickEvent.getType()); + } + } else { + if (mouseUpHandlerRegistration != null) { + // Remove existing handlers + doubleClickHandlerRegistration.removeHandler(); + mouseUpHandlerRegistration.removeHandler(); + contextMenuHandlerRegistration.removeHandler(); + + contextMenuHandlerRegistration = null; + mouseUpHandlerRegistration = null; + doubleClickHandlerRegistration = null; + + } + } + + } + + /** + * Registers the given handler to the widget so that the necessary events + * are passed to this {@link ClickEventHandler}. + * <p> + * By default registers the handler with the connector root widget. + * </p> + * + * @param <H> + * @param handler + * The handler to register + * @param type + * The type of the handler. + * @return A reference for the registration of the handler. + */ + protected <H extends EventHandler> HandlerRegistration registerHandler( + final H handler, DomEvent.Type<H> type) { + return connector.getWidget().addDomHandler(handler, type); + } + + /** + * Checks if there is a server side event listener registered for clicks + * + * @return true if there is a server side event listener registered, false + * otherwise + */ + public boolean hasEventListener() { + return connector.hasEventListener(clickEventIdentifier); + } + + /** + * Event handler for context menu. Prevents the browser context menu from + * popping up if there is a listener for right clicks. + */ + public void onContextMenu(ContextMenuEvent event) { + if (hasEventListener() && shouldFireEvent(event)) { + // Prevent showing the browser's context menu when there is a right + // click listener. + event.preventDefault(); + } + } + + /** + * Event handler for mouse up. This is used to detect all single click + * events. + */ + public void onMouseUp(MouseUpEvent event) { + // TODO For perfect accuracy we should check that a mousedown has + // occured on this element before this mouseup and that no mouseup + // has occured anywhere after that. + if (hasEventListener() && shouldFireEvent(event)) { + // "Click" with left, right or middle button + fireClick(event.getNativeEvent()); + } + } + + /** + * Sends the click event based on the given native event. + * + * @param event + * The native event that caused this click event + */ + protected abstract void fireClick(NativeEvent event); + + /** + * Called before firing a click event. Allows sub classes to decide if this + * in an event that should cause an event or not. + * + * @param event + * The user event + * @return true if the event should be fired, false otherwise + */ + protected boolean shouldFireEvent(DomEvent<?> event) { + return true; + } + + /** + * Event handler for double clicks. Used to fire double click events. Note + * that browsers typically fail to prevent the second click event so a + * double click will result in two click events and one double click event. + */ + public void onDoubleClick(DoubleClickEvent event) { + if (hasEventListener() && shouldFireEvent(event)) { + fireClick(event.getNativeEvent()); + } + } + + /** + * Click event calculates and returns coordinates relative to the element + * returned by this method. Default implementation uses the root element of + * the widget. Override to provide a different relative element. + * + * @return The Element used for calculating relative coordinates for a click + * or null if no relative coordinates can be calculated. + */ + protected Element getRelativeToElement() { + return connector.getWidget().getElement(); + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java new file mode 100644 index 0000000000..fdb04f0ddf --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java @@ -0,0 +1,353 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import java.util.Set; + +import com.google.gwt.user.client.ui.Focusable; +import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.TooltipInfo; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; + +public abstract class AbstractComponentConnector extends AbstractConnector + implements ComponentConnector { + + private ComponentContainerConnector parent; + + private Widget widget; + + // shared state from the server to the client + private ComponentState state; + + private String lastKnownWidth = ""; + private String lastKnownHeight = ""; + + /** + * Default constructor + */ + public AbstractComponentConnector() { + } + + /** + * Creates and returns the widget for this VPaintableWidget. This method + * should only be called once when initializing the paintable. + * + * @return + */ + protected abstract Widget createWidget(); + + /** + * Returns the widget associated with this paintable. The widget returned by + * this method must not changed during the life time of the paintable. + * + * @return The widget associated with this paintable + */ + public Widget getWidget() { + if (widget == null) { + widget = createWidget(); + } + + return widget; + } + + /** + * Returns the shared state object for this connector. + * + * If overriding this method to return a more specific type, also + * {@link #createState()} must be overridden. + * + * @return current shared state (not null) + */ + public ComponentState getState() { + return state; + } + + @Deprecated + public static boolean isRealUpdate(UIDL uidl) { + return !uidl.hasAttribute("cached"); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + ConnectorMap paintableMap = ConnectorMap.get(getConnection()); + + if (getState().getDebugId() != null) { + getWidget().getElement().setId(getState().getDebugId()); + } else { + getWidget().getElement().removeAttribute("id"); + + } + + /* + * Disabled state may affect (override) tabindex so the order must be + * first setting tabindex, then enabled state. + */ + if (state instanceof TabIndexState && getWidget() instanceof Focusable) { + ((Focusable) getWidget()).setTabIndex(((TabIndexState) state) + .getTabIndex()); + } + + setWidgetEnabled(isEnabled()); + + // Style names + String styleName = getStyleNames(getWidget().getStylePrimaryName()); + getWidget().setStyleName(styleName); + + // Update tooltip + TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(this, null); + if (getState().hasDescription()) { + tooltipInfo.setTitle(getState().getDescription()); + } else { + tooltipInfo.setTitle(null); + } + // add error info to tooltip if present + tooltipInfo.setErrorMessage(getState().getErrorMessage()); + + // Set captions + if (delegateCaptionHandling()) { + ComponentContainerConnector parent = getParent(); + if (parent != null) { + parent.updateCaption(this); + } else if (!(this instanceof RootConnector)) { + VConsole.error("Parent of connector " + + Util.getConnectorString(this) + + " is null. This is typically an indication of a broken component hierarchy"); + } + } + + /* + * updateComponentSize need to be after caption update so caption can be + * taken into account + */ + + updateComponentSize(); + } + + public void setWidgetEnabled(boolean widgetEnabled) { + if (getWidget() instanceof HasEnabled) { + ((HasEnabled) getWidget()).setEnabled(widgetEnabled); + } + } + + private void updateComponentSize() { + String newWidth = getState().getWidth(); + String newHeight = getState().getHeight(); + + // Parent should be updated if either dimension changed between relative + // and non-relative + if (newWidth.endsWith("%") != lastKnownWidth.endsWith("%")) { + ComponentContainerConnector parent = getParent(); + if (parent instanceof ManagedLayout) { + getLayoutManager().setNeedsHorizontalLayout( + (ManagedLayout) parent); + } + } + + if (newHeight.endsWith("%") != lastKnownHeight.endsWith("%")) { + ComponentContainerConnector parent = getParent(); + if (parent instanceof ManagedLayout) { + getLayoutManager().setNeedsVerticalLayout( + (ManagedLayout) parent); + } + } + + lastKnownWidth = newWidth; + lastKnownHeight = newHeight; + + // Set defined sizes + Widget widget = getWidget(); + + widget.setStyleName("v-has-width", !isUndefinedWidth()); + widget.setStyleName("v-has-height", !isUndefinedHeight()); + + widget.setHeight(newHeight); + widget.setWidth(newWidth); + } + + public boolean isRelativeHeight() { + return getState().getHeight().endsWith("%"); + } + + public boolean isRelativeWidth() { + return getState().getWidth().endsWith("%"); + } + + public boolean isUndefinedHeight() { + return getState().getHeight().length() == 0; + } + + public boolean isUndefinedWidth() { + return getState().getWidth().length() == 0; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.Connector#isEnabled() + */ + public boolean isEnabled() { + if (!getState().isEnabled()) { + return false; + } + + if (getParent() == null) { + return true; + } else { + return getParent().isEnabled(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ComponentConnector#delegateCaptionHandling + * () + */ + public boolean delegateCaptionHandling() { + return true; + } + + /** + * Generates the style name for the widget based on the given primary style + * name and the shared state. + * <p> + * This method can be overridden to provide additional style names for the + * component + * </p> + * + * @param primaryStyleName + * The primary style name to use when generating the final style + * names + * @return The style names, settable using + * {@link Widget#setStyleName(String)} + */ + protected String getStyleNames(String primaryStyleName) { + ComponentState state = getState(); + + StringBuilder styleBuf = new StringBuilder(); + styleBuf.append(primaryStyleName); + styleBuf.append(" v-connector"); + + // Uses connector methods to enable connectors to take hierarchy or + // multiple state variables into account + if (!isEnabled()) { + styleBuf.append(" "); + styleBuf.append(ApplicationConnection.DISABLED_CLASSNAME); + } + if (isReadOnly()) { + styleBuf.append(" "); + styleBuf.append("v-readonly"); + } + + // add additional styles as css classes, prefixed with component default + // stylename + if (state.hasStyles()) { + for (String style : state.getStyles()) { + styleBuf.append(" "); + styleBuf.append(primaryStyleName); + styleBuf.append("-"); + styleBuf.append(style); + styleBuf.append(" "); + styleBuf.append(style); + } + } + + // add error classname to components w/ error + if (null != state.getErrorMessage()) { + styleBuf.append(" "); + styleBuf.append(primaryStyleName); + styleBuf.append(ApplicationConnection.ERROR_CLASSNAME_EXT); + } + + return styleBuf.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ComponentConnector#isReadOnly() + */ + @Deprecated + public boolean isReadOnly() { + return getState().isReadOnly(); + } + + /** + * Sets the shared state for the paintable widget. + * + * @param new shared state (must be compatible with the return value of + * {@link #getState()} - {@link ComponentState} if + * {@link #getState()} is not overridden + */ + public final void setState(SharedState state) { + this.state = (ComponentState) state; + } + + public LayoutManager getLayoutManager() { + return LayoutManager.get(getConnection()); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.Connector#getParent() + */ + public ComponentContainerConnector getParent() { + return parent; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.Connector#setParent(com.vaadin.terminal + * .gwt.client.ComponentContainerConnector) + */ + public void setParent(ComponentContainerConnector parent) { + this.parent = parent; + } + + /** + * Checks if there is a registered server side listener for the given event + * identifier. + * + * @param eventIdentifier + * The identifier to check for + * @return true if an event listener has been registered with the given + * event identifier on the server side, false otherwise + */ + public boolean hasEventListener(String eventIdentifier) { + Set<String> reg = getState().getRegisteredEventListeners(); + return (reg != null && reg.contains(eventIdentifier)); + } + + @Override + public void onUnregister() { + super.onUnregister(); + + // Show an error if widget is still attached to DOM. It should never be + // at this point. + if (getWidget() != null && getWidget().isAttached()) { + getWidget().removeFromParent(); + VConsole.error("Widget is still attached to the DOM after the connector (" + + Util.getConnectorString(this) + + ") has been unregistered. Widget was removed."); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java new file mode 100644 index 0000000000..526631e4b2 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentContainerConnector.java @@ -0,0 +1,110 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import java.util.LinkedList; +import java.util.List; + +import com.google.gwt.event.shared.HandlerRegistration; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; + +public abstract class AbstractComponentContainerConnector extends + AbstractComponentConnector implements ComponentContainerConnector, + ConnectorHierarchyChangeHandler { + + List<ComponentConnector> children; + + private final boolean debugLogging = false; + + /** + * Temporary storage for last enabled state to be able to see if it has + * changed. Can be removed once we are able to listen specifically for + * enabled changes in the state. Widget.isEnabled() cannot be used as all + * Widgets do not implement HasEnabled + */ + private boolean lastWidgetEnabledState = true; + + /** + * Default constructor + */ + public AbstractComponentContainerConnector() { + addConnectorHierarchyChangeHandler(this); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ComponentContainerConnector#getChildren() + */ + public List<ComponentConnector> getChildren() { + if (children == null) { + return new LinkedList<ComponentConnector>(); + } + + return children; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ComponentContainerConnector#setChildren + * (java.util.Collection) + */ + public void setChildren(List<ComponentConnector> children) { + this.children = children; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ComponentContainerConnector# + * connectorHierarchyChanged + * (com.vaadin.terminal.gwt.client.ConnectorHierarchyChangedEvent) + */ + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + if (debugLogging) { + VConsole.log("Hierarchy changed for " + + Util.getConnectorString(this)); + String oldChildren = "* Old children: "; + for (ComponentConnector child : event.getOldChildren()) { + oldChildren += Util.getConnectorString(child) + " "; + } + VConsole.log(oldChildren); + + String newChildren = "* New children: "; + for (ComponentConnector child : getChildren()) { + newChildren += Util.getConnectorString(child) + " "; + } + VConsole.log(newChildren); + } + } + + public HandlerRegistration addConnectorHierarchyChangeHandler( + ConnectorHierarchyChangeHandler handler) { + return ensureHandlerManager().addHandler( + ConnectorHierarchyChangeEvent.TYPE, handler); + } + + @Override + public void setWidgetEnabled(boolean widgetEnabled) { + if (lastWidgetEnabledState == widgetEnabled) { + return; + } + lastWidgetEnabledState = widgetEnabled; + + super.setWidgetEnabled(widgetEnabled); + for (ComponentConnector c : getChildren()) { + // Update children as they might be affected by the enabled state of + // their parent + c.setWidgetEnabled(c.isEnabled()); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java new file mode 100644 index 0000000000..ef74228ae8 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractConnector.java @@ -0,0 +1,186 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.event.shared.GwtEvent; +import com.google.gwt.event.shared.HandlerManager; +import com.google.web.bindery.event.shared.HandlerRegistration; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ServerConnector; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.communication.ClientRpc; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler; + +/** + * An abstract implementation of Connector. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public abstract class AbstractConnector implements ServerConnector, + StateChangeHandler { + + private ApplicationConnection connection; + private String id; + + private HandlerManager handlerManager; + private Map<String, Collection<ClientRpc>> rpcImplementations; + private final boolean debugLogging = false; + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.VPaintable#getConnection() + */ + public final ApplicationConnection getConnection() { + return connection; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.Connector#getId() + */ + public String getConnectorId() { + return id; + } + + /** + * Called once by the framework to initialize the connector. + * <p> + * Note that the shared state is not yet available when this method is + * called. + * <p> + * Connector classes should override {@link #init()} instead of this method. + */ + public final void doInit(String connectorId, + ApplicationConnection connection) { + this.connection = connection; + id = connectorId; + + addStateChangeHandler(this); + init(); + } + + /** + * Called when the connector has been initialized. Override this method to + * perform initialization of the connector. + */ + // FIXME: It might make sense to make this abstract to force users to + // use init instead of constructor, where connection and id has not yet been + // set. + protected void init() { + + } + + /** + * Registers an implementation for a server to client RPC interface. + * + * Multiple registrations can be made for a single interface, in which case + * all of them receive corresponding RPC calls. + * + * @param rpcInterface + * RPC interface + * @param implementation + * implementation that should receive RPC calls + * @param <T> + * The type of the RPC interface that is being registered + */ + protected <T extends ClientRpc> void registerRpc(Class<T> rpcInterface, + T implementation) { + String rpcInterfaceId = rpcInterface.getName().replaceAll("\\$", "."); + if (null == rpcImplementations) { + rpcImplementations = new HashMap<String, Collection<ClientRpc>>(); + } + if (null == rpcImplementations.get(rpcInterfaceId)) { + rpcImplementations.put(rpcInterfaceId, new ArrayList<ClientRpc>()); + } + rpcImplementations.get(rpcInterfaceId).add(implementation); + } + + /** + * Unregisters an implementation for a server to client RPC interface. + * + * @param rpcInterface + * RPC interface + * @param implementation + * implementation to unregister + */ + protected <T extends ClientRpc> void unregisterRpc(Class<T> rpcInterface, + T implementation) { + String rpcInterfaceId = rpcInterface.getName().replaceAll("\\$", "."); + if (null != rpcImplementations + && null != rpcImplementations.get(rpcInterfaceId)) { + rpcImplementations.get(rpcInterfaceId).remove(implementation); + } + } + + public <T extends ClientRpc> Collection<T> getRpcImplementations( + String rpcInterfaceId) { + if (null == rpcImplementations) { + return Collections.emptyList(); + } + return (Collection<T>) rpcImplementations.get(rpcInterfaceId); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.Connector#isConnectorEnabled() + */ + public boolean isConnectorEnabled() { + // Client side can always receive message from the server + return true; + } + + public void fireEvent(GwtEvent<?> event) { + if (handlerManager != null) { + handlerManager.fireEvent(event); + } + } + + protected HandlerManager ensureHandlerManager() { + if (handlerManager == null) { + handlerManager = new HandlerManager(this); + } + + return handlerManager; + } + + public HandlerRegistration addStateChangeHandler(StateChangeHandler handler) { + return ensureHandlerManager() + .addHandler(StateChangeEvent.TYPE, handler); + } + + public void onStateChanged(StateChangeEvent stateChangeEvent) { + if (debugLogging) { + VConsole.log("State change event for " + + Util.getConnectorString(stateChangeEvent.getConnector()) + + " received by " + Util.getConnectorString(this)); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ServerConnector#onUnregister() + */ + public void onUnregister() { + if (debugLogging) { + VConsole.log("Unregistered connector " + + Util.getConnectorString(this)); + } + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java new file mode 100644 index 0000000000..4be0f02c2a --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractFieldConnector.java @@ -0,0 +1,54 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.AbstractFieldState; +import com.vaadin.terminal.gwt.client.ApplicationConnection; + +public abstract class AbstractFieldConnector extends AbstractComponentConnector { + + @Override + public AbstractFieldState getState() { + return (AbstractFieldState) super.getState(); + } + + @Override + public boolean isReadOnly() { + return super.isReadOnly() || getState().isPropertyReadOnly(); + } + + public boolean isModified() { + return getState().isModified(); + } + + /** + * Checks whether the required indicator should be shown for the field. + * + * Required indicators are hidden if the field or its data source is + * read-only. + * + * @return true if required indicator should be shown + */ + public boolean isRequired() { + return getState().isRequired() && !isReadOnly(); + } + + @Override + protected String getStyleNames(String primaryStyleName) { + String styleNames = super.getStyleNames(primaryStyleName); + + if (isModified()) { + // add modified classname to Fields + styleNames += " " + ApplicationConnection.MODIFIED_CLASSNAME; + } + + if (isRequired()) { + // add required classname to Fields + styleNames += " " + primaryStyleName + + ApplicationConnection.REQUIRED_CLASSNAME_EXT; + } + + return styleNames; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractLayoutConnector.java new file mode 100644 index 0000000000..175e67807f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractLayoutConnector.java @@ -0,0 +1,13 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +public abstract class AbstractLayoutConnector extends + AbstractComponentContainerConnector { + + @Override + public AbstractLayoutState getState() { + return (AbstractLayoutState) super.getState(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractLayoutState.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractLayoutState.java new file mode 100644 index 0000000000..fee5ea746a --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractLayoutState.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.ComponentState; + +public class AbstractLayoutState extends ComponentState { + private int marginsBitmask; + + public int getMarginsBitmask() { + return marginsBitmask; + } + + public void setMarginsBitmask(int marginsBitmask) { + this.marginsBitmask = marginsBitmask; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java index 3deb140d30..cffdb1e68a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java @@ -3,134 +3,48 @@ */ package com.vaadin.terminal.gwt.client.ui; -import java.util.HashMap; -import java.util.Map; - import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.event.dom.client.ContextMenuEvent; -import com.google.gwt.event.dom.client.ContextMenuHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.dom.client.DoubleClickEvent; -import com.google.gwt.event.dom.client.DoubleClickHandler; -import com.google.gwt.event.dom.client.MouseUpEvent; -import com.google.gwt.event.dom.client.MouseUpHandler; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; - -public abstract class ClickEventHandler implements DoubleClickHandler, - ContextMenuHandler, MouseUpHandler { +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; - private HandlerRegistration doubleClickHandlerRegistration; - private HandlerRegistration mouseUpHandlerRegistration; - private HandlerRegistration contextMenuHandlerRegistration; +public abstract class ClickEventHandler extends AbstractClickEventHandler { - protected String clickEventIdentifier; - protected Paintable paintable; - private ApplicationConnection client; + public static final String CLICK_EVENT_IDENTIFIER = "click"; - public ClickEventHandler(Paintable paintable, String clickEventIdentifier) { - this.paintable = paintable; - this.clickEventIdentifier = clickEventIdentifier; + public ClickEventHandler(ComponentConnector connector) { + this(connector, CLICK_EVENT_IDENTIFIER); } - public void handleEventHandlerRegistration(ApplicationConnection client) { - this.client = client; - // Handle registering/unregistering of click handler depending on if - // server side listeners have been added or removed. - if (hasEventListener()) { - if (mouseUpHandlerRegistration == null) { - mouseUpHandlerRegistration = registerHandler(this, - MouseUpEvent.getType()); - contextMenuHandlerRegistration = registerHandler(this, - ContextMenuEvent.getType()); - doubleClickHandlerRegistration = registerHandler(this, - DoubleClickEvent.getType()); - } - } else { - if (mouseUpHandlerRegistration != null) { - // Remove existing handlers - doubleClickHandlerRegistration.removeHandler(); - mouseUpHandlerRegistration.removeHandler(); - contextMenuHandlerRegistration.removeHandler(); - - contextMenuHandlerRegistration = null; - mouseUpHandlerRegistration = null; - doubleClickHandlerRegistration = null; - - } - } - - } - - protected abstract <H extends EventHandler> HandlerRegistration registerHandler( - final H handler, DomEvent.Type<H> type); - - protected ApplicationConnection getApplicationConnection() { - return client; - } - - public boolean hasEventListener() { - return getApplicationConnection().hasEventListeners(paintable, - clickEventIdentifier); + public ClickEventHandler(ComponentConnector connector, + String clickEventIdentifier) { + super(connector, clickEventIdentifier); } + /** + * Sends the click event based on the given native event. Delegates actual + * sending to {@link #fireClick(MouseEventDetails)}. + * + * @param event + * The native event that caused this click event + */ protected void fireClick(NativeEvent event) { - ApplicationConnection client = getApplicationConnection(); - String pid = getApplicationConnection().getPid(paintable); - - MouseEventDetails mouseDetails = new MouseEventDetails(event, - getRelativeToElement()); - - Map<String, Object> parameters = new HashMap<String, Object>(); - parameters.put("mouseDetails", mouseDetails.serialize()); - client.updateVariable(pid, clickEventIdentifier, parameters, true); - - } - - public void onContextMenu(ContextMenuEvent event) { - if (hasEventListener()) { - // Prevent showing the browser's context menu when there is a right - // click listener. - event.preventDefault(); - } - - } - - public void onMouseUp(MouseUpEvent event) { - // TODO For perfect accuracy we should check that a mousedown has - // occured on this element before this mouseup and that no mouseup - // has occured anywhere after that. - if (hasEventListener()) { - // "Click" with left, right or middle button - fireClick(event.getNativeEvent()); - } - } - - public void onDoubleClick(DoubleClickEvent event) { - if (hasEventListener()) { - fireClick(event.getNativeEvent()); - } + MouseEventDetails mouseDetails = MouseEventDetailsBuilder + .buildMouseEventDetails(event, getRelativeToElement()); + fireClick(event, mouseDetails); } /** - * Click event calculates and returns coordinates relative to the element - * returned by this method. Default implementation uses the root element of - * the widget. Override to provide a different relative element. + * Sends the click event to the server. Must be implemented by sub classes, + * typically by calling an RPC method. * - * @return The Element used for calculating relative coordinates for a click - * or null if no relative coordinates can be calculated. + * @param event + * The event that caused this click to be fired + * + * @param mouseDetails + * The mouse details for the event */ - protected Element getRelativeToElement() { - if (paintable instanceof Widget) { - return ((Widget) paintable).getElement(); - } - - return null; - } + protected abstract void fireClick(NativeEvent event, + MouseEventDetails mouseDetails); }
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickRpc.java b/src/com/vaadin/terminal/gwt/client/ui/ClickRpc.java new file mode 100644 index 0000000000..37d6443f55 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/ClickRpc.java @@ -0,0 +1,18 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public interface ClickRpc extends ServerRpc { + /** + * Called when a click event has occurred and there are server side + * listeners for the event. + * + * @param mouseDetails + * Details about the mouse when the event took place + */ + public void click(MouseEventDetails mouseDetails); +}
\ No newline at end of file diff --git a/src/com/vaadin/ui/ClientWidget.java b/src/com/vaadin/terminal/gwt/client/ui/Connect.java index 8817f8f776..0581bdb99c 100644 --- a/src/com/vaadin/ui/ClientWidget.java +++ b/src/com/vaadin/terminal/gwt/client/ui/Connect.java @@ -1,42 +1,39 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -/** - * - */ -package com.vaadin.ui; +package com.vaadin.terminal.gwt.client.ui; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.server.ClientConnector; import com.vaadin.terminal.gwt.widgetsetutils.CustomWidgetMapGenerator; import com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator; import com.vaadin.terminal.gwt.widgetsetutils.LazyWidgetMapGenerator; import com.vaadin.terminal.gwt.widgetsetutils.WidgetMapGenerator; /** - * Annotation defining the default client side counterpart in GWT terminal for - * {@link Component}. + * Annotation defining the server side connector that this ClientSideConnector + * should connect to. The value must always by a class extending + * {@link ClientConnector}. * <p> - * With this annotation server side Vaadin component is marked to have a client - * side counterpart. The value of the annotation is the class of client side + * With this annotation client side Vaadin connector is marked to have a server + * side counterpart. The value of the annotation is the class of server side * implementation. - * <p> - * Note, even though client side implementation is needed during development, - * one may safely remove them from the classpath of the production server. * - * @since 6.2 + * @since 7.0 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface ClientWidget { +public @interface Connect { + /** - * @return the client side counterpart for the annotated component + * @return the server side counterpart for the annotated component connector */ - Class<? extends Paintable> value(); + Class<? extends Connector> value(); /** * Depending on the used WidgetMap generator, these optional hints may be @@ -49,7 +46,7 @@ public @interface ClientWidget { * is not included in the initial JavaScript application loaded when the * application starts. Instead the implementation is loaded to the client * when it is first needed. Lazy loaded widget can be achieved by giving - * {@link LoadStyle#LAZY} value in ClientWidget annotation. + * {@link LoadStyle#LAZY} value in {@link Connect} annotation. * <p> * Lazy loaded widgets don't stress the size and startup time of the client * side as much as eagerly loaded widgets. On the other hand there is a @@ -93,5 +90,4 @@ public @interface ClientWidget { */ LAZY } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java index 1b97406ae0..4984c4ce3b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/FocusElementPanel.java @@ -13,11 +13,9 @@ import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.impl.FocusImpl; -import com.vaadin.terminal.gwt.client.BrowserInfo; /** * A panel that contains an always visible 0x0 size element that holds the focus - * for all browsers but IE6. */ public class FocusElementPanel extends SimpleFocusablePanel { @@ -30,22 +28,20 @@ public class FocusElementPanel extends SimpleFocusablePanel { @Override public void setWidget(Widget w) { super.setWidget(w); - if (!BrowserInfo.get().isIE6()) { - if (focusElement.getParentElement() == null) { - Style style = focusElement.getStyle(); - style.setPosition(Position.FIXED); - style.setTop(0, Unit.PX); - style.setLeft(0, Unit.PX); - getElement().appendChild(focusElement); - /* Sink from focusElement too as focus and blur don't bubble */ - DOM.sinkEvents( - (com.google.gwt.user.client.Element) focusElement - .cast(), Event.FOCUSEVENTS); - // revert to original, not focusable - getElement().setPropertyObject("tabIndex", null); - } else { - moveFocusElementAfterWidget(); - } + if (focusElement.getParentElement() == null) { + Style style = focusElement.getStyle(); + style.setPosition(Position.FIXED); + style.setTop(0, Unit.PX); + style.setLeft(0, Unit.PX); + getElement().appendChild(focusElement); + /* Sink from focusElement too as focus and blur don't bubble */ + DOM.sinkEvents( + (com.google.gwt.user.client.Element) focusElement.cast(), + Event.FOCUSEVENTS); + // revert to original, not focusable + getElement().setPropertyObject("tabIndex", null); + } else { + moveFocusElementAfterWidget(); } } @@ -58,28 +54,20 @@ public class FocusElementPanel extends SimpleFocusablePanel { @Override public void setFocus(boolean focus) { - if (BrowserInfo.get().isIE6()) { - super.setFocus(focus); + if (focus) { + FocusImpl.getFocusImplForPanel().focus( + (Element) focusElement.cast()); } else { - if (focus) { - FocusImpl.getFocusImplForPanel().focus( - (Element) focusElement.cast()); - } else { - FocusImpl.getFocusImplForPanel().blur( - (Element) focusElement.cast()); - } + FocusImpl.getFocusImplForPanel() + .blur((Element) focusElement.cast()); } } @Override public void setTabIndex(int tabIndex) { - if (BrowserInfo.get().isIE6()) { - super.setTabIndex(tabIndex); - } else { - getElement().setTabIndex(-1); - if (focusElement != null) { - focusElement.setTabIndex(tabIndex); - } + getElement().setTabIndex(-1); + if (focusElement != null) { + focusElement.setTabIndex(tabIndex); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java index 96cb4b8a35..533d6a78ae 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java @@ -24,7 +24,6 @@ import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.impl.FocusImpl; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.VConsole; /** * A scrollhandlers similar to {@link ScrollPanel}. @@ -60,18 +59,9 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements if (useFakeFocusElement()) { if (focusElement.getParentElement() == null) { Style style = focusElement.getStyle(); - if (BrowserInfo.get().isIE6()) { - style.setOverflow(Overflow.HIDDEN); - style.setHeight(0, Unit.PX); - style.setWidth(0, Unit.PX); - style.setPosition(Position.ABSOLUTE); - - addScrollHandler(this); - } else { - style.setPosition(Position.FIXED); - style.setTop(0, Unit.PX); - style.setLeft(0, Unit.PX); - } + style.setPosition(Position.FIXED); + style.setTop(0, Unit.PX); + style.setLeft(0, Unit.PX); getElement().appendChild(focusElement); /* Sink from focusElemet too as focusa and blur don't bubble */ DOM.sinkEvents( diff --git a/src/com/vaadin/terminal/gwt/client/ui/Icon.java b/src/com/vaadin/terminal/gwt/client/ui/Icon.java index fd2229fc8d..b64605aac9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/Icon.java +++ b/src/com/vaadin/terminal/gwt/client/ui/Icon.java @@ -19,7 +19,6 @@ public class Icon extends UIObject { DOM.setElementProperty(getElement(), "alt", ""); setStyleName(CLASSNAME); this.client = client; - client.addPngFix(getElement()); } public Icon(ApplicationConnection client, String uidlUri) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java index 3a4048907f..7a5d85e34b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java @@ -3,39 +3,37 @@ */ package com.vaadin.terminal.gwt.client.ui; -import java.util.HashMap; -import java.util.Map; - import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.Element; -import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; + +public abstract class LayoutClickEventHandler extends AbstractClickEventHandler { -public abstract class LayoutClickEventHandler extends ClickEventHandler { + public static final String LAYOUT_CLICK_EVENT_IDENTIFIER = "lClick"; - public LayoutClickEventHandler(Paintable paintable, + public LayoutClickEventHandler(ComponentConnector connector) { + this(connector, LAYOUT_CLICK_EVENT_IDENTIFIER); + } + + public LayoutClickEventHandler(ComponentConnector connector, String clickEventIdentifier) { - super(paintable, clickEventIdentifier); + super(connector, clickEventIdentifier); } - protected abstract Paintable getChildComponent(Element element); + protected abstract ComponentConnector getChildComponent(Element element); + + protected ComponentConnector getChildComponent(NativeEvent event) { + return getChildComponent((Element) event.getEventTarget().cast()); + } @Override protected void fireClick(NativeEvent event) { - ApplicationConnection client = getApplicationConnection(); - String pid = getApplicationConnection().getPid(paintable); - - MouseEventDetails mouseDetails = new MouseEventDetails(event, - getRelativeToElement()); - Paintable childComponent = getChildComponent((Element) event - .getEventTarget().cast()); - - Map<String, Object> parameters = new HashMap<String, Object>(); - parameters.put("mouseDetails", mouseDetails.serialize()); - parameters.put("component", childComponent); - - client.updateVariable(pid, clickEventIdentifier, parameters, true); + MouseEventDetails mouseDetails = MouseEventDetailsBuilder + .buildMouseEventDetails(event, getRelativeToElement()); + getLayoutClickRPC().layoutClick(mouseDetails, getChildComponent(event)); } + protected abstract LayoutClickRpc getLayoutClickRPC(); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRpc.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRpc.java new file mode 100644 index 0000000000..5b76f398a9 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickRpc.java @@ -0,0 +1,22 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public interface LayoutClickRpc extends ServerRpc { + /** + * Called when a layout click event has occurred and there are server side + * listeners for the event. + * + * @param mouseDetails + * Details about the mouse when the event took place + * @param clickedConnector + * The child component that was the target of the event + */ + public void layoutClick(MouseEventDetails mouseDetails, + Connector clickedConnector); +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/ManagedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/ManagedLayout.java new file mode 100644 index 0000000000..6d0271ee40 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/ManagedLayout.java @@ -0,0 +1,10 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.ComponentConnector; + +public interface ManagedLayout extends ComponentConnector { + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/MediaBaseConnector.java b/src/com/vaadin/terminal/gwt/client/ui/MediaBaseConnector.java new file mode 100644 index 0000000000..1e067bf6fb --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/MediaBaseConnector.java @@ -0,0 +1,130 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.communication.ClientRpc; + +public abstract class MediaBaseConnector extends AbstractComponentConnector + implements Paintable { + + public static final String TAG_SOURCE = "src"; + + public static final String ATTR_MUTED = "muted"; + public static final String ATTR_CONTROLS = "ctrl"; + public static final String ATTR_AUTOPLAY = "auto"; + public static final String ATTR_RESOURCE = "res"; + public static final String ATTR_RESOURCE_TYPE = "type"; + public static final String ATTR_HTML = "html"; + public static final String ATTR_ALT_TEXT = "alt"; + + /** + * Server to client RPC interface for controlling playback of the media. + * + * @since 7.0 + */ + public static interface MediaControl extends ClientRpc { + /** + * Start playing the media. + */ + public void play(); + + /** + * Pause playback of the media. + */ + public void pause(); + } + + @Override + protected void init() { + super.init(); + + registerRpc(MediaControl.class, new MediaControl() { + public void play() { + getWidget().play(); + } + + public void pause() { + getWidget().pause(); + } + }); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().setControls(shouldShowControls(uidl)); + getWidget().setAutoplay(shouldAutoplay(uidl)); + getWidget().setMuted(isMediaMuted(uidl)); + + // Add all sources + for (int ix = 0; ix < uidl.getChildCount(); ix++) { + UIDL child = uidl.getChildUIDL(ix); + if (TAG_SOURCE.equals(child.getTag())) { + getWidget() + .addSource(getSourceUrl(child), getSourceType(child)); + } + } + setAltText(uidl); + } + + protected boolean shouldShowControls(UIDL uidl) { + return uidl.getBooleanAttribute(ATTR_CONTROLS); + } + + private boolean shouldAutoplay(UIDL uidl) { + return uidl.getBooleanAttribute(ATTR_AUTOPLAY); + } + + private boolean isMediaMuted(UIDL uidl) { + return uidl.getBooleanAttribute(ATTR_MUTED); + } + + private boolean allowHtmlContent(UIDL uidl) { + return uidl.getBooleanAttribute(ATTR_HTML); + } + + @Override + public VMediaBase getWidget() { + return (VMediaBase) super.getWidget(); + } + + /** + * @param uidl + * @return the URL of a resource to be used as a source for the media + */ + private String getSourceUrl(UIDL uidl) { + String url = getConnection().translateVaadinUri( + uidl.getStringAttribute(MediaBaseConnector.ATTR_RESOURCE)); + if (url == null) { + return ""; + } + return url; + } + + /** + * @param uidl + * @return the mime type of the media + */ + private String getSourceType(UIDL uidl) { + return uidl.getStringAttribute(MediaBaseConnector.ATTR_RESOURCE_TYPE); + } + + private void setAltText(UIDL uidl) { + String alt = uidl.getStringAttribute(MediaBaseConnector.ATTR_ALT_TEXT); + + if (alt == null || "".equals(alt)) { + alt = getWidget().getDefaultAltHtml(); + } else if (!allowHtmlContent(uidl)) { + alt = Util.escapeHTML(alt); + } + getWidget().setAltText(alt); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/PostLayoutListener.java b/src/com/vaadin/terminal/gwt/client/ui/PostLayoutListener.java new file mode 100644 index 0000000000..feb7494f87 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/PostLayoutListener.java @@ -0,0 +1,8 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +public interface PostLayoutListener { + public void postLayout(); +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java index 934fcaa8b7..37e9ab4a69 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java @@ -15,11 +15,9 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.KeyboardListener; import com.google.gwt.user.client.ui.KeyboardListenerCollection; -import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea; @@ -34,9 +32,8 @@ import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea; public class ShortcutActionHandler { /** - * An interface implemented by those users (most often {@link Container}s, - * but HasWidgets at least) of this helper class that want to support - * special components like {@link VRichTextArea} that don't properly + * An interface implemented by those users of this helper class that want to + * support special components like {@link VRichTextArea} that don't properly * propagate key down events. Those components can build support for * shortcut actions by traversing the closest * {@link ShortcutActionHandlerOwner} from the component hierarchy an @@ -52,12 +49,12 @@ public class ShortcutActionHandler { } /** - * A focusable {@link Paintable} implementing this interface will be - * notified before shortcut actions are handled if it will be the target of - * the action (most commonly means it is the focused component during the + * A focusable {@link ComponentConnector} implementing this interface will + * be notified before shortcut actions are handled if it will be the target + * of the action (most commonly means it is the focused component during the * keyboard combination is triggered by the user). */ - public interface BeforeShortcutActionListener extends Paintable { + public interface BeforeShortcutActionListener extends ComponentConnector { /** * This method is called by ShortcutActionHandler before firing the * shortcut if the Paintable is currently focused (aka the target of the @@ -111,7 +108,7 @@ public class ShortcutActionHandler { } } - public void handleKeyboardEvent(final Event event, Paintable target) { + public void handleKeyboardEvent(final Event event, ComponentConnector target) { final int modifiers = KeyboardListenerCollection .getKeyboardModifiers(event); final char keyCode = (char) DOM.eventGetKeyCode(event); @@ -133,16 +130,12 @@ public class ShortcutActionHandler { } private void fireAction(final Event event, final ShortcutAction a, - Paintable target) { + ComponentConnector target) { final Element et = DOM.eventGetTarget(event); if (target == null) { - Widget w = Util.findWidget(et, null); - while (w != null && !(w instanceof Paintable)) { - w = w.getParent(); - } - target = (Paintable) w; + target = Util.findPaintable(client, et); } - final Paintable finalTarget = target; + final ComponentConnector finalTarget = target; event.preventDefault(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/SimpleManagedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/SimpleManagedLayout.java new file mode 100644 index 0000000000..9ccb29a750 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/SimpleManagedLayout.java @@ -0,0 +1,8 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +public interface SimpleManagedLayout extends ManagedLayout { + public void layout(); +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/TabIndexState.java b/src/com/vaadin/terminal/gwt/client/ui/TabIndexState.java new file mode 100644 index 0000000000..7ffb328add --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/TabIndexState.java @@ -0,0 +1,29 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +/** + * Interface implemented by state classes that support tab indexes. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public interface TabIndexState { + /** + * Gets the <i>tabulator index</i> of the field. + * + * @return the tab index for the Field + */ + public int getTabIndex(); + + /** + * Sets the <i>tabulator index</i> of the field. + * + * @param tabIndex + * the tab index to set + */ + public void setTabIndex(int tabIndex); +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/Table.java b/src/com/vaadin/terminal/gwt/client/ui/Table.java deleted file mode 100644 index 4b3ba0422e..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/Table.java +++ /dev/null @@ -1,15 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.user.client.ui.HasWidgets; -import com.vaadin.terminal.gwt.client.Paintable; - -public interface Table extends Paintable, HasWidgets { - final int SELECT_MODE_NONE = 0; - final int SELECT_MODE_SINGLE = 1; - final int SELECT_MODE_MULTI = 2; - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java new file mode 100644 index 0000000000..94eff44eee --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/UnknownComponentConnector.java @@ -0,0 +1,39 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; + +public class UnknownComponentConnector extends AbstractComponentConnector { + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + @Override + protected Widget createWidget() { + return GWT.create(VUnknownComponent.class); + } + + @Override + public VUnknownComponent getWidget() { + return (VUnknownComponent) super.getWidget(); + } + + public void setServerSideClassName(String serverClassName) { + getWidget() + .setCaption( + "Widgetset does not contain implementation for " + + serverClassName + + ". Check its component connector's @Connect mapping, widgetsets " + + "GWT module description file and re-compile your" + + " widgetset. In case you have downloaded a vaadin" + + " add-on package, you might want to refer to " + + "<a href='http://vaadin.com/using-addons'>add-on " + + "instructions</a>."); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java deleted file mode 100644 index a6abc411f8..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java +++ /dev/null @@ -1,442 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Style; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.ComplexPanel; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VCaption; -import com.vaadin.terminal.gwt.client.VConsole; - -public class VAbsoluteLayout extends ComplexPanel implements Container { - - /** Tag name for widget creation */ - public static final String TAGNAME = "absolutelayout"; - - /** Class name, prefix in styling */ - public static final String CLASSNAME = "v-absolutelayout"; - - private DivElement marginElement; - - protected final Element canvas = DOM.createDiv(); - - // private int excessPixelsHorizontal; - // - // private int excessPixelsVertical; - - private Object previousStyleName; - - private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>(); - - protected ApplicationConnection client; - - private boolean rendering; - - private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( - this, EventId.LAYOUT_CLICK) { - - @Override - protected Paintable getChildComponent(Element element) { - return getComponent(element); - } - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - - public VAbsoluteLayout() { - setElement(Document.get().createDivElement()); - setStyleName(CLASSNAME); - marginElement = Document.get().createDivElement(); - canvas.getStyle().setProperty("position", "relative"); - canvas.getStyle().setProperty("overflow", "hidden"); - marginElement.appendChild(canvas); - getElement().appendChild(marginElement); - } - - public RenderSpace getAllocatedSpace(Widget child) { - // TODO needs some special handling for components with only on edge - // horizontally or vertically defined - AbsoluteWrapper wrapper = (AbsoluteWrapper) child.getParent(); - int w; - if (wrapper.left != null && wrapper.right != null) { - w = wrapper.getOffsetWidth(); - } else if (wrapper.right != null) { - // left == null - // available width == right edge == offsetleft + width - w = wrapper.getOffsetWidth() + wrapper.getElement().getOffsetLeft(); - } else { - // left != null && right == null || left == null && - // right == null - // available width == canvas width - offset left - w = canvas.getOffsetWidth() - wrapper.getElement().getOffsetLeft(); - } - int h; - if (wrapper.top != null && wrapper.bottom != null) { - h = wrapper.getOffsetHeight(); - } else if (wrapper.bottom != null) { - // top not defined, available space 0... bottom of wrapper - h = wrapper.getElement().getOffsetTop() + wrapper.getOffsetHeight(); - } else { - // top defined or both undefined, available space == canvas - top - h = canvas.getOffsetHeight() - wrapper.getElement().getOffsetTop(); - } - - return new RenderSpace(w, h); - } - - public boolean hasChildComponent(Widget component) { - for (Iterator<Entry<String, AbsoluteWrapper>> iterator = pidToComponentWrappper - .entrySet().iterator(); iterator.hasNext();) { - if (iterator.next().getValue().paintable == component) { - return true; - } - } - return false; - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - for (Widget wrapper : getChildren()) { - AbsoluteWrapper w = (AbsoluteWrapper) wrapper; - if (w.getWidget() == oldComponent) { - w.setWidget(newComponent); - return; - } - } - } - - public boolean requestLayout(Set<Paintable> children) { - // component inside an absolute panel never affects parent nor the - // layout - return true; - } - - public void updateCaption(Paintable component, UIDL uidl) { - AbsoluteWrapper parent2 = (AbsoluteWrapper) ((Widget) component) - .getParent(); - parent2.updateCaption(uidl); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - this.client = client; - // TODO margin handling - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - - clickEventHandler.handleEventHandlerRegistration(client); - - HashSet<String> unrenderedPids = new HashSet<String>( - pidToComponentWrappper.keySet()); - - for (Iterator<Object> childIterator = uidl.getChildIterator(); childIterator - .hasNext();) { - UIDL cc = (UIDL) childIterator.next(); - if (cc.getTag().equals("cc")) { - UIDL componentUIDL = cc.getChildUIDL(0); - unrenderedPids.remove(componentUIDL.getId()); - getWrapper(client, componentUIDL).updateFromUIDL(cc); - } - } - - for (String pid : unrenderedPids) { - AbsoluteWrapper absoluteWrapper = pidToComponentWrappper.get(pid); - pidToComponentWrappper.remove(pid); - absoluteWrapper.destroy(); - } - rendering = false; - } - - private AbsoluteWrapper getWrapper(ApplicationConnection client, - UIDL componentUIDL) { - AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL - .getId()); - if (wrapper == null) { - wrapper = new AbsoluteWrapper(client.getPaintable(componentUIDL)); - pidToComponentWrappper.put(componentUIDL.getId(), wrapper); - add(wrapper); - } - return wrapper; - - } - - @Override - public void add(Widget child) { - super.add(child, canvas); - } - - @Override - public void setStyleName(String style) { - super.setStyleName(style); - if (previousStyleName == null || !previousStyleName.equals(style)) { - // excessPixelsHorizontal = -1; - // excessPixelsVertical = -1; - } - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - // TODO do this so that canvas gets the sized properly (the area - // inside marginals) - canvas.getStyle().setProperty("width", width); - - if (!rendering) { - if (BrowserInfo.get().isIE6()) { - relayoutWrappersForIe6(); - } - relayoutRelativeChildren(); - } - } - - private void relayoutRelativeChildren() { - for (Widget widget : getChildren()) { - if (widget instanceof AbsoluteWrapper) { - AbsoluteWrapper w = (AbsoluteWrapper) widget; - client.handleComponentRelativeSize(w.getWidget()); - w.updateCaptionPosition(); - } - } - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - // TODO do this so that canvas gets the sized properly (the area - // inside marginals) - canvas.getStyle().setProperty("height", height); - - if (!rendering) { - if (BrowserInfo.get().isIE6()) { - relayoutWrappersForIe6(); - } - relayoutRelativeChildren(); - } - } - - private void relayoutWrappersForIe6() { - for (Widget wrapper : getChildren()) { - if (wrapper instanceof AbsoluteWrapper) { - ((AbsoluteWrapper) wrapper).ie6Layout(); - } - } - } - - public class AbsoluteWrapper extends SimplePanel { - private String css; - private String left; - private String top; - private String right; - private String bottom; - private String zIndex; - - private Paintable paintable; - private VCaption caption; - - public AbsoluteWrapper(Paintable paintable) { - this.paintable = paintable; - setStyleName(CLASSNAME + "-wrapper"); - } - - public void updateCaption(UIDL uidl) { - - boolean captionIsNeeded = VCaption.isNeeded(uidl); - if (captionIsNeeded) { - if (caption == null) { - caption = new VCaption(paintable, client); - VAbsoluteLayout.this.add(caption); - } - caption.updateCaption(uidl); - updateCaptionPosition(); - } else { - if (caption != null) { - caption.removeFromParent(); - caption = null; - } - } - } - - @Override - public void setWidget(Widget w) { - // this fixes #5457 (Widget implementation can change on-the-fly) - paintable = (Paintable) w; - super.setWidget(w); - } - - public void destroy() { - if (caption != null) { - caption.removeFromParent(); - } - client.unregisterPaintable(paintable); - removeFromParent(); - } - - public void updateFromUIDL(UIDL componentUIDL) { - setPosition(componentUIDL.getStringAttribute("css")); - if (getWidget() != paintable) { - setWidget((Widget) paintable); - } - UIDL childUIDL = componentUIDL.getChildUIDL(0); - paintable.updateFromUIDL(childUIDL, client); - if (childUIDL.hasAttribute("cached")) { - // child may need relative size adjustment if wrapper details - // have changed this could be optimized (check if wrapper size - // has changed) - client.handleComponentRelativeSize((Widget) paintable); - } - } - - public void setPosition(String stringAttribute) { - if (css == null || !css.equals(stringAttribute)) { - css = stringAttribute; - top = right = bottom = left = zIndex = null; - if (!css.equals("")) { - String[] properties = css.split(";"); - for (int i = 0; i < properties.length; i++) { - String[] keyValue = properties[i].split(":"); - if (keyValue[0].equals("left")) { - left = keyValue[1]; - } else if (keyValue[0].equals("top")) { - top = keyValue[1]; - } else if (keyValue[0].equals("right")) { - right = keyValue[1]; - } else if (keyValue[0].equals("bottom")) { - bottom = keyValue[1]; - } else if (keyValue[0].equals("z-index")) { - zIndex = keyValue[1]; - } - } - } - // ensure ne values - Style style = getElement().getStyle(); - /* - * IE8 dies when nulling zIndex, even in IE7 mode. All other css - * properties (and even in older IE's) accept null values just - * fine. Assign empty string instead of null. - */ - if (zIndex != null) { - style.setProperty("zIndex", zIndex); - } else { - style.setProperty("zIndex", ""); - } - style.setProperty("top", top); - style.setProperty("left", left); - style.setProperty("right", right); - style.setProperty("bottom", bottom); - - if (BrowserInfo.get().isIE6()) { - ie6Layout(); - } - } - updateCaptionPosition(); - } - - private void updateCaptionPosition() { - if (caption != null) { - Style style = caption.getElement().getStyle(); - style.setProperty("position", "absolute"); - style.setPropertyPx("left", getElement().getOffsetLeft()); - style.setPropertyPx("top", getElement().getOffsetTop() - - caption.getHeight()); - } - } - - private void ie6Layout() { - // special handling for IE6 is needed, it does not support - // setting both left/right or top/bottom - Style style = getElement().getStyle(); - if (bottom != null && top != null) { - // define height for wrapper to simulate bottom property - int bottompixels = measureForIE6(bottom, true); - VConsole.log("ALB" + bottompixels); - int height = canvas.getOffsetHeight() - bottompixels - - getElement().getOffsetTop(); - VConsole.log("ALB" + height); - if (height < 0) { - height = 0; - } - style.setPropertyPx("height", height); - } else { - // reset possibly existing value - style.setProperty("height", ""); - } - if (left != null && right != null) { - // define width for wrapper to simulate right property - int rightPixels = measureForIE6(right, false); - VConsole.log("ALR" + rightPixels); - int width = canvas.getOffsetWidth() - rightPixels - - getElement().getOffsetLeft(); - VConsole.log("ALR" + width); - if (width < 0) { - width = 0; - } - style.setPropertyPx("width", width); - } else { - // reset possibly existing value - style.setProperty("width", ""); - } - } - - } - - private Element measureElement; - - private int measureForIE6(String cssLength, boolean vertical) { - if (measureElement == null) { - measureElement = DOM.createDiv(); - measureElement.getStyle().setProperty("position", "absolute"); - canvas.appendChild(measureElement); - } - if (vertical) { - measureElement.getStyle().setProperty("height", cssLength); - return measureElement.getOffsetHeight(); - } else { - measureElement.getStyle().setProperty("width", cssLength); - return measureElement.getOffsetWidth(); - } - } - - /** - * Returns the deepest nested child component which contains "element". The - * child component is also returned if "element" is part of its caption. - * - * @param element - * An element that is a nested sub element of the root element in - * this layout - * @return The Paintable which the element is a part of. Null if the element - * belongs to the layout and not to a child. - */ - private Paintable getComponent(Element element) { - return Util.getPaintableForElement(client, this, element); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java b/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java deleted file mode 100644 index b1eda728dc..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java +++ /dev/null @@ -1,196 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.dom.client.InputElement; -import com.google.gwt.dom.client.LabelElement; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.EventHelper; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; - -public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements - Paintable, Field, FocusHandler, BlurHandler { - - public static final String CLASSNAME = "v-checkbox"; - - String id; - - boolean immediate; - - ApplicationConnection client; - - private Element errorIndicatorElement; - - private Icon icon; - - private HandlerRegistration focusHandlerRegistration; - private HandlerRegistration blurHandlerRegistration; - - public VCheckBox() { - setStyleName(CLASSNAME); - addClickHandler(new ClickHandler() { - - public void onClick(ClickEvent event) { - if (id == null || client == null || !isEnabled()) { - return; - } - - // Add mouse details - MouseEventDetails details = new MouseEventDetails( - event.getNativeEvent(), getElement()); - client.updateVariable(id, "mousedetails", details.serialize(), - false); - client.updateVariable(id, "state", getValue(), immediate); - } - - }); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - Element el = DOM.getFirstChild(getElement()); - while (el != null) { - DOM.sinkEvents(el, - (DOM.getEventsSunk(el) | VTooltip.TOOLTIP_EVENTS)); - el = DOM.getNextSibling(el); - } - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Save details - this.client = client; - id = uidl.getId(); - - // Ensure correct implementation - if (client.updateComponent(this, uidl, false)) { - return; - } - - focusHandlerRegistration = EventHelper.updateFocusHandler(this, client, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, client, - blurHandlerRegistration); - - if (uidl.hasAttribute("error")) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createSpan(); - errorIndicatorElement.setInnerHTML(" "); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - DOM.appendChild(getElement(), errorIndicatorElement); - DOM.sinkEvents(errorIndicatorElement, VTooltip.TOOLTIP_EVENTS - | Event.ONCLICK); - } else { - DOM.setStyleAttribute(errorIndicatorElement, "display", ""); - } - } else if (errorIndicatorElement != null) { - DOM.setStyleAttribute(errorIndicatorElement, "display", "none"); - } - - if (uidl.hasAttribute("readonly")) { - setEnabled(false); - } - - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - DOM.insertChild(getElement(), icon.getElement(), 1); - icon.sinkEvents(VTooltip.TOOLTIP_EVENTS); - icon.sinkEvents(Event.ONCLICK); - } - icon.setUri(uidl.getStringAttribute("icon")); - } else if (icon != null) { - // detach icon - DOM.removeChild(getElement(), icon.getElement()); - icon = null; - } - - // Set text - setText(uidl.getStringAttribute("caption")); - setValue(uidl.getBooleanVariable("state")); - immediate = uidl.getBooleanAttribute("immediate"); - } - - @Override - public void setText(String text) { - super.setText(text); - if (BrowserInfo.get().isIE() && BrowserInfo.get().getIEVersion() < 8) { - - boolean breakLink = text == null || "".equals(text); - - // break or create link between label element and checkbox, to - // enable native focus outline around checkbox element itself, if - // caption is not present - NodeList<Node> childNodes = getElement().getChildNodes(); - String id = null; - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.getItem(i); - if (item.getNodeName().toLowerCase().equals("input")) { - InputElement input = (InputElement) item; - id = input.getId(); - } - if (item.getNodeName().toLowerCase().equals("label")) { - LabelElement label = (LabelElement) item; - if (breakLink) { - label.setHtmlFor(""); - } else { - label.setHtmlFor(id); - } - } - } - } - } - - @Override - public void onBrowserEvent(Event event) { - if (icon != null && (event.getTypeInt() == Event.ONCLICK) - && (DOM.eventGetTarget(event) == icon.getElement())) { - // Click on icon should do nothing if widget is disabled - if (isEnabled()) { - setValue(!getValue()); - } - } - super.onBrowserEvent(event); - if (event.getTypeInt() == Event.ONLOAD) { - Util.notifyParentOfSizeChange(this, true); - } - if (client != null) { - client.handleTooltipEvent(event, this); - } - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - } - - public void onFocus(FocusEvent arg0) { - client.updateVariable(id, EventId.FOCUS, "", true); - } - - public void onBlur(BlurEvent arg0) { - client.updateVariable(id, EventId.BLUR, "", true); - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java b/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java index 8158fd90c2..692e13bd94 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java @@ -31,7 +31,6 @@ import com.google.gwt.user.client.ui.MenuBar; import com.google.gwt.user.client.ui.MenuItem; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.impl.FocusImpl; -import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.Util; @@ -45,8 +44,8 @@ public class VContextMenu extends VOverlay implements SubPartAware { private int top; - private VLazyExecutor delayedImageLoadExecutioner = new VLazyExecutor( - 100, new ScheduledCommand() { + private VLazyExecutor delayedImageLoadExecutioner = new VLazyExecutor(100, + new ScheduledCommand() { public void execute() { imagesLoaded(); } @@ -218,11 +217,6 @@ public class VContextMenu extends VOverlay implements SubPartAware { public void onLoad(LoadEvent event) { // Handle icon onload events to ensure shadow is resized correctly - if (BrowserInfo.get().isIE6()) { - // Ensure PNG transparency works in IE6 - Util.doIE6PngFix((Element) Element.as(event.getNativeEvent() - .getEventTarget())); - } delayedImageLoadExecutioner.trigger(); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java deleted file mode 100644 index 585180f8f4..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VCssLayout.java +++ /dev/null @@ -1,342 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.google.gwt.dom.client.Style; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.StyleConstants; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VCaption; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ValueMap; - -public class VCssLayout extends SimplePanel implements Paintable, Container { - public static final String TAGNAME = "csslayout"; - public static final String CLASSNAME = "v-" + TAGNAME; - - private FlowPane panel = new FlowPane(); - - private Element margin = DOM.createDiv(); - - private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( - this, EventId.LAYOUT_CLICK) { - - @Override - protected Paintable getChildComponent(Element element) { - return panel.getComponent(element); - } - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - - private boolean hasHeight; - private boolean hasWidth; - private boolean rendering; - - public VCssLayout() { - super(); - getElement().appendChild(margin); - setStyleName(CLASSNAME); - margin.setClassName(CLASSNAME + "-margin"); - setWidget(panel); - } - - @Override - protected Element getContainerElement() { - return margin; - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - // panel.setWidth(width); - hasWidth = width != null && !width.equals(""); - if (!rendering) { - panel.updateRelativeSizes(); - } - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - // panel.setHeight(height); - hasHeight = height != null && !height.equals(""); - if (!rendering) { - panel.updateRelativeSizes(); - } - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - clickEventHandler.handleEventHandlerRegistration(client); - - final VMarginInfo margins = new VMarginInfo( - uidl.getIntAttribute("margins")); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP, - margins.hasTop()); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT, - margins.hasRight()); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM, - margins.hasBottom()); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT, - margins.hasLeft()); - - setStyleName(margin, CLASSNAME + "-" + "spacing", - uidl.hasAttribute("spacing")); - panel.updateFromUIDL(uidl, client); - rendering = false; - } - - public boolean hasChildComponent(Widget component) { - return panel.hasChildComponent(component); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - panel.replaceChildComponent(oldComponent, newComponent); - } - - public void updateCaption(Paintable component, UIDL uidl) { - panel.updateCaption(component, uidl); - } - - public class FlowPane extends FlowPanel { - - private final HashMap<Widget, VCaption> widgetToCaption = new HashMap<Widget, VCaption>(); - private ApplicationConnection client; - private int lastIndex; - - public FlowPane() { - super(); - setStyleName(CLASSNAME + "-container"); - } - - public void updateRelativeSizes() { - for (Widget w : getChildren()) { - if (w instanceof Paintable) { - client.handleComponentRelativeSize(w); - } - } - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - // for later requests - this.client = client; - - final Collection<Widget> oldWidgets = new HashSet<Widget>(); - for (final Iterator<Widget> iterator = iterator(); iterator - .hasNext();) { - oldWidgets.add(iterator.next()); - } - - ValueMap mapAttribute = null; - if (uidl.hasAttribute("css")) { - mapAttribute = uidl.getMapAttribute("css"); - } - - lastIndex = 0; - for (final Iterator<Object> i = uidl.getChildIterator(); i - .hasNext();) { - final UIDL r = (UIDL) i.next(); - final Paintable child = client.getPaintable(r); - final Widget widget = (Widget) child; - if (widget.getParent() == this) { - oldWidgets.remove(child); - VCaption vCaption = widgetToCaption.get(child); - if (vCaption != null) { - addOrMove(vCaption, lastIndex++); - oldWidgets.remove(vCaption); - } - } - - addOrMove(widget, lastIndex++); - if (mapAttribute != null && mapAttribute.containsKey(r.getId())) { - String css = null; - try { - Style style = widget.getElement().getStyle(); - css = mapAttribute.getString(r.getId()); - String[] cssRules = css.split(";"); - for (int j = 0; j < cssRules.length; j++) { - String[] rule = cssRules[j].split(":"); - if (rule.length == 0) { - continue; - } else { - style.setProperty( - makeCamelCase(rule[0].trim()), - rule[1].trim()); - } - } - } catch (Exception e) { - VConsole.log("CssLayout encounterd invalid css string: " - + css); - } - } - - if (!r.getBooleanAttribute("cached")) { - child.updateFromUIDL(r, client); - } - } - - // loop oldWidgetWrappers that where not re-attached and unregister - // them - for (Widget w : oldWidgets) { - remove(w); - if (w instanceof Paintable) { - final Paintable p = (Paintable) w; - client.unregisterPaintable(p); - } - VCaption vCaption = widgetToCaption.remove(w); - if (vCaption != null) { - remove(vCaption); - } - } - } - - private void addOrMove(Widget child, int index) { - if (child.getParent() == this) { - int currentIndex = getWidgetIndex(child); - if (index == currentIndex) { - return; - } - } - insert(child, index); - } - - public boolean hasChildComponent(Widget component) { - return component.getParent() == this; - } - - public void replaceChildComponent(Widget oldComponent, - Widget newComponent) { - VCaption caption = widgetToCaption.get(oldComponent); - if (caption != null) { - remove(caption); - widgetToCaption.remove(oldComponent); - } - int index = getWidgetIndex(oldComponent); - if (index >= 0) { - remove(oldComponent); - insert(newComponent, index); - } - } - - public void updateCaption(Paintable component, UIDL uidl) { - VCaption caption = widgetToCaption.get(component); - if (VCaption.isNeeded(uidl)) { - Widget widget = (Widget) component; - if (caption == null) { - caption = new VCaption(component, client); - widgetToCaption.put(widget, caption); - insert(caption, getWidgetIndex(widget)); - lastIndex++; - } else if (!caption.isAttached()) { - insert(caption, getWidgetIndex(widget)); - lastIndex++; - } - caption.updateCaption(uidl); - } else if (caption != null) { - remove(caption); - widgetToCaption.remove(component); - } - } - - private Paintable getComponent(Element element) { - return Util - .getPaintableForElement(client, VCssLayout.this, element); - } - - } - - private RenderSpace space; - - public RenderSpace getAllocatedSpace(Widget child) { - if (space == null) { - space = new RenderSpace(-1, -1) { - @Override - public int getWidth() { - if (BrowserInfo.get().isIE()) { - int width = getOffsetWidth(); - int margins = margin.getOffsetWidth() - - panel.getOffsetWidth(); - return width - margins; - } else { - return panel.getOffsetWidth(); - } - } - - @Override - public int getHeight() { - int height = getOffsetHeight(); - int margins = margin.getOffsetHeight() - - panel.getOffsetHeight(); - return height - margins; - } - }; - } - return space; - } - - public boolean requestLayout(Set<Paintable> children) { - if (hasSize()) { - return true; - } else { - // Size may have changed - // TODO optimize this: cache size if not fixed, handle both width - // and height separately - return false; - } - } - - private boolean hasSize() { - return hasWidth && hasHeight; - } - - private static final String makeCamelCase(String cssProperty) { - // TODO this might be cleaner to implement with regexp - while (cssProperty.contains("-")) { - int indexOf = cssProperty.indexOf("-"); - cssProperty = cssProperty.substring(0, indexOf) - + String.valueOf(cssProperty.charAt(indexOf + 1)) - .toUpperCase() + cssProperty.substring(indexOf + 2); - } - if ("float".equals(cssProperty)) { - if (BrowserInfo.get().isIE()) { - return "styleFloat"; - } else { - return "cssFloat"; - } - } - return cssProperty; - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java deleted file mode 100644 index 1fb3f297ad..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java +++ /dev/null @@ -1,168 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Set; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; - -public class VCustomComponent extends SimplePanel implements Container { - - private static final String CLASSNAME = "v-customcomponent"; - private String height; - private ApplicationConnection client; - private boolean rendering; - private String width; - private RenderSpace renderSpace = new RenderSpace(); - - public VCustomComponent() { - super(); - setStyleName(CLASSNAME); - } - - public void updateFromUIDL(UIDL uidl, final ApplicationConnection client) { - rendering = true; - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - this.client = client; - - final UIDL child = uidl.getChildUIDL(0); - if (child != null) { - final Paintable p = client.getPaintable(child); - if (p != getWidget()) { - if (getWidget() != null) { - client.unregisterPaintable((Paintable) getWidget()); - clear(); - } - setWidget((Widget) p); - } - p.updateFromUIDL(child, client); - } - - boolean updateDynamicSize = updateDynamicSize(); - if (updateDynamicSize) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - // FIXME deferred relative size update needed to fix some - // scrollbar issues in sampler. This must be the wrong way - // to do it. Might be that some other component is broken. - client.handleComponentRelativeSize(VCustomComponent.this); - - } - }); - } - - renderSpace.setWidth(getElement().getOffsetWidth()); - renderSpace.setHeight(getElement().getOffsetHeight()); - - /* - * Needed to update client size if the size of this component has - * changed and the child uses relative size(s). - */ - client.runDescendentsLayout(this); - - rendering = false; - } - - private boolean updateDynamicSize() { - boolean updated = false; - if (isDynamicWidth()) { - int childWidth = Util.getRequiredWidth(getWidget()); - getElement().getStyle().setPropertyPx("width", childWidth); - updated = true; - } - if (isDynamicHeight()) { - int childHeight = Util.getRequiredHeight(getWidget()); - getElement().getStyle().setPropertyPx("height", childHeight); - updated = true; - } - - return updated; - } - - protected boolean isDynamicWidth() { - return width == null || width.equals(""); - } - - protected boolean isDynamicHeight() { - return height == null || height.equals(""); - } - - public boolean hasChildComponent(Widget component) { - if (getWidget() == component) { - return true; - } else { - return false; - } - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - if (hasChildComponent(oldComponent)) { - clear(); - setWidget(newComponent); - } else { - throw new IllegalStateException(); - } - } - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP, custom component dont render composition roots caption - } - - public boolean requestLayout(Set<Paintable> child) { - // If a child grows in size, it will not necessarily be calculated - // correctly unless we remove previous size definitions - if (isDynamicWidth()) { - getElement().getStyle().setProperty("width", ""); - } - if (isDynamicHeight()) { - getElement().getStyle().setProperty("height", ""); - } - - return !updateDynamicSize(); - } - - public RenderSpace getAllocatedSpace(Widget child) { - return renderSpace; - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - renderSpace.setHeight(getElement().getOffsetHeight()); - - if (!height.equals(this.height)) { - this.height = height; - if (!rendering) { - client.handleComponentRelativeSize(getWidget()); - } - } - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - renderSpace.setWidth(getElement().getOffsetWidth()); - - if (!width.equals(this.width)) { - this.width = width; - if (!rendering) { - client.handleComponentRelativeSize(getWidget()); - } - } - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java deleted file mode 100644 index 2783db99d1..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java +++ /dev/null @@ -1,453 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.dom.client.ObjectElement; -import com.google.gwt.dom.client.Style; -import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -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.HTML; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VTooltip; - -public class VEmbedded extends HTML implements Paintable { - public static final String CLICK_EVENT_IDENTIFIER = "click"; - public static final String ALTERNATE_TEXT = "alt"; - - private static String CLASSNAME = "v-embedded"; - - private String height; - private String width; - private Element browserElement; - - private String type; - - private ApplicationConnection client; - - private final ClickEventHandler clickEventHandler = new ClickEventHandler( - this, CLICK_EVENT_IDENTIFIER) { - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - - }; - - public VEmbedded() { - setStyleName(CLASSNAME); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { - return; - } - this.client = client; - - boolean clearBrowserElement = true; - - clickEventHandler.handleEventHandlerRegistration(client); - - if (uidl.hasAttribute("type")) { - type = uidl.getStringAttribute("type"); - if (type.equals("image")) { - addStyleName(CLASSNAME + "-image"); - Element el = null; - boolean created = false; - NodeList<Node> nodes = getElement().getChildNodes(); - if (nodes != null && nodes.getLength() == 1) { - Node n = nodes.getItem(0); - if (n.getNodeType() == Node.ELEMENT_NODE) { - Element e = (Element) n; - if (e.getTagName().equals("IMG")) { - el = e; - } - } - } - if (el == null) { - setHTML(""); - el = DOM.createImg(); - created = true; - client.addPngFix(el); - DOM.sinkEvents(el, Event.ONLOAD); - } - - // Set attributes - Style style = el.getStyle(); - String w = uidl.getStringAttribute("width"); - if (w != null) { - style.setProperty("width", w); - } else { - style.setProperty("width", ""); - } - String h = uidl.getStringAttribute("height"); - if (h != null) { - style.setProperty("height", h); - } else { - style.setProperty("height", ""); - } - DOM.setElementProperty(el, "src", getSrc(uidl, client)); - - if (uidl.hasAttribute(ALTERNATE_TEXT)) { - el.setPropertyString(ALTERNATE_TEXT, - uidl.getStringAttribute(ALTERNATE_TEXT)); - } - - if (created) { - // insert in dom late - getElement().appendChild(el); - } - - /* - * Sink tooltip events so tooltip is displayed when hovering the - * image. - */ - sinkEvents(VTooltip.TOOLTIP_EVENTS); - - } else if (type.equals("browser")) { - addStyleName(CLASSNAME + "-browser"); - if (browserElement == null) { - setHTML("<iframe width=\"100%\" height=\"100%\" frameborder=\"0\"" - + " allowTransparency=\"true\" src=\"\"" - + " name=\"" + uidl.getId() + "\"></iframe>"); - browserElement = DOM.getFirstChild(getElement()); - } - DOM.setElementAttribute(browserElement, "src", - getSrc(uidl, client)); - clearBrowserElement = false; - } else { - VConsole.log("Unknown Embedded type '" + type + "'"); - } - } else if (uidl.hasAttribute("mimetype")) { - final String mime = uidl.getStringAttribute("mimetype"); - if (mime.equals("application/x-shockwave-flash")) { - // Handle embedding of Flash - addStyleName(CLASSNAME + "-flash"); - setHTML(createFlashEmbed(uidl)); - } else if (mime.equals("image/svg+xml")) { - addStyleName(CLASSNAME + "-svg"); - String data; - Map<String, String> parameters = getParameters(uidl); - if (parameters.get("data") == null) { - data = getSrc(uidl, client); - } else { - data = "data:image/svg+xml," + parameters.get("data"); - } - setHTML(""); - ObjectElement obj = Document.get().createObjectElement(); - obj.setType(mime); - obj.setData(data); - if (width != null) { - obj.getStyle().setProperty("width", "100%"); - } - if (height != null) { - obj.getStyle().setProperty("height", "100%"); - } - if (uidl.hasAttribute("classid")) { - obj.setAttribute("classid", - uidl.getStringAttribute("classid")); - } - if (uidl.hasAttribute("codebase")) { - obj.setAttribute("codebase", - uidl.getStringAttribute("codebase")); - } - if (uidl.hasAttribute("codetype")) { - obj.setAttribute("codetype", - uidl.getStringAttribute("codetype")); - } - if (uidl.hasAttribute("archive")) { - obj.setAttribute("archive", - uidl.getStringAttribute("archive")); - } - if (uidl.hasAttribute("standby")) { - obj.setAttribute("standby", - uidl.getStringAttribute("standby")); - } - getElement().appendChild(obj); - if (uidl.hasAttribute(ALTERNATE_TEXT)) { - obj.setInnerText(uidl.getStringAttribute(ALTERNATE_TEXT)); - } - } else { - VConsole.log("Unknown Embedded mimetype '" + mime + "'"); - } - } else { - VConsole.log("Unknown Embedded; no type or mimetype attribute"); - } - - if (clearBrowserElement) { - browserElement = null; - } - } - - /** - * Creates the Object and Embed tags for the Flash plugin so it works - * cross-browser - * - * @param uidl - * The UIDL - * @return Tags concatenated into a string - */ - private String createFlashEmbed(UIDL uidl) { - /* - * To ensure cross-browser compatibility we are using the twice-cooked - * method to embed flash i.e. we add a OBJECT tag for IE ActiveX and - * inside it a EMBED for all other browsers. - */ - - StringBuilder html = new StringBuilder(); - - // Start the object tag - html.append("<object "); - - /* - * Add classid required for ActiveX to recognize the flash. This is a - * predefined value which ActiveX recognizes and must be the given - * value. More info can be found on - * http://kb2.adobe.com/cps/415/tn_4150.html. Allow user to override - * this by setting his own classid. - */ - if (uidl.hasAttribute("classid")) { - html.append("classid=\"" - + Util.escapeAttribute(uidl.getStringAttribute("classid")) - + "\" "); - } else { - html.append("classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" "); - } - - /* - * Add codebase required for ActiveX and must be exactly this according - * to http://kb2.adobe.com/cps/415/tn_4150.html to work with the above - * given classid. Again, see more info on - * http://kb2.adobe.com/cps/415/tn_4150.html. Limiting Flash version to - * 6.0.0.0 and above. Allow user to override this by setting his own - * codebase - */ - if (uidl.hasAttribute("codebase")) { - html.append("codebase=\"" - + Util.escapeAttribute(uidl.getStringAttribute("codebase")) - + "\" "); - } else { - html.append("codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\" "); - } - - // Add width and height - html.append("width=\"" + Util.escapeAttribute(width) + "\" "); - html.append("height=\"" + Util.escapeAttribute(height) + "\" "); - html.append("type=\"application/x-shockwave-flash\" "); - - // Codetype - if (uidl.hasAttribute("codetype")) { - html.append("codetype=\"" - + Util.escapeAttribute(uidl.getStringAttribute("codetype")) - + "\" "); - } - - // Standby - if (uidl.hasAttribute("standby")) { - html.append("standby=\"" - + Util.escapeAttribute(uidl.getStringAttribute("standby")) - + "\" "); - } - - // Archive - if (uidl.hasAttribute("archive")) { - html.append("archive=\"" - + Util.escapeAttribute(uidl.getStringAttribute("archive")) - + "\" "); - } - - // End object tag - html.append(">"); - - // Ensure we have an movie parameter - Map<String, String> parameters = getParameters(uidl); - if (parameters.get("movie") == null) { - parameters.put("movie", getSrc(uidl, client)); - } - - // Add parameters to OBJECT - for (String name : parameters.keySet()) { - html.append("<param "); - html.append("name=\"" + Util.escapeAttribute(name) + "\" "); - html.append("value=\"" + Util.escapeAttribute(parameters.get(name)) - + "\" "); - html.append("/>"); - } - - // Build inner EMBED tag - html.append("<embed "); - html.append("src=\"" + Util.escapeAttribute(getSrc(uidl, client)) - + "\" "); - html.append("width=\"" + Util.escapeAttribute(width) + "\" "); - html.append("height=\"" + Util.escapeAttribute(height) + "\" "); - html.append("type=\"application/x-shockwave-flash\" "); - - // Add the parameters to the Embed - for (String name : parameters.keySet()) { - html.append(Util.escapeAttribute(name)); - html.append("="); - html.append("\"" + Util.escapeAttribute(parameters.get(name)) - + "\""); - } - - // End embed tag - html.append("></embed>"); - - if (uidl.hasAttribute(ALTERNATE_TEXT)) { - html.append(uidl.getStringAttribute(ALTERNATE_TEXT)); - } - - // End object tag - html.append("</object>"); - - return html.toString(); - } - - /** - * Returns a map (name -> value) of all parameters in the UIDL. - * - * @param uidl - * @return - */ - private static Map<String, String> getParameters(UIDL uidl) { - Map<String, String> parameters = new HashMap<String, String>(); - - Iterator<Object> childIterator = uidl.getChildIterator(); - while (childIterator.hasNext()) { - - Object child = childIterator.next(); - if (child instanceof UIDL) { - - UIDL childUIDL = (UIDL) child; - if (childUIDL.getTag().equals("embeddedparam")) { - String name = childUIDL.getStringAttribute("name"); - String value = childUIDL.getStringAttribute("value"); - parameters.put(name, value); - } - } - - } - - return parameters; - } - - /** - * Helper to return translated src-attribute from embedded's UIDL - * - * @param uidl - * @param client - * @return - */ - private String getSrc(UIDL uidl, ApplicationConnection client) { - String url = client.translateVaadinUri(uidl.getStringAttribute("src")); - if (url == null) { - return ""; - } - return url; - } - - @Override - public void setWidth(String width) { - this.width = width; - if (isDynamicHeight()) { - int oldHeight = getOffsetHeight(); - super.setWidth(width); - int newHeight = getOffsetHeight(); - /* - * Must notify parent if the height changes as a result of a width - * change - */ - if (oldHeight != newHeight) { - Util.notifyParentOfSizeChange(this, false); - } - } else { - super.setWidth(width); - } - - } - - private boolean isDynamicWidth() { - return width == null || width.equals(""); - } - - private boolean isDynamicHeight() { - return height == null || height.equals(""); - } - - @Override - public void setHeight(String height) { - this.height = height; - super.setHeight(height); - } - - @Override - protected void onDetach() { - if (BrowserInfo.get().isIE()) { - // Force browser to fire unload event when component is detached - // from the view (IE doesn't do this automatically) - if (browserElement != null) { - /* - * src was previously set to javascript:false, but this was not - * enough to overcome a bug when detaching an iframe with a pdf - * loaded in IE9. about:blank seems to cause the adobe reader - * plugin to unload properly before the iframe is removed. See - * #7855 - */ - DOM.setElementAttribute(browserElement, "src", "about:blank"); - } - } - super.onDetach(); - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (DOM.eventGetType(event) == Event.ONLOAD) { - if ("image".equals(type)) { - updateElementDynamicSizeFromImage(); - } - Util.notifyParentOfSizeChange(this, true); - } - - client.handleTooltipEvent(event, this); - } - - /** - * Updates the size of the embedded component's element if size is - * undefined. Without this embeddeds containing images will remain the wrong - * size in certain cases (e.g. #6304). - */ - private void updateElementDynamicSizeFromImage() { - if (isDynamicWidth()) { - getElement().getStyle().setWidth( - getElement().getFirstChildElement().getOffsetWidth(), - Unit.PX); - } - if (isDynamicHeight()) { - getElement().getStyle().setHeight( - getElement().getFirstChildElement().getOffsetHeight(), - Unit.PX); - } - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VForm.java b/src/com/vaadin/terminal/gwt/client/ui/VForm.java deleted file mode 100644 index c0a6e5b275..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VForm.java +++ /dev/null @@ -1,331 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Set; - -import com.google.gwt.dom.client.Style.Display; -import com.google.gwt.event.dom.client.KeyDownEvent; -import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.event.shared.HandlerRegistration; -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.ComplexPanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.VErrorMessage; - -public class VForm extends ComplexPanel implements Container, KeyDownHandler { - - protected String id; - - private String height = ""; - - private String width = ""; - - public static final String CLASSNAME = "v-form"; - - private Container lo; - private Element legend = DOM.createLegend(); - private Element caption = DOM.createSpan(); - private Element errorIndicatorElement = DOM.createDiv(); - private Element desc = DOM.createDiv(); - private Icon icon; - private VErrorMessage errorMessage = new VErrorMessage(); - - private Element fieldContainer = DOM.createDiv(); - - private Element footerContainer = DOM.createDiv(); - - private Element fieldSet = DOM.createFieldSet(); - - private Container footer; - - private ApplicationConnection client; - - private RenderInformation renderInformation = new RenderInformation(); - - private int borderPaddingHorizontal = -1; - - private boolean rendering = false; - - ShortcutActionHandler shortcutHandler; - - private HandlerRegistration keyDownRegistration; - - public VForm() { - setElement(DOM.createDiv()); - getElement().appendChild(fieldSet); - setStyleName(CLASSNAME); - fieldSet.appendChild(legend); - legend.appendChild(caption); - errorIndicatorElement.setClassName("v-errorindicator"); - errorIndicatorElement.getStyle().setDisplay(Display.NONE); - errorIndicatorElement.setInnerText(" "); // needed for IE - desc.setClassName("v-form-description"); - fieldSet.appendChild(desc); // Adding description for initial padding - // measurements, removed later if no - // description is set - fieldSet.appendChild(fieldContainer); - errorMessage.setVisible(false); - errorMessage.setStyleName(CLASSNAME + "-errormessage"); - fieldSet.appendChild(errorMessage.getElement()); - fieldSet.appendChild(footerContainer); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - this.client = client; - id = uidl.getId(); - - if (client.updateComponent(this, uidl, false)) { - rendering = false; - return; - } - - boolean legendEmpty = true; - if (uidl.hasAttribute("caption")) { - caption.setInnerText(uidl.getStringAttribute("caption")); - legendEmpty = false; - } else { - caption.setInnerText(""); - } - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - legend.insertFirst(icon.getElement()); - } - icon.setUri(uidl.getStringAttribute("icon")); - legendEmpty = false; - } else { - if (icon != null) { - legend.removeChild(icon.getElement()); - } - } - if (legendEmpty) { - addStyleDependentName("nocaption"); - } else { - removeStyleDependentName("nocaption"); - } - - if (uidl.hasAttribute("error")) { - final UIDL errorUidl = uidl.getErrors(); - errorMessage.updateFromUIDL(errorUidl); - errorMessage.setVisible(true); - - } else { - errorMessage.setVisible(false); - } - - if (uidl.hasAttribute("description")) { - desc.setInnerHTML(uidl.getStringAttribute("description")); - if (desc.getParentElement() == null) { - fieldSet.insertAfter(desc, legend); - } - } else { - desc.setInnerHTML(""); - if (desc.getParentElement() != null) { - fieldSet.removeChild(desc); - } - } - - updateSize(); - - // first render footer so it will be easier to handle relative height of - // main layout - if (uidl.getChildCount() > 1 - && !uidl.getChildUIDL(1).getTag().equals("actions")) { - // render footer - Container newFooter = (Container) client.getPaintable(uidl - .getChildUIDL(1)); - if (footer == null) { - add((Widget) newFooter, footerContainer); - footer = newFooter; - } else if (newFooter != footer) { - remove((Widget) footer); - client.unregisterPaintable(footer); - add((Widget) newFooter, footerContainer); - } - footer = newFooter; - footer.updateFromUIDL(uidl.getChildUIDL(1), client); - // needed for the main layout to know the space it has available - updateSize(); - } else { - if (footer != null) { - remove((Widget) footer); - client.unregisterPaintable(footer); - // needed for the main layout to know the space it has available - updateSize(); - } - } - - final UIDL layoutUidl = uidl.getChildUIDL(0); - Container newLo = (Container) client.getPaintable(layoutUidl); - if (lo == null) { - lo = newLo; - add((Widget) lo, fieldContainer); - } else if (lo != newLo) { - client.unregisterPaintable(lo); - remove((Widget) lo); - lo = newLo; - add((Widget) lo, fieldContainer); - } - lo.updateFromUIDL(layoutUidl, client); - - // also recalculates size of the footer if undefined size form - see - // #3710 - updateSize(); - client.runDescendentsLayout(this); - - // We may have actions attached - if (uidl.getChildCount() > 1) { - UIDL childUidl = uidl.getChildByTagName("actions"); - if (childUidl != null) { - if (shortcutHandler == null) { - shortcutHandler = new ShortcutActionHandler(id, client); - keyDownRegistration = addDomHandler(this, - KeyDownEvent.getType()); - } - shortcutHandler.updateActionMap(childUidl); - } - } else if (shortcutHandler != null) { - keyDownRegistration.removeHandler(); - shortcutHandler = null; - keyDownRegistration = null; - } - - rendering = false; - } - - public void updateSize() { - - renderInformation.updateSize(getElement()); - - renderInformation.setContentAreaHeight(renderInformation - .getRenderedSize().getHeight() - getSpaceConsumedVertically()); - if (BrowserInfo.get().isIE6()) { - getElement().getStyle().setProperty("overflow", "hidden"); - } - renderInformation.setContentAreaWidth(renderInformation - .getRenderedSize().getWidth() - borderPaddingHorizontal); - } - - public RenderSpace getAllocatedSpace(Widget child) { - if (child == lo) { - return renderInformation.getContentAreaSize(); - } else if (child == footer) { - return new RenderSpace(renderInformation.getContentAreaSize() - .getWidth(), 0); - } else { - VConsole.error("Invalid child requested RenderSpace information"); - return null; - } - } - - public boolean hasChildComponent(Widget component) { - return component != null && (component == lo || component == footer); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - if (!hasChildComponent(oldComponent)) { - throw new IllegalArgumentException( - "Old component is not inside this Container"); - } - remove(oldComponent); - if (oldComponent == lo) { - lo = (Container) newComponent; - add((Widget) lo, fieldContainer); - } else { - footer = (Container) newComponent; - add((Widget) footer, footerContainer); - } - - } - - public boolean requestLayout(Set<Paintable> child) { - - if (height != null && !"".equals(height) && width != null - && !"".equals(width)) { - /* - * If the height and width has been specified the child components - * cannot make the size of the layout change - */ - - return true; - } - - if (renderInformation.updateSize(getElement())) { - return false; - } else { - return true; - } - - } - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP form don't render caption for neither field layout nor footer - // layout - } - - @Override - public void setHeight(String height) { - if (this.height.equals(height)) { - return; - } - - this.height = height; - super.setHeight(height); - - updateSize(); - } - - /** - * @return pixels consumed by decoration, captions, descrioptiosn etc.. In - * other words space, not used by the actual layout in form. - */ - private int getSpaceConsumedVertically() { - int offsetHeight2 = fieldSet.getOffsetHeight(); - int offsetHeight3 = fieldContainer.getOffsetHeight(); - int borderPadding = offsetHeight2 - offsetHeight3; - return borderPadding; - } - - @Override - public void setWidth(String width) { - if (borderPaddingHorizontal < 0) { - // measure excess size lazily after stylename setting, but before - // setting width - int ow = getOffsetWidth(); - int dow = desc.getOffsetWidth(); - borderPaddingHorizontal = ow - dow; - } - if (Util.equals(this.width, width)) { - return; - } - - this.width = width; - super.setWidth(width); - - updateSize(); - - if (!rendering && height.equals("")) { - // Width might affect height - Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this); - } - } - - public void onKeyDown(KeyDownEvent event) { - shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent())); - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java deleted file mode 100644 index 174e66b7aa..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java +++ /dev/null @@ -1,533 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -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.FlexTable; -import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.StyleConstants; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; - -/** - * Two col Layout that places caption on left col and field on right col - */ -public class VFormLayout extends SimplePanel implements Container { - - private final static String CLASSNAME = "v-formlayout"; - - private ApplicationConnection client; - private VFormLayoutTable table; - - private String width = ""; - private String height = ""; - - private boolean rendering = false; - - public VFormLayout() { - super(); - setStyleName(CLASSNAME); - table = new VFormLayoutTable(); - setWidget(table); - } - - /** - * Parses the stylenames from an uidl - * - * @param uidl - * The uidl to get the stylenames from - * @return An array of stylenames - */ - private String[] getStylesFromUIDL(UIDL uidl) { - List<String> styles = new ArrayList<String>(); - if (uidl.hasAttribute("style")) { - String[] stylesnames = uidl.getStringAttribute("style").split(" "); - for (String name : stylesnames) { - styles.add(name); - } - } - - if (uidl.hasAttribute("disabled")) { - styles.add(ApplicationConnection.DISABLED_CLASSNAME); - } - - return styles.toArray(new String[styles.size()]); - } - - public class VFormLayoutTable extends FlexTable implements ClickHandler { - - private static final int COLUMN_CAPTION = 0; - private static final int COLUMN_ERRORFLAG = 1; - private static final int COLUMN_WIDGET = 2; - - private HashMap<Paintable, Caption> componentToCaption = new HashMap<Paintable, Caption>(); - private HashMap<Paintable, ErrorFlag> componentToError = new HashMap<Paintable, ErrorFlag>(); - - public VFormLayoutTable() { - DOM.setElementProperty(getElement(), "cellPadding", "0"); - DOM.setElementProperty(getElement(), "cellSpacing", "0"); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - final VMarginInfo margins = new VMarginInfo( - uidl.getIntAttribute("margins")); - - Element margin = getElement(); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP, - margins.hasTop()); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT, - margins.hasRight()); - setStyleName(margin, - CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM, - margins.hasBottom()); - setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT, - margins.hasLeft()); - - setStyleName(margin, CLASSNAME + "-" + "spacing", - uidl.hasAttribute("spacing")); - - int i = 0; - for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext(); i++) { - prepareCell(i, 1); - final UIDL childUidl = (UIDL) it.next(); - final Paintable p = client.getPaintable(childUidl); - Caption caption = componentToCaption.get(p); - if (caption == null) { - caption = new Caption(p, client); - caption.addClickHandler(this); - componentToCaption.put(p, caption); - } - ErrorFlag error = componentToError.get(p); - if (error == null) { - error = new ErrorFlag(); - componentToError.put(p, error); - } - prepareCell(i, COLUMN_WIDGET); - final Paintable oldComponent = (Paintable) getWidget(i, - COLUMN_WIDGET); - if (oldComponent == null) { - setWidget(i, COLUMN_WIDGET, (Widget) p); - } else if (oldComponent != p) { - client.unregisterPaintable(oldComponent); - setWidget(i, COLUMN_WIDGET, (Widget) p); - } - getCellFormatter().setStyleName(i, COLUMN_WIDGET, - CLASSNAME + "-contentcell"); - getCellFormatter().setStyleName(i, COLUMN_CAPTION, - CLASSNAME + "-captioncell"); - setWidget(i, COLUMN_CAPTION, caption); - - setContentWidth(i); - - getCellFormatter().setStyleName(i, COLUMN_ERRORFLAG, - CLASSNAME + "-errorcell"); - setWidget(i, COLUMN_ERRORFLAG, error); - - p.updateFromUIDL(childUidl, client); - - String rowstyles = CLASSNAME + "-row"; - if (i == 0) { - rowstyles += " " + CLASSNAME + "-firstrow"; - } - if (!it.hasNext()) { - rowstyles += " " + CLASSNAME + "-lastrow"; - } - - getRowFormatter().setStyleName(i, rowstyles); - - } - - while (getRowCount() > i) { - final Paintable p = (Paintable) getWidget(i, COLUMN_WIDGET); - client.unregisterPaintable(p); - componentToCaption.remove(p); - removeRow(i); - } - - /* - * Must update relative sized fields last when it is clear how much - * space they are allowed to use - */ - for (Paintable p : componentToCaption.keySet()) { - client.handleComponentRelativeSize((Widget) p); - } - } - - public void setContentWidths() { - for (int row = 0; row < getRowCount(); row++) { - setContentWidth(row); - } - } - - private void setContentWidth(int row) { - String width = ""; - if (!isDynamicWidth()) { - width = "100%"; - } - getCellFormatter().setWidth(row, COLUMN_WIDGET, width); - } - - public void replaceChildComponent(Widget oldComponent, - Widget newComponent) { - int i; - for (i = 0; i < getRowCount(); i++) { - Widget candidate = getWidget(i, COLUMN_WIDGET); - if (oldComponent == candidate) { - Caption oldCap = componentToCaption.get(oldComponent); - final Caption newCap = new Caption( - (Paintable) newComponent, client); - newCap.addClickHandler(this); - newCap.setStyleName(oldCap.getStyleName()); - componentToCaption.put((Paintable) newComponent, newCap); - ErrorFlag error = componentToError.get(newComponent); - if (error == null) { - error = new ErrorFlag(); - componentToError.put((Paintable) newComponent, error); - } - - setWidget(i, COLUMN_CAPTION, newCap); - setWidget(i, COLUMN_ERRORFLAG, error); - setWidget(i, COLUMN_WIDGET, newComponent); - break; - } - } - - } - - public boolean hasChildComponent(Widget component) { - return componentToCaption.containsKey(component); - } - - public void updateCaption(Paintable component, UIDL uidl) { - final Caption c = componentToCaption.get(component); - if (c != null) { - c.updateCaption(uidl); - } - final ErrorFlag e = componentToError.get(component); - if (e != null) { - e.updateFromUIDL(uidl, component); - } - - } - - public int getAllocatedWidth(Widget child, int availableWidth) { - Caption caption = componentToCaption.get(child); - ErrorFlag error = componentToError.get(child); - int width = availableWidth; - - if (caption != null) { - width -= DOM.getParent(caption.getElement()).getOffsetWidth(); - } - if (error != null) { - width -= DOM.getParent(error.getElement()).getOffsetWidth(); - } - - return width; - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt - * .event.dom.client.ClickEvent) - */ - public void onClick(ClickEvent event) { - Caption caption = (Caption) event.getSource(); - if (caption.getOwner() != null) { - if (caption.getOwner() instanceof Focusable) { - ((Focusable) caption.getOwner()).focus(); - } else if (caption.getOwner() instanceof com.google.gwt.user.client.ui.Focusable) { - ((com.google.gwt.user.client.ui.Focusable) caption - .getOwner()).setFocus(true); - } - } - } - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - - this.client = client; - - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - - table.updateFromUIDL(uidl, client); - - rendering = false; - } - - public boolean isDynamicWidth() { - return width.equals(""); - } - - public boolean hasChildComponent(Widget component) { - return table.hasChildComponent(component); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - table.replaceChildComponent(oldComponent, newComponent); - } - - public void updateCaption(Paintable component, UIDL uidl) { - table.updateCaption(component, uidl); - } - - public class Caption extends HTML { - - public static final String CLASSNAME = "v-caption"; - - private final Paintable owner; - - private Element requiredFieldIndicator; - - private Icon icon; - - private Element captionText; - - private final ApplicationConnection client; - - /** - * - * @param component - * optional owner of caption. If not set, getOwner will - * return null - * @param client - */ - public Caption(Paintable component, ApplicationConnection client) { - super(); - this.client = client; - owner = component; - - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - private void setStyles(String[] styles) { - String styleName = CLASSNAME; - - if (styles != null) { - for (String style : styles) { - if (ApplicationConnection.DISABLED_CLASSNAME.equals(style)) { - // Add v-disabled also without classname prefix so - // generic v-disabled CSS rules work - styleName += " " + style; - } - - styleName += " " + CLASSNAME + "-" + style; - } - } - - setStyleName(styleName); - } - - public void updateCaption(UIDL uidl) { - setVisible(!uidl.getBooleanAttribute("invisible")); - - // Update styles as they might have changed when the caption changed - setStyles(getStylesFromUIDL(uidl)); - - boolean isEmpty = true; - - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - - DOM.insertChild(getElement(), icon.getElement(), 0); - } - icon.setUri(uidl.getStringAttribute("icon")); - isEmpty = false; - } else { - if (icon != null) { - DOM.removeChild(getElement(), icon.getElement()); - icon = null; - } - - } - - if (uidl.hasAttribute("caption")) { - if (captionText == null) { - captionText = DOM.createSpan(); - DOM.insertChild(getElement(), captionText, icon == null ? 0 - : 1); - } - String c = uidl.getStringAttribute("caption"); - if (c == null) { - c = ""; - } else { - isEmpty = false; - } - DOM.setInnerText(captionText, c); - } else { - // TODO should span also be removed - } - - if (uidl.hasAttribute("description")) { - if (captionText != null) { - addStyleDependentName("hasdescription"); - } else { - removeStyleDependentName("hasdescription"); - } - } - - if (uidl.getBooleanAttribute("required")) { - if (requiredFieldIndicator == null) { - requiredFieldIndicator = DOM.createSpan(); - DOM.setInnerText(requiredFieldIndicator, "*"); - DOM.setElementProperty(requiredFieldIndicator, "className", - "v-required-field-indicator"); - DOM.appendChild(getElement(), requiredFieldIndicator); - } - } else { - if (requiredFieldIndicator != null) { - DOM.removeChild(getElement(), requiredFieldIndicator); - requiredFieldIndicator = null; - } - } - - // Workaround for IE weirdness, sometimes returns bad height in some - // circumstances when Caption is empty. See #1444 - // IE7 bugs more often. I wonder what happens when IE8 arrives... - if (BrowserInfo.get().isIE()) { - if (isEmpty) { - setHeight("0px"); - DOM.setStyleAttribute(getElement(), "overflow", "hidden"); - } else { - setHeight(""); - DOM.setStyleAttribute(getElement(), "overflow", ""); - } - - } - - } - - /** - * Returns Paintable for which this Caption belongs to. - * - * @return owner Widget - */ - public Paintable getOwner() { - return owner; - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, owner); - } - } - } - - private class ErrorFlag extends HTML { - private static final String CLASSNAME = VFormLayout.CLASSNAME - + "-error-indicator"; - Element errorIndicatorElement; - private Paintable owner; - - public ErrorFlag() { - setStyleName(CLASSNAME); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - public void updateFromUIDL(UIDL uidl, Paintable component) { - owner = component; - if (uidl.hasAttribute("error") - && !uidl.getBooleanAttribute("hideErrors")) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createDiv(); - DOM.setInnerHTML(errorIndicatorElement, " "); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - DOM.appendChild(getElement(), errorIndicatorElement); - } - - } else if (errorIndicatorElement != null) { - DOM.removeChild(getElement(), errorIndicatorElement); - errorIndicatorElement = null; - } - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (owner != null) { - client.handleTooltipEvent(event, owner); - } - } - - } - - public boolean requestLayout(Set<Paintable> child) { - if (height.equals("") || width.equals("")) { - // A dynamic size might change due to children changes - return false; - } - - return true; - } - - public RenderSpace getAllocatedSpace(Widget child) { - int width = 0; - int height = 0; - - if (!this.width.equals("")) { - int availableWidth = getOffsetWidth(); - width = table.getAllocatedWidth(child, availableWidth); - } - - return new RenderSpace(width, height, false); - } - - @Override - public void setHeight(String height) { - if (this.height.equals(height)) { - return; - } - - this.height = height; - super.setHeight(height); - } - - @Override - public void setWidth(String width) { - if (this.width.equals(width)) { - return; - } - - this.width = width; - super.setWidth(width); - - if (!rendering) { - table.setContentWidths(); - if (height.equals("")) { - // Width might affect height - Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this); - } - } - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java deleted file mode 100644 index 82b3eabf40..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java +++ /dev/null @@ -1,1132 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.AbsolutePanel; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.StyleConstants; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout; -import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer; - -public class VGridLayout extends SimplePanel implements Paintable, Container { - - public static final String CLASSNAME = "v-gridlayout"; - - private DivElement margin = Document.get().createDivElement(); - - private final AbsolutePanel canvas = new AbsolutePanel(); - - private ApplicationConnection client; - - protected HashMap<Widget, ChildComponentContainer> widgetToComponentContainer = new HashMap<Widget, ChildComponentContainer>(); - - private HashMap<Paintable, Cell> paintableToCell = new HashMap<Paintable, Cell>(); - - private int spacingPixelsHorizontal; - private int spacingPixelsVertical; - - private int[] columnWidths; - private int[] rowHeights; - - private String height; - - private String width; - - private int[] colExpandRatioArray; - - private int[] rowExpandRatioArray; - - private int[] minColumnWidths; - - private int[] minRowHeights; - - private boolean rendering; - - private HashMap<Widget, ChildComponentContainer> nonRenderedWidgets; - - private boolean sizeChangedDuringRendering = false; - - private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( - this, EventId.LAYOUT_CLICK) { - - @Override - protected Paintable getChildComponent(Element element) { - return getComponent(element); - } - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - - public VGridLayout() { - super(); - getElement().appendChild(margin); - setStyleName(CLASSNAME); - setWidget(canvas); - } - - @Override - protected Element getContainerElement() { - return margin.cast(); - } - - /** - * Returns the column widths measured in pixels - * - * @return - */ - protected int[] getColumnWidths() { - return columnWidths; - } - - /** - * Returns the row heights measured in pixels - * - * @return - */ - protected int[] getRowHeights() { - return rowHeights; - } - - /** - * Returns the spacing between the cells horizontally in pixels - * - * @return - */ - protected int getHorizontalSpacing() { - return spacingPixelsHorizontal; - } - - /** - * Returns the spacing between the cells vertically in pixels - * - * @return - */ - protected int getVerticalSpacing() { - return spacingPixelsVertical; - } - - @SuppressWarnings("unchecked") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - this.client = client; - - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - clickEventHandler.handleEventHandlerRegistration(client); - - canvas.setWidth("0px"); - - handleMargins(uidl); - detectSpacing(uidl); - - int cols = uidl.getIntAttribute("w"); - int rows = uidl.getIntAttribute("h"); - - columnWidths = new int[cols]; - rowHeights = new int[rows]; - - if (cells == null) { - cells = new Cell[cols][rows]; - } else if (cells.length != cols || cells[0].length != rows) { - Cell[][] newCells = new Cell[cols][rows]; - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < cells[i].length; j++) { - if (i < cols && j < rows) { - newCells[i][j] = cells[i][j]; - } - } - } - cells = newCells; - } - - nonRenderedWidgets = (HashMap<Widget, ChildComponentContainer>) widgetToComponentContainer - .clone(); - - final int[] alignments = uidl.getIntArrayAttribute("alignments"); - int alignmentIndex = 0; - - LinkedList<Cell> pendingCells = new LinkedList<Cell>(); - - LinkedList<Cell> relativeHeighted = new LinkedList<Cell>(); - - for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) { - final UIDL r = (UIDL) i.next(); - if ("gr".equals(r.getTag())) { - for (final Iterator<?> j = r.getChildIterator(); j.hasNext();) { - final UIDL c = (UIDL) j.next(); - if ("gc".equals(c.getTag())) { - Cell cell = getCell(c); - if (cell.hasContent()) { - boolean rendered = cell.renderIfNoRelativeWidth(); - cell.alignment = alignments[alignmentIndex++]; - if (!rendered) { - pendingCells.add(cell); - } - - if (cell.colspan > 1) { - storeColSpannedCell(cell); - } else if (rendered) { - // strore non-colspanned widths to columnWidth - // array - if (columnWidths[cell.col] < cell.getWidth()) { - columnWidths[cell.col] = cell.getWidth(); - } - } - if (cell.hasRelativeHeight()) { - relativeHeighted.add(cell); - } - } - } - } - } - } - - colExpandRatioArray = uidl.getIntArrayAttribute("colExpand"); - rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand"); - distributeColSpanWidths(); - - minColumnWidths = cloneArray(columnWidths); - expandColumns(); - - renderRemainingComponentsWithNoRelativeHeight(pendingCells); - - detectRowHeights(); - - expandRows(); - - renderRemainingComponents(pendingCells); - - for (Cell cell : relativeHeighted) { - // rendering done above so cell.cc should not be null - Widget widget2 = cell.cc.getWidget(); - client.handleComponentRelativeSize(widget2); - cell.cc.updateWidgetSize(); - } - - layoutCells(); - - // clean non rendered components - for (Widget w : nonRenderedWidgets.keySet()) { - ChildComponentContainer childComponentContainer = widgetToComponentContainer - .get(w); - paintableToCell.remove(w); - widgetToComponentContainer.remove(w); - childComponentContainer.removeFromParent(); - client.unregisterPaintable((Paintable) w); - } - nonRenderedWidgets = null; - - rendering = false; - sizeChangedDuringRendering = false; - - } - - private static int[] cloneArray(int[] toBeCloned) { - int[] clone = new int[toBeCloned.length]; - for (int i = 0; i < clone.length; i++) { - clone[i] = toBeCloned[i] * 1; - } - return clone; - } - - private void expandRows() { - if (!"".equals(height)) { - int usedSpace = minRowHeights[0]; - for (int i = 1; i < minRowHeights.length; i++) { - usedSpace += spacingPixelsVertical + minRowHeights[i]; - } - int availableSpace = getOffsetHeight() - marginTopAndBottom; - int excessSpace = availableSpace - usedSpace; - int distributed = 0; - if (excessSpace > 0) { - for (int i = 0; i < rowHeights.length; i++) { - int ew = excessSpace * rowExpandRatioArray[i] / 1000; - rowHeights[i] = minRowHeights[i] + ew; - distributed += ew; - } - excessSpace -= distributed; - int c = 0; - while (excessSpace > 0) { - rowHeights[c % rowHeights.length]++; - excessSpace--; - c++; - } - } - } - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - if (!height.equals(this.height)) { - this.height = height; - if (rendering) { - sizeChangedDuringRendering = true; - } else { - expandRows(); - layoutCells(); - for (Paintable c : paintableToCell.keySet()) { - client.handleComponentRelativeSize((Widget) c); - } - } - } - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - if (!width.equals(this.width)) { - this.width = width; - if (rendering) { - sizeChangedDuringRendering = true; - } else { - int[] oldWidths = cloneArray(columnWidths); - expandColumns(); - boolean heightChanged = false; - HashSet<Integer> dirtyRows = null; - for (int i = 0; i < oldWidths.length; i++) { - if (columnWidths[i] != oldWidths[i]) { - Cell[] column = cells[i]; - for (int j = 0; j < column.length; j++) { - Cell c = column[j]; - if (c != null && c.cc != null - && c.widthCanAffectHeight()) { - c.cc.setContainerSize(c.getAvailableWidth(), - c.getAvailableHeight()); - client.handleComponentRelativeSize(c.cc - .getWidget()); - c.cc.updateWidgetSize(); - int newHeight = c.getHeight(); - if (columnWidths[i] < oldWidths[i] - && newHeight > minRowHeights[j] - && c.rowspan == 1) { - /* - * The width of this column was reduced and - * this affected the height. The height is - * now greater than the previously - * calculated minHeight for the row. - */ - minRowHeights[j] = newHeight; - if (newHeight > rowHeights[j]) { - /* - * The new height is greater than the - * previously calculated rowHeight -> we - * need to recalculate heights later on - */ - rowHeights[j] = newHeight; - heightChanged = true; - } - } else if (newHeight < minRowHeights[j]) { - /* - * The new height of the component is less - * than the previously calculated min row - * height. The min row height may be - * affected and must thus be recalculated - */ - if (dirtyRows == null) { - dirtyRows = new HashSet<Integer>(); - } - dirtyRows.add(j); - } - } - } - } - } - if (dirtyRows != null) { - /* flag indicating that there is a potential row shrinking */ - boolean rowMayShrink = false; - for (Integer rowIndex : dirtyRows) { - int oldMinimum = minRowHeights[rowIndex]; - int newMinimum = 0; - for (int colIndex = 0; colIndex < columnWidths.length; colIndex++) { - Cell cell = cells[colIndex][rowIndex]; - if (cell != null && !cell.hasRelativeHeight() - && cell.getHeight() > newMinimum) { - newMinimum = cell.getHeight(); - } - } - if (newMinimum < oldMinimum) { - minRowHeights[rowIndex] = rowHeights[rowIndex] = newMinimum; - rowMayShrink = true; - } - } - if (rowMayShrink) { - distributeRowSpanHeights(); - minRowHeights = cloneArray(rowHeights); - heightChanged = true; - } - - } - layoutCells(); - for (Paintable c : paintableToCell.keySet()) { - client.handleComponentRelativeSize((Widget) c); - } - if (heightChanged && "".equals(height)) { - Util.notifyParentOfSizeChange(this, false); - } - } - } - } - - private void expandColumns() { - if (!"".equals(width)) { - int usedSpace = minColumnWidths[0]; - for (int i = 1; i < minColumnWidths.length; i++) { - usedSpace += spacingPixelsHorizontal + minColumnWidths[i]; - } - canvas.setWidth(""); - int availableSpace = canvas.getOffsetWidth(); - int excessSpace = availableSpace - usedSpace; - int distributed = 0; - if (excessSpace > 0) { - for (int i = 0; i < columnWidths.length; i++) { - int ew = excessSpace * colExpandRatioArray[i] / 1000; - columnWidths[i] = minColumnWidths[i] + ew; - distributed += ew; - } - excessSpace -= distributed; - int c = 0; - while (excessSpace > 0) { - columnWidths[c % columnWidths.length]++; - excessSpace--; - c++; - } - } - } - } - - private void layoutCells() { - int x = 0; - int y = 0; - for (int i = 0; i < cells.length; i++) { - y = 0; - for (int j = 0; j < cells[i].length; j++) { - Cell cell = cells[i][j]; - if (cell != null) { - cell.layout(x, y); - } - y += rowHeights[j] + spacingPixelsVertical; - } - x += columnWidths[i] + spacingPixelsHorizontal; - } - - if (isUndefinedWidth()) { - canvas.setWidth((x - spacingPixelsHorizontal) + "px"); - } else { - // main element defines width - canvas.setWidth(""); - } - - int canvasHeight; - if (isUndefinedHeight()) { - canvasHeight = y - spacingPixelsVertical; - } else { - canvasHeight = getOffsetHeight() - marginTopAndBottom; - if (canvasHeight < 0) { - canvasHeight = 0; - } - } - canvas.setHeight(canvasHeight + "px"); - } - - private boolean isUndefinedHeight() { - return "".equals(height); - } - - private boolean isUndefinedWidth() { - return "".equals(width); - } - - private void renderRemainingComponents(LinkedList<Cell> pendingCells) { - for (Cell cell : pendingCells) { - cell.render(); - } - } - - private void detectRowHeights() { - - // collect min rowheight from non-rowspanned cells - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < cells[i].length; j++) { - Cell cell = cells[i][j]; - if (cell != null) { - /* - * Setting fixing container width may in some situations - * affect height. Example: Label with wrapping text without - * or with relative width. - */ - if (cell.cc != null && cell.widthCanAffectHeight()) { - cell.cc.setWidth(cell.getAvailableWidth() + "px"); - cell.cc.updateWidgetSize(); - } - if (cell.rowspan == 1) { - if (!cell.hasRelativeHeight() - && rowHeights[j] < cell.getHeight()) { - rowHeights[j] = cell.getHeight(); - } - } else { - storeRowSpannedCell(cell); - } - } - } - } - - distributeRowSpanHeights(); - - minRowHeights = cloneArray(rowHeights); - } - - private void storeRowSpannedCell(Cell cell) { - SpanList l = null; - for (SpanList list : rowSpans) { - if (list.span < cell.rowspan) { - continue; - } else { - // insert before this - l = list; - break; - } - } - if (l == null) { - l = new SpanList(cell.rowspan); - rowSpans.add(l); - } else if (l.span != cell.rowspan) { - SpanList newL = new SpanList(cell.rowspan); - rowSpans.add(rowSpans.indexOf(l), newL); - l = newL; - } - l.cells.add(cell); - } - - private void renderRemainingComponentsWithNoRelativeHeight( - LinkedList<Cell> pendingCells) { - - for (Iterator<Cell> iterator = pendingCells.iterator(); iterator - .hasNext();) { - Cell cell = iterator.next(); - if (!cell.hasRelativeHeight()) { - cell.render(); - iterator.remove(); - } - } - - } - - /** - * Iterates colspanned cells, ensures cols have enough space to accommodate - * them - */ - private void distributeColSpanWidths() { - for (SpanList list : colSpans) { - for (Cell cell : list.cells) { - // cells with relative content may return non 0 here if on - // subsequent renders - int width = cell.hasRelativeWidth() ? 0 : cell.getWidth(); - distributeSpanSize(columnWidths, cell.col, cell.colspan, - spacingPixelsHorizontal, width, colExpandRatioArray); - } - } - } - - /** - * Iterates rowspanned cells, ensures rows have enough space to accommodate - * them - */ - private void distributeRowSpanHeights() { - for (SpanList list : rowSpans) { - for (Cell cell : list.cells) { - // cells with relative content may return non 0 here if on - // subsequent renders - int height = cell.hasRelativeHeight() ? 0 : cell.getHeight(); - distributeSpanSize(rowHeights, cell.row, cell.rowspan, - spacingPixelsVertical, height, rowExpandRatioArray); - } - } - } - - private static void distributeSpanSize(int[] dimensions, - int spanStartIndex, int spanSize, int spacingSize, int size, - int[] expansionRatios) { - int allocated = dimensions[spanStartIndex]; - for (int i = 1; i < spanSize; i++) { - allocated += spacingSize + dimensions[spanStartIndex + i]; - } - if (allocated < size) { - // dimensions needs to be expanded due spanned cell - int neededExtraSpace = size - allocated; - int allocatedExtraSpace = 0; - - // Divide space according to expansion ratios if any span has a - // ratio - int totalExpansion = 0; - for (int i = 0; i < spanSize; i++) { - int itemIndex = spanStartIndex + i; - totalExpansion += expansionRatios[itemIndex]; - } - - for (int i = 0; i < spanSize; i++) { - int itemIndex = spanStartIndex + i; - int expansion; - if (totalExpansion == 0) { - // Divide equally among all cells if there are no - // expansion ratios - expansion = neededExtraSpace / spanSize; - } else { - expansion = neededExtraSpace * expansionRatios[itemIndex] - / totalExpansion; - } - dimensions[itemIndex] += expansion; - allocatedExtraSpace += expansion; - } - - // We might still miss a couple of pixels because of - // rounding errors... - if (neededExtraSpace > allocatedExtraSpace) { - for (int i = 0; i < spanSize; i++) { - // Add one pixel to every cell until we have - // compensated for any rounding error - int itemIndex = spanStartIndex + i; - dimensions[itemIndex] += 1; - allocatedExtraSpace += 1; - if (neededExtraSpace == allocatedExtraSpace) { - break; - } - } - } - } - } - - private LinkedList<SpanList> colSpans = new LinkedList<SpanList>(); - private LinkedList<SpanList> rowSpans = new LinkedList<SpanList>(); - - private int marginTopAndBottom; - - private class SpanList { - final int span; - List<Cell> cells = new LinkedList<Cell>(); - - public SpanList(int span) { - this.span = span; - } - } - - private void storeColSpannedCell(Cell cell) { - SpanList l = null; - for (SpanList list : colSpans) { - if (list.span < cell.colspan) { - continue; - } else { - // insert before this - l = list; - break; - } - } - if (l == null) { - l = new SpanList(cell.colspan); - colSpans.add(l); - } else if (l.span != cell.colspan) { - - SpanList newL = new SpanList(cell.colspan); - colSpans.add(colSpans.indexOf(l), newL); - l = newL; - } - l.cells.add(cell); - } - - private void detectSpacing(UIDL uidl) { - DivElement spacingmeter = Document.get().createDivElement(); - spacingmeter.setClassName(CLASSNAME + "-" + "spacing-" - + (uidl.getBooleanAttribute("spacing") ? "on" : "off")); - spacingmeter.getStyle().setProperty("width", "0"); - spacingmeter.getStyle().setProperty("height", "0"); - canvas.getElement().appendChild(spacingmeter); - spacingPixelsHorizontal = spacingmeter.getOffsetWidth(); - spacingPixelsVertical = spacingmeter.getOffsetHeight(); - canvas.getElement().removeChild(spacingmeter); - } - - private void handleMargins(UIDL uidl) { - final VMarginInfo margins = new VMarginInfo( - uidl.getIntAttribute("margins")); - - String styles = CLASSNAME + "-margin"; - if (margins.hasTop()) { - styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_TOP; - } - if (margins.hasRight()) { - styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT; - } - if (margins.hasBottom()) { - styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM; - } - if (margins.hasLeft()) { - styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_LEFT; - } - margin.setClassName(styles); - - marginTopAndBottom = margin.getOffsetHeight() - - canvas.getOffsetHeight(); - } - - public boolean hasChildComponent(Widget component) { - return paintableToCell.containsKey(component); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - ChildComponentContainer componentContainer = widgetToComponentContainer - .remove(oldComponent); - if (componentContainer == null) { - return; - } - - componentContainer.setWidget(newComponent); - widgetToComponentContainer.put(newComponent, componentContainer); - - paintableToCell.put((Paintable) newComponent, - paintableToCell.get(oldComponent)); - } - - public void updateCaption(Paintable component, UIDL uidl) { - ChildComponentContainer cc = widgetToComponentContainer.get(component); - if (cc != null) { - cc.updateCaption(uidl, client); - } - if (!rendering) { - // ensure rel size details are updated - paintableToCell.get(component).updateRelSizeStatus(uidl); - /* - * This was a component-only update and the possible size change - * must be propagated to the layout - */ - client.captionSizeUpdated(component); - } - } - - public boolean requestLayout(final Set<Paintable> changedChildren) { - boolean needsLayout = false; - boolean reDistributeColSpanWidths = false; - boolean reDistributeRowSpanHeights = false; - int offsetHeight = canvas.getOffsetHeight(); - int offsetWidth = canvas.getOffsetWidth(); - if ("".equals(width) || "".equals(height)) { - needsLayout = true; - } - ArrayList<Integer> dirtyColumns = new ArrayList<Integer>(); - ArrayList<Integer> dirtyRows = new ArrayList<Integer>(); - for (Paintable paintable : changedChildren) { - - Cell cell = paintableToCell.get(paintable); - if (!cell.hasRelativeHeight() || !cell.hasRelativeWidth()) { - // cell sizes will only stay still if only relatively - // sized components - // check if changed child affects min col widths - assert cell.cc != null; - cell.cc.setWidth(""); - cell.cc.setHeight(""); - - cell.cc.updateWidgetSize(); - - /* - * If this is the result of an caption icon onload event the - * caption size may have changed - */ - cell.cc.updateCaptionSize(); - - int width = cell.getWidth(); - int allocated = columnWidths[cell.col]; - for (int i = 1; i < cell.colspan; i++) { - allocated += spacingPixelsHorizontal - + columnWidths[cell.col + i]; - } - if (allocated < width) { - needsLayout = true; - if (cell.colspan == 1) { - // do simple column width expansion - columnWidths[cell.col] = minColumnWidths[cell.col] = width; - } else { - // mark that col span expansion is needed - reDistributeColSpanWidths = true; - } - } else if (allocated != width) { - // size is smaller thant allocated, column might - // shrink - dirtyColumns.add(cell.col); - } - - int height = cell.getHeight(); - - allocated = rowHeights[cell.row]; - for (int i = 1; i < cell.rowspan; i++) { - allocated += spacingPixelsVertical - + rowHeights[cell.row + i]; - } - if (allocated < height) { - needsLayout = true; - if (cell.rowspan == 1) { - // do simple row expansion - rowHeights[cell.row] = minRowHeights[cell.row] = height; - } else { - // mark that row span expansion is needed - reDistributeRowSpanHeights = true; - } - } else if (allocated != height) { - // size is smaller than allocated, row might shrink - dirtyRows.add(cell.row); - } - } - } - - if (dirtyColumns.size() > 0) { - for (Integer colIndex : dirtyColumns) { - int colW = 0; - for (int i = 0; i < rowHeights.length; i++) { - Cell cell = cells[colIndex][i]; - if (cell != null && cell.getChildUIDL() != null - && !cell.hasRelativeWidth() && cell.colspan == 1) { - int width = cell.getWidth(); - if (width > colW) { - colW = width; - } - } - } - minColumnWidths[colIndex] = colW; - } - needsLayout = true; - // ensure colspanned columns have enough space - columnWidths = cloneArray(minColumnWidths); - distributeColSpanWidths(); - reDistributeColSpanWidths = false; - } - - if (reDistributeColSpanWidths) { - distributeColSpanWidths(); - } - - if (dirtyRows.size() > 0) { - needsLayout = true; - for (Integer rowIndex : dirtyRows) { - // recalculate min row height - int rowH = minRowHeights[rowIndex] = 0; - // loop all columns on row rowIndex - for (int i = 0; i < columnWidths.length; i++) { - Cell cell = cells[i][rowIndex]; - if (cell != null && cell.getChildUIDL() != null - && !cell.hasRelativeHeight() && cell.rowspan == 1) { - int h = cell.getHeight(); - if (h > rowH) { - rowH = h; - } - } - } - minRowHeights[rowIndex] = rowH; - } - // TODO could check only some row spans - rowHeights = cloneArray(minRowHeights); - distributeRowSpanHeights(); - reDistributeRowSpanHeights = false; - } - - if (reDistributeRowSpanHeights) { - distributeRowSpanHeights(); - } - - if (needsLayout) { - expandColumns(); - expandRows(); - layoutCells(); - // loop all relative sized components and update their size - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < cells[i].length; j++) { - Cell cell = cells[i][j]; - if (cell != null - && cell.cc != null - && (cell.hasRelativeHeight() || cell - .hasRelativeWidth())) { - client.handleComponentRelativeSize(cell.cc.getWidget()); - } - } - } - } - if (canvas.getOffsetHeight() != offsetHeight - || canvas.getOffsetWidth() != offsetWidth) { - return false; - } else { - return true; - } - } - - public RenderSpace getAllocatedSpace(Widget child) { - Cell cell = paintableToCell.get(child); - assert cell != null; - return cell.getAllocatedSpace(); - } - - private Cell[][] cells; - - /** - * Private helper class. - */ - private class Cell { - private boolean relHeight = false; - private boolean relWidth = false; - private boolean widthCanAffectHeight = false; - - public Cell(UIDL c) { - row = c.getIntAttribute("y"); - col = c.getIntAttribute("x"); - setUidl(c); - } - - public boolean widthCanAffectHeight() { - return widthCanAffectHeight; - } - - public boolean hasRelativeHeight() { - return relHeight; - } - - public RenderSpace getAllocatedSpace() { - return new RenderSpace(getAvailableWidth() - - cc.getCaptionWidthAfterComponent(), getAvailableHeight() - - cc.getCaptionHeightAboveComponent()); - } - - public boolean hasContent() { - return childUidl != null; - } - - /** - * @return total of spanned cols - */ - private int getAvailableWidth() { - int width = columnWidths[col]; - for (int i = 1; i < colspan; i++) { - width += spacingPixelsHorizontal + columnWidths[col + i]; - } - return width; - } - - /** - * @return total of spanned rows - */ - private int getAvailableHeight() { - int height = rowHeights[row]; - for (int i = 1; i < rowspan; i++) { - height += spacingPixelsVertical + rowHeights[row + i]; - } - return height; - } - - public void layout(int x, int y) { - if (cc != null && cc.isAttached()) { - canvas.setWidgetPosition(cc, x, y); - cc.setContainerSize(getAvailableWidth(), getAvailableHeight()); - cc.setAlignment(new AlignmentInfo(alignment)); - cc.updateAlignments(getAvailableWidth(), getAvailableHeight()); - } - } - - public int getWidth() { - if (cc != null) { - int w = cc.getWidgetSize().getWidth() - + cc.getCaptionWidthAfterComponent(); - return w; - } else { - return 0; - } - } - - public int getHeight() { - if (cc != null) { - return cc.getWidgetSize().getHeight() - + cc.getCaptionHeightAboveComponent(); - } else { - return 0; - } - } - - public boolean renderIfNoRelativeWidth() { - if (childUidl == null) { - return false; - } - if (!hasRelativeWidth()) { - render(); - return true; - } else { - return false; - } - } - - protected boolean hasRelativeWidth() { - return relWidth; - } - - protected void render() { - assert childUidl != null; - - Paintable paintable = client.getPaintable(childUidl); - assert paintable != null; - if (cc == null || cc.getWidget() != paintable) { - if (widgetToComponentContainer.containsKey(paintable)) { - // Component moving from one place to another - cc = widgetToComponentContainer.get(paintable); - cc.setWidth(""); - cc.setHeight(""); - /* - * Widget might not be set if moving from another component - * and this layout has been hidden when moving out, see - * #5372 - */ - cc.setWidget((Widget) paintable); - } else { - // A new component - cc = new ChildComponentContainer((Widget) paintable, - CellBasedLayout.ORIENTATION_VERTICAL); - widgetToComponentContainer.put((Widget) paintable, cc); - cc.setWidth(""); - canvas.add(cc, 0, 0); - } - paintableToCell.put(paintable, this); - } - cc.renderChild(childUidl, client, -1); - if (sizeChangedDuringRendering && Util.isCached(childUidl)) { - client.handleComponentRelativeSize(cc.getWidget()); - } - cc.updateWidgetSize(); - nonRenderedWidgets.remove(paintable); - } - - public UIDL getChildUIDL() { - return childUidl; - } - - final int row; - final int col; - int colspan = 1; - int rowspan = 1; - UIDL childUidl; - int alignment; - // may be null after setUidl() if content has vanished or changed, set - // in render() - ChildComponentContainer cc; - - public void setUidl(UIDL c) { - // Set cell width - colspan = c.hasAttribute("w") ? c.getIntAttribute("w") : 1; - // Set cell height - rowspan = c.hasAttribute("h") ? c.getIntAttribute("h") : 1; - // ensure we will lose reference to old cells, now overlapped by - // this cell - for (int i = 0; i < colspan; i++) { - for (int j = 0; j < rowspan; j++) { - if (i > 0 || j > 0) { - cells[col + i][row + j] = null; - } - } - } - - c = c.getChildUIDL(0); // we are interested about childUidl - if (childUidl != null) { - if (c == null) { - // content has vanished, old content will be removed from - // canvas later during the render phase - cc = null; - } else if (cc != null - && cc.getWidget() != client.getPaintable(c)) { - // content has changed - cc = null; - Paintable paintable = client.getPaintable(c); - if (widgetToComponentContainer.containsKey(paintable)) { - // cc exist for this component (moved) use that for this - // cell - cc = widgetToComponentContainer.get(paintable); - cc.setWidth(""); - cc.setHeight(""); - paintableToCell.put(paintable, this); - } - } - } - childUidl = c; - updateRelSizeStatus(c); - } - - protected void updateRelSizeStatus(UIDL uidl) { - if (uidl != null && !uidl.getBooleanAttribute("cached")) { - if (uidl.hasAttribute("height") - && uidl.getStringAttribute("height").contains("%")) { - relHeight = true; - } else { - relHeight = false; - } - if (uidl.hasAttribute("width")) { - widthCanAffectHeight = relWidth = uidl.getStringAttribute( - "width").contains("%"); - if (uidl.hasAttribute("height")) { - widthCanAffectHeight = false; - } - } else { - widthCanAffectHeight = !uidl.hasAttribute("height"); - relWidth = false; - } - } - } - } - - private Cell getCell(UIDL c) { - int row = c.getIntAttribute("y"); - int col = c.getIntAttribute("x"); - Cell cell = cells[col][row]; - if (cell == null) { - cell = new Cell(c); - cells[col][row] = cell; - } else { - cell.setUidl(c); - } - return cell; - } - - /** - * Returns the deepest nested child component which contains "element". The - * child component is also returned if "element" is part of its caption. - * - * @param element - * An element that is a nested sub element of the root element in - * this layout - * @return The Paintable which the element is a part of. Null if the element - * belongs to the layout and not to a child. - */ - private Paintable getComponent(Element element) { - return Util.getPaintableForElement(client, this, element); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayout.java deleted file mode 100644 index b3a036f748..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayout.java +++ /dev/null @@ -1,14 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -public class VHorizontalLayout extends VOrderedLayout { - - public static final String CLASSNAME = "v-horizontallayout"; - - public VHorizontalLayout() { - super(CLASSNAME, ORIENTATION_HORIZONTAL); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLabel.java b/src/com/vaadin/terminal/gwt/client/ui/VLabel.java deleted file mode 100644 index 341e9f3484..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VLabel.java +++ /dev/null @@ -1,135 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.dom.client.PreElement; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.HTML; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; - -public class VLabel extends HTML implements Paintable { - - public static final String CLASSNAME = "v-label"; - private static final String CLASSNAME_UNDEFINED_WIDTH = "v-label-undef-w"; - - private ApplicationConnection client; - private int verticalPaddingBorder = 0; - private int horizontalPaddingBorder = 0; - - public VLabel() { - super(); - setStyleName(CLASSNAME); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - public VLabel(String text) { - super(text); - setStyleName(CLASSNAME); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (event.getTypeInt() == Event.ONLOAD) { - Util.notifyParentOfSizeChange(this, true); - event.cancelBubble(true); - return; - } - if (client != null) { - client.handleTooltipEvent(event, this); - } - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - if (client.updateComponent(this, uidl, true)) { - return; - } - - this.client = client; - - boolean sinkOnloads = false; - - final String mode = uidl.getStringAttribute("mode"); - if (mode == null || "text".equals(mode)) { - setText(uidl.getChildString(0)); - } else if ("pre".equals(mode)) { - PreElement preElement = Document.get().createPreElement(); - preElement.setInnerText(uidl.getChildUIDL(0).getChildString(0)); - // clear existing content - setHTML(""); - // add preformatted text to dom - getElement().appendChild(preElement); - } else if ("uidl".equals(mode)) { - setHTML(uidl.getChildrenAsXML()); - } else if ("xhtml".equals(mode)) { - UIDL content = uidl.getChildUIDL(0).getChildUIDL(0); - if (content.getChildCount() > 0) { - setHTML(content.getChildString(0)); - } else { - setHTML(""); - } - sinkOnloads = true; - } else if ("xml".equals(mode)) { - setHTML(uidl.getChildUIDL(0).getChildString(0)); - } else if ("raw".equals(mode)) { - setHTML(uidl.getChildUIDL(0).getChildString(0)); - sinkOnloads = true; - } else { - setText(""); - } - if (sinkOnloads) { - sinkOnloadsForContainedImgs(); - } - } - - private void sinkOnloadsForContainedImgs() { - NodeList<Element> images = getElement().getElementsByTagName("img"); - for (int i = 0; i < images.getLength(); i++) { - Element img = images.getItem(i); - DOM.sinkEvents((com.google.gwt.user.client.Element) img, - Event.ONLOAD); - } - - } - - @Override - public void setHeight(String height) { - verticalPaddingBorder = Util.setHeightExcludingPaddingAndBorder(this, - height, verticalPaddingBorder); - } - - @Override - public void setWidth(String width) { - horizontalPaddingBorder = Util.setWidthExcludingPaddingAndBorder(this, - width, horizontalPaddingBorder); - if (width == null || width.equals("")) { - setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true); - } else { - setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false); - } - } - - @Override - public void setText(String text) { - if (BrowserInfo.get().isIE() && BrowserInfo.get().getIEVersion() < 9) { - // #3983 - IE6-IE8 incorrectly replaces \n with <br> so we do the - // escaping manually and set as HTML - super.setHTML(Util.escapeHTML(text)); - } else { - super.setText(text); - } - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLink.java b/src/com/vaadin/terminal/gwt/client/ui/VLink.java deleted file mode 100644 index b8030de421..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VLink.java +++ /dev/null @@ -1,182 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -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.Window; -import com.google.gwt.user.client.ui.HTML; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; - -public class VLink extends HTML implements Paintable, ClickHandler { - - public static final String CLASSNAME = "v-link"; - - private static final int BORDER_STYLE_DEFAULT = 0; - private static final int BORDER_STYLE_MINIMAL = 1; - private static final int BORDER_STYLE_NONE = 2; - - private String src; - - private String target; - - private int borderStyle = BORDER_STYLE_DEFAULT; - - private boolean enabled; - - private boolean readonly; - - private int targetWidth; - - private int targetHeight; - - private Element errorIndicatorElement; - - private final Element anchor = DOM.createAnchor(); - - private final Element captionElement = DOM.createSpan(); - - private Icon icon; - - private ApplicationConnection client; - - public VLink() { - super(); - getElement().appendChild(anchor); - anchor.appendChild(captionElement); - addClickHandler(this); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - setStyleName(CLASSNAME); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - // Ensure correct implementation, - // but don't let container manage caption etc. - if (client.updateComponent(this, uidl, false)) { - return; - } - - this.client = client; - - enabled = uidl.hasAttribute("disabled") ? false : true; - readonly = uidl.hasAttribute("readonly") ? true : false; - - if (uidl.hasAttribute("name")) { - target = uidl.getStringAttribute("name"); - anchor.setAttribute("target", target); - } - if (uidl.hasAttribute("src")) { - src = client.translateVaadinUri(uidl.getStringAttribute("src")); - anchor.setAttribute("href", src); - } - - if (uidl.hasAttribute("border")) { - if ("none".equals(uidl.getStringAttribute("border"))) { - borderStyle = BORDER_STYLE_NONE; - } else { - borderStyle = BORDER_STYLE_MINIMAL; - } - } else { - borderStyle = BORDER_STYLE_DEFAULT; - } - - targetHeight = uidl.hasAttribute("targetHeight") ? uidl - .getIntAttribute("targetHeight") : -1; - targetWidth = uidl.hasAttribute("targetWidth") ? uidl - .getIntAttribute("targetWidth") : -1; - - // Set link caption - captionElement.setInnerText(uidl.getStringAttribute("caption")); - - // handle error - if (uidl.hasAttribute("error")) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createDiv(); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - } - DOM.insertChild(getElement(), errorIndicatorElement, 0); - } else if (errorIndicatorElement != null) { - DOM.setStyleAttribute(errorIndicatorElement, "display", "none"); - } - - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - anchor.insertBefore(icon.getElement(), captionElement); - } - icon.setUri(uidl.getStringAttribute("icon")); - } - - } - - public void onClick(ClickEvent event) { - if (enabled && !readonly) { - if (target == null) { - target = "_self"; - } - String features; - switch (borderStyle) { - case BORDER_STYLE_NONE: - features = "menubar=no,location=no,status=no"; - break; - case BORDER_STYLE_MINIMAL: - features = "menubar=yes,location=no,status=no"; - break; - default: - features = ""; - break; - } - - if (targetWidth > 0) { - features += (features.length() > 0 ? "," : "") + "width=" - + targetWidth; - } - if (targetHeight > 0) { - features += (features.length() > 0 ? "," : "") + "height=" - + targetHeight; - } - - if (features.length() > 0) { - // if 'special features' are set, use window.open(), unless - // a modifier key is held (ctrl to open in new tab etc) - Event e = DOM.eventGetCurrentEvent(); - if (!e.getCtrlKey() && !e.getAltKey() && !e.getShiftKey() - && !e.getMetaKey()) { - Window.open(src, target, features); - e.preventDefault(); - } - } - } - } - - @Override - public void onBrowserEvent(Event event) { - final Element target = DOM.eventGetTarget(event); - if (event.getTypeInt() == Event.ONLOAD) { - Util.notifyParentOfSizeChange(this, true); - } - if (client != null) { - client.handleTooltipEvent(event, this); - } - if (target == captionElement || target == anchor - || (icon != null && target == icon.getElement())) { - super.onBrowserEvent(event); - } - if (!enabled) { - event.preventDefault(); - } - - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java b/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java index 53638917b2..6c5fbc2ef0 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java @@ -8,25 +8,10 @@ import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.MediaElement; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -public abstract class VMediaBase extends Widget implements Paintable { - public static final String ATTR_PAUSE = "pause"; - public static final String ATTR_PLAY = "play"; - public static final String ATTR_MUTED = "muted"; - public static final String ATTR_CONTROLS = "ctrl"; - public static final String ATTR_AUTOPLAY = "auto"; - public static final String TAG_SOURCE = "src"; - public static final String ATTR_RESOURCE = "res"; - public static final String ATTR_RESOURCE_TYPE = "type"; - public static final String ATTR_HTML = "html"; - public static final String ATTR_ALT_TEXT = "alt"; +public abstract class VMediaBase extends Widget { private MediaElement media; - protected ApplicationConnection client; /** * Sets the MediaElement that is to receive all commands and properties. @@ -38,96 +23,40 @@ public abstract class VMediaBase extends Widget implements Paintable { media = element; } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { - return; - } - - this.client = client; - - media.setControls(shouldShowControls(uidl)); - media.setAutoplay(shouldAutoplay(uidl)); - media.setMuted(isMediaMuted(uidl)); - - // Add all sources - for (int ix = 0; ix < uidl.getChildCount(); ix++) { - UIDL child = uidl.getChildUIDL(ix); - if (TAG_SOURCE.equals(child.getTag())) { - Element src = Document.get().createElement("source").cast(); - src.setAttribute("src", getSourceUrl(child)); - src.setAttribute("type", getSourceType(child)); - media.appendChild(src); - } - } - setAltText(uidl); - - evalPauseCommand(uidl); - evalPlayCommand(uidl); - } - - protected boolean shouldShowControls(UIDL uidl) { - return uidl.getBooleanAttribute(ATTR_CONTROLS); - } - - private boolean shouldAutoplay(UIDL uidl) { - return uidl.getBooleanAttribute(ATTR_AUTOPLAY); - } - - private boolean isMediaMuted(UIDL uidl) { - return uidl.getBooleanAttribute(ATTR_MUTED); - } - /** - * @param uidl - * @return the URL of a resource to be used as a source for the media + * @return the default HTML to show users with browsers that do not support + * HTML5 media markup. */ - private String getSourceUrl(UIDL uidl) { - String url = client.translateVaadinUri(uidl - .getStringAttribute(ATTR_RESOURCE)); - if (url == null) { - return ""; - } - return url; - } + protected abstract String getDefaultAltHtml(); - /** - * @param uidl - * @return the mime type of the media - */ - private String getSourceType(UIDL uidl) { - return uidl.getStringAttribute(ATTR_RESOURCE_TYPE); + public void play() { + media.play(); } - private void setAltText(UIDL uidl) { - String alt = uidl.getStringAttribute(ATTR_ALT_TEXT); + public void pause() { + media.pause(); + } - if (alt == null || "".equals(alt)) { - alt = getDefaultAltHtml(); - } else if (!allowHtmlContent(uidl)) { - alt = Util.escapeHTML(alt); - } + public void setAltText(String alt) { media.appendChild(Document.get().createTextNode(alt)); } - private boolean allowHtmlContent(UIDL uidl) { - return uidl.getBooleanAttribute(ATTR_HTML); + public void setControls(boolean shouldShowControls) { + media.setControls(shouldShowControls); } - private void evalPlayCommand(UIDL uidl) { - if (uidl.hasAttribute(ATTR_PLAY)) { - media.play(); - } + public void setAutoplay(boolean shouldAutoplay) { + media.setAutoplay(shouldAutoplay); } - private void evalPauseCommand(UIDL uidl) { - if (uidl.hasAttribute(ATTR_PAUSE)) { - media.pause(); - } + public void setMuted(boolean mediaMuted) { + media.setMuted(mediaMuted); } - /** - * @return the default HTML to show users with browsers that do not support - * HTML5 media markup. - */ - protected abstract String getDefaultAltHtml(); + public void addSource(String sourceUrl, String sourceType) { + Element src = Document.get().createElement("source").cast(); + src.setAttribute("src", sourceUrl); + src.setAttribute("type", sourceType); + media.appendChild(src); + } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java deleted file mode 100644 index 98d3b505ae..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VNativeButton.java +++ /dev/null @@ -1,238 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.dom.client.Element; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.Button; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.EventHelper; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VTooltip; - -public class VNativeButton extends Button implements Paintable, ClickHandler, - FocusHandler, BlurHandler { - - public static final String CLASSNAME = "v-nativebutton"; - - protected String width = null; - - protected String id; - - protected ApplicationConnection client; - - protected Element errorIndicatorElement; - - protected final Element captionElement = DOM.createSpan(); - - protected Icon icon; - - /** - * Helper flag to handle special-case where the button is moved from under - * mouse while clicking it. In this case mouse leaves the button without - * moving. - */ - private boolean clickPending; - - private HandlerRegistration focusHandlerRegistration; - private HandlerRegistration blurHandlerRegistration; - - private boolean disableOnClick = false; - - public VNativeButton() { - setStyleName(CLASSNAME); - - getElement().appendChild(captionElement); - captionElement.setClassName(getStyleName() + "-caption"); - - addClickHandler(this); - - sinkEvents(VTooltip.TOOLTIP_EVENTS); - sinkEvents(Event.ONMOUSEDOWN); - sinkEvents(Event.ONMOUSEUP); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - // Ensure correct implementation, - // but don't let container manage caption etc. - if (client.updateComponent(this, uidl, false)) { - return; - } - - disableOnClick = uidl.hasAttribute(VButton.ATTR_DISABLE_ON_CLICK); - - focusHandlerRegistration = EventHelper.updateFocusHandler(this, client, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, client, - blurHandlerRegistration); - - // Save details - this.client = client; - id = uidl.getId(); - - // Set text - setText(uidl.getStringAttribute("caption")); - - // handle error - if (uidl.hasAttribute("error")) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createSpan(); - errorIndicatorElement.setClassName("v-errorindicator"); - } - getElement().insertBefore(errorIndicatorElement, captionElement); - - // Fix for IE6, IE7 - if (BrowserInfo.get().isIE()) { - errorIndicatorElement.setInnerText(" "); - } - - } else if (errorIndicatorElement != null) { - getElement().removeChild(errorIndicatorElement); - errorIndicatorElement = null; - } - - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - getElement().insertBefore(icon.getElement(), captionElement); - } - icon.setUri(uidl.getStringAttribute("icon")); - } else { - if (icon != null) { - getElement().removeChild(icon.getElement()); - icon = null; - } - } - - if (BrowserInfo.get().isIE7()) { - /* - * Workaround for IE7 size calculation issues. Deferred because of - * issues with a button with an icon using the reindeer theme - */ - if (width.equals("")) { - Scheduler.get().scheduleDeferred(new Command() { - - public void execute() { - setWidth(""); - setWidth(getOffsetWidth() + "px"); - } - }); - } - } - } - - @Override - public void setText(String text) { - captionElement.setInnerText(text); - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - - if (DOM.eventGetType(event) == Event.ONLOAD) { - Util.notifyParentOfSizeChange(this, true); - - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN - && event.getButton() == Event.BUTTON_LEFT) { - clickPending = true; - } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) { - clickPending = false; - } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) { - if (clickPending) { - click(); - } - clickPending = false; - } - - if (client != null) { - client.handleTooltipEvent(event, this); - } - } - - @Override - public void setWidth(String width) { - /* Workaround for IE7 button size part 1 (#2014) */ - if (BrowserInfo.get().isIE7() && this.width != null) { - if (this.width.equals(width)) { - return; - } - - if (width == null) { - width = ""; - } - } - - this.width = width; - super.setWidth(width); - - /* Workaround for IE7 button size part 2 (#2014) */ - if (BrowserInfo.get().isIE7()) { - super.setWidth(width); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event - * .dom.client.ClickEvent) - */ - public void onClick(ClickEvent event) { - if (id == null || client == null) { - return; - } - - if (BrowserInfo.get().isSafari()) { - VNativeButton.this.setFocus(true); - } - if (disableOnClick) { - setEnabled(false); - client.updateVariable(id, "disabledOnClick", true, false); - } - - // Add mouse details - MouseEventDetails details = new MouseEventDetails( - event.getNativeEvent(), getElement()); - client.updateVariable(id, "mousedetails", details.serialize(), false); - - client.updateVariable(id, "state", true, true); - clickPending = false; - } - - public void onFocus(FocusEvent arg0) { - client.updateVariable(id, EventId.FOCUS, "", true); - } - - public void onBlur(BlurEvent arg0) { - client.updateVariable(id, EventId.BLUR, "", true); - } - - @Override - public void setEnabled(boolean enabled) { - if (isEnabled() != enabled) { - super.setEnabled(enabled); - setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled); - } - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java deleted file mode 100644 index ecdb171ec4..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java +++ /dev/null @@ -1,969 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Set; - -import com.google.gwt.core.client.JsArrayString; -import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize; -import com.vaadin.terminal.gwt.client.RenderInformation.Size; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.ValueMap; -import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout; -import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer; - -public class VOrderedLayout extends CellBasedLayout { - - public static final String CLASSNAME = "v-orderedlayout"; - - private int orientation; - - // Can be removed once OrderedLayout is removed - private boolean allowOrientationUpdate = false; - - /** - * Size of the layout excluding any margins. - */ - private Size activeLayoutSize = new Size(0, 0); - - private boolean isRendering = false; - - private String width = ""; - - private boolean sizeHasChangedDuringRendering = false; - - private ValueMap expandRatios; - - private double expandRatioSum; - - private double defaultExpandRatio; - - private ValueMap alignments; - - private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( - this, EventId.LAYOUT_CLICK) { - - @Override - protected Paintable getChildComponent(Element element) { - return getComponent(element); - } - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - - public VOrderedLayout() { - this(CLASSNAME, ORIENTATION_VERTICAL); - allowOrientationUpdate = true; - } - - protected VOrderedLayout(String className, int orientation) { - setStyleName(className); - this.orientation = orientation; - - STYLENAME_SPACING = className + "-spacing"; - STYLENAME_MARGIN_TOP = className + "-margin-top"; - STYLENAME_MARGIN_RIGHT = className + "-margin-right"; - STYLENAME_MARGIN_BOTTOM = className + "-margin-bottom"; - STYLENAME_MARGIN_LEFT = className + "-margin-left"; - } - - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - isRendering = true; - super.updateFromUIDL(uidl, client); - - // Only non-cached, visible UIDL:s can introduce changes - if (uidl.getBooleanAttribute("cached") - || uidl.getBooleanAttribute("invisible")) { - isRendering = false; - return; - } - - clickEventHandler.handleEventHandlerRegistration(client); - - if (allowOrientationUpdate) { - handleOrientationUpdate(uidl); - } - - // IStopWatch w = new IStopWatch("OrderedLayout.updateFromUIDL"); - - ArrayList<Widget> uidlWidgets = new ArrayList<Widget>( - uidl.getChildCount()); - ArrayList<ChildComponentContainer> relativeSizeComponents = new ArrayList<ChildComponentContainer>(); - ArrayList<UIDL> relativeSizeComponentUIDL = new ArrayList<UIDL>(); - - int pos = 0; - for (final Iterator<Object> it = uidl.getChildIterator(); it.hasNext();) { - final UIDL childUIDL = (UIDL) it.next(); - final Paintable child = client.getPaintable(childUIDL); - Widget widget = (Widget) child; - - // Create container for component - ChildComponentContainer childComponentContainer = getComponentContainer(widget); - - if (childComponentContainer == null) { - // This is a new component - childComponentContainer = createChildContainer(widget); - } else { - /* - * The widget may be null if the same paintable has been - * rendered in a different component container while this has - * been invisible. Ensure the childComponentContainer has the - * widget attached. See e.g. #5372 - */ - childComponentContainer.setWidget(widget); - } - - addOrMoveChild(childComponentContainer, pos++); - - /* - * Components which are to be expanded in the same orientation as - * the layout are rendered later when it is clear how much space - * they can use - */ - if (!Util.isCached(childUIDL)) { - FloatSize relativeSize = Util.parseRelativeSize(childUIDL); - childComponentContainer.setRelativeSize(relativeSize); - } - - if (childComponentContainer.isComponentRelativeSized(orientation)) { - relativeSizeComponents.add(childComponentContainer); - relativeSizeComponentUIDL.add(childUIDL); - } else { - if (isDynamicWidth()) { - childComponentContainer.renderChild(childUIDL, client, -1); - } else { - childComponentContainer.renderChild(childUIDL, client, - activeLayoutSize.getWidth()); - } - if (sizeHasChangedDuringRendering && Util.isCached(childUIDL)) { - // notify cached relative sized component about size - // chance - client.handleComponentRelativeSize(childComponentContainer - .getWidget()); - } - } - - uidlWidgets.add(widget); - - } - - // w.mark("Rendering of " - // + (uidlWidgets.size() - relativeSizeComponents.size()) - // + " absolute size components done"); - - /* - * Remove any children after pos. These are the ones that previously - * were in the layout but have now been removed - */ - removeChildrenAfter(pos); - - // w.mark("Old children removed"); - - /* Fetch alignments and expand ratio from UIDL */ - updateAlignmentsAndExpandRatios(uidl, uidlWidgets); - // w.mark("Alignments and expand ratios updated"); - - /* Fetch widget sizes from rendered components */ - updateWidgetSizes(); - // w.mark("Widget sizes updated"); - - recalculateLayout(); - // w.mark("Layout size calculated (" + activeLayoutSize + - // ") offsetSize: " - // + getOffsetWidth() + "," + getOffsetHeight()); - - /* Render relative size components */ - for (int i = 0; i < relativeSizeComponents.size(); i++) { - ChildComponentContainer childComponentContainer = relativeSizeComponents - .get(i); - UIDL childUIDL = relativeSizeComponentUIDL.get(i); - - if (isDynamicWidth()) { - childComponentContainer.renderChild(childUIDL, client, -1); - } else { - childComponentContainer.renderChild(childUIDL, client, - activeLayoutSize.getWidth()); - } - - if (Util.isCached(childUIDL)) { - /* - * We must update the size of the relative sized component if - * the expand ratio or something else in the layout changes - * which affects the size of a relative sized component - */ - client.handleComponentRelativeSize(childComponentContainer - .getWidget()); - } - - // childComponentContainer.updateWidgetSize(); - } - - // w.mark("Rendering of " + (relativeSizeComponents.size()) - // + " relative size components done"); - - /* Fetch widget sizes for relative size components */ - for (ChildComponentContainer childComponentContainer : widgetToComponentContainer - .values()) { - - /* Update widget size from DOM */ - childComponentContainer.updateWidgetSize(); - } - - // w.mark("Widget sizes updated"); - - /* - * Components with relative size in main direction may affect the layout - * size in the other direction - */ - if ((isHorizontal() && isDynamicHeight()) - || (isVertical() && isDynamicWidth())) { - layoutSizeMightHaveChanged(); - } - // w.mark("Layout dimensions updated"); - - /* Update component spacing */ - updateContainerMargins(); - - /* - * Update component sizes for components with relative size in non-main - * direction - */ - if (updateRelativeSizesInNonMainDirection()) { - // Sizes updated - might affect the other dimension so we need to - // recheck the widget sizes and recalculate layout dimensions - updateWidgetSizes(); - layoutSizeMightHaveChanged(); - } - calculateAlignments(); - // w.mark("recalculateComponentSizesAndAlignments done"); - - setRootSize(); - - if (BrowserInfo.get().isIE()) { - /* - * This should fix the issue with padding not always taken into - * account for the containers leading to no spacing between - * elements. - */ - root.getStyle().setProperty("zoom", "1"); - } - - // w.mark("runDescendentsLayout done"); - isRendering = false; - sizeHasChangedDuringRendering = false; - } - - private void layoutSizeMightHaveChanged() { - Size oldSize = new Size(activeLayoutSize.getWidth(), - activeLayoutSize.getHeight()); - calculateLayoutDimensions(); - - /* - * If layout dimension changes we must also update container sizes - */ - if (!oldSize.equals(activeLayoutSize)) { - calculateContainerSize(); - } - } - - private void updateWidgetSizes() { - for (ChildComponentContainer childComponentContainer : widgetToComponentContainer - .values()) { - - /* - * Update widget size from DOM - */ - childComponentContainer.updateWidgetSize(); - } - } - - private void recalculateLayout() { - - /* Calculate space for relative size components */ - int spaceForExpansion = calculateLayoutDimensions(); - - if (!widgetToComponentContainer.isEmpty()) { - /* Divide expansion space between component containers */ - expandComponentContainers(spaceForExpansion); - - /* Update container sizes */ - calculateContainerSize(); - } - - } - - private void expandComponentContainers(int spaceForExpansion) { - int remaining = spaceForExpansion; - for (ChildComponentContainer childComponentContainer : widgetToComponentContainer - .values()) { - remaining -= childComponentContainer.expand(orientation, - spaceForExpansion); - } - - if (remaining > 0) { - - // Some left-over pixels due to rounding errors - - // Add one pixel to each container until there are no pixels left - // FIXME extra pixels should be divided among expanded widgets if - // such a widgets exists - - Iterator<Widget> widgetIterator = iterator(); - while (widgetIterator.hasNext() && remaining-- > 0) { - ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator - .next(); - childComponentContainer.expandExtra(orientation, 1); - } - } - - } - - private void handleOrientationUpdate(UIDL uidl) { - int newOrientation = ORIENTATION_VERTICAL; - if ("horizontal".equals(uidl.getStringAttribute("orientation"))) { - newOrientation = ORIENTATION_HORIZONTAL; - } - - if (orientation != newOrientation) { - orientation = newOrientation; - - for (ChildComponentContainer childComponentContainer : widgetToComponentContainer - .values()) { - childComponentContainer.setOrientation(orientation); - } - } - - } - - /** - * Updated components with relative height in horizontal layouts and - * components with relative width in vertical layouts. This is only needed - * if the height (horizontal layout) or width (vertical layout) has not been - * specified. - */ - private boolean updateRelativeSizesInNonMainDirection() { - int updateDirection = 1 - orientation; - if ((updateDirection == ORIENTATION_HORIZONTAL && !isDynamicWidth()) - || (updateDirection == ORIENTATION_VERTICAL && !isDynamicHeight())) { - return false; - } - - boolean updated = false; - for (ChildComponentContainer componentContainer : widgetToComponentContainer - .values()) { - if (componentContainer.isComponentRelativeSized(updateDirection)) { - client.handleComponentRelativeSize(componentContainer - .getWidget()); - } - - updated = true; - } - - return updated; - } - - private int calculateLayoutDimensions() { - int summedWidgetWidth = 0; - int summedWidgetHeight = 0; - - int maxWidgetWidth = 0; - int maxWidgetHeight = 0; - - // Calculate layout dimensions from component dimensions - for (ChildComponentContainer childComponentContainer : widgetToComponentContainer - .values()) { - - int widgetHeight = 0; - int widgetWidth = 0; - if (childComponentContainer.isComponentRelativeSized(orientation)) { - if (orientation == ORIENTATION_HORIZONTAL) { - widgetHeight = getWidgetHeight(childComponentContainer); - } else { - widgetWidth = getWidgetWidth(childComponentContainer); - } - } else { - widgetWidth = getWidgetWidth(childComponentContainer); - widgetHeight = getWidgetHeight(childComponentContainer); - } - - summedWidgetWidth += widgetWidth; - summedWidgetHeight += widgetHeight; - - maxWidgetHeight = Math.max(maxWidgetHeight, widgetHeight); - maxWidgetWidth = Math.max(maxWidgetWidth, widgetWidth); - } - - if (isHorizontal()) { - summedWidgetWidth += activeSpacing.hSpacing - * (widgetToComponentContainer.size() - 1); - } else { - summedWidgetHeight += activeSpacing.vSpacing - * (widgetToComponentContainer.size() - 1); - } - - Size layoutSize = updateLayoutDimensions(summedWidgetWidth, - summedWidgetHeight, maxWidgetWidth, maxWidgetHeight); - - int remainingSpace; - if (isHorizontal()) { - remainingSpace = layoutSize.getWidth() - summedWidgetWidth; - } else { - remainingSpace = layoutSize.getHeight() - summedWidgetHeight; - } - if (remainingSpace < 0) { - remainingSpace = 0; - } - - // ApplicationConnection.getConsole().log( - // "Layout size: " + activeLayoutSize); - return remainingSpace; - } - - private int getWidgetHeight(ChildComponentContainer childComponentContainer) { - Size s = childComponentContainer.getWidgetSize(); - return s.getHeight() - + childComponentContainer.getCaptionHeightAboveComponent(); - } - - private int getWidgetWidth(ChildComponentContainer childComponentContainer) { - Size s = childComponentContainer.getWidgetSize(); - int widgetWidth = s.getWidth() - + childComponentContainer.getCaptionWidthAfterComponent(); - - /* - * If the component does not have a specified size in the main direction - * the caption may determine the space used by the component - */ - if (!childComponentContainer.widgetHasSizeSpecified(orientation)) { - int captionWidth = childComponentContainer - .getCaptionRequiredWidth(); - - if (captionWidth > widgetWidth) { - widgetWidth = captionWidth; - } - } - - return widgetWidth; - } - - private void calculateAlignments() { - int w = 0; - int h = 0; - - if (isHorizontal()) { - // HORIZONTAL - h = activeLayoutSize.getHeight(); - if (!isDynamicWidth()) { - w = -1; - } - - } else { - // VERTICAL - w = activeLayoutSize.getWidth(); - if (!isDynamicHeight()) { - h = -1; - } - } - - for (ChildComponentContainer childComponentContainer : widgetToComponentContainer - .values()) { - childComponentContainer.updateAlignments(w, h); - } - - } - - private void calculateContainerSize() { - - /* - * Container size here means the size the container gets from the - * component. The expansion size is not include in this but taken - * separately into account. - */ - int height = 0, width = 0; - Iterator<Widget> widgetIterator = iterator(); - if (isHorizontal()) { - height = activeLayoutSize.getHeight(); - int availableWidth = activeLayoutSize.getWidth(); - boolean first = true; - while (widgetIterator.hasNext()) { - ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator - .next(); - if (!childComponentContainer - .isComponentRelativeSized(ORIENTATION_HORIZONTAL)) { - /* - * Only components with non-relative size in the main - * direction has a container size - */ - width = childComponentContainer.getWidgetSize().getWidth() - + childComponentContainer - .getCaptionWidthAfterComponent(); - - /* - * If the component does not have a specified size in the - * main direction the caption may determine the space used - * by the component - */ - if (!childComponentContainer - .widgetHasSizeSpecified(orientation)) { - int captionWidth = childComponentContainer - .getCaptionRequiredWidth(); - // ApplicationConnection.getConsole().log( - // "Component width: " + width - // + ", caption width: " + captionWidth); - if (captionWidth > width) { - width = captionWidth; - } - } - } else { - width = 0; - } - - if (!isDynamicWidth()) { - if (availableWidth == 0) { - /* - * Let the overflowing components overflow. IE has - * problems with zero sizes. - */ - // width = 0; - // height = 0; - } else if (width > availableWidth) { - width = availableWidth; - - if (!first) { - width -= activeSpacing.hSpacing; - } - availableWidth = 0; - } else { - availableWidth -= width; - if (!first) { - availableWidth -= activeSpacing.hSpacing; - } - } - - first = false; - } - - childComponentContainer.setContainerSize(width, height); - } - } else { - width = activeLayoutSize.getWidth(); - while (widgetIterator.hasNext()) { - ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator - .next(); - - if (!childComponentContainer - .isComponentRelativeSized(ORIENTATION_VERTICAL)) { - /* - * Only components with non-relative size in the main - * direction has a container size - */ - height = childComponentContainer.getWidgetSize() - .getHeight() - + childComponentContainer - .getCaptionHeightAboveComponent(); - } else { - height = 0; - } - - childComponentContainer.setContainerSize(width, height); - } - - } - - } - - private Size updateLayoutDimensions(int totalComponentWidth, - int totalComponentHeight, int maxComponentWidth, - int maxComponentHeight) { - - /* Only need to calculate dynamic dimensions */ - if (!isDynamicHeight() && !isDynamicWidth()) { - return activeLayoutSize; - } - - int activeLayoutWidth = 0; - int activeLayoutHeight = 0; - - // Update layout dimensions - if (isHorizontal()) { - // Horizontal - if (isDynamicWidth()) { - activeLayoutWidth = totalComponentWidth; - } - - if (isDynamicHeight()) { - activeLayoutHeight = maxComponentHeight; - } - - } else { - // Vertical - if (isDynamicWidth()) { - activeLayoutWidth = maxComponentWidth; - } - - if (isDynamicHeight()) { - activeLayoutHeight = totalComponentHeight; - } - } - - if (isDynamicWidth()) { - setActiveLayoutWidth(activeLayoutWidth); - setOuterLayoutWidth(activeLayoutSize.getWidth()); - } - - if (isDynamicHeight()) { - setActiveLayoutHeight(activeLayoutHeight); - setOuterLayoutHeight(activeLayoutSize.getHeight()); - } - - return activeLayoutSize; - } - - private void setActiveLayoutWidth(int activeLayoutWidth) { - if (activeLayoutWidth < 0) { - activeLayoutWidth = 0; - } - activeLayoutSize.setWidth(activeLayoutWidth); - } - - private void setActiveLayoutHeight(int activeLayoutHeight) { - if (activeLayoutHeight < 0) { - activeLayoutHeight = 0; - } - activeLayoutSize.setHeight(activeLayoutHeight); - - } - - private void setOuterLayoutWidth(int activeLayoutWidth) { - // Don't call setWidth to avoid triggering all kinds of recalculations - // Also don't call super.setWidth to avoid messing with the - // dynamicWidth property - int newPixelWidth = (activeLayoutWidth + activeMargins.getHorizontal()); - getElement().getStyle().setWidth(newPixelWidth, Unit.PX); - } - - private void setOuterLayoutHeight(int activeLayoutHeight) { - // Don't call setHeight to avoid triggering all kinds of recalculations - // Also don't call super.setHeight to avoid messing with the - // dynamicHeight property - int newPixelHeight = (activeLayoutHeight + activeMargins.getVertical()); - getElement().getStyle().setHeight(newPixelHeight, Unit.PX); - } - - /** - * Updates the spacing between components. Needs to be done only when - * components are added/removed. - */ - private void updateContainerMargins() { - ChildComponentContainer firstChildComponent = getFirstChildComponentContainer(); - if (firstChildComponent != null) { - firstChildComponent.setMarginLeft(0); - firstChildComponent.setMarginTop(0); - - for (ChildComponentContainer childComponent : widgetToComponentContainer - .values()) { - if (childComponent == firstChildComponent) { - continue; - } - - if (isHorizontal()) { - childComponent.setMarginLeft(activeSpacing.hSpacing); - } else { - childComponent.setMarginTop(activeSpacing.vSpacing); - } - } - } - } - - private boolean isHorizontal() { - return orientation == ORIENTATION_HORIZONTAL; - } - - private boolean isVertical() { - return orientation == ORIENTATION_VERTICAL; - } - - private ChildComponentContainer createChildContainer(Widget child) { - - // Create a container DIV for the child - ChildComponentContainer childComponent = new ChildComponentContainer( - child, orientation); - - return childComponent; - - } - - public RenderSpace getAllocatedSpace(Widget child) { - int width = 0; - int height = 0; - ChildComponentContainer childComponentContainer = getComponentContainer(child); - // WIDTH CALCULATION - if (isVertical()) { - width = activeLayoutSize.getWidth(); - width -= childComponentContainer.getCaptionWidthAfterComponent(); - } else if (!isDynamicWidth()) { - // HORIZONTAL - width = childComponentContainer.getContSize().getWidth(); - width -= childComponentContainer.getCaptionWidthAfterComponent(); - } - - // HEIGHT CALCULATION - if (isHorizontal()) { - height = activeLayoutSize.getHeight(); - height -= childComponentContainer.getCaptionHeightAboveComponent(); - } else if (!isDynamicHeight()) { - // VERTICAL - height = childComponentContainer.getContSize().getHeight(); - height -= childComponentContainer.getCaptionHeightAboveComponent(); - } - - // ApplicationConnection.getConsole().log( - // "allocatedSpace for " + Util.getSimpleName(child) + ": " - // + width + "," + height); - RenderSpace space = new RenderSpace(width, height); - return space; - } - - private void recalculateLayoutAndComponentSizes() { - recalculateLayout(); - - if (!(isDynamicHeight() && isDynamicWidth())) { - /* First update relative sized components */ - for (ChildComponentContainer componentContainer : widgetToComponentContainer - .values()) { - client.handleComponentRelativeSize(componentContainer - .getWidget()); - - // Update widget size from DOM - componentContainer.updateWidgetSize(); - } - } - - if (isDynamicHeight()) { - /* - * Height is not necessarily correct anymore as the height of - * components might have changed if the width has changed. - */ - - /* - * Get the new widget sizes from DOM and calculate new container - * sizes - */ - updateWidgetSizes(); - - /* Update layout dimensions based on widget sizes */ - recalculateLayout(); - } - - updateRelativeSizesInNonMainDirection(); - calculateAlignments(); - - setRootSize(); - } - - private void setRootSize() { - root.getStyle().setPropertyPx("width", activeLayoutSize.getWidth()); - root.getStyle().setPropertyPx("height", activeLayoutSize.getHeight()); - } - - public boolean requestLayout(Set<Paintable> children) { - for (Paintable p : children) { - /* Update widget size from DOM */ - ChildComponentContainer componentContainer = getComponentContainer((Widget) p); - // This should no longer be needed (after #2563) - // if (isDynamicWidth()) { - // componentContainer.setUnlimitedContainerWidth(); - // } else { - // componentContainer.setLimitedContainerWidth(activeLayoutSize - // .getWidth()); - // } - - componentContainer.updateWidgetSize(); - - /* - * If this is the result of an caption icon onload event the caption - * size may have changed - */ - componentContainer.updateCaptionSize(); - } - - Size sizeBefore = new Size(activeLayoutSize.getWidth(), - activeLayoutSize.getHeight()); - - recalculateLayoutAndComponentSizes(); - boolean sameSize = (sizeBefore.equals(activeLayoutSize)); - if (!sameSize) { - /* Must inform child components about possible size updates */ - client.runDescendentsLayout(this); - } - - /* Automatically propagated upwards if the size has changed */ - - return sameSize; - } - - @Override - public void setHeight(String height) { - Size sizeBefore = new Size(activeLayoutSize.getWidth(), - activeLayoutSize.getHeight()); - - super.setHeight(height); - - if (height != null && !height.equals("")) { - setActiveLayoutHeight(getOffsetHeight() - - activeMargins.getVertical()); - } - - if (isRendering) { - sizeHasChangedDuringRendering = true; - } else { - recalculateLayoutAndComponentSizes(); - boolean sameSize = (sizeBefore.equals(activeLayoutSize)); - if (!sameSize) { - /* Must inform child components about possible size updates */ - client.runDescendentsLayout(this); - } - } - } - - @Override - public void setWidth(String width) { - if (this.width.equals(width) || !isVisible()) { - return; - } - Size sizeBefore = new Size(activeLayoutSize.getWidth(), - activeLayoutSize.getHeight()); - - super.setWidth(width); - this.width = width; - if (width != null && !width.equals("")) { - setActiveLayoutWidth(getOffsetWidth() - - activeMargins.getHorizontal()); - } - - if (isRendering) { - sizeHasChangedDuringRendering = true; - } else { - recalculateLayoutAndComponentSizes(); - boolean sameSize = (sizeBefore.equals(activeLayoutSize)); - if (!sameSize) { - /* Must inform child components about possible size updates */ - client.runDescendentsLayout(this); - } - /* - * If the height changes as a consequence of this we must inform the - * parent also - */ - if (isDynamicHeight() - && sizeBefore.getHeight() != activeLayoutSize.getHeight()) { - Util.notifyParentOfSizeChange(this, false); - } - - } - } - - protected void updateAlignmentsAndExpandRatios(UIDL uidl, - ArrayList<Widget> renderedWidgets) { - - /* - */ - alignments = uidl.getMapAttribute("alignments"); - - /* - * UIDL contains a map of paintable ids to expand ratios - */ - - expandRatios = uidl.getMapAttribute("expandRatios"); - expandRatioSum = -1.0; - - for (int i = 0; i < renderedWidgets.size(); i++) { - Widget widget = renderedWidgets.get(i); - String pid = client.getPid(widget.getElement()); - - ChildComponentContainer container = getComponentContainer(widget); - - // Calculate alignment info - container.setAlignment(getAlignment(pid)); - - // Update expand ratio - container.setNormalizedExpandRatio(getExpandRatio(pid)); - } - } - - private AlignmentInfo getAlignment(String pid) { - if (alignments.containsKey(pid)) { - return new AlignmentInfo(alignments.getInt(pid)); - } else { - return AlignmentInfo.TOP_LEFT; - } - } - - private double getExpandRatio(String pid) { - if (expandRatioSum < 0) { - expandRatioSum = 0; - JsArrayString keyArray = expandRatios.getKeyArray(); - int length = keyArray.length(); - for (int i = 0; i < length; i++) { - expandRatioSum += expandRatios.getRawNumber(keyArray.get(i)); - } - if (expandRatioSum == 0) { - // by default split equally among components - defaultExpandRatio = 1.0 / widgetToComponentContainer.size(); - } else { - defaultExpandRatio = 0; - } - } - if (expandRatios.containsKey(pid)) { - return expandRatios.getRawNumber(pid) / expandRatioSum; - } else { - return defaultExpandRatio; - } - } - - public void updateCaption(Paintable component, UIDL uidl) { - ChildComponentContainer componentContainer = getComponentContainer((Widget) component); - componentContainer.updateCaption(uidl, client); - if (!isRendering) { - /* - * This was a component-only update and the possible size change - * must be propagated to the layout - */ - client.captionSizeUpdated(component); - } - } - - /** - * Returns the deepest nested child component which contains "element". The - * child component is also returned if "element" is part of its caption. - * - * @param element - * An element that is a nested sub element of the root element in - * this layout - * @return The Paintable which the element is a part of. Null if the element - * belongs to the layout and not to a child. - */ - private Paintable getComponent(Element element) { - return Util.getPaintableForElement(client, this, element); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java index 413f30ad06..df655ef959 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VOverlay.java @@ -15,7 +15,6 @@ import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.RootPanel; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Util; /** * In Vaadin UI this Overlay should always be used for all elements that @@ -28,7 +27,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { * The z-index value from where all overlays live. This can be overridden in * any extending class. */ - protected static int Z_INDEX = 20000; + public static int Z_INDEX = 20000; private static int leftFix = -1; @@ -162,32 +161,18 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { private static int adjustByRelativeTopBodyMargin() { if (topFix == -1) { - boolean ie6OrIe7 = BrowserInfo.get().isIE() - && BrowserInfo.get().getIEVersion() <= 7; - topFix = detectRelativeBodyFixes("top", ie6OrIe7); + topFix = detectRelativeBodyFixes("top"); } return topFix; } - private native static int detectRelativeBodyFixes(String axis, - boolean removeClientLeftOrTop) + private native static int detectRelativeBodyFixes(String axis) /*-{ try { var b = $wnd.document.body; var cstyle = b.currentStyle ? b.currentStyle : getComputedStyle(b); if(cstyle && cstyle.position == 'relative') { - var offset = b.getBoundingClientRect()[axis]; - if (removeClientLeftOrTop) { - // IE6 and IE7 include the top left border of the client area into the boundingClientRect - var clientTopOrLeft = 0; - if (axis == "top") - clientTopOrLeft = $wnd.document.documentElement.clientTop; - else - clientTopOrLeft = $wnd.document.documentElement.clientLeft; - - offset -= clientTopOrLeft; - } - return offset; + return b.getBoundingClientRect()[axis]; } } catch(e){} return 0; @@ -195,9 +180,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { private static int adjustByRelativeLeftBodyMargin() { if (leftFix == -1) { - boolean ie6OrIe7 = BrowserInfo.get().isIE() - && BrowserInfo.get().getIEVersion() <= 7; - leftFix = detectRelativeBodyFixes("left", ie6OrIe7); + leftFix = detectRelativeBodyFixes("left"); } return leftFix; @@ -214,13 +197,6 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { updateShadowSizeAndPosition(1.0); } } - Util.runIE7ZeroSizedBodyFix(); - } - - @Override - public void hide(boolean autoClosed) { - super.hide(autoClosed); - Util.runIE7ZeroSizedBodyFix(); } @Override @@ -273,7 +249,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { * size of overlay without using normal 'setWidth(String)' and * 'setHeight(String)' methods (if not calling super.setWidth/Height). */ - protected void updateShadowSizeAndPosition() { + public void updateShadowSizeAndPosition() { updateShadowSizeAndPosition(1.0); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java deleted file mode 100644 index 036f4f0600..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java +++ /dev/null @@ -1,609 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.Set; - -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.dom.client.TouchStartEvent; -import com.google.gwt.event.dom.client.TouchStartHandler; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -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.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; - -public class VPanel extends SimplePanel implements Container, - ShortcutActionHandlerOwner, Focusable { - - public static final String CLICK_EVENT_IDENTIFIER = "click"; - public static final String CLASSNAME = "v-panel"; - - ApplicationConnection client; - - String id; - - private final Element captionNode = DOM.createDiv(); - - private final Element captionText = DOM.createSpan(); - - private Icon icon; - - private final Element bottomDecoration = DOM.createDiv(); - - private final Element contentNode = DOM.createDiv(); - - private Element errorIndicatorElement; - - private String height; - - private Paintable layout; - - ShortcutActionHandler shortcutHandler; - - private String width = ""; - - private Element geckoCaptionMeter; - - private int scrollTop; - - private int scrollLeft; - - private RenderInformation renderInformation = new RenderInformation(); - - private int borderPaddingHorizontal = -1; - - private int borderPaddingVertical = -1; - - private int captionPaddingHorizontal = -1; - - private int captionMarginLeft = -1; - - private boolean rendering; - - private int contentMarginLeft = -1; - - private String previousStyleName; - - private ClickEventHandler clickEventHandler = new ClickEventHandler(this, - CLICK_EVENT_IDENTIFIER) { - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - private TouchScrollDelegate touchScrollDelegate; - - public VPanel() { - super(); - DivElement captionWrap = Document.get().createDivElement(); - captionWrap.appendChild(captionNode); - captionNode.appendChild(captionText); - - captionWrap.setClassName(CLASSNAME + "-captionwrap"); - captionNode.setClassName(CLASSNAME + "-caption"); - contentNode.setClassName(CLASSNAME + "-content"); - bottomDecoration.setClassName(CLASSNAME + "-deco"); - - getElement().appendChild(captionWrap); - - /* - * Make contentNode focusable only by using the setFocus() method. This - * behaviour can be changed by invoking setTabIndex() in the serverside - * implementation - */ - contentNode.setTabIndex(-1); - - getElement().appendChild(contentNode); - - getElement().appendChild(bottomDecoration); - setStyleName(CLASSNAME); - DOM.sinkEvents(getElement(), Event.ONKEYDOWN); - DOM.sinkEvents(contentNode, Event.ONSCROLL | Event.TOUCHEVENTS); - contentNode.getStyle().setProperty("position", "relative"); - getElement().getStyle().setProperty("overflow", "hidden"); - addHandler(new TouchStartHandler() { - public void onTouchStart(TouchStartEvent event) { - getTouchScrollDelegate().onTouchStart(event); - } - }, TouchStartEvent.getType()); - } - - /** - * Sets the keyboard focus on the Panel - * - * @param focus - * Should the panel have focus or not. - */ - public void setFocus(boolean focus) { - if (focus) { - getContainerElement().focus(); - } else { - getContainerElement().blur(); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.Focusable#focus() - */ - public void focus() { - setFocus(true); - - } - - @Override - protected Element getContainerElement() { - return contentNode; - } - - private void setCaption(String text) { - DOM.setInnerHTML(captionText, text); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - if (!uidl.hasAttribute("cached")) { - - // Handle caption displaying and style names, prior generics. - // Affects size - // calculations - - // Restore default stylenames - contentNode.setClassName(CLASSNAME + "-content"); - bottomDecoration.setClassName(CLASSNAME + "-deco"); - captionNode.setClassName(CLASSNAME + "-caption"); - boolean hasCaption = false; - if (uidl.hasAttribute("caption") - && !uidl.getStringAttribute("caption").equals("")) { - setCaption(uidl.getStringAttribute("caption")); - hasCaption = true; - } else { - setCaption(""); - captionNode.setClassName(CLASSNAME + "-nocaption"); - } - - // Add proper stylenames for all elements. This way we can prevent - // unwanted CSS selector inheritance. - if (uidl.hasAttribute("style")) { - final String[] styles = uidl.getStringAttribute("style").split( - " "); - final String captionBaseClass = CLASSNAME - + (hasCaption ? "-caption" : "-nocaption"); - final String contentBaseClass = CLASSNAME + "-content"; - final String decoBaseClass = CLASSNAME + "-deco"; - String captionClass = captionBaseClass; - String contentClass = contentBaseClass; - String decoClass = decoBaseClass; - for (int i = 0; i < styles.length; i++) { - captionClass += " " + captionBaseClass + "-" + styles[i]; - contentClass += " " + contentBaseClass + "-" + styles[i]; - decoClass += " " + decoBaseClass + "-" + styles[i]; - } - captionNode.setClassName(captionClass); - contentNode.setClassName(contentClass); - bottomDecoration.setClassName(decoClass); - - } - } - // Ensure correct implementation - if (client.updateComponent(this, uidl, false)) { - rendering = false; - return; - } - - clickEventHandler.handleEventHandlerRegistration(client); - - this.client = client; - id = uidl.getId(); - - setIconUri(uidl, client); - - handleError(uidl); - - // Render content - final UIDL layoutUidl = uidl.getChildUIDL(0); - final Paintable newLayout = client.getPaintable(layoutUidl); - if (newLayout != layout) { - if (layout != null) { - client.unregisterPaintable(layout); - } - setWidget((Widget) newLayout); - layout = newLayout; - } - layout.updateFromUIDL(layoutUidl, client); - - // We may have actions attached to this panel - if (uidl.getChildCount() > 1) { - final int cnt = uidl.getChildCount(); - for (int i = 1; i < cnt; i++) { - UIDL childUidl = uidl.getChildUIDL(i); - if (childUidl.getTag().equals("actions")) { - if (shortcutHandler == null) { - shortcutHandler = new ShortcutActionHandler(id, client); - } - shortcutHandler.updateActionMap(childUidl); - } - } - } - - if (uidl.hasVariable("scrollTop") - && uidl.getIntVariable("scrollTop") != scrollTop) { - scrollTop = uidl.getIntVariable("scrollTop"); - contentNode.setScrollTop(scrollTop); - // re-read the actual scrollTop in case invalid value was set - // (scrollTop != 0 when no scrollbar exists, other values would be - // caught by scroll listener), see #3784 - scrollTop = contentNode.getScrollTop(); - } - - if (uidl.hasVariable("scrollLeft") - && uidl.getIntVariable("scrollLeft") != scrollLeft) { - scrollLeft = uidl.getIntVariable("scrollLeft"); - contentNode.setScrollLeft(scrollLeft); - // re-read the actual scrollTop in case invalid value was set - // (scrollTop != 0 when no scrollbar exists, other values would be - // caught by scroll listener), see #3784 - scrollLeft = contentNode.getScrollLeft(); - } - - // Must be run after scrollTop is set as Webkit overflow fix re-sets the - // scrollTop - runHacks(false); - - // And apply tab index - if (uidl.hasVariable("tabindex")) { - contentNode.setTabIndex(uidl.getIntVariable("tabindex")); - } - - rendering = false; - - } - - @Override - public void setStyleName(String style) { - if (!style.equals(previousStyleName)) { - super.setStyleName(style); - detectContainerBorders(); - previousStyleName = style; - } - } - - private void handleError(UIDL uidl) { - if (uidl.hasAttribute("error")) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createSpan(); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS); - sinkEvents(Event.MOUSEEVENTS); - } - DOM.insertBefore(captionNode, errorIndicatorElement, captionText); - } else if (errorIndicatorElement != null) { - DOM.removeChild(captionNode, errorIndicatorElement); - errorIndicatorElement = null; - } - } - - private void setIconUri(UIDL uidl, ApplicationConnection client) { - final String iconUri = uidl.hasAttribute("icon") ? uidl - .getStringAttribute("icon") : null; - if (iconUri == null) { - if (icon != null) { - DOM.removeChild(captionNode, icon.getElement()); - icon = null; - } - } else { - if (icon == null) { - icon = new Icon(client); - DOM.insertChild(captionNode, icon.getElement(), 0); - } - icon.setUri(iconUri); - } - } - - public void runHacks(boolean runGeckoFix) { - if (BrowserInfo.get().isIE6() && width != null && !width.equals("")) { - /* - * IE6 requires overflow-hidden elements to have a width specified - * so we calculate the width of the content and caption nodes when - * no width has been specified. - */ - /* - * Fixes #1923 VPanel: Horizontal scrollbar does not appear in IE6 - * with wide content - */ - - /* - * Caption must be shrunk for parent measurements to return correct - * result in IE6 - */ - DOM.setStyleAttribute(captionNode, "width", "1px"); - - int parentPadding = Util.measureHorizontalPaddingAndBorder( - getElement(), 0); - - int parentWidthExcludingPadding = getElement().getOffsetWidth() - - parentPadding; - - Util.setWidthExcludingPaddingAndBorder(captionNode, - parentWidthExcludingPadding - getCaptionMarginLeft(), 26, - false); - - int contentMarginLeft = getContentMarginLeft(); - - Util.setWidthExcludingPaddingAndBorder(contentNode, - parentWidthExcludingPadding - contentMarginLeft, 2, false); - - } - - if ((BrowserInfo.get().isIE() || BrowserInfo.get().isFF2()) - && (width == null || width.equals(""))) { - /* - * IE and FF2 needs width to be specified for the root DIV so we - * calculate that from the sizes of the caption and layout - */ - int captionWidth = captionText.getOffsetWidth() - + getCaptionMarginLeft() + getCaptionPaddingHorizontal(); - int layoutWidth = ((Widget) layout).getOffsetWidth() - + getContainerBorderWidth(); - int width = layoutWidth; - if (captionWidth > width) { - width = captionWidth; - } - - if (BrowserInfo.get().isIE7()) { - Util.setWidthExcludingPaddingAndBorder(captionNode, width - - getCaptionMarginLeft(), 26, false); - } - - super.setWidth(width + "px"); - } - - if (runGeckoFix && BrowserInfo.get().isGecko()) { - // workaround for #1764 - if (width == null || width.equals("")) { - if (geckoCaptionMeter == null) { - geckoCaptionMeter = DOM.createDiv(); - DOM.appendChild(captionNode, geckoCaptionMeter); - } - int captionWidth = DOM.getElementPropertyInt(captionText, - "offsetWidth"); - int availWidth = DOM.getElementPropertyInt(geckoCaptionMeter, - "offsetWidth"); - if (captionWidth == availWidth) { - /* - * Caption width defines panel width -> Gecko based browsers - * somehow fails to float things right, without the - * "noncode" below - */ - setWidth(getOffsetWidth() + "px"); - } else { - DOM.setStyleAttribute(captionNode, "width", ""); - } - } - } - - client.runDescendentsLayout(this); - - Util.runWebkitOverflowAutoFix(contentNode); - - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - - final Element target = DOM.eventGetTarget(event); - final int type = DOM.eventGetType(event); - if (type == Event.ONKEYDOWN && shortcutHandler != null) { - shortcutHandler.handleKeyboardEvent(event); - return; - } - if (type == Event.ONSCROLL) { - int newscrollTop = DOM.getElementPropertyInt(contentNode, - "scrollTop"); - int newscrollLeft = DOM.getElementPropertyInt(contentNode, - "scrollLeft"); - if (client != null - && (newscrollLeft != scrollLeft || newscrollTop != scrollTop)) { - scrollLeft = newscrollLeft; - scrollTop = newscrollTop; - client.updateVariable(id, "scrollTop", scrollTop, false); - client.updateVariable(id, "scrollLeft", scrollLeft, false); - } - } else if (captionNode.isOrHasChild(target)) { - if (client != null) { - client.handleTooltipEvent(event, this); - } - } - } - - protected TouchScrollDelegate getTouchScrollDelegate() { - if (touchScrollDelegate == null) { - touchScrollDelegate = new TouchScrollDelegate(contentNode); - } - return touchScrollDelegate; - - } - - @Override - public void setHeight(String height) { - this.height = height; - super.setHeight(height); - if (height != null && !"".equals(height)) { - final int targetHeight = getOffsetHeight(); - int containerHeight = targetHeight - - captionNode.getParentElement().getOffsetHeight() - - bottomDecoration.getOffsetHeight() - - getContainerBorderHeight(); - if (containerHeight < 0) { - containerHeight = 0; - } - DOM.setStyleAttribute(contentNode, "height", containerHeight + "px"); - } else { - DOM.setStyleAttribute(contentNode, "height", ""); - } - if (!rendering) { - runHacks(true); - } - } - - private int getCaptionMarginLeft() { - if (captionMarginLeft < 0) { - detectContainerBorders(); - } - return captionMarginLeft; - } - - private int getContentMarginLeft() { - if (contentMarginLeft < 0) { - detectContainerBorders(); - } - return contentMarginLeft; - } - - private int getCaptionPaddingHorizontal() { - if (captionPaddingHorizontal < 0) { - detectContainerBorders(); - } - return captionPaddingHorizontal; - } - - private int getContainerBorderHeight() { - if (borderPaddingVertical < 0) { - detectContainerBorders(); - } - return borderPaddingVertical; - } - - @Override - public void setWidth(String width) { - if (this.width.equals(width)) { - return; - } - - this.width = width; - super.setWidth(width); - if (!rendering) { - runHacks(true); - - if (height.equals("")) { - // Width change may affect height - Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this); - } - - } - } - - private int getContainerBorderWidth() { - if (borderPaddingHorizontal < 0) { - detectContainerBorders(); - } - return borderPaddingHorizontal; - } - - private void detectContainerBorders() { - DOM.setStyleAttribute(contentNode, "overflow", "hidden"); - - borderPaddingHorizontal = Util.measureHorizontalBorder(contentNode); - borderPaddingVertical = Util.measureVerticalBorder(contentNode); - - DOM.setStyleAttribute(contentNode, "overflow", "auto"); - - captionPaddingHorizontal = Util.measureHorizontalPaddingAndBorder( - captionNode, 26); - - captionMarginLeft = Util.measureMarginLeft(captionNode); - contentMarginLeft = Util.measureMarginLeft(contentNode); - - } - - public boolean hasChildComponent(Widget component) { - if (component != null && component == layout) { - return true; - } else { - return false; - } - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - // TODO This is untested as no layouts require this - if (oldComponent != layout) { - return; - } - - setWidget(newComponent); - layout = (Paintable) newComponent; - } - - public RenderSpace getAllocatedSpace(Widget child) { - int w = 0; - int h = 0; - - if (width != null && !width.equals("")) { - w = getOffsetWidth() - getContainerBorderWidth(); - if (w < 0) { - w = 0; - } - } - - if (height != null && !height.equals("")) { - h = contentNode.getOffsetHeight() - getContainerBorderHeight(); - if (h < 0) { - h = 0; - } - } - - return new RenderSpace(w, h, true); - } - - public boolean requestLayout(Set<Paintable> child) { - // content size change might cause change to its available space - // (scrollbars) - client.handleComponentRelativeSize((Widget) layout); - if (height != null && height != "" && width != null && width != "") { - /* - * If the height and width has been specified the child components - * cannot make the size of the layout change - */ - return true; - } - runHacks(false); - return !renderInformation.updateSize(getElement()); - } - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP: layouts caption, errors etc not rendered in Panel - } - - @Override - protected void onAttach() { - super.onAttach(); - detectContainerBorders(); - } - - public ShortcutActionHandler getShortcutActionHandler() { - return shortcutHandler; - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java deleted file mode 100644 index ff1e2e6b78..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java +++ /dev/null @@ -1,12 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -public class VSplitPanelHorizontal extends VSplitPanel { - - public VSplitPanelHorizontal() { - super(VSplitPanel.ORIENTATION_HORIZONTAL); - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java deleted file mode 100644 index dcf7622e50..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java +++ /dev/null @@ -1,12 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -public class VSplitPanelVertical extends VSplitPanel { - - public VSplitPanelVertical() { - super(VSplitPanel.ORIENTATION_VERTICAL); - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java b/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java deleted file mode 100644 index d3cb3130b0..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java +++ /dev/null @@ -1,446 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; - -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.Grid; -import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.HorizontalPanel; -import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.VerticalPanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; - -/** - * TODO make this work (just an early prototype). We may want to have paging - * style table which will be much lighter than VScrollTable is. - */ -public class VTablePaging extends Composite implements Table, Paintable, - ClickHandler { - - private final Grid tBody = new Grid(); - private final Button nextPage = new Button(">"); - private final Button prevPage = new Button("<"); - private final Button firstPage = new Button("<<"); - private final Button lastPage = new Button(">>"); - - private int pageLength = 15; - - private boolean rowHeaders = false; - - private ApplicationConnection client; - private String id; - - private boolean immediate = false; - - private int selectMode = Table.SELECT_MODE_NONE; - - private final ArrayList<String> selectedRowKeys = new ArrayList<String>(); - - private int totalRows; - - private final HashMap<?, ?> visibleColumns = new HashMap<Object, Object>(); - - private int rows; - - private int firstRow; - private boolean sortAscending = true; - private final HorizontalPanel pager; - - public HashMap<String, TableRow> rowKeysToTableRows = new HashMap<String, TableRow>(); - - public VTablePaging() { - - tBody.setStyleName("itable-tbody"); - - final VerticalPanel panel = new VerticalPanel(); - - pager = new HorizontalPanel(); - pager.add(firstPage); - firstPage.addClickHandler(this); - pager.add(prevPage); - prevPage.addClickHandler(this); - pager.add(nextPage); - nextPage.addClickHandler(this); - pager.add(lastPage); - lastPage.addClickHandler(this); - - panel.add(pager); - panel.add(tBody); - - initWidget(panel); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { - return; - } - - this.client = client; - id = uidl.getStringAttribute("id"); - immediate = uidl.getBooleanAttribute("immediate"); - totalRows = uidl.getIntAttribute("totalrows"); - pageLength = uidl.getIntAttribute("pagelength"); - firstRow = uidl.getIntAttribute("firstrow"); - rows = uidl.getIntAttribute("rows"); - - if (uidl.hasAttribute("selectmode")) { - if (uidl.getStringAttribute("selectmode").equals("multi")) { - selectMode = Table.SELECT_MODE_MULTI; - } else { - selectMode = Table.SELECT_MODE_SINGLE; - } - - if (uidl.hasAttribute("selected")) { - final Set<String> selectedKeys = uidl - .getStringArrayVariableAsSet("selected"); - selectedRowKeys.clear(); - for (final Iterator<String> it = selectedKeys.iterator(); it - .hasNext();) { - selectedRowKeys.add(it.next()); - } - } - } - - if (uidl.hasVariable("sortascending")) { - sortAscending = uidl.getBooleanVariable("sortascending"); - } - - if (uidl.hasAttribute("rowheaders")) { - rowHeaders = true; - } - - UIDL rowData = null; - UIDL visibleColumns = null; - for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext();) { - final UIDL c = (UIDL) it.next(); - if (c.getTag().equals("rows")) { - rowData = c; - } else if (c.getTag().equals("actions")) { - updateActionMap(c); - } else if (c.getTag().equals("visiblecolumns")) { - visibleColumns = c; - } - } - tBody.resize(rows + 1, uidl.getIntAttribute("cols") - + (rowHeaders ? 1 : 0)); - updateHeader(visibleColumns); - updateBody(rowData); - - updatePager(); - } - - private void updateHeader(UIDL c) { - final Iterator<?> it = c.getChildIterator(); - visibleColumns.clear(); - int colIndex = (rowHeaders ? 1 : 0); - while (it.hasNext()) { - final UIDL col = (UIDL) it.next(); - final String cid = col.getStringAttribute("cid"); - if (!col.hasAttribute("collapsed")) { - tBody.setWidget(0, colIndex, - new HeaderCell(cid, col.getStringAttribute("caption"))); - - } - colIndex++; - } - } - - private void updateActionMap(UIDL c) { - // TODO Auto-generated method stub - - } - - /** - * Updates row data from uidl. UpdateFromUIDL delegates updating tBody to - * this method. - * - * Updates may be to different part of tBody, depending on update type. It - * can be initial row data, scroll up, scroll down... - * - * @param uidl - * which contains row data - */ - private void updateBody(UIDL uidl) { - final Iterator<?> it = uidl.getChildIterator(); - - int curRowIndex = 1; - while (it.hasNext()) { - final UIDL rowUidl = (UIDL) it.next(); - final TableRow row = new TableRow(curRowIndex, - String.valueOf(rowUidl.getIntAttribute("key")), - rowUidl.hasAttribute("selected")); - int colIndex = 0; - if (rowHeaders) { - tBody.setWidget(curRowIndex, colIndex, new BodyCell(row, - rowUidl.getStringAttribute("caption"))); - colIndex++; - } - final Iterator<?> cells = rowUidl.getChildIterator(); - while (cells.hasNext()) { - final Object cell = cells.next(); - if (cell instanceof String) { - tBody.setWidget(curRowIndex, colIndex, new BodyCell(row, - (String) cell)); - } else { - final Paintable cellContent = client - .getPaintable((UIDL) cell); - final BodyCell bodyCell = new BodyCell(row); - bodyCell.setWidget((Widget) cellContent); - tBody.setWidget(curRowIndex, colIndex, bodyCell); - } - colIndex++; - } - curRowIndex++; - } - } - - private void updatePager() { - if (pageLength == 0) { - pager.setVisible(false); - return; - } - if (isFirstPage()) { - firstPage.setEnabled(false); - prevPage.setEnabled(false); - } else { - firstPage.setEnabled(true); - prevPage.setEnabled(true); - } - if (hasNextPage()) { - nextPage.setEnabled(true); - lastPage.setEnabled(true); - } else { - nextPage.setEnabled(false); - lastPage.setEnabled(false); - - } - } - - private boolean hasNextPage() { - if (firstRow + rows + 1 > totalRows) { - return false; - } - return true; - } - - private boolean isFirstPage() { - if (firstRow == 0) { - return true; - } - return false; - } - - public void onClick(ClickEvent event) { - Object sender = event.getSource(); - if (sender instanceof Button) { - if (sender == firstPage) { - client.updateVariable(id, "firstvisible", 0, true); - } else if (sender == nextPage) { - client.updateVariable(id, "firstvisible", - firstRow + pageLength, true); - } else if (sender == prevPage) { - int newFirst = firstRow - pageLength; - if (newFirst < 0) { - newFirst = 0; - } - client.updateVariable(id, "firstvisible", newFirst, true); - } else if (sender == lastPage) { - client.updateVariable(id, "firstvisible", totalRows - - pageLength, true); - } - } - if (sender instanceof HeaderCell) { - final HeaderCell hCell = (HeaderCell) sender; - client.updateVariable(id, "sortcolumn", hCell.getCid(), false); - client.updateVariable(id, "sortascending", (sortAscending ? false - : true), true); - } - } - - private class HeaderCell extends HTML { - - private String cid; - - public String getCid() { - return cid; - } - - public void setCid(String pid) { - cid = pid; - } - - HeaderCell(String pid, String caption) { - super(); - cid = pid; - addClickHandler(VTablePaging.this); - setText(caption); - // TODO remove debug color - DOM.setStyleAttribute(getElement(), "color", "brown"); - DOM.setStyleAttribute(getElement(), "font-weight", "bold"); - } - } - - /** - * Abstraction of table cell content. In needs to know on which row it is in - * case of context click. - * - * @author mattitahvonen - */ - public class BodyCell extends SimplePanel { - private final TableRow row; - - public BodyCell(TableRow row) { - super(); - sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT); - this.row = row; - } - - public BodyCell(TableRow row2, String textContent) { - super(); - sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT); - row = row2; - setWidget(new Label(textContent)); - } - - @Override - public void onBrowserEvent(Event event) { - System.out.println("CEll event: " + event.toString()); - switch (DOM.eventGetType(event)) { - case Event.BUTTON_RIGHT: - row.showContextMenu(event); - Window.alert("context menu un-implemented"); - DOM.eventCancelBubble(event, true); - break; - case Event.BUTTON_LEFT: - if (selectMode > Table.SELECT_MODE_NONE) { - row.toggleSelected(); - } - break; - default: - break; - } - super.onBrowserEvent(event); - } - } - - private class TableRow { - - private final String key; - private final int rowIndex; - private boolean selected = false; - - public TableRow(int rowIndex, String rowKey, boolean selected) { - rowKeysToTableRows.put(rowKey, this); - this.rowIndex = rowIndex; - key = rowKey; - setSelected(selected); - } - - /** - * This method is used to set row status. Does not change value on - * server. - * - * @param selected - */ - public void setSelected(boolean sel) { - selected = sel; - if (selected) { - selectedRowKeys.add(key); - DOM.setStyleAttribute( - tBody.getRowFormatter().getElement(rowIndex), - "background", "yellow"); - - } else { - selectedRowKeys.remove(key); - DOM.setStyleAttribute( - tBody.getRowFormatter().getElement(rowIndex), - "background", "transparent"); - } - } - - public void setContextMenuOptions(HashMap<?, ?> options) { - - } - - /** - * Toggles rows select state. Also updates state to server according to - * tables immediate flag. - * - */ - public void toggleSelected() { - if (selected) { - setSelected(false); - } else { - if (selectMode == Table.SELECT_MODE_SINGLE) { - deselectAll(); - } - setSelected(true); - } - client.updateVariable( - id, - "selected", - selectedRowKeys.toArray(new String[selectedRowKeys.size()]), - immediate); - } - - /** - * Shows context menu for this row. - * - * @param event - * Event which triggered context menu. Correct place for - * context menu can be determined with it. - */ - public void showContextMenu(Event event) { - System.out.println("TODO: Show context menu"); - } - } - - public void deselectAll() { - final Object[] keys = selectedRowKeys.toArray(); - for (int i = 0; i < keys.length; i++) { - final TableRow tableRow = rowKeysToTableRows.get(keys[i]); - if (tableRow != null) { - tableRow.setSelected(false); - } - } - // still ensure all selects are removed from - selectedRowKeys.clear(); - } - - public void add(Widget w) { - // TODO Auto-generated method stub - - } - - public void clear() { - // TODO Auto-generated method stub - - } - - public Iterator<Widget> iterator() { - // TODO Auto-generated method stub - return null; - } - - public boolean remove(Widget w) { - // TODO Auto-generated method stub - return false; - } -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java deleted file mode 100644 index 7304f62f41..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java +++ /dev/null @@ -1,153 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.ui.ComplexPanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; - -abstract class VTabsheetBase extends ComplexPanel implements Container { - - String id; - ApplicationConnection client; - - protected final ArrayList<String> tabKeys = new ArrayList<String>(); - protected int activeTabIndex = 0; - protected boolean disabled; - protected boolean readonly; - protected Set<String> disabledTabKeys = new HashSet<String>(); - protected boolean cachedUpdate = false; - - public VTabsheetBase(String classname) { - setElement(DOM.createDiv()); - setStyleName(classname); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - - // Ensure correct implementation - cachedUpdate = client.updateComponent(this, uidl, true); - if (cachedUpdate) { - return; - } - - // Update member references - id = uidl.getId(); - disabled = uidl.hasAttribute("disabled"); - - // Render content - final UIDL tabs = uidl.getChildUIDL(0); - - // Paintables in the TabSheet before update - ArrayList<Object> oldPaintables = new ArrayList<Object>(); - for (Iterator<Object> iterator = getPaintableIterator(); iterator - .hasNext();) { - oldPaintables.add(iterator.next()); - } - - // Clear previous values - tabKeys.clear(); - disabledTabKeys.clear(); - - int index = 0; - for (final Iterator<Object> it = tabs.getChildIterator(); it.hasNext();) { - final UIDL tab = (UIDL) it.next(); - final String key = tab.getStringAttribute("key"); - final boolean selected = tab.getBooleanAttribute("selected"); - final boolean hidden = tab.getBooleanAttribute("hidden"); - - if (tab.getBooleanAttribute("disabled")) { - disabledTabKeys.add(key); - } - - tabKeys.add(key); - - if (selected) { - activeTabIndex = index; - } - renderTab(tab, index, selected, hidden); - index++; - } - - int tabCount = getTabCount(); - while (tabCount-- > index) { - removeTab(index); - } - - for (int i = 0; i < getTabCount(); i++) { - Paintable p = getTab(i); - oldPaintables.remove(p); - } - - // Perform unregister for any paintables removed during update - for (Iterator<Object> iterator = oldPaintables.iterator(); iterator - .hasNext();) { - Object oldPaintable = iterator.next(); - if (oldPaintable instanceof Paintable) { - Widget w = (Widget) oldPaintable; - if (w.isAttached()) { - w.removeFromParent(); - } - client.unregisterPaintable((Paintable) oldPaintable); - } - } - - } - - /** - * @return a list of currently shown Paintables - * - * Apparently can be something else than Paintable as - * {@link #updateFromUIDL(UIDL, ApplicationConnection)} checks if - * instanceof Paintable. Therefore set to <Object> - */ - abstract protected Iterator<Object> getPaintableIterator(); - - /** - * Clears current tabs and contents - */ - abstract protected void clearPaintables(); - - /** - * Implement in extending classes. This method should render needed elements - * and set the visibility of the tab according to the 'selected' parameter. - */ - protected abstract void renderTab(final UIDL tabUidl, int index, - boolean selected, boolean hidden); - - /** - * Implement in extending classes. This method should render any previously - * non-cached content and set the activeTabIndex property to the specified - * index. - */ - protected abstract void selectTab(int index, final UIDL contentUidl); - - /** - * Implement in extending classes. This method should return the number of - * tabs currently rendered. - */ - protected abstract int getTabCount(); - - /** - * Implement in extending classes. This method should return the Paintable - * corresponding to the given index. - */ - protected abstract Paintable getTab(int index); - - /** - * Implement in extending classes. This method should remove the rendered - * tab with the specified index. - */ - protected abstract void removeTab(int index); -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java index c7442e4436..7bcdcec660 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java @@ -6,18 +6,13 @@ package com.vaadin.terminal.gwt.client.ui; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.VerticalPanel; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.SimpleTree; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.VUIDLBrowser; -public class VUnknownComponent extends Composite implements Paintable { +public class VUnknownComponent extends Composite { com.google.gwt.user.client.ui.Label caption = new com.google.gwt.user.client.ui.Label();; SimpleTree uidlTree; - private VerticalPanel panel; - private String serverClassName = "unkwnown"; + protected VerticalPanel panel; public VUnknownComponent() { panel = new VerticalPanel(); @@ -27,32 +22,6 @@ public class VUnknownComponent extends Composite implements Paintable { caption.setStyleName("vaadin-unknown-caption"); } - public void setServerSideClassName(String serverClassName) { - this.serverClassName = serverClassName; - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, false)) { - return; - } - setCaption("Widgetset does not contain implementation for " - + serverClassName - + ". Check its @ClientWidget mapping, widgetsets " - + "GWT module description file and re-compile your" - + " widgetset. In case you have downloaded a vaadin" - + " add-on package, you might want to refer to " - + "<a href='http://vaadin.com/using-addons'>add-on " - + "instructions</a>. Unrendered UIDL:"); - if (uidlTree != null) { - uidlTree.removeFromParent(); - } - - uidlTree = new VUIDLBrowser(uidl, client.getConfiguration()); - uidlTree.open(true); - uidlTree.setText("Unrendered UIDL"); - panel.add(uidlTree); - } - public void setCaption(String c) { caption.getElement().setInnerHTML(c); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java b/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java deleted file mode 100644 index db01699383..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java +++ /dev/null @@ -1,85 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.dom.client.Document; -import com.google.gwt.event.logical.shared.ValueChangeEvent; -import com.google.gwt.event.logical.shared.ValueChangeHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.History; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; - -/** - * Client side implementation for UriFragmentUtility. Uses GWT's History object - * as an implementation. - * - */ -public class VUriFragmentUtility extends Widget implements Paintable, - ValueChangeHandler<String> { - - private String fragment; - private ApplicationConnection client; - private String paintableId; - private boolean immediate; - private HandlerRegistration historyValueHandlerRegistration; - - public VUriFragmentUtility() { - setElement(Document.get().createDivElement()); - if (BrowserInfo.get().isIE6()) { - getElement().getStyle().setProperty("overflow", "hidden"); - getElement().getStyle().setProperty("height", "0"); - } - } - - @Override - protected void onAttach() { - super.onAttach(); - historyValueHandlerRegistration = History.addValueChangeHandler(this); - History.fireCurrentHistoryState(); - } - - @Override - protected void onDetach() { - super.onDetach(); - historyValueHandlerRegistration.removeHandler(); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, false)) { - return; - } - String uidlFragment = uidl.getStringVariable("fragment"); - immediate = uidl.getBooleanAttribute("immediate"); - if (this.client == null) { - // initial paint has some special logic - this.client = client; - paintableId = uidl.getId(); - if (!fragment.equals(uidlFragment)) { - // initial server side fragment (from link/bookmark/typed) does - // not equal the one on - // server, send initial fragment to server - History.fireCurrentHistoryState(); - } - } else { - if (uidlFragment != null && !uidlFragment.equals(fragment)) { - fragment = uidlFragment; - // normal fragment change from server, add new history item - History.newItem(uidlFragment, false); - } - } - } - - public void onValueChange(ValueChangeEvent<String> event) { - String historyToken = event.getValue(); - fragment = historyToken; - if (client != null) { - client.updateVariable(paintableId, "fragment", fragment, immediate); - } - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayout.java deleted file mode 100644 index fe5749ec8b..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayout.java +++ /dev/null @@ -1,14 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui; - -public class VVerticalLayout extends VOrderedLayout { - - public static final String CLASSNAME = "v-verticallayout"; - - public VVerticalLayout() { - super(CLASSNAME, ORIENTATION_VERTICAL); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java deleted file mode 100644 index 07ade6a8b1..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/VView.java +++ /dev/null @@ -1,779 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.client.ui; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Style; -import com.google.gwt.dom.client.Style.Display; -import com.google.gwt.event.dom.client.DomEvent.Type; -import com.google.gwt.event.logical.shared.ResizeEvent; -import com.google.gwt.event.logical.shared.ResizeHandler; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.RootPanel; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; - -/** - * - */ -public class VView extends SimplePanel implements Container, ResizeHandler, - Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable { - - private static final String CLASSNAME = "v-view"; - - public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain"; - - private String theme; - - private Paintable layout; - - private final LinkedHashSet<VWindow> subWindows = new LinkedHashSet<VWindow>(); - - private String id; - - private ShortcutActionHandler actionHandler; - - /** stored width for IE resize optimization */ - private int width; - - /** stored height for IE resize optimization */ - private int height; - - private ApplicationConnection connection; - - /** - * We are postponing resize process with IE. IE bugs with scrollbars in some - * situations, that causes false onWindowResized calls. With Timer we will - * give IE some time to decide if it really wants to keep current size - * (scrollbars). - */ - private Timer resizeTimer; - - private int scrollTop; - - private int scrollLeft; - - private boolean rendering; - - private boolean scrollable; - - private boolean immediate; - - private boolean resizeLazy = false; - - public static final String RESIZE_LAZY = "rL"; - /** - * Reference to the parent frame/iframe. Null if there is no parent (i)frame - * or if the application and parent frame are in different domains. - */ - private Element parentFrame; - - private ClickEventHandler clickEventHandler = new ClickEventHandler(this, - VPanel.CLICK_EVENT_IDENTIFIER) { - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - - private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200, - new ScheduledCommand() { - public void execute() { - windowSizeMaybeChanged(Window.getClientWidth(), - Window.getClientHeight()); - } - - }); - - public VView() { - super(); - setStyleName(CLASSNAME); - - // Allow focusing the view by using the focus() method, the view - // should not be in the document focus flow - getElement().setTabIndex(-1); - } - - /** - * Called when the window might have been resized. - * - * @param newWidth - * The new width of the window - * @param newHeight - * The new height of the window - */ - protected void windowSizeMaybeChanged(int newWidth, int newHeight) { - boolean changed = false; - if (width != newWidth) { - width = newWidth; - changed = true; - VConsole.log("New window width: " + width); - } - if (height != newHeight) { - height = newHeight; - changed = true; - VConsole.log("New window height: " + height); - } - if (changed) { - VConsole.log("Running layout functions due to window resize"); - connection.runDescendentsLayout(VView.this); - Util.runWebkitOverflowAutoFix(getElement()); - - sendClientResized(); - } - } - - public String getTheme() { - return theme; - } - - /** - * Used to reload host page on theme changes. - */ - private static native void reloadHostPage() - /*-{ - $wnd.location.reload(); - }-*/; - - /** - * Evaluate the given script in the browser document. - * - * @param script - * Script to be executed. - */ - private static native void eval(String script) - /*-{ - try { - if (script == null) return; - $wnd.eval(script); - } catch (e) { - } - }-*/; - - /** - * Returns true if the body is NOT generated, i.e if someone else has made - * the page that we're running in. Otherwise we're in charge of the whole - * page. - * - * @return true if we're running embedded - */ - public boolean isEmbedded() { - return !getElement().getOwnerDocument().getBody().getClassName() - .contains(ApplicationConnection.GENERATED_BODY_CLASSNAME); - } - - public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) { - rendering = true; - - id = uidl.getId(); - boolean firstPaint = connection == null; - connection = client; - - immediate = uidl.hasAttribute("immediate"); - resizeLazy = uidl.hasAttribute(RESIZE_LAZY); - String newTheme = uidl.getStringAttribute("theme"); - if (theme != null && !newTheme.equals(theme)) { - // Complete page refresh is needed due css can affect layout - // calculations etc - reloadHostPage(); - } else { - theme = newTheme; - } - if (uidl.hasAttribute("style")) { - setStyleName(getStylePrimaryName() + " " - + uidl.getStringAttribute("style")); - } - - if (uidl.hasAttribute("name")) { - client.setWindowName(uidl.getStringAttribute("name")); - } - - clickEventHandler.handleEventHandlerRegistration(client); - - if (!isEmbedded()) { - // only change window title if we're in charge of the whole page - com.google.gwt.user.client.Window.setTitle(uidl - .getStringAttribute("caption")); - } - - // Process children - int childIndex = 0; - - // Open URL:s - boolean isClosed = false; // was this window closed? - while (childIndex < uidl.getChildCount() - && "open".equals(uidl.getChildUIDL(childIndex).getTag())) { - final UIDL open = uidl.getChildUIDL(childIndex); - final String url = client.translateVaadinUri(open - .getStringAttribute("src")); - final String target = open.getStringAttribute("name"); - if (target == null) { - // source will be opened to this browser window, but we may have - // to finish rendering this window in case this is a download - // (and window stays open). - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - goTo(url); - } - }); - } else if ("_self".equals(target)) { - // This window is closing (for sure). Only other opens are - // relevant in this change. See #3558, #2144 - isClosed = true; - goTo(url); - } else { - String options; - if (open.hasAttribute("border")) { - if (open.getStringAttribute("border").equals("minimal")) { - options = "menubar=yes,location=no,status=no"; - } else { - options = "menubar=no,location=no,status=no"; - } - - } else { - options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes"; - } - - if (open.hasAttribute("width")) { - int w = open.getIntAttribute("width"); - options += ",width=" + w; - } - if (open.hasAttribute("height")) { - int h = open.getIntAttribute("height"); - options += ",height=" + h; - } - - Window.open(url, target, options); - } - childIndex++; - } - if (isClosed) { - // don't render the content, something else will be opened to this - // browser view - rendering = false; - return; - } - - // Draw this application level window - UIDL childUidl = uidl.getChildUIDL(childIndex); - final Paintable lo = client.getPaintable(childUidl); - - if (layout != null) { - if (layout != lo) { - // remove old - client.unregisterPaintable(layout); - // add new - setWidget((Widget) lo); - layout = lo; - } - } else { - setWidget((Widget) lo); - layout = lo; - } - - layout.updateFromUIDL(childUidl, client); - if (!childUidl.getBooleanAttribute("cached")) { - updateParentFrameSize(); - } - - // Save currently open subwindows to track which will need to be closed - final HashSet<VWindow> removedSubWindows = new HashSet<VWindow>( - subWindows); - - // Handle other UIDL children - while ((childUidl = uidl.getChildUIDL(++childIndex)) != null) { - String tag = childUidl.getTag().intern(); - if (tag == "actions") { - if (actionHandler == null) { - actionHandler = new ShortcutActionHandler(id, client); - } - actionHandler.updateActionMap(childUidl); - } else if (tag == "execJS") { - String script = childUidl.getStringAttribute("script"); - eval(script); - } else if (tag == "notifications") { - for (final Iterator<?> it = childUidl.getChildIterator(); it - .hasNext();) { - final UIDL notification = (UIDL) it.next(); - VNotification.showNotification(client, notification); - } - } else { - // subwindows - final Paintable w = client.getPaintable(childUidl); - if (subWindows.contains(w)) { - removedSubWindows.remove(w); - } else { - subWindows.add((VWindow) w); - } - w.updateFromUIDL(childUidl, client); - } - } - - // Close old windows which where not in UIDL anymore - for (final Iterator<VWindow> rem = removedSubWindows.iterator(); rem - .hasNext();) { - final VWindow w = rem.next(); - client.unregisterPaintable(w); - subWindows.remove(w); - w.hide(); - } - - if (uidl.hasAttribute("focused")) { - // set focused component when render phase is finished - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - final Paintable toBeFocused = uidl.getPaintableAttribute( - "focused", connection); - - /* - * Two types of Widgets can be focused, either implementing - * GWT HasFocus of a thinner Vaadin specific Focusable - * interface. - */ - if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) { - final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused; - toBeFocusedWidget.setFocus(true); - } else if (toBeFocused instanceof Focusable) { - ((Focusable) toBeFocused).focus(); - } else { - VConsole.log("Could not focus component"); - } - } - }); - } - - // Add window listeners on first paint, to prevent premature - // variablechanges - if (firstPaint) { - Window.addWindowClosingHandler(this); - Window.addResizeHandler(this); - } - - onResize(); - - // finally set scroll position from UIDL - if (uidl.hasVariable("scrollTop")) { - scrollable = true; - scrollTop = uidl.getIntVariable("scrollTop"); - DOM.setElementPropertyInt(getElement(), "scrollTop", scrollTop); - scrollLeft = uidl.getIntVariable("scrollLeft"); - DOM.setElementPropertyInt(getElement(), "scrollLeft", scrollLeft); - } else { - scrollable = false; - } - - // Safari workaround must be run after scrollTop is updated as it sets - // scrollTop using a deferred command. - if (BrowserInfo.get().isSafari()) { - Util.runWebkitOverflowAutoFix(getElement()); - } - - scrollIntoView(uidl); - - rendering = false; - } - - /** - * Tries to scroll paintable referenced from given UIDL snippet to be - * visible. - * - * @param uidl - */ - void scrollIntoView(final UIDL uidl) { - if (uidl.hasAttribute("scrollTo")) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - final Paintable paintable = uidl.getPaintableAttribute( - "scrollTo", connection); - ((Widget) paintable).getElement().scrollIntoView(); - } - }); - } - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - int type = DOM.eventGetType(event); - if (type == Event.ONKEYDOWN && actionHandler != null) { - actionHandler.handleKeyboardEvent(event); - return; - } else if (scrollable && type == Event.ONSCROLL) { - updateScrollPosition(); - } - } - - /** - * Updates scroll position from DOM and saves variables to server. - */ - private void updateScrollPosition() { - int oldTop = scrollTop; - int oldLeft = scrollLeft; - scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop"); - scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft"); - if (connection != null && !rendering) { - if (oldTop != scrollTop) { - connection.updateVariable(id, "scrollTop", scrollTop, false); - } - if (oldLeft != scrollLeft) { - connection.updateVariable(id, "scrollLeft", scrollLeft, false); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google - * .gwt.event.logical.shared.ResizeEvent) - */ - public void onResize(ResizeEvent event) { - onResize(); - } - - /** - * Called when a resize event is received. - */ - private void onResize() { - /* - * IE (pre IE9 at least) will give us some false resize events due to - * problems with scrollbars. Firefox 3 might also produce some extra - * events. We postpone both the re-layouting and the server side event - * for a while to deal with these issues. - * - * We may also postpone these events to avoid slowness when resizing the - * browser window. Constantly recalculating the layout causes the resize - * operation to be really slow with complex layouts. - */ - boolean lazy = resizeLazy - || (BrowserInfo.get().isIE() && BrowserInfo.get() - .getIEVersion() <= 8) || BrowserInfo.get().isFF3(); - - if (lazy) { - delayedResizeExecutor.trigger(); - } else { - windowSizeMaybeChanged(Window.getClientWidth(), - Window.getClientHeight()); - } - } - - /** - * Send new dimensions to the server. - */ - private void sendClientResized() { - connection.updateVariable(id, "height", height, false); - connection.updateVariable(id, "width", width, immediate); - } - - public native static void goTo(String url) - /*-{ - $wnd.location = url; - }-*/; - - public void onWindowClosing(Window.ClosingEvent event) { - // Change focus on this window in order to ensure that all state is - // collected from textfields - // TODO this is a naive hack, that only works with text fields and may - // cause some odd issues. Should be replaced with a decent solution, see - // also related BeforeShortcutActionListener interface. Same interface - // might be usable here. - VTextField.flushChangesFromFocusedTextField(); - - // Send the closing state to server - connection.updateVariable(id, "close", true, false); - connection.sendPendingVariableChangesSync(); - } - - private final RenderSpace myRenderSpace = new RenderSpace() { - private int excessHeight = -1; - private int excessWidth = -1; - - @Override - public int getHeight() { - return getElement().getOffsetHeight() - getExcessHeight(); - } - - private int getExcessHeight() { - if (excessHeight < 0) { - detectExcessSize(); - } - return excessHeight; - } - - private void detectExcessSize() { - // TODO define that iview cannot be themed and decorations should - // get to parent element, then get rid of this expensive and error - // prone function - final String overflow = getElement().getStyle().getProperty( - "overflow"); - getElement().getStyle().setProperty("overflow", "hidden"); - if (BrowserInfo.get().isIE() - && getElement().getPropertyInt("clientWidth") == 0) { - // can't detect possibly themed border/padding width in some - // situations (with some layout configurations), use empty div - // to measure width properly - DivElement div = Document.get().createDivElement(); - div.setInnerHTML(" "); - div.getStyle().setProperty("overflow", "hidden"); - div.getStyle().setProperty("height", "1px"); - getElement().appendChild(div); - excessWidth = getElement().getOffsetWidth() - - div.getOffsetWidth(); - getElement().removeChild(div); - } else { - excessWidth = getElement().getOffsetWidth() - - getElement().getPropertyInt("clientWidth"); - } - excessHeight = getElement().getOffsetHeight() - - getElement().getPropertyInt("clientHeight"); - - getElement().getStyle().setProperty("overflow", overflow); - } - - @Override - public int getWidth() { - int w = getRealWidth(); - if (w < 10 && BrowserInfo.get().isIE7()) { - // Overcome an IE7 bug #3295 - Util.shakeBodyElement(); - w = getRealWidth(); - } - return w; - } - - private int getRealWidth() { - if (connection.getConfiguration().isStandalone()) { - return getElement().getOffsetWidth() - getExcessWidth(); - } - - // If not running standalone, there might be multiple Vaadin apps - // that won't shrink with the browser window as the components have - // calculated widths (#3125) - - // Find all Vaadin applications on the page - ArrayList<String> vaadinApps = new ArrayList<String>(); - loadAppIdListFromDOM(vaadinApps); - - // Store original styles here so they can be restored - ArrayList<String> originalDisplays = new ArrayList<String>( - vaadinApps.size()); - - String ownAppId = connection.getConfiguration().getRootPanelId(); - - // Hiding elements causes browser to forget scroll position -> must - // save values and restore when the elements are visible again #7976 - int originalScrollTop = Window.getScrollTop(); - int originalScrollLeft = Window.getScrollLeft(); - - // Set display: none for all Vaadin apps - for (int i = 0; i < vaadinApps.size(); i++) { - String appId = vaadinApps.get(i); - Element targetElement; - if (appId.equals(ownAppId)) { - // Only hide the contents of current application - targetElement = ((Widget) layout).getElement(); - } else { - // Hide everything for other applications - targetElement = Document.get().getElementById(appId); - } - Style layoutStyle = targetElement.getStyle(); - - originalDisplays.add(i, layoutStyle.getDisplay()); - layoutStyle.setDisplay(Display.NONE); - } - - int w = getElement().getOffsetWidth() - getExcessWidth(); - - // Then restore the old display style before returning - for (int i = 0; i < vaadinApps.size(); i++) { - String appId = vaadinApps.get(i); - Element targetElement; - if (appId.equals(ownAppId)) { - targetElement = ((Widget) layout).getElement(); - } else { - targetElement = Document.get().getElementById(appId); - } - Style layoutStyle = targetElement.getStyle(); - String originalDisplay = originalDisplays.get(i); - - if (originalDisplay.length() == 0) { - layoutStyle.clearDisplay(); - } else { - layoutStyle.setProperty("display", originalDisplay); - } - } - - // Scroll back to original location - Window.scrollTo(originalScrollLeft, originalScrollTop); - - return w; - } - - private int getExcessWidth() { - if (excessWidth < 0) { - detectExcessSize(); - } - return excessWidth; - } - - @Override - public int getScrollbarSize() { - return Util.getNativeScrollbarSize(); - } - }; - - private native static void loadAppIdListFromDOM(ArrayList<String> list) - /*-{ - var j; - for(j in $wnd.vaadin.vaadinConfigurations) { - list.@java.util.Collection::add(Ljava/lang/Object;)(j); - } - }-*/; - - public RenderSpace getAllocatedSpace(Widget child) { - return myRenderSpace; - } - - public boolean hasChildComponent(Widget component) { - return (component != null && component == layout); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - // TODO This is untested as no layouts require this - if (oldComponent != layout) { - return; - } - - setWidget(newComponent); - layout = (Paintable) newComponent; - } - - public boolean requestLayout(Set<Paintable> child) { - /* - * Can never propagate further and we do not want need to re-layout the - * layout which has caused this request. - */ - updateParentFrameSize(); - - // layout size change may affect its available space (scrollbars) - connection.handleComponentRelativeSize((Widget) layout); - - return true; - - } - - private void updateParentFrameSize() { - if (parentFrame == null) { - return; - } - - int childHeight = Util.getRequiredHeight(getWidget().getElement()); - int childWidth = Util.getRequiredWidth(getWidget().getElement()); - - parentFrame.getStyle().setPropertyPx("width", childWidth); - parentFrame.getStyle().setPropertyPx("height", childHeight); - } - - private static native Element getParentFrame() - /*-{ - try { - var frameElement = $wnd.frameElement; - if (frameElement == null) { - return null; - } - if (frameElement.getAttribute("autoResize") == "true") { - return frameElement; - } - } catch (e) { - } - return null; - }-*/; - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP Subwindows never draw caption for their first child (layout) - } - - /** - * Return an iterator for current subwindows. This method is meant for - * testing purposes only. - * - * @return - */ - public ArrayList<VWindow> getSubWindowList() { - ArrayList<VWindow> windows = new ArrayList<VWindow>(subWindows.size()); - for (VWindow widget : subWindows) { - windows.add(widget); - } - return windows; - } - - public void init(String rootPanelId, - ApplicationConnection applicationConnection) { - DOM.sinkEvents(getElement(), Event.ONKEYDOWN | Event.ONSCROLL); - - // iview is focused when created so element needs tabIndex - // 1 due 0 is at the end of natural tabbing order - DOM.setElementProperty(getElement(), "tabIndex", "1"); - - RootPanel root = RootPanel.get(rootPanelId); - - // Remove the v-app-loading or any splash screen added inside the div by - // the user - root.getElement().setInnerHTML(""); - // For backwards compatibility with static index pages only. - // No longer added by AbstractApplicationServlet/Portlet - root.removeStyleName("v-app-loading"); - - root.add(this); - - if (applicationConnection.getConfiguration().isStandalone()) { - // set focus to iview element by default to listen possible keyboard - // shortcuts. For embedded applications this is unacceptable as we - // don't want to steal focus from the main page nor we don't want - // side-effects from focusing (scrollIntoView). - getElement().focus(); - } - - parentFrame = getParentFrame(); - } - - public ShortcutActionHandler getShortcutActionHandler() { - return actionHandler; - } - - public void focus() { - getElement().focus(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/Vaadin6Connector.java b/src/com/vaadin/terminal/gwt/client/ui/Vaadin6Connector.java new file mode 100644 index 0000000000..7fccdafd2a --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/Vaadin6Connector.java @@ -0,0 +1,17 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui; + +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; + +public abstract class Vaadin6Connector extends AbstractComponentConnector + implements Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + ((Paintable) getWidget()).updateFromUIDL(uidl, client); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java new file mode 100644 index 0000000000..80b6254e02 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutConnector.java @@ -0,0 +1,219 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.absolutelayout; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; +import com.vaadin.terminal.gwt.client.ui.absolutelayout.VAbsoluteLayout.AbsoluteWrapper; +import com.vaadin.ui.AbsoluteLayout; + +@Connect(AbsoluteLayout.class) +public class AbsoluteLayoutConnector extends + AbstractComponentContainerConnector implements DirectionalManagedLayout { + + private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( + this) { + + @Override + protected ComponentConnector getChildComponent(Element element) { + return getConnectorForElement(element); + } + + @Override + protected LayoutClickRpc getLayoutClickRPC() { + return rpc; + }; + + }; + + private AbsoluteLayoutServerRpc rpc; + + private Map<String, AbsoluteWrapper> connectorIdToComponentWrapper = new HashMap<String, AbsoluteWrapper>(); + + @Override + protected void init() { + super.init(); + rpc = RpcProxy.create(AbsoluteLayoutServerRpc.class, this); + } + + /** + * Returns the deepest nested child component which contains "element". The + * child component is also returned if "element" is part of its caption. + * + * @param element + * An element that is a nested sub element of the root element in + * this layout + * @return The Paintable which the element is a part of. Null if the element + * belongs to the layout and not to a child. + */ + protected ComponentConnector getConnectorForElement(Element element) { + return Util.getConnectorForElement(getConnection(), getWidget(), + element); + } + + public void updateCaption(ComponentConnector component) { + VAbsoluteLayout absoluteLayoutWidget = getWidget(); + AbsoluteWrapper componentWrapper = getWrapper(component); + + boolean captionIsNeeded = VCaption.isNeeded(component.getState()); + + VCaption caption = componentWrapper.getCaption(); + + if (captionIsNeeded) { + if (caption == null) { + caption = new VCaption(component, getConnection()); + absoluteLayoutWidget.add(caption); + componentWrapper.setCaption(caption); + } + caption.updateCaption(); + componentWrapper.updateCaptionPosition(); + } else { + if (caption != null) { + caption.removeFromParent(); + } + } + + } + + @Override + protected Widget createWidget() { + return GWT.create(VAbsoluteLayout.class); + } + + @Override + public VAbsoluteLayout getWidget() { + return (VAbsoluteLayout) super.getWidget(); + } + + @Override + public AbsoluteLayoutState getState() { + return (AbsoluteLayoutState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + clickEventHandler.handleEventHandlerRegistration(); + + // TODO Margin handling + + for (ComponentConnector child : getChildren()) { + getWrapper(child).setPosition( + getState().getConnectorPosition(child)); + } + }; + + private AbsoluteWrapper getWrapper(ComponentConnector child) { + String childId = child.getConnectorId(); + AbsoluteWrapper wrapper = connectorIdToComponentWrapper.get(childId); + if (wrapper != null) { + return wrapper; + } + + wrapper = new AbsoluteWrapper(child.getWidget()); + connectorIdToComponentWrapper.put(childId, wrapper); + getWidget().add(wrapper); + return wrapper; + + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + for (ComponentConnector child : getChildren()) { + getWrapper(child); + } + + for (ComponentConnector oldChild : event.getOldChildren()) { + if (oldChild.getParent() != this) { + String connectorId = oldChild.getConnectorId(); + AbsoluteWrapper absoluteWrapper = connectorIdToComponentWrapper + .remove(connectorId); + absoluteWrapper.destroy(); + } + } + } + + public void layoutVertically() { + VAbsoluteLayout layout = getWidget(); + for (ComponentConnector paintable : getChildren()) { + Widget widget = paintable.getWidget(); + AbsoluteWrapper wrapper = (AbsoluteWrapper) widget.getParent(); + Style wrapperStyle = wrapper.getElement().getStyle(); + + if (paintable.isRelativeHeight()) { + int h; + if (wrapper.top != null && wrapper.bottom != null) { + h = wrapper.getOffsetHeight(); + } else if (wrapper.bottom != null) { + // top not defined, available space 0... bottom of + // wrapper + h = wrapper.getElement().getOffsetTop() + + wrapper.getOffsetHeight(); + } else { + // top defined or both undefined, available space == + // canvas - top + h = layout.canvas.getOffsetHeight() + - wrapper.getElement().getOffsetTop(); + } + wrapperStyle.setHeight(h, Unit.PX); + getLayoutManager().reportHeightAssignedToRelative(paintable, h); + } else { + wrapperStyle.clearHeight(); + } + + wrapper.updateCaptionPosition(); + } + } + + public void layoutHorizontally() { + VAbsoluteLayout layout = getWidget(); + for (ComponentConnector paintable : getChildren()) { + AbsoluteWrapper wrapper = getWrapper(paintable); + Style wrapperStyle = wrapper.getElement().getStyle(); + + if (paintable.isRelativeWidth()) { + int w; + if (wrapper.left != null && wrapper.right != null) { + w = wrapper.getOffsetWidth(); + } else if (wrapper.right != null) { + // left == null + // available width == right edge == offsetleft + width + w = wrapper.getOffsetWidth() + + wrapper.getElement().getOffsetLeft(); + } else { + // left != null && right == null || left == null && + // right == null + // available width == canvas width - offset left + w = layout.canvas.getOffsetWidth() + - wrapper.getElement().getOffsetLeft(); + } + wrapperStyle.setWidth(w, Unit.PX); + getLayoutManager().reportWidthAssignedToRelative(paintable, w); + } else { + wrapperStyle.clearWidth(); + } + + wrapper.updateCaptionPosition(); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRpc.java new file mode 100644 index 0000000000..d626eb5b6c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutServerRpc.java @@ -0,0 +1,11 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.absolutelayout; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; + +public interface AbsoluteLayoutServerRpc extends LayoutClickRpc, ServerRpc { + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutState.java b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutState.java new file mode 100644 index 0000000000..4e1a43dd8b --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/AbsoluteLayoutState.java @@ -0,0 +1,29 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.absolutelayout; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutState; + +public class AbsoluteLayoutState extends AbstractLayoutState { + // Maps each component to a position + private Map<String, String> connectorToCssPosition = new HashMap<String, String>(); + + public String getConnectorPosition(Connector connector) { + return connectorToCssPosition.get(connector.getConnectorId()); + } + + public Map<String, String> getConnectorToCssPosition() { + return connectorToCssPosition; + } + + public void setConnectorToCssPosition( + Map<String, String> componentToCssPosition) { + connectorToCssPosition = componentToCssPosition; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/VAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/VAbsoluteLayout.java new file mode 100644 index 0000000000..e2cb629d68 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/absolutelayout/VAbsoluteLayout.java @@ -0,0 +1,134 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.absolutelayout; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Style; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.VCaption; + +public class VAbsoluteLayout extends ComplexPanel { + + /** Tag name for widget creation */ + public static final String TAGNAME = "absolutelayout"; + + /** Class name, prefix in styling */ + public static final String CLASSNAME = "v-absolutelayout"; + + private DivElement marginElement; + + protected final Element canvas = DOM.createDiv(); + + private Object previousStyleName; + + protected ApplicationConnection client; + + public VAbsoluteLayout() { + setElement(Document.get().createDivElement()); + setStyleName(CLASSNAME); + marginElement = Document.get().createDivElement(); + canvas.getStyle().setProperty("position", "relative"); + canvas.getStyle().setProperty("overflow", "hidden"); + marginElement.appendChild(canvas); + getElement().appendChild(marginElement); + + canvas.setClassName(CLASSNAME + "-canvas"); + canvas.setClassName(CLASSNAME + "-margin"); + } + + @Override + public void add(Widget child) { + super.add(child, canvas); + } + + public static class AbsoluteWrapper extends SimplePanel { + private String css; + String left; + String top; + String right; + String bottom; + private String zIndex; + + private VCaption caption; + + public AbsoluteWrapper(Widget child) { + setWidget(child); + setStyleName(CLASSNAME + "-wrapper"); + } + + public VCaption getCaption() { + return caption; + } + + public void setCaption(VCaption caption) { + this.caption = caption; + } + + public void destroy() { + if (caption != null) { + caption.removeFromParent(); + } + removeFromParent(); + } + + public void setPosition(String stringAttribute) { + if (css == null || !css.equals(stringAttribute)) { + css = stringAttribute; + top = right = bottom = left = zIndex = null; + if (!css.equals("")) { + String[] properties = css.split(";"); + for (int i = 0; i < properties.length; i++) { + String[] keyValue = properties[i].split(":"); + if (keyValue[0].equals("left")) { + left = keyValue[1]; + } else if (keyValue[0].equals("top")) { + top = keyValue[1]; + } else if (keyValue[0].equals("right")) { + right = keyValue[1]; + } else if (keyValue[0].equals("bottom")) { + bottom = keyValue[1]; + } else if (keyValue[0].equals("z-index")) { + zIndex = keyValue[1]; + } + } + } + // ensure ne values + Style style = getElement().getStyle(); + /* + * IE8 dies when nulling zIndex, even in IE7 mode. All other css + * properties (and even in older IE's) accept null values just + * fine. Assign empty string instead of null. + */ + if (zIndex != null) { + style.setProperty("zIndex", zIndex); + } else { + style.setProperty("zIndex", ""); + } + style.setProperty("top", top); + style.setProperty("left", left); + style.setProperty("right", right); + style.setProperty("bottom", bottom); + + } + updateCaptionPosition(); + } + + void updateCaptionPosition() { + if (caption != null) { + Style style = caption.getElement().getStyle(); + style.setProperty("position", "absolute"); + style.setPropertyPx("left", getElement().getOffsetLeft()); + style.setPropertyPx("top", getElement().getOffsetTop() + - caption.getHeight()); + } + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/accordion/AccordionConnector.java b/src/com/vaadin/terminal/gwt/client/ui/accordion/AccordionConnector.java new file mode 100644 index 0000000000..a03fa37214 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/accordion/AccordionConnector.java @@ -0,0 +1,83 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.accordion; + +import java.util.Iterator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.accordion.VAccordion.StackItem; +import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; +import com.vaadin.terminal.gwt.client.ui.tabsheet.TabsheetBaseConnector; +import com.vaadin.ui.Accordion; + +@Connect(Accordion.class) +public class AccordionConnector extends TabsheetBaseConnector implements + SimpleManagedLayout, MayScrollChildren { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().selectedUIDLItemIndex = -1; + super.updateFromUIDL(uidl, client); + /* + * Render content after all tabs have been created and we know how large + * the content area is + */ + if (getWidget().selectedUIDLItemIndex >= 0) { + StackItem selectedItem = getWidget().getStackItem( + getWidget().selectedUIDLItemIndex); + UIDL selectedTabUIDL = getWidget().lazyUpdateMap + .remove(selectedItem); + getWidget().open(getWidget().selectedUIDLItemIndex); + + selectedItem.setContent(selectedTabUIDL); + } else if (isRealUpdate(uidl) && getWidget().openTab != null) { + getWidget().close(getWidget().openTab); + } + + getWidget().iLayout(); + // finally render possible hidden tabs + if (getWidget().lazyUpdateMap.size() > 0) { + for (Iterator iterator = getWidget().lazyUpdateMap.keySet() + .iterator(); iterator.hasNext();) { + StackItem item = (StackItem) iterator.next(); + item.setContent(getWidget().lazyUpdateMap.get(item)); + } + getWidget().lazyUpdateMap.clear(); + } + + } + + @Override + public VAccordion getWidget() { + return (VAccordion) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VAccordion.class); + } + + public void updateCaption(ComponentConnector component) { + /* Accordion does not render its children's captions */ + } + + public void layout() { + VAccordion accordion = getWidget(); + + accordion.updateOpenTabSize(); + + if (isUndefinedHeight()) { + accordion.openTab.setHeightFromWidget(); + } + accordion.iLayout(); + + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java b/src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java index 4d0776a5f9..dcd520bbb3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java +++ b/src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java @@ -1,7 +1,7 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.accordion; import java.util.HashMap; import java.util.HashSet; @@ -15,80 +15,28 @@ import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderSpace; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ui.tabsheet.TabsheetBaseConnector; +import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheetBase; -public class VAccordion extends VTabsheetBase implements - ContainerResizedListener { +public class VAccordion extends VTabsheetBase { public static final String CLASSNAME = "v-accordion"; - private Set<Paintable> paintables = new HashSet<Paintable>(); + private Set<Widget> widgets = new HashSet<Widget>(); - private String height; + HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>(); - private String width = ""; + StackItem openTab = null; - private HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>(); - - private RenderSpace renderSpace = new RenderSpace(0, 0, true); - - private StackItem openTab = null; - - private boolean rendering = false; - - private int selectedUIDLItemIndex = -1; - - private RenderInformation renderInformation = new RenderInformation(); + int selectedUIDLItemIndex = -1; public VAccordion() { super(CLASSNAME); - // IE6 needs this to calculate offsetHeight correctly - if (BrowserInfo.get().isIE6()) { - DOM.setStyleAttribute(getElement(), "zoom", "1"); - } - } - - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - selectedUIDLItemIndex = -1; - super.updateFromUIDL(uidl, client); - /* - * Render content after all tabs have been created and we know how large - * the content area is - */ - if (selectedUIDLItemIndex >= 0) { - StackItem selectedItem = getStackItem(selectedUIDLItemIndex); - UIDL selectedTabUIDL = lazyUpdateMap.remove(selectedItem); - open(selectedUIDLItemIndex); - - selectedItem.setContent(selectedTabUIDL); - } else if (!uidl.getBooleanAttribute("cached") && openTab != null) { - close(openTab); - } - - iLayout(); - // finally render possible hidden tabs - if (lazyUpdateMap.size() > 0) { - for (Iterator iterator = lazyUpdateMap.keySet().iterator(); iterator - .hasNext();) { - StackItem item = (StackItem) iterator.next(); - item.setContent(lazyUpdateMap.get(item)); - } - lazyUpdateMap.clear(); - } - - renderInformation.updateSize(getElement()); - - rendering = false; } @Override @@ -137,7 +85,7 @@ public class VAccordion extends VTabsheetBase implements private StackItem moveStackItemIfNeeded(StackItem item, int newIndex, UIDL tabUidl) { UIDL tabContentUIDL = null; - Paintable tabContent = null; + ComponentConnector tabContent = null; if (tabUidl.getChildCount() > 0) { tabContentUIDL = tabUidl.getChildUIDL(0); tabContent = client.getPaintable(tabContentUIDL); @@ -179,14 +127,13 @@ public class VAccordion extends VTabsheetBase implements // StackItem Widget oldWidget = item.getComponent(); if (oldWidget != null) { - item = new StackItem(tabUidl); - insert(item, getElement(), newIndex, true); + oldWidget.removeFromParent(); } } return item; } - private void open(int itemIndex) { + void open(int itemIndex) { StackItem item = (StackItem) getWidget(itemIndex); boolean alreadyOpen = false; if (openTab != null) { @@ -209,7 +156,7 @@ public class VAccordion extends VTabsheetBase implements updateOpenTabSize(); } - private void close(StackItem item) { + void close(StackItem item) { if (!item.isOpen()) { return; } @@ -242,58 +189,19 @@ public class VAccordion extends VTabsheetBase implements } } - @Override - public void setWidth(String width) { - if (this.width.equals(width)) { - return; - } - - Util.setWidthExcludingPaddingAndBorder(this, width, 2); - this.width = width; - if (!rendering) { - updateOpenTabSize(); - - if (isDynamicHeight()) { - Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, - openTab, this); - updateOpenTabSize(); - } - - if (isDynamicHeight()) { - openTab.setHeightFromWidget(); - } - iLayout(); - } - } - - @Override - public void setHeight(String height) { - Util.setHeightExcludingPaddingAndBorder(this, height, 2); - this.height = height; - - if (!rendering) { - updateOpenTabSize(); - } - - } - /** * Sets the size of the open tab */ - private void updateOpenTabSize() { + void updateOpenTabSize() { if (openTab == null) { - renderSpace.setHeight(0); - renderSpace.setWidth(0); return; } // WIDTH if (!isDynamicWidth()) { - int w = getOffsetWidth(); - openTab.setWidth(w); - renderSpace.setWidth(w); + openTab.setWidth("100%"); } else { - renderSpace.setWidth(0); + openTab.setWidth(null); } // HEIGHT @@ -317,10 +225,8 @@ public class VAccordion extends VTabsheetBase implements spaceForOpenItem = 0; } - renderSpace.setHeight(spaceForOpenItem); openTab.setHeight(spaceForOpenItem); } else { - renderSpace.setHeight(0); openTab.setHeightFromWidget(); } @@ -348,13 +254,11 @@ public class VAccordion extends VTabsheetBase implements super.setWidth(maxWidth + "px"); openTab.setWidth(maxWidth); } - - Util.runWebkitOverflowAutoFix(openTab.getContainerElement()); - } /** - * + * A StackItem has always two children, Child 0 is a VCaption, Child 1 is + * the actual child widget. */ protected class StackItem extends ComplexPanel implements ClickHandler { @@ -383,12 +287,12 @@ public class VAccordion extends VTabsheetBase implements } public void setHeightFromWidget() { - Widget paintable = getPaintable(); - if (paintable == null) { + Widget widget = getChildWidget(); + if (widget == null) { return; } - int paintableHeight = (paintable).getElement().getOffsetHeight(); + int paintableHeight = widget.getElement().getOffsetHeight(); setHeight(paintableHeight); } @@ -432,12 +336,8 @@ public class VAccordion extends VTabsheetBase implements public StackItem(UIDL tabUidl) { setElement(DOM.createDiv()); - caption = new VCaption(null, client); + caption = new VCaption(client); caption.addClickHandler(this); - if (BrowserInfo.get().isIE6()) { - DOM.setEventListener(captionNode, this); - DOM.sinkEvents(captionNode, Event.BUTTON_LEFT); - } super.add(caption, captionNode); DOM.appendChild(captionNode, caption.getElement()); DOM.appendChild(getElement(), captionNode); @@ -459,7 +359,7 @@ public class VAccordion extends VTabsheetBase implements return content; } - public Widget getPaintable() { + public Widget getChildWidget() { if (getWidgetCount() > 1) { return getWidget(1); } else { @@ -467,14 +367,17 @@ public class VAccordion extends VTabsheetBase implements } } - public void replacePaintable(Paintable newPntbl) { + public void replaceWidget(Widget newWidget) { if (getWidgetCount() > 1) { - client.unregisterPaintable((Paintable) getWidget(1)); - paintables.remove(getWidget(1)); + Widget oldWidget = getWidget(1); + ComponentConnector oldPaintable = ConnectorMap.get(client) + .getConnector(oldWidget); + ConnectorMap.get(client).unregisterConnector(oldPaintable); + widgets.remove(oldWidget); remove(1); } - add((Widget) newPntbl, content); - paintables.add(newPntbl); + add(newWidget, content); + widgets.add(newWidget); } public void open() { @@ -496,10 +399,6 @@ public class VAccordion extends VTabsheetBase implements removeStyleDependentName("open"); setHeight(-1); setWidth(""); - if (BrowserInfo.get().isIE6()) { - // Work around for IE6 layouting problem #3359 - getElement().getStyle().setProperty("zoom", "1"); - } open = false; } @@ -508,20 +407,21 @@ public class VAccordion extends VTabsheetBase implements } public void setContent(UIDL contentUidl) { - final Paintable newPntbl = client.getPaintable(contentUidl); - if (getPaintable() == null) { - add((Widget) newPntbl, content); - paintables.add(newPntbl); - } else if (getPaintable() != newPntbl) { - replacePaintable(newPntbl); + final ComponentConnector newPntbl = client + .getPaintable(contentUidl); + Widget newWidget = newPntbl.getWidget(); + if (getChildWidget() == null) { + add(newWidget, content); + widgets.add(newWidget); + } else if (getChildWidget() != newWidget) { + replaceWidget(newWidget); } - newPntbl.updateFromUIDL(contentUidl, client); if (contentUidl.getBooleanAttribute("cached")) { /* * The size of a cached, relative sized component must be * updated to report correct size. */ - client.handleComponentRelativeSize((Widget) newPntbl); + client.handleComponentRelativeSize(newPntbl.getWidget()); } if (isOpen() && isDynamicHeight()) { setHeightFromWidget(); @@ -533,15 +433,21 @@ public class VAccordion extends VTabsheetBase implements } public void updateCaption(UIDL uidl) { - caption.updateCaption(uidl); + // TODO need to call this because the caption does not have an owner + caption.updateCaptionWithoutOwner( + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION), + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED), + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION), + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE), + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON)); } public int getWidgetWidth() { return DOM.getFirstChild(content).getOffsetWidth(); } - public boolean contains(Paintable p) { - return (getPaintable() == p); + public boolean contains(ComponentConnector p) { + return (getChildWidget() == p.getWidget()); } public boolean isCaptionVisible() { @@ -555,80 +461,22 @@ public class VAccordion extends VTabsheetBase implements clear(); } - public boolean isDynamicHeight() { - return height == null || height.equals(""); + boolean isDynamicWidth() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + return paintable.isUndefinedWidth(); } - public boolean isDynamicWidth() { - return width == null || width.equals(""); + boolean isDynamicHeight() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + return paintable.isUndefinedHeight(); } @Override @SuppressWarnings("unchecked") - protected Iterator<Object> getPaintableIterator() { - return (Iterator) paintables.iterator(); - } - - public boolean hasChildComponent(Widget component) { - if (paintables.contains(component)) { - return true; - } else { - return false; - } - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - for (Widget w : getChildren()) { - StackItem item = (StackItem) w; - if (item.getPaintable() == oldComponent) { - item.replacePaintable((Paintable) newComponent); - return; - } - } - } - - public void updateCaption(Paintable component, UIDL uidl) { - /* Accordion does not render its children's captions */ - } - - public boolean requestLayout(Set<Paintable> child) { - if (!isDynamicHeight() && !isDynamicWidth()) { - /* - * If the height and width has been specified for this container the - * child components cannot make the size of the layout change - */ - // layout size change may affect its available space (scrollbars) - for (Paintable paintable : child) { - client.handleComponentRelativeSize((Widget) paintable); - } - - return true; - } - - updateOpenTabSize(); - - if (renderInformation.updateSize(getElement())) { - /* - * Size has changed so we let the child components know about the - * new size. - */ - iLayout(); - // TODO Check if this is needed - client.runDescendentsLayout(this); - - return false; - } else { - /* - * Size has not changed so we do not need to propagate the event - * further - */ - return true; - } - - } - - public RenderSpace getAllocatedSpace(Widget child) { - return renderSpace; + protected Iterator<Widget> getWidgetIterator() { + return widgets.iterator(); } @Override @@ -643,15 +491,17 @@ public class VAccordion extends VTabsheetBase implements } @Override - protected Paintable getTab(int index) { + protected ComponentConnector getTab(int index) { if (index < getWidgetCount()) { - return (Paintable) (getStackItem(index)).getPaintable(); + Widget w = getStackItem(index); + return ConnectorMap.get(client).getConnector(w); } return null; } - private StackItem getStackItem(int index) { + StackItem getStackItem(int index) { return (StackItem) getWidget(index); } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAudio.java b/src/com/vaadin/terminal/gwt/client/ui/audio/AudioConnector.java index 1fdfaca831..d55e66dbd5 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VAudio.java +++ b/src/com/vaadin/terminal/gwt/client/ui/audio/AudioConnector.java @@ -1,35 +1,29 @@ /* @VaadinApache2LicenseForJavaFiles@ */ +package com.vaadin.terminal.gwt.client.ui.audio; -package com.vaadin.terminal.gwt.client.ui; - -import com.google.gwt.dom.client.AudioElement; -import com.google.gwt.dom.client.Document; +import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.MediaBaseConnector; +import com.vaadin.ui.Audio; -public class VAudio extends VMediaBase { - private static String CLASSNAME = "v-audio"; - - private AudioElement audio; - - public VAudio() { - audio = Document.get().createAudioElement(); - setMediaElement(audio); - setStyleName(CLASSNAME); - } +@Connect(Audio.class) +public class AudioConnector extends MediaBaseConnector { @Override public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { + super.updateFromUIDL(uidl, client); + if (!isRealUpdate(uidl)) { return; } - super.updateFromUIDL(uidl, client); - Style style = audio.getStyle(); + Style style = getWidget().getElement().getStyle(); // Make sure that the controls are not clipped if visible. if (shouldShowControls(uidl) @@ -43,7 +37,8 @@ public class VAudio extends VMediaBase { } @Override - protected String getDefaultAltHtml() { - return "Your browser does not support the <code>audio</code> element."; + protected Widget createWidget() { + return GWT.create(VAudio.class); } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/audio/VAudio.java b/src/com/vaadin/terminal/gwt/client/ui/audio/VAudio.java new file mode 100644 index 0000000000..7d5d1fe034 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/audio/VAudio.java @@ -0,0 +1,27 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.audio; + +import com.google.gwt.dom.client.AudioElement; +import com.google.gwt.dom.client.Document; +import com.vaadin.terminal.gwt.client.ui.VMediaBase; + +public class VAudio extends VMediaBase { + private static String CLASSNAME = "v-audio"; + + private AudioElement audio; + + public VAudio() { + audio = Document.get().createAudioElement(); + setMediaElement(audio); + setStyleName(CLASSNAME); + } + + @Override + protected String getDefaultAltHtml() { + return "Your browser does not support the <code>audio</code> element."; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java new file mode 100644 index 0000000000..62a5e8ac8b --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonConnector.java @@ -0,0 +1,134 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.button; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.EventHelper; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; +import com.vaadin.terminal.gwt.client.communication.FieldRpc.FocusAndBlurServerRpc; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.ui.Button; + +@Connect(value = Button.class, loadStyle = LoadStyle.EAGER) +public class ButtonConnector extends AbstractComponentConnector implements + BlurHandler, FocusHandler, ClickHandler { + + private ButtonServerRpc rpc = RpcProxy.create(ButtonServerRpc.class, this); + private FocusAndBlurServerRpc focusBlurProxy = RpcProxy.create( + FocusAndBlurServerRpc.class, this); + + private HandlerRegistration focusHandlerRegistration = null; + private HandlerRegistration blurHandlerRegistration = null; + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + @Override + public void init() { + super.init(); + getWidget().addClickHandler(this); + getWidget().client = getConnection(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + focusHandlerRegistration = EventHelper.updateFocusHandler(this, + focusHandlerRegistration); + blurHandlerRegistration = EventHelper.updateBlurHandler(this, + blurHandlerRegistration); + // Set text + getWidget().setText(getState().getCaption()); + + // handle error + if (null != getState().getErrorMessage()) { + if (getWidget().errorIndicatorElement == null) { + getWidget().errorIndicatorElement = DOM.createSpan(); + getWidget().errorIndicatorElement + .setClassName("v-errorindicator"); + } + getWidget().wrapper.insertBefore(getWidget().errorIndicatorElement, + getWidget().captionElement); + + } else if (getWidget().errorIndicatorElement != null) { + getWidget().wrapper.removeChild(getWidget().errorIndicatorElement); + getWidget().errorIndicatorElement = null; + } + + if (getState().getIcon() != null) { + if (getWidget().icon == null) { + getWidget().icon = new Icon(getConnection()); + getWidget().wrapper.insertBefore(getWidget().icon.getElement(), + getWidget().captionElement); + } + getWidget().icon.setUri(getState().getIcon().getURL()); + } else { + if (getWidget().icon != null) { + getWidget().wrapper.removeChild(getWidget().icon.getElement()); + getWidget().icon = null; + } + } + + getWidget().clickShortcut = getState().getClickShortcutKeyCode(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VButton.class); + } + + @Override + public VButton getWidget() { + return (VButton) super.getWidget(); + } + + @Override + public ButtonState getState() { + return (ButtonState) super.getState(); + } + + public void onFocus(FocusEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + focusBlurProxy.focus(); + } + + public void onBlur(BlurEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + focusBlurProxy.blur(); + } + + public void onClick(ClickEvent event) { + if (getState().isDisableOnClick()) { + getWidget().setEnabled(false); + rpc.disableOnClick(); + } + + // Add mouse details + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event.getNativeEvent(), getWidget() + .getElement()); + rpc.click(details); + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonServerRpc.java new file mode 100644 index 0000000000..4a379c9262 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonServerRpc.java @@ -0,0 +1,28 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.button; + +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +/** + * RPC interface for calls from client to server. + * + * @since 7.0 + */ +public interface ButtonServerRpc extends ServerRpc { + /** + * Button click event. + * + * @param mouseEventDetails + * serialized mouse event details + */ + public void click(MouseEventDetails mouseEventDetails); + + /** + * Indicate to the server that the client has disabled the button as a + * result of a click. + */ + public void disableOnClick(); +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java new file mode 100644 index 0000000000..f26cdae0c6 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/button/ButtonState.java @@ -0,0 +1,65 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.button; + +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.ui.Button; + +/** + * Shared state for Button and NativeButton. + * + * @see ComponentState + * + * @since 7.0 + */ +public class ButtonState extends ComponentState { + private boolean disableOnClick = false; + private int clickShortcutKeyCode = 0; + + /** + * Checks whether the button should be disabled on the client side on next + * click. + * + * @return true if the button should be disabled on click + */ + public boolean isDisableOnClick() { + return disableOnClick; + } + + /** + * Sets whether the button should be disabled on the client side on next + * click. + * + * @param disableOnClick + * true if the button should be disabled on click + */ + public void setDisableOnClick(boolean disableOnClick) { + this.disableOnClick = disableOnClick; + } + + /** + * Returns the key code for activating the button via a keyboard shortcut. + * + * See {@link Button#setClickShortcut(int, int...)} for more information. + * + * @return key code or 0 for none + */ + public int getClickShortcutKeyCode() { + return clickShortcutKeyCode; + } + + /** + * Sets the key code for activating the button via a keyboard shortcut. + * + * See {@link Button#setClickShortcut(int, int...)} for more information. + * + * @param clickShortcutKeyCode + * key code or 0 for none + */ + public void setClickShortcutKeyCode(int clickShortcutKeyCode) { + this.clickShortcutKeyCode = clickShortcutKeyCode; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java index 9188f7406a..f7d73d3b5e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VButton.java +++ b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java @@ -2,48 +2,34 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.button; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Accessibility; import com.google.gwt.user.client.ui.FocusWidget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.EventHelper; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Icon; -public class VButton extends FocusWidget implements Paintable, ClickHandler, - FocusHandler, BlurHandler { +public class VButton extends FocusWidget implements ClickHandler { public static final String CLASSNAME = "v-button"; private static final String CLASSNAME_PRESSED = "v-pressed"; - public static final String ATTR_DISABLE_ON_CLICK = "dc"; - // mouse movement is checked before synthesizing click event on mouseout protected static int MOVE_THRESHOLD = 3; protected int mousedownX = 0; protected int mousedownY = 0; - protected String id; - protected ApplicationConnection client; protected final Element wrapper = DOM.createSpan(); @@ -65,8 +51,6 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, private int tabIndex = 0; - private boolean disableOnClick = false; - /* * BELOW PRIVATE MEMBERS COPY-PASTED FROM GWT CustomButton */ @@ -88,10 +72,7 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, private boolean disallowNextClick = false; private boolean isHovering; - private HandlerRegistration focusHandlerRegistration; - private HandlerRegistration blurHandlerRegistration; - - private int clickShortcut = 0; + protected int clickShortcut = 0; public VButton() { super(DOM.createDiv()); @@ -113,64 +94,6 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, addClickHandler(this); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - // Ensure correct implementation, - // but don't let container manage caption etc. - if (client.updateComponent(this, uidl, false)) { - return; - } - - focusHandlerRegistration = EventHelper.updateFocusHandler(this, client, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, client, - blurHandlerRegistration); - - // Save details - this.client = client; - id = uidl.getId(); - - // Set text - setText(uidl.getStringAttribute("caption")); - - disableOnClick = uidl.hasAttribute(ATTR_DISABLE_ON_CLICK); - - // handle error - if (uidl.hasAttribute("error")) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createSpan(); - errorIndicatorElement.setClassName("v-errorindicator"); - } - wrapper.insertBefore(errorIndicatorElement, captionElement); - - // Fix for IE6, IE7 - if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) { - errorIndicatorElement.setInnerText(" "); - } - - } else if (errorIndicatorElement != null) { - wrapper.removeChild(errorIndicatorElement); - errorIndicatorElement = null; - } - - if (uidl.hasAttribute("icon")) { - if (icon == null) { - icon = new Icon(client); - wrapper.insertBefore(icon.getElement(), captionElement); - } - icon.setUri(uidl.getStringAttribute("icon")); - } else { - if (icon != null) { - wrapper.removeChild(icon.getElement()); - icon = null; - } - } - - if (uidl.hasAttribute("keycode")) { - clickShortcut = uidl.getIntAttribute("keycode"); - } - } - public void setText(String text) { captionElement.setInnerText(text); } @@ -250,10 +173,9 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) { removeStyleName(CLASSNAME_PRESSED); } - // Explicitly prevent IE 6 to 8 from propagating mouseup events + // Explicitly prevent IE 8 from propagating mouseup events // upward (fixes #6753) - if (BrowserInfo.get().isIE() - && BrowserInfo.get().getIEVersion() < 9) { + if (BrowserInfo.get().isIE8()) { event.stopPropagation(); } } @@ -359,23 +281,9 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, * .dom.client.ClickEvent) */ public void onClick(ClickEvent event) { - if (id == null || client == null) { - return; - } if (BrowserInfo.get().isSafari()) { VButton.this.setFocus(true); } - if (disableOnClick) { - setEnabled(false); - client.updateVariable(id, "disabledOnClick", true, false); - } - - client.updateVariable(id, "state", true, false); - - // Add mouse details - MouseEventDetails details = new MouseEventDetails( - event.getNativeEvent(), getElement()); - client.updateVariable(id, "mousedetails", details.serialize(), true); clickPending = false; } @@ -457,25 +365,6 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, } } - @Override - public void setWidth(String width) { - if (BrowserInfo.get().isIE6() || BrowserInfo.get().isIE7()) { - if (width != null && width.length() > 2) { - // Assume pixel values are always sent from - // ApplicationConnection - int w = Integer - .parseInt(width.substring(0, width.length() - 2)); - w -= getHorizontalBorderAndPaddingWidth(getElement()); - if (w < 0) { - // validity check for IE - w = 0; - } - width = w + "px"; - } - } - super.setWidth(width); - } - private static native int getHorizontalBorderAndPaddingWidth(Element elem) /*-{ // THIS METHOD IS ONLY USED FOR INTERNET EXPLORER, IT DOESN'T WORK WITH OTHERS @@ -527,12 +416,4 @@ public class VButton extends FocusWidget implements Paintable, ClickHandler, return ret; }-*/; - public void onFocus(FocusEvent arg0) { - client.updateVariable(id, EventId.FOCUS, "", true); - } - - public void onBlur(BlurEvent arg0) { - client.updateVariable(id, EventId.BLUR, "", true); - } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxConnector.java b/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxConnector.java new file mode 100644 index 0000000000..731838371f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxConnector.java @@ -0,0 +1,148 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.checkbox; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.EventHelper; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; +import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.communication.FieldRpc.FocusAndBlurServerRpc; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.ui.CheckBox; + +@Connect(CheckBox.class) +public class CheckBoxConnector extends AbstractFieldConnector implements + FocusHandler, BlurHandler, ClickHandler { + + private HandlerRegistration focusHandlerRegistration; + private HandlerRegistration blurHandlerRegistration; + + private CheckBoxServerRpc rpc = RpcProxy.create(CheckBoxServerRpc.class, + this); + private FocusAndBlurServerRpc focusBlurRpc = RpcProxy.create( + FocusAndBlurServerRpc.class, this); + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + @Override + protected void init() { + super.init(); + getWidget().addClickHandler(this); + getWidget().client = getConnection(); + getWidget().id = getConnectorId(); + + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + focusHandlerRegistration = EventHelper.updateFocusHandler(this, + focusHandlerRegistration); + blurHandlerRegistration = EventHelper.updateBlurHandler(this, + blurHandlerRegistration); + + if (null != getState().getErrorMessage()) { + if (getWidget().errorIndicatorElement == null) { + getWidget().errorIndicatorElement = DOM.createSpan(); + getWidget().errorIndicatorElement.setInnerHTML(" "); + DOM.setElementProperty(getWidget().errorIndicatorElement, + "className", "v-errorindicator"); + DOM.appendChild(getWidget().getElement(), + getWidget().errorIndicatorElement); + DOM.sinkEvents(getWidget().errorIndicatorElement, + VTooltip.TOOLTIP_EVENTS | Event.ONCLICK); + } else { + DOM.setStyleAttribute(getWidget().errorIndicatorElement, + "display", ""); + } + } else if (getWidget().errorIndicatorElement != null) { + DOM.setStyleAttribute(getWidget().errorIndicatorElement, "display", + "none"); + } + + if (isReadOnly()) { + getWidget().setEnabled(false); + } + + if (getState().getIcon() != null) { + if (getWidget().icon == null) { + getWidget().icon = new Icon(getConnection()); + DOM.insertChild(getWidget().getElement(), + getWidget().icon.getElement(), 1); + getWidget().icon.sinkEvents(VTooltip.TOOLTIP_EVENTS); + getWidget().icon.sinkEvents(Event.ONCLICK); + } + getWidget().icon.setUri(getState().getIcon().getURL()); + } else if (getWidget().icon != null) { + // detach icon + DOM.removeChild(getWidget().getElement(), + getWidget().icon.getElement()); + getWidget().icon = null; + } + + // Set text + getWidget().setText(getState().getCaption()); + getWidget().setValue(getState().isChecked()); + getWidget().immediate = getState().isImmediate(); + } + + @Override + public CheckBoxState getState() { + return (CheckBoxState) super.getState(); + } + + @Override + public VCheckBox getWidget() { + return (VCheckBox) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VCheckBox.class); + } + + public void onFocus(FocusEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + focusBlurRpc.focus(); + } + + public void onBlur(BlurEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + focusBlurRpc.blur(); + } + + public void onClick(ClickEvent event) { + if (!isEnabled()) { + return; + } + + // Add mouse details + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event.getNativeEvent(), getWidget() + .getElement()); + rpc.setChecked(getWidget().getValue(), details); + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxServerRpc.java new file mode 100644 index 0000000000..05091ff6ed --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxServerRpc.java @@ -0,0 +1,11 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.checkbox; + +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public interface CheckBoxServerRpc extends ServerRpc { + public void setChecked(boolean checked, MouseEventDetails mouseEventDetails); +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxState.java b/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxState.java new file mode 100644 index 0000000000..d6d51cad36 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/checkbox/CheckBoxState.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.checkbox; + +import com.vaadin.terminal.gwt.client.AbstractFieldState; + +public class CheckBoxState extends AbstractFieldState { + private boolean checked = false; + + public boolean isChecked() { + return checked; + } + + public void setChecked(boolean checked) { + this.checked = checked; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java b/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java new file mode 100644 index 0000000000..fd90796ea5 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/checkbox/VCheckBox.java @@ -0,0 +1,61 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.checkbox; + +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.Icon; + +public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements + Field { + + public static final String CLASSNAME = "v-checkbox"; + + String id; + + boolean immediate; + + ApplicationConnection client; + + Element errorIndicatorElement; + + Icon icon; + + public VCheckBox() { + setStyleName(CLASSNAME); + + sinkEvents(VTooltip.TOOLTIP_EVENTS); + Element el = DOM.getFirstChild(getElement()); + while (el != null) { + DOM.sinkEvents(el, + (DOM.getEventsSunk(el) | VTooltip.TOOLTIP_EVENTS)); + el = DOM.getNextSibling(el); + } + } + + @Override + public void onBrowserEvent(Event event) { + if (icon != null && (event.getTypeInt() == Event.ONCLICK) + && (DOM.eventGetTarget(event) == icon.getElement())) { + // Click on icon should do nothing if widget is disabled + if (isEnabled()) { + setValue(!getValue()); + } + } + super.onBrowserEvent(event); + if (event.getTypeInt() == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + } + if (client != null) { + client.handleTooltipEvent(event, this); + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/combobox/ComboBoxConnector.java b/src/com/vaadin/terminal/gwt/client/ui/combobox/ComboBoxConnector.java new file mode 100644 index 0000000000..ee16d90b12 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/combobox/ComboBoxConnector.java @@ -0,0 +1,246 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.combobox; + +import java.util.Iterator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.combobox.VFilterSelect.FilterSelectSuggestion; +import com.vaadin.terminal.gwt.client.ui.menubar.MenuItem; +import com.vaadin.ui.Select; + +@Connect(Select.class) +public class ComboBoxConnector extends AbstractFieldConnector implements + Paintable, SimpleManagedLayout { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal + * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection) + */ + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Save details + getWidget().client = client; + getWidget().paintableId = uidl.getId(); + + getWidget().readonly = isReadOnly(); + getWidget().enabled = isEnabled(); + + getWidget().tb.setEnabled(getWidget().enabled); + getWidget().updateReadOnly(); + + if (!isRealUpdate(uidl)) { + return; + } + + // Inverse logic here to make the default case (text input enabled) + // work without additional UIDL messages + boolean noTextInput = uidl + .hasAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT) + && uidl.getBooleanAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT); + getWidget().setTextInputEnabled(!noTextInput); + + // not a FocusWidget -> needs own tabindex handling + if (uidl.hasAttribute("tabindex")) { + getWidget().tb.setTabIndex(uidl.getIntAttribute("tabindex")); + } + + if (uidl.hasAttribute("filteringmode")) { + getWidget().filteringmode = uidl.getIntAttribute("filteringmode"); + } + + getWidget().immediate = getState().isImmediate(); + + getWidget().nullSelectionAllowed = uidl.hasAttribute("nullselect"); + + getWidget().nullSelectItem = uidl.hasAttribute("nullselectitem") + && uidl.getBooleanAttribute("nullselectitem"); + + getWidget().currentPage = uidl.getIntVariable("page"); + + if (uidl.hasAttribute("pagelength")) { + getWidget().pageLength = uidl.getIntAttribute("pagelength"); + } + + if (uidl.hasAttribute(VFilterSelect.ATTR_INPUTPROMPT)) { + // input prompt changed from server + getWidget().inputPrompt = uidl + .getStringAttribute(VFilterSelect.ATTR_INPUTPROMPT); + } else { + getWidget().inputPrompt = ""; + } + + getWidget().suggestionPopup.updateStyleNames(uidl, getState()); + + getWidget().allowNewItem = uidl.hasAttribute("allownewitem"); + getWidget().lastNewItemString = null; + + getWidget().currentSuggestions.clear(); + if (!getWidget().waitingForFilteringResponse) { + /* + * Clear the current suggestions as the server response always + * includes the new ones. Exception is when filtering, then we need + * to retain the value if the user does not select any of the + * options matching the filter. + */ + getWidget().currentSuggestion = null; + /* + * Also ensure no old items in menu. Unless cleared the old values + * may cause odd effects on blur events. Suggestions in menu might + * not necessary exist in select at all anymore. + */ + getWidget().suggestionPopup.menu.clearItems(); + + } + + final UIDL options = uidl.getChildUIDL(0); + if (uidl.hasAttribute("totalMatches")) { + getWidget().totalMatches = uidl.getIntAttribute("totalMatches"); + } else { + getWidget().totalMatches = 0; + } + + // used only to calculate minimum popup width + String captions = Util.escapeHTML(getWidget().inputPrompt); + + for (final Iterator<?> i = options.getChildIterator(); i.hasNext();) { + final UIDL optionUidl = (UIDL) i.next(); + final FilterSelectSuggestion suggestion = getWidget().new FilterSelectSuggestion( + optionUidl); + getWidget().currentSuggestions.add(suggestion); + if (optionUidl.hasAttribute("selected")) { + if (!getWidget().waitingForFilteringResponse + || getWidget().popupOpenerClicked) { + String newSelectedOptionKey = Integer.toString(suggestion + .getOptionKey()); + if (!newSelectedOptionKey + .equals(getWidget().selectedOptionKey) + || suggestion.getReplacementString().equals( + getWidget().tb.getText())) { + // Update text field if we've got a new selection + // Also update if we've got the same text to retain old + // text selection behavior + getWidget().setPromptingOff( + suggestion.getReplacementString()); + getWidget().selectedOptionKey = newSelectedOptionKey; + } + } + getWidget().currentSuggestion = suggestion; + getWidget().setSelectedItemIcon(suggestion.getIconUri()); + } + + // Collect captions so we can calculate minimum width for textarea + if (captions.length() > 0) { + captions += "|"; + } + captions += Util.escapeHTML(suggestion.getReplacementString()); + } + + if ((!getWidget().waitingForFilteringResponse || getWidget().popupOpenerClicked) + && uidl.hasVariable("selected") + && uidl.getStringArrayVariable("selected").length == 0) { + // select nulled + if (!getWidget().waitingForFilteringResponse + || !getWidget().popupOpenerClicked) { + if (!getWidget().focused) { + /* + * client.updateComponent overwrites all styles so we must + * ALWAYS set the prompting style at this point, even though + * we think it has been set already... + */ + getWidget().prompting = false; + getWidget().setPromptingOn(); + } else { + // we have focus in field, prompting can't be set on, + // instead just clear the input + getWidget().tb.setValue(""); + } + } + getWidget().setSelectedItemIcon(null); + getWidget().selectedOptionKey = null; + } + + if (getWidget().waitingForFilteringResponse + && getWidget().lastFilter.toLowerCase().equals( + uidl.getStringVariable("filter"))) { + getWidget().suggestionPopup.showSuggestions( + getWidget().currentSuggestions, getWidget().currentPage, + getWidget().totalMatches); + getWidget().waitingForFilteringResponse = false; + if (!getWidget().popupOpenerClicked + && getWidget().selectPopupItemWhenResponseIsReceived != VFilterSelect.Select.NONE) { + // we're paging w/ arrows + if (getWidget().selectPopupItemWhenResponseIsReceived == VFilterSelect.Select.LAST) { + getWidget().suggestionPopup.menu.selectLastItem(); + } else { + getWidget().suggestionPopup.menu.selectFirstItem(); + } + + // This is used for paging so we update the keyboard selection + // variable as well. + MenuItem activeMenuItem = getWidget().suggestionPopup.menu + .getSelectedItem(); + getWidget().suggestionPopup.menu + .setKeyboardSelectedItem(activeMenuItem); + + // Update text field to contain the correct text + getWidget().setTextboxText(activeMenuItem.getText()); + getWidget().tb.setSelectionRange( + getWidget().lastFilter.length(), + activeMenuItem.getText().length() + - getWidget().lastFilter.length()); + + getWidget().selectPopupItemWhenResponseIsReceived = VFilterSelect.Select.NONE; // reset + } + if (getWidget().updateSelectionWhenReponseIsReceived) { + getWidget().suggestionPopup.menu + .doPostFilterSelectedItemAction(); + } + } + + // Calculate minumum textarea width + getWidget().suggestionPopupMinWidth = getWidget().minWidth(captions); + + getWidget().popupOpenerClicked = false; + + if (!getWidget().initDone) { + getWidget().updateRootWidth(); + } + + // Focus dependent style names are lost during the update, so we add + // them here back again + if (getWidget().focused) { + getWidget().addStyleDependentName("focus"); + } + + getWidget().initDone = true; + } + + @Override + protected Widget createWidget() { + return GWT.create(VFilterSelect.class); + } + + @Override + public VFilterSelect getWidget() { + return (VFilterSelect) super.getWidget(); + } + + public void layout() { + VFilterSelect widget = getWidget(); + if (widget.initDone) { + widget.updateRootWidth(); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java index 8362d6fbec..d29eda0d6a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.combobox; import java.util.ArrayList; import java.util.Collection; @@ -12,9 +12,9 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.dom.client.Style.Overflow; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; @@ -46,13 +46,21 @@ import com.google.gwt.user.client.ui.SuggestOracle.Suggestion; import com.google.gwt.user.client.ui.TextBox; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; +import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.menubar.MenuBar; +import com.vaadin.terminal.gwt.client.ui.menubar.MenuItem; /** * Client side implementation of the Select component. @@ -60,9 +68,8 @@ import com.vaadin.terminal.gwt.client.VTooltip; * TODO needs major refactoring (to be extensible etc) */ @SuppressWarnings("deprecation") -public class VFilterSelect extends Composite implements Paintable, Field, - KeyDownHandler, KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, - Focusable { +public class VFilterSelect extends Composite implements Field, KeyDownHandler, + KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable { /** * Represents a suggestion in the suggestion popup box @@ -154,7 +161,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, private static final String Z_INDEX = "30000"; - private final SuggestionMenu menu; + protected final SuggestionMenu menu; private final Element up = DOM.createDiv(); private final Element down = DOM.createDiv(); @@ -543,14 +550,19 @@ public class VFilterSelect extends Composite implements Paintable, Field, /** * Updates style names in suggestion popup to help theme building. + * + * @param uidl + * UIDL for the whole combo box + * @param componentState + * shared state of the combo box */ - public void updateStyleNames(UIDL uidl) { - if (uidl.hasAttribute("style")) { - setStyleName(CLASSNAME + "-suggestpopup"); - final String[] styles = uidl.getStringAttribute("style").split( - " "); - for (int i = 0; i < styles.length; i++) { - addStyleDependentName(styles[i]); + public void updateStyleNames(UIDL uidl, ComponentState componentState) { + setStyleName(CLASSNAME + "-suggestpopup"); + if (componentState.hasStyles()) { + for (String style : componentState.getStyles()) { + if (!"".equals(style)) { + addStyleDependentName(style); + } } } } @@ -762,12 +774,6 @@ public class VFilterSelect extends Composite implements Paintable, Field, } public void onLoad(LoadEvent event) { - if (BrowserInfo.get().isIE6()) { - // Ensure PNG transparency works in IE6 - Util.doIE6PngFix((Element) Element.as(event.getNativeEvent() - .getEventTarget())); - } - // Handle icon onload events to ensure shadow is resized // correctly delayedImageLoadExecutioner.trigger(); @@ -783,7 +789,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, return keyboardSelectedItem; } - private void setKeyboardSelectedItem(MenuItem firstItem) { + protected void setKeyboardSelectedItem(MenuItem firstItem) { keyboardSelectedItem = firstItem; } @@ -810,7 +816,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, /** * The text box where the filter is written */ - private final TextBox tb = new TextBox() { + protected final TextBox tb = new TextBox() { /* * (non-Javadoc) * @@ -837,7 +843,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, }; }; - private final SuggestionPopup suggestionPopup = new SuggestionPopup(); + protected final SuggestionPopup suggestionPopup = new SuggestionPopup(); /** * Used when measuring the width of the popup @@ -868,74 +874,70 @@ public class VFilterSelect extends Composite implements Paintable, Field, private final Image selectedItemIcon = new Image(); - private ApplicationConnection client; + protected ApplicationConnection client; - private String paintableId; + protected String paintableId; - private int currentPage; + protected int currentPage; /** * A collection of available suggestions (options) as received from the * server. */ - private final List<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>(); + protected final List<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>(); - private boolean immediate; + protected boolean immediate; - private String selectedOptionKey; + protected String selectedOptionKey; - private boolean waitingForFilteringResponse = false; - private boolean updateSelectionWhenReponseIsReceived = false; + protected boolean waitingForFilteringResponse = false; + protected boolean updateSelectionWhenReponseIsReceived = false; private boolean tabPressedWhenPopupOpen = false; - private boolean initDone = false; + protected boolean initDone = false; - private String lastFilter = ""; + protected String lastFilter = ""; - private enum Select { + protected enum Select { NONE, FIRST, LAST }; - private Select selectPopupItemWhenResponseIsReceived = Select.NONE; + protected Select selectPopupItemWhenResponseIsReceived = Select.NONE; /** * The current suggestion selected from the dropdown. This is one of the * values in currentSuggestions except when filtering, in this case * currentSuggestion might not be in currentSuggestions. */ - private FilterSelectSuggestion currentSuggestion; + protected FilterSelectSuggestion currentSuggestion; - private int totalMatches; - private boolean allowNewItem; - private boolean nullSelectionAllowed; - private boolean nullSelectItem; - private boolean enabled; - private boolean readonly; + protected int totalMatches; + protected boolean allowNewItem; + protected boolean nullSelectionAllowed; + protected boolean nullSelectItem; + protected boolean enabled; + protected boolean readonly; - private int filteringmode = FILTERINGMODE_OFF; + protected int filteringmode = FILTERINGMODE_OFF; // shown in unfocused empty field, disappears on focus (e.g "Search here") private static final String CLASSNAME_PROMPT = "prompt"; - private static final String ATTR_INPUTPROMPT = "prompt"; + protected static final String ATTR_INPUTPROMPT = "prompt"; public static final String ATTR_NO_TEXT_INPUT = "noInput"; - private String inputPrompt = ""; - private boolean prompting = false; + protected String inputPrompt = ""; + protected boolean prompting = false; // Set true when popupopened has been clicked. Cleared on each UIDL-update. // This handles the special case where are not filtering yet and the // selected value has changed on the server-side. See #2119 - private boolean popupOpenerClicked; - private String width = null; - private int textboxPadding = -1; - private int componentPadding = -1; - private int suggestionPopupMinWidth = 0; + protected boolean popupOpenerClicked; + protected int suggestionPopupMinWidth = 0; private int popupWidth = -1; /* * Stores the last new item string to avoid double submissions. Cleared on * uidl updates */ - private String lastNewItemString; - private boolean focused = false; - private int horizPaddingAndBorder = 2; + protected String lastNewItemString; + protected boolean focused = false; /** * If set to false, the component should not allow entering text to the @@ -950,16 +952,13 @@ public class VFilterSelect extends Composite implements Paintable, Field, selectedItemIcon.setStyleName("v-icon"); selectedItemIcon.addLoadHandler(new LoadHandler() { public void onLoad(LoadEvent event) { + if (BrowserInfo.get().isIE8()) { + // IE8 needs some help to discover it should reposition the + // text field + forceReflow(); + } updateRootWidth(); updateSelectedIconPosition(); - /* - * Workaround for an IE bug where the text is positioned below - * the icon (#3991) - */ - if (BrowserInfo.get().isIE()) { - Util.setStyleTemporarily(tb.getElement(), "paddingLeft", - "0"); - } } }); @@ -1051,206 +1050,11 @@ public class VFilterSelect extends Composite implements Paintable, Field, currentPage = page; } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal - * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - paintableId = uidl.getId(); - this.client = client; - - readonly = uidl.hasAttribute("readonly"); - enabled = !uidl.hasAttribute("disabled"); - - tb.setEnabled(enabled); - updateReadOnly(); - - if (client.updateComponent(this, uidl, true)) { - return; - } - - // Inverse logic here to make the default case (text input enabled) - // work without additional UIDL messages - boolean noTextInput = uidl.hasAttribute(ATTR_NO_TEXT_INPUT) - && uidl.getBooleanAttribute(ATTR_NO_TEXT_INPUT); - setTextInputEnabled(!noTextInput); - - // not a FocusWidget -> needs own tabindex handling - if (uidl.hasAttribute("tabindex")) { - tb.setTabIndex(uidl.getIntAttribute("tabindex")); - } - - if (uidl.hasAttribute("filteringmode")) { - filteringmode = uidl.getIntAttribute("filteringmode"); - } - - immediate = uidl.hasAttribute("immediate"); - - nullSelectionAllowed = uidl.hasAttribute("nullselect"); - - nullSelectItem = uidl.hasAttribute("nullselectitem") - && uidl.getBooleanAttribute("nullselectitem"); - - currentPage = uidl.getIntVariable("page"); - - if (uidl.hasAttribute("pagelength")) { - pageLength = uidl.getIntAttribute("pagelength"); - } - - if (uidl.hasAttribute(ATTR_INPUTPROMPT)) { - // input prompt changed from server - inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT); - } else { - inputPrompt = ""; - } - - suggestionPopup.updateStyleNames(uidl); - - allowNewItem = uidl.hasAttribute("allownewitem"); - lastNewItemString = null; - - currentSuggestions.clear(); - if (!waitingForFilteringResponse) { - /* - * Clear the current suggestions as the server response always - * includes the new ones. Exception is when filtering, then we need - * to retain the value if the user does not select any of the - * options matching the filter. - */ - currentSuggestion = null; - /* - * Also ensure no old items in menu. Unless cleared the old values - * may cause odd effects on blur events. Suggestions in menu might - * not necessary exist in select at all anymore. - */ - suggestionPopup.menu.clearItems(); - - } - - final UIDL options = uidl.getChildUIDL(0); - if (uidl.hasAttribute("totalMatches")) { - totalMatches = uidl.getIntAttribute("totalMatches"); - } else { - totalMatches = 0; - } - - // used only to calculate minimum popup width - String captions = Util.escapeHTML(inputPrompt); - - for (final Iterator<?> i = options.getChildIterator(); i.hasNext();) { - final UIDL optionUidl = (UIDL) i.next(); - final FilterSelectSuggestion suggestion = new FilterSelectSuggestion( - optionUidl); - currentSuggestions.add(suggestion); - if (optionUidl.hasAttribute("selected")) { - if (!waitingForFilteringResponse || popupOpenerClicked) { - String newSelectedOptionKey = Integer.toString(suggestion - .getOptionKey()); - if (!newSelectedOptionKey.equals(selectedOptionKey) - || suggestion.getReplacementString().equals( - tb.getText())) { - // Update text field if we've got a new selection - // Also update if we've got the same text to retain old - // text selection behavior - setPromptingOff(suggestion.getReplacementString()); - selectedOptionKey = newSelectedOptionKey; - } - } - currentSuggestion = suggestion; - setSelectedItemIcon(suggestion.getIconUri()); - } - - // Collect captions so we can calculate minimum width for textarea - if (captions.length() > 0) { - captions += "|"; - } - captions += Util.escapeHTML(suggestion.getReplacementString()); - } - - if ((!waitingForFilteringResponse || popupOpenerClicked) - && uidl.hasVariable("selected") - && uidl.getStringArrayVariable("selected").length == 0) { - // select nulled - if (!waitingForFilteringResponse || !popupOpenerClicked) { - if (!focused) { - /* - * client.updateComponent overwrites all styles so we must - * ALWAYS set the prompting style at this point, even though - * we think it has been set already... - */ - prompting = false; - setPromptingOn(); - } else { - // we have focus in field, prompting can't be set on, - // instead just clear the input - tb.setValue(""); - } - } - - setSelectedItemIcon(null); - selectedOptionKey = null; - } - - if (waitingForFilteringResponse - && lastFilter.toLowerCase().equals( - uidl.getStringVariable("filter"))) { - suggestionPopup.showSuggestions(currentSuggestions, currentPage, - totalMatches); - waitingForFilteringResponse = false; - if (!popupOpenerClicked - && selectPopupItemWhenResponseIsReceived != Select.NONE) { - // we're paging w/ arrows - if (selectPopupItemWhenResponseIsReceived == Select.LAST) { - suggestionPopup.menu.selectLastItem(); - } else { - suggestionPopup.menu.selectFirstItem(); - } - - // This is used for paging so we update the keyboard selection - // variable as well. - MenuItem activeMenuItem = suggestionPopup.menu - .getSelectedItem(); - suggestionPopup.menu.setKeyboardSelectedItem(activeMenuItem); - - // Update text field to contain the correct text - setTextboxText(activeMenuItem.getText()); - tb.setSelectionRange(lastFilter.length(), activeMenuItem - .getText().length() - lastFilter.length()); - - selectPopupItemWhenResponseIsReceived = Select.NONE; // reset - } - if (updateSelectionWhenReponseIsReceived) { - suggestionPopup.menu.doPostFilterSelectedItemAction(); - } - } - - // Calculate minumum textarea width - suggestionPopupMinWidth = minWidth(captions); - - popupOpenerClicked = false; - - if (!initDone) { - updateRootWidth(); - } - - // Focus dependent style names are lost during the update, so we add - // them here back again - if (focused) { - addStyleDependentName("focus"); - } - - initDone = true; - } - - private void updateReadOnly() { + protected void updateReadOnly() { tb.setReadOnly(readonly || !textInputEnabled); } - private void setTextInputEnabled(boolean textInputEnabled) { + protected void setTextInputEnabled(boolean textInputEnabled) { // Always update styles as they might have been overwritten if (textInputEnabled) { removeStyleDependentName(STYLE_NO_INPUT); @@ -1267,45 +1071,20 @@ public class VFilterSelect extends Composite implements Paintable, Field, } /** - * Sets the text in the text box using a deferred command if on Gecko. This - * is required for performance reasons (see #3663). + * Sets the text in the text box. * * @param text * the text to set in the text box */ - private void setTextboxText(final String text) { - if (BrowserInfo.get().isFF3()) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - tb.setText(text); - } - }); - } else { - tb.setText(text); - } - } - - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.Composite#onAttach() - */ - @Override - protected void onAttach() { - super.onAttach(); - - /* - * We need to recalculate the root width when the select is attached, so - * #2974 won't happen. - */ - updateRootWidth(); + protected void setTextboxText(final String text) { + tb.setText(text); } /** * Turns prompting on. When prompting is turned on a command prompt is shown * in the text box if nothing has been entered. */ - private void setPromptingOn() { + protected void setPromptingOn() { if (!prompting) { prompting = true; addStyleDependentName(CLASSNAME_PROMPT); @@ -1320,7 +1099,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, * @param text * The text the text box should contain. */ - private void setPromptingOff(String text) { + protected void setPromptingOff(String text) { setTextboxText(text); if (prompting) { prompting = false; @@ -1370,10 +1149,15 @@ public class VFilterSelect extends Composite implements Paintable, Field, * @param iconUri * The URI of the icon */ - private void setSelectedItemIcon(String iconUri) { + protected void setSelectedItemIcon(String iconUri) { if (iconUri == null || iconUri.length() == 0) { if (selectedItemIcon.isAttached()) { panel.remove(selectedItemIcon); + if (BrowserInfo.get().isIE8()) { + // IE8 needs some help to discover it should reposition the + // text field + forceReflow(); + } updateRootWidth(); } } else { @@ -1384,6 +1168,10 @@ public class VFilterSelect extends Composite implements Paintable, Field, } } + private void forceReflow() { + Util.setStyleTemporarily(tb.getElement(), "zoom", "1"); + } + /** * Positions the icon vertically in the middle. Should be called after the * icon has loaded @@ -1391,13 +1179,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, private void updateSelectedIconPosition() { // Position icon vertically to middle int availableHeight = 0; - if (BrowserInfo.get().isIE6()) { - getElement().getStyle().setOverflow(Overflow.HIDDEN); - availableHeight = getOffsetHeight(); - getElement().getStyle().setProperty("overflow", ""); - } else { - availableHeight = getOffsetHeight(); - } + availableHeight = getOffsetHeight(); int iconHeight = Util.getRequiredHeight(selectedItemIcon); int marginTop = (availableHeight - iconHeight) / 2; @@ -1658,7 +1440,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, /** * Calculate minimum width for FilterSelect textarea */ - private native int minWidth(String captions) + protected native int minWidth(String captions) /*-{ if(!captions || captions.length <= 0) return 0; @@ -1793,68 +1575,14 @@ public class VFilterSelect extends Composite implements Paintable, Field, tb.setFocus(true); } - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.UIObject#setWidth(java.lang.String) - */ - @Override - public void setWidth(String width) { - if (width == null || width.equals("")) { - this.width = null; - } else { - this.width = width; - } - - if (BrowserInfo.get().isIE6()) { - // Required in IE when textfield is wider than this.width - getElement().getStyle().setOverflow(Overflow.HIDDEN); - horizPaddingAndBorder = Util.setWidthExcludingPaddingAndBorder( - this, width, horizPaddingAndBorder); - getElement().getStyle().setProperty("overflow", ""); - } else { - horizPaddingAndBorder = Util.setWidthExcludingPaddingAndBorder( - this, width, horizPaddingAndBorder); - } - - if (initDone) { - updateRootWidth(); - } - } - - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.UIObject#setHeight(java.lang.String) - */ - @Override - public void setHeight(String height) { - super.setHeight(height); - Util.setHeightExcludingPaddingAndBorder(tb, height, 3); - } - /** * Calculates the width of the select if the select has undefined width. * Should be called when the width changes or when the icon changes. */ - private void updateRootWidth() { - if (width == null) { - /* - * When the width is not specified we must specify width for root - * div so the popupopener won't wrap to the next line and also so - * the size of the combobox won't change over time. - */ - int tbWidth = Util.getRequiredWidth(tb); - - /* - * Note: iconWidth is here calculated as a negative pixel value so - * you should consider this in further calculations. - */ - int iconWidth = selectedItemIcon.isAttached() ? Util - .measureMarginLeft(tb.getElement()) - - Util.measureMarginLeft(selectedItemIcon.getElement()) : 0; - - int w = tbWidth + getPopUpOpenerWidth() + iconWidth; + protected void updateRootWidth() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + if (paintable.isUndefinedWidth()) { /* * When the select has a undefined with we need to check that we are @@ -1863,45 +1591,37 @@ public class VFilterSelect extends Composite implements Paintable, Field, * when the popup is used to view longer items than the text box is * wide. */ + int w = Util.getRequiredWidth(this); if ((!initDone || currentPage + 1 < 0) && suggestionPopupMinWidth > w) { - setTextboxWidth(suggestionPopupMinWidth); - w = suggestionPopupMinWidth; - } else { /* - * Firefox3 has its own way of doing rendering so we need to - * specify the width for the TextField to make sure it actually - * is rendered as wide as FF3 says it is + * We want to compensate for the paddings just to preserve the + * exact size as in Vaadin 6.x, but we get here before + * MeasuredSize has been initialized. + * Util.measureHorizontalPaddingAndBorder does not work with + * border-box, so we must do this the hard way. */ - tb.setWidth((tbWidth - getTextboxPadding()) + "px"); + Style style = getElement().getStyle(); + String originalPadding = style.getPadding(); + String originalBorder = style.getBorderWidth(); + style.setPaddingLeft(0, Unit.PX); + style.setBorderWidth(0, Unit.PX); + int offset = w - Util.getRequiredWidth(this); + style.setProperty("padding", originalPadding); + style.setProperty("borderWidth", originalBorder); + + setWidth(suggestionPopupMinWidth + offset + "px"); } - super.setWidth((w) + "px"); - // Freeze the initial width, so that it won't change even if the - // icon size changes - width = w + "px"; - } else { /* - * When the width is specified we also want to explicitly specify - * widths for textbox and popupopener + * Lock the textbox width to its current value if it's not already + * locked */ - setTextboxWidth(getMainWidth() - getComponentPadding()); - - } - } - - /** - * Only use the first page popup width so the textbox will not get resized - * whenever the popup is resized. This also resolves issue where toggling - * combo box between read only and normal state makes it grow larger. - * - * @return Width of popup opener - */ - private int getPopUpOpenerWidth() { - if (popupWidth < 0) { - popupWidth = Util.getRequiredWidth(popupOpener); + if (!tb.getElement().getStyle().getWidth().endsWith("px")) { + tb.setWidth((tb.getOffsetWidth() - selectedItemIcon + .getOffsetWidth()) + "px"); + } } - return popupWidth; } /** @@ -1911,63 +1631,15 @@ public class VFilterSelect extends Composite implements Paintable, Field, * @return The width in pixels */ private int getMainWidth() { - int componentWidth; - if (BrowserInfo.get().isIE6()) { - // Required in IE when textfield is wider than this.width - getElement().getStyle().setOverflow(Overflow.HIDDEN); - componentWidth = getOffsetWidth(); - getElement().getStyle().setProperty("overflow", ""); - } else { - componentWidth = getOffsetWidth(); - } - return componentWidth; - } - - /** - * Sets the text box width in pixels. - * - * @param componentWidth - * The width of the text box in pixels - */ - private void setTextboxWidth(int componentWidth) { - int padding = getTextboxPadding(); - int iconWidth = selectedItemIcon.isAttached() ? Util - .getRequiredWidth(selectedItemIcon) : 0; - - int textboxWidth = componentWidth - padding - getPopUpOpenerWidth() - - iconWidth; - if (textboxWidth < 0) { - textboxWidth = 0; - } - tb.setWidth(textboxWidth + "px"); - } - - /** - * Gets the horizontal padding of the text box in pixels. The measurement - * includes the border width. - * - * @return The padding in pixels - */ - private int getTextboxPadding() { - if (textboxPadding < 0) { - textboxPadding = Util.measureHorizontalPaddingAndBorder( - tb.getElement(), 4); - } - return textboxPadding; + return getOffsetWidth(); } - /** - * Gets the horizontal padding of the select. The measurement includes the - * border width. - * - * @return The padding in pixels - */ - private int getComponentPadding() { - if (componentPadding < 0) { - componentPadding = Util.measureHorizontalPaddingAndBorder( - getElement(), 3); + @Override + public void setWidth(String width) { + super.setWidth(width); + if (width.length() != 0) { + tb.setWidth("100%"); } - return componentPadding; } /** diff --git a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java new file mode 100644 index 0000000000..7df31a8593 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutConnector.java @@ -0,0 +1,169 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.csslayout; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.BrowserInfo; +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.VCaption; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; +import com.vaadin.terminal.gwt.client.ui.csslayout.VCssLayout.FlowPane; +import com.vaadin.ui.CssLayout; + +@Connect(CssLayout.class) +public class CssLayoutConnector extends AbstractLayoutConnector { + + private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( + this) { + + @Override + protected ComponentConnector getChildComponent(Element element) { + return Util.getConnectorForElement(getConnection(), getWidget(), + element); + } + + @Override + protected LayoutClickRpc getLayoutClickRPC() { + return rpc; + }; + }; + + private CssLayoutServerRpc rpc; + + private Map<ComponentConnector, VCaption> childToCaption = new HashMap<ComponentConnector, VCaption>(); + + @Override + protected void init() { + super.init(); + rpc = RpcProxy.create(CssLayoutServerRpc.class, this); + } + + @Override + public CssLayoutState getState() { + return (CssLayoutState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + getWidget().setMarginStyles( + new VMarginInfo(getState().getMarginsBitmask())); + + for (ComponentConnector child : getChildren()) { + if (!getState().getChildCss().containsKey(child)) { + continue; + } + String css = getState().getChildCss().get(child); + Style style = child.getWidget().getElement().getStyle(); + // should we remove styles also? How can we know what we have added + // as it is added directly to the child component? + String[] cssRules = css.split(";"); + for (String cssRule : cssRules) { + String parts[] = cssRule.split(":"); + if (parts.length == 2) { + style.setProperty(makeCamelCase(parts[0].trim()), + parts[1].trim()); + } + } + } + + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + clickEventHandler.handleEventHandlerRegistration(); + + int index = 0; + FlowPane cssLayoutWidgetContainer = getWidget().panel; + for (ComponentConnector child : getChildren()) { + VCaption childCaption = childToCaption.get(child); + if (childCaption != null) { + cssLayoutWidgetContainer.addOrMove(childCaption, index++); + } + cssLayoutWidgetContainer.addOrMove(child.getWidget(), index++); + } + + // Detach old child widgets and possibly their caption + for (ComponentConnector child : event.getOldChildren()) { + if (child.getParent() == this) { + // Skip current children + continue; + } + cssLayoutWidgetContainer.remove(child.getWidget()); + VCaption vCaption = childToCaption.remove(child); + if (vCaption != null) { + cssLayoutWidgetContainer.remove(vCaption); + } + } + } + + private static final String makeCamelCase(String cssProperty) { + // TODO this might be cleaner to implement with regexp + while (cssProperty.contains("-")) { + int indexOf = cssProperty.indexOf("-"); + cssProperty = cssProperty.substring(0, indexOf) + + String.valueOf(cssProperty.charAt(indexOf + 1)) + .toUpperCase() + cssProperty.substring(indexOf + 2); + } + if ("float".equals(cssProperty)) { + if (BrowserInfo.get().isIE()) { + return "styleFloat"; + } else { + return "cssFloat"; + } + } + return cssProperty; + } + + @Override + public VCssLayout getWidget() { + return (VCssLayout) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VCssLayout.class); + } + + public void updateCaption(ComponentConnector child) { + Widget childWidget = child.getWidget(); + FlowPane cssLayoutWidgetContainer = getWidget().panel; + int widgetPosition = cssLayoutWidgetContainer + .getWidgetIndex(childWidget); + + VCaption caption = childToCaption.get(child); + if (VCaption.isNeeded(child.getState())) { + if (caption == null) { + caption = new VCaption(child, getConnection()); + childToCaption.put(child, caption); + } + if (!caption.isAttached()) { + // Insert caption at widget index == before widget + cssLayoutWidgetContainer.insert(caption, widgetPosition); + } + caption.updateCaption(); + } else if (caption != null) { + childToCaption.remove(child); + cssLayoutWidgetContainer.remove(caption); + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRpc.java new file mode 100644 index 0000000000..7ba89d4c4c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutServerRpc.java @@ -0,0 +1,11 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.csslayout; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; + +public interface CssLayoutServerRpc extends LayoutClickRpc, ServerRpc { + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutState.java b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutState.java new file mode 100644 index 0000000000..07a8c1804a --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/csslayout/CssLayoutState.java @@ -0,0 +1,23 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.csslayout; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutState; + +public class CssLayoutState extends AbstractLayoutState { + private Map<Connector, String> childCss = new HashMap<Connector, String>(); + + public Map<Connector, String> getChildCss() { + return childCss; + } + + public void setChildCss(Map<Connector, String> childCss) { + this.childCss = childCss; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/csslayout/VCssLayout.java b/src/com/vaadin/terminal/gwt/client/ui/csslayout/VCssLayout.java new file mode 100644 index 0000000000..7076120388 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/csslayout/VCssLayout.java @@ -0,0 +1,72 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.csslayout; + +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.StyleConstants; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; + +public class VCssLayout extends SimplePanel { + public static final String TAGNAME = "csslayout"; + public static final String CLASSNAME = "v-" + TAGNAME; + + FlowPane panel = new FlowPane(); + + Element margin = DOM.createDiv(); + + public VCssLayout() { + super(); + getElement().appendChild(margin); + setStyleName(CLASSNAME); + margin.setClassName(CLASSNAME + "-margin"); + setWidget(panel); + } + + @Override + protected Element getContainerElement() { + return margin; + } + + public class FlowPane extends FlowPanel { + + public FlowPane() { + super(); + setStyleName(CLASSNAME + "-container"); + } + + void addOrMove(Widget child, int index) { + if (child.getParent() == this) { + int currentIndex = getWidgetIndex(child); + if (index == currentIndex) { + return; + } + } + insert(child, index); + } + + } + + /** + * Sets CSS classes for margin based on the given parameters. + * + * @param margins + * A {@link VMarginInfo} object that provides info on + * top/left/bottom/right margins + */ + protected void setMarginStyles(VMarginInfo margins) { + setStyleName(margin, VCssLayout.CLASSNAME + "-" + + StyleConstants.MARGIN_TOP, margins.hasTop()); + setStyleName(margin, VCssLayout.CLASSNAME + "-" + + StyleConstants.MARGIN_RIGHT, margins.hasRight()); + setStyleName(margin, VCssLayout.CLASSNAME + "-" + + StyleConstants.MARGIN_BOTTOM, margins.hasBottom()); + setStyleName(margin, VCssLayout.CLASSNAME + "-" + + StyleConstants.MARGIN_LEFT, margins.hasLeft()); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/customcomponent/CustomComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/customcomponent/CustomComponentConnector.java new file mode 100644 index 0000000000..a65187a461 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/customcomponent/CustomComponentConnector.java @@ -0,0 +1,46 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.customcomponent; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.CustomComponent; + +@Connect(value = CustomComponent.class, loadStyle = LoadStyle.EAGER) +public class CustomComponentConnector extends + AbstractComponentContainerConnector { + + @Override + protected Widget createWidget() { + return GWT.create(VCustomComponent.class); + } + + @Override + public VCustomComponent getWidget() { + return (VCustomComponent) super.getWidget(); + } + + public void updateCaption(ComponentConnector component) { + // NOP, custom component dont render composition roots caption + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + ComponentConnector newChild = null; + if (getChildren().size() == 1) { + newChild = getChildren().get(0); + } + + VCustomComponent customComponent = getWidget(); + customComponent.setWidget(newChild.getWidget()); + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/customcomponent/VCustomComponent.java b/src/com/vaadin/terminal/gwt/client/ui/customcomponent/VCustomComponent.java new file mode 100644 index 0000000000..2b27bd0e58 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/customcomponent/VCustomComponent.java @@ -0,0 +1,18 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.customcomponent; + +import com.google.gwt.user.client.ui.SimplePanel; + +public class VCustomComponent extends SimplePanel { + + private static final String CLASSNAME = "v-customcomponent"; + + public VCustomComponent() { + super(); + setStyleName(CLASSNAME); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/customfield/CustomFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/customfield/CustomFieldConnector.java new file mode 100644 index 0000000000..a2ba09da43 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/customfield/CustomFieldConnector.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.customfield; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.customcomponent.CustomComponentConnector; +import com.vaadin.terminal.gwt.client.ui.customcomponent.VCustomComponent; +import com.vaadin.ui.CustomField; + +@Connect(value = CustomField.class) +public class CustomFieldConnector extends CustomComponentConnector { + + @Override + protected Widget createWidget() { + return GWT.create(VCustomComponent.class); + } + + @Override + public VCustomComponent getWidget() { + return super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/customlayout/CustomLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/customlayout/CustomLayoutConnector.java new file mode 100644 index 0000000000..5e8f01258f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/customlayout/CustomLayoutConnector.java @@ -0,0 +1,118 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.customlayout; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.ui.CustomLayout; + +@Connect(CustomLayout.class) +public class CustomLayoutConnector extends AbstractLayoutConnector implements + SimpleManagedLayout { + + @Override + public CustomLayoutState getState() { + return (CustomLayoutState) super.getState(); + } + + @Override + protected void init() { + super.init(); + getWidget().client = getConnection(); + getWidget().pid = getConnectorId(); + + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + // Evaluate scripts + VCustomLayout.eval(getWidget().scripts); + getWidget().scripts = null; + + } + + private void updateHtmlTemplate() { + if (getWidget().hasTemplate()) { + // We (currently) only do this once. You can't change the template + // later on. + return; + } + String templateName = getState().getTemplateName(); + String templateContents = getState().getTemplateContents(); + + if (templateName != null) { + // Get the HTML-template from client. Overrides templateContents + // (even though both can never be given at the same time) + templateContents = getConnection().getResource( + "layouts/" + templateName + ".html"); + if (templateContents == null) { + templateContents = "<em>Layout file layouts/" + + templateName + + ".html is missing. Components will be drawn for debug purposes.</em>"; + } + } + + getWidget().initializeHTML(templateContents, + getConnection().getThemeUri()); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + // Must do this once here so the HTML has been set up before we start + // adding child widgets. + + updateHtmlTemplate(); + + // For all contained widgets + for (ComponentConnector child : getChildren()) { + String location = getState().getChildLocations().get(child); + try { + getWidget().setWidget(child.getWidget(), location); + } catch (final IllegalArgumentException e) { + // If no location is found, this component is not visible + } + } + for (ComponentConnector oldChild : event.getOldChildren()) { + if (oldChild.getParent() == this) { + // Connector still a child of this + continue; + } + Widget oldChildWidget = oldChild.getWidget(); + if (oldChildWidget.isAttached()) { + // slot of this widget is emptied, remove it + getWidget().remove(oldChildWidget); + } + } + + } + + @Override + public VCustomLayout getWidget() { + return (VCustomLayout) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VCustomLayout.class); + } + + public void updateCaption(ComponentConnector paintable) { + getWidget().updateCaption(paintable); + } + + public void layout() { + getWidget().iLayoutJS(DOM.getFirstChild(getWidget().getElement())); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/customlayout/CustomLayoutState.java b/src/com/vaadin/terminal/gwt/client/ui/customlayout/CustomLayoutState.java new file mode 100644 index 0000000000..6b374a8099 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/customlayout/CustomLayoutState.java @@ -0,0 +1,41 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.customlayout; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutState; + +public class CustomLayoutState extends AbstractLayoutState { + Map<Connector, String> childLocations = new HashMap<Connector, String>(); + private String templateContents; + private String templateName; + + public String getTemplateContents() { + return templateContents; + } + + public void setTemplateContents(String templateContents) { + this.templateContents = templateContents; + } + + public String getTemplateName() { + return templateName; + } + + public void setTemplateName(String templateName) { + this.templateName = templateName; + } + + public Map<Connector, String> getChildLocations() { + return childLocations; + } + + public void setChildLocations(Map<Connector, String> childLocations) { + this.childLocations = childLocations; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java b/src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java index f4aacf3ea2..b4194c40a6 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/customlayout/VCustomLayout.java @@ -2,12 +2,10 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.customlayout; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; -import java.util.Set; import com.google.gwt.dom.client.ImageElement; import com.google.gwt.dom.client.NodeList; @@ -18,12 +16,7 @@ import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; import com.vaadin.terminal.gwt.client.VCaptionWrapper; @@ -34,8 +27,7 @@ import com.vaadin.terminal.gwt.client.VCaptionWrapper; * @author Vaadin Ltd * */ -public class VCustomLayout extends ComplexPanel implements Paintable, - Container, ContainerResizedListener { +public class VCustomLayout extends ComplexPanel { public static final String CLASSNAME = "v-customlayout"; @@ -43,24 +35,23 @@ public class VCustomLayout extends ComplexPanel implements Paintable, private final HashMap<String, Element> locationToElement = new HashMap<String, Element>(); /** Location-name to contained widget map */ - private final HashMap<String, Widget> locationToWidget = new HashMap<String, Widget>(); + final HashMap<String, Widget> locationToWidget = new HashMap<String, Widget>(); /** Widget to captionwrapper map */ - private final HashMap<Paintable, VCaptionWrapper> widgetToCaptionWrapper = new HashMap<Paintable, VCaptionWrapper>(); + private final HashMap<Widget, VCaptionWrapper> childWidgetToCaptionWrapper = new HashMap<Widget, VCaptionWrapper>(); /** Name of the currently rendered style */ String currentTemplateName; /** Unexecuted scripts loaded from the template */ - private String scripts = ""; + String scripts = ""; /** Paintable ID of this paintable */ - private String pid; + String pid; - private ApplicationConnection client; + ApplicationConnection client; - /** Has the template been loaded from contents passed in UIDL **/ - private boolean hasTemplateContents = false; + private boolean htmlInitialized = false; private Element elementWithNativeResizeFunction; @@ -68,8 +59,6 @@ public class VCustomLayout extends ComplexPanel implements Paintable, private String width = ""; - private HashMap<String, FloatSize> locationToExtraSize = new HashMap<String, FloatSize>(); - public VCustomLayout() { setElement(DOM.createDiv()); // Clear any unwanted styling @@ -131,94 +120,14 @@ public class VCustomLayout extends ComplexPanel implements Paintable, locationToWidget.put(location, widget); } - /** Update the layout from UIDL */ - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - // ApplicationConnection manages generic component features - if (client.updateComponent(this, uidl, true)) { - return; - } - - pid = uidl.getId(); - if (!hasTemplate()) { - // Update HTML template only once - initializeHTML(uidl, client); - } - - // Evaluate scripts - eval(scripts); - scripts = null; - - iLayout(); - // TODO Check if this is needed - client.runDescendentsLayout(this); - - Set<Widget> oldWidgets = new HashSet<Widget>(); - oldWidgets.addAll(locationToWidget.values()); - - // For all contained widgets - for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) { - final UIDL uidlForChild = (UIDL) i.next(); - if (uidlForChild.getTag().equals("location")) { - final String location = uidlForChild.getStringAttribute("name"); - final Paintable child = client.getPaintable(uidlForChild - .getChildUIDL(0)); - try { - setWidget((Widget) child, location); - child.updateFromUIDL(uidlForChild.getChildUIDL(0), client); - } catch (final IllegalArgumentException e) { - // If no location is found, this component is not visible - } - oldWidgets.remove(child); - } - } - for (Iterator<Widget> iterator = oldWidgets.iterator(); iterator - .hasNext();) { - Widget oldWidget = iterator.next(); - if (oldWidget.isAttached()) { - // slot of this widget is emptied, remove it - remove(oldWidget); - } - } - - iLayout(); - // TODO Check if this is needed - client.runDescendentsLayout(this); - - } - /** Initialize HTML-layout. */ - private void initializeHTML(UIDL uidl, ApplicationConnection client) { - - final String newTemplateContents = uidl - .getStringAttribute("templateContents"); - final String newTemplate = uidl.getStringAttribute("template"); - - currentTemplateName = null; - hasTemplateContents = false; - - String template = ""; - if (newTemplate != null) { - // Get the HTML-template from client - template = client.getResource("layouts/" + newTemplate + ".html"); - if (template == null) { - template = "<em>Layout file layouts/" - + newTemplate - + ".html is missing. Components will be drawn for debug purposes.</em>"; - } else { - currentTemplateName = newTemplate; - } - } else { - hasTemplateContents = true; - template = newTemplateContents; - } + public void initializeHTML(String template, String themeUri) { // Connect body of the template to DOM template = extractBodyAndScriptsFromTemplate(template); // TODO prefix img src:s here with a regeps, cannot work further with IE - String themeUri = client.getThemeUri(); String relImgPrefix = themeUri + "/layouts/"; // prefix all relative image elements to point to theme dir with a @@ -251,6 +160,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable, } publishResizedFunction(elementWithNativeResizeFunction); + htmlInitialized = true; } private native boolean uriEndsWithSlash() @@ -261,12 +171,8 @@ public class VCustomLayout extends ComplexPanel implements Paintable, return false; }-*/; - private boolean hasTemplate() { - if (currentTemplateName == null && !hasTemplateContents) { - return false; - } else { - return true; - } + boolean hasTemplate() { + return htmlInitialized; } /** Collect locations from template */ @@ -276,12 +182,6 @@ public class VCustomLayout extends ComplexPanel implements Paintable, if (!"".equals(location)) { locationToElement.put(location, elem); elem.setInnerHTML(""); - int x = Util.measureHorizontalPaddingAndBorder(elem, 0); - int y = Util.measureVerticalPaddingAndBorder(elem, 0); - - FloatSize fs = new FloatSize(x, y); - - locationToExtraSize.put(location, fs); } else { final int len = DOM.getChildCount(elem); @@ -292,7 +192,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable, } /** Evaluate given script in browser document */ - private static native void eval(String script) + static native void eval(String script) /*-{ try { if (script != null) @@ -369,39 +269,27 @@ public class VCustomLayout extends ComplexPanel implements Paintable, return res; } - /** Replace child components */ - public void replaceChildComponent(Widget from, Widget to) { - final String location = getLocation(from); - if (location == null) { - throw new IllegalArgumentException(); - } - setWidget(to, location); - } - - /** Does this layout contain given child */ - public boolean hasChildComponent(Widget component) { - return locationToWidget.containsValue(component); - } - /** Update caption for given widget */ - public void updateCaption(Paintable component, UIDL uidl) { - VCaptionWrapper wrapper = widgetToCaptionWrapper.get(component); - if (VCaption.isNeeded(uidl)) { + public void updateCaption(ComponentConnector paintable) { + Widget widget = paintable.getWidget(); + VCaptionWrapper wrapper = childWidgetToCaptionWrapper.get(widget); + if (VCaption.isNeeded(paintable.getState())) { if (wrapper == null) { - final String loc = getLocation((Widget) component); - super.remove((Widget) component); - wrapper = new VCaptionWrapper(component, client); + // Add a wrapper between the layout and the child widget + final String loc = getLocation(widget); + super.remove(widget); + wrapper = new VCaptionWrapper(paintable, client); super.add(wrapper, locationToElement.get(loc)); - widgetToCaptionWrapper.put(component, wrapper); + childWidgetToCaptionWrapper.put(widget, wrapper); } - wrapper.updateCaption(uidl); + wrapper.updateCaption(); } else { if (wrapper != null) { - final String loc = getLocation((Widget) component); + // Remove the wrapper and add the widget directly to the layout + final String loc = getLocation(widget); super.remove(wrapper); - super.add((Widget) wrapper.getPaintable(), - locationToElement.get(loc)); - widgetToCaptionWrapper.remove(component); + super.add(widget, locationToElement.get(loc)); + childWidgetToCaptionWrapper.remove(widget); } } } @@ -421,14 +309,13 @@ public class VCustomLayout extends ComplexPanel implements Paintable, /** Removes given widget from the layout */ @Override public boolean remove(Widget w) { - client.unregisterPaintable((Paintable) w); final String location = getLocation(w); if (location != null) { locationToWidget.remove(location); } - final VCaptionWrapper cw = widgetToCaptionWrapper.get(w); + final VCaptionWrapper cw = childWidgetToCaptionWrapper.get(w); if (cw != null) { - widgetToCaptionWrapper.remove(w); + childWidgetToCaptionWrapper.remove(w); return super.remove(cw); } else if (w != null) { return super.remove(w); @@ -447,11 +334,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable, public void clear() { super.clear(); locationToWidget.clear(); - widgetToCaptionWrapper.clear(); - } - - public void iLayout() { - iLayoutJS(DOM.getFirstChild(getElement())); + childWidgetToCaptionWrapper.clear(); } /** @@ -480,7 +363,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable, /*-{ var self = this; element.notifyChildrenOfSizeChange = $entry(function() { - self.@com.vaadin.terminal.gwt.client.ui.VCustomLayout::notifyChildrenOfSizeChange()(); + self.@com.vaadin.terminal.gwt.client.ui.customlayout.VCustomLayout::notifyChildrenOfSizeChange()(); }); }-*/; @@ -499,7 +382,7 @@ public class VCustomLayout extends ComplexPanel implements Paintable, * @return true if layout function exists and was run successfully, else * false. */ - private native boolean iLayoutJS(Element el) + native boolean iLayoutJS(Element el) /*-{ if(el && el.iLayoutJS) { try { @@ -513,27 +396,6 @@ public class VCustomLayout extends ComplexPanel implements Paintable, } }-*/; - public boolean requestLayout(Set<Paintable> child) { - updateRelativeSizedComponents(true, true); - - if (width.equals("") || height.equals("")) { - /* Automatically propagated upwards if the size can change */ - return false; - } - - return true; - } - - public RenderSpace getAllocatedSpace(Widget child) { - com.google.gwt.dom.client.Element pe = child.getElement() - .getParentElement(); - - FloatSize extra = locationToExtraSize.get(getLocation(child)); - return new RenderSpace(pe.getOffsetWidth() - (int) extra.getWidth(), - pe.getOffsetHeight() - (int) extra.getHeight(), - Util.mayHaveScrollBars(pe)); - } - @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); @@ -543,103 +405,4 @@ public class VCustomLayout extends ComplexPanel implements Paintable, } } - @Override - public void setHeight(String height) { - if (this.height.equals(height)) { - return; - } - - boolean shrinking = true; - if (isLarger(height, this.height)) { - shrinking = false; - } - - this.height = height; - super.setHeight(height); - - /* - * If the height shrinks we must remove all components with relative - * height from the DOM, update their height when they do not affect the - * available space and finally restore them to the original state - */ - if (shrinking) { - updateRelativeSizedComponents(false, true); - } - } - - @Override - public void setWidth(String width) { - if (this.width.equals(width)) { - return; - } - - boolean shrinking = true; - if (isLarger(width, this.width)) { - shrinking = false; - } - - super.setWidth(width); - this.width = width; - - /* - * If the width shrinks we must remove all components with relative - * width from the DOM, update their width when they do not affect the - * available space and finally restore them to the original state - */ - if (shrinking) { - updateRelativeSizedComponents(true, false); - } - } - - private void updateRelativeSizedComponents(boolean relativeWidth, - boolean relativeHeight) { - - Set<Widget> relativeSizeWidgets = new HashSet<Widget>(); - - for (Widget widget : locationToWidget.values()) { - FloatSize relativeSize = client.getRelativeSize(widget); - if (relativeSize != null) { - if ((relativeWidth && (relativeSize.getWidth() >= 0.0f)) - || (relativeHeight && (relativeSize.getHeight() >= 0.0f))) { - - relativeSizeWidgets.add(widget); - widget.getElement().getStyle() - .setProperty("position", "absolute"); - } - } - } - - for (Widget widget : relativeSizeWidgets) { - client.handleComponentRelativeSize(widget); - widget.getElement().getStyle().setProperty("position", ""); - } - } - - /** - * Compares newSize with currentSize and returns true if it is clear that - * newSize is larger than currentSize. Returns false if newSize is smaller - * or if it is unclear which one is smaller. - * - * @param newSize - * @param currentSize - * @return - */ - private boolean isLarger(String newSize, String currentSize) { - if (newSize.equals("") || currentSize.equals("")) { - return false; - } - - if (!newSize.endsWith("px") || !currentSize.endsWith("px")) { - return false; - } - - int newSizePx = Integer.parseInt(newSize.substring(0, - newSize.length() - 2)); - int currentSizePx = Integer.parseInt(currentSize.substring(0, - currentSize.length() - 2)); - - boolean larger = newSizePx > currentSizePx; - return larger; - } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java new file mode 100644 index 0000000000..e19d9b996f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/AbstractDateFieldConnector.java @@ -0,0 +1,109 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.datefield; + +import java.util.Date; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; + +public class AbstractDateFieldConnector extends AbstractFieldConnector + implements Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + + // Save details + getWidget().client = client; + getWidget().paintableId = uidl.getId(); + getWidget().immediate = getState().isImmediate(); + + getWidget().readonly = isReadOnly(); + getWidget().enabled = isEnabled(); + + if (uidl.hasAttribute("locale")) { + final String locale = uidl.getStringAttribute("locale"); + try { + getWidget().dts.setLocale(locale); + getWidget().currentLocale = locale; + } catch (final LocaleNotLoadedException e) { + getWidget().currentLocale = getWidget().dts.getLocale(); + VConsole.error("Tried to use an unloaded locale \"" + locale + + "\". Using default locale (" + + getWidget().currentLocale + ")."); + VConsole.error(e); + } + } + + // We show week numbers only if the week starts with Monday, as ISO 8601 + // specifies + getWidget().showISOWeekNumbers = uidl + .getBooleanAttribute(VDateField.WEEK_NUMBERS) + && getWidget().dts.getFirstDayOfWeek() == 1; + + int newResolution; + if (uidl.hasVariable("sec")) { + newResolution = VDateField.RESOLUTION_SEC; + } else if (uidl.hasVariable("min")) { + newResolution = VDateField.RESOLUTION_MIN; + } else if (uidl.hasVariable("hour")) { + newResolution = VDateField.RESOLUTION_HOUR; + } else if (uidl.hasVariable("day")) { + newResolution = VDateField.RESOLUTION_DAY; + } else if (uidl.hasVariable("month")) { + newResolution = VDateField.RESOLUTION_MONTH; + } else { + newResolution = VDateField.RESOLUTION_YEAR; + } + + getWidget().currentResolution = newResolution; + + // Add stylename that indicates current resolution + getWidget() + .addStyleName( + VDateField.CLASSNAME + + "-" + + VDateField + .resolutionToString(getWidget().currentResolution)); + + final int year = uidl.getIntVariable("year"); + final int month = (getWidget().currentResolution >= VDateField.RESOLUTION_MONTH) ? uidl + .getIntVariable("month") : -1; + final int day = (getWidget().currentResolution >= VDateField.RESOLUTION_DAY) ? uidl + .getIntVariable("day") : -1; + final int hour = (getWidget().currentResolution >= VDateField.RESOLUTION_HOUR) ? uidl + .getIntVariable("hour") : 0; + final int min = (getWidget().currentResolution >= VDateField.RESOLUTION_MIN) ? uidl + .getIntVariable("min") : 0; + final int sec = (getWidget().currentResolution >= VDateField.RESOLUTION_SEC) ? uidl + .getIntVariable("sec") : 0; + + // Construct new date for this datefield (only if not null) + if (year > -1) { + getWidget().setCurrentDate( + new Date((long) getWidget().getTime(year, month, day, hour, + min, sec, 0))); + } else { + getWidget().setCurrentDate(null); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VDateField.class); + } + + @Override + public VDateField getWidget() { + return (VDateField) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/InlineDateFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/InlineDateFieldConnector.java new file mode 100644 index 0000000000..8a4840a088 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/InlineDateFieldConnector.java @@ -0,0 +1,104 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.datefield; + +import java.util.Date; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.DateTimeService; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.FocusChangeListener; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.TimeChangeListener; +import com.vaadin.ui.InlineDateField; + +@Connect(InlineDateField.class) +public class InlineDateFieldConnector extends AbstractDateFieldConnector { + + @Override + @SuppressWarnings("deprecation") + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + super.updateFromUIDL(uidl, client); + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().calendarPanel.setShowISOWeekNumbers(getWidget() + .isShowISOWeekNumbers()); + getWidget().calendarPanel.setDateTimeService(getWidget() + .getDateTimeService()); + getWidget().calendarPanel.setResolution(getWidget() + .getCurrentResolution()); + Date currentDate = getWidget().getCurrentDate(); + if (currentDate != null) { + getWidget().calendarPanel.setDate(new Date(currentDate.getTime())); + } else { + getWidget().calendarPanel.setDate(null); + } + + if (getWidget().currentResolution > VDateField.RESOLUTION_DAY) { + getWidget().calendarPanel + .setTimeChangeListener(new TimeChangeListener() { + public void changed(int hour, int min, int sec, int msec) { + Date d = getWidget().getDate(); + if (d == null) { + // date currently null, use the value from + // calendarPanel + // (~ client time at the init of the widget) + d = (Date) getWidget().calendarPanel.getDate() + .clone(); + } + d.setHours(hour); + d.setMinutes(min); + d.setSeconds(sec); + DateTimeService.setMilliseconds(d, msec); + + // Always update time changes to the server + getWidget().calendarPanel.setDate(d); + getWidget().updateValueFromPanel(); + } + }); + } + + if (getWidget().currentResolution <= VDateField.RESOLUTION_MONTH) { + getWidget().calendarPanel + .setFocusChangeListener(new FocusChangeListener() { + public void focusChanged(Date date) { + Date date2 = new Date(); + if (getWidget().calendarPanel.getDate() != null) { + date2.setTime(getWidget().calendarPanel + .getDate().getTime()); + } + /* + * Update the value of calendarPanel + */ + date2.setYear(date.getYear()); + date2.setMonth(date.getMonth()); + getWidget().calendarPanel.setDate(date2); + /* + * Then update the value from panel to server + */ + getWidget().updateValueFromPanel(); + } + }); + } else { + getWidget().calendarPanel.setFocusChangeListener(null); + } + + // Update possible changes + getWidget().calendarPanel.renderCalendar(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VDateFieldCalendar.class); + } + + @Override + public VDateFieldCalendar getWidget() { + return (VDateFieldCalendar) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java new file mode 100644 index 0000000000..1bcb40d549 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/PopupDateFieldConnector.java @@ -0,0 +1,124 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.datefield; + +import java.util.Date; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.DateTimeService; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.FocusChangeListener; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.TimeChangeListener; +import com.vaadin.ui.DateField; + +@Connect(DateField.class) +public class PopupDateFieldConnector extends TextualDateConnector { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin + * .terminal.gwt.client.UIDL, + * com.vaadin.terminal.gwt.client.ApplicationConnection) + */ + @Override + @SuppressWarnings("deprecation") + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + boolean lastReadOnlyState = getWidget().readonly; + boolean lastEnabledState = getWidget().isEnabled(); + + getWidget().parsable = uidl.getBooleanAttribute("parsable"); + + super.updateFromUIDL(uidl, client); + + String popupStyleNames = getStyleNames(VPopupCalendar.POPUP_PRIMARY_STYLE_NAME); + popupStyleNames += " " + + VDateField.CLASSNAME + + "-" + + VPopupCalendar + .resolutionToString(getWidget().currentResolution); + getWidget().popup.setStyleName(popupStyleNames); + + getWidget().calendar.setDateTimeService(getWidget() + .getDateTimeService()); + getWidget().calendar.setShowISOWeekNumbers(getWidget() + .isShowISOWeekNumbers()); + if (getWidget().calendar.getResolution() != getWidget().currentResolution) { + getWidget().calendar.setResolution(getWidget().currentResolution); + if (getWidget().calendar.getDate() != null) { + getWidget().calendar.setDate((Date) getWidget() + .getCurrentDate().clone()); + // force re-render when changing resolution only + getWidget().calendar.renderCalendar(); + } + } + getWidget().calendarToggle.setEnabled(getWidget().enabled); + + if (getWidget().currentResolution <= VPopupCalendar.RESOLUTION_MONTH) { + getWidget().calendar + .setFocusChangeListener(new FocusChangeListener() { + public void focusChanged(Date date) { + getWidget().updateValue(date); + getWidget().buildDate(); + Date date2 = getWidget().calendar.getDate(); + date2.setYear(date.getYear()); + date2.setMonth(date.getMonth()); + } + }); + } else { + getWidget().calendar.setFocusChangeListener(null); + } + + if (getWidget().currentResolution > VPopupCalendar.RESOLUTION_DAY) { + getWidget().calendar + .setTimeChangeListener(new TimeChangeListener() { + public void changed(int hour, int min, int sec, int msec) { + Date d = getWidget().getDate(); + if (d == null) { + // date currently null, use the value from + // calendarPanel + // (~ client time at the init of the widget) + d = (Date) getWidget().calendar.getDate() + .clone(); + } + d.setHours(hour); + d.setMinutes(min); + d.setSeconds(sec); + DateTimeService.setMilliseconds(d, msec); + + // Always update time changes to the server + getWidget().updateValue(d); + + // Update text field + getWidget().buildDate(); + } + }); + } + + if (getWidget().readonly) { + getWidget().calendarToggle.addStyleName(VPopupCalendar.CLASSNAME + + "-button-readonly"); + } else { + getWidget().calendarToggle.removeStyleName(VPopupCalendar.CLASSNAME + + "-button-readonly"); + } + + getWidget().calendarToggle.setEnabled(true); + } + + @Override + protected Widget createWidget() { + return GWT.create(VPopupCalendar.class); + } + + @Override + public VPopupCalendar getWidget() { + return (VPopupCalendar) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/datefield/TextualDateConnector.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/TextualDateConnector.java new file mode 100644 index 0000000000..90679f5705 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/TextualDateConnector.java @@ -0,0 +1,56 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.datefield; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.UIDL; + +public class TextualDateConnector extends AbstractDateFieldConnector { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + int origRes = getWidget().currentResolution; + String oldLocale = getWidget().currentLocale; + super.updateFromUIDL(uidl, client); + if (origRes != getWidget().currentResolution + || oldLocale != getWidget().currentLocale) { + // force recreating format string + getWidget().formatStr = null; + } + if (uidl.hasAttribute("format")) { + getWidget().formatStr = uidl.getStringAttribute("format"); + } + + getWidget().inputPrompt = uidl + .getStringAttribute(VTextualDate.ATTR_INPUTPROMPT); + + getWidget().lenient = !uidl.getBooleanAttribute("strict"); + + getWidget().buildDate(); + // not a FocusWidget -> needs own tabindex handling + if (uidl.hasAttribute("tabindex")) { + getWidget().text.setTabIndex(uidl.getIntAttribute("tabindex")); + } + + if (getWidget().readonly) { + getWidget().text.addStyleDependentName("readonly"); + } else { + getWidget().text.removeStyleDependentName("readonly"); + } + + } + + @Override + protected Widget createWidget() { + return GWT.create(VTextualDate.class); + } + + @Override + public VTextualDate getWidget() { + return (VTextualDate) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VCalendarPanel.java index 845ac837f6..acfff60d53 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VCalendarPanel.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.datefield; import java.util.Date; import java.util.Iterator; @@ -40,6 +40,10 @@ import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.DateTimeService; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.FocusableFlexTable; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.label.VLabel; +import com.vaadin.terminal.gwt.client.ui.nativeselect.VNativeSelect; @SuppressWarnings("deprecation") public class VCalendarPanel extends FocusableFlexTable implements @@ -1139,7 +1143,7 @@ public class VCalendarPanel extends FocusableFlexTable implements // elapsed, another timer is triggered to go off every 150ms. Both // timers are cancelled on mouseup or mouseout. if (event.getSource() instanceof VEventButton) { - final Widget sender = (Widget) event.getSource(); + final VEventButton sender = (VEventButton) event.getSource(); processClickEvent(sender); mouseTimer = new Timer() { @Override @@ -1228,8 +1232,6 @@ public class VCalendarPanel extends FocusableFlexTable implements private ListBox sec; - private ListBox msec; - private ListBox ampm; /** @@ -1294,19 +1296,6 @@ public class VCalendarPanel extends FocusableFlexTable implements } sec.addChangeHandler(this); } - if (getResolution() == VDateField.RESOLUTION_MSEC) { - msec = createListBox(); - for (int i = 0; i < 1000; i++) { - if (i < 10) { - msec.addItem("00" + i); - } else if (i < 100) { - msec.addItem("0" + i); - } else { - msec.addItem("" + i); - } - } - msec.addChangeHandler(this); - } final String delimiter = getDateTimeService().getClockDelimeter(); if (isReadonly()) { @@ -1340,16 +1329,6 @@ public class VCalendarPanel extends FocusableFlexTable implements add(sec); } } - if (getResolution() == VDateField.RESOLUTION_MSEC) { - add(new VLabel(".")); - if (isReadonly()) { - final int m = getMilliseconds(); - final String ms = m < 100 ? "0" + m : "" + m; - add(new VLabel(m < 10 ? "0" + ms : ms)); - } else { - add(msec); - } - } if (getResolution() == VDateField.RESOLUTION_HOUR) { add(new VLabel(delimiter + "00")); // o'clock } @@ -1425,13 +1404,6 @@ public class VCalendarPanel extends FocusableFlexTable implements if (getResolution() >= VDateField.RESOLUTION_SEC) { sec.setSelectedIndex(value.getSeconds()); } - if (getResolution() == VDateField.RESOLUTION_MSEC) { - if (selected) { - msec.setSelectedIndex(getMilliseconds()); - } else { - msec.setSelectedIndex(0); - } - } if (getDateTimeService().isTwelveHourClock()) { ampm.setSelectedIndex(value.getHours() < 12 ? 0 : 1); } @@ -1443,9 +1415,6 @@ public class VCalendarPanel extends FocusableFlexTable implements if (sec != null) { sec.setEnabled(isEnabled()); } - if (msec != null) { - msec.setEnabled(isEnabled()); - } if (ampm != null) { ampm.setEnabled(isEnabled()); } @@ -1508,15 +1477,6 @@ public class VCalendarPanel extends FocusableFlexTable implements } event.preventDefault(); event.stopPropagation(); - } else if (event.getSource() == msec) { - final int ms = msec.getSelectedIndex(); - DateTimeService.setMilliseconds(value, ms); - if (timeChangeListener != null) { - timeChangeListener.changed(value.getHours(), - value.getMinutes(), value.getSeconds(), ms); - } - event.preventDefault(); - event.stopPropagation(); } else if (event.getSource() == ampm) { final int h = hours.getSelectedIndex() + (ampm.getSelectedIndex() * 12); @@ -1699,8 +1659,6 @@ public class VCalendarPanel extends FocusableFlexTable implements return SUBPART_MINUTE_SELECT; } else if (contains(time.sec, subElement)) { return SUBPART_SECS_SELECT; - } else if (contains(time.msec, subElement)) { - return SUBPART_MSECS_SELECT; } else if (contains(time.ampm, subElement)) { return SUBPART_AMPM_SELECT; @@ -1749,9 +1707,6 @@ public class VCalendarPanel extends FocusableFlexTable implements if (SUBPART_SECS_SELECT.equals(subPart)) { return time.sec.getElement(); } - if (SUBPART_MSECS_SELECT.equals(subPart)) { - return time.msec.getElement(); - } if (SUBPART_AMPM_SELECT.equals(subPart)) { return time.ampm.getElement(); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateField.java index bc228675b2..d169b1b47e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateField.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.datefield; import java.util.Date; @@ -10,19 +10,16 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.FlowPanel; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Field; -public class VDateField extends FlowPanel implements Paintable, Field { +public class VDateField extends FlowPanel implements Field { public static final String CLASSNAME = "v-datefield"; - private String id; + protected String paintableId; - private ApplicationConnection client; + protected ApplicationConnection client; protected boolean immediate; @@ -32,7 +29,6 @@ public class VDateField extends FlowPanel implements Paintable, Field { public static final int RESOLUTION_HOUR = 8; public static final int RESOLUTION_MIN = 16; public static final int RESOLUTION_SEC = 32; - public static final int RESOLUTION_MSEC = 64; public static final String WEEK_NUMBERS = "wn"; @@ -65,7 +61,7 @@ public class VDateField extends FlowPanel implements Paintable, Field { protected DateTimeService dts; - private boolean showISOWeekNumbers = false; + protected boolean showISOWeekNumbers = false; public VDateField() { setStyleName(CLASSNAME); @@ -81,88 +77,11 @@ public class VDateField extends FlowPanel implements Paintable, Field { } } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Ensure correct implementation and let layout manage caption - if (client.updateComponent(this, uidl, true)) { - return; - } - - // Save details - this.client = client; - id = uidl.getId(); - immediate = uidl.getBooleanAttribute("immediate"); - - readonly = uidl.getBooleanAttribute("readonly"); - enabled = !uidl.getBooleanAttribute("disabled"); - - if (uidl.hasAttribute("locale")) { - final String locale = uidl.getStringAttribute("locale"); - try { - dts.setLocale(locale); - currentLocale = locale; - } catch (final LocaleNotLoadedException e) { - currentLocale = dts.getLocale(); - VConsole.error("Tried to use an unloaded locale \"" + locale - + "\". Using default locale (" + currentLocale + ")."); - VConsole.error(e); - } - } - - // We show week numbers only if the week starts with Monday, as ISO 8601 - // specifies - showISOWeekNumbers = uidl.getBooleanAttribute(WEEK_NUMBERS) - && dts.getFirstDayOfWeek() == 1; - - int newResolution; - if (uidl.hasVariable("msec")) { - newResolution = RESOLUTION_MSEC; - } else if (uidl.hasVariable("sec")) { - newResolution = RESOLUTION_SEC; - } else if (uidl.hasVariable("min")) { - newResolution = RESOLUTION_MIN; - } else if (uidl.hasVariable("hour")) { - newResolution = RESOLUTION_HOUR; - } else if (uidl.hasVariable("day")) { - newResolution = RESOLUTION_DAY; - } else if (uidl.hasVariable("month")) { - newResolution = RESOLUTION_MONTH; - } else { - newResolution = RESOLUTION_YEAR; - } - - currentResolution = newResolution; - - // Add stylename that indicates current resolution - addStyleName(CLASSNAME + "-" + resolutionToString(currentResolution)); - - final int year = uidl.getIntVariable("year"); - final int month = (currentResolution >= RESOLUTION_MONTH) ? uidl - .getIntVariable("month") : -1; - final int day = (currentResolution >= RESOLUTION_DAY) ? uidl - .getIntVariable("day") : -1; - final int hour = (currentResolution >= RESOLUTION_HOUR) ? uidl - .getIntVariable("hour") : 0; - final int min = (currentResolution >= RESOLUTION_MIN) ? uidl - .getIntVariable("min") : 0; - final int sec = (currentResolution >= RESOLUTION_SEC) ? uidl - .getIntVariable("sec") : 0; - final int msec = (currentResolution >= RESOLUTION_MSEC) ? uidl - .getIntVariable("msec") : 0; - - // Construct new date for this datefield (only if not null) - if (year > -1) { - setCurrentDate(new Date((long) getTime(year, month, day, hour, min, - sec, msec))); - } else { - setCurrentDate(null); - } - } - /* * We need this redundant native function because Java's Date object doesn't * have a setMilliseconds method. */ - private static native double getTime(int y, int m, int d, int h, int mi, + protected static native double getTime(int y, int m, int d, int h, int mi, int s, int ms) /*-{ try { @@ -231,7 +150,7 @@ public class VDateField extends FlowPanel implements Paintable, Field { } public String getId() { - return id; + return paintableId; } public ApplicationConnection getClient() { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java index 91388edcaf..21e0e0820d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VDateFieldCalendar.java @@ -2,25 +2,21 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.datefield; import java.util.Date; import com.google.gwt.event.dom.client.DomEvent; -import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.FocusOutListener; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.SubmitListener; /** * A client side implementation for InlineDateField */ public class VDateFieldCalendar extends VDateField { - private final VCalendarPanel calendarPanel; + protected final VCalendarPanel calendarPanel; public VDateFieldCalendar() { super(); @@ -44,73 +40,11 @@ public class VDateFieldCalendar extends VDateField { }); } - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - super.updateFromUIDL(uidl, client); - calendarPanel.setShowISOWeekNumbers(isShowISOWeekNumbers()); - calendarPanel.setDateTimeService(getDateTimeService()); - calendarPanel.setResolution(getCurrentResolution()); - Date currentDate = getCurrentDate(); - if (currentDate != null) { - calendarPanel.setDate(new Date(currentDate.getTime())); - } else { - calendarPanel.setDate(null); - } - - if (currentResolution > RESOLUTION_DAY) { - calendarPanel.setTimeChangeListener(new TimeChangeListener() { - public void changed(int hour, int min, int sec, int msec) { - Date d = getDate(); - if (d == null) { - // date currently null, use the value from calendarPanel - // (~ client time at the init of the widget) - d = (Date) calendarPanel.getDate().clone(); - } - d.setHours(hour); - d.setMinutes(min); - d.setSeconds(sec); - DateTimeService.setMilliseconds(d, msec); - - // Always update time changes to the server - calendarPanel.setDate(d); - updateValueFromPanel(); - } - }); - } - - if (currentResolution <= RESOLUTION_MONTH) { - calendarPanel.setFocusChangeListener(new FocusChangeListener() { - public void focusChanged(Date date) { - Date date2 = new Date(); - if (calendarPanel.getDate() != null) { - date2.setTime(calendarPanel.getDate().getTime()); - } - /* - * Update the value of calendarPanel - */ - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - calendarPanel.setDate(date2); - /* - * Then update the value from panel to server - */ - updateValueFromPanel(); - } - }); - } else { - calendarPanel.setFocusChangeListener(null); - } - - // Update possible changes - calendarPanel.renderCalendar(); - } - /** * TODO refactor: almost same method as in VPopupCalendar.updateValue */ @SuppressWarnings("deprecation") - private void updateValueFromPanel() { + protected void updateValueFromPanel() { Date date2 = calendarPanel.getDate(); Date currentDate = getCurrentDate(); if (currentDate == null || date2.getTime() != currentDate.getTime()) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VPopupCalendar.java index 8bf2f6bfbf..7011e5358b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VPopupCalendar.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.datefield; import java.util.Date; @@ -21,16 +21,13 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; -import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; -import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.FocusOutListener; +import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.SubmitListener; /** * Represents a date selection component with a text field and a popup date @@ -42,19 +39,19 @@ import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; * <code>setCalendarPanel(VCalendarPanel panel)</code> method. * */ -public class VPopupCalendar extends VTextualDate implements Paintable, Field, +public class VPopupCalendar extends VTextualDate implements Field, ClickHandler, CloseHandler<PopupPanel>, SubPartAware { - private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME + protected static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME + "-popup"; - private final Button calendarToggle; + protected final Button calendarToggle; - private VCalendarPanel calendar; + protected VCalendarPanel calendar; - private final VOverlay popup; + protected final VOverlay popup; private boolean open = false; - private boolean parsable = true; + protected boolean parsable = true; public VPopupCalendar() { super(); @@ -105,7 +102,7 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field, } @SuppressWarnings("deprecation") - private void updateValue(Date newDate) { + protected void updateValue(Date newDate) { Date currentDate = getCurrentDate(); if (currentDate == null || newDate.getTime() != currentDate.getTime()) { setCurrentDate((Date) newDate.clone()); @@ -126,14 +123,6 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field, if (getCurrentResolution() > RESOLUTION_MIN) { getClient().updateVariable(getId(), "sec", newDate.getSeconds(), false); - if (getCurrentResolution() == RESOLUTION_MSEC) { - getClient().updateVariable( - getId(), - "msec", - DateTimeService - .getMilliseconds(newDate), - false); - } } } } @@ -149,96 +138,6 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field, * (non-Javadoc) * * @see - * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin - * .terminal.gwt.client.UIDL, - * com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - boolean lastReadOnlyState = readonly; - boolean lastEnabledState = isEnabled(); - - parsable = uidl.getBooleanAttribute("parsable"); - - super.updateFromUIDL(uidl, client); - - String popupStyleNames = ApplicationConnection.getStyleName( - POPUP_PRIMARY_STYLE_NAME, uidl, false); - popupStyleNames += " " + VDateField.CLASSNAME + "-" - + resolutionToString(currentResolution); - popup.setStyleName(popupStyleNames); - - calendar.setDateTimeService(getDateTimeService()); - calendar.setShowISOWeekNumbers(isShowISOWeekNumbers()); - if (calendar.getResolution() != currentResolution) { - calendar.setResolution(currentResolution); - if (calendar.getDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - // force re-render when changing resolution only - calendar.renderCalendar(); - } - } - calendarToggle.setEnabled(enabled); - - if (currentResolution <= RESOLUTION_MONTH) { - calendar.setFocusChangeListener(new FocusChangeListener() { - public void focusChanged(Date date) { - updateValue(date); - buildDate(); - Date date2 = calendar.getDate(); - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - } - }); - } else { - calendar.setFocusChangeListener(null); - } - - if (currentResolution > RESOLUTION_DAY) { - calendar.setTimeChangeListener(new TimeChangeListener() { - public void changed(int hour, int min, int sec, int msec) { - Date d = getDate(); - if (d == null) { - // date currently null, use the value from calendarPanel - // (~ client time at the init of the widget) - d = (Date) calendar.getDate().clone(); - } - d.setHours(hour); - d.setMinutes(min); - d.setSeconds(sec); - DateTimeService.setMilliseconds(d, msec); - - // Always update time changes to the server - updateValue(d); - - // Update text field - buildDate(); - } - }); - } - - if (readonly) { - calendarToggle.addStyleName(CLASSNAME + "-button-readonly"); - } else { - calendarToggle.removeStyleName(CLASSNAME + "-button-readonly"); - } - - if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) { - // Enabled or readonly state changed. Differences in theming might - // affect the width (for instance if the popup button is hidden) so - // we have to recalculate the width (IF the width of the field is - // fixed) - updateWidth(); - } - - calendarToggle.setEnabled(true); - } - - /* - * (non-Javadoc) - * - * @see * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String) */ @Override @@ -276,7 +175,7 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field, int l = calendarToggle.getAbsoluteLeft(); // Add a little extra space to the right to avoid - // problems with IE6/IE7 scrollbars and to make it look + // problems with IE7 scrollbars and to make it look // nicer. int extraSpace = 30; @@ -381,20 +280,6 @@ public class VPopupCalendar extends VTextualDate implements Paintable, Field, /* * (non-Javadoc) * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth() - */ - @Override - protected int getFieldExtraWidth() { - if (fieldExtraWidth < 0) { - fieldExtraWidth = super.getFieldExtraWidth(); - fieldExtraWidth += calendarToggle.getOffsetWidth(); - } - return fieldExtraWidth; - } - - /* - * (non-Javadoc) - * * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate() */ @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java b/src/com/vaadin/terminal/gwt/client/ui/datefield/VTextualDate.java index 56cdf05ddb..db4eca152a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java +++ b/src/com/vaadin/terminal/gwt/client/ui/datefield/VTextualDate.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.datefield; import java.util.Date; @@ -12,41 +12,32 @@ import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.TextBox; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.ContainerResizedListener; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; import com.vaadin.terminal.gwt.client.LocaleService; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; -public class VTextualDate extends VDateField implements Paintable, Field, - ChangeHandler, ContainerResizedListener, Focusable, SubPartAware { +public class VTextualDate extends VDateField implements Field, ChangeHandler, + Focusable, SubPartAware { private static final String PARSE_ERROR_CLASSNAME = CLASSNAME + "-parseerror"; - private final TextBox text; + protected final TextBox text; - private String formatStr; + protected String formatStr; - private String width; - - private boolean needLayout; - - protected int fieldExtraWidth = -1; - - private boolean lenient; + protected boolean lenient; private static final String CLASSNAME_PROMPT = "prompt"; - private static final String ATTR_INPUTPROMPT = "prompt"; - private String inputPrompt = ""; + protected static final String ATTR_INPUTPROMPT = "prompt"; + protected String inputPrompt = ""; private boolean prompting = false; public VTextualDate() { @@ -94,37 +85,6 @@ public class VTextualDate extends VDateField implements Paintable, Field, add(text); } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - int origRes = currentResolution; - String oldLocale = currentLocale; - super.updateFromUIDL(uidl, client); - if (origRes != currentResolution || oldLocale != currentLocale) { - // force recreating format string - formatStr = null; - } - if (uidl.hasAttribute("format")) { - formatStr = uidl.getStringAttribute("format"); - } - - inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT); - - lenient = !uidl.getBooleanAttribute("strict"); - - buildDate(); - // not a FocusWidget -> needs own tabindex handling - if (uidl.hasAttribute("tabindex")) { - text.setTabIndex(uidl.getIntAttribute("tabindex")); - } - - if (readonly) { - text.addStyleDependentName("readonly"); - } else { - text.removeStyleDependentName("readonly"); - } - - } - protected String getFormatString() { if (formatStr == null) { if (currentResolution == RESOLUTION_YEAR) { @@ -148,9 +108,6 @@ public class VTextualDate extends VDateField implements Paintable, Field, frmString += ":mm"; if (currentResolution >= RESOLUTION_SEC) { frmString += ":ss"; - if (currentResolution >= RESOLUTION_MSEC) { - frmString += ".SSS"; - } } } if (dts.isTwelveHourClock()) { @@ -300,10 +257,6 @@ public class VTextualDate extends VDateField implements Paintable, Field, currentResolution == VDateField.RESOLUTION_SEC && immediate); } - if (currentResolution == VDateField.RESOLUTION_MSEC) { - getClient().updateVariable(getId(), "msec", - currentDate != null ? getMilliseconds() : -1, immediate); - } } @@ -338,83 +291,6 @@ public class VTextualDate extends VDateField implements Paintable, Field, return format.trim(); } - @Override - public void setWidth(String newWidth) { - if (!"".equals(newWidth) && (isUndefinedWidth() || !newWidth.equals(width))) { - if (BrowserInfo.get().isIE6()) { - // in IE6 cols ~ min-width - DOM.setElementProperty(text.getElement(), "size", "1"); - } - needLayout = true; - width = newWidth; - super.setWidth(width); - iLayout(); - if (newWidth.indexOf("%") < 0) { - needLayout = false; - } - } else { - if ("".equals(newWidth) && !isUndefinedWidth()) { - // Changing from defined to undefined - if (BrowserInfo.get().isIE6()) { - // revert IE6 hack - DOM.setElementProperty(text.getElement(), "size", ""); - } - super.setWidth(""); - iLayout(true); - width = null; - } - } - } - protected boolean isUndefinedWidth() { - return width == null || "".equals(width); - } - - /** - * Returns pixels in x-axis reserved for other than textfield content. - * - * @return extra width in pixels - */ - protected int getFieldExtraWidth() { - if (fieldExtraWidth < 0) { - text.setWidth("0"); - fieldExtraWidth = text.getOffsetWidth(); - if (BrowserInfo.get().isFF3()) { - // Firefox somehow always leaves the INPUT element 2px wide - fieldExtraWidth -= 2; - } - } - return fieldExtraWidth; - } - - /** - * Force an recalculation of the width of the component IF the width has - * been defined. Does nothing if width is undefined as the width will be - * automatically adjusted by the browser. - */ - public void updateWidth() { - if (isUndefinedWidth()) { - return; - } - needLayout = true; - fieldExtraWidth = -1; - iLayout(true); - } - - public void iLayout() { - iLayout(false); - } - - public void iLayout(boolean force) { - if (needLayout || force) { - int textFieldWidth = getOffsetWidth() - getFieldExtraWidth(); - if (textFieldWidth < 0) { - // Field can never be smaller than 0 (causes exception in IE) - textFieldWidth = 0; - } - text.setWidth(textFieldWidth + "px"); - } - } - public void focus() { text.setFocus(true); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java index 6280031d84..ce47c7d13a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VAbstractDropHandler.java @@ -9,7 +9,7 @@ import com.google.gwt.user.client.Command; import com.vaadin.event.Transferable; import com.vaadin.event.dd.DropTarget; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.UIDL; public abstract class VAbstractDropHandler implements VDropHandler { @@ -129,6 +129,6 @@ public abstract class VAbstractDropHandler implements VDropHandler { * side counterpart of the Paintable is expected to implement * {@link DropTarget} interface. */ - public abstract Paintable getPaintable(); + public abstract ComponentConnector getConnector(); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java index 74ab1dcc47..2f404a3028 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragAndDropManager.java @@ -23,8 +23,9 @@ import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.ValueMap; @@ -226,7 +227,7 @@ public class VDragAndDropManager { ENTER, LEAVE, OVER, DROP } - private static final String DD_SERVICE = "DD"; + public static final String DD_SERVICE = "DD"; private static VDragAndDropManager instance; private HandlerRegistration handlerRegistration; @@ -337,10 +338,10 @@ public class VDragAndDropManager { } private void addActiveDragSourceStyleName() { - Paintable dragSource = currentDrag.getTransferable() + ComponentConnector dragSource = currentDrag.getTransferable() .getDragSource(); - ((Widget) dragSource) - .addStyleName(ACTIVE_DRAG_SOURCE_STYLENAME); + dragSource.getWidget().addStyleName( + ACTIVE_DRAG_SOURCE_STYLENAME); } }; @@ -503,8 +504,8 @@ public class VDragAndDropManager { * handled. E.g. hidden on start, removed in drophandler -> * would flicker in case removed eagerly. */ - final Paintable dragSource = currentDrag.getTransferable() - .getDragSource(); + final ComponentConnector dragSource = currentDrag + .getTransferable().getDragSource(); final ApplicationConnection client = currentDropHandler .getApplicationConnection(); Scheduler.get().scheduleFixedDelay(new RepeatingCommand() { @@ -547,8 +548,8 @@ public class VDragAndDropManager { } - private void removeActiveDragSourceStyleName(Paintable dragSource) { - ((Widget) dragSource).removeStyleName(ACTIVE_DRAG_SOURCE_STYLENAME); + private void removeActiveDragSourceStyleName(ComponentConnector dragSource) { + dragSource.getWidget().removeStyleName(ACTIVE_DRAG_SOURCE_STYLENAME); } private void clearDragElement() { @@ -582,7 +583,7 @@ public class VDragAndDropManager { if (currentDropHandler == null) { return; } - Paintable paintable = currentDropHandler.getPaintable(); + ComponentConnector paintable = currentDropHandler.getConnector(); ApplicationConnection client = currentDropHandler .getApplicationConnection(); /* @@ -610,8 +611,9 @@ public class VDragAndDropManager { if (currentDrag.getCurrentGwtEvent() != null) { try { - MouseEventDetails mouseEventDetails = new MouseEventDetails( - currentDrag.getCurrentGwtEvent()); + MouseEventDetails mouseEventDetails = MouseEventDetailsBuilder + .buildMouseEventDetails(currentDrag + .getCurrentGwtEvent()); currentDrag.getDropDetails().put("mouseEvent", mouseEventDetails.serialize()); } catch (Exception e) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java index 1278ed7fdb..aabbf58b24 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java @@ -3,7 +3,8 @@ */ package com.vaadin.terminal.gwt.client.ui.dd; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.UIDL; /** @@ -16,14 +17,17 @@ final public class VDragSourceIs extends VAcceptCriterion { @Override protected boolean accept(VDragEvent drag, UIDL configuration) { try { - Paintable component = drag.getTransferable().getDragSource(); + ComponentConnector component = drag.getTransferable() + .getDragSource(); int c = configuration.getIntAttribute("c"); for (int i = 0; i < c; i++) { String requiredPid = configuration .getStringAttribute("component" + i); - Paintable paintable = VDragAndDropManager.get() - .getCurrentDropHandler().getApplicationConnection() - .getPaintable(requiredPid); + VDropHandler currentDropHandler = VDragAndDropManager.get() + .getCurrentDropHandler(); + ComponentConnector paintable = (ComponentConnector) ConnectorMap + .get(currentDropHandler.getApplicationConnection()) + .getConnector(requiredPid); if (paintable == component) { return true; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java index a597e9ed30..92bd6abe61 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDropHandler.java @@ -4,7 +4,7 @@ package com.vaadin.terminal.gwt.client.ui.dd; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; /** * Vaadin Widgets that want to receive something via drag and drop implement @@ -59,9 +59,9 @@ public interface VDropHandler { public void dragOver(VDragEvent currentDrag); /** - * Returns the Paintable into which this DragHandler is associated + * Returns the ComponentConnector with which this DropHandler is associated */ - public Paintable getPaintable(); + public ComponentConnector getConnector(); /** * Returns the application connection to which this {@link VDropHandler} diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java index 0195862431..6d6f7c776d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VHasDropHandler.java @@ -3,13 +3,13 @@ */ package com.vaadin.terminal.gwt.client.ui.dd; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; /** * Used to detect Widget from widget tree that has {@link #getDropHandler()} * * Decide whether to get rid of this class. If so, {@link VAbstractDropHandler} - * must extend {@link Paintable}. + * must extend {@link ComponentConnector}. * */ public interface VHasDropHandler { diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java index 58dc0d3956..90e2b033c9 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java @@ -6,7 +6,8 @@ */ package com.vaadin.terminal.gwt.client.ui.dd; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.UIDL; final public class VIsOverId extends VAcceptCriterion { @@ -16,10 +17,14 @@ final public class VIsOverId extends VAcceptCriterion { try { String pid = configuration.getStringAttribute("s"); - Paintable paintable = VDragAndDropManager.get() - .getCurrentDropHandler().getPaintable(); - String pid2 = VDragAndDropManager.get().getCurrentDropHandler() - .getApplicationConnection().getPid(paintable); + VDropHandler currentDropHandler = VDragAndDropManager.get() + .getCurrentDropHandler(); + ComponentConnector dropHandlerConnector = currentDropHandler + .getConnector(); + ConnectorMap paintableMap = ConnectorMap.get(currentDropHandler + .getApplicationConnection()); + + String pid2 = dropHandlerConnector.getConnectorId(); if (pid2.equals(pid)) { Object searchedId = drag.getDropDetails().get("itemIdOver"); String[] stringArrayAttribute = configuration diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java index ada7a3c78a..eb55c1a91c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java @@ -6,7 +6,7 @@ */ package com.vaadin.terminal.gwt.client.ui.dd; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.UIDL; final public class VItemIdIs extends VAcceptCriterion { @@ -15,9 +15,11 @@ final public class VItemIdIs extends VAcceptCriterion { protected boolean accept(VDragEvent drag, UIDL configuration) { try { String pid = configuration.getStringAttribute("s"); - Paintable dragSource = drag.getTransferable().getDragSource(); - String pid2 = VDragAndDropManager.get().getCurrentDropHandler() - .getApplicationConnection().getPid(dragSource); + ComponentConnector dragSource = drag.getTransferable() + .getDragSource(); + VDropHandler currentDropHandler = VDragAndDropManager.get() + .getCurrentDropHandler(); + String pid2 = dragSource.getConnectorId(); if (pid2.equals(pid)) { Object searchedId = drag.getTransferable().getData("itemId"); String[] stringArrayAttribute = configuration diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java index ff4c4f1d35..430b422b34 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java @@ -6,16 +6,16 @@ */ package com.vaadin.terminal.gwt.client.ui.dd; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.UIDL; final public class VSourceIsTarget extends VAcceptCriterion { @Override protected boolean accept(VDragEvent drag, UIDL configuration) { - Paintable dragSource = drag.getTransferable().getDragSource(); - Paintable paintable = VDragAndDropManager.get().getCurrentDropHandler() - .getPaintable(); + ComponentConnector dragSource = drag.getTransferable().getDragSource(); + ComponentConnector paintable = VDragAndDropManager.get() + .getCurrentDropHandler().getConnector(); return paintable == dragSource; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java index e1f2e34063..f69fa85290 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java @@ -8,8 +8,8 @@ package com.vaadin.terminal.gwt.client.ui.dd; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.ui.VTree; -import com.vaadin.terminal.gwt.client.ui.VTree.TreeNode; +import com.vaadin.terminal.gwt.client.ui.tree.VTree; +import com.vaadin.terminal.gwt.client.ui.tree.VTree.TreeNode; final public class VTargetInSubtree extends VAcceptCriterion { @@ -17,7 +17,7 @@ final public class VTargetInSubtree extends VAcceptCriterion { protected boolean accept(VDragEvent drag, UIDL configuration) { VTree tree = (VTree) VDragAndDropManager.get().getCurrentDropHandler() - .getPaintable(); + .getConnector(); TreeNode treeNode = tree.getNodeByKey((String) drag.getDropDetails() .get("itemIdOver")); if (treeNode != null) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java index fe51ea82e4..f87da378d7 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VTransferable.java @@ -8,7 +8,7 @@ import java.util.HashMap; import java.util.Map; import com.vaadin.event.dd.DragSource; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.ComponentConnector; /** * Client side counterpart for Transferable in com.vaadin.event.Transferable @@ -16,7 +16,7 @@ import com.vaadin.terminal.gwt.client.Paintable; */ public class VTransferable { - private Paintable component; + private ComponentConnector component; private final Map<String, Object> variables = new HashMap<String, Object>(); @@ -26,7 +26,7 @@ public class VTransferable { * * @return the component */ - public Paintable getDragSource() { + public ComponentConnector getDragSource() { return component; } @@ -41,7 +41,7 @@ public class VTransferable { * @param component * the component to set */ - public void setDragSource(Paintable component) { + public void setDragSource(ComponentConnector component) { this.component = component; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java new file mode 100644 index 0000000000..db531ac70f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java @@ -0,0 +1,75 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.draganddropwrapper; + +import java.util.HashMap; +import java.util.Set; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.customcomponent.CustomComponentConnector; +import com.vaadin.ui.DragAndDropWrapper; + +@Connect(DragAndDropWrapper.class) +public class DragAndDropWrapperConnector extends CustomComponentConnector + implements Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().client = client; + if (isRealUpdate(uidl) && !uidl.hasAttribute("hidden")) { + UIDL acceptCrit = uidl.getChildByTagName("-ac"); + if (acceptCrit == null) { + getWidget().dropHandler = null; + } else { + if (getWidget().dropHandler == null) { + getWidget().dropHandler = getWidget().new CustomDropHandler(); + } + getWidget().dropHandler.updateAcceptRules(acceptCrit); + } + + Set<String> variableNames = uidl.getVariableNames(); + for (String fileId : variableNames) { + if (fileId.startsWith("rec-")) { + String receiverUrl = uidl.getStringVariable(fileId); + fileId = fileId.substring(4); + if (getWidget().fileIdToReceiver == null) { + getWidget().fileIdToReceiver = new HashMap<String, String>(); + } + if ("".equals(receiverUrl)) { + Integer id = Integer.parseInt(fileId); + int indexOf = getWidget().fileIds.indexOf(id); + if (indexOf != -1) { + getWidget().files.remove(indexOf); + getWidget().fileIds.remove(indexOf); + } + } else { + getWidget().fileIdToReceiver.put(fileId, receiverUrl); + } + } + } + getWidget().startNextUpload(); + + getWidget().dragStartMode = uidl + .getIntAttribute(VDragAndDropWrapper.DRAG_START_MODE); + getWidget().initDragStartMode(); + getWidget().html5DataFlavors = uidl + .getMapAttribute(VDragAndDropWrapper.HTML5_DATA_FLAVORS); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VDragAndDropWrapper.class); + } + + @Override + public VDragAndDropWrapper getWidget() { + return (VDragAndDropWrapper) super.getWidget(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java index ff649ebeb1..d09b81e1e1 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java +++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java @@ -1,13 +1,11 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.draganddropwrapper; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArrayString; @@ -25,15 +23,15 @@ import com.google.gwt.user.client.ui.Widget; import com.google.gwt.xhr.client.ReadyStateChangeHandler; import com.google.gwt.xhr.client.XMLHttpRequest; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderInformation.Size; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VTooltip; import com.vaadin.terminal.gwt.client.ValueMap; +import com.vaadin.terminal.gwt.client.ui.customcomponent.VCustomComponent; import com.vaadin.terminal.gwt.client.ui.dd.DDUtil; import com.vaadin.terminal.gwt.client.ui.dd.HorizontalDropLocation; import com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler; @@ -109,28 +107,23 @@ public class VDragAndDropWrapper extends VCustomComponent implements private boolean startDrag(NativeEvent event) { if (dragStartMode == WRAPPER || dragStartMode == COMPONENT) { VTransferable transferable = new VTransferable(); - transferable.setDragSource(VDragAndDropWrapper.this); - - Paintable paintable; - Widget w = Util.findWidget((Element) event.getEventTarget().cast(), - null); - while (w != null && !(w instanceof Paintable)) { - w = w.getParent(); - } - paintable = (Paintable) w; + transferable.setDragSource(ConnectorMap.get(client).getConnector( + VDragAndDropWrapper.this)); + ComponentConnector paintable = Util.findPaintable(client, + (Element) event.getEventTarget().cast()); + Widget widget = paintable.getWidget(); transferable.setData("component", paintable); VDragEvent dragEvent = VDragAndDropManager.get().startDrag( transferable, event, true); - transferable.setData("mouseDown", - new MouseEventDetails(event).serialize()); + transferable.setData("mouseDown", MouseEventDetailsBuilder + .buildMouseEventDetails(event).serialize()); if (dragStartMode == WRAPPER) { dragEvent.createDragImage(getElement(), true); } else { - dragEvent.createDragImage(((Widget) paintable).getElement(), - true); + dragEvent.createDragImage(widget.getElement(), true); } return true; } @@ -144,58 +137,15 @@ public class VDragAndDropWrapper extends VCustomComponent implements protected int dragStartMode; - private ApplicationConnection client; - private VAbstractDropHandler dropHandler; + ApplicationConnection client; + VAbstractDropHandler dropHandler; private VDragEvent vaadinDragEvent; - private int filecounter = 0; - private Map<String, String> fileIdToReceiver; - private ValueMap html5DataFlavors; + int filecounter = 0; + Map<String, String> fileIdToReceiver; + ValueMap html5DataFlavors; private Element dragStartElement; - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - super.updateFromUIDL(uidl, client); - if (!uidl.hasAttribute("cached") && !uidl.hasAttribute("hidden")) { - UIDL acceptCrit = uidl.getChildByTagName("-ac"); - if (acceptCrit == null) { - dropHandler = null; - } else { - if (dropHandler == null) { - dropHandler = new CustomDropHandler(); - } - dropHandler.updateAcceptRules(acceptCrit); - } - - Set<String> variableNames = uidl.getVariableNames(); - for (String fileId : variableNames) { - if (fileId.startsWith("rec-")) { - String receiverUrl = uidl.getStringVariable(fileId); - fileId = fileId.substring(4); - if (fileIdToReceiver == null) { - fileIdToReceiver = new HashMap<String, String>(); - } - if ("".equals(receiverUrl)) { - Integer id = Integer.parseInt(fileId); - int indexOf = fileIds.indexOf(id); - if (indexOf != -1) { - files.remove(indexOf); - fileIds.remove(indexOf); - } - } else { - fileIdToReceiver.put(fileId, receiverUrl); - } - } - } - startNextUpload(); - - dragStartMode = uidl.getIntAttribute(DRAG_START_MODE); - initDragStartMode(); - html5DataFlavors = uidl.getMapAttribute(HTML5_DATA_FLAVORS); - } - } - protected void initDragStartMode() { Element div = getElement(); if (dragStartMode == HTML5) { @@ -235,7 +185,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements }; private Timer dragleavetimer; - private void startNextUpload() { + void startNextUpload() { Scheduler.get().scheduleDeferred(new Command() { public void execute() { @@ -291,7 +241,8 @@ public class VDragAndDropWrapper extends VCustomComponent implements } if (VDragAndDropManager.get().getCurrentDropHandler() != getDropHandler()) { VTransferable transferable = new VTransferable(); - transferable.setDragSource(this); + transferable.setDragSource(ConnectorMap.get(client) + .getConnector(this)); vaadinDragEvent = VDragAndDropManager.get().startDrag( transferable, event, false); @@ -459,18 +410,14 @@ public class VDragAndDropWrapper extends VCustomComponent implements * @param fileId * @param data */ - private List<Integer> fileIds = new ArrayList<Integer>(); - private List<VHtml5File> files = new ArrayList<VHtml5File>(); + List<Integer> fileIds = new ArrayList<Integer>(); + List<VHtml5File> files = new ArrayList<VHtml5File>(); private void queueFilePost(final int fileId, final VHtml5File file) { fileIds.add(fileId); files.add(file); } - private String getPid() { - return client.getPid(this); - } - public VDropHandler getDropHandler() { return dropHandler; } @@ -547,8 +494,9 @@ public class VDragAndDropWrapper extends VCustomComponent implements } @Override - public Paintable getPaintable() { - return VDragAndDropWrapper.this; + public ComponentConnector getConnector() { + return ConnectorMap.get(client).getConnector( + VDragAndDropWrapper.this); } public ApplicationConnection getApplicationConnection() { @@ -561,7 +509,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements /*-{ var me = this; el.addEventListener("dragstart", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragStart(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragStart(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); }), false); }-*/; @@ -575,19 +523,19 @@ public class VDragAndDropWrapper extends VCustomComponent implements var me = this; el.addEventListener("dragenter", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragEnter(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragEnter(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); }), false); el.addEventListener("dragleave", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragLeave(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragLeave(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); }), false); el.addEventListener("dragover", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragOver(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragOver(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); }), false); el.addEventListener("drop", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragDrop(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragDrop(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); }), false); }-*/; @@ -610,11 +558,6 @@ public class VDragAndDropWrapper extends VCustomComponent implements } protected void deEmphasis(boolean doLayout) { - Size size = null; - if (doLayout) { - size = new RenderInformation.Size(getOffsetWidth(), - getOffsetHeight()); - } if (emphasizedVDrop != null) { VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE, false); VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE + "-" @@ -623,13 +566,16 @@ public class VDragAndDropWrapper extends VCustomComponent implements + emphasizedHDrop.toString().toLowerCase(), false); } if (doLayout) { - handleVaadinRelatedSizeChange(size); + notifySizePotentiallyChanged(); } } + private void notifySizePotentiallyChanged() { + LayoutManager.get(client).setNeedsMeasure( + ConnectorMap.get(client).getConnector(getElement())); + } + protected void emphasis(VDragEvent drag) { - Size size = new RenderInformation.Size(getOffsetWidth(), - getOffsetHeight()); deEmphasis(false); VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE, true); VDragAndDropWrapper.setStyleName(getElement(), OVER_STYLE + "-" @@ -641,20 +587,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements // TODO build (to be an example) an emphasis mode where drag image // is fitted before or after the content - handleVaadinRelatedSizeChange(size); - - } - - protected void handleVaadinRelatedSizeChange(Size originalSize) { - if (isDynamicHeight() || isDynamicWidth()) { - if (!originalSize.equals(new RenderInformation.Size( - getOffsetWidth(), getOffsetHeight()))) { - Util.notifyParentOfSizeChange(VDragAndDropWrapper.this, false); - } - } - client.handleComponentRelativeSize(VDragAndDropWrapper.this); - Util.notifyParentOfSizeChange(this, false); - + notifySizePotentiallyChanged(); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java index 30483545e9..bb511524e5 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapperIE.java +++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapperIE.java @@ -1,8 +1,8 @@ -/* +/* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.draganddropwrapper; import com.google.gwt.dom.client.AnchorElement; import com.google.gwt.dom.client.Document; @@ -40,7 +40,7 @@ public class VDragAndDropWrapperIE extends VDragAndDropWrapper { var me = this; el.attachEvent("ondragstart", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragStart(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragStart(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); })); }-*/; @@ -50,19 +50,19 @@ public class VDragAndDropWrapperIE extends VDragAndDropWrapper { var me = this; el.attachEvent("ondragenter", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragEnter(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragEnter(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); })); el.attachEvent("ondragleave", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragLeave(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragLeave(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); })); el.attachEvent("ondragover", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragOver(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragOver(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); })); el.attachEvent("ondrop", $entry(function(ev) { - return me.@com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper::html5DragDrop(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); + return me.@com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper::html5DragDrop(Lcom/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent;)(ev); })); }-*/; diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java new file mode 100644 index 0000000000..81ac195c8e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedConnector.java @@ -0,0 +1,205 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.embedded; + +import java.util.Map; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.ObjectElement; +import com.google.gwt.dom.client.Style; +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.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.ui.Embedded; + +@Connect(Embedded.class) +public class EmbeddedConnector extends AbstractComponentConnector implements + Paintable { + + public static final String ALTERNATE_TEXT = "alt"; + + EmbeddedServerRpc rpc; + + @Override + protected void init() { + super.init(); + rpc = RpcProxy.create(EmbeddedServerRpc.class, this); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + + // Save details + getWidget().client = client; + + boolean clearBrowserElement = true; + + clickEventHandler.handleEventHandlerRegistration(); + + if (uidl.hasAttribute("type")) { + getWidget().type = uidl.getStringAttribute("type"); + if (getWidget().type.equals("image")) { + getWidget().addStyleName(VEmbedded.CLASSNAME + "-image"); + Element el = null; + boolean created = false; + NodeList<Node> nodes = getWidget().getElement().getChildNodes(); + if (nodes != null && nodes.getLength() == 1) { + Node n = nodes.getItem(0); + if (n.getNodeType() == Node.ELEMENT_NODE) { + Element e = (Element) n; + if (e.getTagName().equals("IMG")) { + el = e; + } + } + } + if (el == null) { + getWidget().setHTML(""); + el = DOM.createImg(); + created = true; + DOM.sinkEvents(el, Event.ONLOAD); + } + + // Set attributes + Style style = el.getStyle(); + style.setProperty("width", getState().getWidth()); + style.setProperty("height", getState().getHeight()); + + DOM.setElementProperty(el, "src", + getWidget().getSrc(uidl, client)); + + if (uidl.hasAttribute(ALTERNATE_TEXT)) { + el.setPropertyString(ALTERNATE_TEXT, + uidl.getStringAttribute(ALTERNATE_TEXT)); + } + + if (created) { + // insert in dom late + getWidget().getElement().appendChild(el); + } + + /* + * Sink tooltip events so tooltip is displayed when hovering the + * image. + */ + getWidget().sinkEvents(VTooltip.TOOLTIP_EVENTS); + + } else if (getWidget().type.equals("browser")) { + getWidget().addStyleName(VEmbedded.CLASSNAME + "-browser"); + if (getWidget().browserElement == null) { + getWidget().setHTML( + "<iframe width=\"100%\" height=\"100%\" frameborder=\"0\"" + + " allowTransparency=\"true\" src=\"\"" + + " name=\"" + uidl.getId() + + "\"></iframe>"); + getWidget().browserElement = DOM.getFirstChild(getWidget() + .getElement()); + } + DOM.setElementAttribute(getWidget().browserElement, "src", + getWidget().getSrc(uidl, client)); + clearBrowserElement = false; + } else { + VConsole.log("Unknown Embedded type '" + getWidget().type + "'"); + } + } else if (uidl.hasAttribute("mimetype")) { + final String mime = uidl.getStringAttribute("mimetype"); + if (mime.equals("application/x-shockwave-flash")) { + // Handle embedding of Flash + getWidget().addStyleName(VEmbedded.CLASSNAME + "-flash"); + getWidget().setHTML(getWidget().createFlashEmbed(uidl)); + + } else if (mime.equals("image/svg+xml")) { + getWidget().addStyleName(VEmbedded.CLASSNAME + "-svg"); + String data; + Map<String, String> parameters = VEmbedded.getParameters(uidl); + if (parameters.get("data") == null) { + data = getWidget().getSrc(uidl, client); + } else { + data = "data:image/svg+xml," + parameters.get("data"); + } + getWidget().setHTML(""); + ObjectElement obj = Document.get().createObjectElement(); + obj.setType(mime); + obj.setData(data); + if (!isUndefinedWidth()) { + obj.getStyle().setProperty("width", "100%"); + } + if (!isUndefinedHeight()) { + obj.getStyle().setProperty("height", "100%"); + } + if (uidl.hasAttribute("classid")) { + obj.setAttribute("classid", + uidl.getStringAttribute("classid")); + } + if (uidl.hasAttribute("codebase")) { + obj.setAttribute("codebase", + uidl.getStringAttribute("codebase")); + } + if (uidl.hasAttribute("codetype")) { + obj.setAttribute("codetype", + uidl.getStringAttribute("codetype")); + } + if (uidl.hasAttribute("archive")) { + obj.setAttribute("archive", + uidl.getStringAttribute("archive")); + } + if (uidl.hasAttribute("standby")) { + obj.setAttribute("standby", + uidl.getStringAttribute("standby")); + } + getWidget().getElement().appendChild(obj); + if (uidl.hasAttribute(ALTERNATE_TEXT)) { + obj.setInnerText(uidl.getStringAttribute(ALTERNATE_TEXT)); + } + } else { + VConsole.log("Unknown Embedded mimetype '" + mime + "'"); + } + } else { + VConsole.log("Unknown Embedded; no type or mimetype attribute"); + } + + if (clearBrowserElement) { + getWidget().browserElement = null; + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VEmbedded.class); + } + + @Override + public VEmbedded getWidget() { + return (VEmbedded) super.getWidget(); + } + + protected final ClickEventHandler clickEventHandler = new ClickEventHandler( + this) { + + @Override + protected void fireClick(NativeEvent event, + MouseEventDetails mouseDetails) { + rpc.click(mouseDetails); + } + + }; + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRpc.java new file mode 100644 index 0000000000..7f36c812bc --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/EmbeddedServerRpc.java @@ -0,0 +1,10 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.embedded; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.ClickRpc; + +public interface EmbeddedServerRpc extends ClickRpc, ServerRpc { +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java new file mode 100644 index 0000000000..203e7362f3 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/embedded/VEmbedded.java @@ -0,0 +1,239 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.embedded; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +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.HTML; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; + +public class VEmbedded extends HTML { + public static String CLASSNAME = "v-embedded"; + + protected Element browserElement; + + protected String type; + + protected ApplicationConnection client; + + public VEmbedded() { + setStyleName(CLASSNAME); + } + + /** + * Creates the Object and Embed tags for the Flash plugin so it works + * cross-browser + * + * @param uidl + * The UIDL + * @return Tags concatenated into a string + */ + protected String createFlashEmbed(UIDL uidl) { + /* + * To ensure cross-browser compatibility we are using the twice-cooked + * method to embed flash i.e. we add a OBJECT tag for IE ActiveX and + * inside it a EMBED for all other browsers. + */ + + StringBuilder html = new StringBuilder(); + + // Start the object tag + html.append("<object "); + + /* + * Add classid required for ActiveX to recognize the flash. This is a + * predefined value which ActiveX recognizes and must be the given + * value. More info can be found on + * http://kb2.adobe.com/cps/415/tn_4150.html. Allow user to override + * this by setting his own classid. + */ + if (uidl.hasAttribute("classid")) { + html.append("classid=\"" + + Util.escapeAttribute(uidl.getStringAttribute("classid")) + + "\" "); + } else { + html.append("classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" "); + } + + /* + * Add codebase required for ActiveX and must be exactly this according + * to http://kb2.adobe.com/cps/415/tn_4150.html to work with the above + * given classid. Again, see more info on + * http://kb2.adobe.com/cps/415/tn_4150.html. Limiting Flash version to + * 6.0.0.0 and above. Allow user to override this by setting his own + * codebase + */ + if (uidl.hasAttribute("codebase")) { + html.append("codebase=\"" + + Util.escapeAttribute(uidl.getStringAttribute("codebase")) + + "\" "); + } else { + html.append("codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\" "); + } + + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + String height = paintable.getState().getHeight(); + String width = paintable.getState().getWidth(); + + // Add width and height + html.append("width=\"" + Util.escapeAttribute(width) + "\" "); + html.append("height=\"" + Util.escapeAttribute(height) + "\" "); + html.append("type=\"application/x-shockwave-flash\" "); + + // Codetype + if (uidl.hasAttribute("codetype")) { + html.append("codetype=\"" + + Util.escapeAttribute(uidl.getStringAttribute("codetype")) + + "\" "); + } + + // Standby + if (uidl.hasAttribute("standby")) { + html.append("standby=\"" + + Util.escapeAttribute(uidl.getStringAttribute("standby")) + + "\" "); + } + + // Archive + if (uidl.hasAttribute("archive")) { + html.append("archive=\"" + + Util.escapeAttribute(uidl.getStringAttribute("archive")) + + "\" "); + } + + // End object tag + html.append(">"); + + // Ensure we have an movie parameter + Map<String, String> parameters = getParameters(uidl); + if (parameters.get("movie") == null) { + parameters.put("movie", getSrc(uidl, client)); + } + + // Add parameters to OBJECT + for (String name : parameters.keySet()) { + html.append("<param "); + html.append("name=\"" + Util.escapeAttribute(name) + "\" "); + html.append("value=\"" + Util.escapeAttribute(parameters.get(name)) + + "\" "); + html.append("/>"); + } + + // Build inner EMBED tag + html.append("<embed "); + html.append("src=\"" + Util.escapeAttribute(getSrc(uidl, client)) + + "\" "); + html.append("width=\"" + Util.escapeAttribute(width) + "\" "); + html.append("height=\"" + Util.escapeAttribute(height) + "\" "); + html.append("type=\"application/x-shockwave-flash\" "); + + // Add the parameters to the Embed + for (String name : parameters.keySet()) { + html.append(Util.escapeAttribute(name)); + html.append("="); + html.append("\"" + Util.escapeAttribute(parameters.get(name)) + + "\""); + } + + // End embed tag + html.append("></embed>"); + + if (uidl.hasAttribute(EmbeddedConnector.ALTERNATE_TEXT)) { + html.append(uidl + .getStringAttribute(EmbeddedConnector.ALTERNATE_TEXT)); + } + + // End object tag + html.append("</object>"); + + return html.toString(); + } + + /** + * Returns a map (name -> value) of all parameters in the UIDL. + * + * @param uidl + * @return + */ + protected static Map<String, String> getParameters(UIDL uidl) { + Map<String, String> parameters = new HashMap<String, String>(); + + Iterator<Object> childIterator = uidl.getChildIterator(); + while (childIterator.hasNext()) { + + Object child = childIterator.next(); + if (child instanceof UIDL) { + + UIDL childUIDL = (UIDL) child; + if (childUIDL.getTag().equals("embeddedparam")) { + String name = childUIDL.getStringAttribute("name"); + String value = childUIDL.getStringAttribute("value"); + parameters.put(name, value); + } + } + + } + + return parameters; + } + + /** + * Helper to return translated src-attribute from embedded's UIDL + * + * @param uidl + * @param client + * @return + */ + protected String getSrc(UIDL uidl, ApplicationConnection client) { + String url = client.translateVaadinUri(uidl.getStringAttribute("src")); + if (url == null) { + return ""; + } + return url; + } + + @Override + protected void onDetach() { + if (BrowserInfo.get().isIE()) { + // Force browser to fire unload event when component is detached + // from the view (IE doesn't do this automatically) + if (browserElement != null) { + /* + * src was previously set to javascript:false, but this was not + * enough to overcome a bug when detaching an iframe with a pdf + * loaded in IE9. about:blank seems to cause the adobe reader + * plugin to unload properly before the iframe is removed. See + * #7855 + */ + DOM.setElementAttribute(browserElement, "src", "about:blank"); + } + } + super.onDetach(); + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (DOM.eventGetType(event) == Event.ONLOAD) { + VConsole.log("Embeddable onload"); + Util.notifyParentOfSizeChange(this, true); + } + + client.handleTooltipEvent(event, this); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/form/FormConnector.java b/src/com/vaadin/terminal/gwt/client/ui/form/FormConnector.java new file mode 100644 index 0000000000..82cbc95b2d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/form/FormConnector.java @@ -0,0 +1,209 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.form; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +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.layout.MayScrollChildren; +import com.vaadin.ui.Form; + +@Connect(Form.class) +public class FormConnector extends AbstractComponentContainerConnector + implements Paintable, MayScrollChildren { + + private final ElementResizeListener footerResizeListener = new ElementResizeListener() { + public void onElementResize(ElementResizeEvent e) { + VForm form = getWidget(); + + int footerHeight; + if (form.footer != null) { + LayoutManager lm = getLayoutManager(); + footerHeight = lm.getOuterHeight(form.footer.getElement()); + } else { + footerHeight = 0; + } + + form.fieldContainer.getStyle().setPaddingBottom(footerHeight, + Unit.PX); + form.footerContainer.getStyle() + .setMarginTop(-footerHeight, Unit.PX); + } + }; + + @Override + public void onUnregister() { + VForm form = getWidget(); + if (form.footer != null) { + getLayoutManager().removeElementResizeListener( + form.footer.getElement(), footerResizeListener); + } + } + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().client = client; + getWidget().id = uidl.getId(); + + if (!isRealUpdate(uidl)) { + return; + } + + boolean legendEmpty = true; + if (getState().getCaption() != null) { + getWidget().caption.setInnerText(getState().getCaption()); + legendEmpty = false; + } else { + getWidget().caption.setInnerText(""); + } + if (getState().getIcon() != null) { + if (getWidget().icon == null) { + getWidget().icon = new Icon(client); + getWidget().legend.insertFirst(getWidget().icon.getElement()); + } + getWidget().icon.setUri(getState().getIcon().getURL()); + legendEmpty = false; + } else { + if (getWidget().icon != null) { + getWidget().legend.removeChild(getWidget().icon.getElement()); + } + } + if (legendEmpty) { + getWidget().addStyleDependentName("nocaption"); + } else { + getWidget().removeStyleDependentName("nocaption"); + } + + if (null != getState().getErrorMessage()) { + getWidget().errorMessage + .updateMessage(getState().getErrorMessage()); + getWidget().errorMessage.setVisible(true); + } else { + getWidget().errorMessage.setVisible(false); + } + + if (getState().hasDescription()) { + getWidget().desc.setInnerHTML(getState().getDescription()); + if (getWidget().desc.getParentElement() == null) { + getWidget().fieldSet.insertAfter(getWidget().desc, + getWidget().legend); + } + } else { + getWidget().desc.setInnerHTML(""); + if (getWidget().desc.getParentElement() != null) { + getWidget().fieldSet.removeChild(getWidget().desc); + } + } + + // first render footer so it will be easier to handle relative height of + // main layout + if (getState().getFooter() != null) { + // render footer + ComponentConnector newFooter = (ComponentConnector) getState() + .getFooter(); + Widget newFooterWidget = newFooter.getWidget(); + if (getWidget().footer == null) { + getLayoutManager().addElementResizeListener( + newFooterWidget.getElement(), footerResizeListener); + getWidget().add(newFooter.getWidget(), + getWidget().footerContainer); + getWidget().footer = newFooterWidget; + } else if (newFooter != getWidget().footer) { + getLayoutManager().removeElementResizeListener( + getWidget().footer.getElement(), footerResizeListener); + getLayoutManager().addElementResizeListener( + newFooterWidget.getElement(), footerResizeListener); + getWidget().remove(getWidget().footer); + getWidget().add(newFooter.getWidget(), + getWidget().footerContainer); + } + getWidget().footer = newFooterWidget; + } else { + if (getWidget().footer != null) { + getLayoutManager().removeElementResizeListener( + getWidget().footer.getElement(), footerResizeListener); + getWidget().remove(getWidget().footer); + getWidget().footer = null; + } + } + + ComponentConnector newLayout = (ComponentConnector) getState() + .getLayout(); + Widget newLayoutWidget = newLayout.getWidget(); + if (getWidget().lo == null) { + // Layout not rendered before + getWidget().lo = newLayoutWidget; + getWidget().add(newLayoutWidget, getWidget().fieldContainer); + } else if (getWidget().lo != newLayoutWidget) { + // Layout has changed + getWidget().remove(getWidget().lo); + getWidget().lo = newLayoutWidget; + getWidget().add(newLayoutWidget, getWidget().fieldContainer); + } + + // also recalculates size of the footer if undefined size form - see + // #3710 + client.runDescendentsLayout(getWidget()); + + // We may have actions attached + if (uidl.getChildCount() >= 1) { + UIDL childUidl = uidl.getChildByTagName("actions"); + if (childUidl != null) { + if (getWidget().shortcutHandler == null) { + getWidget().shortcutHandler = new ShortcutActionHandler( + getConnectorId(), client); + getWidget().keyDownRegistration = getWidget() + .addDomHandler(getWidget(), KeyDownEvent.getType()); + } + getWidget().shortcutHandler.updateActionMap(childUidl); + } + } else if (getWidget().shortcutHandler != null) { + getWidget().keyDownRegistration.removeHandler(); + getWidget().shortcutHandler = null; + getWidget().keyDownRegistration = null; + } + } + + public void updateCaption(ComponentConnector component) { + // NOP form don't render caption for neither field layout nor footer + // layout + } + + @Override + public VForm getWidget() { + return (VForm) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VForm.class); + } + + @Override + public boolean isReadOnly() { + return super.isReadOnly() || getState().isPropertyReadOnly(); + } + + @Override + public FormState getState() { + return (FormState) super.getState(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/form/FormState.java b/src/com/vaadin/terminal/gwt/client/ui/form/FormState.java new file mode 100644 index 0000000000..c1acc0971d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/form/FormState.java @@ -0,0 +1,29 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.form; + +import com.vaadin.terminal.gwt.client.AbstractFieldState; +import com.vaadin.terminal.gwt.client.Connector; + +public class FormState extends AbstractFieldState { + private Connector layout; + private Connector footer; + + public Connector getLayout() { + return layout; + } + + public void setLayout(Connector layout) { + this.layout = layout; + } + + public Connector getFooter() { + return footer; + } + + public void setFooter(Connector footer) { + this.footer = footer; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java b/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java new file mode 100644 index 0000000000..e3a0c9b321 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java @@ -0,0 +1,80 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.form; + +import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.shared.HandlerRegistration; +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.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.VErrorMessage; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; + +public class VForm extends ComplexPanel implements KeyDownHandler { + + protected String id; + + public static final String CLASSNAME = "v-form"; + + Widget lo; + Element legend = DOM.createLegend(); + Element caption = DOM.createSpan(); + private Element errorIndicatorElement = DOM.createDiv(); + Element desc = DOM.createDiv(); + Icon icon; + VErrorMessage errorMessage = new VErrorMessage(); + + Element fieldContainer = DOM.createDiv(); + + Element footerContainer = DOM.createDiv(); + + Element fieldSet = DOM.createFieldSet(); + + Widget footer; + + ApplicationConnection client; + + ShortcutActionHandler shortcutHandler; + + HandlerRegistration keyDownRegistration; + + public VForm() { + setElement(DOM.createDiv()); + getElement().appendChild(fieldSet); + setStyleName(CLASSNAME); + fieldSet.appendChild(legend); + legend.appendChild(caption); + errorIndicatorElement.setClassName("v-errorindicator"); + errorIndicatorElement.getStyle().setDisplay(Display.NONE); + errorIndicatorElement.setInnerText(" "); // needed for IE + desc.setClassName("v-form-description"); + fieldSet.appendChild(desc); // Adding description for initial padding + // measurements, removed later if no + // description is set + fieldContainer.setClassName(CLASSNAME + "-content"); + fieldSet.appendChild(fieldContainer); + errorMessage.setVisible(false); + errorMessage.setStyleName(CLASSNAME + "-errormessage"); + fieldSet.appendChild(errorMessage.getElement()); + fieldSet.appendChild(footerContainer); + } + + public void onKeyDown(KeyDownEvent event) { + shortcutHandler.handleKeyboardEvent(Event.as(event.getNativeEvent())); + } + + @Override + protected void add(Widget child, Element container) { + // Overridden to allow VFormPaintable to call this. Should be removed + // once functionality from VFormPaintable is moved to VForm. + super.add(child, container); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java new file mode 100644 index 0000000000..d7774b66ef --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/formlayout/FormLayoutConnector.java @@ -0,0 +1,105 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.formlayout; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; +import com.vaadin.terminal.gwt.client.ui.formlayout.VFormLayout.Caption; +import com.vaadin.terminal.gwt.client.ui.formlayout.VFormLayout.ErrorFlag; +import com.vaadin.terminal.gwt.client.ui.formlayout.VFormLayout.VFormLayoutTable; +import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutState; +import com.vaadin.ui.FormLayout; + +@Connect(FormLayout.class) +public class FormLayoutConnector extends AbstractLayoutConnector { + + @Override + public AbstractOrderedLayoutState getState() { + return (AbstractOrderedLayoutState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + VFormLayoutTable formLayoutTable = getWidget().table; + + formLayoutTable.setMargins(new VMarginInfo(getState() + .getMarginsBitmask())); + formLayoutTable.setSpacing(getState().isSpacing()); + + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + VFormLayout formLayout = getWidget(); + VFormLayoutTable formLayoutTable = getWidget().table; + + int childId = 0; + + formLayoutTable.setRowCount(getChildren().size()); + + for (ComponentConnector child : getChildren()) { + Widget childWidget = child.getWidget(); + + Caption caption = formLayoutTable.getCaption(childWidget); + if (caption == null) { + caption = formLayout.new Caption(child); + caption.addClickHandler(formLayoutTable); + } + + ErrorFlag error = formLayoutTable.getError(childWidget); + if (error == null) { + error = formLayout.new ErrorFlag(child); + } + + formLayoutTable.setChild(childId, childWidget, caption, error); + childId++; + } + + for (ComponentConnector oldChild : event.getOldChildren()) { + if (oldChild.getParent() == this) { + continue; + } + + formLayoutTable.cleanReferences(oldChild.getWidget()); + } + + } + + public void updateCaption(ComponentConnector component) { + getWidget().table.updateCaption(component.getWidget(), + component.getState(), component.isEnabled()); + boolean hideErrors = false; + + // FIXME This incorrectly depends on AbstractFieldConnector + if (component instanceof AbstractFieldConnector) { + hideErrors = ((AbstractFieldConnector) component).getState() + .isHideErrors(); + } + + getWidget().table.updateError(component.getWidget(), component + .getState().getErrorMessage(), hideErrors); + } + + @Override + public VFormLayout getWidget() { + return (VFormLayout) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VFormLayout.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java new file mode 100644 index 0000000000..85584755a6 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/formlayout/VFormLayout.java @@ -0,0 +1,379 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.formlayout; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +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.FlexTable; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.StyleConstants; +import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; + +/** + * Two col Layout that places caption on left col and field on right col + */ +public class VFormLayout extends SimplePanel { + + private final static String CLASSNAME = "v-formlayout"; + + ApplicationConnection client; + VFormLayoutTable table; + + public VFormLayout() { + super(); + setStyleName(CLASSNAME); + table = new VFormLayoutTable(); + setWidget(table); + } + + /** + * Parses the stylenames from shared state + * + * @param state + * shared state of the component + * @param enabled + * @return An array of stylenames + */ + private String[] getStylesFromState(ComponentState state, boolean enabled) { + List<String> styles = new ArrayList<String>(); + if (state.hasStyles()) { + for (String name : state.getStyles()) { + styles.add(name); + } + } + + if (!enabled) { + styles.add(ApplicationConnection.DISABLED_CLASSNAME); + } + + return styles.toArray(new String[styles.size()]); + } + + public class VFormLayoutTable extends FlexTable implements ClickHandler { + + private static final int COLUMN_CAPTION = 0; + private static final int COLUMN_ERRORFLAG = 1; + private static final int COLUMN_WIDGET = 2; + + private HashMap<Widget, Caption> widgetToCaption = new HashMap<Widget, Caption>(); + private HashMap<Widget, ErrorFlag> widgetToError = new HashMap<Widget, ErrorFlag>(); + + public VFormLayoutTable() { + DOM.setElementProperty(getElement(), "cellPadding", "0"); + DOM.setElementProperty(getElement(), "cellSpacing", "0"); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt + * .event.dom.client.ClickEvent) + */ + public void onClick(ClickEvent event) { + Caption caption = (Caption) event.getSource(); + if (caption.getOwner() != null) { + if (caption.getOwner() instanceof Focusable) { + ((Focusable) caption.getOwner()).focus(); + } else if (caption.getOwner() instanceof com.google.gwt.user.client.ui.Focusable) { + ((com.google.gwt.user.client.ui.Focusable) caption + .getOwner()).setFocus(true); + } + } + } + + public void setMargins(VMarginInfo margins) { + Element margin = getElement(); + setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP, + margins.hasTop()); + setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT, + margins.hasRight()); + setStyleName(margin, + CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM, + margins.hasBottom()); + setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT, + margins.hasLeft()); + + } + + public void setSpacing(boolean spacing) { + setStyleName(getElement(), CLASSNAME + "-" + "spacing", spacing); + + } + + public void setRowCount(int rowNr) { + for (int i = 0; i < rowNr; i++) { + prepareCell(i, COLUMN_CAPTION); + getCellFormatter().setStyleName(i, COLUMN_CAPTION, + CLASSNAME + "-captioncell"); + + prepareCell(i, 1); + getCellFormatter().setStyleName(i, COLUMN_ERRORFLAG, + CLASSNAME + "-errorcell"); + + prepareCell(i, 2); + getCellFormatter().setStyleName(i, COLUMN_WIDGET, + CLASSNAME + "-contentcell"); + + String rowstyles = CLASSNAME + "-row"; + if (i == 0) { + rowstyles += " " + CLASSNAME + "-firstrow"; + } + if (i == rowNr - 1) { + rowstyles += " " + CLASSNAME + "-lastrow"; + } + + getRowFormatter().setStyleName(i, rowstyles); + + } + while (getRowCount() != rowNr) { + removeRow(rowNr); + } + } + + public void setChild(int rowNr, Widget childWidget, Caption caption, + ErrorFlag error) { + setWidget(rowNr, COLUMN_WIDGET, childWidget); + setWidget(rowNr, COLUMN_CAPTION, caption); + setWidget(rowNr, COLUMN_ERRORFLAG, error); + + widgetToCaption.put(childWidget, caption); + widgetToError.put(childWidget, error); + + } + + public Caption getCaption(Widget childWidget) { + return widgetToCaption.get(childWidget); + } + + public ErrorFlag getError(Widget childWidget) { + return widgetToError.get(childWidget); + } + + public void cleanReferences(Widget oldChildWidget) { + widgetToError.remove(oldChildWidget); + widgetToCaption.remove(oldChildWidget); + + } + + public void updateCaption(Widget widget, ComponentState state, + boolean enabled) { + final Caption c = widgetToCaption.get(widget); + if (c != null) { + c.updateCaption(state, enabled); + } + } + + public void updateError(Widget widget, String errorMessage, + boolean hideErrors) { + final ErrorFlag e = widgetToError.get(widget); + if (e != null) { + e.updateError(errorMessage, hideErrors); + } + + } + + } + + // TODO why duplicated here? + public class Caption extends HTML { + + public static final String CLASSNAME = "v-caption"; + + private final ComponentConnector owner; + + private Element requiredFieldIndicator; + + private Icon icon; + + private Element captionText; + + /** + * + * @param component + * optional owner of caption. If not set, getOwner will + * return null + */ + public Caption(ComponentConnector component) { + super(); + owner = component; + + sinkEvents(VTooltip.TOOLTIP_EVENTS); + } + + private void setStyles(String[] styles) { + String styleName = CLASSNAME; + + if (styles != null) { + for (String style : styles) { + if (ApplicationConnection.DISABLED_CLASSNAME.equals(style)) { + // Add v-disabled also without classname prefix so + // generic v-disabled CSS rules work + styleName += " " + style; + } + + styleName += " " + CLASSNAME + "-" + style; + } + } + + setStyleName(styleName); + } + + public void updateCaption(ComponentState state, boolean enabled) { + // Update styles as they might have changed when the caption changed + setStyles(getStylesFromState(state, enabled)); + + boolean isEmpty = true; + + if (state.getIcon() != null) { + if (icon == null) { + icon = new Icon(owner.getConnection()); + + DOM.insertChild(getElement(), icon.getElement(), 0); + } + icon.setUri(state.getIcon().getURL()); + isEmpty = false; + } else { + if (icon != null) { + DOM.removeChild(getElement(), icon.getElement()); + icon = null; + } + + } + + if (state.getCaption() != null) { + if (captionText == null) { + captionText = DOM.createSpan(); + DOM.insertChild(getElement(), captionText, icon == null ? 0 + : 1); + } + String c = state.getCaption(); + if (c == null) { + c = ""; + } else { + isEmpty = false; + } + DOM.setInnerText(captionText, c); + } else { + // TODO should span also be removed + } + + if (state.hasDescription() && captionText != null) { + addStyleDependentName("hasdescription"); + } else { + removeStyleDependentName("hasdescription"); + } + + boolean required = owner instanceof AbstractFieldConnector + && ((AbstractFieldConnector) owner).isRequired(); + if (required) { + if (requiredFieldIndicator == null) { + requiredFieldIndicator = DOM.createSpan(); + DOM.setInnerText(requiredFieldIndicator, "*"); + DOM.setElementProperty(requiredFieldIndicator, "className", + "v-required-field-indicator"); + DOM.appendChild(getElement(), requiredFieldIndicator); + } + } else { + if (requiredFieldIndicator != null) { + DOM.removeChild(getElement(), requiredFieldIndicator); + requiredFieldIndicator = null; + } + } + + // Workaround for IE weirdness, sometimes returns bad height in some + // circumstances when Caption is empty. See #1444 + // IE7 bugs more often. I wonder what happens when IE8 arrives... + // FIXME: This could be unnecessary for IE8+ + if (BrowserInfo.get().isIE()) { + if (isEmpty) { + setHeight("0px"); + DOM.setStyleAttribute(getElement(), "overflow", "hidden"); + } else { + setHeight(""); + DOM.setStyleAttribute(getElement(), "overflow", ""); + } + + } + + } + + /** + * Returns Paintable for which this Caption belongs to. + * + * @return owner Widget + */ + public ComponentConnector getOwner() { + return owner; + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + owner.getConnection().handleTooltipEvent(event, owner); + } + } + + class ErrorFlag extends HTML { + private static final String CLASSNAME = VFormLayout.CLASSNAME + + "-error-indicator"; + Element errorIndicatorElement; + + private ComponentConnector owner; + + public ErrorFlag(ComponentConnector owner) { + setStyleName(CLASSNAME); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + this.owner = owner; + } + + public void updateError(String errorMessage, boolean hideErrors) { + boolean showError = null != errorMessage; + if (hideErrors) { + showError = false; + } + + if (showError) { + if (errorIndicatorElement == null) { + errorIndicatorElement = DOM.createDiv(); + DOM.setInnerHTML(errorIndicatorElement, " "); + DOM.setElementProperty(errorIndicatorElement, "className", + "v-errorindicator"); + DOM.appendChild(getElement(), errorIndicatorElement); + } + + } else if (errorIndicatorElement != null) { + DOM.removeChild(getElement(), errorIndicatorElement); + errorIndicatorElement = null; + } + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (owner != null) { + client.handleTooltipEvent(event, owner); + } + } + + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java new file mode 100644 index 0000000000..e4a31b96ef --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutConnector.java @@ -0,0 +1,239 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.gridlayout; + +import java.util.Iterator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.AlignmentInfo; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; +import com.vaadin.terminal.gwt.client.ui.gridlayout.VGridLayout.Cell; +import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot; +import com.vaadin.ui.GridLayout; + +@Connect(GridLayout.class) +public class GridLayoutConnector extends AbstractComponentContainerConnector + implements Paintable, DirectionalManagedLayout { + + private LayoutClickEventHandler clickEventHandler = new LayoutClickEventHandler( + this) { + + @Override + protected ComponentConnector getChildComponent(Element element) { + return getWidget().getComponent(element); + } + + @Override + protected LayoutClickRpc getLayoutClickRPC() { + return rpc; + }; + + }; + + private GridLayoutServerRpc rpc; + private boolean needCaptionUpdate = false; + + @Override + public void init() { + rpc = RpcProxy.create(GridLayoutServerRpc.class, this); + getLayoutManager().registerDependency(this, + getWidget().spacingMeasureElement); + } + + @Override + public void onUnregister() { + VGridLayout layout = getWidget(); + getLayoutManager().unregisterDependency(this, + layout.spacingMeasureElement); + + // Unregister caption size dependencies + for (ComponentConnector child : getChildren()) { + Cell cell = layout.widgetToCell.get(child.getWidget()); + cell.slot.setCaption(null); + } + } + + @Override + public GridLayoutState getState() { + return (GridLayoutState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + clickEventHandler.handleEventHandlerRegistration(); + + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + VGridLayout layout = getWidget(); + layout.client = client; + + if (!isRealUpdate(uidl)) { + return; + } + + int cols = getState().getColumns(); + int rows = getState().getRows(); + + layout.columnWidths = new int[cols]; + layout.rowHeights = new int[rows]; + + layout.setSize(rows, cols); + + final int[] alignments = uidl.getIntArrayAttribute("alignments"); + int alignmentIndex = 0; + + for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) { + final UIDL r = (UIDL) i.next(); + if ("gr".equals(r.getTag())) { + for (final Iterator<?> j = r.getChildIterator(); j.hasNext();) { + final UIDL cellUidl = (UIDL) j.next(); + if ("gc".equals(cellUidl.getTag())) { + int row = cellUidl.getIntAttribute("y"); + int col = cellUidl.getIntAttribute("x"); + + Widget previousWidget = null; + + Cell cell = layout.getCell(row, col); + if (cell != null && cell.slot != null) { + // This is an update. Track if the widget changes + // and update the caption if that happens. This + // workaround can be removed once the DOM update is + // done in onContainerHierarchyChange + previousWidget = cell.slot.getWidget(); + } + + cell = layout.createCell(row, col); + + cell.updateFromUidl(cellUidl); + + if (cell.hasContent()) { + cell.setAlignment(new AlignmentInfo( + alignments[alignmentIndex++])); + if (cell.slot.getWidget() != previousWidget) { + // Widget changed or widget moved from another + // slot. Update its caption as the widget might + // have called updateCaption when the widget was + // still in its old slot. This workaround can be + // removed once the DOM update + // is done in onContainerHierarchyChange + updateCaption(ConnectorMap.get(getConnection()) + .getConnector(cell.slot.getWidget())); + } + } + } + } + } + } + + layout.colExpandRatioArray = uidl.getIntArrayAttribute("colExpand"); + layout.rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand"); + + layout.updateMarginStyleNames(new VMarginInfo(getState() + .getMarginsBitmask())); + + layout.updateSpacingStyleName(getState().isSpacing()); + + if (needCaptionUpdate) { + needCaptionUpdate = false; + + for (ComponentConnector child : getChildren()) { + updateCaption(child); + } + } + getLayoutManager().setNeedsLayout(this); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + VGridLayout layout = getWidget(); + + // clean non rendered components + for (ComponentConnector oldChild : event.getOldChildren()) { + if (oldChild.getParent() == this) { + continue; + } + + Widget childWidget = oldChild.getWidget(); + layout.remove(childWidget); + + Cell cell = layout.widgetToCell.remove(childWidget); + cell.slot.setCaption(null); + cell.slot.getWrapperElement().removeFromParent(); + cell.slot = null; + } + + } + + public void updateCaption(ComponentConnector childConnector) { + if (!childConnector.delegateCaptionHandling()) { + // Check not required by interface but by workarounds in this class + // when updateCaption is explicitly called for all children. + return; + } + + VGridLayout layout = getWidget(); + Cell cell = layout.widgetToCell.get(childConnector.getWidget()); + if (cell == null) { + // workaround before updateFromUidl is removed. We currently update + // the captions at the end of updateFromUidl instead of immediately + // because the DOM has not been set up at this point (as it is done + // in updateFromUidl) + needCaptionUpdate = true; + return; + } + if (VCaption.isNeeded(childConnector.getState())) { + VLayoutSlot layoutSlot = cell.slot; + VCaption caption = layoutSlot.getCaption(); + if (caption == null) { + caption = new VCaption(childConnector, getConnection()); + + Widget widget = childConnector.getWidget(); + + layout.setCaption(widget, caption); + } + caption.updateCaption(); + } else { + layout.setCaption(childConnector.getWidget(), null); + } + } + + @Override + public VGridLayout getWidget() { + return (VGridLayout) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VGridLayout.class); + } + + public void layoutVertically() { + getWidget().updateHeight(); + } + + public void layoutHorizontally() { + getWidget().updateWidth(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRpc.java new file mode 100644 index 0000000000..cd8df297ec --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutServerRpc.java @@ -0,0 +1,11 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.gridlayout; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; + +public interface GridLayoutServerRpc extends LayoutClickRpc, ServerRpc { + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutState.java b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutState.java new file mode 100644 index 0000000000..109dc7dea6 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/GridLayoutState.java @@ -0,0 +1,37 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.gridlayout; + +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutState; + +public class GridLayoutState extends AbstractLayoutState { + private boolean spacing = false; + private int rows = 0; + private int columns = 0; + + public boolean isSpacing() { + return spacing; + } + + public void setSpacing(boolean spacing) { + this.spacing = spacing; + } + + public int getRows() { + return rows; + } + + public void setRows(int rows) { + this.rows = rows; + } + + public int getColumns() { + return columns; + } + + public void setColumns(int cols) { + columns = cols; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/gridlayout/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/VGridLayout.java new file mode 100644 index 0000000000..7629e09cac --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/gridlayout/VGridLayout.java @@ -0,0 +1,702 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.gridlayout; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ui.AlignmentInfo; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; +import com.vaadin.terminal.gwt.client.ui.layout.ComponentConnectorLayoutSlot; +import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot; + +public class VGridLayout extends ComplexPanel { + + public static final String CLASSNAME = "v-gridlayout"; + + ApplicationConnection client; + + HashMap<Widget, Cell> widgetToCell = new HashMap<Widget, Cell>(); + + int[] columnWidths; + int[] rowHeights; + + int[] colExpandRatioArray; + + int[] rowExpandRatioArray; + + int[] minColumnWidths; + + private int[] minRowHeights; + + DivElement spacingMeasureElement; + + public VGridLayout() { + super(); + setElement(Document.get().createDivElement()); + + spacingMeasureElement = Document.get().createDivElement(); + Style spacingStyle = spacingMeasureElement.getStyle(); + spacingStyle.setPosition(Position.ABSOLUTE); + getElement().appendChild(spacingMeasureElement); + + setStyleName(CLASSNAME); + } + + private GridLayoutConnector getConnector() { + return (GridLayoutConnector) ConnectorMap.get(client) + .getConnector(this); + } + + /** + * Returns the column widths measured in pixels + * + * @return + */ + protected int[] getColumnWidths() { + return columnWidths; + } + + /** + * Returns the row heights measured in pixels + * + * @return + */ + protected int[] getRowHeights() { + return rowHeights; + } + + /** + * Returns the spacing between the cells horizontally in pixels + * + * @return + */ + protected int getHorizontalSpacing() { + return LayoutManager.get(client).getOuterWidth(spacingMeasureElement); + } + + /** + * Returns the spacing between the cells vertically in pixels + * + * @return + */ + protected int getVerticalSpacing() { + return LayoutManager.get(client).getOuterHeight(spacingMeasureElement); + } + + static int[] cloneArray(int[] toBeCloned) { + int[] clone = new int[toBeCloned.length]; + for (int i = 0; i < clone.length; i++) { + clone[i] = toBeCloned[i] * 1; + } + return clone; + } + + void expandRows() { + if (!isUndefinedHeight()) { + int usedSpace = minRowHeights[0]; + int verticalSpacing = getVerticalSpacing(); + for (int i = 1; i < minRowHeights.length; i++) { + usedSpace += verticalSpacing + minRowHeights[i]; + } + int availableSpace = LayoutManager.get(client).getInnerHeight( + getElement()); + int excessSpace = availableSpace - usedSpace; + int distributed = 0; + if (excessSpace > 0) { + for (int i = 0; i < rowHeights.length; i++) { + int ew = excessSpace * rowExpandRatioArray[i] / 1000; + rowHeights[i] = minRowHeights[i] + ew; + distributed += ew; + } + excessSpace -= distributed; + int c = 0; + while (excessSpace > 0) { + rowHeights[c % rowHeights.length]++; + excessSpace--; + c++; + } + } + } + } + + void updateHeight() { + // Detect minimum heights & calculate spans + detectRowHeights(); + + // Expand + expandRows(); + + // Position + layoutCellsVertically(); + } + + void updateWidth() { + // Detect widths & calculate spans + detectColWidths(); + // Expand + expandColumns(); + // Position + layoutCellsHorizontally(); + + } + + void expandColumns() { + if (!isUndefinedWidth()) { + int usedSpace = minColumnWidths[0]; + int horizontalSpacing = getHorizontalSpacing(); + for (int i = 1; i < minColumnWidths.length; i++) { + usedSpace += horizontalSpacing + minColumnWidths[i]; + } + + int availableSpace = LayoutManager.get(client).getInnerWidth( + getElement()); + int excessSpace = availableSpace - usedSpace; + int distributed = 0; + if (excessSpace > 0) { + for (int i = 0; i < columnWidths.length; i++) { + int ew = excessSpace * colExpandRatioArray[i] / 1000; + columnWidths[i] = minColumnWidths[i] + ew; + distributed += ew; + } + excessSpace -= distributed; + int c = 0; + while (excessSpace > 0) { + columnWidths[c % columnWidths.length]++; + excessSpace--; + c++; + } + } + } + } + + void layoutCellsVertically() { + int verticalSpacing = getVerticalSpacing(); + LayoutManager layoutManager = LayoutManager.get(client); + Element element = getElement(); + int paddingTop = layoutManager.getPaddingTop(element); + int paddingBottom = layoutManager.getPaddingBottom(element); + int y = paddingTop; + + for (int i = 0; i < cells.length; i++) { + y = paddingTop; + for (int j = 0; j < cells[i].length; j++) { + Cell cell = cells[i][j]; + if (cell != null) { + int reservedMargin; + if (cell.rowspan + j >= cells[i].length) { + // Make room for layout padding for cells reaching the + // bottom of the layout + reservedMargin = paddingBottom; + } else { + reservedMargin = 0; + } + cell.layoutVertically(y, reservedMargin); + } + y += rowHeights[j] + verticalSpacing; + } + } + + if (isUndefinedHeight()) { + int outerHeight = y - verticalSpacing + + layoutManager.getPaddingBottom(element) + + layoutManager.getBorderHeight(element); + element.getStyle().setHeight(outerHeight, Unit.PX); + getConnector().getLayoutManager().reportOuterHeight(getConnector(), + outerHeight); + } + } + + void layoutCellsHorizontally() { + LayoutManager layoutManager = LayoutManager.get(client); + Element element = getElement(); + int x = layoutManager.getPaddingLeft(element); + int paddingRight = layoutManager.getPaddingRight(element); + int horizontalSpacing = getHorizontalSpacing(); + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + Cell cell = cells[i][j]; + if (cell != null) { + int reservedMargin; + // Make room for layout padding for cells reaching the + // right edge of the layout + if (i + cell.colspan >= cells.length) { + reservedMargin = paddingRight; + } else { + reservedMargin = 0; + } + cell.layoutHorizontally(x, reservedMargin); + } + } + x += columnWidths[i] + horizontalSpacing; + } + + if (isUndefinedWidth()) { + int outerWidth = x - horizontalSpacing + + layoutManager.getPaddingRight(element) + + layoutManager.getBorderWidth(element); + element.getStyle().setWidth(outerWidth, Unit.PX); + getConnector().getLayoutManager().reportOuterWidth(getConnector(), + outerWidth); + } + } + + private boolean isUndefinedHeight() { + return getConnector().isUndefinedHeight(); + } + + private boolean isUndefinedWidth() { + return getConnector().isUndefinedWidth(); + } + + private void detectRowHeights() { + for (int i = 0; i < rowHeights.length; i++) { + rowHeights[i] = 0; + } + + // collect min rowheight from non-rowspanned cells + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + Cell cell = cells[i][j]; + if (cell != null) { + if (cell.rowspan == 1) { + if (!cell.hasRelativeHeight() + && rowHeights[j] < cell.getHeight()) { + rowHeights[j] = cell.getHeight(); + } + } else { + storeRowSpannedCell(cell); + } + } + } + } + + distributeRowSpanHeights(); + + minRowHeights = cloneArray(rowHeights); + } + + private void detectColWidths() { + // collect min colwidths from non-colspanned cells + for (int i = 0; i < columnWidths.length; i++) { + columnWidths[i] = 0; + } + + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + Cell cell = cells[i][j]; + if (cell != null) { + if (cell.colspan == 1) { + if (!cell.hasRelativeWidth() + && columnWidths[i] < cell.getWidth()) { + columnWidths[i] = cell.getWidth(); + } + } else { + storeColSpannedCell(cell); + } + } + } + } + + distributeColSpanWidths(); + + minColumnWidths = cloneArray(columnWidths); + } + + private void storeRowSpannedCell(Cell cell) { + SpanList l = null; + for (SpanList list : rowSpans) { + if (list.span < cell.rowspan) { + continue; + } else { + // insert before this + l = list; + break; + } + } + if (l == null) { + l = new SpanList(cell.rowspan); + rowSpans.add(l); + } else if (l.span != cell.rowspan) { + SpanList newL = new SpanList(cell.rowspan); + rowSpans.add(rowSpans.indexOf(l), newL); + l = newL; + } + l.cells.add(cell); + } + + /** + * Iterates colspanned cells, ensures cols have enough space to accommodate + * them + */ + void distributeColSpanWidths() { + for (SpanList list : colSpans) { + for (Cell cell : list.cells) { + // cells with relative content may return non 0 here if on + // subsequent renders + int width = cell.hasRelativeWidth() ? 0 : cell.getWidth(); + distributeSpanSize(columnWidths, cell.col, cell.colspan, + getHorizontalSpacing(), width, colExpandRatioArray); + } + } + } + + /** + * Iterates rowspanned cells, ensures rows have enough space to accommodate + * them + */ + private void distributeRowSpanHeights() { + for (SpanList list : rowSpans) { + for (Cell cell : list.cells) { + // cells with relative content may return non 0 here if on + // subsequent renders + int height = cell.hasRelativeHeight() ? 0 : cell.getHeight(); + distributeSpanSize(rowHeights, cell.row, cell.rowspan, + getVerticalSpacing(), height, rowExpandRatioArray); + } + } + } + + private static void distributeSpanSize(int[] dimensions, + int spanStartIndex, int spanSize, int spacingSize, int size, + int[] expansionRatios) { + int allocated = dimensions[spanStartIndex]; + for (int i = 1; i < spanSize; i++) { + allocated += spacingSize + dimensions[spanStartIndex + i]; + } + if (allocated < size) { + // dimensions needs to be expanded due spanned cell + int neededExtraSpace = size - allocated; + int allocatedExtraSpace = 0; + + // Divide space according to expansion ratios if any span has a + // ratio + int totalExpansion = 0; + for (int i = 0; i < spanSize; i++) { + int itemIndex = spanStartIndex + i; + totalExpansion += expansionRatios[itemIndex]; + } + + for (int i = 0; i < spanSize; i++) { + int itemIndex = spanStartIndex + i; + int expansion; + if (totalExpansion == 0) { + // Divide equally among all cells if there are no + // expansion ratios + expansion = neededExtraSpace / spanSize; + } else { + expansion = neededExtraSpace * expansionRatios[itemIndex] + / totalExpansion; + } + dimensions[itemIndex] += expansion; + allocatedExtraSpace += expansion; + } + + // We might still miss a couple of pixels because of + // rounding errors... + if (neededExtraSpace > allocatedExtraSpace) { + for (int i = 0; i < spanSize; i++) { + // Add one pixel to every cell until we have + // compensated for any rounding error + int itemIndex = spanStartIndex + i; + dimensions[itemIndex] += 1; + allocatedExtraSpace += 1; + if (neededExtraSpace == allocatedExtraSpace) { + break; + } + } + } + } + } + + private LinkedList<SpanList> colSpans = new LinkedList<SpanList>(); + private LinkedList<SpanList> rowSpans = new LinkedList<SpanList>(); + + private class SpanList { + final int span; + List<Cell> cells = new LinkedList<Cell>(); + + public SpanList(int span) { + this.span = span; + } + } + + void storeColSpannedCell(Cell cell) { + SpanList l = null; + for (SpanList list : colSpans) { + if (list.span < cell.colspan) { + continue; + } else { + // insert before this + l = list; + break; + } + } + if (l == null) { + l = new SpanList(cell.colspan); + colSpans.add(l); + } else if (l.span != cell.colspan) { + + SpanList newL = new SpanList(cell.colspan); + colSpans.add(colSpans.indexOf(l), newL); + l = newL; + } + l.cells.add(cell); + } + + Cell[][] cells; + + /** + * Private helper class. + */ + class Cell { + public Cell(int row, int col) { + this.row = row; + this.col = col; + } + + public boolean hasContent() { + return hasContent; + } + + public boolean hasRelativeHeight() { + if (slot != null) { + return slot.getChild().isRelativeHeight(); + } else { + return true; + } + } + + /** + * @return total of spanned cols + */ + private int getAvailableWidth() { + int width = columnWidths[col]; + for (int i = 1; i < colspan; i++) { + width += getHorizontalSpacing() + columnWidths[col + i]; + } + return width; + } + + /** + * @return total of spanned rows + */ + private int getAvailableHeight() { + int height = rowHeights[row]; + for (int i = 1; i < rowspan; i++) { + height += getVerticalSpacing() + rowHeights[row + i]; + } + return height; + } + + public void layoutHorizontally(int x, int marginRight) { + if (slot != null) { + slot.positionHorizontally(x, getAvailableWidth(), marginRight); + } + } + + public void layoutVertically(int y, int marginBottom) { + if (slot != null) { + slot.positionVertically(y, getAvailableHeight(), marginBottom); + } + } + + public int getWidth() { + if (slot != null) { + return slot.getUsedWidth(); + } else { + return 0; + } + } + + public int getHeight() { + if (slot != null) { + return slot.getUsedHeight(); + } else { + return 0; + } + } + + protected boolean hasRelativeWidth() { + if (slot != null) { + return slot.getChild().isRelativeWidth(); + } else { + return true; + } + } + + final int row; + final int col; + int colspan = 1; + int rowspan = 1; + + private boolean hasContent; + + private AlignmentInfo alignment; + + ComponentConnectorLayoutSlot slot; + + public void updateFromUidl(UIDL cellUidl) { + // Set cell width + colspan = cellUidl.hasAttribute("w") ? cellUidl + .getIntAttribute("w") : 1; + // Set cell height + rowspan = cellUidl.hasAttribute("h") ? cellUidl + .getIntAttribute("h") : 1; + // ensure we will lose reference to old cells, now overlapped by + // this cell + for (int i = 0; i < colspan; i++) { + for (int j = 0; j < rowspan; j++) { + if (i > 0 || j > 0) { + cells[col + i][row + j] = null; + } + } + } + + UIDL childUidl = cellUidl.getChildUIDL(0); // we are interested + // about childUidl + hasContent = childUidl != null; + if (hasContent) { + ComponentConnector childConnector = client + .getPaintable(childUidl); + + if (slot == null || slot.getChild() != childConnector) { + slot = new ComponentConnectorLayoutSlot(CLASSNAME, + childConnector, getConnector()); + if (childConnector.isRelativeWidth()) { + slot.getWrapperElement().getStyle() + .setWidth(100, Unit.PCT); + } + Element slotWrapper = slot.getWrapperElement(); + getElement().appendChild(slotWrapper); + + Widget widget = childConnector.getWidget(); + insert(widget, slotWrapper, getWidgetCount(), false); + Cell oldCell = widgetToCell.put(widget, this); + if (oldCell != null) { + oldCell.slot.getWrapperElement().removeFromParent(); + oldCell.slot = null; + } + } + + } + } + + public void setAlignment(AlignmentInfo alignmentInfo) { + slot.setAlignment(alignmentInfo); + } + } + + Cell getCell(int row, int col) { + return cells[col][row]; + } + + /** + * Creates a new Cell with the given coordinates. If an existing cell was + * found, returns that one. + * + * @param row + * @param col + * @return + */ + Cell createCell(int row, int col) { + Cell cell = getCell(row, col); + if (cell == null) { + cell = new Cell(row, col); + cells[col][row] = cell; + } + return cell; + } + + /** + * Returns the deepest nested child component which contains "element". The + * child component is also returned if "element" is part of its caption. + * + * @param element + * An element that is a nested sub element of the root element in + * this layout + * @return The Paintable which the element is a part of. Null if the element + * belongs to the layout and not to a child. + */ + ComponentConnector getComponent(Element element) { + return Util.getConnectorForElement(client, this, element); + } + + void setCaption(Widget widget, VCaption caption) { + VLayoutSlot slot = widgetToCell.get(widget).slot; + + if (caption != null) { + // Logical attach. + getChildren().add(caption); + } + + // Physical attach if not null, also removes old caption + slot.setCaption(caption); + + if (caption != null) { + // Adopt. + adopt(caption); + } + } + + private void togglePrefixedStyleName(String name, boolean enabled) { + if (enabled) { + addStyleDependentName(name); + } else { + removeStyleDependentName(name); + } + } + + void updateMarginStyleNames(VMarginInfo marginInfo) { + togglePrefixedStyleName("margin-top", marginInfo.hasTop()); + togglePrefixedStyleName("margin-right", marginInfo.hasRight()); + togglePrefixedStyleName("margin-bottom", marginInfo.hasBottom()); + togglePrefixedStyleName("margin-left", marginInfo.hasLeft()); + } + + void updateSpacingStyleName(boolean spacingEnabled) { + String styleName = getStylePrimaryName(); + if (spacingEnabled) { + spacingMeasureElement.addClassName(styleName + "-spacing-on"); + spacingMeasureElement.removeClassName(styleName + "-spacing-off"); + } else { + spacingMeasureElement.removeClassName(styleName + "-spacing-on"); + spacingMeasureElement.addClassName(styleName + "-spacing-off"); + } + } + + public void setSize(int rows, int cols) { + if (cells == null) { + cells = new Cell[cols][rows]; + } else if (cells.length != cols || cells[0].length != rows) { + Cell[][] newCells = new Cell[cols][rows]; + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < cells[i].length; j++) { + if (i < cols && j < rows) { + newCells[i][j] = cells[i][j]; + } + } + } + cells = newCells; + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java new file mode 100644 index 0000000000..308a4860b5 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java @@ -0,0 +1,74 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.label; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.PreElement; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.Label; + +@Connect(value = Label.class, loadStyle = LoadStyle.EAGER) +public class LabelConnector extends AbstractComponentConnector implements + Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().setConnection(client); + if (!isRealUpdate(uidl)) { + return; + } + + boolean sinkOnloads = false; + + final String mode = uidl.getStringAttribute("mode"); + if (mode == null || "text".equals(mode)) { + getWidget().setText(uidl.getChildString(0)); + } else if ("pre".equals(mode)) { + PreElement preElement = Document.get().createPreElement(); + preElement.setInnerText(uidl.getChildUIDL(0).getChildString(0)); + // clear existing content + getWidget().setHTML(""); + // add preformatted text to dom + getWidget().getElement().appendChild(preElement); + } else if ("uidl".equals(mode)) { + getWidget().setHTML(uidl.getChildrenAsXML()); + } else if ("xhtml".equals(mode)) { + UIDL content = uidl.getChildUIDL(0).getChildUIDL(0); + if (content.getChildCount() > 0) { + getWidget().setHTML(content.getChildString(0)); + } else { + getWidget().setHTML(""); + } + sinkOnloads = true; + } else if ("xml".equals(mode)) { + getWidget().setHTML(uidl.getChildUIDL(0).getChildString(0)); + } else if ("raw".equals(mode)) { + getWidget().setHTML(uidl.getChildUIDL(0).getChildString(0)); + sinkOnloads = true; + } else { + getWidget().setText(""); + } + if (sinkOnloads) { + Util.sinkOnloadForImages(getWidget().getElement()); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VLabel.class); + } + + @Override + public VLabel getWidget() { + return (VLabel) super.getWidget(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java b/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java new file mode 100644 index 0000000000..f47b8437b7 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java @@ -0,0 +1,73 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.label; + +import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.HTML; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VTooltip; + +public class VLabel extends HTML { + + public static final String CLASSNAME = "v-label"; + private static final String CLASSNAME_UNDEFINED_WIDTH = "v-label-undef-w"; + + private ApplicationConnection connection; + + public VLabel() { + super(); + setStyleName(CLASSNAME); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + } + + public VLabel(String text) { + super(text); + setStyleName(CLASSNAME); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (event.getTypeInt() == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + event.stopPropagation(); + return; + } + if (connection != null) { + connection.handleTooltipEvent(event, this); + } + } + + @Override + public void setWidth(String width) { + super.setWidth(width); + if (width == null || width.equals("")) { + setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true); + getElement().getStyle().setDisplay(Display.INLINE_BLOCK); + } else { + setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false); + getElement().getStyle().clearDisplay(); + } + } + + @Override + public void setText(String text) { + if (BrowserInfo.get().isIE8()) { + // #3983 - IE8 incorrectly replaces \n with <br> so we do the + // escaping manually and set as HTML + super.setHTML(Util.escapeHTML(text)); + } else { + super.setText(text); + } + } + + void setConnection(ApplicationConnection client) { + connection = client; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java deleted file mode 100644 index 2ca58a38c2..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java +++ /dev/null @@ -1,397 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui.layout; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.dom.client.Style; -import com.google.gwt.user.client.ui.ComplexPanel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.ui.VMarginInfo; - -public abstract class CellBasedLayout extends ComplexPanel implements Container { - - protected Map<Widget, ChildComponentContainer> widgetToComponentContainer = new HashMap<Widget, ChildComponentContainer>(); - - protected ApplicationConnection client = null; - - protected DivElement root; - - public static final int ORIENTATION_VERTICAL = 0; - public static final int ORIENTATION_HORIZONTAL = 1; - - protected Margins activeMargins = new Margins(0, 0, 0, 0); - protected VMarginInfo activeMarginsInfo = new VMarginInfo(-1); - - protected boolean spacingEnabled = false; - protected final Spacing spacingFromCSS = new Spacing(12, 12); - protected final Spacing activeSpacing = new Spacing(0, 0); - - private boolean dynamicWidth; - - private boolean dynamicHeight; - - private final DivElement clearElement = Document.get().createDivElement(); - - private String lastStyleName = ""; - - private boolean marginsNeedsRecalculation = false; - - protected String STYLENAME_SPACING = ""; - protected String STYLENAME_MARGIN_TOP = ""; - protected String STYLENAME_MARGIN_RIGHT = ""; - protected String STYLENAME_MARGIN_BOTTOM = ""; - protected String STYLENAME_MARGIN_LEFT = ""; - - public static class Spacing { - - public int hSpacing = 0; - public int vSpacing = 0; - - public Spacing(int hSpacing, int vSpacing) { - this.hSpacing = hSpacing; - this.vSpacing = vSpacing; - } - - @Override - public String toString() { - return "Spacing [hSpacing=" + hSpacing + ",vSpacing=" + vSpacing - + "]"; - } - - } - - public CellBasedLayout() { - super(); - - setElement(Document.get().createDivElement()); - getElement().getStyle().setProperty("overflow", "hidden"); - if (BrowserInfo.get().isIE()) { - getElement().getStyle().setProperty("position", "relative"); - getElement().getStyle().setProperty("zoom", "1"); - } - - root = Document.get().createDivElement(); - root.getStyle().setProperty("overflow", "hidden"); - if (BrowserInfo.get().isIE()) { - root.getStyle().setProperty("position", "relative"); - } - - getElement().appendChild(root); - - Style style = clearElement.getStyle(); - style.setProperty("width", "0px"); - style.setProperty("height", "0px"); - style.setProperty("clear", "both"); - style.setProperty("overflow", "hidden"); - root.appendChild(clearElement); - - } - - public boolean hasChildComponent(Widget component) { - return widgetToComponentContainer.containsKey(component); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - - // Only non-cached UIDL:s can introduce changes - if (uidl.getBooleanAttribute("cached")) { - return; - } - - /** - * Margin and spacind detection depends on classNames and must be set - * before setting size. Here just update the details from UIDL and from - * overridden setStyleName run actual margin detections. - */ - updateMarginAndSpacingInfo(uidl); - - /* - * This call should be made first. Ensure correct implementation, handle - * size etc. - */ - if (client.updateComponent(this, uidl, true)) { - return; - } - - handleDynamicDimensions(uidl); - } - - @Override - public void setStyleName(String styleName) { - super.setStyleName(styleName); - - if (isAttached() && marginsNeedsRecalculation - || !lastStyleName.equals(styleName)) { - measureMarginsAndSpacing(); - lastStyleName = styleName; - marginsNeedsRecalculation = false; - } - - } - - @Override - public void setWidth(String width) { - super.setWidth(width); - - /* - * Ensure the the dynamic width stays up to date even if size is altered - * only on client side. - */ - if (width == null || width.equals("")) { - dynamicWidth = true; - } else { - dynamicWidth = false; - } - } - - private void handleDynamicDimensions(UIDL uidl) { - String w = uidl.hasAttribute("width") ? uidl - .getStringAttribute("width") : ""; - - String h = uidl.hasAttribute("height") ? uidl - .getStringAttribute("height") : ""; - - if (w.equals("")) { - dynamicWidth = true; - } else { - dynamicWidth = false; - } - - if (h.equals("")) { - dynamicHeight = true; - } else { - dynamicHeight = false; - } - - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - - /* - * Ensure the the dynamic height stays up to date even if size is - * altered only on client side. - */ - if (height == null || height.equals("")) { - dynamicHeight = true; - } else { - dynamicHeight = false; - } - } - - protected void addOrMoveChild(ChildComponentContainer childComponent, - int position) { - if (childComponent.getParent() == this) { - if (getWidgetIndex(childComponent) != position) { - // Detach from old position child. - childComponent.removeFromParent(); - - // Logical attach. - getChildren().insert(childComponent, position); - - root.insertBefore(childComponent.getElement(), root - .getChildNodes().getItem(position)); - - adopt(childComponent); - } - } else { - widgetToComponentContainer.put(childComponent.getWidget(), - childComponent); - - // Logical attach. - getChildren().insert(childComponent, position); - - // avoid inserts (they are slower than appends) - boolean insert = true; - if (widgetToComponentContainer.size() == position) { - insert = false; - } - if (insert) { - root.insertBefore(childComponent.getElement(), root - .getChildNodes().getItem(position)); - } else { - root.insertBefore(childComponent.getElement(), clearElement); - } - // Adopt. - adopt(childComponent); - - } - - } - - protected ChildComponentContainer getComponentContainer(Widget child) { - return widgetToComponentContainer.get(child); - } - - protected boolean isDynamicWidth() { - return dynamicWidth; - } - - protected boolean isDynamicHeight() { - return dynamicHeight; - } - - private void updateMarginAndSpacingInfo(UIDL uidl) { - if (!uidl.hasAttribute("invisible")) { - int bitMask = uidl.getIntAttribute("margins"); - if (activeMarginsInfo.getBitMask() != bitMask) { - activeMarginsInfo = new VMarginInfo(bitMask); - marginsNeedsRecalculation = true; - } - boolean spacing = uidl.getBooleanAttribute("spacing"); - if (spacing != spacingEnabled) { - marginsNeedsRecalculation = true; - spacingEnabled = spacing; - } - } - } - - private static DivElement measurement; - private static DivElement measurement2; - private static DivElement measurement3; - private static DivElement helper; - - static { - helper = Document.get().createDivElement(); - helper.setInnerHTML("<div style=\"position:absolute;top:0;left:0;height:0;visibility:hidden;overflow:hidden;\">" - + "<div style=\"width:0;height:0;visibility:hidden;overflow:hidden;\">" - + "</div></div>" - + "<div style=\"position:absolute;height:0;overflow:hidden;\"></div>"); - NodeList<Node> childNodes = helper.getChildNodes(); - measurement = (DivElement) childNodes.getItem(0); - measurement2 = (DivElement) measurement.getFirstChildElement(); - measurement3 = (DivElement) childNodes.getItem(1); - } - - protected boolean measureMarginsAndSpacing() { - if (!isAttached()) { - return false; - } - - // Measure spacing (actually CSS padding) - measurement3.setClassName(STYLENAME_SPACING - + (spacingEnabled ? "-on" : "-off")); - - String sn = getStylePrimaryName() + "-margin"; - - if (activeMarginsInfo.hasTop()) { - sn += " " + STYLENAME_MARGIN_TOP; - } - if (activeMarginsInfo.hasBottom()) { - sn += " " + STYLENAME_MARGIN_BOTTOM; - } - if (activeMarginsInfo.hasLeft()) { - sn += " " + STYLENAME_MARGIN_LEFT; - } - if (activeMarginsInfo.hasRight()) { - sn += " " + STYLENAME_MARGIN_RIGHT; - } - - // Measure top and left margins (actually CSS padding) - measurement.setClassName(sn); - - root.appendChild(helper); - - activeSpacing.vSpacing = measurement3.getOffsetHeight(); - activeSpacing.hSpacing = measurement3.getOffsetWidth(); - - activeMargins.setMarginTop(measurement2.getOffsetTop()); - activeMargins.setMarginLeft(measurement2.getOffsetLeft()); - activeMargins.setMarginRight(measurement.getOffsetWidth() - - activeMargins.getMarginLeft()); - activeMargins.setMarginBottom(measurement.getOffsetHeight() - - activeMargins.getMarginTop()); - - // ApplicationConnection.getConsole().log("Margins: " + activeMargins); - // ApplicationConnection.getConsole().log("Spacing: " + activeSpacing); - // Util.alert("Margins: " + activeMargins); - root.removeChild(helper); - - // apply margin - Style style = root.getStyle(); - style.setPropertyPx("marginLeft", activeMargins.getMarginLeft()); - style.setPropertyPx("marginRight", activeMargins.getMarginRight()); - style.setPropertyPx("marginTop", activeMargins.getMarginTop()); - style.setPropertyPx("marginBottom", activeMargins.getMarginBottom()); - - return true; - } - - protected ChildComponentContainer getFirstChildComponentContainer() { - int size = getChildren().size(); - if (size < 1) { - return null; - } - - return (ChildComponentContainer) getChildren().get(0); - } - - protected void removeChildrenAfter(int pos) { - // Remove all children after position "pos" but leave the clear element - // in place - - int toRemove = getChildren().size() - pos; - while (toRemove-- > 0) { - /* flag to not if widget has been moved and rendered elsewhere */ - boolean relocated = false; - ChildComponentContainer child = (ChildComponentContainer) getChildren() - .get(pos); - Widget widget = child.getWidget(); - if (widget == null) { - // a rare case where child component has been relocated and - // rendered elsewhere - // clean widgetToComponentContainer map by iterating the correct - // mapping - Iterator<Widget> iterator = widgetToComponentContainer.keySet() - .iterator(); - while (iterator.hasNext()) { - Widget key = iterator.next(); - if (widgetToComponentContainer.get(key) == child) { - widget = key; - relocated = true; - break; - } - } - if (widget == null) { - throw new NullPointerException(); - } - } - // ChildComponentContainer remove = - widgetToComponentContainer.remove(widget); - remove(child); - if (!relocated) { - Paintable p = (Paintable) widget; - client.unregisterPaintable(p); - } - } - - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - ChildComponentContainer componentContainer = widgetToComponentContainer - .remove(oldComponent); - if (componentContainer == null) { - return; - } - - componentContainer.setWidget(newComponent); - client.unregisterPaintable((Paintable) oldComponent); - widgetToComponentContainer.put(newComponent, componentContainer); - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java deleted file mode 100644 index 36d18306fa..0000000000 --- a/src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java +++ /dev/null @@ -1,794 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.client.ui.layout; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -import com.google.gwt.dom.client.DivElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Style; -import com.google.gwt.dom.client.Style.BorderStyle; -import com.google.gwt.dom.client.TableElement; -import com.google.gwt.user.client.ui.Panel; -import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize; -import com.vaadin.terminal.gwt.client.RenderInformation.Size; -import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VCaption; -import com.vaadin.terminal.gwt.client.VConsole; -import com.vaadin.terminal.gwt.client.ui.AlignmentInfo; - -public class ChildComponentContainer extends Panel { - - /** - * Size of the container DIV excluding any margins and also excluding the - * expansion amount (containerExpansion) - */ - private Size contSize = new Size(0, 0); - - /** - * Size of the widget inside the container DIV - */ - private Size widgetSize = new Size(0, 0); - /** - * Size of the caption - */ - private int captionRequiredWidth = 0; - private int captionWidth = 0; - private int captionHeight = 0; - - /** - * - * Padding added to the container when it is larger than the component. - */ - private Size containerExpansion = new Size(0, 0); - - private double expandRatio; - - // private int containerMarginLeft = 0; - private int containerMarginTop = 0; - - AlignmentInfo alignment = AlignmentInfo.TOP_LEFT; - - private int alignmentLeftOffsetForWidget = 0; - private int alignmentLeftOffsetForCaption = 0; - /** - * Top offset for implementing alignment. Top offset is set to the container - * DIV as it otherwise would have to be set to either the Caption or the - * Widget depending on whether there is a caption and where the caption is - * located. - */ - private int alignmentTopOffset = 0; - - // private Margins alignmentOffset = new Margins(0, 0, 0, 0); - private VCaption caption = null; - private DivElement containerDIV; - private DivElement widgetDIV; - private Widget widget; - private FloatSize relativeSize = null; - - public ChildComponentContainer(Widget widget, int orientation) { - super(); - - containerDIV = Document.get().createDivElement(); - - widgetDIV = Document.get().createDivElement(); - if (BrowserInfo.get().isFF2()) { - // Style style = widgetDIV.getStyle(); - // FF2 chokes on some floats very easily. Measuring size escpecially - // becomes terribly slow - TableElement tableEl = Document.get().createTableElement(); - tableEl.setInnerHTML("<tbody><tr><td><div></div></td></tr></tbody>"); - DivElement div = (DivElement) tableEl.getFirstChildElement() - .getFirstChildElement().getFirstChildElement() - .getFirstChildElement(); - tableEl.setCellPadding(0); - tableEl.setCellSpacing(0); - tableEl.setBorder(0); - div.getStyle().setProperty("padding", "0"); - - setElement(tableEl); - containerDIV = div; - } else { - setFloat(widgetDIV, "left"); - setElement(containerDIV); - containerDIV.getStyle().setProperty("height", "0"); - containerDIV.getStyle().setProperty("width", "0px"); - containerDIV.getStyle().setProperty("overflow", "hidden"); - } - - if (BrowserInfo.get().isIE()) { - /* - * IE requires position: relative on overflow:hidden elements if - * they should hide position:relative elements. Without this e.g. a - * 1000x1000 Panel inside an 500x500 OrderedLayout will not be - * clipped but fully shown. - */ - containerDIV.getStyle().setProperty("position", "relative"); - widgetDIV.getStyle().setProperty("position", "relative"); - } - - containerDIV.appendChild(widgetDIV); - - setOrientation(orientation); - - setWidget(widget); - - } - - public void setWidget(Widget w) { - // Validate - if (w == widget) { - return; - } - - // Detach new child. - if (w != null) { - w.removeFromParent(); - } - - // Remove old child. - if (widget != null) { - remove(widget); - } - - // Logical attach. - widget = w; - - if (w != null) { - // Physical attach. - widgetDIV.appendChild(widget.getElement()); - adopt(w); - } - } - - private static void setFloat(Element div, String floatString) { - if (BrowserInfo.get().isIE()) { - div.getStyle().setProperty("styleFloat", floatString); - // IE requires display:inline for margin-left to work together - // with float:left - if (floatString.equals("left")) { - div.getStyle().setProperty("display", "inline"); - } else { - div.getStyle().setProperty("display", "block"); - } - - } else { - div.getStyle().setProperty("cssFloat", floatString); - } - } - - public void setOrientation(int orientation) { - if (orientation == CellBasedLayout.ORIENTATION_HORIZONTAL) { - setFloat(getElement(), "left"); - } else { - setFloat(getElement(), ""); - } - setHeight("0px"); - // setWidth("0px"); - contSize.setHeight(0); - contSize.setWidth(0); - // containerMarginLeft = 0; - containerMarginTop = 0; - containerDIV.getStyle().setProperty("paddingLeft", "0"); - containerDIV.getStyle().setProperty("paddingTop", "0"); - - containerExpansion.setHeight(0); - containerExpansion.setWidth(0); - - // Clear old alignments - clearAlignments(); - - } - - public void renderChild(UIDL childUIDL, ApplicationConnection client, - int fixedWidth) { - /* - * Must remove width specification from container before rendering to - * allow components to grow in horizontal direction. - * - * For fixed width layouts we specify the width directly so that height - * is automatically calculated correctly (e.g. for Labels). - */ - /* - * This should no longer be needed (after #2563) as all components are - * such that they can be rendered inside a 0x0 DIV. - * - * The exception seems to be complex components (Tree and Table) on - * Opera (#3444). - */ - if (fixedWidth < 0 && BrowserInfo.get().isOpera()) { - setUnlimitedContainerWidth(); - } - ((Paintable) widget).updateFromUIDL(childUIDL, client); - } - - public void setUnlimitedContainerWidth() { - setLimitedContainerWidth(1000000); - } - - public void setLimitedContainerWidth(int width) { - containerDIV.getStyle().setProperty("width", width + "px"); - } - - public void updateWidgetSize() { - /* - * Widget wrapper includes margin which the widget offsetWidth/Height - * does not include - */ - int w = Util.getRequiredWidth(widgetDIV); - - // IE7 ignores the width of the content if there's a border (#3915) - if (BrowserInfo.get().isIE7()) { - // Also read the inner width of the target element - int clientWidth = widget.getElement().getClientWidth(); - - // If the widths are different, there might be a border involved and - // then the width should be calculated without borders - if (w != clientWidth) { - // Remember old border style and remove current border - Style style = widget.getElement().getStyle(); - String oldBorderStyle = style.getBorderStyle(); - style.setBorderStyle(BorderStyle.NONE); - - // Calculate width without borders - int newWidth = Util.getRequiredWidth(widgetDIV); - - // Restore old border style - style.setProperty("borderStyle", oldBorderStyle); - - // Borders triggered the bug if the element is wider without - // borders - if (newWidth > w) { - // Use new measured width + the border width calculated as - // the difference between previous inner and outer widths - w = newWidth + (w - clientWidth); - } - } - } - - int h = Util.getRequiredHeight(widgetDIV); - - widgetSize.setWidth(w); - widgetSize.setHeight(h); - - // ApplicationConnection.getConsole().log( - // Util.getSimpleName(widget) + " size is " + w + "," + h); - - } - - public void setMarginLeft(int marginLeft) { - // containerMarginLeft = marginLeft; - containerDIV.getStyle().setPropertyPx("paddingLeft", marginLeft); - } - - public void setMarginTop(int marginTop) { - containerMarginTop = marginTop; - containerDIV.getStyle().setPropertyPx("paddingTop", - marginTop + alignmentTopOffset); - - updateContainerDOMSize(); - } - - public void updateAlignments(int parentWidth, int parentHeight) { - if (parentHeight == -1) { - parentHeight = contSize.getHeight(); - } - if (parentWidth == -1) { - parentWidth = contSize.getWidth(); - } - - alignmentTopOffset = calculateVerticalAlignmentTopOffset(parentHeight); - - calculateHorizontalAlignment(parentWidth); - - applyAlignments(); - - } - - private void applyAlignments() { - - // Update top margin to take alignment into account - setMarginTop(containerMarginTop); - - if (caption != null) { - caption.getElement().getStyle() - .setPropertyPx("marginLeft", alignmentLeftOffsetForCaption); - } - widgetDIV.getStyle().setPropertyPx("marginLeft", - alignmentLeftOffsetForWidget); - } - - public int getCaptionRequiredWidth() { - if (caption == null) { - return 0; - } - - return captionRequiredWidth; - } - - public int getCaptionWidth() { - if (caption == null) { - return 0; - } - - return captionWidth; - } - - public int getCaptionHeight() { - if (caption == null) { - return 0; - } - - return captionHeight; - } - - public int getCaptionWidthAfterComponent() { - if (caption == null || !caption.shouldBePlacedAfterComponent()) { - return 0; - } - - return getCaptionWidth(); - } - - public int getCaptionHeightAboveComponent() { - if (caption == null || caption.shouldBePlacedAfterComponent()) { - return 0; - } - - return getCaptionHeight(); - } - - private int calculateVerticalAlignmentTopOffset(int emptySpace) { - if (alignment.isTop()) { - return 0; - } - - if (caption != null) { - if (caption.shouldBePlacedAfterComponent()) { - /* - * Take into account the rare case that the caption on the right - * side of the component AND is higher than the component - */ - emptySpace -= Math.max(widgetSize.getHeight(), - caption.getHeight()); - } else { - emptySpace -= widgetSize.getHeight(); - emptySpace -= getCaptionHeight(); - } - } else { - /* - * There is no caption and thus we do not need to take anything but - * the widget into account - */ - emptySpace -= widgetSize.getHeight(); - } - - int top = 0; - if (alignment.isVerticalCenter()) { - top = emptySpace / 2; - } else if (alignment.isBottom()) { - top = emptySpace; - } - - if (top < 0) { - top = 0; - } - return top; - } - - private void calculateHorizontalAlignment(int emptySpace) { - alignmentLeftOffsetForCaption = 0; - alignmentLeftOffsetForWidget = 0; - - if (alignment.isLeft()) { - return; - } - - int captionSpace = emptySpace; - int widgetSpace = emptySpace; - - if (caption != null) { - // There is a caption - if (caption.shouldBePlacedAfterComponent()) { - /* - * The caption is after component. In this case the caption - * needs no alignment. - */ - captionSpace = 0; - widgetSpace -= widgetSize.getWidth(); - widgetSpace -= getCaptionWidth(); - } else { - /* - * The caption is above the component. Caption and widget needs - * separate alignment offsets. - */ - widgetSpace -= widgetSize.getWidth(); - captionSpace -= getCaptionWidth(); - } - } else { - /* - * There is no caption and thus we do not need to take anything but - * the widget into account - */ - captionSpace = 0; - widgetSpace -= widgetSize.getWidth(); - } - - if (alignment.isHorizontalCenter()) { - alignmentLeftOffsetForCaption = captionSpace / 2; - alignmentLeftOffsetForWidget = widgetSpace / 2; - } else if (alignment.isRight()) { - alignmentLeftOffsetForCaption = captionSpace; - alignmentLeftOffsetForWidget = widgetSpace; - } - - if (alignmentLeftOffsetForCaption < 0) { - alignmentLeftOffsetForCaption = 0; - } - if (alignmentLeftOffsetForWidget < 0) { - alignmentLeftOffsetForWidget = 0; - } - - } - - public void setAlignment(AlignmentInfo alignmentInfo) { - alignment = alignmentInfo; - } - - public Size getWidgetSize() { - return widgetSize; - } - - public void updateCaption(UIDL uidl, ApplicationConnection client) { - if (VCaption.isNeeded(uidl)) { - // We need a caption - - VCaption newCaption = caption; - - if (newCaption == null) { - newCaption = new VCaption((Paintable) widget, client); - // Set initial height to avoid Safari flicker - newCaption.setHeight("18px"); - // newCaption.setHeight(newCaption.getHeight()); // This might - // be better... ?? - if (BrowserInfo.get().isIE()) { - /* - * Must attach caption here so IE sends an immediate onload - * event for images coming from the cache - */ - setCaption(newCaption); - } - } - - boolean positionChanged = newCaption.updateCaption(uidl); - - if (newCaption != caption || positionChanged) { - setCaption(newCaption); - } - - } else { - // Caption is not needed - if (caption != null) { - remove(caption); - } - - } - - updateCaptionSize(); - - if (relativeSize == null) { - /* - * relativeSize may be null if component is updated via independent - * update, after it has initially been hidden. See #4608 - * - * It might also change in which case there would be similar issues. - * - * Yes, it is an ugly hack. Don't come telling me about it. - */ - setRelativeSize(Util.parseRelativeSize(uidl)); - } - } - - public void updateCaptionSize() { - captionWidth = 0; - captionHeight = 0; - - if (caption != null) { - captionWidth = caption.getRenderedWidth(); - captionHeight = caption.getHeight(); - captionRequiredWidth = caption.getRequiredWidth(); - - /* - * ApplicationConnection.getConsole().log( - * "Caption rendered width: " + captionWidth + - * ", caption required width: " + captionRequiredWidth + - * ", caption height: " + captionHeight); - */ - } - - } - - private void setCaption(VCaption newCaption) { - // Validate - // if (newCaption == caption) { - // return; - // } - - // Detach new child. - if (newCaption != null) { - newCaption.removeFromParent(); - } - - // Remove old child. - if (caption != null && newCaption != caption) { - remove(caption); - } - - // Logical attach. - caption = newCaption; - - if (caption != null) { - // Physical attach. - if (caption.shouldBePlacedAfterComponent()) { - Util.setFloat(caption.getElement(), "left"); - containerDIV.appendChild(caption.getElement()); - } else { - Util.setFloat(caption.getElement(), ""); - containerDIV.insertBefore(caption.getElement(), widgetDIV); - } - - adopt(caption); - } - - } - - @Override - public boolean remove(Widget child) { - // Validate - if (child != caption && child != widget) { - return false; - } - - // Orphan - orphan(child); - - // Physical && Logical Detach - if (child == caption) { - containerDIV.removeChild(child.getElement()); - caption = null; - } else { - widgetDIV.removeChild(child.getElement()); - widget = null; - } - - return true; - } - - public Iterator<Widget> iterator() { - return new ChildComponentContainerIterator<Widget>(); - } - - public class ChildComponentContainerIterator<T> implements Iterator<Widget> { - private int id = 0; - - public boolean hasNext() { - return (id < size()); - } - - public Widget next() { - Widget w = get(id); - id++; - return w; - } - - private Widget get(int i) { - if (i == 0) { - if (widget != null) { - return widget; - } else if (caption != null) { - return caption; - } else { - throw new NoSuchElementException(); - } - } else if (i == 1) { - if (widget != null && caption != null) { - return caption; - } else { - throw new NoSuchElementException(); - } - } else { - throw new NoSuchElementException(); - } - } - - public void remove() { - int toRemove = id - 1; - if (toRemove == 0) { - if (widget != null) { - ChildComponentContainer.this.remove(widget); - } else if (caption != null) { - ChildComponentContainer.this.remove(caption); - } else { - throw new IllegalStateException(); - } - - } else if (toRemove == 1) { - if (widget != null && caption != null) { - ChildComponentContainer.this.remove(caption); - } else { - throw new IllegalStateException(); - } - } else { - throw new IllegalStateException(); - } - - id--; - } - } - - public int size() { - if (widget != null) { - if (caption != null) { - return 2; - } else { - return 1; - } - } else { - if (caption != null) { - return 1; - } else { - return 0; - } - } - } - - public Widget getWidget() { - return widget; - } - - /** - * Return true if the size of the widget has been specified in the selected - * orientation. - * - * @return - */ - public boolean widgetHasSizeSpecified(int orientation) { - String size; - if (orientation == CellBasedLayout.ORIENTATION_HORIZONTAL) { - size = widget.getElement().getStyle().getProperty("width"); - } else { - size = widget.getElement().getStyle().getProperty("height"); - } - return (size != null && !size.equals("")); - } - - public boolean isComponentRelativeSized(int orientation) { - if (relativeSize == null) { - return false; - } - if (orientation == CellBasedLayout.ORIENTATION_HORIZONTAL) { - return relativeSize.getWidth() >= 0; - } else { - return relativeSize.getHeight() >= 0; - } - } - - public void setRelativeSize(FloatSize relativeSize) { - this.relativeSize = relativeSize; - } - - public Size getContSize() { - return contSize; - } - - public void clearAlignments() { - alignmentLeftOffsetForCaption = 0; - alignmentLeftOffsetForWidget = 0; - alignmentTopOffset = 0; - applyAlignments(); - - } - - /** - * Sets the normalized expand ratio of this slot. The fraction that this - * slot will use of "excess space". - * - * @param expandRatio - */ - public void setNormalizedExpandRatio(double expandRatio) { - this.expandRatio = expandRatio; - } - - public int expand(int orientation, int spaceForExpansion) { - int expansionAmount = (int) (spaceForExpansion * expandRatio); - - if (orientation == CellBasedLayout.ORIENTATION_HORIZONTAL) { - // HORIZONTAL - containerExpansion.setWidth(expansionAmount); - } else { - // VERTICAL - containerExpansion.setHeight(expansionAmount); - } - - return expansionAmount; - } - - public void expandExtra(int orientation, int extra) { - if (orientation == CellBasedLayout.ORIENTATION_HORIZONTAL) { - // HORIZONTAL - containerExpansion.setWidth(containerExpansion.getWidth() + extra); - } else { - // VERTICAL - containerExpansion - .setHeight(containerExpansion.getHeight() + extra); - } - - } - - public void setContainerSize(int widgetAndCaptionWidth, - int widgetAndCaptionHeight) { - - int containerWidth = widgetAndCaptionWidth; - containerWidth += containerExpansion.getWidth(); - - int containerHeight = widgetAndCaptionHeight; - containerHeight += containerExpansion.getHeight(); - - // ApplicationConnection.getConsole().log( - // "Setting container size for " + Util.getSimpleName(widget) - // + " to " + containerWidth + "," + containerHeight); - - if (containerWidth < 0) { - VConsole.log("containerWidth should never be negative: " - + containerWidth); - containerWidth = 0; - } - if (containerHeight < 0) { - VConsole.log("containerHeight should never be negative: " - + containerHeight); - containerHeight = 0; - } - - contSize.setWidth(containerWidth); - contSize.setHeight(containerHeight); - - updateContainerDOMSize(); - } - - public void updateContainerDOMSize() { - int width = contSize.getWidth(); - int height = contSize.getHeight() - alignmentTopOffset; - if (width < 0) { - width = 0; - } - if (height < 0) { - height = 0; - } - - setWidth(width + "px"); - setHeight(height + "px"); - - // Also update caption max width - if (caption != null) { - if (caption.shouldBePlacedAfterComponent()) { - caption.setMaxWidth(captionWidth); - } else { - caption.setMaxWidth(width); - } - captionWidth = caption.getRenderedWidth(); - - // Remove initial height - caption.setHeight(""); - } - - } - -} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ComponentConnectorLayoutSlot.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ComponentConnectorLayoutSlot.java new file mode 100644 index 0000000000..d479e8da9d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/ComponentConnectorLayoutSlot.java @@ -0,0 +1,99 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.layout; + +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ui.ManagedLayout; + +public class ComponentConnectorLayoutSlot extends VLayoutSlot { + + final ComponentConnector child; + final ManagedLayout layout; + + public ComponentConnectorLayoutSlot(String baseClassName, + ComponentConnector child, ManagedLayout layout) { + super(baseClassName, child.getWidget()); + this.child = child; + this.layout = layout; + } + + public ComponentConnector getChild() { + return child; + } + + @Override + protected int getCaptionHeight() { + VCaption caption = getCaption(); + return caption != null ? getLayoutManager().getOuterHeight( + caption.getElement()) : 0; + } + + @Override + protected int getCaptionWidth() { + VCaption caption = getCaption(); + return caption != null ? getLayoutManager().getOuterWidth( + caption.getElement()) : 0; + } + + public LayoutManager getLayoutManager() { + return layout.getLayoutManager(); + } + + @Override + public void setCaption(VCaption caption) { + VCaption oldCaption = getCaption(); + if (oldCaption != null) { + getLayoutManager().unregisterDependency(layout, + oldCaption.getElement()); + } + super.setCaption(caption); + if (caption != null) { + getLayoutManager().registerDependency( + (ManagedLayout) child.getParent(), caption.getElement()); + } + } + + @Override + protected void reportActualRelativeHeight(int allocatedHeight) { + getLayoutManager().reportOuterHeight(child, allocatedHeight); + } + + @Override + protected void reportActualRelativeWidth(int allocatedWidth) { + getLayoutManager().reportOuterWidth(child, allocatedWidth); + } + + @Override + public int getWidgetHeight() { + return getLayoutManager() + .getOuterHeight(child.getWidget().getElement()); + } + + @Override + public int getWidgetWidth() { + return getLayoutManager().getOuterWidth(child.getWidget().getElement()); + } + + @Override + public boolean isUndefinedHeight() { + return child.isUndefinedHeight(); + } + + @Override + public boolean isUndefinedWidth() { + return child.isUndefinedWidth(); + } + + @Override + public boolean isRelativeHeight() { + return child.isRelativeHeight(); + } + + @Override + public boolean isRelativeWidth() { + return child.isRelativeWidth(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java new file mode 100644 index 0000000000..a519f5db87 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeEvent.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.layout; + +import com.google.gwt.dom.client.Element; +import com.vaadin.terminal.gwt.client.LayoutManager; + +public class ElementResizeEvent { + private final Element element; + private final LayoutManager layoutManager; + + public ElementResizeEvent(LayoutManager layoutManager, Element element) { + this.layoutManager = layoutManager; + this.element = element; + } + + public Element getElement() { + return element; + } + + public LayoutManager getLayoutManager() { + return layoutManager; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java new file mode 100644 index 0000000000..d6d3de48b8 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/ElementResizeListener.java @@ -0,0 +1,9 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.layout; + +public interface ElementResizeListener { + public void onElementResize(ElementResizeEvent e); +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java b/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java new file mode 100644 index 0000000000..1ca8933ff2 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/LayoutDependencyTree.java @@ -0,0 +1,521 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.layout; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.ManagedLayout; + +public class LayoutDependencyTree { + private class LayoutDependency { + private final ComponentConnector connector; + private final int direction; + + private boolean needsLayout = false; + private boolean needsMeasure = false; + + private boolean scrollingParentCached = false; + private ComponentConnector scrollingBoundary = null; + + private Set<ComponentConnector> measureBlockers = new HashSet<ComponentConnector>(); + private Set<ComponentConnector> layoutBlockers = new HashSet<ComponentConnector>(); + + public LayoutDependency(ComponentConnector connector, int direction) { + this.connector = connector; + this.direction = direction; + } + + private void addLayoutBlocker(ComponentConnector blocker) { + boolean blockerAdded = layoutBlockers.add(blocker); + if (blockerAdded && layoutBlockers.size() == 1) { + if (needsLayout) { + getLayoutQueue(direction).remove(connector); + } else { + // Propagation already done if needsLayout is set + propagatePotentialLayout(); + } + } + } + + private void removeLayoutBlocker(ComponentConnector blocker) { + boolean removed = layoutBlockers.remove(blocker); + if (removed && layoutBlockers.isEmpty()) { + if (needsLayout) { + getLayoutQueue(direction).add((ManagedLayout) connector); + } else { + propagateNoUpcomingLayout(); + } + } + } + + private void addMeasureBlocker(ComponentConnector blocker) { + boolean blockerAdded = measureBlockers.add(blocker); + if (blockerAdded && measureBlockers.size() == 1) { + if (needsMeasure) { + getMeasureQueue(direction).remove(connector); + } else { + propagatePotentialResize(); + } + } + } + + private void removeMeasureBlocker(ComponentConnector blocker) { + boolean removed = measureBlockers.remove(blocker); + if (removed && measureBlockers.isEmpty()) { + if (needsMeasure) { + getMeasureQueue(direction).add(connector); + } else { + propagateNoUpcomingResize(); + } + } + } + + public void setNeedsMeasure(boolean needsMeasure) { + if (needsMeasure && !this.needsMeasure) { + // If enabling needsMeasure + this.needsMeasure = needsMeasure; + + if (measureBlockers.isEmpty()) { + // Add to queue if there are no blockers + getMeasureQueue(direction).add(connector); + // Only need to propagate if not already propagated when + // setting blockers + propagatePotentialResize(); + } + } else if (!needsMeasure && this.needsMeasure + && measureBlockers.isEmpty()) { + // Only disable if there are no blockers (elements gets measured + // in both directions even if there is a blocker in one + // direction) + this.needsMeasure = needsMeasure; + getMeasureQueue(direction).remove(connector); + propagateNoUpcomingResize(); + } + } + + public void setNeedsLayout(boolean needsLayout) { + if (!(connector instanceof ManagedLayout)) { + throw new IllegalStateException( + "Only managed layouts can need layout, layout attempted for " + + Util.getConnectorString(connector)); + } + if (needsLayout && !this.needsLayout) { + // If enabling needsLayout + this.needsLayout = needsLayout; + + if (layoutBlockers.isEmpty()) { + // Add to queue if there are no blockers + getLayoutQueue(direction).add((ManagedLayout) connector); + // Only need to propagate if not already propagated when + // setting blockers + propagatePotentialLayout(); + } + } else if (!needsLayout && this.needsLayout + && layoutBlockers.isEmpty()) { + // Only disable if there are no layout blockers + // (SimpleManagedLayout gets layouted in both directions + // even if there is a blocker in one direction) + this.needsLayout = needsLayout; + getLayoutQueue(direction).remove(connector); + propagateNoUpcomingLayout(); + } + } + + private void propagatePotentialResize() { + for (ComponentConnector needsSize : getNeedsSizeForLayout()) { + LayoutDependency layoutDependency = getDependency(needsSize, + direction); + layoutDependency.addLayoutBlocker(connector); + } + } + + private Collection<ComponentConnector> getNeedsSizeForLayout() { + // Find all connectors that need the size of this connector for + // layouting + + // Parent needs size if it isn't relative? + // Connector itself needs size if it isn't undefined? + // Children doesn't care? + + ArrayList<ComponentConnector> needsSize = new ArrayList<ComponentConnector>(); + + if (!isUndefinedInDirection(connector, direction)) { + needsSize.add(connector); + } + if (!isRelativeInDirection(connector, direction)) { + ComponentConnector parent = connector.getParent(); + if (parent != null) { + needsSize.add(parent); + } + } + + return needsSize; + } + + private void propagateNoUpcomingResize() { + for (ComponentConnector mightNeedLayout : getNeedsSizeForLayout()) { + LayoutDependency layoutDependency = getDependency( + mightNeedLayout, direction); + layoutDependency.removeLayoutBlocker(connector); + } + } + + private void propagatePotentialLayout() { + for (ComponentConnector sizeMightChange : getResizedByLayout()) { + LayoutDependency layoutDependency = getDependency( + sizeMightChange, direction); + layoutDependency.addMeasureBlocker(connector); + } + } + + private Collection<ComponentConnector> getResizedByLayout() { + // Components that might get resized by a layout of this component + + // Parent never resized + // Connector itself resized if undefined + // Children resized if relative + + ArrayList<ComponentConnector> resized = new ArrayList<ComponentConnector>(); + if (isUndefinedInDirection(connector, direction)) { + resized.add(connector); + } + + if (connector instanceof ComponentContainerConnector) { + ComponentContainerConnector container = (ComponentContainerConnector) connector; + for (ComponentConnector child : container.getChildren()) { + if (isRelativeInDirection(child, direction)) { + resized.add(child); + } + } + } + + return resized; + } + + private void propagateNoUpcomingLayout() { + for (ComponentConnector sizeMightChange : getResizedByLayout()) { + LayoutDependency layoutDependency = getDependency( + sizeMightChange, direction); + layoutDependency.removeMeasureBlocker(connector); + } + } + + public void markSizeAsChanged() { + // When the size has changed, all that use that size should be + // layouted + for (ComponentConnector connector : getNeedsSizeForLayout()) { + LayoutDependency layoutDependency = getDependency(connector, + direction); + if (connector instanceof ManagedLayout) { + layoutDependency.setNeedsLayout(true); + } else { + // Should simulate setNeedsLayout(true) + markAsLayouted -> + // propagate needs measure + layoutDependency.propagatePostLayoutMeasure(); + } + } + + // Should also go through the hierarchy to discover appeared or + // disappeared scrollbars + ComponentConnector scrollingBoundary = getScrollingBoundary(connector); + if (scrollingBoundary != null) { + getDependency(scrollingBoundary, getOppositeDirection()) + .setNeedsMeasure(true); + } + + } + + /** + * Go up the hierarchy to find a component whose size might have changed + * in the other direction because changes to this component causes + * scrollbars to appear or disappear. + * + * @return + */ + private LayoutDependency findPotentiallyChangedScrollbar() { + ComponentConnector currentConnector = connector; + while (true) { + ComponentContainerConnector parent = currentConnector + .getParent(); + if (parent == null) { + return null; + } + if (parent instanceof MayScrollChildren) { + return getDependency(currentConnector, + getOppositeDirection()); + } + currentConnector = parent; + } + } + + private int getOppositeDirection() { + return direction == HORIZONTAL ? VERTICAL : HORIZONTAL; + } + + public void markAsLayouted() { + if (!layoutBlockers.isEmpty()) { + // Don't do anything if there are layout blockers (SimpleLayout + // gets layouted in both directions even if one direction is + // blocked) + return; + } + setNeedsLayout(false); + propagatePostLayoutMeasure(); + } + + private void propagatePostLayoutMeasure() { + for (ComponentConnector resized : getResizedByLayout()) { + LayoutDependency layoutDependency = getDependency(resized, + direction); + layoutDependency.setNeedsMeasure(true); + } + + // Special case for e.g. wrapping texts + if (direction == HORIZONTAL && !connector.isUndefinedWidth() + && connector.isUndefinedHeight()) { + LayoutDependency dependency = getDependency(connector, VERTICAL); + dependency.setNeedsMeasure(true); + } + } + + @Override + public String toString() { + String s = getCompactConnectorString(connector) + "\n"; + if (direction == VERTICAL) { + s += "Vertical"; + } else { + s += "Horizontal"; + } + ComponentState state = connector.getState(); + s += " sizing: " + + getSizeDefinition(direction == VERTICAL ? state + .getHeight() : state.getWidth()) + "\n"; + + if (needsLayout) { + s += "Needs layout\n"; + } + if (getLayoutQueue(direction).contains(connector)) { + s += "In layout queue\n"; + } + s += "Layout blockers: " + blockersToString(layoutBlockers) + "\n"; + + if (needsMeasure) { + s += "Needs measure\n"; + } + if (getMeasureQueue(direction).contains(connector)) { + s += "In measure queue\n"; + } + s += "Measure blockers: " + blockersToString(measureBlockers); + + return s; + } + + public boolean noMoreChangesExpected() { + return !needsLayout && !needsMeasure && layoutBlockers.isEmpty() + && measureBlockers.isEmpty(); + } + + } + + private static final int HORIZONTAL = 0; + private static final int VERTICAL = 1; + + private final Map<?, ?>[] dependenciesInDirection = new Map<?, ?>[] { + new HashMap<ComponentConnector, LayoutDependency>(), + new HashMap<ComponentConnector, LayoutDependency>() }; + + private final Collection<?>[] measureQueueInDirection = new HashSet<?>[] { + new HashSet<ComponentConnector>(), + new HashSet<ComponentConnector>() }; + + private final Collection<?>[] layoutQueueInDirection = new HashSet<?>[] { + new HashSet<ComponentConnector>(), + new HashSet<ComponentConnector>() }; + + public void setNeedsMeasure(ComponentConnector connector, + boolean needsMeasure) { + setNeedsHorizontalMeasure(connector, needsMeasure); + setNeedsVerticalMeasure(connector, needsMeasure); + } + + public void setNeedsHorizontalMeasure(ComponentConnector connector, + boolean needsMeasure) { + LayoutDependency dependency = getDependency(connector, HORIZONTAL); + dependency.setNeedsMeasure(needsMeasure); + } + + public void setNeedsVerticalMeasure(ComponentConnector connector, + boolean needsMeasure) { + LayoutDependency dependency = getDependency(connector, VERTICAL); + dependency.setNeedsMeasure(needsMeasure); + } + + private LayoutDependency getDependency(ComponentConnector connector, + int direction) { + @SuppressWarnings("unchecked") + Map<ComponentConnector, LayoutDependency> dependencies = (Map<ComponentConnector, LayoutDependency>) dependenciesInDirection[direction]; + LayoutDependency dependency = dependencies.get(connector); + if (dependency == null) { + dependency = new LayoutDependency(connector, direction); + dependencies.put(connector, dependency); + } + return dependency; + } + + @SuppressWarnings("unchecked") + private Collection<ManagedLayout> getLayoutQueue(int direction) { + return (Collection<ManagedLayout>) layoutQueueInDirection[direction]; + } + + @SuppressWarnings("unchecked") + private Collection<ComponentConnector> getMeasureQueue(int direction) { + return (Collection<ComponentConnector>) measureQueueInDirection[direction]; + } + + public void setNeedsHorizontalLayout(ManagedLayout layout, + boolean needsLayout) { + LayoutDependency dependency = getDependency(layout, HORIZONTAL); + dependency.setNeedsLayout(needsLayout); + } + + public void setNeedsVerticalLayout(ManagedLayout layout, boolean needsLayout) { + LayoutDependency dependency = getDependency(layout, VERTICAL); + dependency.setNeedsLayout(needsLayout); + } + + public void markAsHorizontallyLayouted(ManagedLayout layout) { + LayoutDependency dependency = getDependency(layout, HORIZONTAL); + dependency.markAsLayouted(); + } + + public void markAsVerticallyLayouted(ManagedLayout layout) { + LayoutDependency dependency = getDependency(layout, VERTICAL); + dependency.markAsLayouted(); + } + + public void markHeightAsChanged(ComponentConnector connector) { + LayoutDependency dependency = getDependency(connector, VERTICAL); + dependency.markSizeAsChanged(); + } + + public void markWidthAsChanged(ComponentConnector connector) { + LayoutDependency dependency = getDependency(connector, HORIZONTAL); + dependency.markSizeAsChanged(); + } + + private static boolean isRelativeInDirection(ComponentConnector connector, + int direction) { + if (direction == HORIZONTAL) { + return connector.isRelativeWidth(); + } else { + return connector.isRelativeHeight(); + } + } + + private static boolean isUndefinedInDirection(ComponentConnector connector, + int direction) { + if (direction == VERTICAL) { + return connector.isUndefinedHeight(); + } else { + return connector.isUndefinedWidth(); + } + } + + private static String getCompactConnectorString(ComponentConnector connector) { + return Util.getSimpleName(connector) + " (" + + connector.getConnectorId() + ")"; + } + + private static String getSizeDefinition(String size) { + if (size == null || size.length() == 0) { + return "undefined"; + } else if (size.endsWith("%")) { + return "relative"; + } else { + return "fixed"; + } + } + + private static String blockersToString( + Collection<ComponentConnector> blockers) { + StringBuilder b = new StringBuilder("["); + for (ComponentConnector blocker : blockers) { + if (b.length() != 1) { + b.append(", "); + } + b.append(getCompactConnectorString(blocker)); + } + b.append(']'); + return b.toString(); + } + + public boolean hasConnectorsToMeasure() { + return !measureQueueInDirection[HORIZONTAL].isEmpty() + || !measureQueueInDirection[VERTICAL].isEmpty(); + } + + public boolean hasHorizontalConnectorToLayout() { + return !getLayoutQueue(HORIZONTAL).isEmpty(); + } + + public boolean hasVerticaConnectorToLayout() { + return !getLayoutQueue(VERTICAL).isEmpty(); + } + + public ManagedLayout[] getHorizontalLayoutTargets() { + Collection<ManagedLayout> queue = getLayoutQueue(HORIZONTAL); + return queue.toArray(new ManagedLayout[queue.size()]); + } + + public ManagedLayout[] getVerticalLayoutTargets() { + Collection<ManagedLayout> queue = getLayoutQueue(VERTICAL); + return queue.toArray(new ManagedLayout[queue.size()]); + } + + public Collection<ComponentConnector> getMeasureTargets() { + Collection<ComponentConnector> measureTargets = new HashSet<ComponentConnector>( + getMeasureQueue(HORIZONTAL)); + measureTargets.addAll(getMeasureQueue(VERTICAL)); + return measureTargets; + } + + public void logDependencyStatus(ComponentConnector connector) { + VConsole.log("===="); + VConsole.log(getDependency(connector, HORIZONTAL).toString()); + VConsole.log(getDependency(connector, VERTICAL).toString()); + } + + public boolean noMoreChangesExpected(ComponentConnector connector) { + return getDependency(connector, HORIZONTAL).noMoreChangesExpected() + && getDependency(connector, VERTICAL).noMoreChangesExpected(); + } + + public ComponentConnector getScrollingBoundary(ComponentConnector connector) { + LayoutDependency dependency = getDependency(connector, HORIZONTAL); + if (!dependency.scrollingParentCached) { + ComponentContainerConnector parent = dependency.connector + .getParent(); + if (parent instanceof MayScrollChildren) { + dependency.scrollingBoundary = connector; + } else if (parent != null) { + dependency.scrollingBoundary = getScrollingBoundary(parent); + } else { + // No scrolling parent + } + + dependency.scrollingParentCached = true; + } + return dependency.scrollingBoundary; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/MayScrollChildren.java b/src/com/vaadin/terminal/gwt/client/ui/layout/MayScrollChildren.java new file mode 100644 index 0000000000..62c9937c4c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/MayScrollChildren.java @@ -0,0 +1,10 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.layout; + +import com.vaadin.terminal.gwt.client.ComponentContainerConnector; + +public interface MayScrollChildren extends ComponentContainerConnector { + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/layout/VLayoutSlot.java b/src/com/vaadin/terminal/gwt/client/ui/layout/VLayoutSlot.java new file mode 100644 index 0000000000..034fe35649 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/layout/VLayoutSlot.java @@ -0,0 +1,287 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.layout; + +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ui.AlignmentInfo; + +public abstract class VLayoutSlot { + + private final Element wrapper = Document.get().createDivElement().cast(); + + private AlignmentInfo alignment; + private VCaption caption; + private final Widget widget; + + private double expandRatio; + + public VLayoutSlot(String baseClassName, Widget widget) { + this.widget = widget; + + wrapper.setClassName(baseClassName + "-slot"); + } + + public VCaption getCaption() { + return caption; + } + + public void setCaption(VCaption caption) { + if (this.caption != null) { + this.caption.removeFromParent(); + } + this.caption = caption; + if (caption != null) { + // Physical attach. + DOM.insertBefore(wrapper, caption.getElement(), widget.getElement()); + Style style = caption.getElement().getStyle(); + style.setPosition(Position.ABSOLUTE); + style.setTop(0, Unit.PX); + } + } + + public AlignmentInfo getAlignment() { + return alignment; + } + + public Widget getWidget() { + return widget; + } + + public void setAlignment(AlignmentInfo alignment) { + this.alignment = alignment; + } + + public void positionHorizontally(double currentLocation, + double allocatedSpace, double marginRight) { + Style style = wrapper.getStyle(); + + double availableWidth = allocatedSpace; + + VCaption caption = getCaption(); + Style captionStyle = caption != null ? caption.getElement().getStyle() + : null; + int captionWidth = getCaptionWidth(); + + boolean captionAboveCompnent; + if (caption == null) { + captionAboveCompnent = false; + style.clearPaddingRight(); + } else { + captionAboveCompnent = !caption.shouldBePlacedAfterComponent(); + if (!captionAboveCompnent) { + availableWidth -= captionWidth; + captionStyle.clearLeft(); + captionStyle.setRight(0, Unit.PX); + style.setPaddingRight(captionWidth, Unit.PX); + } else { + captionStyle.setLeft(0, Unit.PX); + captionStyle.clearRight(); + style.clearPaddingRight(); + } + } + + if (marginRight > 0) { + style.setMarginRight(marginRight, Unit.PX); + } else { + style.clearMarginRight(); + } + + if (isRelativeWidth()) { + style.setPropertyPx("width", (int) availableWidth); + } else { + style.clearProperty("width"); + } + + double allocatedContentWidth = 0; + if (isRelativeWidth()) { + String percentWidth = getWidget().getElement().getStyle() + .getWidth(); + double percentage = parsePercent(percentWidth); + allocatedContentWidth = availableWidth * (percentage / 100); + reportActualRelativeWidth(Math.round((float) allocatedContentWidth)); + } + + AlignmentInfo alignment = getAlignment(); + if (!alignment.isLeft()) { + double usedWidth; + if (isRelativeWidth()) { + usedWidth = allocatedContentWidth; + } else { + usedWidth = getWidgetWidth(); + } + if (alignment.isHorizontalCenter()) { + currentLocation += (allocatedSpace - usedWidth) / 2d; + if (captionAboveCompnent) { + captionStyle.setLeft( + Math.round(usedWidth - captionWidth) / 2, Unit.PX); + } + } else { + currentLocation += (allocatedSpace - usedWidth); + if (captionAboveCompnent) { + captionStyle.setLeft(Math.round(usedWidth - captionWidth), + Unit.PX); + } + } + } else { + if (captionAboveCompnent) { + captionStyle.setLeft(0, Unit.PX); + } + } + + style.setLeft(Math.round(currentLocation), Unit.PX); + } + + private double parsePercent(String size) { + return Double.parseDouble(size.replaceAll("%", "")); + } + + public void positionVertically(double currentLocation, + double allocatedSpace, double marginBottom) { + Style style = wrapper.getStyle(); + + double contentHeight = allocatedSpace; + + int captionHeight; + VCaption caption = getCaption(); + if (caption == null || caption.shouldBePlacedAfterComponent()) { + style.clearPaddingTop(); + captionHeight = 0; + } else { + captionHeight = getCaptionHeight(); + contentHeight -= captionHeight; + if (contentHeight < 0) { + contentHeight = 0; + } + style.setPaddingTop(captionHeight, Unit.PX); + } + + if (marginBottom > 0) { + style.setMarginBottom(marginBottom, Unit.PX); + } else { + style.clearMarginBottom(); + } + + if (isRelativeHeight()) { + style.setHeight(contentHeight, Unit.PX); + } else { + style.clearHeight(); + } + + double allocatedContentHeight = 0; + if (isRelativeHeight()) { + String height = getWidget().getElement().getStyle().getHeight(); + double percentage = parsePercent(height); + allocatedContentHeight = contentHeight * (percentage / 100); + reportActualRelativeHeight(Math + .round((float) allocatedContentHeight)); + } + + AlignmentInfo alignment = getAlignment(); + if (!alignment.isTop()) { + double usedHeight; + if (isRelativeHeight()) { + usedHeight = captionHeight + allocatedContentHeight; + } else { + usedHeight = getUsedHeight(); + } + if (alignment.isVerticalCenter()) { + currentLocation += (allocatedSpace - usedHeight) / 2d; + } else { + currentLocation += (allocatedSpace - usedHeight); + } + } + + style.setTop(currentLocation, Unit.PX); + } + + protected void reportActualRelativeHeight(int allocatedHeight) { + // Default implementation does nothing + } + + protected void reportActualRelativeWidth(int allocatedWidth) { + // Default implementation does nothing + } + + public void positionInDirection(double currentLocation, + double allocatedSpace, double endingMargin, boolean isVertical) { + if (isVertical) { + positionVertically(currentLocation, allocatedSpace, endingMargin); + } else { + positionHorizontally(currentLocation, allocatedSpace, endingMargin); + } + } + + public int getWidgetSizeInDirection(boolean isVertical) { + return isVertical ? getWidgetHeight() : getWidgetWidth(); + } + + public int getUsedWidth() { + int widgetWidth = getWidgetWidth(); + if (caption == null) { + return widgetWidth; + } else if (caption.shouldBePlacedAfterComponent()) { + return widgetWidth + getCaptionWidth(); + } else { + return Math.max(widgetWidth, getCaptionWidth()); + } + } + + public int getUsedHeight() { + int widgetHeight = getWidgetHeight(); + if (caption == null) { + return widgetHeight; + } else if (caption.shouldBePlacedAfterComponent()) { + return Math.max(widgetHeight, getCaptionHeight()); + } else { + return widgetHeight + getCaptionHeight(); + } + } + + public int getUsedSizeInDirection(boolean isVertical) { + return isVertical ? getUsedHeight() : getUsedWidth(); + } + + protected abstract int getCaptionHeight(); + + protected abstract int getCaptionWidth(); + + public abstract int getWidgetHeight(); + + public abstract int getWidgetWidth(); + + public abstract boolean isUndefinedHeight(); + + public abstract boolean isUndefinedWidth(); + + public boolean isUndefinedInDirection(boolean isVertical) { + return isVertical ? isUndefinedHeight() : isUndefinedWidth(); + } + + public abstract boolean isRelativeHeight(); + + public abstract boolean isRelativeWidth(); + + public boolean isRelativeInDirection(boolean isVertical) { + return isVertical ? isRelativeHeight() : isRelativeWidth(); + } + + public Element getWrapperElement() { + return wrapper; + } + + public void setExpandRatio(double expandRatio) { + this.expandRatio = expandRatio; + } + + public double getExpandRatio() { + return expandRatio; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/link/LinkConnector.java b/src/com/vaadin/terminal/gwt/client/ui/link/LinkConnector.java new file mode 100644 index 0000000000..f74a851d03 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/link/LinkConnector.java @@ -0,0 +1,99 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.link; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.ui.Link; + +@Connect(Link.class) +public class LinkConnector extends AbstractComponentConnector implements + Paintable { + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().client = client; + + getWidget().enabled = isEnabled(); + + if (uidl.hasAttribute("name")) { + getWidget().target = uidl.getStringAttribute("name"); + getWidget().anchor.setAttribute("target", getWidget().target); + } + if (uidl.hasAttribute("src")) { + getWidget().src = client.translateVaadinUri(uidl + .getStringAttribute("src")); + getWidget().anchor.setAttribute("href", getWidget().src); + } + + if (uidl.hasAttribute("border")) { + if ("none".equals(uidl.getStringAttribute("border"))) { + getWidget().borderStyle = VLink.BORDER_STYLE_NONE; + } else { + getWidget().borderStyle = VLink.BORDER_STYLE_MINIMAL; + } + } else { + getWidget().borderStyle = VLink.BORDER_STYLE_DEFAULT; + } + + getWidget().targetHeight = uidl.hasAttribute("targetHeight") ? uidl + .getIntAttribute("targetHeight") : -1; + getWidget().targetWidth = uidl.hasAttribute("targetWidth") ? uidl + .getIntAttribute("targetWidth") : -1; + + // Set link caption + getWidget().captionElement.setInnerText(getState().getCaption()); + + // handle error + if (null != getState().getErrorMessage()) { + if (getWidget().errorIndicatorElement == null) { + getWidget().errorIndicatorElement = DOM.createDiv(); + DOM.setElementProperty(getWidget().errorIndicatorElement, + "className", "v-errorindicator"); + } + DOM.insertChild(getWidget().getElement(), + getWidget().errorIndicatorElement, 0); + } else if (getWidget().errorIndicatorElement != null) { + DOM.setStyleAttribute(getWidget().errorIndicatorElement, "display", + "none"); + } + + if (getState().getIcon() != null) { + if (getWidget().icon == null) { + getWidget().icon = new Icon(client); + getWidget().anchor.insertBefore(getWidget().icon.getElement(), + getWidget().captionElement); + } + getWidget().icon.setUri(getState().getIcon().getURL()); + } + + } + + @Override + protected Widget createWidget() { + return GWT.create(VLink.class); + } + + @Override + public VLink getWidget() { + return (VLink) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java b/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java new file mode 100644 index 0000000000..68fe5d9292 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/link/VLink.java @@ -0,0 +1,117 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.link; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +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.Window; +import com.google.gwt.user.client.ui.HTML; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Icon; + +public class VLink extends HTML implements ClickHandler { + + public static final String CLASSNAME = "v-link"; + + protected static final int BORDER_STYLE_DEFAULT = 0; + protected static final int BORDER_STYLE_MINIMAL = 1; + protected static final int BORDER_STYLE_NONE = 2; + + protected String src; + + protected String target; + + protected int borderStyle = BORDER_STYLE_DEFAULT; + + protected boolean enabled; + + protected int targetWidth; + + protected int targetHeight; + + protected Element errorIndicatorElement; + + protected final Element anchor = DOM.createAnchor(); + + protected final Element captionElement = DOM.createSpan(); + + protected Icon icon; + + protected ApplicationConnection client; + + public VLink() { + super(); + getElement().appendChild(anchor); + anchor.appendChild(captionElement); + addClickHandler(this); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + setStyleName(CLASSNAME); + } + + public void onClick(ClickEvent event) { + if (enabled) { + if (target == null) { + target = "_self"; + } + String features; + switch (borderStyle) { + case BORDER_STYLE_NONE: + features = "menubar=no,location=no,status=no"; + break; + case BORDER_STYLE_MINIMAL: + features = "menubar=yes,location=no,status=no"; + break; + default: + features = ""; + break; + } + + if (targetWidth > 0) { + features += (features.length() > 0 ? "," : "") + "width=" + + targetWidth; + } + if (targetHeight > 0) { + features += (features.length() > 0 ? "," : "") + "height=" + + targetHeight; + } + + if (features.length() > 0) { + // if 'special features' are set, use window.open(), unless + // a modifier key is held (ctrl to open in new tab etc) + Event e = DOM.eventGetCurrentEvent(); + if (!e.getCtrlKey() && !e.getAltKey() && !e.getShiftKey() + && !e.getMetaKey()) { + Window.open(src, target, features); + e.preventDefault(); + } + } + } + } + + @Override + public void onBrowserEvent(Event event) { + final Element target = DOM.eventGetTarget(event); + if (event.getTypeInt() == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + } + if (client != null) { + client.handleTooltipEvent(event, this); + } + if (target == captionElement || target == anchor + || (icon != null && target == icon.getElement())) { + super.onBrowserEvent(event); + } + if (!enabled) { + event.preventDefault(); + } + + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/listselect/ListSelectConnector.java b/src/com/vaadin/terminal/gwt/client/ui/listselect/ListSelectConnector.java new file mode 100644 index 0000000000..ddaa959560 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/listselect/ListSelectConnector.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.listselect; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.optiongroup.OptionGroupBaseConnector; +import com.vaadin.ui.ListSelect; + +@Connect(ListSelect.class) +public class ListSelectConnector extends OptionGroupBaseConnector { + + @Override + protected Widget createWidget() { + return GWT.create(VListSelect.class); + } + + @Override + public VListSelect getWidget() { + return (VListSelect) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java b/src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java new file mode 100644 index 0000000000..abecd844da --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/listselect/TooltipListBox.java @@ -0,0 +1,41 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.listselect; + +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.VTooltip; + +/** + * Extended ListBox to listen tooltip events and forward them to generic + * handler. + */ +public class TooltipListBox extends ListBox { + private ApplicationConnection client; + private Widget widget; + + public TooltipListBox(boolean isMultiselect) { + super(isMultiselect); + sinkEvents(VTooltip.TOOLTIP_EVENTS); + } + + public void setClient(ApplicationConnection client) { + this.client = client; + } + + public void setSelect(Widget widget) { + this.widget = widget; + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (client != null) { + client.handleTooltipEvent(event, widget); + } + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java b/src/com/vaadin/terminal/gwt/client/ui/listselect/VListSelect.java index cebc4600a2..e338897841 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/listselect/VListSelect.java @@ -2,18 +2,14 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.listselect; import java.util.ArrayList; import java.util.Iterator; import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.ui.ListBox; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroupBase; public class VListSelect extends VOptionGroupBase { @@ -80,11 +76,11 @@ public class VListSelect extends VOptionGroupBase { } else { lastSelectedIndex = si; if (isMultiselect()) { - client.updateVariable(id, "selected", getSelectedItems(), - isImmediate()); + client.updateVariable(paintableId, "selected", + getSelectedItems(), isImmediate()); } else { - client.updateVariable(id, "selected", new String[] { "" - + getSelectedItem() }, isImmediate()); + client.updateVariable(paintableId, "selected", + new String[] { "" + getSelectedItem() }, isImmediate()); } } } @@ -109,35 +105,4 @@ public class VListSelect extends VOptionGroupBase { public void focus() { select.setFocus(true); } - -} - -/** - * Extended ListBox to listen tooltip events and forward them to generic - * handler. - */ -class TooltipListBox extends ListBox { - private ApplicationConnection client; - private Paintable pntbl; - - TooltipListBox(boolean isMultiselect) { - super(isMultiselect); - sinkEvents(VTooltip.TOOLTIP_EVENTS); - } - - public void setClient(ApplicationConnection client) { - this.client = client; - } - - public void setSelect(Paintable s) { - pntbl = s; - } - - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (client != null) { - client.handleTooltipEvent(event, pntbl); - } - } }
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/MenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuBar.java index f0857f48c1..7bee870387 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/MenuBar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuBar.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.menubar; /* * Copyright 2007 Google Inc. @@ -32,6 +32,7 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.PopupListener; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ui.VOverlay; /** * A standard menu bar widget. A menu bar can contain any number of menu items, @@ -294,7 +295,7 @@ public class MenuBar extends Widget implements PopupListener { * @return a list containing the <code>MenuItem</code> objects in the menu * bar */ - protected List<MenuItem> getItems() { + public List<MenuItem> getItems() { return items; } @@ -306,7 +307,7 @@ public class MenuBar extends Widget implements PopupListener { * @return the <code>MenuItem</code> that is currently selected, or * <code>null</code> if no items are currently selected */ - protected MenuItem getSelectedItem() { + public MenuItem getSelectedItem() { return selectedItem; } @@ -347,7 +348,7 @@ public class MenuBar extends Widget implements PopupListener { * <code>true</code> if the item's command should be fired, * <code>false</code> otherwise. */ - void doItemAction(final MenuItem item, boolean fireCommand) { + protected void doItemAction(final MenuItem item, boolean fireCommand) { // If the given item is already showing its menu, we're done. if ((shownChildMenu != null) && (item.getSubMenu() == shownChildMenu)) { return; @@ -451,7 +452,7 @@ public class MenuBar extends Widget implements PopupListener { } } - void selectItem(MenuItem item) { + public void selectItem(MenuItem item) { if (item == selectedItem) { return; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuBarConnector.java b/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuBarConnector.java new file mode 100644 index 0000000000..d063c89ca9 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuBarConnector.java @@ -0,0 +1,169 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.menubar; + +import java.util.Iterator; +import java.util.Stack; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.menubar.VMenuBar.CustomMenuItem; + +@Connect(value = com.vaadin.ui.MenuBar.class, loadStyle = LoadStyle.LAZY) +public class MenuBarConnector extends AbstractComponentConnector implements + Paintable, SimpleManagedLayout { + /** + * This method must be implemented to update the client-side component from + * UIDL data received from server. + * + * This method is called when the page is loaded for the first time, and + * every time UI changes in the component are received from the server. + */ + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().htmlContentAllowed = uidl + .hasAttribute(VMenuBar.HTML_CONTENT_ALLOWED); + + getWidget().openRootOnHover = uidl + .getBooleanAttribute(VMenuBar.OPEN_ROOT_MENU_ON_HOWER); + + getWidget().enabled = isEnabled(); + + // For future connections + getWidget().client = client; + getWidget().uidlId = uidl.getId(); + + // Empty the menu every time it receives new information + if (!getWidget().getItems().isEmpty()) { + getWidget().clearItems(); + } + + UIDL options = uidl.getChildUIDL(0); + + if (null != getState() && !getState().isUndefinedWidth()) { + UIDL moreItemUIDL = options.getChildUIDL(0); + StringBuffer itemHTML = new StringBuffer(); + + if (moreItemUIDL.hasAttribute("icon")) { + itemHTML.append("<img src=\"" + + Util.escapeAttribute(client + .translateVaadinUri(moreItemUIDL + .getStringAttribute("icon"))) + + "\" class=\"" + Icon.CLASSNAME + "\" alt=\"\" />"); + } + + String moreItemText = moreItemUIDL.getStringAttribute("text"); + if ("".equals(moreItemText)) { + moreItemText = "►"; + } + itemHTML.append(moreItemText); + + getWidget().moreItem = GWT.create(CustomMenuItem.class); + getWidget().moreItem.setHTML(itemHTML.toString()); + getWidget().moreItem.setCommand(VMenuBar.emptyCommand); + + getWidget().collapsedRootItems = new VMenuBar(true, getWidget()); + getWidget().moreItem.setSubMenu(getWidget().collapsedRootItems); + getWidget().moreItem.addStyleName(VMenuBar.CLASSNAME + + "-more-menuitem"); + } + + UIDL uidlItems = uidl.getChildUIDL(1); + Iterator<Object> itr = uidlItems.getChildIterator(); + Stack<Iterator<Object>> iteratorStack = new Stack<Iterator<Object>>(); + Stack<VMenuBar> menuStack = new Stack<VMenuBar>(); + VMenuBar currentMenu = getWidget(); + + while (itr.hasNext()) { + UIDL item = (UIDL) itr.next(); + CustomMenuItem currentItem = null; + + final int itemId = item.getIntAttribute("id"); + + boolean itemHasCommand = item.hasAttribute("command"); + boolean itemIsCheckable = item + .hasAttribute(VMenuBar.ATTRIBUTE_CHECKED); + + String itemHTML = getWidget().buildItemHTML(item); + + Command cmd = null; + if (!item.hasAttribute("separator")) { + if (itemHasCommand || itemIsCheckable) { + // Construct a command that fires onMenuClick(int) with the + // item's id-number + cmd = new Command() { + public void execute() { + getWidget().hostReference.onMenuClick(itemId); + } + }; + } + } + + currentItem = currentMenu.addItem(itemHTML.toString(), cmd); + currentItem.updateFromUIDL(item, client); + + if (item.getChildCount() > 0) { + menuStack.push(currentMenu); + iteratorStack.push(itr); + itr = item.getChildIterator(); + currentMenu = new VMenuBar(true, currentMenu); + // this is the top-level style that also propagates to items - + // any item specific styles are set above in + // currentItem.updateFromUIDL(item, client) + if (getState().hasStyles()) { + for (String style : getState().getStyles()) { + currentMenu.addStyleDependentName(style); + } + } + currentItem.setSubMenu(currentMenu); + } + + while (!itr.hasNext() && !iteratorStack.empty()) { + boolean hasCheckableItem = false; + for (CustomMenuItem menuItem : currentMenu.getItems()) { + hasCheckableItem = hasCheckableItem + || menuItem.isCheckable(); + } + if (hasCheckableItem) { + currentMenu.addStyleDependentName("check-column"); + } else { + currentMenu.removeStyleDependentName("check-column"); + } + + itr = iteratorStack.pop(); + currentMenu = menuStack.pop(); + } + }// while + + getLayoutManager().setNeedsHorizontalLayout(this); + + }// updateFromUIDL + + @Override + protected Widget createWidget() { + return GWT.create(VMenuBar.class); + } + + @Override + public VMenuBar getWidget() { + return (VMenuBar) super.getWidget(); + } + + public void layout() { + getWidget().iLayout(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/MenuItem.java b/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuItem.java index ec02db1c70..af79ba7c5e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/MenuItem.java +++ b/src/com/vaadin/terminal/gwt/client/ui/menubar/MenuItem.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.menubar; /* * Copyright 2007 Google Inc. diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java index 12678c9515..e48483cb02 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/menubar/VMenuBar.java @@ -1,17 +1,14 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.menubar; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import java.util.Stack; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; -import com.google.gwt.dom.client.NodeList; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Unit; @@ -35,16 +32,20 @@ import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.LayoutManager; import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.SimpleFocusablePanel; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; +import com.vaadin.terminal.gwt.client.ui.VOverlay; -public class VMenuBar extends SimpleFocusablePanel implements Paintable, - CloseHandler<PopupPanel>, ContainerResizedListener, KeyPressHandler, - KeyDownHandler, FocusHandler, SubPartAware { +public class VMenuBar extends SimpleFocusablePanel implements + CloseHandler<PopupPanel>, KeyPressHandler, KeyDownHandler, + FocusHandler, SubPartAware { // The hierarchy of VMenuBar is a bit weird as VMenuBar is the Paintable, // used for the root menu but also used for the sub menus. @@ -57,7 +58,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, protected ApplicationConnection client; protected final VMenuBar hostReference = this; - protected String submenuIcon = null; protected CustomMenuItem moreItem = null; // Only used by the root menu bar @@ -70,6 +70,10 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, public static final String OPEN_ROOT_MENU_ON_HOWER = "ormoh"; public static final String ATTRIBUTE_CHECKED = "checked"; + public static final String ATTRIBUTE_ITEM_DESCRIPTION = "description"; + public static final String ATTRIBUTE_ITEM_ICON = "icon"; + public static final String ATTRIBUTE_ITEM_DISABLED = "disabled"; + public static final String ATTRIBUTE_ITEM_STYLE = "style"; public static final String HTML_CONTENT_ALLOWED = "usehtml"; @@ -83,7 +87,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, protected VMenuBar parentMenu; protected CustomMenuItem selected; - private boolean enabled = true; + boolean enabled = true; private String width = "notinited"; @@ -95,9 +99,9 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, } }); - private boolean openRootOnHover; + boolean openRootOnHover; - private boolean htmlContentAllowed; + boolean htmlContentAllowed; public VMenuBar() { // Create an empty horizontal menubar @@ -150,31 +154,8 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, } } - @Override - public void setWidth(String width) { - if (Util.equals(this.width, width)) { - return; - } - - this.width = width; - if (BrowserInfo.get().isIE6() && width.endsWith("px")) { - // IE6 sometimes measures wrong using - // Util.setWidthExcludingPaddingAndBorder so this is extracted to a - // special case that uses another method. Really should fix the - // Util.setWidthExcludingPaddingAndBorder method but that will - // probably break additional cases - int requestedPixelWidth = Integer.parseInt(width.substring(0, - width.length() - 2)); - int paddingBorder = Util.measureHorizontalPaddingAndBorder( - getElement(), 0); - int w = requestedPixelWidth - paddingBorder; - if (w < 0) { - w = 0; - } - getElement().getStyle().setWidth(w, Unit.PX); - } else { - Util.setWidthExcludingPaddingAndBorder(this, width, 0); - } + void updateSize() { + // Take from setWidth if (!subMenu) { // Only needed for root level menu hideChildren(); @@ -184,141 +165,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, } /** - * This method must be implemented to update the client-side component from - * UIDL data received from server. - * - * This method is called when the page is loaded for the first time, and - * every time UI changes in the component are received from the server. - */ - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // This call should be made first. Ensure correct implementation, - // and let the containing layout manage caption, etc. - if (client.updateComponent(this, uidl, true)) { - return; - } - - htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED); - - openRootOnHover = uidl.getBooleanAttribute(OPEN_ROOT_MENU_ON_HOWER); - - enabled = !uidl.getBooleanAttribute("disabled"); - - // For future connections - this.client = client; - uidlId = uidl.getId(); - - // Empty the menu every time it receives new information - if (!getItems().isEmpty()) { - clearItems(); - } - - UIDL options = uidl.getChildUIDL(0); - - // FIXME remove in version 7 - if (options.hasAttribute("submenuIcon")) { - submenuIcon = client.translateVaadinUri(uidl.getChildUIDL(0) - .getStringAttribute("submenuIcon")); - } else { - submenuIcon = null; - } - - if (uidl.hasAttribute("width")) { - UIDL moreItemUIDL = options.getChildUIDL(0); - StringBuffer itemHTML = new StringBuffer(); - - if (moreItemUIDL.hasAttribute("icon")) { - itemHTML.append("<img src=\"" - + Util.escapeAttribute(client - .translateVaadinUri(moreItemUIDL - .getStringAttribute("icon"))) - + "\" class=\"" + Icon.CLASSNAME + "\" alt=\"\" />"); - } - - String moreItemText = moreItemUIDL.getStringAttribute("text"); - if ("".equals(moreItemText)) { - moreItemText = "►"; - } - itemHTML.append(moreItemText); - - moreItem = GWT.create(CustomMenuItem.class); - moreItem.setHTML(itemHTML.toString()); - moreItem.setCommand(emptyCommand); - - collapsedRootItems = new VMenuBar(true, - (VMenuBar) client.getPaintable(uidlId)); - moreItem.setSubMenu(collapsedRootItems); - moreItem.addStyleName(CLASSNAME + "-more-menuitem"); - } - - UIDL uidlItems = uidl.getChildUIDL(1); - Iterator<Object> itr = uidlItems.getChildIterator(); - Stack<Iterator<Object>> iteratorStack = new Stack<Iterator<Object>>(); - Stack<VMenuBar> menuStack = new Stack<VMenuBar>(); - VMenuBar currentMenu = this; - - while (itr.hasNext()) { - UIDL item = (UIDL) itr.next(); - CustomMenuItem currentItem = null; - - final int itemId = item.getIntAttribute("id"); - - boolean itemHasCommand = item.hasAttribute("command"); - boolean itemIsCheckable = item.hasAttribute(ATTRIBUTE_CHECKED); - - String itemHTML = buildItemHTML(item); - - Command cmd = null; - if (!item.hasAttribute("separator")) { - if (itemHasCommand || itemIsCheckable) { - // Construct a command that fires onMenuClick(int) with the - // item's id-number - cmd = new Command() { - public void execute() { - hostReference.onMenuClick(itemId); - } - }; - } - } - - currentItem = currentMenu.addItem(itemHTML.toString(), cmd); - currentItem.updateFromUIDL(item, client); - - if (item.getChildCount() > 0) { - menuStack.push(currentMenu); - iteratorStack.push(itr); - itr = item.getChildIterator(); - currentMenu = new VMenuBar(true, currentMenu); - if (uidl.hasAttribute("style")) { - for (String style : uidl.getStringAttribute("style").split( - " ")) { - currentMenu.addStyleDependentName(style); - } - } - currentItem.setSubMenu(currentMenu); - } - - while (!itr.hasNext() && !iteratorStack.empty()) { - boolean hasCheckableItem = false; - for (CustomMenuItem menuItem : currentMenu.getItems()) { - hasCheckableItem = hasCheckableItem - || menuItem.isCheckable(); - } - if (hasCheckableItem) { - currentMenu.addStyleDependentName("check-column"); - } else { - currentMenu.removeStyleDependentName("check-column"); - } - - itr = iteratorStack.pop(); - currentMenu = menuStack.pop(); - } - }// while - - iLayout(false); - - }// updateFromUIDL - - /** * Build the HTML content for a menu item. * * @param item @@ -332,13 +178,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, } else { // Add submenu indicator if (item.getChildCount() > 0) { - // FIXME For compatibility reasons: remove in version 7 String bgStyle = ""; - if (submenuIcon != null) { - bgStyle = " style=\"background-image: url(" - + Util.escapeAttribute(submenuIcon) - + "); text-indent: -999px; width: 1em;\""; - } itemHTML.append("<span class=\"" + CLASSNAME + "-submenu-indicator\"" + bgStyle + ">►</span>"); } @@ -478,9 +318,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, // Handle onload events (icon loaded, size changes) if (DOM.eventGetType(e) == Event.ONLOAD) { - if (BrowserInfo.get().isIE6()) { - Util.doIE6PngFix((Element) Element.as(e.getEventTarget())); - } VMenuBar parent = getParentMenu(); if (parent != null) { // The onload event for an image in a popup should be sent to @@ -733,27 +570,6 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, popup.setPopupPosition(left, top); - // IE7 really tests one's patience sometimes - // Part of a fix to correct #3850 - if (BrowserInfo.get().isIE7()) { - popup.getElement().getStyle().setProperty("zoom", ""); - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - if (popup == null) { - // The child menu can be hidden before this command is - // run. - return; - } - - if (popup.getElement().getStyle().getProperty("width") == null - || popup.getElement().getStyle() - .getProperty("width") == "") { - popup.setWidth(popup.getOffsetWidth() + "px"); - } - popup.getElement().getStyle().setProperty("zoom", "1"); - } - }); - } } private int adjustPopupHeight(int top, final int shadowSpace) { @@ -780,19 +596,10 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, style.setHeight(availableHeight, Unit.PX); style.setOverflowY(Overflow.SCROLL); - // Make room for the scroll bar - if (BrowserInfo.get().isIE6()) { - // IE6 renders the sub menu arrow icons on the scroll bar - // unless we add some padding - style.setPaddingRight(Util.getNativeScrollbarSize(), - Unit.PX); - } else { - // For other browsers, adjusting the width of the popup is - // enough - style.setWidth( - contentWidth + Util.getNativeScrollbarSize(), - Unit.PX); - } + // Make room for the scroll bar by adjusting the width of the + // popup + style.setWidth(contentWidth + Util.getNativeScrollbarSize(), + Unit.PX); popup.updateShadowSizeAndPosition(); } } @@ -962,6 +769,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, addStyleDependentName("selected"); // needed for IE6 to have a single style name to match for an // element + // TODO Can be optimized now that IE6 is not supported any more if (checkable) { if (checked) { removeStyleDependentName("selected-unchecked"); @@ -1092,7 +900,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { this.client = client; setSeparator(uidl.hasAttribute("separator")); - setEnabled(!uidl.hasAttribute("disabled")); + setEnabled(!uidl.hasAttribute(ATTRIBUTE_ITEM_DISABLED)); if (!isSeparator() && uidl.hasAttribute(ATTRIBUTE_CHECKED)) { // if the selected attribute is present (either true or false), @@ -1103,13 +911,15 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, setCheckable(false); } - if (uidl.hasAttribute("style")) { - String itemStyle = uidl.getStringAttribute("style"); + if (uidl.hasAttribute(ATTRIBUTE_ITEM_STYLE)) { + String itemStyle = uidl + .getStringAttribute(ATTRIBUTE_ITEM_STYLE); addStyleDependentName(itemStyle); } - if (uidl.hasAttribute("description")) { - String description = uidl.getStringAttribute("description"); + if (uidl.hasAttribute(ATTRIBUTE_ITEM_DESCRIPTION)) { + String description = uidl + .getStringAttribute(ATTRIBUTE_ITEM_DESCRIPTION); TooltipInfo info = new TooltipInfo(description); VMenuBar root = findRootMenu(); @@ -1150,10 +960,9 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, /** * @author Jouni Koivuviita / Vaadin Ltd. */ - private int paddingWidth = -1; - public void iLayout() { iLayout(false); + updateSize(); } public void iLayout(boolean iconLoadEvent) { @@ -1172,28 +981,8 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, removeItem(moreItem); } - // Measure available space - if (paddingWidth == -1) { - int widthBefore = getElement().getClientWidth(); - getElement().getStyle().setProperty("padding", "0"); - paddingWidth = widthBefore - getElement().getClientWidth(); - getElement().getStyle().setProperty("padding", ""); - } - String overflow = ""; - if (BrowserInfo.get().isIE6()) { - // IE6 cannot measure available width correctly without - // overflow:hidden - overflow = getElement().getStyle().getProperty("overflow"); - getElement().getStyle().setProperty("overflow", "hidden"); - } - - int availableWidth = getElement().getClientWidth() - paddingWidth; - - if (BrowserInfo.get().isIE6()) { - // IE6 cannot measure available width correctly without - // overflow:hidden - getElement().getStyle().setProperty("overflow", overflow); - } + int availableWidth = LayoutManager.get(client).getInnerWidth( + getElement()); // Used width includes the "more" item if present int usedWidth = getConsumedWidth(); @@ -1237,17 +1026,7 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, removeItem(expand); collapsedRootItems.addItem(expand, 0); } else { - widthAvailable = diff; - } - - if (BrowserInfo.get().isIE6()) { - /* - * Handle transparency for IE6 here as we cannot - * implement it in CustomMenuItem.onAttach because - * onAttach is never called for CustomMenuItem due to an - * invalid component hierarchy (#6203)... - */ - reloadImages(expand.getElement()); + widthAvailable = diff + moreItemWidth; } } } @@ -1656,31 +1435,4 @@ public class VMenuBar extends SimpleFocusablePanel implements Paintable, return null; } - @Override - protected void onLoad() { - super.onLoad(); - if (BrowserInfo.get().isIE6()) { - reloadImages(getElement()); - } - } - - /** - * Force a new onload event for all images. Used only for IE6 to deal with - * PNG transparency. - */ - private void reloadImages(Element root) { - - NodeList<com.google.gwt.dom.client.Element> imgElements = root - .getElementsByTagName("img"); - for (int i = 0; i < imgElements.getLength(); i++) { - Element e = (Element) imgElements.getItem(i); - - // IE6 fires onload events for the icons before the listener - // is attached (or never). Updating the src force another - // onload event - String src = e.getAttribute("src"); - e.setAttribute("src", src); - } - } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java new file mode 100644 index 0000000000..801c405826 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/NativeButtonConnector.java @@ -0,0 +1,125 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.nativebutton; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.EventHelper; +import com.vaadin.terminal.gwt.client.communication.FieldRpc.FocusAndBlurServerRpc; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.button.ButtonServerRpc; +import com.vaadin.terminal.gwt.client.ui.button.ButtonState; +import com.vaadin.ui.NativeButton; + +@Connect(NativeButton.class) +public class NativeButtonConnector extends AbstractComponentConnector implements + BlurHandler, FocusHandler { + + private HandlerRegistration focusHandlerRegistration; + private HandlerRegistration blurHandlerRegistration; + + private FocusAndBlurServerRpc focusBlurRpc = RpcProxy.create( + FocusAndBlurServerRpc.class, this); + + @Override + public void init() { + super.init(); + + getWidget().buttonRpcProxy = RpcProxy.create(ButtonServerRpc.class, + this); + getWidget().client = getConnection(); + getWidget().paintableId = getConnectorId(); + } + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + getWidget().disableOnClick = getState().isDisableOnClick(); + focusHandlerRegistration = EventHelper.updateFocusHandler(this, + focusHandlerRegistration); + blurHandlerRegistration = EventHelper.updateBlurHandler(this, + blurHandlerRegistration); + + // Set text + getWidget().setText(getState().getCaption()); + + // handle error + if (null != getState().getErrorMessage()) { + if (getWidget().errorIndicatorElement == null) { + getWidget().errorIndicatorElement = DOM.createSpan(); + getWidget().errorIndicatorElement + .setClassName("v-errorindicator"); + } + getWidget().getElement().insertBefore( + getWidget().errorIndicatorElement, + getWidget().captionElement); + + } else if (getWidget().errorIndicatorElement != null) { + getWidget().getElement().removeChild( + getWidget().errorIndicatorElement); + getWidget().errorIndicatorElement = null; + } + + if (getState().getIcon() != null) { + if (getWidget().icon == null) { + getWidget().icon = new Icon(getConnection()); + getWidget().getElement().insertBefore( + getWidget().icon.getElement(), + getWidget().captionElement); + } + getWidget().icon.setUri(getState().getIcon().getURL()); + } else { + if (getWidget().icon != null) { + getWidget().getElement().removeChild( + getWidget().icon.getElement()); + getWidget().icon = null; + } + } + + } + + @Override + protected Widget createWidget() { + return GWT.create(VNativeButton.class); + } + + @Override + public VNativeButton getWidget() { + return (VNativeButton) super.getWidget(); + } + + @Override + public ButtonState getState() { + return (ButtonState) super.getState(); + } + + public void onFocus(FocusEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + focusBlurRpc.focus(); + } + + public void onBlur(BlurEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + focusBlurRpc.blur(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java new file mode 100644 index 0000000000..d0b8f73eb1 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java @@ -0,0 +1,132 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.nativebutton; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Button; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.button.ButtonServerRpc; + +public class VNativeButton extends Button implements ClickHandler { + + public static final String CLASSNAME = "v-nativebutton"; + + protected String width = null; + + protected String paintableId; + + protected ApplicationConnection client; + + ButtonServerRpc buttonRpcProxy; + + protected Element errorIndicatorElement; + + protected final Element captionElement = DOM.createSpan(); + + protected Icon icon; + + /** + * Helper flag to handle special-case where the button is moved from under + * mouse while clicking it. In this case mouse leaves the button without + * moving. + */ + private boolean clickPending; + + protected boolean disableOnClick = false; + + public VNativeButton() { + setStyleName(CLASSNAME); + + getElement().appendChild(captionElement); + captionElement.setClassName(getStyleName() + "-caption"); + + addClickHandler(this); + + sinkEvents(VTooltip.TOOLTIP_EVENTS); + sinkEvents(Event.ONMOUSEDOWN); + sinkEvents(Event.ONMOUSEUP); + } + + @Override + public void setText(String text) { + captionElement.setInnerText(text); + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + + if (DOM.eventGetType(event) == Event.ONLOAD) { + Util.notifyParentOfSizeChange(this, true); + + } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN + && event.getButton() == Event.BUTTON_LEFT) { + clickPending = true; + } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) { + clickPending = false; + } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) { + if (clickPending) { + click(); + } + clickPending = false; + } + + if (client != null) { + client.handleTooltipEvent(event, this); + } + } + + @Override + public void setWidth(String width) { + this.width = width; + super.setWidth(width); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event + * .dom.client.ClickEvent) + */ + public void onClick(ClickEvent event) { + if (paintableId == null || client == null) { + return; + } + + if (BrowserInfo.get().isSafari()) { + VNativeButton.this.setFocus(true); + } + if (disableOnClick) { + setEnabled(false); + buttonRpcProxy.disableOnClick(); + } + + // Add mouse details + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event.getNativeEvent(), getElement()); + buttonRpcProxy.click(details); + + clickPending = false; + } + + @Override + public void setEnabled(boolean enabled) { + if (isEnabled() != enabled) { + super.setEnabled(enabled); + setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativeselect/NativeSelectConnector.java b/src/com/vaadin/terminal/gwt/client/ui/nativeselect/NativeSelectConnector.java new file mode 100644 index 0000000000..e6264e492f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/nativeselect/NativeSelectConnector.java @@ -0,0 +1,25 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.nativeselect; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.optiongroup.OptionGroupBaseConnector; +import com.vaadin.ui.NativeSelect; + +@Connect(NativeSelect.class) +public class NativeSelectConnector extends OptionGroupBaseConnector { + + @Override + protected Widget createWidget() { + return GWT.create(VNativeSelect.class); + } + + @Override + public VNativeSelect getWidget() { + return (VNativeSelect) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java b/src/com/vaadin/terminal/gwt/client/ui/nativeselect/VNativeSelect.java index d1b2bd76ae..54f5e9aff5 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/nativeselect/VNativeSelect.java @@ -2,15 +2,16 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.nativeselect; import java.util.ArrayList; import java.util.Iterator; import com.google.gwt.event.dom.client.ChangeEvent; -import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.listselect.TooltipListBox; +import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroupBase; public class VNativeSelect extends VOptionGroupBase implements Field { @@ -58,11 +59,6 @@ public class VNativeSelect extends VOptionGroupBase implements Field { select.setItemSelected(0, true); firstValueIsTemporaryNullItem = true; } - if (BrowserInfo.get().isIE6()) { - // lazy size change - IE6 uses naive dropdown that does not have a - // proper size yet - Util.notifyParentOfSizeChange(this, true); - } } @Override @@ -80,10 +76,10 @@ public class VNativeSelect extends VOptionGroupBase implements Field { public void onChange(ChangeEvent event) { if (select.isMultipleSelect()) { - client.updateVariable(id, "selected", getSelectedItems(), + client.updateVariable(paintableId, "selected", getSelectedItems(), isImmediate()); } else { - client.updateVariable(id, "selected", new String[] { "" + client.updateVariable(paintableId, "selected", new String[] { "" + getSelectedItem() }, isImmediate()); } if (firstValueIsTemporaryNullItem) { @@ -113,5 +109,4 @@ public class VNativeSelect extends VOptionGroupBase implements Field { public void focus() { select.setFocus(true); } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java index 27407c55aa..eb97160f52 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java +++ b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.notification; import java.util.ArrayList; import java.util.Date; @@ -21,6 +21,8 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.root.VRoot; public class VNotification extends VOverlay { @@ -56,6 +58,13 @@ public class VNotification extends VOverlay { private ArrayList<EventListener> listeners; private static final int TOUCH_DEVICE_IDLE_DELAY = 1000; + public static final String ATTRIBUTE_NOTIFICATION_STYLE = "style"; + public static final String ATTRIBUTE_NOTIFICATION_CAPTION = "caption"; + public static final String ATTRIBUTE_NOTIFICATION_MESSAGE = "message"; + public static final String ATTRIBUTE_NOTIFICATION_ICON = "icon"; + public static final String ATTRIBUTE_NOTIFICATION_POSITION = "position"; + public static final String ATTRIBUTE_NOTIFICATION_DELAY = "delay"; + /** * Default constructor. You should use GWT.create instead. */ @@ -357,23 +366,25 @@ public class VNotification extends VOverlay { public static void showNotification(ApplicationConnection client, final UIDL notification) { boolean onlyPlainText = notification - .hasAttribute(VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED); + .hasAttribute(VRoot.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED); String html = ""; - if (notification.hasAttribute("icon")) { + if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_ICON)) { final String parsedUri = client.translateVaadinUri(notification - .getStringAttribute("icon")); + .getStringAttribute(ATTRIBUTE_NOTIFICATION_ICON)); html += "<img src=\"" + Util.escapeAttribute(parsedUri) + "\" />"; } - if (notification.hasAttribute("caption")) { - String caption = notification.getStringAttribute("caption"); + if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_CAPTION)) { + String caption = notification + .getStringAttribute(ATTRIBUTE_NOTIFICATION_CAPTION); if (onlyPlainText) { caption = Util.escapeHTML(caption); caption = caption.replaceAll("\\n", "<br />"); } html += "<h1>" + caption + "</h1>"; } - if (notification.hasAttribute("message")) { - String message = notification.getStringAttribute("message"); + if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_MESSAGE)) { + String message = notification + .getStringAttribute(ATTRIBUTE_NOTIFICATION_MESSAGE); if (onlyPlainText) { message = Util.escapeHTML(message); message = message.replaceAll("\\n", "<br />"); @@ -381,10 +392,13 @@ public class VNotification extends VOverlay { html += "<p>" + message + "</p>"; } - final String style = notification.hasAttribute("style") ? notification - .getStringAttribute("style") : null; - final int position = notification.getIntAttribute("position"); - final int delay = notification.getIntAttribute("delay"); + final String style = notification + .hasAttribute(ATTRIBUTE_NOTIFICATION_STYLE) ? notification + .getStringAttribute(ATTRIBUTE_NOTIFICATION_STYLE) : null; + final int position = notification + .getIntAttribute(ATTRIBUTE_NOTIFICATION_POSITION); + final int delay = notification + .getIntAttribute(ATTRIBUTE_NOTIFICATION_DELAY); createNotification(delay).show(html, position, style); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/optiongroup/OptionGroupBaseConnector.java b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/OptionGroupBaseConnector.java new file mode 100644 index 0000000000..3658126a97 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/OptionGroupBaseConnector.java @@ -0,0 +1,93 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.optiongroup; + +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.nativebutton.VNativeButton; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; + +public abstract class OptionGroupBaseConnector extends AbstractFieldConnector + implements Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + // Save details + getWidget().client = client; + getWidget().paintableId = uidl.getId(); + + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().selectedKeys = uidl.getStringArrayVariableAsSet("selected"); + + getWidget().readonly = isReadOnly(); + getWidget().disabled = !isEnabled(); + getWidget().multiselect = "multi".equals(uidl + .getStringAttribute("selectmode")); + getWidget().immediate = getState().isImmediate(); + getWidget().nullSelectionAllowed = uidl + .getBooleanAttribute("nullselect"); + getWidget().nullSelectionItemAvailable = uidl + .getBooleanAttribute("nullselectitem"); + + if (uidl.hasAttribute("cols")) { + getWidget().cols = uidl.getIntAttribute("cols"); + } + if (uidl.hasAttribute("rows")) { + getWidget().rows = uidl.getIntAttribute("rows"); + } + + final UIDL ops = uidl.getChildUIDL(0); + + if (getWidget().getColumns() > 0) { + getWidget().container.setWidth(getWidget().getColumns() + "em"); + if (getWidget().container != getWidget().optionsContainer) { + getWidget().optionsContainer.setWidth("100%"); + } + } + + getWidget().buildOptions(ops); + + if (uidl.getBooleanAttribute("allownewitem")) { + if (getWidget().newItemField == null) { + getWidget().newItemButton = new VNativeButton(); + getWidget().newItemButton.setText("+"); + getWidget().newItemButton.addClickHandler(getWidget()); + getWidget().newItemField = new VTextField(); + getWidget().newItemField.addKeyPressHandler(getWidget()); + } + getWidget().newItemField.setEnabled(!getWidget().disabled + && !getWidget().readonly); + getWidget().newItemButton.setEnabled(!getWidget().disabled + && !getWidget().readonly); + + if (getWidget().newItemField == null + || getWidget().newItemField.getParent() != getWidget().container) { + getWidget().container.add(getWidget().newItemField); + getWidget().container.add(getWidget().newItemButton); + final int w = getWidget().container.getOffsetWidth() + - getWidget().newItemButton.getOffsetWidth(); + getWidget().newItemField.setWidth(Math.max(w, 0) + "px"); + } + } else if (getWidget().newItemField != null) { + getWidget().container.remove(getWidget().newItemField); + getWidget().container.remove(getWidget().newItemButton); + } + + getWidget().setTabIndex( + uidl.hasAttribute("tabindex") ? uidl + .getIntAttribute("tabindex") : 0); + + } + + @Override + public VOptionGroupBase getWidget() { + return (VOptionGroupBase) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/optiongroup/OptionGroupConnector.java b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/OptionGroupConnector.java new file mode 100644 index 0000000000..06552a2812 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/OptionGroupConnector.java @@ -0,0 +1,73 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.optiongroup; + +import java.util.ArrayList; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.ui.CheckBox; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.EventId; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.ui.OptionGroup; + +@Connect(OptionGroup.class) +public class OptionGroupConnector extends OptionGroupBaseConnector { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().htmlContentAllowed = uidl + .hasAttribute(VOptionGroup.HTML_CONTENT_ALLOWED); + + super.updateFromUIDL(uidl, client); + + getWidget().sendFocusEvents = client.hasEventListeners(this, + EventId.FOCUS); + getWidget().sendBlurEvents = client.hasEventListeners(this, + EventId.BLUR); + + if (getWidget().focusHandlers != null) { + for (HandlerRegistration reg : getWidget().focusHandlers) { + reg.removeHandler(); + } + getWidget().focusHandlers.clear(); + getWidget().focusHandlers = null; + + for (HandlerRegistration reg : getWidget().blurHandlers) { + reg.removeHandler(); + } + getWidget().blurHandlers.clear(); + getWidget().blurHandlers = null; + } + + if (getWidget().sendFocusEvents || getWidget().sendBlurEvents) { + getWidget().focusHandlers = new ArrayList<HandlerRegistration>(); + getWidget().blurHandlers = new ArrayList<HandlerRegistration>(); + + // add focus and blur handlers to checkboxes / radio buttons + for (Widget wid : getWidget().panel) { + if (wid instanceof CheckBox) { + getWidget().focusHandlers.add(((CheckBox) wid) + .addFocusHandler(getWidget())); + getWidget().blurHandlers.add(((CheckBox) wid) + .addBlurHandler(getWidget())); + } + } + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VOptionGroup.class); + } + + @Override + public VOptionGroup getWidget() { + return (VOptionGroup) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/VOptionGroup.java index 662f195fcd..d6e6949242 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java +++ b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/VOptionGroup.java @@ -2,9 +2,8 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.optiongroup; -import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -20,7 +19,6 @@ import com.google.gwt.event.dom.client.LoadEvent; import com.google.gwt.event.dom.client.LoadHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; -import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.Focusable; @@ -28,10 +26,11 @@ import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.RadioButton; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.checkbox.VCheckBox; public class VOptionGroup extends VOptionGroupBase implements FocusHandler, BlurHandler { @@ -40,21 +39,19 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, public static final String CLASSNAME = "v-select-optiongroup"; - private final Panel panel; + public static final String ATTRIBUTE_OPTION_DISABLED = "disabled"; + + protected final Panel panel; private final Map<CheckBox, String> optionsToKeys; - private boolean sendFocusEvents = false; - private boolean sendBlurEvents = false; - private List<HandlerRegistration> focusHandlers = null; - private List<HandlerRegistration> blurHandlers = null; + protected boolean sendFocusEvents = false; + protected boolean sendBlurEvents = false; + protected List<HandlerRegistration> focusHandlers = null; + protected List<HandlerRegistration> blurHandlers = null; private final LoadHandler iconLoadHandler = new LoadHandler() { public void onLoad(LoadEvent event) { - if (BrowserInfo.get().isIE6()) { - Util.doIE6PngFix((Element) Element.as(event.getNativeEvent() - .getEventTarget())); - } Util.notifyParentOfSizeChange(VOptionGroup.this, true); } }; @@ -68,7 +65,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, */ private boolean blurOccured = false; - private boolean htmlContentAllowed = false; + protected boolean htmlContentAllowed = false; public VOptionGroup() { super(CLASSNAME); @@ -76,43 +73,6 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, optionsToKeys = new HashMap<CheckBox, String>(); } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED); - - super.updateFromUIDL(uidl, client); - - sendFocusEvents = client.hasEventListeners(this, EventId.FOCUS); - sendBlurEvents = client.hasEventListeners(this, EventId.BLUR); - - if (focusHandlers != null) { - for (HandlerRegistration reg : focusHandlers) { - reg.removeHandler(); - } - focusHandlers.clear(); - focusHandlers = null; - - for (HandlerRegistration reg : blurHandlers) { - reg.removeHandler(); - } - blurHandlers.clear(); - blurHandlers = null; - } - - if (sendFocusEvents || sendBlurEvents) { - focusHandlers = new ArrayList<HandlerRegistration>(); - blurHandlers = new ArrayList<HandlerRegistration>(); - - // add focus and blur handlers to checkboxes / radio buttons - for (Widget wid : panel) { - if (wid instanceof CheckBox) { - focusHandlers.add(((CheckBox) wid).addFocusHandler(this)); - blurHandlers.add(((CheckBox) wid).addBlurHandler(this)); - } - } - } - } - /* * Return true if no elements were changed, false otherwise. */ @@ -139,7 +99,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, op = new VCheckBox(); op.setHTML(itemHtml); } else { - op = new RadioButton(id, itemHtml, true); + op = new RadioButton(paintableId, itemHtml, true); op.setStyleName("v-radiobutton"); } @@ -150,7 +110,8 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, op.addStyleName(CLASSNAME_OPTION); op.setValue(opUidl.getBooleanAttribute("selected")); - boolean enabled = !opUidl.getBooleanAttribute("disabled") + boolean enabled = !opUidl + .getBooleanAttribute(ATTRIBUTE_OPTION_DISABLED) && !isReadonly() && !isDisabled(); op.setEnabled(enabled); setStyleName(op.getElement(), @@ -180,7 +141,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, } else { selectedKeys.remove(key); } - client.updateVariable(id, "selected", getSelectedItems(), + client.updateVariable(paintableId, "selected", getSelectedItems(), isImmediate()); } } @@ -206,7 +167,7 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, // panel was blurred => fire the event to the server side if // requested by server side if (sendFocusEvents) { - client.updateVariable(id, EventId.FOCUS, "", true); + client.updateVariable(paintableId, EventId.FOCUS, "", true); } } else { // blur occured before this focus event @@ -225,7 +186,8 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, // check whether blurOccured still is true and then send the // event out to the server if (blurOccured) { - client.updateVariable(id, EventId.BLUR, "", true); + client.updateVariable(paintableId, EventId.BLUR, "", + true); blurOccured = false; } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/VOptionGroupBase.java index 50a9f8cb98..a512f024b8 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java +++ b/src/com/vaadin/terminal/gwt/client/ui/optiongroup/VOptionGroupBase.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.optiongroup; import java.util.Set; @@ -19,35 +19,37 @@ import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.nativebutton.VNativeButton; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; -abstract class VOptionGroupBase extends Composite implements Paintable, Field, +public abstract class VOptionGroupBase extends Composite implements Field, ClickHandler, ChangeHandler, KeyPressHandler, Focusable { public static final String CLASSNAME_OPTION = "v-select-option"; protected ApplicationConnection client; - protected String id; + protected String paintableId; protected Set<String> selectedKeys; - private boolean immediate; + protected boolean immediate; - private boolean multiselect; + protected boolean multiselect; - private boolean disabled; + protected boolean disabled; - private boolean readonly; + protected boolean readonly; - private int cols = 0; + protected int cols = 0; - private int rows = 0; + protected int rows = 0; - private boolean nullSelectionAllowed = true; + protected boolean nullSelectionAllowed = true; - private boolean nullSelectionItemAvailable = false; + protected boolean nullSelectionItemAvailable = false; /** * Widget holding the different options (e.g. ListBox or Panel for radio @@ -58,11 +60,11 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field, /** * Panel containing the component */ - private final Panel container; + protected final Panel container; - private VTextField newItemField; + protected VTextField newItemField; - private VNativeButton newItemButton; + protected VNativeButton newItemButton; public VOptionGroupBase(String classname) { container = new FlowPanel(); @@ -122,84 +124,23 @@ abstract class VOptionGroupBase extends Composite implements Paintable, Field, return rows; } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - id = uidl.getId(); - - if (client.updateComponent(this, uidl, true)) { - return; - } - - selectedKeys = uidl.getStringArrayVariableAsSet("selected"); - - readonly = uidl.getBooleanAttribute("readonly"); - disabled = uidl.getBooleanAttribute("disabled"); - multiselect = "multi".equals(uidl.getStringAttribute("selectmode")); - immediate = uidl.getBooleanAttribute("immediate"); - nullSelectionAllowed = uidl.getBooleanAttribute("nullselect"); - nullSelectionItemAvailable = uidl.getBooleanAttribute("nullselectitem"); - - if (uidl.hasAttribute("cols")) { - cols = uidl.getIntAttribute("cols"); - } - if (uidl.hasAttribute("rows")) { - rows = uidl.getIntAttribute("rows"); - } - - final UIDL ops = uidl.getChildUIDL(0); - - if (getColumns() > 0) { - container.setWidth(getColumns() + "em"); - if (container != optionsContainer) { - optionsContainer.setWidth("100%"); - } - } - - buildOptions(ops); - - if (uidl.getBooleanAttribute("allownewitem")) { - if (newItemField == null) { - newItemButton = new VNativeButton(); - newItemButton.setText("+"); - newItemButton.addClickHandler(this); - newItemField = new VTextField(); - newItemField.addKeyPressHandler(this); - } - newItemField.setEnabled(!disabled && !readonly); - newItemButton.setEnabled(!disabled && !readonly); - - if (newItemField == null || newItemField.getParent() != container) { - container.add(newItemField); - container.add(newItemButton); - final int w = container.getOffsetWidth() - - newItemButton.getOffsetWidth(); - newItemField.setWidth(Math.max(w, 0) + "px"); - } - } else if (newItemField != null) { - container.remove(newItemField); - container.remove(newItemButton); - } - - setTabIndex(uidl.hasAttribute("tabindex") ? uidl - .getIntAttribute("tabindex") : 0); - - } - abstract protected void setTabIndex(int tabIndex); public void onClick(ClickEvent event) { if (event.getSource() == newItemButton && !newItemField.getText().equals("")) { - client.updateVariable(id, "newitem", newItemField.getText(), true); + client.updateVariable(paintableId, "newitem", + newItemField.getText(), true); newItemField.setText(""); } } public void onChange(ChangeEvent event) { if (multiselect) { - client.updateVariable(id, "selected", getSelectedItems(), immediate); + client.updateVariable(paintableId, "selected", getSelectedItems(), + immediate); } else { - client.updateVariable(id, "selected", new String[] { "" + client.updateVariable(paintableId, "selected", new String[] { "" + getSelectedItem() }, immediate); } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java new file mode 100644 index 0000000000..174da61bd3 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -0,0 +1,331 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +import java.util.List; + +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ValueMap; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutConnector; +import com.vaadin.terminal.gwt.client.ui.AlignmentInfo; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; +import com.vaadin.terminal.gwt.client.ui.layout.ComponentConnectorLayoutSlot; +import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot; + +public abstract class AbstractOrderedLayoutConnector extends + AbstractLayoutConnector implements Paintable, DirectionalManagedLayout { + + 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() { + rpc = RpcProxy.create(AbstractOrderedLayoutServerRpc.class, this); + getLayoutManager().registerDependency(this, + getWidget().spacingMeasureElement); + } + + @Override + public void onUnregister() { + LayoutManager lm = getLayoutManager(); + + VMeasuringOrderedLayout layout = getWidget(); + lm.unregisterDependency(this, layout.spacingMeasureElement); + + // Unregister child caption listeners + for (ComponentConnector child : getChildren()) { + VLayoutSlot slot = layout.getSlotForChild(child.getWidget()); + slot.setCaption(null); + } + } + + @Override + public AbstractOrderedLayoutState getState() { + return (AbstractOrderedLayoutState) super.getState(); + } + + public void updateCaption(ComponentConnector component) { + VMeasuringOrderedLayout layout = getWidget(); + if (VCaption.isNeeded(component.getState())) { + VLayoutSlot layoutSlot = layout.getSlotForChild(component + .getWidget()); + VCaption caption = layoutSlot.getCaption(); + if (caption == null) { + caption = new VCaption(component, getConnection()); + + Widget widget = component.getWidget(); + + layout.setCaption(widget, caption); + } + caption.updateCaption(); + } else { + layout.setCaption(component.getWidget(), null); + getLayoutManager().setNeedsLayout(this); + } + } + + @Override + public VMeasuringOrderedLayout getWidget() { + return (VMeasuringOrderedLayout) super.getWidget(); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + clickEventHandler.handleEventHandlerRegistration(); + + VMeasuringOrderedLayout layout = getWidget(); + + ValueMap expandRatios = uidl.getMapAttribute("expandRatios"); + ValueMap alignments = uidl.getMapAttribute("alignments"); + + for (ComponentConnector child : getChildren()) { + VLayoutSlot slot = layout.getSlotForChild(child.getWidget()); + String pid = child.getConnectorId(); + + AlignmentInfo alignment; + if (alignments.containsKey(pid)) { + alignment = new AlignmentInfo(alignments.getInt(pid)); + } else { + alignment = AlignmentInfo.TOP_LEFT; + } + slot.setAlignment(alignment); + + double expandRatio; + if (expandRatios.containsKey(pid)) { + expandRatio = expandRatios.getRawNumber(pid); + } else { + expandRatio = 0; + } + slot.setExpandRatio(expandRatio); + } + + layout.updateMarginStyleNames(new VMarginInfo(getState() + .getMarginsBitmask())); + + layout.updateSpacingStyleName(getState().isSpacing()); + + getLayoutManager().setNeedsLayout(this); + } + + private int getSizeForInnerSize(int size, boolean isVertical) { + LayoutManager layoutManager = getLayoutManager(); + Element element = getWidget().getElement(); + if (isVertical) { + return size + layoutManager.getBorderHeight(element) + + layoutManager.getPaddingHeight(element); + } else { + return size + layoutManager.getBorderWidth(element) + + layoutManager.getPaddingWidth(element); + } + } + + private static String getSizeProperty(boolean isVertical) { + return isVertical ? "height" : "width"; + } + + private boolean isUndefinedInDirection(boolean isVertical) { + if (isVertical) { + return isUndefinedHeight(); + } else { + return isUndefinedWidth(); + } + } + + private int getInnerSizeInDirection(boolean isVertical) { + if (isVertical) { + return getLayoutManager().getInnerHeight(getWidget().getElement()); + } else { + return getLayoutManager().getInnerWidth(getWidget().getElement()); + } + } + + private void layoutPrimaryDirection() { + VMeasuringOrderedLayout layout = getWidget(); + boolean isVertical = layout.isVertical; + boolean isUndefined = isUndefinedInDirection(isVertical); + + int startPadding = getStartPadding(isVertical); + int endPadding = getEndPadding(isVertical); + int spacingSize = getSpacingInDirection(isVertical); + int allocatedSize; + + if (isUndefined) { + allocatedSize = -1; + } else { + allocatedSize = getInnerSizeInDirection(isVertical); + } + + allocatedSize = layout.layoutPrimaryDirection(spacingSize, + allocatedSize, startPadding, endPadding); + + Style ownStyle = getWidget().getElement().getStyle(); + if (isUndefined) { + int outerSize = getSizeForInnerSize(allocatedSize, isVertical); + ownStyle.setPropertyPx(getSizeProperty(isVertical), outerSize); + reportUndefinedSize(outerSize, isVertical); + } else { + ownStyle.setProperty(getSizeProperty(isVertical), + getDefinedSize(isVertical)); + } + } + + private void reportUndefinedSize(int outerSize, boolean isVertical) { + if (isVertical) { + getLayoutManager().reportOuterHeight(this, outerSize); + } else { + getLayoutManager().reportOuterWidth(this, outerSize); + } + } + + private int getSpacingInDirection(boolean isVertical) { + if (isVertical) { + return getLayoutManager().getOuterHeight( + getWidget().spacingMeasureElement); + } else { + return getLayoutManager().getOuterWidth( + getWidget().spacingMeasureElement); + } + } + + private void layoutSecondaryDirection() { + VMeasuringOrderedLayout layout = getWidget(); + boolean isVertical = layout.isVertical; + boolean isUndefined = isUndefinedInDirection(!isVertical); + + int startPadding = getStartPadding(!isVertical); + int endPadding = getEndPadding(!isVertical); + + int allocatedSize; + if (isUndefined) { + allocatedSize = -1; + } else { + allocatedSize = getInnerSizeInDirection(!isVertical); + } + + allocatedSize = layout.layoutSecondaryDirection(allocatedSize, + startPadding, endPadding); + + Style ownStyle = getWidget().getElement().getStyle(); + + if (isUndefined) { + int outerSize = getSizeForInnerSize(allocatedSize, + !getWidget().isVertical); + ownStyle.setPropertyPx(getSizeProperty(!getWidget().isVertical), + outerSize); + reportUndefinedSize(outerSize, !isVertical); + } else { + ownStyle.setProperty(getSizeProperty(!getWidget().isVertical), + getDefinedSize(!getWidget().isVertical)); + } + } + + private String getDefinedSize(boolean isVertical) { + if (isVertical) { + return getState().getHeight(); + } else { + return getState().getWidth(); + } + } + + private int getStartPadding(boolean isVertical) { + if (isVertical) { + return getLayoutManager().getPaddingTop(getWidget().getElement()); + } else { + return getLayoutManager().getPaddingLeft(getWidget().getElement()); + } + } + + private int getEndPadding(boolean isVertical) { + if (isVertical) { + return getLayoutManager() + .getPaddingBottom(getWidget().getElement()); + } else { + return getLayoutManager().getPaddingRight(getWidget().getElement()); + } + } + + public void layoutHorizontally() { + if (getWidget().isVertical) { + layoutSecondaryDirection(); + } else { + layoutPrimaryDirection(); + } + } + + public void layoutVertically() { + if (getWidget().isVertical) { + layoutPrimaryDirection(); + } else { + layoutSecondaryDirection(); + } + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + List<ComponentConnector> previousChildren = event.getOldChildren(); + int currentIndex = 0; + VMeasuringOrderedLayout layout = getWidget(); + + for (ComponentConnector child : getChildren()) { + Widget childWidget = child.getWidget(); + VLayoutSlot slot = layout.getSlotForChild(childWidget); + + if (childWidget.getParent() != layout) { + // If the child widget was previously attached to another + // AbstractOrderedLayout a slot might be found that belongs to + // another AbstractOrderedLayout. In this case we discard it and + // create a new slot. + slot = new ComponentConnectorLayoutSlot(getWidget() + .getStylePrimaryName(), child, this); + } + layout.addOrMove(slot, currentIndex++); + if (child.isRelativeWidth()) { + slot.getWrapperElement().getStyle().setWidth(100, Unit.PCT); + } + } + + for (ComponentConnector child : previousChildren) { + if (child.getParent() != this) { + // Remove slot if the connector is no longer a child of this + // layout + layout.removeSlotForWidget(child.getWidget()); + } + } + + }; + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRpc.java new file mode 100644 index 0000000000..5a29eacada --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutServerRpc.java @@ -0,0 +1,12 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.LayoutClickRpc; + +public interface AbstractOrderedLayoutServerRpc extends LayoutClickRpc, + ServerRpc { + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutState.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutState.java new file mode 100644 index 0000000000..bf542d3951 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/AbstractOrderedLayoutState.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutState; + +public class AbstractOrderedLayoutState extends AbstractLayoutState { + private boolean spacing = false; + + public boolean isSpacing() { + return spacing; + } + + public void setSpacing(boolean spacing) { + this.spacing = spacing; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java new file mode 100644 index 0000000000..a12b41ade7 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/HorizontalLayoutConnector.java @@ -0,0 +1,24 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +import com.google.gwt.core.client.GWT; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.HorizontalLayout; + +@Connect(value = HorizontalLayout.class, loadStyle = LoadStyle.EAGER) +public class HorizontalLayoutConnector extends AbstractOrderedLayoutConnector { + + @Override + public VHorizontalLayout getWidget() { + return (VHorizontalLayout) super.getWidget(); + } + + @Override + protected VHorizontalLayout createWidget() { + return GWT.create(VHorizontalLayout.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VHorizontalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VHorizontalLayout.java new file mode 100644 index 0000000000..5bf377642e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VHorizontalLayout.java @@ -0,0 +1,14 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +public class VHorizontalLayout extends VMeasuringOrderedLayout { + + public static final String CLASSNAME = "v-horizontallayout"; + + public VHorizontalLayout() { + super(CLASSNAME, false); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VMeasuringOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VMeasuringOrderedLayout.java new file mode 100644 index 0000000000..de55ca98e6 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VMeasuringOrderedLayout.java @@ -0,0 +1,241 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.user.client.ui.WidgetCollection; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ui.VMarginInfo; +import com.vaadin.terminal.gwt.client.ui.layout.VLayoutSlot; + +public class VMeasuringOrderedLayout extends ComplexPanel { + + final boolean isVertical; + + final DivElement spacingMeasureElement; + + private Map<Widget, VLayoutSlot> widgetToSlot = new HashMap<Widget, VLayoutSlot>(); + + protected VMeasuringOrderedLayout(String className, boolean isVertical) { + DivElement element = Document.get().createDivElement(); + setElement(element); + + spacingMeasureElement = Document.get().createDivElement(); + Style spacingStyle = spacingMeasureElement.getStyle(); + spacingStyle.setPosition(Position.ABSOLUTE); + getElement().appendChild(spacingMeasureElement); + + setStyleName(className); + this.isVertical = isVertical; + } + + public void addOrMove(VLayoutSlot layoutSlot, int index) { + Widget widget = layoutSlot.getWidget(); + Element wrapperElement = layoutSlot.getWrapperElement(); + + Element containerElement = getElement(); + Node childAtIndex = containerElement.getChild(index); + if (childAtIndex != wrapperElement) { + // Insert at correct location not attached or at wrong location + containerElement.insertBefore(wrapperElement, childAtIndex); + insert(widget, wrapperElement, index, false); + } + + widgetToSlot.put(widget, layoutSlot); + } + + private void togglePrefixedStyleName(String name, boolean enabled) { + if (enabled) { + addStyleDependentName(name); + } else { + removeStyleDependentName(name); + } + } + + void updateMarginStyleNames(VMarginInfo marginInfo) { + togglePrefixedStyleName("margin-top", marginInfo.hasTop()); + togglePrefixedStyleName("margin-right", marginInfo.hasRight()); + togglePrefixedStyleName("margin-bottom", marginInfo.hasBottom()); + togglePrefixedStyleName("margin-left", marginInfo.hasLeft()); + } + + void updateSpacingStyleName(boolean spacingEnabled) { + String styleName = getStylePrimaryName(); + if (spacingEnabled) { + spacingMeasureElement.addClassName(styleName + "-spacing-on"); + spacingMeasureElement.removeClassName(styleName + "-spacing-off"); + } else { + spacingMeasureElement.removeClassName(styleName + "-spacing-on"); + spacingMeasureElement.addClassName(styleName + "-spacing-off"); + } + } + + public void removeSlotForWidget(Widget widget) { + VLayoutSlot slot = getSlotForChild(widget); + VCaption caption = slot.getCaption(); + if (caption != null) { + // Must remove using setCaption to ensure dependencies (layout -> + // caption) are unregistered + slot.setCaption(null); + } + + remove(slot.getWidget()); + getElement().removeChild(slot.getWrapperElement()); + widgetToSlot.remove(widget); + } + + public VLayoutSlot getSlotForChild(Widget widget) { + return widgetToSlot.get(widget); + } + + public void setCaption(Widget child, VCaption caption) { + VLayoutSlot slot = getSlotForChild(child); + + if (caption != null) { + // Logical attach. + getChildren().add(caption); + } + + // Physical attach if not null, also removes old caption + slot.setCaption(caption); + + if (caption != null) { + // Adopt. + adopt(caption); + } + } + + public int layoutPrimaryDirection(int spacingSize, int allocatedSize, + int startPadding, int endPadding) { + int actuallyAllocated = 0; + double totalExpand = 0; + + int childCount = 0; + for (Widget child : this) { + if (child instanceof VCaption) { + continue; + } + childCount++; + + VLayoutSlot slot = getSlotForChild(child); + totalExpand += slot.getExpandRatio(); + + if (!slot.isRelativeInDirection(isVertical)) { + actuallyAllocated += slot.getUsedSizeInDirection(isVertical); + } + } + + actuallyAllocated += spacingSize * (childCount - 1); + + if (allocatedSize == -1) { + allocatedSize = actuallyAllocated; + } + + double unallocatedSpace = Math + .max(0, allocatedSize - actuallyAllocated); + + double currentLocation = startPadding; + + WidgetCollection children = getChildren(); + for (int i = 0; i < children.size(); i++) { + Widget child = children.get(i); + if (child instanceof VCaption) { + continue; + } + + VLayoutSlot slot = getSlotForChild(child); + + double childExpandRatio; + if (totalExpand == 0) { + childExpandRatio = 1d / childCount; + } else { + childExpandRatio = slot.getExpandRatio() / totalExpand; + } + + double extraPixels = unallocatedSpace * childExpandRatio; + double endLocation = currentLocation + extraPixels; + if (!slot.isRelativeInDirection(isVertical)) { + endLocation += slot.getUsedSizeInDirection(isVertical); + } + + /* + * currentLocation and allocatedSpace are used with full precision + * to avoid missing pixels in the end. The pixel dimensions passed + * to the DOM are still rounded. Otherwise e.g. 10.5px start + * position + 10.5px space might be cause the component to go 1px + * beyond the edge as the effect of the browser's rounding may cause + * something similar to 11px + 11px. + * + * It's most efficient to use doubles all the way because native + * javascript emulates other number types using doubles. + */ + double roundedLocation = Math.round(currentLocation); + + /* + * Space is calculated as the difference between rounded start and + * end locations. Just rounding the space would cause e.g. 10.5px + + * 10.5px = 21px -> 11px + 11px = 22px but in this way we get 11px + + * 10px = 21px. + */ + double roundedSpace = Math.round(endLocation) - roundedLocation; + + // Reserve room for the padding if we're at the end + double slotEndMargin; + if (i == children.size() - 1) { + slotEndMargin = endPadding; + } else { + slotEndMargin = 0; + } + + slot.positionInDirection(roundedLocation, roundedSpace, + slotEndMargin, isVertical); + + currentLocation = endLocation + spacingSize; + } + + return allocatedSize; + } + + public int layoutSecondaryDirection(int allocatedSize, int startPadding, + int endPadding) { + int maxSize = 0; + for (Widget child : this) { + if (child instanceof VCaption) { + continue; + } + + VLayoutSlot slot = getSlotForChild(child); + if (!slot.isRelativeInDirection(!isVertical)) { + maxSize = Math.max(maxSize, + slot.getUsedSizeInDirection(!isVertical)); + } + } + + if (allocatedSize == -1) { + allocatedSize = maxSize; + } + + for (Widget child : this) { + if (child instanceof VCaption) { + continue; + } + + VLayoutSlot slot = getSlotForChild(child); + slot.positionInDirection(startPadding, allocatedSize, endPadding, + !isVertical); + } + + return allocatedSize; + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VVerticalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VVerticalLayout.java new file mode 100644 index 0000000000..e44c576941 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VVerticalLayout.java @@ -0,0 +1,14 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +public class VVerticalLayout extends VMeasuringOrderedLayout { + + public static final String CLASSNAME = "v-verticallayout"; + + public VVerticalLayout() { + super(CLASSNAME, true); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java new file mode 100644 index 0000000000..1e5651ce38 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/orderedlayout/VerticalLayoutConnector.java @@ -0,0 +1,24 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.orderedlayout; + +import com.google.gwt.core.client.GWT; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.VerticalLayout; + +@Connect(value = VerticalLayout.class, loadStyle = LoadStyle.EAGER) +public class VerticalLayoutConnector extends AbstractOrderedLayoutConnector { + + @Override + public VVerticalLayout getWidget() { + return (VVerticalLayout) super.getWidget(); + } + + @Override + protected VVerticalLayout createWidget() { + return GWT.create(VVerticalLayout.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java new file mode 100644 index 0000000000..9555c38a36 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java @@ -0,0 +1,243 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.panel; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; +import com.vaadin.ui.Panel; + +@Connect(Panel.class) +public class PanelConnector extends AbstractComponentContainerConnector + implements Paintable, SimpleManagedLayout, PostLayoutListener, + MayScrollChildren { + + private Integer uidlScrollTop; + + private ClickEventHandler clickEventHandler = new ClickEventHandler(this) { + + @Override + protected void fireClick(NativeEvent event, + MouseEventDetails mouseDetails) { + rpc.click(mouseDetails); + } + }; + + private Integer uidlScrollLeft; + + private PanelServerRpc rpc; + + @Override + public void init() { + rpc = RpcProxy.create(PanelServerRpc.class, this); + VPanel panel = getWidget(); + LayoutManager layoutManager = getLayoutManager(); + + layoutManager.registerDependency(this, panel.captionNode); + layoutManager.registerDependency(this, panel.bottomDecoration); + layoutManager.registerDependency(this, panel.contentNode); + } + + @Override + public void onUnregister() { + VPanel panel = getWidget(); + LayoutManager layoutManager = getLayoutManager(); + + layoutManager.unregisterDependency(this, panel.captionNode); + layoutManager.unregisterDependency(this, panel.bottomDecoration); + layoutManager.unregisterDependency(this, panel.contentNode); + } + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (isRealUpdate(uidl)) { + + // Handle caption displaying and style names, prior generics. + // Affects size calculations + + // Restore default stylenames + getWidget().contentNode.setClassName(VPanel.CLASSNAME + "-content"); + getWidget().bottomDecoration.setClassName(VPanel.CLASSNAME + + "-deco"); + getWidget().captionNode.setClassName(VPanel.CLASSNAME + "-caption"); + boolean hasCaption = false; + if (getState().getCaption() != null + && !"".equals(getState().getCaption())) { + getWidget().setCaption(getState().getCaption()); + hasCaption = true; + } else { + getWidget().setCaption(""); + getWidget().captionNode.setClassName(VPanel.CLASSNAME + + "-nocaption"); + } + + // Add proper stylenames for all elements. This way we can prevent + // unwanted CSS selector inheritance. + final String captionBaseClass = VPanel.CLASSNAME + + (hasCaption ? "-caption" : "-nocaption"); + final String contentBaseClass = VPanel.CLASSNAME + "-content"; + final String decoBaseClass = VPanel.CLASSNAME + "-deco"; + String captionClass = captionBaseClass; + String contentClass = contentBaseClass; + String decoClass = decoBaseClass; + if (getState().hasStyles()) { + for (String style : getState().getStyles()) { + captionClass += " " + captionBaseClass + "-" + style; + contentClass += " " + contentBaseClass + "-" + style; + decoClass += " " + decoBaseClass + "-" + style; + } + } + getWidget().captionNode.setClassName(captionClass); + getWidget().contentNode.setClassName(contentClass); + getWidget().bottomDecoration.setClassName(decoClass); + } + + if (!isRealUpdate(uidl)) { + return; + } + + clickEventHandler.handleEventHandlerRegistration(); + + getWidget().client = client; + getWidget().id = uidl.getId(); + + if (getState().getIcon() != null) { + getWidget().setIconUri(getState().getIcon().getURL(), client); + } else { + getWidget().setIconUri(null, client); + } + + getWidget().setErrorIndicatorVisible( + null != getState().getErrorMessage()); + + // We may have actions attached to this panel + if (uidl.getChildCount() > 0) { + final int cnt = uidl.getChildCount(); + for (int i = 0; i < cnt; i++) { + UIDL childUidl = uidl.getChildUIDL(i); + if (childUidl.getTag().equals("actions")) { + if (getWidget().shortcutHandler == null) { + getWidget().shortcutHandler = new ShortcutActionHandler( + getConnectorId(), client); + } + getWidget().shortcutHandler.updateActionMap(childUidl); + } + } + } + + if (getState().getScrollTop() != getWidget().scrollTop) { + // Sizes are not yet up to date, so changing the scroll position + // is deferred to after the layout phase + uidlScrollTop = getState().getScrollTop(); + } + + if (getState().getScrollLeft() != getWidget().scrollLeft) { + // Sizes are not yet up to date, so changing the scroll position + // is deferred to after the layout phase + uidlScrollLeft = getState().getScrollLeft(); + } + + // And apply tab index + getWidget().contentNode.setTabIndex(getState().getTabIndex()); + } + + public void updateCaption(ComponentConnector component) { + // NOP: layouts caption, errors etc not rendered in Panel + } + + @Override + public VPanel getWidget() { + return (VPanel) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VPanel.class); + } + + public void layout() { + updateSizes(); + } + + void updateSizes() { + VPanel panel = getWidget(); + + LayoutManager layoutManager = getLayoutManager(); + int top = layoutManager.getOuterHeight(panel.captionNode); + int bottom = layoutManager.getInnerHeight(panel.bottomDecoration); + + Style style = panel.getElement().getStyle(); + panel.captionNode.getParentElement().getStyle() + .setMarginTop(-top, Unit.PX); + panel.bottomDecoration.getStyle().setMarginBottom(-bottom, Unit.PX); + style.setPaddingTop(top, Unit.PX); + style.setPaddingBottom(bottom, Unit.PX); + + // Update scroll positions + panel.contentNode.setScrollTop(panel.scrollTop); + panel.contentNode.setScrollLeft(panel.scrollLeft); + // Read actual value back to ensure update logic is correct + panel.scrollTop = panel.contentNode.getScrollTop(); + panel.scrollLeft = panel.contentNode.getScrollLeft(); + } + + public void postLayout() { + VPanel panel = getWidget(); + if (uidlScrollTop != null) { + panel.contentNode.setScrollTop(uidlScrollTop.intValue()); + // Read actual value back to ensure update logic is correct + // TODO Does this trigger reflows? + panel.scrollTop = panel.contentNode.getScrollTop(); + uidlScrollTop = null; + } + + if (uidlScrollLeft != null) { + panel.contentNode.setScrollLeft(uidlScrollLeft.intValue()); + // Read actual value back to ensure update logic is correct + // TODO Does this trigger reflows? + panel.scrollLeft = panel.contentNode.getScrollLeft(); + uidlScrollLeft = null; + } + } + + @Override + public PanelState getState() { + return (PanelState) super.getState(); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + // We always have 1 child, unless the child is hidden + Widget newChildWidget = null; + if (getChildren().size() == 1) { + ComponentConnector newChild = getChildren().get(0); + newChildWidget = newChild.getWidget(); + } + + getWidget().setWidget(newChildWidget); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRpc.java new file mode 100644 index 0000000000..9b59344aec --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelServerRpc.java @@ -0,0 +1,11 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.panel; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.ClickRpc; + +public interface PanelServerRpc extends ClickRpc, ServerRpc { + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelState.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelState.java new file mode 100644 index 0000000000..fc7921825f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelState.java @@ -0,0 +1,36 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.panel; + +import com.vaadin.terminal.gwt.client.ComponentState; + +public class PanelState extends ComponentState { + private int tabIndex; + private int scrollLeft, scrollTop; + + public int getTabIndex() { + return tabIndex; + } + + public void setTabIndex(int tabIndex) { + this.tabIndex = tabIndex; + } + + public int getScrollLeft() { + return scrollLeft; + } + + public void setScrollLeft(int scrollLeft) { + this.scrollLeft = scrollLeft; + } + + public int getScrollTop() { + return scrollTop; + } + + public void setScrollTop(int scrollTop) { + this.scrollTop = scrollTop; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java new file mode 100644 index 0000000000..e2d3d443a0 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java @@ -0,0 +1,189 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.panel; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.event.dom.client.TouchStartEvent; +import com.google.gwt.event.dom.client.TouchStartHandler; +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.SimplePanel; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate; + +public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner, + Focusable { + + public static final String CLASSNAME = "v-panel"; + + ApplicationConnection client; + + String id; + + final Element captionNode = DOM.createDiv(); + + private final Element captionText = DOM.createSpan(); + + private Icon icon; + + final Element bottomDecoration = DOM.createDiv(); + + final Element contentNode = DOM.createDiv(); + + private Element errorIndicatorElement; + + ShortcutActionHandler shortcutHandler; + + int scrollTop; + + int scrollLeft; + + private TouchScrollDelegate touchScrollDelegate; + + public VPanel() { + super(); + DivElement captionWrap = Document.get().createDivElement(); + captionWrap.appendChild(captionNode); + captionNode.appendChild(captionText); + + captionWrap.setClassName(CLASSNAME + "-captionwrap"); + captionNode.setClassName(CLASSNAME + "-caption"); + contentNode.setClassName(CLASSNAME + "-content"); + bottomDecoration.setClassName(CLASSNAME + "-deco"); + + getElement().appendChild(captionWrap); + + /* + * Make contentNode focusable only by using the setFocus() method. This + * behaviour can be changed by invoking setTabIndex() in the serverside + * implementation + */ + contentNode.setTabIndex(-1); + + getElement().appendChild(contentNode); + + getElement().appendChild(bottomDecoration); + setStyleName(CLASSNAME); + DOM.sinkEvents(getElement(), Event.ONKEYDOWN); + DOM.sinkEvents(contentNode, Event.ONSCROLL | Event.TOUCHEVENTS); + addHandler(new TouchStartHandler() { + public void onTouchStart(TouchStartEvent event) { + getTouchScrollDelegate().onTouchStart(event); + } + }, TouchStartEvent.getType()); + } + + /** + * Sets the keyboard focus on the Panel + * + * @param focus + * Should the panel have focus or not. + */ + public void setFocus(boolean focus) { + if (focus) { + getContainerElement().focus(); + } else { + getContainerElement().blur(); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.Focusable#focus() + */ + public void focus() { + setFocus(true); + + } + + @Override + protected Element getContainerElement() { + return contentNode; + } + + void setCaption(String text) { + DOM.setInnerHTML(captionText, text); + } + + void setErrorIndicatorVisible(boolean showError) { + if (showError) { + if (errorIndicatorElement == null) { + errorIndicatorElement = DOM.createSpan(); + DOM.setElementProperty(errorIndicatorElement, "className", + "v-errorindicator"); + DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS); + sinkEvents(Event.MOUSEEVENTS); + } + DOM.insertBefore(captionNode, errorIndicatorElement, captionText); + } else if (errorIndicatorElement != null) { + DOM.removeChild(captionNode, errorIndicatorElement); + errorIndicatorElement = null; + } + } + + void setIconUri(String iconUri, ApplicationConnection client) { + if (iconUri == null) { + if (icon != null) { + DOM.removeChild(captionNode, icon.getElement()); + icon = null; + } + } else { + if (icon == null) { + icon = new Icon(client); + DOM.insertChild(captionNode, icon.getElement(), 0); + } + icon.setUri(iconUri); + } + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + + final Element target = DOM.eventGetTarget(event); + final int type = DOM.eventGetType(event); + if (type == Event.ONKEYDOWN && shortcutHandler != null) { + shortcutHandler.handleKeyboardEvent(event); + return; + } + if (type == Event.ONSCROLL) { + int newscrollTop = DOM.getElementPropertyInt(contentNode, + "scrollTop"); + int newscrollLeft = DOM.getElementPropertyInt(contentNode, + "scrollLeft"); + if (client != null + && (newscrollLeft != scrollLeft || newscrollTop != scrollTop)) { + scrollLeft = newscrollLeft; + scrollTop = newscrollTop; + client.updateVariable(id, "scrollTop", scrollTop, false); + client.updateVariable(id, "scrollLeft", scrollLeft, false); + } + } else if (captionNode.isOrHasChild(target)) { + if (client != null) { + client.handleTooltipEvent(event, this); + } + } + } + + protected TouchScrollDelegate getTouchScrollDelegate() { + if (touchScrollDelegate == null) { + touchScrollDelegate = new TouchScrollDelegate(contentNode); + } + return touchScrollDelegate; + + } + + public ShortcutActionHandler getShortcutActionHandler() { + return shortcutHandler; + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/passwordfield/PasswordFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/passwordfield/PasswordFieldConnector.java new file mode 100644 index 0000000000..1d1ec58fbb --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/passwordfield/PasswordFieldConnector.java @@ -0,0 +1,32 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.passwordfield; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.textfield.TextFieldConnector; +import com.vaadin.ui.PasswordField; + +@Connect(PasswordField.class) +public class PasswordFieldConnector extends TextFieldConnector { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + super.updateFromUIDL(uidl, client); + } + + @Override + protected Widget createWidget() { + return GWT.create(VPasswordField.class); + } + + @Override + public VPasswordField getWidget() { + return (VPasswordField) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java b/src/com/vaadin/terminal/gwt/client/ui/passwordfield/VPasswordField.java index 5182457067..c160322de5 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/passwordfield/VPasswordField.java @@ -2,9 +2,10 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.passwordfield; import com.google.gwt.user.client.DOM; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; /** * This class represents a password field. diff --git a/src/com/vaadin/terminal/gwt/client/ui/popupview/PopupViewConnector.java b/src/com/vaadin/terminal/gwt/client/ui/popupview/PopupViewConnector.java new file mode 100644 index 0000000000..4faa6cec86 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/popupview/PopupViewConnector.java @@ -0,0 +1,121 @@ +/* + @VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.popupview; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.VCaptionWrapper; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; +import com.vaadin.ui.PopupView; + +@Connect(PopupView.class) +public class PopupViewConnector extends AbstractComponentContainerConnector + implements Paintable, PostLayoutListener { + + private boolean centerAfterLayout = false; + + @Override + public boolean delegateCaptionHandling() { + return false; + } + + /** + * + * + * @see com.vaadin.terminal.gwt.client.ComponentConnector#updateFromUIDL(com.vaadin.terminal.gwt.client.UIDL, + * com.vaadin.terminal.gwt.client.ApplicationConnection) + */ + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + // These are for future server connections + getWidget().client = client; + getWidget().uidlId = uidl.getId(); + + getWidget().hostPopupVisible = uidl + .getBooleanVariable("popupVisibility"); + + getWidget().setHTML(uidl.getStringAttribute("html")); + + if (uidl.hasAttribute("hideOnMouseOut")) { + getWidget().popup.setHideOnMouseOut(uidl + .getBooleanAttribute("hideOnMouseOut")); + } + + // Render the popup if visible and show it. + if (getWidget().hostPopupVisible) { + UIDL popupUIDL = uidl.getChildUIDL(0); + + // showPopupOnTop(popup, hostReference); + getWidget().preparePopup(getWidget().popup); + getWidget().popup.updateFromUIDL(popupUIDL, client); + if (getState().hasStyles()) { + final StringBuffer styleBuf = new StringBuffer(); + final String primaryName = getWidget().popup + .getStylePrimaryName(); + styleBuf.append(primaryName); + for (String style : getState().getStyles()) { + styleBuf.append(" "); + styleBuf.append(primaryName); + styleBuf.append("-"); + styleBuf.append(style); + } + getWidget().popup.setStyleName(styleBuf.toString()); + } else { + getWidget().popup.setStyleName(getWidget().popup + .getStylePrimaryName()); + } + getWidget().showPopup(getWidget().popup); + centerAfterLayout = true; + + // The popup shouldn't be visible, try to hide it. + } else { + getWidget().popup.hide(); + } + }// updateFromUIDL + + public void updateCaption(ComponentConnector component) { + if (VCaption.isNeeded(component.getState())) { + if (getWidget().popup.captionWrapper != null) { + getWidget().popup.captionWrapper.updateCaption(); + } else { + getWidget().popup.captionWrapper = new VCaptionWrapper( + component, getConnection()); + getWidget().popup.setWidget(getWidget().popup.captionWrapper); + getWidget().popup.captionWrapper.updateCaption(); + } + } else { + if (getWidget().popup.captionWrapper != null) { + getWidget().popup + .setWidget(getWidget().popup.popupComponentWidget); + } + } + } + + @Override + public VPopupView getWidget() { + return (VPopupView) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VPopupView.class); + } + + public void postLayout() { + if (centerAfterLayout) { + centerAfterLayout = false; + getWidget().center(); + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java index 907e11ac2d..da48975726 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java +++ b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java @@ -1,11 +1,10 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.popupview; import java.util.HashSet; import java.util.Iterator; -import java.util.NoSuchElementException; import java.util.Set; import com.google.gwt.event.dom.client.ClickEvent; @@ -24,29 +23,25 @@ import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation.Size; -import com.vaadin.terminal.gwt.client.RenderSpace; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.UIDL; -import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.VCaption; import com.vaadin.terminal.gwt.client.VCaptionWrapper; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.VOverlay; import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea; -public class VPopupView extends HTML implements Container, Iterable<Widget> { +public class VPopupView extends HTML { public static final String CLASSNAME = "v-popupview"; /** For server-client communication */ - private String uidlId; - private ApplicationConnection client; + String uidlId; + ApplicationConnection client; /** This variable helps to communicate popup visibility to the server */ - private boolean hostPopupVisible; + boolean hostPopupVisible; - private final CustomPopup popup; + final CustomPopup popup; private final Label loading = new Label(); /** @@ -82,61 +77,6 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { } /** - * - * - * @see com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal.gwt.client.UIDL, - * com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // This call should be made first. Ensure correct implementation, - // and don't let the containing layout manage caption. - if (client.updateComponent(this, uidl, false)) { - return; - } - // These are for future server connections - this.client = client; - uidlId = uidl.getId(); - - hostPopupVisible = uidl.getBooleanVariable("popupVisibility"); - - setHTML(uidl.getStringAttribute("html")); - - if (uidl.hasAttribute("hideOnMouseOut")) { - popup.setHideOnMouseOut(uidl.getBooleanAttribute("hideOnMouseOut")); - } - - // Render the popup if visible and show it. - if (hostPopupVisible) { - UIDL popupUIDL = uidl.getChildUIDL(0); - - // showPopupOnTop(popup, hostReference); - preparePopup(popup); - popup.updateFromUIDL(popupUIDL, client); - if (uidl.hasAttribute("style")) { - final String[] styles = uidl.getStringAttribute("style").split( - " "); - final StringBuffer styleBuf = new StringBuffer(); - final String primaryName = popup.getStylePrimaryName(); - styleBuf.append(primaryName); - for (int i = 0; i < styles.length; i++) { - styleBuf.append(" "); - styleBuf.append(primaryName); - styleBuf.append("-"); - styleBuf.append(styles[i]); - } - popup.setStyleName(styleBuf.toString()); - } else { - popup.setStyleName(popup.getStylePrimaryName()); - } - showPopup(popup); - - // The popup shouldn't be visible, try to hide it. - } else { - popup.hide(); - } - }// updateFromUIDL - - /** * Update popup visibility to server * * @param visibility @@ -149,7 +89,7 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { } } - private void preparePopup(final CustomPopup popup) { + void preparePopup(final CustomPopup popup) { popup.setVisible(false); popup.show(); } @@ -166,6 +106,12 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { * @param popup */ protected void showPopup(final CustomPopup popup) { + popup.setPopupPosition(0, 0); + + popup.setVisible(true); + } + + void center() { int windowTop = RootPanel.get().getAbsoluteTop(); int windowLeft = RootPanel.get().getAbsoluteLeft(); int windowRight = windowLeft + RootPanel.get().getOffsetWidth(); @@ -200,8 +146,6 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { } popup.setPopupPosition(left, top); - - popup.setVisible(true); } /** @@ -230,9 +174,9 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { */ protected class CustomPopup extends VOverlay { - private Paintable popupComponentPaintable = null; - private Widget popupComponentWidget = null; - private VCaptionWrapper captionWrapper = null; + private ComponentConnector popupComponentPaintable = null; + Widget popupComponentWidget = null; + VCaptionWrapper captionWrapper = null; private boolean hasHadMouseOver = false; private boolean hideOnMouseOut = true; @@ -285,7 +229,6 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { public void hide(boolean autoClosed) { hiding = true; syncChildren(); - unregisterPaintables(); if (popupComponentWidget != null && popupComponentWidget != loading) { remove(popupComponentWidget); } @@ -346,26 +289,16 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - Paintable newPopupComponent = client.getPaintable(uidl + ComponentConnector newPopupComponent = client.getPaintable(uidl .getChildUIDL(0)); if (newPopupComponent != popupComponentPaintable) { - - setWidget((Widget) newPopupComponent); - - popupComponentWidget = (Widget) newPopupComponent; - + Widget newWidget = newPopupComponent.getWidget(); + setWidget(newWidget); + popupComponentWidget = newWidget; popupComponentPaintable = newPopupComponent; } - popupComponentPaintable - .updateFromUIDL(uidl.getChildUIDL(0), client); - } - - public void unregisterPaintables() { - if (popupComponentPaintable != null) { - client.unregisterPaintable(popupComponentPaintable); - } } public void setHideOnMouseOut(boolean hideOnMouseOut) { @@ -404,69 +337,6 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { }// class CustomPopup - // Container methods - - public RenderSpace getAllocatedSpace(Widget child) { - Size popupExtra = calculatePopupExtra(); - - return new RenderSpace(RootPanel.get().getOffsetWidth() - - popupExtra.getWidth(), RootPanel.get().getOffsetHeight() - - popupExtra.getHeight()); - } - - /** - * Calculate extra space taken by the popup decorations - * - * @return - */ - protected Size calculatePopupExtra() { - Element pe = popup.getElement(); - Element ipe = popup.getContainerElement(); - - // border + padding - int width = Util.getRequiredWidth(pe) - Util.getRequiredWidth(ipe); - int height = Util.getRequiredHeight(pe) - Util.getRequiredHeight(ipe); - - return new Size(width, height); - } - - public boolean hasChildComponent(Widget component) { - if (popup.popupComponentWidget != null) { - return popup.popupComponentWidget == component; - } else { - return false; - } - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - popup.setWidget(newComponent); - popup.popupComponentWidget = newComponent; - } - - public boolean requestLayout(Set<Paintable> child) { - popup.updateShadowSizeAndPosition(); - return true; - } - - public void updateCaption(Paintable component, UIDL uidl) { - if (VCaption.isNeeded(uidl)) { - if (popup.captionWrapper != null) { - popup.captionWrapper.updateCaption(uidl); - } else { - popup.captionWrapper = new VCaptionWrapper(component, client); - popup.setWidget(popup.captionWrapper); - popup.captionWrapper.updateCaption(uidl); - } - } else { - if (popup.captionWrapper != null) { - popup.setWidget(popup.popupComponentWidget); - } - } - - popup.popupComponentWidget = (Widget) component; - popup.popupComponentPaintable = component; - } - @Override public void onBrowserEvent(Event event) { super.onBrowserEvent(event); @@ -475,30 +345,4 @@ public class VPopupView extends HTML implements Container, Iterable<Widget> { } } - public Iterator<Widget> iterator() { - return new Iterator<Widget>() { - - int pos = 0; - - public boolean hasNext() { - // There is a child widget only if next() has not been called. - return (pos == 0); - } - - public Widget next() { - // Next can be called only once to return the popup. - if (pos != 0) { - throw new NoSuchElementException(); - } - pos++; - return popup; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - - }; - } - }// class VPopupView diff --git a/src/com/vaadin/terminal/gwt/client/ui/progressindicator/ProgressIndicatorConnector.java b/src/com/vaadin/terminal/gwt/client/ui/progressindicator/ProgressIndicatorConnector.java new file mode 100644 index 0000000000..09fa5fb44e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/progressindicator/ProgressIndicatorConnector.java @@ -0,0 +1,66 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.progressindicator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.ui.ProgressIndicator; + +@Connect(ProgressIndicator.class) +public class ProgressIndicatorConnector extends AbstractFieldConnector + implements Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + if (!isRealUpdate(uidl)) { + return; + } + + // Save details + getWidget().client = client; + + getWidget().indeterminate = uidl.getBooleanAttribute("indeterminate"); + + if (getWidget().indeterminate) { + String basename = VProgressIndicator.CLASSNAME + "-indeterminate"; + getWidget().addStyleName(basename); + if (!isEnabled()) { + getWidget().addStyleName(basename + "-disabled"); + } else { + getWidget().removeStyleName(basename + "-disabled"); + } + } else { + try { + final float f = Float.parseFloat(uidl + .getStringAttribute("state")); + final int size = Math.round(100 * f); + DOM.setStyleAttribute(getWidget().indicator, "width", size + + "%"); + } catch (final Exception e) { + } + } + + if (isEnabled()) { + getWidget().interval = uidl.getIntAttribute("pollinginterval"); + getWidget().poller.scheduleRepeating(getWidget().interval); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VProgressIndicator.class); + } + + @Override + public VProgressIndicator getWidget() { + return (VProgressIndicator) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java b/src/com/vaadin/terminal/gwt/client/ui/progressindicator/VProgressIndicator.java index d5eac590ad..bc64efb60a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java +++ b/src/com/vaadin/terminal/gwt/client/ui/progressindicator/VProgressIndicator.java @@ -2,27 +2,25 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.progressindicator; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; -public class VProgressIndicator extends Widget implements Paintable { +public class VProgressIndicator extends Widget { - private static final String CLASSNAME = "v-progressindicator"; + public static final String CLASSNAME = "v-progressindicator"; Element wrapper = DOM.createDiv(); Element indicator = DOM.createDiv(); - private ApplicationConnection client; - private final Poller poller; - private boolean indeterminate = false; + protected ApplicationConnection client; + protected final Poller poller; + protected boolean indeterminate = false; private boolean pollerSuspendedDueDetach; - private int interval; + protected int interval; public VProgressIndicator() { setElement(DOM.createDiv()); @@ -34,38 +32,6 @@ public class VProgressIndicator extends Widget implements Paintable { poller = new Poller(); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - if (!uidl.getBooleanAttribute("cached")) { - poller.cancel(); - } - if (client.updateComponent(this, uidl, true)) { - return; - } - - indeterminate = uidl.getBooleanAttribute("indeterminate"); - - if (indeterminate) { - String basename = CLASSNAME + "-indeterminate"; - VProgressIndicator.setStyleName(getElement(), basename, true); - VProgressIndicator.setStyleName(getElement(), basename - + "-disabled", uidl.getBooleanAttribute("disabled")); - } else { - try { - final float f = Float.parseFloat(uidl - .getStringAttribute("state")); - final int size = Math.round(100 * f); - DOM.setStyleAttribute(indicator, "width", size + "%"); - } catch (final Exception e) { - } - } - - if (!uidl.getBooleanAttribute("disabled")) { - interval = uidl.getIntAttribute("pollinginterval"); - poller.scheduleRepeating(interval); - } - } - @Override protected void onAttach() { super.onAttach(); @@ -102,5 +68,4 @@ public class VProgressIndicator extends Widget implements Paintable { } } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/RichTextAreaConnector.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/RichTextAreaConnector.java new file mode 100644 index 0000000000..01e79bc1c3 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/RichTextAreaConnector.java @@ -0,0 +1,78 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.richtextarea; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; +import com.vaadin.ui.RichTextArea; + +@Connect(value = RichTextArea.class, loadStyle = LoadStyle.LAZY) +public class RichTextAreaConnector extends AbstractFieldConnector implements + Paintable, BeforeShortcutActionListener { + + public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) { + getWidget().client = client; + getWidget().id = uidl.getId(); + + if (uidl.hasVariable("text")) { + getWidget().currentValue = uidl.getStringVariable("text"); + if (getWidget().rta.isAttached()) { + getWidget().rta.setHTML(getWidget().currentValue); + } else { + getWidget().html.setHTML(getWidget().currentValue); + } + } + if (isRealUpdate(uidl)) { + getWidget().setEnabled(isEnabled()); + } + + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().setReadOnly(isReadOnly()); + getWidget().immediate = getState().isImmediate(); + int newMaxLength = uidl.hasAttribute("maxLength") ? uidl + .getIntAttribute("maxLength") : -1; + if (newMaxLength >= 0) { + if (getWidget().maxLength == -1) { + getWidget().keyPressHandler = getWidget().rta + .addKeyPressHandler(getWidget()); + } + getWidget().maxLength = newMaxLength; + } else if (getWidget().maxLength != -1) { + getWidget().getElement().setAttribute("maxlength", ""); + getWidget().maxLength = -1; + getWidget().keyPressHandler.removeHandler(); + } + + if (uidl.hasAttribute("selectAll")) { + getWidget().selectAll(); + } + + } + + public void onBeforeShortcutAction(Event e) { + getWidget().synchronizeContentToServer(); + } + + @Override + public VRichTextArea getWidget() { + return (VRichTextArea) super.getWidget(); + }; + + @Override + protected Widget createWidget() { + return GWT.create(VRichTextArea.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java index bf0a423474..eb062a3799 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java +++ b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java @@ -17,7 +17,6 @@ import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; 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.Timer; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; @@ -27,12 +26,10 @@ import com.google.gwt.user.client.ui.RichTextArea; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.ui.Field; import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; -import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; /** @@ -41,9 +38,8 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHan * @author Vaadin Ltd. * */ -public class VRichTextArea extends Composite implements Paintable, Field, - ChangeHandler, BlurHandler, KeyPressHandler, KeyDownHandler, - BeforeShortcutActionListener, Focusable { +public class VRichTextArea extends Composite implements Field, ChangeHandler, + BlurHandler, KeyPressHandler, KeyDownHandler, Focusable { /** * The input node CSS classname. @@ -54,13 +50,13 @@ public class VRichTextArea extends Composite implements Paintable, Field, protected ApplicationConnection client; - private boolean immediate = false; + boolean immediate = false; - private RichTextArea rta; + RichTextArea rta; private VRichTextToolbar formatter; - private HTML html = new HTML(); + HTML html = new HTML(); private final FlowPanel fp = new FlowPanel(); @@ -69,15 +65,15 @@ public class VRichTextArea extends Composite implements Paintable, Field, private int extraHorizontalPixels = -1; private int extraVerticalPixels = -1; - private int maxLength = -1; + int maxLength = -1; private int toolbarNaturalWidth = 500; - private HandlerRegistration keyPressHandler; + HandlerRegistration keyPressHandler; private ShortcutActionHandlerOwner hasShortcutActionHandler; - private String currentValue = ""; + String currentValue = ""; private boolean readOnly = false; @@ -127,48 +123,7 @@ public class VRichTextArea extends Composite implements Paintable, Field, } } - public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) { - this.client = client; - id = uidl.getId(); - - if (uidl.hasVariable("text")) { - currentValue = uidl.getStringVariable("text"); - if (rta.isAttached()) { - rta.setHTML(currentValue); - } else { - html.setHTML(currentValue); - } - } - if (!uidl.hasAttribute("cached")) { - setEnabled(!uidl.getBooleanAttribute("disabled")); - } - - if (client.updateComponent(this, uidl, true)) { - return; - } - - setReadOnly(uidl.getBooleanAttribute("readonly")); - immediate = uidl.getBooleanAttribute("immediate"); - int newMaxLength = uidl.hasAttribute("maxLength") ? uidl - .getIntAttribute("maxLength") : -1; - if (newMaxLength >= 0) { - if (maxLength == -1) { - keyPressHandler = rta.addKeyPressHandler(this); - } - maxLength = newMaxLength; - } else if (maxLength != -1) { - getElement().setAttribute("maxlength", ""); - maxLength = -1; - keyPressHandler.removeHandler(); - } - - if (uidl.hasAttribute("selectAll")) { - selectAll(); - } - - } - - private void selectAll() { + void selectAll() { /* * There is a timing issue if trying to select all immediately on first * render. Simple deferred command is not enough. Using Timer with @@ -190,7 +145,7 @@ public class VRichTextArea extends Composite implements Paintable, Field, }.schedule(320); } - private void setReadOnly(boolean b) { + void setReadOnly(boolean b) { if (isReadOnly() != b) { swapEditableArea(); readOnly = b; @@ -346,7 +301,8 @@ public class VRichTextArea extends Composite implements Paintable, Field, if (shortcutHandler != null) { shortcutHandler .handleKeyboardEvent(com.google.gwt.user.client.Event - .as(event.getNativeEvent()), this); + .as(event.getNativeEvent()), + ConnectorMap.get(client).getConnector(this)); } } @@ -364,10 +320,6 @@ public class VRichTextArea extends Composite implements Paintable, Field, return hasShortcutActionHandler; } - public void onBeforeShortcutAction(Event e) { - synchronizeContentToServer(); - } - public int getTabIndex() { return rta.getTabIndex(); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java new file mode 100644 index 0000000000..46f82d60b7 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java @@ -0,0 +1,423 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.root; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.History; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.web.bindery.event.shared.HandlerRegistration; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VConsole; +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.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; +import com.vaadin.terminal.gwt.client.ui.notification.VNotification; +import com.vaadin.terminal.gwt.client.ui.window.WindowConnector; +import com.vaadin.ui.Root; + +@Connect(value = Root.class, loadStyle = LoadStyle.EAGER) +public class RootConnector extends AbstractComponentContainerConnector + implements Paintable, MayScrollChildren { + + private RootServerRpc rpc = RpcProxy.create(RootServerRpc.class, this); + + private HandlerRegistration childStateChangeHandlerRegistration; + + private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() { + public void onStateChanged(StateChangeEvent stateChangeEvent) { + // TODO Should use a more specific handler that only reacts to + // size changes + onChildSizeChange(); + } + }; + + @Override + protected void init() { + super.init(); + } + + public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) { + ConnectorMap paintableMap = ConnectorMap.get(getConnection()); + getWidget().rendering = true; + getWidget().id = getConnectorId(); + boolean firstPaint = getWidget().connection == null; + getWidget().connection = client; + + getWidget().immediate = getState().isImmediate(); + getWidget().resizeLazy = uidl.hasAttribute(VRoot.RESIZE_LAZY); + String newTheme = uidl.getStringAttribute("theme"); + if (getWidget().theme != null && !newTheme.equals(getWidget().theme)) { + // Complete page refresh is needed due css can affect layout + // calculations etc + getWidget().reloadHostPage(); + } else { + getWidget().theme = newTheme; + } + // this also implicitly removes old styles + String styles = ""; + styles += getWidget().getStylePrimaryName() + " "; + if (getState().hasStyles()) { + for (String style : getState().getStyles()) { + styles += style + " "; + } + } + if (!client.getConfiguration().isStandalone()) { + styles += getWidget().getStylePrimaryName() + "-embedded"; + } + getWidget().setStyleName(styles.trim()); + + clickEventHandler.handleEventHandlerRegistration(); + + if (!getWidget().isEmbedded() && getState().getCaption() != null) { + // only change window title if we're in charge of the whole page + com.google.gwt.user.client.Window.setTitle(getState().getCaption()); + } + + // Process children + int childIndex = 0; + + // Open URL:s + boolean isClosed = false; // was this window closed? + while (childIndex < uidl.getChildCount() + && "open".equals(uidl.getChildUIDL(childIndex).getTag())) { + final UIDL open = uidl.getChildUIDL(childIndex); + final String url = client.translateVaadinUri(open + .getStringAttribute("src")); + final String target = open.getStringAttribute("name"); + if (target == null) { + // source will be opened to this browser window, but we may have + // to finish rendering this window in case this is a download + // (and window stays open). + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + VRoot.goTo(url); + } + }); + } else if ("_self".equals(target)) { + // This window is closing (for sure). Only other opens are + // relevant in this change. See #3558, #2144 + isClosed = true; + VRoot.goTo(url); + } else { + String options; + if (open.hasAttribute("border")) { + if (open.getStringAttribute("border").equals("minimal")) { + options = "menubar=yes,location=no,status=no"; + } else { + options = "menubar=no,location=no,status=no"; + } + + } else { + options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes"; + } + + if (open.hasAttribute("width")) { + int w = open.getIntAttribute("width"); + options += ",width=" + w; + } + if (open.hasAttribute("height")) { + int h = open.getIntAttribute("height"); + options += ",height=" + h; + } + + Window.open(url, target, options); + } + childIndex++; + } + if (isClosed) { + // don't render the content, something else will be opened to this + // browser view + getWidget().rendering = false; + return; + } + + // Handle other UIDL children + UIDL childUidl; + while ((childUidl = uidl.getChildUIDL(childIndex++)) != null) { + String tag = childUidl.getTag().intern(); + if (tag == "actions") { + if (getWidget().actionHandler == null) { + getWidget().actionHandler = new ShortcutActionHandler( + getWidget().id, client); + } + getWidget().actionHandler.updateActionMap(childUidl); + } else if (tag == "execJS") { + String script = childUidl.getStringAttribute("script"); + VRoot.eval(script); + } else if (tag == "notifications") { + for (final Iterator<?> it = childUidl.getChildIterator(); it + .hasNext();) { + final UIDL notification = (UIDL) it.next(); + VNotification.showNotification(client, notification); + } + } + } + + if (uidl.hasAttribute("focused")) { + // set focused component when render phase is finished + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + ComponentConnector paintable = (ComponentConnector) uidl + .getPaintableAttribute("focused", getConnection()); + + final Widget toBeFocused = paintable.getWidget(); + /* + * Two types of Widgets can be focused, either implementing + * GWT HasFocus of a thinner Vaadin specific Focusable + * interface. + */ + if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) { + final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused; + toBeFocusedWidget.setFocus(true); + } else if (toBeFocused instanceof Focusable) { + ((Focusable) toBeFocused).focus(); + } else { + VConsole.log("Could not focus component"); + } + } + }); + } + + // Add window listeners on first paint, to prevent premature + // variablechanges + if (firstPaint) { + Window.addWindowClosingHandler(getWidget()); + Window.addResizeHandler(getWidget()); + } + + // finally set scroll position from UIDL + if (uidl.hasVariable("scrollTop")) { + getWidget().scrollable = true; + getWidget().scrollTop = uidl.getIntVariable("scrollTop"); + DOM.setElementPropertyInt(getWidget().getElement(), "scrollTop", + getWidget().scrollTop); + getWidget().scrollLeft = uidl.getIntVariable("scrollLeft"); + DOM.setElementPropertyInt(getWidget().getElement(), "scrollLeft", + getWidget().scrollLeft); + } else { + getWidget().scrollable = false; + } + + if (uidl.hasAttribute("scrollTo")) { + final ComponentConnector connector = (ComponentConnector) uidl + .getPaintableAttribute("scrollTo", getConnection()); + scrollIntoView(connector); + } + + if (uidl.hasAttribute(VRoot.FRAGMENT_VARIABLE)) { + getWidget().currentFragment = uidl + .getStringAttribute(VRoot.FRAGMENT_VARIABLE); + if (!getWidget().currentFragment.equals(History.getToken())) { + History.newItem(getWidget().currentFragment, true); + } + } else { + // Initial request for which the server doesn't yet have a fragment + // (and haven't shown any interest in getting one) + getWidget().currentFragment = History.getToken(); + + // Include current fragment in the next request + client.updateVariable(getWidget().id, VRoot.FRAGMENT_VARIABLE, + getWidget().currentFragment, false); + } + + getWidget().rendering = false; + } + + public void init(String rootPanelId, + ApplicationConnection applicationConnection) { + DOM.sinkEvents(getWidget().getElement(), Event.ONKEYDOWN + | Event.ONSCROLL); + + // iview is focused when created so element needs tabIndex + // 1 due 0 is at the end of natural tabbing order + DOM.setElementProperty(getWidget().getElement(), "tabIndex", "1"); + + RootPanel root = RootPanel.get(rootPanelId); + + // Remove the v-app-loading or any splash screen added inside the div by + // the user + root.getElement().setInnerHTML(""); + + root.addStyleName("v-theme-" + + applicationConnection.getConfiguration().getThemeName()); + + root.add(getWidget()); + + if (applicationConnection.getConfiguration().isStandalone()) { + // set focus to iview element by default to listen possible keyboard + // shortcuts. For embedded applications this is unacceptable as we + // don't want to steal focus from the main page nor we don't want + // side-effects from focusing (scrollIntoView). + getWidget().getElement().focus(); + } + } + + private ClickEventHandler clickEventHandler = new ClickEventHandler(this) { + + @Override + protected void fireClick(NativeEvent event, + MouseEventDetails mouseDetails) { + rpc.click(mouseDetails); + } + + }; + + public void updateCaption(ComponentConnector component) { + // NOP The main view never draws caption for its layout + } + + @Override + public VRoot getWidget() { + return (VRoot) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VRoot.class); + } + + protected ComponentConnector getContent() { + return (ComponentConnector) getState().getContent(); + } + + protected void onChildSizeChange() { + ComponentConnector child = getContent(); + Style childStyle = child.getWidget().getElement().getStyle(); + /* + * Must set absolute position if the child has relative height and + * there's a chance of horizontal scrolling as some browsers will + * otherwise not take the scrollbar into account when calculating the + * height. Assuming v-view does not have an undefined width for now, see + * #8460. + */ + if (child.isRelativeHeight() && !BrowserInfo.get().isIE9()) { + childStyle.setPosition(Position.ABSOLUTE); + } else { + childStyle.clearPosition(); + } + } + + /** + * Checks if the given sub window is a child of this Root Connector + * + * @deprecated Should be replaced by a more generic mechanism for getting + * non-ComponentConnector children + * @param wc + * @return + */ + @Deprecated + public boolean hasSubWindow(WindowConnector wc) { + return getChildren().contains(wc); + } + + /** + * Return an iterator for current subwindows. This method is meant for + * testing purposes only. + * + * @return + */ + public List<WindowConnector> getSubWindows() { + ArrayList<WindowConnector> windows = new ArrayList<WindowConnector>(); + for (ComponentConnector child : getChildren()) { + if (child instanceof WindowConnector) { + windows.add((WindowConnector) child); + } + } + return windows; + } + + @Override + public RootState getState() { + return (RootState) super.getState(); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + ComponentConnector oldChild = null; + ComponentConnector newChild = getContent(); + + for (ComponentConnector c : event.getOldChildren()) { + if (!(c instanceof WindowConnector)) { + oldChild = c; + break; + } + } + + if (oldChild != newChild) { + if (childStateChangeHandlerRegistration != null) { + childStateChangeHandlerRegistration.removeHandler(); + childStateChangeHandlerRegistration = null; + } + getWidget().setWidget(newChild.getWidget()); + childStateChangeHandlerRegistration = newChild + .addStateChangeHandler(childStateChangeHandler); + // Must handle new child here as state change events are already + // fired + onChildSizeChange(); + } + + for (ComponentConnector c : getChildren()) { + if (c instanceof WindowConnector) { + WindowConnector wc = (WindowConnector) c; + wc.setWindowOrderAndPosition(); + } + } + + // Close removed sub windows + for (ComponentConnector c : event.getOldChildren()) { + if (c.getParent() != this && c instanceof WindowConnector) { + ((WindowConnector) c).getWidget().hide(); + } + } + } + + /** + * Tries to scroll the viewport so that the given connector is in view. + * + * @param componentConnector + * The connector which should be visible + * + */ + public void scrollIntoView(final ComponentConnector componentConnector) { + if (componentConnector == null) { + return; + } + + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + componentConnector.getWidget().getElement().scrollIntoView(); + } + }); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRpc.java new file mode 100644 index 0000000000..389500949d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootServerRpc.java @@ -0,0 +1,11 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.root; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.ClickRpc; + +public interface RootServerRpc extends ClickRpc, ServerRpc { + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootState.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootState.java new file mode 100644 index 0000000000..85d5e45022 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootState.java @@ -0,0 +1,20 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.root; + +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.Connector; + +public class RootState extends ComponentState { + private Connector content; + + public Connector getContent() { + return content; + } + + public void setContent(Connector content) { + this.content = content; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java new file mode 100644 index 0000000000..13fc55d7ea --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java @@ -0,0 +1,321 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.root; + +import java.util.ArrayList; + +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.event.logical.shared.ResizeEvent; +import com.google.gwt.event.logical.shared.ResizeHandler; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.History; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.SimplePanel; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.Focusable; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; + +/** + * + */ +public class VRoot extends SimplePanel implements ResizeHandler, + Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable { + + public static final String FRAGMENT_VARIABLE = "fragment"; + + private static final String CLASSNAME = "v-view"; + + public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain"; + + String theme; + + String id; + + ShortcutActionHandler actionHandler; + + /** stored width for IE resize optimization */ + private int width; + + /** stored height for IE resize optimization */ + private int height; + + ApplicationConnection connection; + + /** Identifies the click event */ + public static final String CLICK_EVENT_ID = "click"; + + /** + * We are postponing resize process with IE. IE bugs with scrollbars in some + * situations, that causes false onWindowResized calls. With Timer we will + * give IE some time to decide if it really wants to keep current size + * (scrollbars). + */ + private Timer resizeTimer; + + int scrollTop; + + int scrollLeft; + + boolean rendering; + + boolean scrollable; + + boolean immediate; + + boolean resizeLazy = false; + + /** + * Attribute name for the lazy resize setting . + */ + public static final String RESIZE_LAZY = "rL"; + + private HandlerRegistration historyHandlerRegistration; + + /** + * The current URI fragment, used to avoid sending updates if nothing has + * changed. + */ + String currentFragment; + + /** + * Listener for URI fragment changes. Notifies the server of the new value + * whenever the value changes. + */ + private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() { + public void onValueChange(ValueChangeEvent<String> event) { + String newFragment = event.getValue(); + + // Send the new fragment to the server if it has changed + if (!newFragment.equals(currentFragment) && connection != null) { + currentFragment = newFragment; + connection.updateVariable(id, FRAGMENT_VARIABLE, newFragment, + true); + } + } + }; + + private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200, + new ScheduledCommand() { + public void execute() { + windowSizeMaybeChanged(Window.getClientWidth(), + Window.getClientHeight()); + } + + }); + + public VRoot() { + super(); + setStyleName(CLASSNAME); + + // Allow focusing the view by using the focus() method, the view + // should not be in the document focus flow + getElement().setTabIndex(-1); + } + + @Override + protected void onAttach() { + super.onAttach(); + historyHandlerRegistration = History + .addValueChangeHandler(historyChangeHandler); + currentFragment = History.getToken(); + } + + @Override + protected void onDetach() { + super.onDetach(); + historyHandlerRegistration.removeHandler(); + historyHandlerRegistration = null; + } + + /** + * Called when the window might have been resized. + * + * @param newWidth + * The new width of the window + * @param newHeight + * The new height of the window + */ + protected void windowSizeMaybeChanged(int newWidth, int newHeight) { + boolean changed = false; + ComponentConnector connector = ConnectorMap.get(connection) + .getConnector(this); + if (width != newWidth) { + width = newWidth; + changed = true; + connector.getLayoutManager().reportOuterWidth(connector, newWidth); + VConsole.log("New window width: " + width); + } + if (height != newHeight) { + height = newHeight; + changed = true; + connector.getLayoutManager() + .reportOuterHeight(connector, newHeight); + VConsole.log("New window height: " + height); + } + if (changed) { + VConsole.log("Running layout functions due to window resize"); + + sendClientResized(); + + connector.getLayoutManager().layoutNow(); + } + } + + public String getTheme() { + return theme; + } + + /** + * Used to reload host page on theme changes. + */ + static native void reloadHostPage() + /*-{ + $wnd.location.reload(); + }-*/; + + /** + * Evaluate the given script in the browser document. + * + * @param script + * Script to be executed. + */ + static native void eval(String script) + /*-{ + try { + if (script == null) return; + $wnd.eval(script); + } catch (e) { + } + }-*/; + + /** + * Returns true if the body is NOT generated, i.e if someone else has made + * the page that we're running in. Otherwise we're in charge of the whole + * page. + * + * @return true if we're running embedded + */ + public boolean isEmbedded() { + return !getElement().getOwnerDocument().getBody().getClassName() + .contains(ApplicationConnection.GENERATED_BODY_CLASSNAME); + } + + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + int type = DOM.eventGetType(event); + if (type == Event.ONKEYDOWN && actionHandler != null) { + actionHandler.handleKeyboardEvent(event); + return; + } else if (scrollable && type == Event.ONSCROLL) { + updateScrollPosition(); + } + } + + /** + * Updates scroll position from DOM and saves variables to server. + */ + private void updateScrollPosition() { + int oldTop = scrollTop; + int oldLeft = scrollLeft; + scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop"); + scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft"); + if (connection != null && !rendering) { + if (oldTop != scrollTop) { + connection.updateVariable(id, "scrollTop", scrollTop, false); + } + if (oldLeft != scrollLeft) { + connection.updateVariable(id, "scrollLeft", scrollLeft, false); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google + * .gwt.event.logical.shared.ResizeEvent) + */ + public void onResize(ResizeEvent event) { + onResize(); + } + + /** + * Called when a resize event is received. + */ + void onResize() { + /* + * IE (pre IE9 at least) will give us some false resize events due to + * problems with scrollbars. Firefox 3 might also produce some extra + * events. We postpone both the re-layouting and the server side event + * for a while to deal with these issues. + * + * We may also postpone these events to avoid slowness when resizing the + * browser window. Constantly recalculating the layout causes the resize + * operation to be really slow with complex layouts. + */ + boolean lazy = resizeLazy || BrowserInfo.get().isIE8(); + + if (lazy) { + delayedResizeExecutor.trigger(); + } else { + windowSizeMaybeChanged(Window.getClientWidth(), + Window.getClientHeight()); + } + } + + /** + * Send new dimensions to the server. + */ + private void sendClientResized() { + connection.updateVariable(id, "height", height, false); + connection.updateVariable(id, "width", width, immediate); + } + + public native static void goTo(String url) + /*-{ + $wnd.location = url; + }-*/; + + public void onWindowClosing(Window.ClosingEvent event) { + // Change focus on this window in order to ensure that all state is + // collected from textfields + // TODO this is a naive hack, that only works with text fields and may + // cause some odd issues. Should be replaced with a decent solution, see + // also related BeforeShortcutActionListener interface. Same interface + // might be usable here. + VTextField.flushChangesFromFocusedTextField(); + } + + private native static void loadAppIdListFromDOM(ArrayList<String> list) + /*-{ + var j; + for(j in $wnd.vaadin.vaadinConfigurations) { + list.@java.util.Collection::add(Ljava/lang/Object;)(j); + } + }-*/; + + public ShortcutActionHandler getShortcutActionHandler() { + return actionHandler; + } + + public void focus() { + getElement().focus(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/slider/SliderConnector.java b/src/com/vaadin/terminal/gwt/client/ui/slider/SliderConnector.java new file mode 100644 index 0000000000..9cd3c35fee --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/slider/SliderConnector.java @@ -0,0 +1,77 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.slider; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.ui.Slider; + +@Connect(Slider.class) +public class SliderConnector extends AbstractFieldConnector implements + Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + getWidget().client = client; + getWidget().id = uidl.getId(); + + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().immediate = getState().isImmediate(); + getWidget().disabled = !isEnabled(); + getWidget().readonly = isReadOnly(); + + getWidget().vertical = uidl.hasAttribute("vertical"); + + // TODO should style names be used? + + if (getWidget().vertical) { + getWidget().addStyleName(VSlider.CLASSNAME + "-vertical"); + } else { + getWidget().removeStyleName(VSlider.CLASSNAME + "-vertical"); + } + + getWidget().min = uidl.getDoubleAttribute("min"); + getWidget().max = uidl.getDoubleAttribute("max"); + getWidget().resolution = uidl.getIntAttribute("resolution"); + getWidget().value = new Double(uidl.getDoubleVariable("value")); + + getWidget().setFeedbackValue(getWidget().value); + + getWidget().buildBase(); + + if (!getWidget().vertical) { + // Draw handle with a delay to allow base to gain maximum width + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + getWidget().buildHandle(); + getWidget().setValue(getWidget().value, false); + } + }); + } else { + getWidget().buildHandle(); + getWidget().setValue(getWidget().value, false); + } + } + + @Override + public VSlider getWidget() { + return (VSlider) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VSlider.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java index 4a46346613..9ff614252d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java +++ b/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ // -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.slider; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; @@ -16,12 +16,14 @@ import com.google.gwt.user.client.ui.HTML; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.Field; +import com.vaadin.terminal.gwt.client.ui.SimpleFocusablePanel; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; +import com.vaadin.terminal.gwt.client.ui.VOverlay; -public class VSlider extends SimpleFocusablePanel implements Paintable, Field, +public class VSlider extends SimpleFocusablePanel implements Field, ContainerResizedListener { public static final String CLASSNAME = "v-slider"; @@ -36,19 +38,16 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, String id; - private boolean immediate; - private boolean disabled; - private boolean readonly; - private boolean scrollbarStyle; + boolean immediate; + boolean disabled; + boolean readonly; private int acceleration = 1; - private int handleSize; - private double min; - private double max; - private int resolution; - private Double value; - private boolean vertical; - private boolean arrows; + double min; + double max; + int resolution; + Double value; + boolean vertical; private final HTML feedback = new HTML("", false); private final VOverlay feedbackPopup = new VOverlay(true, false, true) { @@ -115,67 +114,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, feedbackPopup.setWidget(feedback); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - this.client = client; - id = uidl.getId(); - - // Ensure correct implementation - if (client.updateComponent(this, uidl, true)) { - return; - } - - immediate = uidl.getBooleanAttribute("immediate"); - disabled = uidl.getBooleanAttribute("disabled"); - readonly = uidl.getBooleanAttribute("readonly"); - - vertical = uidl.hasAttribute("vertical"); - arrows = uidl.hasAttribute("arrows"); - - String style = ""; - if (uidl.hasAttribute("style")) { - style = uidl.getStringAttribute("style"); - } - - scrollbarStyle = style.indexOf("scrollbar") > -1; - - if (arrows) { - DOM.setStyleAttribute(smaller, "display", "block"); - DOM.setStyleAttribute(bigger, "display", "block"); - } - - if (vertical) { - addStyleName(CLASSNAME + "-vertical"); - } else { - removeStyleName(CLASSNAME + "-vertical"); - } - - min = uidl.getDoubleAttribute("min"); - max = uidl.getDoubleAttribute("max"); - resolution = uidl.getIntAttribute("resolution"); - value = new Double(uidl.getDoubleVariable("value")); - - setFeedbackValue(value); - - handleSize = uidl.getIntAttribute("hsize"); - - buildBase(); - - if (!vertical) { - // Draw handle with a delay to allow base to gain maximum width - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - buildHandle(); - setValue(value, false); - } - }); - } else { - buildHandle(); - setValue(value, false); - } - } - - private void setFeedbackValue(double value) { + void setFeedbackValue(double value) { String currentValue = "" + value; if (resolution == 0) { currentValue = "" + new Double(value).intValue(); @@ -198,7 +137,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, } } - private void buildBase() { + void buildBase() { final String styleAttribute = vertical ? "height" : "width"; final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; @@ -232,37 +171,17 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, // TODO attach listeners for focusing and arrow keys } - private void buildHandle() { - final String styleAttribute = vertical ? "height" : "width"; + void buildHandle() { final String handleAttribute = vertical ? "marginTop" : "marginLeft"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; DOM.setStyleAttribute(handle, handleAttribute, "0"); - if (scrollbarStyle) { - // Only stretch the handle if scrollbar style is set. - int s = (int) (Double.parseDouble(DOM.getElementProperty(base, - domProperty)) / 100 * handleSize); - if (handleSize == -1) { - final int baseS = Integer.parseInt(DOM.getElementProperty(base, - domProperty)); - final double range = (max - min) * (resolution + 1) * 3; - s = (int) (baseS - range); - } - if (s < 3) { - s = 3; - } - DOM.setStyleAttribute(handle, styleAttribute, s + "px"); - } else { - DOM.setStyleAttribute(handle, styleAttribute, ""); - } - // Restore visibility DOM.setStyleAttribute(handle, "visibility", "visible"); } - private void setValue(Double value, boolean updateToServer) { + void setValue(Double value, boolean updateToServer) { if (value == null) { return; } @@ -300,9 +219,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, p = 0; } if (vertical) { - // IE6 rounding behaves a little unstable, reduce one pixel so the - // containing element (base) won't expand without limits - p = range - p - (BrowserInfo.get().isIE6() ? 1 : 0); + p = range - p; } final double pos = p; @@ -356,7 +273,7 @@ public class VSlider extends SimpleFocusablePanel implements Paintable, Field, } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { feedbackPopup.show(); } - if(Util.isTouchEvent(event)) { + if (Util.isTouchEvent(event)) { event.preventDefault(); // avoid simulated events event.stopPropagation(); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java new file mode 100644 index 0000000000..b3921204dc --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java @@ -0,0 +1,206 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +import java.util.LinkedList; +import java.util.List; + +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.dom.client.DomEvent.Type; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState.SplitterState; +import com.vaadin.terminal.gwt.client.ui.splitpanel.VAbstractSplitPanel.SplitterMoveHandler; +import com.vaadin.terminal.gwt.client.ui.splitpanel.VAbstractSplitPanel.SplitterMoveHandler.SplitterMoveEvent; + +public abstract class AbstractSplitPanelConnector extends + AbstractComponentContainerConnector implements SimpleManagedLayout { + + private AbstractSplitPanelRpc rpc; + + @Override + protected void init() { + super.init(); + rpc = RpcProxy.create(AbstractSplitPanelRpc.class, this); + // TODO Remove + getWidget().client = getConnection(); + + getWidget().addHandler(new SplitterMoveHandler() { + + public void splitterMoved(SplitterMoveEvent event) { + String position = getWidget().getSplitterPosition(); + float pos = 0; + if (position.indexOf("%") > 0) { + // Send % values as a fraction to avoid that the splitter + // "jumps" when server responds with the integer pct value + // (e.g. dragged 16.6% -> should not jump to 17%) + pos = Float.valueOf(position.substring(0, + position.length() - 1)); + } else { + pos = Integer.parseInt(position.substring(0, + position.length() - 2)); + } + + rpc.setSplitterPosition(pos); + } + + }, SplitterMoveEvent.TYPE); + } + + public void updateCaption(ComponentConnector component) { + // TODO Implement caption handling + } + + ClickEventHandler clickEventHandler = new ClickEventHandler(this) { + + @Override + protected <H extends EventHandler> HandlerRegistration registerHandler( + H handler, Type<H> type) { + if ((Event.getEventsSunk(getWidget().splitter) & Event + .getTypeInt(type.getName())) != 0) { + // If we are already sinking the event for the splitter we do + // not want to additionally sink it for the root element + return getWidget().addHandler(handler, type); + } else { + return getWidget().addDomHandler(handler, type); + } + } + + @Override + protected boolean shouldFireEvent(DomEvent<?> event) { + Element target = event.getNativeEvent().getEventTarget().cast(); + if (!getWidget().splitter.isOrHasChild(target)) { + return false; + } + + return super.shouldFireEvent(event); + }; + + @Override + protected Element getRelativeToElement() { + return getWidget().splitter; + }; + + @Override + protected void fireClick(NativeEvent event, + MouseEventDetails mouseDetails) { + rpc.splitterClick(mouseDetails); + } + + }; + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + getWidget().immediate = getState().isImmediate(); + + getWidget().setEnabled(isEnabled()); + + clickEventHandler.handleEventHandlerRegistration(); + + if (getState().hasStyles()) { + getWidget().componentStyleNames = getState().getStyles(); + } else { + getWidget().componentStyleNames = new LinkedList<String>(); + } + + // Splitter updates + SplitterState splitterState = getState().getSplitterState(); + + getWidget().setLocked(splitterState.isLocked()); + getWidget().setPositionReversed(splitterState.isPositionReversed()); + + getWidget().setStylenames(); + + getWidget().position = splitterState.getPosition() + + splitterState.getPositionUnit(); + + // This is needed at least for cases like #3458 to take + // appearing/disappearing scrollbars into account. + getConnection().runDescendentsLayout(getWidget()); + + getLayoutManager().setNeedsLayout(this); + + } + + public void layout() { + VAbstractSplitPanel splitPanel = getWidget(); + splitPanel.setSplitPosition(splitPanel.position); + splitPanel.updateSizes(); + // Report relative sizes in other direction for quicker propagation + List<ComponentConnector> children = getChildren(); + for (ComponentConnector child : children) { + reportOtherDimension(child); + } + } + + private void reportOtherDimension(ComponentConnector child) { + LayoutManager layoutManager = getLayoutManager(); + if (this instanceof HorizontalSplitPanelConnector) { + if (child.isRelativeHeight()) { + int height = layoutManager.getInnerHeight(getWidget() + .getElement()); + layoutManager.reportHeightAssignedToRelative(child, height); + } + } else { + if (child.isRelativeWidth()) { + int width = layoutManager.getInnerWidth(getWidget() + .getElement()); + layoutManager.reportWidthAssignedToRelative(child, width); + } + } + } + + @Override + public VAbstractSplitPanel getWidget() { + return (VAbstractSplitPanel) super.getWidget(); + } + + @Override + protected abstract VAbstractSplitPanel createWidget(); + + @Override + public AbstractSplitPanelState getState() { + return (AbstractSplitPanelState) super.getState(); + } + + private ComponentConnector getFirstChild() { + return (ComponentConnector) getState().getFirstChild(); + } + + private ComponentConnector getSecondChild() { + return (ComponentConnector) getState().getSecondChild(); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + Widget newFirstChildWidget = null; + if (getFirstChild() != null) { + newFirstChildWidget = getFirstChild().getWidget(); + } + getWidget().setFirstWidget(newFirstChildWidget); + + Widget newSecondChildWidget = null; + if (getSecondChild() != null) { + newSecondChildWidget = getSecondChild().getWidget(); + } + getWidget().setSecondWidget(newSecondChildWidget); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRpc.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRpc.java new file mode 100644 index 0000000000..cc043838ff --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelRpc.java @@ -0,0 +1,28 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public interface AbstractSplitPanelRpc extends ServerRpc { + + /** + * Called when the position has been updated by the user. + * + * @param position + * The new position in % if the current unit is %, in px + * otherwise + */ + public void setSplitterPosition(float position); + + /** + * Called when a click event has occurred on the splitter. + * + * @param mouseDetails + * Details about the mouse when the event took place + */ + public void splitterClick(MouseEventDetails mouseDetails); + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java new file mode 100644 index 0000000000..8b80eed840 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java @@ -0,0 +1,88 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +import java.io.Serializable; + +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.Connector; + +public class AbstractSplitPanelState extends ComponentState { + + private Connector firstChild = null; + private Connector secondChild = null; + private SplitterState splitterState = new SplitterState(); + + public boolean hasFirstChild() { + return firstChild != null; + } + + public boolean hasSecondChild() { + return secondChild != null; + } + + public Connector getFirstChild() { + return firstChild; + } + + public void setFirstChild(Connector firstChild) { + this.firstChild = firstChild; + } + + public Connector getSecondChild() { + return secondChild; + } + + public void setSecondChild(Connector secondChild) { + this.secondChild = secondChild; + } + + public SplitterState getSplitterState() { + return splitterState; + } + + public void setSplitterState(SplitterState splitterState) { + this.splitterState = splitterState; + } + + public static class SplitterState implements Serializable { + private float position; + private String positionUnit; + private boolean positionReversed = false; + private boolean locked = false; + + public float getPosition() { + return position; + } + + public void setPosition(float position) { + this.position = position; + } + + public String getPositionUnit() { + return positionUnit; + } + + public void setPositionUnit(String positionUnit) { + this.positionUnit = positionUnit; + } + + public boolean isPositionReversed() { + return positionReversed; + } + + public void setPositionReversed(boolean positionReversed) { + this.positionReversed = positionReversed; + } + + public boolean isLocked() { + return locked; + } + + public void setLocked(boolean locked) { + this.locked = locked; + } + + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/HorizontalSplitPanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/HorizontalSplitPanelConnector.java new file mode 100644 index 0000000000..7814ab8e13 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/HorizontalSplitPanelConnector.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +import com.google.gwt.core.client.GWT; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.HorizontalSplitPanel; + +@Connect(value = HorizontalSplitPanel.class, loadStyle = LoadStyle.EAGER) +public class HorizontalSplitPanelConnector extends AbstractSplitPanelConnector { + + @Override + protected VAbstractSplitPanel createWidget() { + return GWT.create(VSplitPanelHorizontal.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java index 51e378cc0c..166e79e92e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java @@ -2,14 +2,12 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.splitpanel; -import java.util.Set; +import java.util.List; -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; -import com.google.gwt.event.dom.client.DomEvent.Type; +import com.google.gwt.dom.client.Style; import com.google.gwt.event.dom.client.TouchCancelEvent; import com.google.gwt.event.dom.client.TouchCancelHandler; import com.google.gwt.event.dom.client.TouchEndEvent; @@ -19,8 +17,7 @@ import com.google.gwt.event.dom.client.TouchMoveHandler; import com.google.gwt.event.dom.client.TouchStartEvent; import com.google.gwt.event.dom.client.TouchStartHandler; import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.google.gwt.user.client.Command; +import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -28,64 +25,21 @@ import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; -import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.LayoutManager; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate; +import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.splitpanel.VAbstractSplitPanel.SplitterMoveHandler.SplitterMoveEvent; -public class VSplitPanel extends ComplexPanel implements Container, - ContainerResizedListener { +public class VAbstractSplitPanel extends ComplexPanel { private boolean enabled = false; public static final String CLASSNAME = "v-splitpanel"; - public static final String SPLITTER_CLICK_EVENT_IDENTIFIER = "sp_click"; - - private ClickEventHandler clickEventHandler = new ClickEventHandler(this, - SPLITTER_CLICK_EVENT_IDENTIFIER) { - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - if ((Event.getEventsSunk(splitter) & Event.getTypeInt(type - .getName())) != 0) { - // If we are already sinking the event for the splitter we do - // not want to additionally sink it for the root element - return addHandler(handler, type); - } else { - return addDomHandler(handler, type); - } - } - - @Override - public void onContextMenu( - com.google.gwt.event.dom.client.ContextMenuEvent event) { - Element target = event.getNativeEvent().getEventTarget().cast(); - if (splitter.isOrHasChild(target)) { - super.onContextMenu(event); - } - }; - - @Override - protected void fireClick(NativeEvent event) { - Element target = event.getEventTarget().cast(); - if (splitter.isOrHasChild(target)) { - super.fireClick(event); - } - } - - @Override - protected Element getRelativeToElement() { - return null; - } - - }; - public static final int ORIENTATION_HORIZONTAL = 0; public static final int ORIENTATION_VERTICAL = 1; @@ -94,9 +48,9 @@ public class VSplitPanel extends ComplexPanel implements Container, private int orientation = ORIENTATION_HORIZONTAL; - private Widget firstChild; + Widget firstChild; - private Widget secondChild; + Widget secondChild; private final Element wrapper = DOM.createDiv(); @@ -104,7 +58,7 @@ public class VSplitPanel extends ComplexPanel implements Container, private final Element secondContainer = DOM.createDiv(); - private final Element splitter = DOM.createDiv(); + final Element splitter = DOM.createDiv(); private boolean resizing; @@ -122,29 +76,16 @@ public class VSplitPanel extends ComplexPanel implements Container, private boolean positionReversed = false; - private String[] componentStyleNames; + List<String> componentStyleNames; private Element draggingCurtain; - private ApplicationConnection client; - - private String width = ""; - - private String height = ""; - - private RenderSpace firstRenderSpace = new RenderSpace(0, 0, true); - private RenderSpace secondRenderSpace = new RenderSpace(0, 0, true); + ApplicationConnection client; - RenderInformation renderInformation = new RenderInformation(); - - private String id; - - private boolean immediate; - - private boolean rendering = false; + boolean immediate; /* The current position of the split handle in either percentages or pixels */ - private String position; + String position; protected Element scrolledContainer; @@ -152,11 +93,11 @@ public class VSplitPanel extends ComplexPanel implements Container, private TouchScrollDelegate touchScrollDelegate; - public VSplitPanel() { + public VAbstractSplitPanel() { this(ORIENTATION_HORIZONTAL); } - public VSplitPanel(int orientation) { + public VAbstractSplitPanel(int orientation) { setElement(DOM.createDiv()); switch (orientation) { case ORIENTATION_HORIZONTAL: @@ -256,73 +197,6 @@ public class VSplitPanel extends ComplexPanel implements Container, + "-second-container"); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - id = uidl.getId(); - rendering = true; - - immediate = uidl.hasAttribute("immediate"); - - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - setEnabled(!uidl.getBooleanAttribute("disabled")); - - clickEventHandler.handleEventHandlerRegistration(client); - if (uidl.hasAttribute("style")) { - componentStyleNames = uidl.getStringAttribute("style").split(" "); - } else { - componentStyleNames = new String[0]; - } - - setLocked(uidl.getBooleanAttribute("locked")); - - setPositionReversed(uidl.getBooleanAttribute("reversed")); - - setStylenames(); - - position = uidl.getStringAttribute("position"); - setSplitPosition(position); - - final Paintable newFirstChild = client.getPaintable(uidl - .getChildUIDL(0)); - final Paintable newSecondChild = client.getPaintable(uidl - .getChildUIDL(1)); - if (firstChild != newFirstChild) { - if (firstChild != null) { - client.unregisterPaintable((Paintable) firstChild); - } - setFirstWidget((Widget) newFirstChild); - } - if (secondChild != newSecondChild) { - if (secondChild != null) { - client.unregisterPaintable((Paintable) secondChild); - } - setSecondWidget((Widget) newSecondChild); - } - newFirstChild.updateFromUIDL(uidl.getChildUIDL(0), client); - newSecondChild.updateFromUIDL(uidl.getChildUIDL(1), client); - - renderInformation.updateSize(getElement()); - - if (BrowserInfo.get().isIE7()) { - // Part III of IE7 hack - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - iLayout(); - } - }); - } - - // This is needed at least for cases like #3458 to take - // appearing/disappearing scrollbars into account. - client.runDescendentsLayout(this); - - rendering = false; - - } - @Override public boolean remove(Widget w) { boolean removed = super.remove(w); @@ -336,7 +210,7 @@ public class VSplitPanel extends ComplexPanel implements Container, return removed; } - private void setLocked(boolean newValue) { + void setLocked(boolean newValue) { if (locked != newValue) { locked = newValue; splitterSize = -1; @@ -344,7 +218,7 @@ public class VSplitPanel extends ComplexPanel implements Container, } } - private void setPositionReversed(boolean reversed) { + void setPositionReversed(boolean reversed) { if (positionReversed != reversed) { if (orientation == ORIENTATION_HORIZONTAL) { DOM.setStyleAttribute(splitter, "right", ""); @@ -358,49 +232,47 @@ public class VSplitPanel extends ComplexPanel implements Container, } } - private void setSplitPosition(String pos) { + void setSplitPosition(String pos) { if (pos == null) { return; } // Convert percentage values to pixels if (pos.indexOf("%") > 0) { - pos = Float.parseFloat(pos.substring(0, pos.length() - 1)) - / 100 - * (orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth() - : getOffsetHeight()) + "px"; + int size = orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth() + : getOffsetHeight(); + float percentage = Float.parseFloat(pos.substring(0, + pos.length() - 1)); + pos = percentage / 100 * size + "px"; } + String attributeName; if (orientation == ORIENTATION_HORIZONTAL) { if (positionReversed) { - DOM.setStyleAttribute(splitter, "right", pos); + attributeName = "right"; } else { - DOM.setStyleAttribute(splitter, "left", pos); + attributeName = "left"; } } else { if (positionReversed) { - DOM.setStyleAttribute(splitter, "bottom", pos); + attributeName = "bottom"; } else { - DOM.setStyleAttribute(splitter, "top", pos); + attributeName = "top"; } } - iLayout(); - client.runDescendentsLayout(this); + Style style = splitter.getStyle(); + if (!pos.equals(style.getProperty(attributeName))) { + style.setProperty(attributeName, pos); + updateSizes(); + } } - /* - * Calculates absolutely positioned container places/sizes (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.NeedsLayout#layout() - */ - public void iLayout() { + void updateSizes() { if (!isAttached()) { return; } - renderInformation.updateSize(getElement()); - int wholeSize; int pixelPosition; @@ -430,12 +302,28 @@ public class VSplitPanel extends ComplexPanel implements Container, DOM.setStyleAttribute(secondContainer, "left", (pixelPosition + getSplitterSize()) + "px"); - int contentHeight = renderInformation.getRenderedSize().getHeight(); - firstRenderSpace.setHeight(contentHeight); - firstRenderSpace.setWidth(pixelPosition); - secondRenderSpace.setHeight(contentHeight); - secondRenderSpace.setWidth(secondContainerWidth); - + LayoutManager layoutManager = LayoutManager.get(client); + ConnectorMap connectorMap = ConnectorMap.get(client); + if (firstChild != null) { + ComponentConnector connector = connectorMap + .getConnector(firstChild); + if (connector.isRelativeWidth()) { + layoutManager.reportWidthAssignedToRelative(connector, + pixelPosition); + } else { + layoutManager.setNeedsMeasure(connector); + } + } + if (secondChild != null) { + ComponentConnector connector = connectorMap + .getConnector(secondChild); + if (connector.isRelativeWidth()) { + layoutManager.reportWidthAssignedToRelative(connector, + secondContainerWidth); + } else { + layoutManager.setNeedsMeasure(connector); + } + } break; case ORIENTATION_VERTICAL: wholeSize = DOM.getElementPropertyInt(wrapper, "clientHeight"); @@ -463,34 +351,50 @@ public class VSplitPanel extends ComplexPanel implements Container, DOM.setStyleAttribute(secondContainer, "top", (pixelPosition + getSplitterSize()) + "px"); - int contentWidth = renderInformation.getRenderedSize().getWidth(); - firstRenderSpace.setHeight(pixelPosition); - firstRenderSpace.setWidth(contentWidth); - secondRenderSpace.setHeight(secondContainerHeight); - secondRenderSpace.setWidth(contentWidth); - + layoutManager = LayoutManager.get(client); + connectorMap = ConnectorMap.get(client); + if (firstChild != null) { + ComponentConnector connector = connectorMap + .getConnector(firstChild); + if (connector.isRelativeHeight()) { + layoutManager.reportHeightAssignedToRelative(connector, + pixelPosition); + } else { + layoutManager.setNeedsMeasure(connector); + } + } + if (secondChild != null) { + ComponentConnector connector = connectorMap + .getConnector(secondChild); + if (connector.isRelativeHeight()) { + layoutManager.reportHeightAssignedToRelative(connector, + secondContainerHeight); + } else { + layoutManager.setNeedsMeasure(connector); + } + } break; } - // fixes scrollbars issues on webkit based browsers - Util.runWebkitOverflowAutoFix(secondContainer); - Util.runWebkitOverflowAutoFix(firstContainer); - } - private void setFirstWidget(Widget w) { + void setFirstWidget(Widget w) { if (firstChild != null) { firstChild.removeFromParent(); } - super.add(w, firstContainer); + if (w != null) { + super.add(w, firstContainer); + } firstChild = w; } - private void setSecondWidget(Widget w) { + void setSecondWidget(Widget w) { if (secondChild != null) { secondChild.removeFromParent(); } - super.add(w, secondContainer); + if (w != null) { + super.add(w, secondContainer); + } secondChild = w; } @@ -658,7 +562,38 @@ public class VSplitPanel extends ComplexPanel implements Container, if (!Util.isTouchEvent(event)) { onMouseMove(event); } - updateSplitPositionToServer(); + fireEvent(new SplitterMoveEvent(this)); + } + + public interface SplitterMoveHandler extends EventHandler { + public void splitterMoved(SplitterMoveEvent event); + + public static class SplitterMoveEvent extends + GwtEvent<SplitterMoveHandler> { + + public static final Type<SplitterMoveHandler> TYPE = new Type<SplitterMoveHandler>(); + + private Widget splitPanel; + + public SplitterMoveEvent(Widget splitPanel) { + this.splitPanel = splitPanel; + } + + @Override + public com.google.gwt.event.shared.GwtEvent.Type<SplitterMoveHandler> getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(SplitterMoveHandler handler) { + handler.splitterMoved(this); + } + + } + } + + String getSplitterPosition() { + return position; } /** @@ -723,98 +658,7 @@ public class VSplitPanel extends ComplexPanel implements Container, return splitterSize; } - @Override - public void setHeight(String height) { - if (this.height.equals(height)) { - return; - } - - this.height = height; - super.setHeight(height); - - if (!rendering && client != null) { - setSplitPosition(position); - } - } - - @Override - public void setWidth(String width) { - if (this.width.equals(width)) { - return; - } - - this.width = width; - super.setWidth(width); - - if (!rendering && client != null) { - setSplitPosition(position); - } - } - - public RenderSpace getAllocatedSpace(Widget child) { - if (child == firstChild) { - return firstRenderSpace; - } else if (child == secondChild) { - return secondRenderSpace; - } - - return null; - } - - public boolean hasChildComponent(Widget component) { - return (component != null && (component == firstChild || component == secondChild)); - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - if (oldComponent == firstChild) { - setFirstWidget(newComponent); - } else if (oldComponent == secondChild) { - setSecondWidget(newComponent); - } - } - - public boolean requestLayout(Set<Paintable> child) { - // content size change might cause change to its available space - // (scrollbars) - for (Paintable paintable : child) { - client.handleComponentRelativeSize((Widget) paintable); - } - if (height != null && width != null) { - /* - * If the height and width has been specified the child components - * cannot make the size of the layout change - */ - - return true; - } - - if (renderInformation.updateSize(getElement())) { - return false; - } else { - return true; - } - - } - - public void updateCaption(Paintable component, UIDL uidl) { - // TODO Implement caption handling - } - - /** - * Updates the new split position back to server. - */ - private void updateSplitPositionToServer() { - float pos = 0; - if (position.indexOf("%") > 0) { - pos = Float.valueOf(position.substring(0, position.length() - 1)); - } else { - pos = Integer - .parseInt(position.substring(0, position.length() - 2)); - } - client.updateVariable(id, "position", pos, immediate); - } - - private void setStylenames() { + void setStylenames() { final String splitterSuffix = (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter" : "-vsplitter"); final String firstContainerSuffix = "-first-container"; @@ -829,13 +673,12 @@ public class VSplitPanel extends ComplexPanel implements Container, splitterStyle = CLASSNAME + splitterSuffix + "-locked"; lockedSuffix = "-locked"; } - for (int i = 0; i < componentStyleNames.length; i++) { - splitterStyle += " " + CLASSNAME + splitterSuffix + "-" - + componentStyleNames[i] + lockedSuffix; - firstStyle += " " + CLASSNAME + firstContainerSuffix + "-" - + componentStyleNames[i]; + for (String style : componentStyleNames) { + splitterStyle += " " + CLASSNAME + splitterSuffix + "-" + style + + lockedSuffix; + firstStyle += " " + CLASSNAME + firstContainerSuffix + "-" + style; secondStyle += " " + CLASSNAME + secondContainerSuffix + "-" - + componentStyleNames[i]; + + style; } DOM.setElementProperty(splitter, "className", splitterStyle); DOM.setElementProperty(firstContainer, "className", firstStyle); @@ -849,4 +692,5 @@ public class VSplitPanel extends ComplexPanel implements Container, public boolean isEnabled() { return enabled; } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VSplitPanelHorizontal.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VSplitPanelHorizontal.java new file mode 100644 index 0000000000..9048a59d7d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VSplitPanelHorizontal.java @@ -0,0 +1,12 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +public class VSplitPanelHorizontal extends VAbstractSplitPanel { + + public VSplitPanelHorizontal() { + super(VAbstractSplitPanel.ORIENTATION_HORIZONTAL); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VSplitPanelVertical.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VSplitPanelVertical.java new file mode 100644 index 0000000000..d22ebed5d9 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VSplitPanelVertical.java @@ -0,0 +1,12 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +public class VSplitPanelVertical extends VAbstractSplitPanel { + + public VSplitPanelVertical() { + super(VAbstractSplitPanel.ORIENTATION_VERTICAL); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VerticalSplitPanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VerticalSplitPanelConnector.java new file mode 100644 index 0000000000..83404177c0 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VerticalSplitPanelConnector.java @@ -0,0 +1,19 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +import com.google.gwt.core.client.GWT; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.VerticalSplitPanel; + +@Connect(value = VerticalSplitPanel.class, loadStyle = LoadStyle.EAGER) +public class VerticalSplitPanelConnector extends AbstractSplitPanelConnector { + + @Override + protected VAbstractSplitPanel createWidget() { + return GWT.create(VSplitPanelVertical.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java b/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java new file mode 100644 index 0000000000..f16ee3463f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/table/TableConnector.java @@ -0,0 +1,333 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.table; + +import java.util.Iterator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.AbstractFieldState; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; +import com.vaadin.terminal.gwt.client.ui.table.VScrollTable.ContextMenuDetails; +import com.vaadin.terminal.gwt.client.ui.table.VScrollTable.VScrollTableBody.VScrollTableRow; + +@Connect(com.vaadin.ui.Table.class) +public class TableConnector extends AbstractComponentContainerConnector + implements Paintable, DirectionalManagedLayout, PostLayoutListener { + + @Override + protected void init() { + super.init(); + getWidget().init(getConnection()); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal + * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection) + */ + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().rendering = true; + + // If a row has an open context menu, it will be closed as the row is + // detached. Retain a reference here so we can restore the menu if + // required. + ContextMenuDetails contextMenuBeforeUpdate = getWidget().contextMenu; + + if (uidl.hasAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST)) { + getWidget().serverCacheFirst = uidl + .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST); + getWidget().serverCacheLast = uidl + .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_LAST); + } else { + getWidget().serverCacheFirst = -1; + getWidget().serverCacheLast = -1; + } + /* + * We need to do this before updateComponent since updateComponent calls + * this.setHeight() which will calculate a new body height depending on + * the space available. + */ + if (uidl.hasAttribute("colfooters")) { + getWidget().showColFooters = uidl.getBooleanAttribute("colfooters"); + } + + getWidget().tFoot.setVisible(getWidget().showColFooters); + + if (!isRealUpdate(uidl)) { + getWidget().rendering = false; + return; + } + + getWidget().enabled = isEnabled(); + + if (BrowserInfo.get().isIE8() && !getWidget().enabled) { + /* + * The disabled shim will not cover the table body if it is relative + * in IE8. See #7324 + */ + getWidget().scrollBodyPanel.getElement().getStyle() + .setPosition(Position.STATIC); + } else if (BrowserInfo.get().isIE8()) { + getWidget().scrollBodyPanel.getElement().getStyle() + .setPosition(Position.RELATIVE); + } + + getWidget().paintableId = uidl.getStringAttribute("id"); + getWidget().immediate = getState().isImmediate(); + + int previousTotalRows = getWidget().totalRows; + getWidget().updateTotalRows(uidl); + boolean totalRowsChanged = (getWidget().totalRows != previousTotalRows); + + getWidget().updateDragMode(uidl); + + getWidget().updateSelectionProperties(uidl, getState(), isReadOnly()); + + if (uidl.hasAttribute("alb")) { + getWidget().bodyActionKeys = uidl.getStringArrayAttribute("alb"); + } else { + // Need to clear the actions if the action handlers have been + // removed + getWidget().bodyActionKeys = null; + } + + getWidget().setCacheRateFromUIDL(uidl); + + getWidget().recalcWidths = uidl.hasAttribute("recalcWidths"); + if (getWidget().recalcWidths) { + getWidget().tHead.clear(); + getWidget().tFoot.clear(); + } + + getWidget().updatePageLength(uidl); + + getWidget().updateFirstVisibleAndScrollIfNeeded(uidl); + + getWidget().showRowHeaders = uidl.getBooleanAttribute("rowheaders"); + getWidget().showColHeaders = uidl.getBooleanAttribute("colheaders"); + + getWidget().updateSortingProperties(uidl); + + boolean keyboardSelectionOverRowFetchInProgress = getWidget() + .selectSelectedRows(uidl); + + getWidget().updateActionMap(uidl); + + getWidget().updateColumnProperties(uidl); + + UIDL ac = uidl.getChildByTagName("-ac"); + if (ac == null) { + if (getWidget().dropHandler != null) { + // remove dropHandler if not present anymore + getWidget().dropHandler = null; + } + } else { + if (getWidget().dropHandler == null) { + getWidget().dropHandler = getWidget().new VScrollTableDropHandler(); + } + getWidget().dropHandler.updateAcceptRules(ac); + } + + UIDL partialRowAdditions = uidl.getChildByTagName("prows"); + UIDL partialRowUpdates = uidl.getChildByTagName("urows"); + if (partialRowUpdates != null || partialRowAdditions != null) { + // we may have pending cache row fetch, cancel it. See #2136 + getWidget().rowRequestHandler.cancel(); + + getWidget().updateRowsInBody(partialRowUpdates); + getWidget().addAndRemoveRows(partialRowAdditions); + } else { + UIDL rowData = uidl.getChildByTagName("rows"); + if (rowData != null) { + // we may have pending cache row fetch, cancel it. See #2136 + getWidget().rowRequestHandler.cancel(); + + if (!getWidget().recalcWidths + && getWidget().initializedAndAttached) { + getWidget().updateBody(rowData, + uidl.getIntAttribute("firstrow"), + uidl.getIntAttribute("rows")); + if (getWidget().headerChangedDuringUpdate) { + getWidget().triggerLazyColumnAdjustment(true); + } else if (!getWidget().isScrollPositionVisible() + || totalRowsChanged + || getWidget().lastRenderedHeight != getWidget().scrollBody + .getOffsetHeight()) { + // webkits may still bug with their disturbing scrollbar + // bug, see #3457 + // Run overflow fix for the scrollable area + // #6698 - If there's a scroll going on, don't abort it + // by changing overflows as the length of the contents + // *shouldn't* have changed (unless the number of rows + // or the height of the widget has also changed) + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + Util.runWebkitOverflowAutoFix(getWidget().scrollBodyPanel + .getElement()); + } + }); + } + } else { + getWidget().initializeRows(uidl, rowData); + } + } + } + + // If a row had an open context menu before the update, and after the + // update there's a row with the same key as that row, restore the + // context menu. See #8526. + showSavedContextMenu(contextMenuBeforeUpdate); + + if (!getWidget().isSelectable()) { + getWidget().scrollBody.addStyleName(VScrollTable.CLASSNAME + + "-body-noselection"); + } else { + getWidget().scrollBody.removeStyleName(VScrollTable.CLASSNAME + + "-body-noselection"); + } + + getWidget().hideScrollPositionAnnotation(); + + // selection is no in sync with server, avoid excessive server visits by + // clearing to flag used during the normal operation + if (!keyboardSelectionOverRowFetchInProgress) { + getWidget().selectionChanged = false; + } + + /* + * This is called when the Home or page up button has been pressed in + * selectable mode and the next selected row was not yet rendered in the + * client + */ + if (getWidget().selectFirstItemInNextRender + || getWidget().focusFirstItemInNextRender) { + getWidget().selectFirstRenderedRowInViewPort( + getWidget().focusFirstItemInNextRender); + getWidget().selectFirstItemInNextRender = getWidget().focusFirstItemInNextRender = false; + } + + /* + * This is called when the page down or end button has been pressed in + * selectable mode and the next selected row was not yet rendered in the + * client + */ + if (getWidget().selectLastItemInNextRender + || getWidget().focusLastItemInNextRender) { + getWidget().selectLastRenderedRowInViewPort( + getWidget().focusLastItemInNextRender); + getWidget().selectLastItemInNextRender = getWidget().focusLastItemInNextRender = false; + } + getWidget().multiselectPending = false; + + if (getWidget().focusedRow != null) { + if (!getWidget().focusedRow.isAttached() + && !getWidget().rowRequestHandler.isRunning()) { + // focused row has been orphaned, can't focus + getWidget().focusRowFromBody(); + } + } + + getWidget().tabIndex = uidl.hasAttribute("tabindex") ? uidl + .getIntAttribute("tabindex") : 0; + getWidget().setProperTabIndex(); + + getWidget().resizeSortedColumnForSortIndicator(); + + // Remember this to detect situations where overflow hack might be + // needed during scrolling + getWidget().lastRenderedHeight = getWidget().scrollBody + .getOffsetHeight(); + + getWidget().rendering = false; + getWidget().headerChangedDuringUpdate = false; + + } + + @Override + protected Widget createWidget() { + return GWT.create(VScrollTable.class); + } + + @Override + public VScrollTable getWidget() { + return (VScrollTable) super.getWidget(); + } + + public void updateCaption(ComponentConnector component) { + // NOP, not rendered + } + + public void layoutVertically() { + getWidget().updateHeight(); + } + + public void layoutHorizontally() { + getWidget().updateWidth(); + } + + public void postLayout() { + VScrollTable table = getWidget(); + if (table.sizeNeedsInit) { + table.sizeInit(); + Scheduler.get().scheduleFinally(new ScheduledCommand() { + public void execute() { + getLayoutManager().setNeedsMeasure(TableConnector.this); + getLayoutManager().setNeedsMeasure( + TableConnector.this.getParent()); + getLayoutManager().setNeedsVerticalLayout( + TableConnector.this); + getLayoutManager().layoutNow(); + } + }); + } + } + + @Override + public boolean isReadOnly() { + return super.isReadOnly() || getState().isPropertyReadOnly(); + } + + @Override + public AbstractFieldState getState() { + return (AbstractFieldState) super.getState(); + } + + /** + * Shows a saved row context menu if the row for the context menu is still + * visible. Does nothing if a context menu has not been saved. + * + * @param savedContextMenu + */ + public void showSavedContextMenu(ContextMenuDetails savedContextMenu) { + if (isEnabled() && savedContextMenu != null) { + Iterator<Widget> iterator = getWidget().scrollBody.iterator(); + while (iterator.hasNext()) { + Widget w = iterator.next(); + VScrollTableRow row = (VScrollTableRow) w; + if (row.getKey().equals(savedContextMenu.rowKey)) { + getWidget().contextMenu = savedContextMenu; + getConnection().getContextMenu().showAt(row, + savedContextMenu.left, savedContextMenu.top); + } + } + } + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java index a022a2bd83..c45c26c4ac 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.table; import java.util.ArrayList; import java.util.Collection; @@ -55,6 +55,7 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.RootPanel; @@ -62,17 +63,22 @@ import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Container; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VTooltip; -import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow; +import com.vaadin.terminal.gwt.client.ui.Action; +import com.vaadin.terminal.gwt.client.ui.ActionOwner; +import com.vaadin.terminal.gwt.client.ui.FocusableScrollPanel; +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate; +import com.vaadin.terminal.gwt.client.ui.TreeAction; import com.vaadin.terminal.gwt.client.ui.dd.DDUtil; import com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler; import com.vaadin.terminal.gwt.client.ui.dd.VAcceptCallback; @@ -81,6 +87,10 @@ import com.vaadin.terminal.gwt.client.ui.dd.VDragEvent; import com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler; import com.vaadin.terminal.gwt.client.ui.dd.VTransferable; import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; +import com.vaadin.terminal.gwt.client.ui.embedded.VEmbedded; +import com.vaadin.terminal.gwt.client.ui.label.VLabel; +import com.vaadin.terminal.gwt.client.ui.table.VScrollTable.VScrollTableBody.VScrollTableRow; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; /** * VScrollTable @@ -105,17 +115,31 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; * * TODO implement unregistering for child components in Cells */ -public class VScrollTable extends FlowPanel implements Table, ScrollHandler, - VHasDropHandler, FocusHandler, BlurHandler, Focusable, ActionOwner { +public class VScrollTable extends FlowPanel implements HasWidgets, + ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable, + ActionOwner { - public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft"; - public static final String ATTRIBUTE_PAGEBUFFER_LAST = "pb-l"; + public enum SelectMode { + NONE(0), SINGLE(1), MULTI(2); + private int id; + + private SelectMode(int id) { + this.id = id; + } + + public int getId() { + return id; + } + } private static final String ROW_HEADER_COLUMN_KEY = "0"; public static final String CLASSNAME = "v-table"; public static final String CLASSNAME_SELECTION_FOCUS = CLASSNAME + "-focus"; + public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft"; + public static final String ATTRIBUTE_PAGEBUFFER_LAST = "pb-l"; + public static final String ITEM_CLICK_EVENT_ID = "itemClick"; public static final String HEADER_CLICK_EVENT_ID = "handleHeaderClick"; public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick"; @@ -164,10 +188,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, protected ApplicationConnection client; protected String paintableId; - private boolean immediate; + boolean immediate; private boolean nullSelectionAllowed = true; - private int selectMode = Table.SELECT_MODE_NONE; + private SelectMode selectMode = SelectMode.NONE; private final HashSet<String> selectedRowKeys = new HashSet<String>(); @@ -180,15 +204,15 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, /* * These are used when jumping between pages when pressing Home and End */ - private boolean selectLastItemInNextRender = false; - private boolean selectFirstItemInNextRender = false; - private boolean focusFirstItemInNextRender = false; - private boolean focusLastItemInNextRender = false; + boolean selectLastItemInNextRender = false; + boolean selectFirstItemInNextRender = false; + boolean focusFirstItemInNextRender = false; + boolean focusLastItemInNextRender = false; /* * The currently focused row */ - private VScrollTableRow focusedRow; + VScrollTableRow focusedRow; /* * Helper to store selection range start in when using the keyboard @@ -199,7 +223,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * Flag for notifying when the selection has changed and should be sent to * the server */ - private boolean selectionChanged = false; + boolean selectionChanged = false; /* * The speed (in pixels) which the scrolling scrolls vertically/horizontally @@ -208,7 +232,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private Timer scrollingVelocityTimer = null; - private String[] bodyActionKeys; + String[] bodyActionKeys; private boolean enableDebug = false; @@ -283,19 +307,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private final HashSet<SelectionRange> selectedRowRanges = new HashSet<SelectionRange>(); - private boolean initializedAndAttached = false; + boolean initializedAndAttached = false; /** * Flag to indicate if a column width recalculation is needed due update. */ - private boolean headerChangedDuringUpdate = false; + boolean headerChangedDuringUpdate = false; protected final TableHead tHead = new TableHead(); - private final TableFooter tFoot = new TableFooter(); + final TableFooter tFoot = new TableFooter(); - private final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel( - true); + final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(true); private KeyPressHandler navKeyPressHandler = new KeyPressHandler() { public void onKeyPress(KeyPressEvent keyPressEvent) { @@ -384,12 +407,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } }; - private int totalRows; + int totalRows; private Set<String> collapsedColumns; - private final RowRequestHandler rowRequestHandler; - private VScrollTableBody scrollBody; + final RowRequestHandler rowRequestHandler; + VScrollTableBody scrollBody; private int firstvisible = 0; private boolean sortAscending; private String sortColumn; @@ -404,9 +427,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private String[] visibleColOrder; private boolean initialContentReceived = false; private Element scrollPositionElement; - private boolean enabled; - private boolean showColHeaders; - private boolean showColFooters; + boolean enabled; + boolean showColHeaders; + boolean showColFooters; /** flag to indicate that table body has changed */ private boolean isNewBody = true; @@ -418,18 +441,15 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, */ boolean recalcWidths = false; - private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>(); - private String height; - private String width = ""; - private boolean rendering = false; + boolean rendering = false; private boolean hasFocus = false; private int dragmode; private int multiselectmode; - private int tabIndex; + int tabIndex; private TouchScrollDelegate touchScrollDelegate; - private int lastRenderedHeight; + int lastRenderedHeight; /** * Values (serverCacheFirst+serverCacheLast) sent by server that tells which @@ -443,14 +463,16 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * scrolling in the client will cause empty buttons to be rendered * (cached=true request for non-existing components) */ - private int serverCacheFirst = -1; - private int serverCacheLast = -1; + int serverCacheFirst = -1; + int serverCacheLast = -1; + + boolean sizeNeedsInit = true; /** * Used to recall the position of an open context menu if we need to close * and reopen it during a row update. */ - private class ContextMenuDetails { + class ContextMenuDetails { String rowKey; int left; int top; @@ -462,7 +484,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - ContextMenuDetails contextMenu; + protected ContextMenuDetails contextMenu = null; public VScrollTable() { setMultiSelectMode(MULTISELECT_MODE_DEFAULT); @@ -509,6 +531,17 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, rowRequestHandler = new RowRequestHandler(); } + public void init(ApplicationConnection client) { + this.client = client; + // Add a handler to clear saved context menu details when the menu + // closes. See #8526. + client.getContextMenu().addCloseHandler(new CloseHandler<PopupPanel>() { + public void onClose(CloseEvent<PopupPanel> event) { + contextMenu = null; + } + }); + } + protected TouchScrollDelegate getTouchScrollDelegate() { if (touchScrollDelegate == null) { touchScrollDelegate = new TouchScrollDelegate( @@ -830,243 +863,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return KeyCodes.KEY_END; } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal - * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - - // On the first rendering, add a handler to clear saved context menu - // details when the menu closes. See #8526. - if (this.client == null) { - client.getContextMenu().addCloseHandler( - new CloseHandler<PopupPanel>() { - public void onClose(CloseEvent<PopupPanel> event) { - contextMenu = null; - } - }); - } - // If a row has an open context menu, it will be closed as the row is - // detached. Retain a reference here so we can restore the menu if - // required. - ContextMenuDetails savedContextMenu = contextMenu; - - if (uidl.hasAttribute(ATTRIBUTE_PAGEBUFFER_FIRST)) { - serverCacheFirst = uidl.getIntAttribute(ATTRIBUTE_PAGEBUFFER_FIRST); - serverCacheLast = uidl.getIntAttribute(ATTRIBUTE_PAGEBUFFER_LAST); - } else { - serverCacheFirst = -1; - serverCacheLast = -1; - } - /* - * We need to do this before updateComponent since updateComponent calls - * this.setHeight() which will calculate a new body height depending on - * the space available. - */ - if (uidl.hasAttribute("colfooters")) { - showColFooters = uidl.getBooleanAttribute("colfooters"); - } - - tFoot.setVisible(showColFooters); - - if (client.updateComponent(this, uidl, true)) { - rendering = false; - return; - } - - enabled = !uidl.hasAttribute("disabled"); - - if (BrowserInfo.get().isIE8() && !enabled) { - /* - * The disabled shim will not cover the table body if it is relative - * in IE8. See #7324 - */ - scrollBodyPanel.getElement().getStyle() - .setPosition(Position.STATIC); - } else if (BrowserInfo.get().isIE8()) { - scrollBodyPanel.getElement().getStyle() - .setPosition(Position.RELATIVE); - } - - this.client = client; - paintableId = uidl.getStringAttribute("id"); - immediate = uidl.getBooleanAttribute("immediate"); - - int previousTotalRows = totalRows; - updateTotalRows(uidl); - boolean totalRowsChanged = (totalRows != previousTotalRows); - - updateDragMode(uidl); - - updateSelectionProperties(uidl); - - if (uidl.hasAttribute("alb")) { - bodyActionKeys = uidl.getStringArrayAttribute("alb"); - } else { - // Need to clear the actions if the action handlers have been - // removed - bodyActionKeys = null; - } - - setCacheRateFromUIDL(uidl); - - recalcWidths = uidl.hasAttribute("recalcWidths"); - if (recalcWidths) { - tHead.clear(); - tFoot.clear(); - } - - updatePageLength(uidl); - - updateFirstVisibleAndScrollIfNeeded(uidl); - - showRowHeaders = uidl.getBooleanAttribute("rowheaders"); - showColHeaders = uidl.getBooleanAttribute("colheaders"); - - updateSortingProperties(uidl); - - boolean keyboardSelectionOverRowFetchInProgress = selectSelectedRows(uidl); - - updateActionMap(uidl); - - updateColumnProperties(uidl); - - UIDL ac = uidl.getChildByTagName("-ac"); - if (ac == null) { - if (dropHandler != null) { - // remove dropHandler if not present anymore - dropHandler = null; - } - } else { - if (dropHandler == null) { - dropHandler = new VScrollTableDropHandler(); - } - dropHandler.updateAcceptRules(ac); - } - - UIDL partialRowAdditions = uidl.getChildByTagName("prows"); - UIDL partialRowUpdates = uidl.getChildByTagName("urows"); - if (partialRowUpdates != null || partialRowAdditions != null) { - // we may have pending cache row fetch, cancel it. See #2136 - rowRequestHandler.cancel(); - - updateRowsInBody(partialRowUpdates); - addAndRemoveRows(partialRowAdditions); - } else { - UIDL rowData = uidl.getChildByTagName("rows"); - if (rowData != null) { - // we may have pending cache row fetch, cancel it. See #2136 - rowRequestHandler.cancel(); - - if (!recalcWidths && initializedAndAttached) { - updateBody(rowData, uidl.getIntAttribute("firstrow"), - uidl.getIntAttribute("rows")); - if (headerChangedDuringUpdate) { - triggerLazyColumnAdjustment(true); - } else if (!isScrollPositionVisible() - || totalRowsChanged - || lastRenderedHeight != scrollBody - .getOffsetHeight()) { - // webkits may still bug with their disturbing scrollbar - // bug, see #3457 - // Run overflow fix for the scrollable area - // #6698 - If there's a scroll going on, don't abort it - // by changing overflows as the length of the contents - // *shouldn't* have changed (unless the number of rows - // or the height of the widget has also changed) - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - Util.runWebkitOverflowAutoFix(scrollBodyPanel - .getElement()); - } - }); - } - } else { - initializeRows(uidl, rowData); - } - } - } - - // If a row had an open context menu before the update, and after the - // update there's a row with the same key as that row, restore the - // context menu. See #8526. - if (enabled && savedContextMenu != null) { - for (Widget w : scrollBody.renderedRows) { - VScrollTableRow row = (VScrollTableRow) w; - if (row.isVisible() - && row.getKey().equals(savedContextMenu.rowKey)) { - contextMenu = savedContextMenu; - client.getContextMenu().showAt(row, savedContextMenu.left, - savedContextMenu.top); - } - } - } - - if (!isSelectable()) { - scrollBody.addStyleName(CLASSNAME + "-body-noselection"); - } else { - scrollBody.removeStyleName(CLASSNAME + "-body-noselection"); - } - - hideScrollPositionAnnotation(); - purgeUnregistryBag(); - - // selection is no in sync with server, avoid excessive server visits by - // clearing to flag used during the normal operation - if (!keyboardSelectionOverRowFetchInProgress) { - selectionChanged = false; - } - - /* - * This is called when the Home or page up button has been pressed in - * selectable mode and the next selected row was not yet rendered in the - * client - */ - if (selectFirstItemInNextRender || focusFirstItemInNextRender) { - selectFirstRenderedRowInViewPort(focusFirstItemInNextRender); - selectFirstItemInNextRender = focusFirstItemInNextRender = false; - } - - /* - * This is called when the page down or end button has been pressed in - * selectable mode and the next selected row was not yet rendered in the - * client - */ - if (selectLastItemInNextRender || focusLastItemInNextRender) { - selectLastRenderedRowInViewPort(focusLastItemInNextRender); - selectLastItemInNextRender = focusLastItemInNextRender = false; - } - multiselectPending = false; - - if (focusedRow != null) { - if (!focusedRow.isAttached() && !rowRequestHandler.isRunning()) { - // focused row has been orphaned, can't focus - focusRowFromBody(); - } - } - - tabIndex = uidl.hasAttribute("tabindex") ? uidl - .getIntAttribute("tabindex") : 0; - setProperTabIndex(); - - resizeSortedColumnForSortIndicator(); - - // Remember this to detect situations where overflow hack might be - // needed during scrolling - lastRenderedHeight = scrollBody.getOffsetHeight(); - - rendering = false; - headerChangedDuringUpdate = false; - } - - private void initializeRows(UIDL uidl, UIDL rowData) { + void initializeRows(UIDL uidl, UIDL rowData) { if (scrollBody != null) { scrollBody.removeFromParent(); - lazyUnregistryBag.add(scrollBody); } scrollBody = createScrollBody(); @@ -1080,13 +879,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, tFoot.setHorizontalScrollPosition(0); initialContentReceived = true; - if (isAttached()) { - sizeInit(); - } + sizeNeedsInit = true; scrollBody.restoreRowVisibility(); } - private void updateColumnProperties(UIDL uidl) { + void updateColumnProperties(UIDL uidl) { updateColumnOrder(uidl); updateCollapsedColumns(uidl); @@ -1121,7 +918,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - private boolean selectSelectedRows(UIDL uidl) { + boolean selectSelectedRows(UIDL uidl) { boolean keyboardSelectionOverRowFetchInProgress = false; if (uidl.hasVariable("selected")) { @@ -1158,7 +955,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return keyboardSelectionOverRowFetchInProgress; } - private void updateSortingProperties(UIDL uidl) { + void updateSortingProperties(UIDL uidl) { oldSortColumn = sortColumn; if (uidl.hasVariable("sortascending")) { sortAscending = uidl.getBooleanVariable("sortascending"); @@ -1166,7 +963,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - private void resizeSortedColumnForSortIndicator() { + void resizeSortedColumnForSortIndicator() { // Force recalculation of the captionContainer element inside the header // cell to accomodate for the size of the sort arrow. HeaderCell sortedHeader = tHead.getHeaderCell(sortColumn); @@ -1181,7 +978,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - private void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) { + void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) { firstvisible = uidl.hasVariable("firstvisible") ? uidl .getIntVariable("firstvisible") : 0; if (firstvisible != lastRequestedFirstvisible && scrollBody != null) { @@ -1196,7 +993,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return (int) (rowIx * scrollBody.getRowHeight()); } - private void updatePageLength(UIDL uidl) { + void updatePageLength(UIDL uidl) { int oldPageLength = pageLength; if (uidl.hasAttribute("pagelength")) { pageLength = uidl.getIntAttribute("pagelength"); @@ -1207,11 +1004,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, if (oldPageLength != pageLength && initializedAndAttached) { // page length changed, need to update size - sizeInit(); + sizeNeedsInit = true; } } - private void updateSelectionProperties(UIDL uidl) { + void updateSelectionProperties(UIDL uidl, ComponentState state, + boolean readOnly) { setMultiSelectMode(uidl.hasAttribute("multiselectmode") ? uidl .getIntAttribute("multiselectmode") : MULTISELECT_MODE_DEFAULT); @@ -1219,19 +1017,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, .getBooleanAttribute("nsa") : true; if (uidl.hasAttribute("selectmode")) { - if (uidl.getBooleanAttribute("readonly")) { - selectMode = Table.SELECT_MODE_NONE; + if (readOnly) { + selectMode = SelectMode.NONE; } else if (uidl.getStringAttribute("selectmode").equals("multi")) { - selectMode = Table.SELECT_MODE_MULTI; + selectMode = SelectMode.MULTI; } else if (uidl.getStringAttribute("selectmode").equals("single")) { - selectMode = Table.SELECT_MODE_SINGLE; + selectMode = SelectMode.SINGLE; } else { - selectMode = Table.SELECT_MODE_NONE; + selectMode = SelectMode.NONE; } } } - private void updateDragMode(UIDL uidl) { + void updateDragMode(UIDL uidl) { dragmode = uidl.hasAttribute("dragmode") ? uidl .getIntAttribute("dragmode") : 0; if (BrowserInfo.get().isIE()) { @@ -1264,11 +1062,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, totalRows = newTotalRows; } - protected int getTotalRows() { + public int getTotalRows() { return totalRows; } - private void focusRowFromBody() { + void focusRowFromBody() { if (selectedRowKeys.size() == 1) { // try to focus a row currently selected and in viewport String selectedRowKey = selectedRowKeys.iterator().next(); @@ -1296,7 +1094,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * @param focusOnly * Should the focus only be moved to the last row */ - private void selectLastRenderedRowInViewPort(boolean focusOnly) { + void selectLastRenderedRowInViewPort(boolean focusOnly) { int index = firstRowInViewPort + getFullyVisibleRowCount(); VScrollTableRow lastRowInViewport = scrollBody.getRowByRowIndex(index); if (lastRowInViewport == null) { @@ -1321,7 +1119,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * @param focusOnly * Should the focus only be moved to the first row */ - private void selectFirstRenderedRowInViewPort(boolean focusOnly) { + void selectFirstRenderedRowInViewPort(boolean focusOnly) { int index = firstRowInViewPort; VScrollTableRow firstInViewport = scrollBody.getRowByRowIndex(index); if (firstInViewport == null) { @@ -1335,7 +1133,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - private void setCacheRateFromUIDL(UIDL uidl) { + void setCacheRateFromUIDL(UIDL uidl) { setCacheRate(uidl.hasAttribute("cr") ? uidl.getDoubleAttribute("cr") : CACHE_RATE_DEFAULT); } @@ -1347,20 +1145,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - /** - * Unregisters Paintables in "trashed" HasWidgets (IScrollTableBodys or - * IScrollTableRows). This is done lazily as Table must survive from - * "subtreecaching" logic. - */ - private void purgeUnregistryBag() { - for (Iterator<Panel> iterator = lazyUnregistryBag.iterator(); iterator - .hasNext();) { - client.unregisterChildPaintables(iterator.next()); - } - lazyUnregistryBag.clear(); - } - - private void updateActionMap(UIDL mainUidl) { + void updateActionMap(UIDL mainUidl) { UIDL actionsUidl = mainUidl.getChildByTagName("actions"); if (actionsUidl == null) { return; @@ -1462,7 +1247,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * @param reqRows * amount of rows in data set */ - private void updateBody(UIDL uidl, int firstRow, int reqRows) { + void updateBody(UIDL uidl, int firstRow, int reqRows) { if (uidl == null || reqRows < 1) { // container is empty, remove possibly existing rows if (firstRow <= 0) { @@ -1479,7 +1264,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, discardRowsOutsideCacheWindow(); } - private void updateRowsInBody(UIDL partialRowUpdates) { + void updateRowsInBody(UIDL partialRowUpdates) { if (partialRowUpdates == null) { return; } @@ -1612,20 +1397,20 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } private boolean isMultiSelectModeSimple() { - return selectMode == Table.SELECT_MODE_MULTI + return selectMode == SelectMode.MULTI && multiselectmode == MULTISELECT_MODE_SIMPLE; } private boolean isSingleSelectMode() { - return selectMode == Table.SELECT_MODE_SINGLE; + return selectMode == SelectMode.SINGLE; } private boolean isMultiSelectModeAny() { - return selectMode == Table.SELECT_MODE_MULTI; + return selectMode == SelectMode.MULTI; } private boolean isMultiSelectModeDefault() { - return selectMode == Table.SELECT_MODE_MULTI + return selectMode == SelectMode.MULTI && multiselectmode == MULTISELECT_MODE_DEFAULT; } @@ -1641,7 +1426,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } protected boolean isSelectable() { - return selectMode > Table.SELECT_MODE_NONE; + return selectMode.getId() > SelectMode.NONE.getId(); } private boolean isCollapsedColumn(String colKey) { @@ -1692,7 +1477,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * The key to search with * @return */ - protected VScrollTableRow getRenderedRowByKey(String key) { + public VScrollTableRow getRenderedRowByKey(String key) { if (scrollBody != null) { final Iterator<Widget> it = scrollBody.iterator(); VScrollTableRow r = null; @@ -1823,14 +1608,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } @Override - protected void onAttach() { - super.onAttach(); - if (initialContentReceived) { - sizeInit(); - } - } - - @Override protected void onDetach() { rowRequestHandler.cancel(); super.onDetach(); @@ -1853,7 +1630,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * * * Makes deferred request to get some cache rows */ - private void sizeInit() { + void sizeInit() { + sizeNeedsInit = false; + + scrollBody.setContainerHeight(); + /* * We will use browsers table rendering algorithm to find proper column * widths. If content and header take less space than available, we will @@ -1908,7 +1689,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, boolean willHaveScrollbarz = willHaveScrollbars(); // fix "natural" width if width not set - if (width == null || "".equals(width)) { + if (isDynamicWidth()) { int w = total; w += scrollBody.getCellExtraWidth() * visibleColOrder.length; if (willHaveScrollbarz) { @@ -2036,7 +1817,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * Fix "natural" height if height is not set. This must be after width * fixing so the components' widths have been adjusted. */ - if (height == null || "".equals(height)) { + if (isDynamicHeight()) { /* * We must force an update of the row height as this point as it * might have been (incorrectly) calculated earlier @@ -2120,7 +1901,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * @return true if content area will have scrollbars visible. */ protected boolean willHaveScrollbars() { - if (!(height != null && !height.equals(""))) { + if (isDynamicHeight()) { if (pageLength < totalRows) { return true; } @@ -2159,19 +1940,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, style.setDisplay(Display.BLOCK); } - private void hideScrollPositionAnnotation() { + void hideScrollPositionAnnotation() { if (scrollPositionElement != null) { DOM.setStyleAttribute(scrollPositionElement, "display", "none"); } } - private boolean isScrollPositionVisible() { + boolean isScrollPositionVisible() { return scrollPositionElement != null && !scrollPositionElement.getStyle().getDisplay() .equals(Display.NONE.toString()); } - private class RowRequestHandler extends Timer { + class RowRequestHandler extends Timer { private int reqFirstRow = 0; private int reqRows = 0; @@ -2346,11 +2127,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * of the caption container element by the correct amount */ public void resizeCaptionContainer(int rightSpacing) { - int captionContainerWidth = width - colResizeWidget.getOffsetWidth() - rightSpacing; - if (BrowserInfo.get().isIE6() || td.getClassName().contains("-asc") + if (td.getClassName().contains("-asc") || td.getClassName().contains("-desc")) { // Leave room for the sort indicator captionContainerWidth -= sortIndicator.getOffsetWidth(); @@ -2573,7 +2353,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private void fireHeaderClickedEvent(Event event) { if (client.hasEventListeners(VScrollTable.this, HEADER_CLICK_EVENT_ID)) { - MouseEventDetails details = new MouseEventDetails(event); + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event); client.updateVariable(paintableId, "headerClickEvent", details.toString(), false); client.updateVariable(paintableId, "headerClickCID", cid, true); @@ -2830,8 +2611,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, int hw = captionContainer.getOffsetWidth() + scrollBody.getCellExtraWidth(); - if (BrowserInfo.get().isGecko() - || BrowserInfo.get().isIE7()) { + if (BrowserInfo.get().isGecko()) { hw += sortIndicator.getOffsetWidth(); } if (columnIndex < 0) { @@ -3098,12 +2878,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } public void setHorizontalScrollPosition(int scrollLeft) { - if (BrowserInfo.get().isIE6()) { - hTableWrapper.getStyle().setPosition(Position.RELATIVE); - hTableWrapper.getStyle().setLeft(-scrollLeft, Unit.PX); - } else { - hTableWrapper.setScrollLeft(scrollLeft); - } + hTableWrapper.setScrollLeft(scrollLeft); } public void setColumnCollapsingAllowed(boolean cc) { @@ -3636,7 +3411,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private void fireFooterClickedEvent(Event event) { if (client.hasEventListeners(VScrollTable.this, FOOTER_CLICK_EVENT_ID)) { - MouseEventDetails details = new MouseEventDetails(event); + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event); client.updateVariable(paintableId, "footerClickEvent", details.toString(), false); client.updateVariable(paintableId, "footerClickCID", cid, true); @@ -3966,12 +3742,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * The value of the leftScroll */ public void setHorizontalScrollPosition(int scrollLeft) { - if (BrowserInfo.get().isIE6()) { - hTableWrapper.getStyle().setProperty("position", "relative"); - hTableWrapper.getStyle().setPropertyPx("left", -scrollLeft); - } else { - hTableWrapper.setScrollLeft(scrollLeft); - } + hTableWrapper.setScrollLeft(scrollLeft); } /** @@ -4406,7 +4177,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, Element td = toBeRemoved.getElement().getChild(i).cast(); client.registerTooltip(VScrollTable.this, td, null); } - lazyUnregistryBag.add(toBeRemoved); tBodyElement.removeChild(toBeRemoved.getElement()); orphan(toBeRemoved); renderedRows.remove(index); @@ -4417,12 +4187,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, throw new UnsupportedOperationException(); } - @Override - protected void onAttach() { - super.onAttach(); - setContainerHeight(); - } - /** * Fix container blocks height according to totalRows to avoid * "bouncing" when scrolling @@ -4614,15 +4378,13 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - public class VScrollTableRow extends Panel implements ActionOwner, - Container { + public class VScrollTableRow extends Panel implements ActionOwner { private static final int TOUCHSCROLL_TIMEOUT = 100; private static final int DRAGMODE_MULTIROW = 2; protected ArrayList<Widget> childWidgets = new ArrayList<Widget>(); private boolean selected = false; protected final int rowKey; - private List<UIDL> pendingComponentPaints; private String[] actionKeys = null; private final TableRowElement rowElement; @@ -4744,12 +4506,11 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, addCell(uidl, cell.toString(), aligns[col++], style, isRenderHtmlInCells(), sorted, description); } else { - final Paintable cellContent = client + final ComponentConnector cellContent = client .getPaintable((UIDL) cell); - addCell(uidl, (Widget) cellContent, aligns[col++], + addCell(uidl, cellContent.getWidget(), aligns[col++], style, sorted); - paintComponent(cellContent, (UIDL) cell); } } } @@ -4822,29 +4583,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return index; } - protected void paintComponent(Paintable p, UIDL uidl) { - if (isAttached()) { - p.updateFromUIDL(uidl, client); - } else { - if (pendingComponentPaints == null) { - pendingComponentPaints = new LinkedList<UIDL>(); - } - pendingComponentPaints.add(uidl); - } - } - - @Override - protected void onAttach() { - super.onAttach(); - if (pendingComponentPaints != null) { - for (UIDL uidl : pendingComponentPaints) { - Paintable paintable = client.getPaintable(uidl); - paintable.updateFromUIDL(uidl, client); - } - pendingComponentPaints.clear(); - } - } - @Override protected void onDetach() { super.onDetach(); @@ -5003,7 +4741,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, false); } - MouseEventDetails details = new MouseEventDetails(event); + MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(event); client.updateVariable(paintableId, "clickEvent", details.toString(), immediate); @@ -5027,8 +4766,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, if (!containsWidget) { // Only text nodes has tooltips - if (client.getTooltipTitleInfo(VScrollTable.this, - target) != null) { + if (ConnectorMap.get(client).getWidgetTooltipInfo( + VScrollTable.this, target) != null) { // Cell has description, use it client.handleTooltipEvent(event, VScrollTable.this, target); @@ -5361,7 +5100,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, Element targetTdOrTr) { mDown = true; VTransferable transferable = new VTransferable(); - transferable.setDragSource(VScrollTable.this); + transferable.setDragSource(ConnectorMap.get(client) + .getConnector(VScrollTable.this)); transferable.setData("itemId", "" + rowKey); NodeList<TableCellElement> cells = rowElement.getCells(); for (int i = 0; i < cells.getLength(); i++) { @@ -5580,29 +5320,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return paintableId; } - public RenderSpace getAllocatedSpace(Widget child) { - int w = 0; - int i = getColIndexOf(child); - HeaderCell headerCell = tHead.getHeaderCell(i); - if (headerCell != null) { - if (initializedAndAttached) { - w = headerCell.getWidth(); - } else { - // header offset width is not absolutely correct value, - // but a best guess (expecting similar content in all - // columns -> - // if one component is relative width so are others) - w = headerCell.getOffsetWidth() - getCellExtraWidth(); - } - } - return new RenderSpace(w, 0) { - @Override - public int getHeight() { - return (int) getRowHeight(); - } - }; - } - private int getColIndexOf(Widget child) { com.google.gwt.dom.client.Element widgetCell = child .getElement().getParentElement().getParentElement(); @@ -5615,37 +5332,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return -1; } - public boolean hasChildComponent(Widget component) { - return childWidgets.contains(component); - } - - public void replaceChildComponent(Widget oldComponent, - Widget newComponent) { - com.google.gwt.dom.client.Element parentElement = oldComponent - .getElement().getParentElement(); - int index = childWidgets.indexOf(oldComponent); - oldComponent.removeFromParent(); - - parentElement.appendChild(newComponent.getElement()); - childWidgets.add(index, newComponent); - adopt(newComponent); - - } - - public boolean requestLayout(Set<Paintable> children) { - // row size should never change and system wouldn't event - // survive as this is a kind of fake paitable - return true; - } - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP, not rendered - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Should never be called, - // Component container interface faked here to get layouts - // render properly + public Widget getWidgetForPaintable() { + return this; } } @@ -5780,7 +5468,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, if (!hasFocus) { scrollBodyPanel.setFocus(true); } + } + } /** @@ -5822,7 +5512,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return; } - if (height == null || height.equals("")) { + if (isDynamicHeight()) { return; } @@ -5846,16 +5536,14 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, scrollBodyPanel.setScrollPosition(scrollTop + 1); scrollBodyPanel.setScrollPosition(scrollTop - 1); } + + sizeNeedsInit = true; } } } - @Override - public void setWidth(String width) { - if (this.width.equals(width)) { - return; - } + void updateWidth() { if (!isVisible()) { /* * Do not update size when the table is hidden as all column widths @@ -5865,9 +5553,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return; } - this.width = width; - if (width != null && !"".equals(width)) { - super.setWidth(width); + if (!isDynamicWidth()) { int innerPixels = getOffsetWidth() - getBorderWidth(); if (innerPixels < 0) { innerPixels = 0; @@ -5879,11 +5565,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } else { - // Undefined width - super.setWidth(""); - - // Readjust size of table - sizeInit(); + sizeNeedsInit = true; // readjust undefined width columns triggerLazyColumnAdjustment(false); @@ -5997,8 +5679,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } - if ((height == null || "".equals(height)) - && totalRows == pageLength) { + if (isDynamicHeight() && totalRows == pageLength) { // fix body height (may vary if lazy loading is offhorizontal // scrollbar appears/disappears) int bodyHeight = scrollBody.getRequiredHeight(); @@ -6070,7 +5751,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private int containerHeight; private void setContainerHeight() { - if (height != null && !"".equals(height)) { + if (!isDynamicHeight()) { containerHeight = getOffsetHeight(); containerHeight -= showColHeaders ? tHead.getOffsetHeight() : 0; containerHeight -= tFoot.getOffsetHeight(); @@ -6085,41 +5766,46 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private int contentAreaBorderHeight = -1; private int scrollLeft; private int scrollTop; - private VScrollTableDropHandler dropHandler; + VScrollTableDropHandler dropHandler; private boolean navKeyDown; - private boolean multiselectPending; + boolean multiselectPending; /** * @return border top + border bottom of the scrollable area of table */ private int getContentAreaBorderHeight() { if (contentAreaBorderHeight < 0) { - if (BrowserInfo.get().isIE7() || BrowserInfo.get().isIE6()) { - contentAreaBorderHeight = Util - .measureVerticalBorder(scrollBodyPanel.getElement()); - } else { - DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow", - "hidden"); - int oh = scrollBodyPanel.getOffsetHeight(); - int ch = scrollBodyPanel.getElement().getPropertyInt( - "clientHeight"); - contentAreaBorderHeight = oh - ch; - DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow", - "auto"); - } + + DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow", + "hidden"); + int oh = scrollBodyPanel.getOffsetHeight(); + int ch = scrollBodyPanel.getElement() + .getPropertyInt("clientHeight"); + contentAreaBorderHeight = oh - ch; + DOM.setStyleAttribute(scrollBodyPanel.getElement(), "overflow", + "auto"); } return contentAreaBorderHeight; } @Override public void setHeight(String height) { - this.height = height; + if (height.length() == 0 + && getElement().getStyle().getHeight().length() != 0) { + /* + * Changing from defined to undefined size -> should do a size init + * to take page length into account again + */ + sizeNeedsInit = true; + } super.setHeight(height); + } + + void updateHeight() { setContainerHeight(); - if (initializedAndAttached) { - updatePageLength(); - } + updatePageLength(); + if (!rendering) { // Webkit may sometimes get an odd rendering bug (white space // between header and body), see bug #3875. Running @@ -6439,8 +6125,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } @Override - public Paintable getPaintable() { - return VScrollTable.this; + public ComponentConnector getConnector() { + return ConnectorMap.get(client).getConnector(VScrollTable.this); } public ApplicationConnection getApplicationConnection() { @@ -6460,7 +6146,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * The row to where the selection head should move * @return Returns true if focus was moved successfully, else false */ - protected boolean setRowFocus(VScrollTableRow row) { + public boolean setRowFocus(VScrollTableRow row) { if (!isSelectable()) { return false; @@ -6800,7 +6486,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, if (BrowserInfo.get().isIE()) { // IE sometimes moves focus to a clicked table cell... Element focusedElement = Util.getIEFocusedElement(); - if (Util.getPaintableForElement(client, getParent(), focusedElement) == this) { + if (Util.getConnectorForElement(client, getParent(), focusedElement) == this) { // ..in that case, steal the focus back to the focus handler // but not if focus is in a child component instead (#7965) focus(); @@ -6882,7 +6568,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * actions may need focus. * */ - private void setProperTabIndex() { + void setProperTabIndex() { int storedScrollTop = 0; int storedScrollLeft = 0; @@ -6991,7 +6677,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, return function(){ return false; }; }-*/; - protected void triggerLazyColumnAdjustment(boolean now) { + public void triggerLazyColumnAdjustment(boolean now) { lazyAdjustColumnWidths.cancel(); if (now) { lazyAdjustColumnWidths.run(); @@ -7000,9 +6686,31 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } + private boolean isDynamicWidth() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + return paintable.isUndefinedWidth(); + } + + private boolean isDynamicHeight() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + if (paintable == null) { + // This should be refactored. As isDynamicHeight can be called from + // a timer it is possible that the connector has been unregistered + // when this method is called, causing getConnector to return null. + return false; + } + return paintable.isUndefinedHeight(); + } + private void debug(String msg) { if (enableDebug) { VConsole.error(msg); } } + + public Widget getWidgetForPaintable() { + return this; + } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetBaseConnector.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetBaseConnector.java new file mode 100644 index 0000000000..e16e84d112 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetBaseConnector.java @@ -0,0 +1,99 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.tabsheet; + +import java.util.ArrayList; +import java.util.Iterator; + +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; + +public abstract class TabsheetBaseConnector extends + AbstractComponentContainerConnector implements Paintable { + + public static final String ATTRIBUTE_TAB_DISABLED = "disabled"; + public static final String ATTRIBUTE_TAB_DESCRIPTION = "description"; + public static final String ATTRIBUTE_TAB_ERROR_MESSAGE = "error"; + public static final String ATTRIBUTE_TAB_CAPTION = "caption"; + public static final String ATTRIBUTE_TAB_ICON = "icon"; + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().client = client; + + if (!isRealUpdate(uidl)) { + return; + } + + // Update member references + getWidget().id = uidl.getId(); + getWidget().disabled = !isEnabled(); + + // Render content + final UIDL tabs = uidl.getChildUIDL(0); + + // Widgets in the TabSheet before update + ArrayList<Widget> oldWidgets = new ArrayList<Widget>(); + for (Iterator<Widget> iterator = getWidget().getWidgetIterator(); iterator + .hasNext();) { + oldWidgets.add(iterator.next()); + } + + // Clear previous values + getWidget().tabKeys.clear(); + getWidget().disabledTabKeys.clear(); + + int index = 0; + for (final Iterator<Object> it = tabs.getChildIterator(); it.hasNext();) { + final UIDL tab = (UIDL) it.next(); + final String key = tab.getStringAttribute("key"); + final boolean selected = tab.getBooleanAttribute("selected"); + final boolean hidden = tab.getBooleanAttribute("hidden"); + + if (tab.getBooleanAttribute(ATTRIBUTE_TAB_DISABLED)) { + getWidget().disabledTabKeys.add(key); + } + + getWidget().tabKeys.add(key); + + if (selected) { + getWidget().activeTabIndex = index; + } + getWidget().renderTab(tab, index, selected, hidden); + index++; + } + + int tabCount = getWidget().getTabCount(); + while (tabCount-- > index) { + getWidget().removeTab(index); + } + + for (int i = 0; i < getWidget().getTabCount(); i++) { + ComponentConnector p = getWidget().getTab(i); + // null for PlaceHolder widgets + if (p != null) { + oldWidgets.remove(p.getWidget()); + } + } + + // Detach any old tab widget, should be max 1 + for (Iterator<Widget> iterator = oldWidgets.iterator(); iterator + .hasNext();) { + Widget oldWidget = iterator.next(); + if (oldWidget.isAttached()) { + oldWidget.removeFromParent(); + } + } + + } + + @Override + public VTabsheetBase getWidget() { + return (VTabsheetBase) super.getWidget(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java new file mode 100644 index 0000000000..7829934f70 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/TabsheetConnector.java @@ -0,0 +1,105 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.tabsheet; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; +import com.vaadin.ui.TabSheet; + +@Connect(TabSheet.class) +public class TabsheetConnector extends TabsheetBaseConnector implements + SimpleManagedLayout, MayScrollChildren { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + if (isRealUpdate(uidl)) { + // Handle stylename changes before generics (might affect size + // calculations) + getWidget().handleStyleNames(uidl, getState()); + } + + super.updateFromUIDL(uidl, client); + if (!isRealUpdate(uidl)) { + return; + } + + // tabs; push or not + if (!isUndefinedWidth()) { + DOM.setStyleAttribute(getWidget().tabs, "overflow", "hidden"); + } else { + getWidget().showAllTabs(); + DOM.setStyleAttribute(getWidget().tabs, "width", ""); + DOM.setStyleAttribute(getWidget().tabs, "overflow", "visible"); + getWidget().updateDynamicWidth(); + } + + if (!isUndefinedHeight()) { + // Must update height after the styles have been set + getWidget().updateContentNodeHeight(); + getWidget().updateOpenTabSize(); + } + + getWidget().iLayout(); + + // Re run relative size update to ensure optimal scrollbars + // TODO isolate to situation that visible tab has undefined height + try { + client.handleComponentRelativeSize(getWidget().tp + .getWidget(getWidget().tp.getVisibleWidget())); + } catch (Exception e) { + // Ignore, most likely empty tabsheet + } + + getWidget().waitingForResponse = false; + } + + @Override + protected Widget createWidget() { + return GWT.create(VTabsheet.class); + } + + @Override + public VTabsheet getWidget() { + return (VTabsheet) super.getWidget(); + } + + public void updateCaption(ComponentConnector component) { + /* Tabsheet does not render its children's captions */ + } + + public void layout() { + VTabsheet tabsheet = getWidget(); + + tabsheet.updateContentNodeHeight(); + + if (isUndefinedWidth()) { + tabsheet.contentNode.getStyle().setProperty("width", ""); + } else { + int contentWidth = tabsheet.getOffsetWidth() + - tabsheet.getContentAreaBorderWidth(); + if (contentWidth < 0) { + contentWidth = 0; + } + tabsheet.contentNode.getStyle().setProperty("width", + contentWidth + "px"); + } + + tabsheet.updateOpenTabSize(); + if (isUndefinedWidth()) { + tabsheet.updateDynamicWidth(); + } + + tabsheet.iLayout(); + + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java index f1a5b31379..c97ede1252 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java @@ -2,14 +2,15 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.tabsheet; import java.util.Iterator; -import java.util.Set; +import java.util.List; import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Visibility; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableElement; import com.google.gwt.event.dom.client.BlurEvent; @@ -35,15 +36,16 @@ import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.impl.FocusImpl; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderInformation; -import com.vaadin.terminal.gwt.client.RenderSpace; import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.ui.label.VLabel; public class VTabsheet extends VTabsheetBase implements Focusable, FocusHandler, BlurHandler, KeyDownHandler { @@ -239,27 +241,33 @@ public class VTabsheet extends VTabsheetBase implements Focusable, private ApplicationConnection client; TabCaption(Tab tab, ApplicationConnection client) { - super(null, client); + super(client); this.client = client; this.tab = tab; } - @Override public boolean updateCaption(UIDL uidl) { - if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION) - || uidl.hasAttribute(ATTRIBUTE_ERROR)) { + if (uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)) { TooltipInfo tooltipInfo = new TooltipInfo(); - tooltipInfo.setTitle(uidl - .getStringAttribute(ATTRIBUTE_DESCRIPTION)); - if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { - tooltipInfo.setErrorUidl(uidl.getErrors()); - } + tooltipInfo + .setTitle(uidl + .getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION)); + tooltipInfo + .setErrorMessage(uidl + .getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE)); client.registerTooltip(getTabsheet(), getElement(), tooltipInfo); } else { client.registerTooltip(getTabsheet(), getElement(), null); } - boolean ret = super.updateCaption(uidl); + // TODO need to call this instead of super because the caption does + // not have an owner + boolean ret = updateCaptionWithoutOwner( + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION), + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED), + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION), + uidl.hasAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE), + uidl.getStringAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON)); setClosable(uidl.hasAttribute("closable")); @@ -291,33 +299,6 @@ public class VTabsheet extends VTabsheetBase implements Focusable, return tab; } - @Override - public void setWidth(String width) { - super.setWidth(width); - if (BrowserInfo.get().isIE7()) { - /* - * IE7 apparently has problems with calculating width for - * floated elements inside a DIV with padding. Set the width - * explicitly for the caption. - */ - fixTextWidth(); - } - } - - private void fixTextWidth() { - Element captionText = getTextElement(); - if (captionText == null) { - return; - } - - int captionWidth = Util.getRequiredWidth(captionText); - int scrollWidth = captionText.getScrollWidth(); - if (scrollWidth > captionWidth) { - captionWidth = scrollWidth; - } - captionText.getStyle().setPropertyPx("width", captionWidth); - } - public void setClosable(boolean closable) { this.closable = closable; if (closable && closeButton == null) { @@ -552,45 +533,32 @@ public class VTabsheet extends VTabsheetBase implements Focusable, // Can't use "style" as it's already in use public static final String TAB_STYLE_NAME = "tabstyle"; + final Element tabs; // tabbar and 'scroller' container + Tab focusedTab; + /** + * The tabindex property (position in the browser's focus cycle.) Named like + * this to avoid confusion with activeTabIndex. + */ + int tabulatorIndex = 0; + private static final FocusImpl focusImpl = FocusImpl.getFocusImplForPanel(); - private final Element tabs; // tabbar and 'scroller' container private final Element scroller; // tab-scroller element private final Element scrollerNext; // tab-scroller next button element private final Element scrollerPrev; // tab-scroller prev button element - private Tab focusedTab; - - /** - * The tabindex property (position in the browser's focus cycle.) Named like - * this to avoid confusion with activeTabIndex. - */ - private int tabulatorIndex = 0; - /** * The index of the first visible tab (when scrolled) */ private int scrollerIndex = 0; - private final TabBar tb = new TabBar(this); - private final VTabsheetPanel tp = new VTabsheetPanel(); - private final Element contentNode, deco; - - private String height; - private String width; + final TabBar tb = new TabBar(this); + final VTabsheetPanel tp = new VTabsheetPanel(); + final Element contentNode; - private boolean waitingForResponse; + private final Element deco; - private final RenderInformation renderInformation = new RenderInformation(); - - /** - * Previous visible widget is set invisible with CSS (not display: none, but - * visibility: hidden), to avoid flickering during render process. Normal - * visibility must be returned later when new widget is rendered. - */ - private Widget previousVisibleWidget; - - private boolean rendering = false; + boolean waitingForResponse; private String currentStyle; @@ -615,18 +583,14 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } addStyleDependentName("loading"); - // run updating variables in deferred command to bypass some FF - // optimization issues - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - previousVisibleWidget = tp.getWidget(tp.getVisibleWidget()); - DOM.setStyleAttribute( - DOM.getParent(previousVisibleWidget.getElement()), - "visibility", "hidden"); - client.updateVariable(id, "selected", tabKeys.get(tabIndex) - .toString(), true); - } - }); + // Hide the current contents so a loading indicator can be shown + // instead + Widget currentlyDisplayedWidget = tp.getWidget(tp + .getVisibleWidget()); + currentlyDisplayedWidget.getElement().getParentElement().getStyle() + .setVisibility(Visibility.HIDDEN); + client.updateVariable(id, "selected", tabKeys.get(tabIndex) + .toString(), true); waitingForResponse = true; } // Note that we return true when tabIndex == activeTabIndex; the active @@ -651,12 +615,16 @@ public class VTabsheet extends VTabsheetBase implements Focusable, client.updateVariable(id, "close", tabKeys.get(tabIndex), true); } - private boolean isDynamicWidth() { - return width == null || width.equals(""); + boolean isDynamicWidth() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + return paintable.isUndefinedWidth(); } - private boolean isDynamicHeight() { - return height == null || height.equals(""); + boolean isDynamicHeight() { + ComponentConnector paintable = ConnectorMap.get(client).getConnector( + this); + return paintable.isUndefinedHeight(); } public VTabsheet() { @@ -742,85 +710,24 @@ public class VTabsheet extends VTabsheetBase implements Focusable, return scrollerIndex > index; } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - rendering = true; - - if (!uidl.getBooleanAttribute("cached")) { - // Handle stylename changes before generics (might affect size - // calculations) - handleStyleNames(uidl); - } - - super.updateFromUIDL(uidl, client); - if (cachedUpdate) { - rendering = false; - return; - } - - // tabs; push or not - if (!isDynamicWidth()) { - DOM.setStyleAttribute(tabs, "overflow", "hidden"); - } else { - showAllTabs(); - DOM.setStyleAttribute(tabs, "width", ""); - DOM.setStyleAttribute(tabs, "overflow", "visible"); - updateDynamicWidth(); - } - - if (!isDynamicHeight()) { - // Must update height after the styles have been set - updateContentNodeHeight(); - updateOpenTabSize(); - } - - if (uidl.hasAttribute("tabindex")) { - tabulatorIndex = uidl.getIntAttribute("tabindex"); - if (tabulatorIndex == -1) { - blur(); - } - } - - // If a tab was focused before, focus the new active tab - if (focusedTab != null && tb.getTabCount() > 0 && tabulatorIndex != -1) { - focus(); - } - - iLayout(); - // Re run relative size update to ensure optimal scrollbars - // TODO isolate to situation that visible tab has undefined height - try { - client.handleComponentRelativeSize(tp.getWidget(tp - .getVisibleWidget())); - } catch (Exception e) { - // Ignore, most likely empty tabsheet - } - - renderInformation.updateSize(getElement()); - - waitingForResponse = false; - rendering = false; - } - - private void handleStyleNames(UIDL uidl) { + void handleStyleNames(UIDL uidl, ComponentState state) { // Add proper stylenames for all elements (easier to prevent unwanted // style inheritance) - if (uidl.hasAttribute("style")) { - final String style = uidl.getStringAttribute("style"); - if (currentStyle != style) { - currentStyle = style; - final String[] styles = style.split(" "); + if (state.hasStyles()) { + final List<String> styles = state.getStyles(); + if (!currentStyle.equals(styles.toString())) { + currentStyle = styles.toString(); final String tabsBaseClass = TABS_CLASSNAME; String tabsClass = tabsBaseClass; final String contentBaseClass = CLASSNAME + "-content"; String contentClass = contentBaseClass; final String decoBaseClass = CLASSNAME + "-deco"; String decoClass = decoBaseClass; - for (int i = 0; i < styles.length; i++) { - tb.addStyleDependentName(styles[i]); - tabsClass += " " + tabsBaseClass + "-" + styles[i]; - contentClass += " " + contentBaseClass + "-" + styles[i]; - decoClass += " " + decoBaseClass + "-" + styles[i]; + for (String style : styles) { + tb.addStyleDependentName(style); + tabsClass += " " + tabsBaseClass + "-" + style; + contentClass += " " + contentBaseClass + "-" + style; + decoClass += " " + decoBaseClass + "-" + style; } DOM.setElementProperty(tabs, "className", tabsClass); DOM.setElementProperty(contentNode, "className", contentClass); @@ -844,7 +751,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } } - private void updateDynamicWidth() { + void updateDynamicWidth() { // Find width consumed by tabs TableCellElement spacerCell = ((TableElement) tb.getElement().cast()) .getRows().getItem(0).getCells().getItem(tb.getTabCount()); @@ -921,22 +828,24 @@ public class VTabsheet extends VTabsheetBase implements Focusable, tab.recalculateCaptionWidth(); UIDL tabContentUIDL = null; - Paintable tabContent = null; + ComponentConnector tabContentPaintable = null; + Widget tabContentWidget = null; if (tabUidl.getChildCount() > 0) { tabContentUIDL = tabUidl.getChildUIDL(0); - tabContent = client.getPaintable(tabContentUIDL); + tabContentPaintable = client.getPaintable(tabContentUIDL); + tabContentWidget = tabContentPaintable.getWidget(); } - if (tabContent != null) { + if (tabContentPaintable != null) { /* This is a tab with content information */ - int oldIndex = tp.getWidgetIndex((Widget) tabContent); + int oldIndex = tp.getWidgetIndex(tabContentWidget); if (oldIndex != -1 && oldIndex != index) { /* * The tab has previously been rendered in another position so * we must move the cached content to correct position */ - tp.insert((Widget) tabContent, index); + tp.insert(tabContentWidget, index); } } else { /* A tab whose content has not yet been loaded */ @@ -960,10 +869,9 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } else { if (tabContentUIDL != null) { // updating a drawn child on hidden tab - if (tp.getWidgetIndex((Widget) tabContent) < 0) { - tp.insert((Widget) tabContent, index); + if (tp.getWidgetIndex(tabContentWidget) < 0) { + tp.insert(tabContentWidget, index); } - tabContent.updateFromUIDL(tabContentUIDL, client); } else if (tp.getWidgetCount() <= index) { tp.add(new PlaceHolder()); } @@ -986,57 +894,39 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } private void renderContent(final UIDL contentUIDL) { - final Paintable content = client.getPaintable(contentUIDL); + final ComponentConnector content = client.getPaintable(contentUIDL); + Widget newWidget = content.getWidget(); if (tp.getWidgetCount() > activeTabIndex) { Widget old = tp.getWidget(activeTabIndex); - if (old != content) { + if (old != newWidget) { tp.remove(activeTabIndex); - if (old instanceof Paintable) { - client.unregisterPaintable((Paintable) old); + ConnectorMap paintableMap = ConnectorMap.get(client); + if (paintableMap.isConnector(old)) { + paintableMap.unregisterConnector(paintableMap + .getConnector(old)); } - tp.insert((Widget) content, activeTabIndex); + tp.insert(content.getWidget(), activeTabIndex); } } else { - tp.add((Widget) content); + tp.add(content.getWidget()); } tp.showWidget(activeTabIndex); VTabsheet.this.iLayout(); - (content).updateFromUIDL(contentUIDL, client); /* * The size of a cached, relative sized component must be updated to * report correct size to updateOpenTabSize(). */ if (contentUIDL.getBooleanAttribute("cached")) { - client.handleComponentRelativeSize((Widget) content); + client.handleComponentRelativeSize(content.getWidget()); } updateOpenTabSize(); VTabsheet.this.removeStyleDependentName("loading"); - if (previousVisibleWidget != null) { - DOM.setStyleAttribute( - DOM.getParent(previousVisibleWidget.getElement()), - "visibility", ""); - previousVisibleWidget = null; - } - } - - @Override - public void setHeight(String height) { - super.setHeight(height); - this.height = height; - updateContentNodeHeight(); - - if (!rendering) { - updateOpenTabSize(); - iLayout(); - // TODO Check if this is needed - client.runDescendentsLayout(this); - } } - private void updateContentNodeHeight() { - if (height != null && !"".equals(height)) { + void updateContentNodeHeight() { + if (!isDynamicHeight()) { int contentHeight = getOffsetHeight(); contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight"); contentHeight -= tb.getOffsetHeight(); @@ -1046,55 +936,13 @@ public class VTabsheet extends VTabsheetBase implements Focusable, // Set proper values for content element DOM.setStyleAttribute(contentNode, "height", contentHeight + "px"); - renderSpace.setHeight(contentHeight); } else { DOM.setStyleAttribute(contentNode, "height", ""); - renderSpace.setHeight(0); - } - } - - @Override - public void setWidth(String width) { - if ((this.width == null && width.equals("")) - || (this.width != null && this.width.equals(width))) { - return; - } - - super.setWidth(width); - if (width.equals("")) { - width = null; } - this.width = width; - if (width == null) { - renderSpace.setWidth(0); - contentNode.getStyle().setProperty("width", ""); - } else { - int contentWidth = getOffsetWidth() - getContentAreaBorderWidth(); - if (contentWidth < 0) { - contentWidth = 0; - } - contentNode.getStyle().setProperty("width", contentWidth + "px"); - renderSpace.setWidth(contentWidth); - } - - if (!rendering) { - if (isDynamicHeight()) { - Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, tp, - this); - } - - updateOpenTabSize(); - iLayout(); - // TODO Check if this is needed - client.runDescendentsLayout(this); - - } - } public void iLayout() { updateTabScroller(); - tp.runWebkitOverflowAutoFix(); } /** @@ -1102,7 +950,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, * position: absolute (to work around a firefox flickering bug) we must keep * this up-to-date by hand. */ - private void updateOpenTabSize() { + void updateOpenTabSize() { /* * The overflow=auto element must have a height specified, otherwise it * will be just as high as the contents and no scrollbars will appear @@ -1112,10 +960,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, int minWidth = 0; if (!isDynamicHeight()) { - height = renderSpace.getHeight(); + height = contentNode.getOffsetHeight(); } if (!isDynamicWidth()) { - width = renderSpace.getWidth(); + width = contentNode.getOffsetWidth() - getContentAreaBorderWidth(); } else { /* * If the tabbar is wider than the content we need to use the tabbar @@ -1132,8 +980,11 @@ public class VTabsheet extends VTabsheetBase implements Focusable, * Layouts the tab-scroller elements, and applies styles. */ private void updateTabScroller() { - if (width != null) { - DOM.setStyleAttribute(tabs, "width", width); + if (!isDynamicWidth()) { + ComponentConnector paintable = ConnectorMap.get(client) + .getConnector(this); + DOM.setStyleAttribute(tabs, "width", paintable.getState() + .getWidth()); } // Make sure scrollerIndex is valid @@ -1178,7 +1029,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } - private void showAllTabs() { + void showAllTabs() { scrollerIndex = tb.getFirstVisibleTab(); for (int i = 0; i < tb.getTabCount(); i++) { Tab t = tb.getTab(i); @@ -1215,92 +1066,29 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } @Override - protected Iterator getPaintableIterator() { + protected Iterator<Widget> getWidgetIterator() { return tp.iterator(); } - public boolean hasChildComponent(Widget component) { - if (tp.getWidgetIndex(component) < 0) { - return false; - } else { - return true; - } - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - tp.replaceComponent(oldComponent, newComponent); - } - - public void updateCaption(Paintable component, UIDL uidl) { - /* Tabsheet does not render its children's captions */ - } - - public boolean requestLayout(Set<Paintable> child) { - if (!isDynamicHeight() && !isDynamicWidth()) { - /* - * If the height and width has been specified for this container the - * child components cannot make the size of the layout change - */ - // layout size change may affect its available space (scrollbars) - for (Paintable paintable : child) { - client.handleComponentRelativeSize((Widget) paintable); - } - return true; - } - - updateOpenTabSize(); - - if (renderInformation.updateSize(getElement())) { - /* - * Size has changed so we let the child components know about the - * new size. - */ - iLayout(); - client.runDescendentsLayout(this); - /* - * Firefox and IE9 need a nudge to prevent unwanted scrollbars with - * Chameleon theme (#8625) - */ - if (BrowserInfo.get().isFirefox() || BrowserInfo.get().isIE9()) { - Util.setStyleTemporarily((Element) tp.getElement() - .getFirstChildElement(), "overflow", ""); - } - return false; - } else { - /* - * Size has not changed so we do not need to propagate the event - * further - */ - return true; - } - - } - private int borderW = -1; - private int getContentAreaBorderWidth() { + int getContentAreaBorderWidth() { if (borderW < 0) { borderW = Util.measureHorizontalBorder(contentNode); } return borderW; } - private final RenderSpace renderSpace = new RenderSpace(0, 0, true); - - public RenderSpace getAllocatedSpace(Widget child) { - // All tabs have equal amount of space allocated - return renderSpace; - } - @Override protected int getTabCount() { return tb.getTabCount(); } @Override - protected Paintable getTab(int index) { + protected ComponentConnector getTab(int index) { if (tp.getWidgetCount() > index) { - return (Paintable) tp.getWidget(index); + Widget widget = tp.getWidget(index); + return ConnectorMap.get(client).getConnector(widget); } return null; } diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetBase.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetBase.java new file mode 100644 index 0000000000..ed9883dd35 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetBase.java @@ -0,0 +1,75 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.tabsheet; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.UIDL; + +public abstract class VTabsheetBase extends ComplexPanel { + + protected String id; + protected ApplicationConnection client; + + protected final ArrayList<String> tabKeys = new ArrayList<String>(); + protected int activeTabIndex = 0; + protected boolean disabled; + protected boolean readonly; + protected Set<String> disabledTabKeys = new HashSet<String>(); + + public VTabsheetBase(String classname) { + setElement(DOM.createDiv()); + setStyleName(classname); + } + + /** + * @return a list of currently shown Widgets + */ + abstract protected Iterator<Widget> getWidgetIterator(); + + /** + * Clears current tabs and contents + */ + abstract protected void clearPaintables(); + + /** + * Implement in extending classes. This method should render needed elements + * and set the visibility of the tab according to the 'selected' parameter. + */ + protected abstract void renderTab(final UIDL tabUidl, int index, + boolean selected, boolean hidden); + + /** + * Implement in extending classes. This method should render any previously + * non-cached content and set the activeTabIndex property to the specified + * index. + */ + protected abstract void selectTab(int index, final UIDL contentUidl); + + /** + * Implement in extending classes. This method should return the number of + * tabs currently rendered. + */ + protected abstract int getTabCount(); + + /** + * Implement in extending classes. This method should return the Paintable + * corresponding to the given index. + */ + protected abstract ComponentConnector getTab(int index); + + /** + * Implement in extending classes. This method should remove the rendered + * tab with the specified index. + */ + protected abstract void removeTab(int index); +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java index 126b0ebea1..f2b37c3a1c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.tabsheet; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.NodeList; @@ -13,12 +13,12 @@ import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate; /** * A panel that displays all of its child widgets in a 'deck', where only one * can be visible at a time. It is used by - * {@link com.vaadin.terminal.gwt.client.ui.VTabsheet}. + * {@link com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheet}. * * This class has the same basic functionality as the GWT DeckPanel * {@link com.google.gwt.user.client.ui.DeckPanel}, with the exception that it @@ -141,8 +141,11 @@ public class VTabsheetPanel extends ComplexPanel { hide(DOM.getParent(visibleWidget.getElement())); } visibleWidget = newVisible; - unHide(DOM.getParent(visibleWidget.getElement())); } + // Always ensure the selected tab is visible. If server prevents a tab + // change we might end up here with visibleWidget == newVisible but its + // parent is still hidden. + unHide(DOM.getParent(visibleWidget.getElement())); } private void hide(Element e) { @@ -190,16 +193,12 @@ public class VTabsheetPanel extends ComplexPanel { getElement().getStyle().setPropertyPx("height", height); // widget wrapper height - wrapperDiv.getStyle().setPropertyPx("height", height); - runWebkitOverflowAutoFix(); - } - - public void runWebkitOverflowAutoFix() { - if (visibleWidget != null) { - Util.runWebkitOverflowAutoFix(DOM.getParent(visibleWidget - .getElement())); + if (dynamicHeight) { + wrapperDiv.getStyle().clearHeight(); + } else { + // widget wrapper height + wrapperDiv.getStyle().setPropertyPx("height", height); } - } public void replaceComponent(Widget oldComponent, Widget newComponent) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/textarea/TextAreaConnector.java b/src/com/vaadin/terminal/gwt/client/ui/textarea/TextAreaConnector.java new file mode 100644 index 0000000000..0f3ae0ad4f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/textarea/TextAreaConnector.java @@ -0,0 +1,42 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.textarea; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.textfield.TextFieldConnector; +import com.vaadin.ui.TextArea; + +@Connect(TextArea.class) +public class TextAreaConnector extends TextFieldConnector { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Call parent renderer explicitly + super.updateFromUIDL(uidl, client); + + if (uidl.hasAttribute("rows")) { + getWidget().setRows(uidl.getIntAttribute("rows")); + } + + if (getWidget().getMaxLength() >= 0) { + getWidget().sinkEvents(Event.ONKEYUP); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VTextArea.class); + } + + @Override + public VTextArea getWidget() { + return (VTextArea) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/textarea/VTextArea.java index c6107e3b0e..c600b2fd1e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java +++ b/src/com/vaadin/terminal/gwt/client/ui/textarea/VTextArea.java @@ -2,15 +2,14 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.textarea; import com.google.gwt.core.client.Scheduler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; /** * This class represents a multiline textfield (textarea). @@ -29,20 +28,6 @@ public class VTextArea extends VTextField { setStyleName(CLASSNAME); } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Call parent renderer explicitly - super.updateFromUIDL(uidl, client); - - if (uidl.hasAttribute("rows")) { - setRows(uidl.getIntAttribute("rows")); - } - - if (getMaxLength() >= 0) { - sinkEvents(Event.ONKEYUP); - } - } - public void setRows(int rows) { setRows(getElement(), rows); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/textfield/TextFieldConnector.java b/src/com/vaadin/terminal/gwt/client/ui/textfield/TextFieldConnector.java new file mode 100644 index 0000000000..7e9e786676 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/textfield/TextFieldConnector.java @@ -0,0 +1,123 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.textfield; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractFieldConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; +import com.vaadin.ui.TextField; + +@Connect(value = TextField.class, loadStyle = LoadStyle.EAGER) +public class TextFieldConnector extends AbstractFieldConnector implements + Paintable, BeforeShortcutActionListener { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Save details + getWidget().client = client; + getWidget().paintableId = uidl.getId(); + + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().setReadOnly(isReadOnly()); + + getWidget().inputPrompt = uidl + .getStringAttribute(VTextField.ATTR_INPUTPROMPT); + + getWidget().setMaxLength( + uidl.hasAttribute("maxLength") ? uidl + .getIntAttribute("maxLength") : -1); + + getWidget().immediate = getState().isImmediate(); + + getWidget().listenTextChangeEvents = hasEventListener("ie"); + if (getWidget().listenTextChangeEvents) { + getWidget().textChangeEventMode = uidl + .getStringAttribute(VTextField.ATTR_TEXTCHANGE_EVENTMODE); + if (getWidget().textChangeEventMode + .equals(VTextField.TEXTCHANGE_MODE_EAGER)) { + getWidget().textChangeEventTimeout = 1; + } else { + getWidget().textChangeEventTimeout = uidl + .getIntAttribute(VTextField.ATTR_TEXTCHANGE_TIMEOUT); + if (getWidget().textChangeEventTimeout < 1) { + // Sanitize and allow lazy/timeout with timeout set to 0 to + // work as eager + getWidget().textChangeEventTimeout = 1; + } + } + getWidget().sinkEvents(VTextField.TEXTCHANGE_EVENTS); + getWidget().attachCutEventListener(getWidget().getElement()); + } + + if (uidl.hasAttribute("cols")) { + getWidget().setColumns( + new Integer(uidl.getStringAttribute("cols")).intValue()); + } + + final String text = uidl.getStringVariable("text"); + + /* + * We skip the text content update if field has been repainted, but text + * has not been changed. Additional sanity check verifies there is no + * change in the que (in which case we count more on the server side + * value). + */ + if (!(uidl + .getBooleanAttribute(VTextField.ATTR_NO_VALUE_CHANGE_BETWEEN_PAINTS) + && getWidget().valueBeforeEdit != null && text + .equals(getWidget().valueBeforeEdit))) { + getWidget().updateFieldContent(text); + } + + if (uidl.hasAttribute("selpos")) { + final int pos = uidl.getIntAttribute("selpos"); + final int length = uidl.getIntAttribute("sellen"); + /* + * Gecko defers setting the text so we need to defer the selection. + */ + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + getWidget().setSelectionRange(pos, length); + } + }); + } + + // Here for backward compatibility; to be moved to TextArea. + // Optimization: server does not send attribute for the default 'true' + // state. + if (uidl.hasAttribute("wordwrap") + && uidl.getBooleanAttribute("wordwrap") == false) { + getWidget().setWordwrap(false); + } else { + getWidget().setWordwrap(true); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VTextField.class); + } + + @Override + public VTextField getWidget() { + return (VTextField) super.getWidget(); + } + + public void onBeforeShortcutAction(Event e) { + getWidget().valueChange(false); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java index d1e4f7ca5b..7bd392b503 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/textfield/VTextField.java @@ -2,9 +2,8 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.textfield; -import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; @@ -15,7 +14,6 @@ import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -24,11 +22,9 @@ import com.google.gwt.user.client.ui.TextBoxBase; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VTooltip; -import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; +import com.vaadin.terminal.gwt.client.ui.Field; /** * This class represents a basic text input field with one row. @@ -36,9 +32,8 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutAct * @author Vaadin Ltd. * */ -public class VTextField extends TextBoxBase implements Paintable, Field, - ChangeHandler, FocusHandler, BlurHandler, BeforeShortcutActionListener, - KeyDownHandler { +public class VTextField extends TextBoxBase implements Field, ChangeHandler, + FocusHandler, BlurHandler, KeyDownHandler { public static final String VAR_CUR_TEXT = "curText"; @@ -52,11 +47,11 @@ public class VTextField extends TextBoxBase implements Paintable, Field, */ public static final String CLASSNAME_FOCUS = "focus"; - protected String id; + protected String paintableId; protected ApplicationConnection client; - private String valueBeforeEdit = null; + protected String valueBeforeEdit = null; /** * Set to false if a text change event has been sent since the last value @@ -65,20 +60,18 @@ public class VTextField extends TextBoxBase implements Paintable, Field, */ private boolean valueBeforeEditIsSynced = true; - private boolean immediate = false; - private int extraHorizontalPixels = -1; - private int extraVerticalPixels = -1; + protected boolean immediate = false; private int maxLength = -1; private static final String CLASSNAME_PROMPT = "prompt"; - private static final String ATTR_INPUTPROMPT = "prompt"; + protected static final String ATTR_INPUTPROMPT = "prompt"; public static final String ATTR_TEXTCHANGE_TIMEOUT = "iet"; public static final String VAR_CURSOR = "c"; public static final String ATTR_TEXTCHANGE_EVENTMODE = "iem"; - private static final String TEXTCHANGE_MODE_EAGER = "EAGER"; + protected static final String TEXTCHANGE_MODE_EAGER = "EAGER"; private static final String TEXTCHANGE_MODE_TIMEOUT = "TIMEOUT"; - private String inputPrompt = null; + protected String inputPrompt = null; private boolean prompting = false; private int lastCursorPos = -1; private boolean wordwrap = true; @@ -89,12 +82,6 @@ public class VTextField extends TextBoxBase implements Paintable, Field, protected VTextField(Element node) { super(node); - if (BrowserInfo.get().getIEVersion() > 0 - && BrowserInfo.get().getIEVersion() < 8) { - // Fixes IE margin problem (#2058) - DOM.setStyleAttribute(node, "marginTop", "-1px"); - DOM.setStyleAttribute(node, "marginBottom", "-1px"); - } setStyleName(CLASSNAME); addChangeHandler(this); if (BrowserInfo.get().isIE()) { @@ -117,7 +104,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, * Eager polling for a change is bit dum and heavy operation, so I guess we * should first try to survive without. */ - private static final int TEXTCHANGE_EVENTS = Event.ONPASTE + protected static final int TEXTCHANGE_EVENTS = Event.ONPASTE | Event.KEYEVENTS | Event.ONMOUSEUP; @Override @@ -163,7 +150,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, client.sendPendingVariableChanges(); } else { // Default case - just send an immediate text change message - client.updateVariable(id, VAR_CUR_TEXT, text, true); + client.updateVariable(paintableId, VAR_CUR_TEXT, text, true); // Shouldn't investigate valueBeforeEdit to avoid duplicate text // change events as the states are not in sync any more @@ -185,9 +172,9 @@ public class VTextField extends TextBoxBase implements Paintable, Field, } }; private boolean scheduled = false; - private boolean listenTextChangeEvents; - private String textChangeEventMode; - private int textChangeEventTimeout; + protected boolean listenTextChangeEvents; + protected String textChangeEventMode; + protected int textChangeEventTimeout; private void deferTextChangeEvent() { if (textChangeEventMode.equals(TEXTCHANGE_MODE_TIMEOUT) && scheduled) { @@ -220,129 +207,19 @@ public class VTextField extends TextBoxBase implements Paintable, Field, super.setReadOnly(readOnly); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - id = uidl.getId(); - - if (client.updateComponent(this, uidl, true)) { - return; - } - - if (uidl.getBooleanAttribute("readonly")) { - setReadOnly(true); - } else { - setReadOnly(false); - } - - inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT); - - setMaxLength(uidl.hasAttribute("maxLength") ? uidl - .getIntAttribute("maxLength") : -1); - - immediate = uidl.getBooleanAttribute("immediate"); - - listenTextChangeEvents = client.hasEventListeners(this, "ie"); - if (listenTextChangeEvents) { - textChangeEventMode = uidl - .getStringAttribute(ATTR_TEXTCHANGE_EVENTMODE); - if (textChangeEventMode.equals(TEXTCHANGE_MODE_EAGER)) { - textChangeEventTimeout = 1; - } else { - textChangeEventTimeout = uidl - .getIntAttribute(ATTR_TEXTCHANGE_TIMEOUT); - if (textChangeEventTimeout < 1) { - // Sanitize and allow lazy/timeout with timeout set to 0 to - // work as eager - textChangeEventTimeout = 1; - } - } - sinkEvents(TEXTCHANGE_EVENTS); - attachCutEventListener(getElement()); - } - - if (uidl.hasAttribute("cols")) { - setColumns(new Integer(uidl.getStringAttribute("cols")).intValue()); - } - - final String text = uidl.getStringVariable("text"); - - /* - * We skip the text content update if field has been repainted, but text - * has not been changed. Additional sanity check verifies there is no - * change in the que (in which case we count more on the server side - * value). - */ - if (!(uidl.getBooleanAttribute(ATTR_NO_VALUE_CHANGE_BETWEEN_PAINTS) - && valueBeforeEdit != null && text.equals(valueBeforeEdit))) { - updateFieldContent(text); - } - - if (uidl.hasAttribute("selpos")) { - final int pos = uidl.getIntAttribute("selpos"); - final int length = uidl.getIntAttribute("sellen"); - /* - * Gecko defers setting the text so we need to defer the selection. - */ - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - setSelectionRange(pos, length); - } - }); - } - - // Here for backward compatibility; to be moved to TextArea. - // Optimization: server does not send attribute for the default 'true' - // state. - if (uidl.hasAttribute("wordwrap") - && uidl.getBooleanAttribute("wordwrap") == false) { - setWordwrap(false); - } else { - setWordwrap(true); - } - } - - private void updateFieldContent(final String text) { + protected void updateFieldContent(final String text) { setPrompting(inputPrompt != null && focusedTextField != this && (text.equals(""))); - if (BrowserInfo.get().isFF3()) { - /* - * Firefox 3 is really sluggish when updating input attached to dom. - * Some optimizations seems to work much better in Firefox3 if we - * update the actual content lazily when the rest of the DOM has - * stabilized. In tests, about ten times better performance is - * achieved with this optimization. See for eg. #2898 - */ - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - String fieldValue; - if (prompting) { - fieldValue = isReadOnly() ? "" : inputPrompt; - addStyleDependentName(CLASSNAME_PROMPT); - } else { - fieldValue = text; - removeStyleDependentName(CLASSNAME_PROMPT); - } - /* - * Avoid resetting the old value. Prevents cursor flickering - * which then again happens due to this Gecko hack. - */ - if (!getText().equals(fieldValue)) { - setText(fieldValue); - } - } - }); + String fieldValue; + if (prompting) { + fieldValue = isReadOnly() ? "" : inputPrompt; + addStyleDependentName(CLASSNAME_PROMPT); } else { - String fieldValue; - if (prompting) { - fieldValue = isReadOnly() ? "" : inputPrompt; - addStyleDependentName(CLASSNAME_PROMPT); - } else { - fieldValue = text; - removeStyleDependentName(CLASSNAME_PROMPT); - } - setText(fieldValue); + fieldValue = text; + removeStyleDependentName(CLASSNAME_PROMPT); } + setText(fieldValue); lastTextChangeString = valueBeforeEdit = text; valueBeforeEditIsSynced = true; @@ -358,7 +235,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, /*-{ var me = this; el.oncut = $entry(function() { - me.@com.vaadin.terminal.gwt.client.ui.VTextField::onCut()(); + me.@com.vaadin.terminal.gwt.client.ui.textfield.VTextField::onCut()(); }); }-*/; @@ -384,7 +261,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, } } - private void setMaxLength(int newMaxLength) { + protected void setMaxLength(int newMaxLength) { if (newMaxLength >= 0) { maxLength = newMaxLength; if (getElement().getTagName().toLowerCase().equals("textarea")) { @@ -403,7 +280,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, } - protected int getMaxLength() { + public int getMaxLength() { return maxLength; } @@ -420,20 +297,20 @@ public class VTextField extends TextBoxBase implements Paintable, Field, * true if the field was blurred */ public void valueChange(boolean blurred) { - if (client != null && id != null) { + if (client != null && paintableId != null) { boolean sendBlurEvent = false; boolean sendValueChange = false; if (blurred && client.hasEventListeners(this, EventId.BLUR)) { sendBlurEvent = true; - client.updateVariable(id, EventId.BLUR, "", false); + client.updateVariable(paintableId, EventId.BLUR, "", false); } String newText = getText(); if (!prompting && newText != null && !newText.equals(valueBeforeEdit)) { sendValueChange = immediate; - client.updateVariable(id, "text", getText(), false); + client.updateVariable(paintableId, "text", getText(), false); valueBeforeEdit = newText; valueBeforeEditIsSynced = true; } @@ -466,7 +343,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field, if (Util.isAttachedAndDisplayed(this)) { int cursorPos = getCursorPos(); if (lastCursorPos != cursorPos) { - client.updateVariable(id, VAR_CURSOR, cursorPos, false); + client.updateVariable(paintableId, VAR_CURSOR, cursorPos, false); lastCursorPos = cursorPos; return true; } @@ -488,14 +365,10 @@ public class VTextField extends TextBoxBase implements Paintable, Field, setText(""); removeStyleDependentName(CLASSNAME_PROMPT); setPrompting(false); - if (BrowserInfo.get().isIE6()) { - // IE6 does not show the cursor when tabbing into the field - setCursorPos(0); - } } focusedTextField = this; if (client.hasEventListeners(this, EventId.FOCUS)) { - client.updateVariable(client.getPid(this), EventId.FOCUS, "", true); + client.updateVariable(paintableId, EventId.FOCUS, "", true); } } @@ -537,79 +410,6 @@ public class VTextField extends TextBoxBase implements Paintable, Field, } catch (e) {} }-*/; - /** - * @return space used by components paddings and borders - */ - private int getExtraHorizontalPixels() { - if (extraHorizontalPixels < 0) { - detectExtraSizes(); - } - return extraHorizontalPixels; - } - - /** - * @return space used by components paddings and borders - */ - private int getExtraVerticalPixels() { - if (extraVerticalPixels < 0) { - detectExtraSizes(); - } - return extraVerticalPixels; - } - - /** - * Detects space used by components paddings and borders. Used when - * relational size are used. - */ - private void detectExtraSizes() { - Element clone = Util.cloneNode(getElement(), false); - DOM.setElementAttribute(clone, "id", ""); - DOM.setStyleAttribute(clone, "visibility", "hidden"); - DOM.setStyleAttribute(clone, "position", "absolute"); - // due FF3 bug set size to 10px and later subtract it from extra pixels - DOM.setStyleAttribute(clone, "width", "10px"); - DOM.setStyleAttribute(clone, "height", "10px"); - DOM.appendChild(DOM.getParent(getElement()), clone); - extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10; - extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10; - - DOM.removeChild(DOM.getParent(getElement()), clone); - } - - @Override - public void setHeight(String height) { - if (height.endsWith("px")) { - int h = Integer.parseInt(height.substring(0, height.length() - 2)); - h -= getExtraVerticalPixels(); - if (h < 0) { - h = 0; - } - - super.setHeight(h + "px"); - } else { - super.setHeight(height); - } - } - - @Override - public void setWidth(String width) { - if (width.endsWith("px")) { - int w = Integer.parseInt(width.substring(0, width.length() - 2)); - w -= getExtraHorizontalPixels(); - if (w < 0) { - w = 0; - } - - super.setWidth(w + "px"); - } else { - super.setWidth(width); - } - } - - public void onBeforeShortcutAction(Event e) { - valueChange(false); - } - // Here for backward compatibility; to be moved to TextArea public void setWordwrap(boolean enabled) { if (enabled == wordwrap) { diff --git a/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java b/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java new file mode 100644 index 0000000000..ebe5d22e99 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/tree/TreeConnector.java @@ -0,0 +1,260 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.tree; + +import java.util.Iterator; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.AbstractFieldState; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.TooltipInfo; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.tree.VTree.TreeNode; +import com.vaadin.ui.Tree; + +@Connect(Tree.class) +public class TreeConnector extends AbstractComponentConnector implements + Paintable { + + public static final String ATTRIBUTE_NODE_STYLE = "style"; + public static final String ATTRIBUTE_NODE_CAPTION = "caption"; + public static final String ATTRIBUTE_NODE_ICON = "icon"; + + public static final String ATTRIBUTE_ACTION_CAPTION = "caption"; + public static final String ATTRIBUTE_ACTION_ICON = ATTRIBUTE_NODE_ICON; + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + + getWidget().rendering = true; + + getWidget().client = client; + + if (uidl.hasAttribute("partialUpdate")) { + handleUpdate(uidl); + getWidget().rendering = false; + return; + } + + getWidget().paintableId = uidl.getId(); + + getWidget().immediate = getState().isImmediate(); + + getWidget().disabled = !isEnabled(); + getWidget().readonly = isReadOnly(); + + getWidget().dragMode = uidl.hasAttribute("dragMode") ? uidl + .getIntAttribute("dragMode") : 0; + + getWidget().isNullSelectionAllowed = uidl + .getBooleanAttribute("nullselect"); + + if (uidl.hasAttribute("alb")) { + getWidget().bodyActionKeys = uidl.getStringArrayAttribute("alb"); + } + + getWidget().body.clear(); + // clear out any references to nodes that no longer are attached + getWidget().clearNodeToKeyMap(); + TreeNode childTree = null; + UIDL childUidl = null; + for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) { + childUidl = (UIDL) i.next(); + if ("actions".equals(childUidl.getTag())) { + updateActionMap(childUidl); + continue; + } else if ("-ac".equals(childUidl.getTag())) { + getWidget().updateDropHandler(childUidl); + continue; + } + childTree = getWidget().new TreeNode(); + updateNodeFromUIDL(childTree, childUidl); + getWidget().body.add(childTree); + childTree.addStyleDependentName("root"); + childTree.childNodeContainer.addStyleDependentName("root"); + } + if (childTree != null && childUidl != null) { + boolean leaf = !childUidl.getTag().equals("node"); + childTree.addStyleDependentName(leaf ? "leaf-last" : "last"); + childTree.childNodeContainer.addStyleDependentName("last"); + } + final String selectMode = uidl.getStringAttribute("selectmode"); + getWidget().selectable = !"none".equals(selectMode); + getWidget().isMultiselect = "multi".equals(selectMode); + + if (getWidget().isMultiselect) { + if (BrowserInfo.get().isTouchDevice()) { + // Always use the simple mode for touch devices that do not have + // shift/ctrl keys (#8595) + getWidget().multiSelectMode = VTree.MULTISELECT_MODE_SIMPLE; + } else { + getWidget().multiSelectMode = uidl + .getIntAttribute("multiselectmode"); + } + } + + getWidget().selectedIds = uidl.getStringArrayVariableAsSet("selected"); + + // Update lastSelection and focusedNode to point to *actual* nodes again + // after the old ones have been cleared from the body. This fixes focus + // and keyboard navigation issues as described in #7057 and other + // tickets. + if (getWidget().lastSelection != null) { + getWidget().lastSelection = getWidget().getNodeByKey( + getWidget().lastSelection.key); + } + if (getWidget().focusedNode != null) { + getWidget().setFocusedNode( + getWidget().getNodeByKey(getWidget().focusedNode.key)); + } + + if (getWidget().lastSelection == null + && getWidget().focusedNode == null + && !getWidget().selectedIds.isEmpty()) { + getWidget().setFocusedNode( + getWidget().getNodeByKey( + getWidget().selectedIds.iterator().next())); + getWidget().focusedNode.setFocused(false); + } + + getWidget().rendering = false; + + } + + @Override + protected Widget createWidget() { + return GWT.create(VTree.class); + } + + @Override + public VTree getWidget() { + return (VTree) super.getWidget(); + } + + private void handleUpdate(UIDL uidl) { + final TreeNode rootNode = getWidget().getNodeByKey( + uidl.getStringAttribute("rootKey")); + if (rootNode != null) { + if (!rootNode.getState()) { + // expanding node happened server side + rootNode.setState(true, false); + } + renderChildNodes(rootNode, (Iterator) uidl.getChildIterator()); + } + } + + /** + * Registers action for the root and also for individual nodes + * + * @param uidl + */ + private void updateActionMap(UIDL uidl) { + final Iterator<?> it = uidl.getChildIterator(); + while (it.hasNext()) { + final UIDL action = (UIDL) it.next(); + final String key = action.getStringAttribute("key"); + final String caption = action + .getStringAttribute(ATTRIBUTE_ACTION_CAPTION); + String iconUrl = null; + if (action.hasAttribute(ATTRIBUTE_ACTION_ICON)) { + iconUrl = getConnection().translateVaadinUri( + action.getStringAttribute(ATTRIBUTE_ACTION_ICON)); + } + getWidget().registerAction(key, caption, iconUrl); + } + + } + + public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl) { + String nodeKey = uidl.getStringAttribute("key"); + treeNode.setText(uidl.getStringAttribute(ATTRIBUTE_NODE_CAPTION)); + treeNode.key = nodeKey; + + getWidget().registerNode(treeNode); + + if (uidl.hasAttribute("al")) { + treeNode.actionKeys = uidl.getStringArrayAttribute("al"); + } + + if (uidl.getTag().equals("node")) { + if (uidl.getChildCount() == 0) { + treeNode.childNodeContainer.setVisible(false); + } else { + renderChildNodes(treeNode, (Iterator) uidl.getChildIterator()); + treeNode.childrenLoaded = true; + } + } else { + treeNode.addStyleName(TreeNode.CLASSNAME + "-leaf"); + } + if (uidl.hasAttribute(ATTRIBUTE_NODE_STYLE)) { + treeNode.setNodeStyleName(uidl + .getStringAttribute(ATTRIBUTE_NODE_STYLE)); + } + + String description = uidl.getStringAttribute("descr"); + if (description != null && getConnection() != null) { + // Set tooltip + TooltipInfo info = new TooltipInfo(description); + getConnection().registerTooltip(this, nodeKey, info); + } else { + // Remove possible previous tooltip + getConnection().registerTooltip(this, nodeKey, null); + } + + if (uidl.getBooleanAttribute("expanded") && !treeNode.getState()) { + treeNode.setState(true, false); + } + + if (uidl.getBooleanAttribute("selected")) { + treeNode.setSelected(true); + // ensure that identifier is in selectedIds array (this may be a + // partial update) + getWidget().selectedIds.add(nodeKey); + } + + treeNode.setIcon(uidl.getStringAttribute(ATTRIBUTE_NODE_ICON)); + } + + void renderChildNodes(TreeNode containerNode, Iterator<UIDL> i) { + containerNode.childNodeContainer.clear(); + containerNode.childNodeContainer.setVisible(true); + while (i.hasNext()) { + final UIDL childUidl = i.next(); + // actions are in bit weird place, don't mix them with children, + // but current node's actions + if ("actions".equals(childUidl.getTag())) { + updateActionMap(childUidl); + continue; + } + final TreeNode childTree = getWidget().new TreeNode(); + updateNodeFromUIDL(childTree, childUidl); + containerNode.childNodeContainer.add(childTree); + if (!i.hasNext()) { + childTree + .addStyleDependentName(childTree.isLeaf() ? "leaf-last" + : "last"); + childTree.childNodeContainer.addStyleDependentName("last"); + } + } + containerNode.childrenLoaded = true; + } + + @Override + public boolean isReadOnly() { + return super.isReadOnly() || getState().isPropertyReadOnly(); + } + + @Override + public AbstractFieldState getState() { + return (AbstractFieldState) super.getState(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/tree/VTree.java index 1d5ec206aa..6f19cba957 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/tree/VTree.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.tree; import java.util.ArrayList; import java.util.HashMap; @@ -39,12 +39,20 @@ import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.TooltipInfo; +import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.Action; +import com.vaadin.terminal.gwt.client.ui.ActionOwner; +import com.vaadin.terminal.gwt.client.ui.FocusElementPanel; +import com.vaadin.terminal.gwt.client.ui.Icon; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.TreeAction; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; import com.vaadin.terminal.gwt.client.ui.dd.DDUtil; import com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler; import com.vaadin.terminal.gwt.client.ui.dd.VAcceptCallback; @@ -58,9 +66,9 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; /** * */ -public class VTree extends FocusElementPanel implements Paintable, - VHasDropHandler, FocusHandler, BlurHandler, KeyPressHandler, - KeyDownHandler, SubPartAware, ActionOwner { +public class VTree extends FocusElementPanel implements VHasDropHandler, + FocusHandler, BlurHandler, KeyPressHandler, KeyDownHandler, + SubPartAware, ActionOwner { public static final String CLASSNAME = "v-tree"; @@ -78,17 +86,17 @@ public class VTree extends FocusElementPanel implements Paintable, private static final int CHARCODE_SPACE = 32; - private final FlowPanel body = new FlowPanel(); + final FlowPanel body = new FlowPanel(); - private Set<String> selectedIds = new HashSet<String>(); - private ApplicationConnection client; - private String paintableId; - private boolean selectable; - private boolean isMultiselect; + Set<String> selectedIds = new HashSet<String>(); + ApplicationConnection client; + String paintableId; + boolean selectable; + boolean isMultiselect; private String currentMouseOverKey; - private TreeNode lastSelection; - private TreeNode focusedNode; - private int multiSelectMode = MULTISELECT_MODE_DEFAULT; + TreeNode lastSelection; + TreeNode focusedNode; + int multiSelectMode = MULTISELECT_MODE_DEFAULT; private final HashMap<String, TreeNode> keyToNode = new HashMap<String, TreeNode>(); @@ -98,23 +106,23 @@ public class VTree extends FocusElementPanel implements Paintable, */ private final HashMap<String, String> actionMap = new HashMap<String, String>(); - private boolean immediate; + boolean immediate; - private boolean isNullSelectionAllowed = true; + boolean isNullSelectionAllowed = true; - private boolean disabled = false; + boolean disabled = false; - private boolean readonly; + boolean readonly; - private boolean rendering; + boolean rendering; private VAbstractDropHandler dropHandler; - private int dragMode; + int dragMode; private boolean selectionHasChanged = false; - private String[] bodyActionKeys; + String[] bodyActionKeys; public VLazyExecutor iconLoaded = new VLazyExecutor(50, new ScheduledCommand() { @@ -213,24 +221,6 @@ public class VTree extends FocusElementPanel implements Paintable, } } - private void updateActionMap(UIDL c) { - final Iterator<?> it = c.getChildIterator(); - while (it.hasNext()) { - final UIDL action = (UIDL) it.next(); - final String key = action.getStringAttribute("key"); - final String caption = action.getStringAttribute("caption"); - actionMap.put(key + "_c", caption); - if (action.hasAttribute("icon")) { - // TODO need some uri handling ?? - actionMap.put(key + "_i", client.translateVaadinUri(action - .getStringAttribute("icon"))); - } else { - actionMap.remove(key + "_i"); - } - } - - } - public String getActionCaption(String actionKey) { return actionMap.get(actionKey + "_c"); } @@ -239,105 +229,6 @@ public class VTree extends FocusElementPanel implements Paintable, return actionMap.get(actionKey + "_i"); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Ensure correct implementation and let container manage caption - if (client.updateComponent(this, uidl, true)) { - return; - } - - rendering = true; - - this.client = client; - - if (uidl.hasAttribute("partialUpdate")) { - handleUpdate(uidl); - rendering = false; - return; - } - - paintableId = uidl.getId(); - - immediate = uidl.hasAttribute("immediate"); - - disabled = uidl.getBooleanAttribute("disabled"); - readonly = uidl.getBooleanAttribute("readonly"); - - dragMode = uidl.hasAttribute("dragMode") ? uidl - .getIntAttribute("dragMode") : 0; - - isNullSelectionAllowed = uidl.getBooleanAttribute("nullselect"); - - if (uidl.hasAttribute("alb")) { - bodyActionKeys = uidl.getStringArrayAttribute("alb"); - } - - body.clear(); - // clear out any references to nodes that no longer are attached - keyToNode.clear(); - TreeNode childTree = null; - UIDL childUidl = null; - for (final Iterator<?> i = uidl.getChildIterator(); i.hasNext();) { - childUidl = (UIDL) i.next(); - if ("actions".equals(childUidl.getTag())) { - updateActionMap(childUidl); - continue; - } else if ("-ac".equals(childUidl.getTag())) { - updateDropHandler(childUidl); - continue; - } - childTree = new TreeNode(); - if (childTree.ie6compatnode != null) { - body.add(childTree); - } - childTree.updateFromUIDL(childUidl, client); - if (childTree.ie6compatnode == null) { - body.add(childTree); - } - childTree.addStyleDependentName("root"); - childTree.childNodeContainer.addStyleDependentName("root"); - } - if (childTree != null && childUidl != null) { - boolean leaf = !childUidl.getTag().equals("node"); - childTree.addStyleDependentName(leaf ? "leaf-last" : "last"); - childTree.childNodeContainer.addStyleDependentName("last"); - } - final String selectMode = uidl.getStringAttribute("selectmode"); - selectable = !"none".equals(selectMode); - isMultiselect = "multi".equals(selectMode); - - if (isMultiselect) { - if (BrowserInfo.get().isTouchDevice()) { - // Always use the simple mode for touch devices that do not have - // shift/ctrl keys (#8595) - multiSelectMode = MULTISELECT_MODE_SIMPLE; - } else { - multiSelectMode = uidl.getIntAttribute("multiselectmode"); - } - } - - selectedIds = uidl.getStringArrayVariableAsSet("selected"); - - // Update lastSelection and focusedNode to point to *actual* nodes again - // after the old ones have been cleared from the body. This fixes focus - // and keyboard navigation issues as described in #7057 and other - // tickets. - if (lastSelection != null) { - lastSelection = keyToNode.get(lastSelection.key); - } - if (focusedNode != null) { - setFocusedNode(keyToNode.get(focusedNode.key)); - } - - if (lastSelection == null && focusedNode == null - && !selectedIds.isEmpty()) { - setFocusedNode(keyToNode.get(selectedIds.iterator().next())); - focusedNode.setFocused(false); - } - - rendering = false; - - } - /** * Returns the first root node of the tree or null if there are no root * nodes. @@ -384,7 +275,7 @@ public class VTree extends FocusElementPanel implements Paintable, drag.getDropDetails().put("itemIdOver", currentMouseOverKey); if (currentMouseOverKey != null) { - TreeNode treeNode = keyToNode.get(currentMouseOverKey); + TreeNode treeNode = getNodeByKey(currentMouseOverKey); VerticalDropLocation detail = treeNode.getDropDetail(drag .getCurrentGwtEvent()); Boolean overTreeNode = null; @@ -406,7 +297,7 @@ public class VTree extends FocusElementPanel implements Paintable, return treeNode == null ? null : treeNode.key; } - private void updateDropHandler(UIDL childUidl) { + void updateDropHandler(UIDL childUidl) { if (dropHandler == null) { dropHandler = new VAbstractDropHandler() { @@ -448,7 +339,7 @@ public class VTree extends FocusElementPanel implements Paintable, .getDropDetails().get("detail"); if (curDetail == detail && newKey.equals(currentMouseOverKey)) { - keyToNode.get(newKey).emphasis(detail); + getNodeByKey(newKey).emphasis(detail); } /* * Else drag is already on a different @@ -470,7 +361,7 @@ public class VTree extends FocusElementPanel implements Paintable, private void cleanUp() { if (currentMouseOverKey != null) { - keyToNode.get(currentMouseOverKey).emphasis(null); + getNodeByKey(currentMouseOverKey).emphasis(null); currentMouseOverKey = null; } } @@ -482,8 +373,8 @@ public class VTree extends FocusElementPanel implements Paintable, } @Override - public Paintable getPaintable() { - return VTree.this; + public ComponentConnector getConnector() { + return ConnectorMap.get(client).getConnector(VTree.this); } public ApplicationConnection getApplicationConnection() { @@ -495,24 +386,12 @@ public class VTree extends FocusElementPanel implements Paintable, dropHandler.updateAcceptRules(childUidl); } - private void handleUpdate(UIDL uidl) { - final TreeNode rootNode = keyToNode.get(uidl - .getStringAttribute("rootKey")); - if (rootNode != null) { - if (!rootNode.getState()) { - // expanding node happened server side - rootNode.setState(true, false); - } - rootNode.renderChildNodes(uidl.getChildIterator()); - } - } - public void setSelected(TreeNode treeNode, boolean selected) { if (selected) { if (!isMultiselect) { while (selectedIds.size() > 0) { final String id = selectedIds.iterator().next(); - final TreeNode oldSelection = keyToNode.get(id); + final TreeNode oldSelection = getNodeByKey(id); if (oldSelection != null) { // can be null if the node is not visible (parent // collapsed) @@ -581,33 +460,26 @@ public class VTree extends FocusElementPanel implements Paintable, public String key; - private String[] actionKeys = null; + String[] actionKeys = null; - private boolean childrenLoaded; + boolean childrenLoaded; - private Element nodeCaptionDiv; + Element nodeCaptionDiv; protected Element nodeCaptionSpan; - private FlowPanel childNodeContainer; + FlowPanel childNodeContainer; private boolean open; private Icon icon; - private Element ie6compatnode; - private Event mouseDownEvent; private int cachedHeight = -1; private boolean focused = false; - /** - * Track onload events as IE6 sends two - */ - private boolean onloadHandled = false; - public TreeNode() { constructDom(); sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.MOUSEEVENTS @@ -705,11 +577,11 @@ public class VTree extends FocusElementPanel implements Paintable, // always when clicking an item, focus it setFocusedNode(this, false); - if (!isIE6OrOpera()) { + if (!BrowserInfo.get().isOpera()) { /* * Ensure that the tree's focus element also gains focus * (TreeNodes focus is faked using FocusElementPanel in browsers - * other than IE6 and Opera). + * other than Opera). */ focus(); } @@ -777,14 +649,7 @@ public class VTree extends FocusElementPanel implements Paintable, final Element target = DOM.eventGetTarget(event); if (type == Event.ONLOAD && target == icon.getElement()) { - if (onloadHandled) { - return; - } - if (BrowserInfo.get().isIE6()) { - fixWidth(); - } iconLoaded.trigger(); - onloadHandled = true; } if (disabled) { @@ -805,7 +670,7 @@ public class VTree extends FocusElementPanel implements Paintable, fireClick(event); } if (type == Event.ONCLICK) { - if (getElement() == target || ie6compatnode == target) { + if (getElement() == target) { // state change toggleState(); } else if (!readonly && inCaption) { @@ -860,7 +725,8 @@ public class VTree extends FocusElementPanel implements Paintable, if (mouseDownEvent != null) { // start actual drag on slight move when mouse is down VTransferable t = new VTransferable(); - t.setDragSource(VTree.this); + t.setDragSource(ConnectorMap.get(client).getConnector( + VTree.this)); t.setData("itemId", key); VDragEvent drag = VDragAndDropManager.get().startDrag( t, mouseDownEvent, true); @@ -891,7 +757,7 @@ public class VTree extends FocusElementPanel implements Paintable, * previously modified field may contain dirty variables. */ if (!treeHasFocus) { - if (isIE6OrOpera()) { + if (BrowserInfo.get().isOpera()) { if (focusedNode == null) { getNodeByKey(key).setFocused(true); } else { @@ -901,7 +767,8 @@ public class VTree extends FocusElementPanel implements Paintable, focus(); } } - final MouseEventDetails details = new MouseEventDetails(evt); + final MouseEventDetails details = MouseEventDetailsBuilder + .buildMouseEventDetails(evt); ScheduledCommand command = new ScheduledCommand() { public void execute() { // Determine if we should send the event immediately to the @@ -952,15 +819,6 @@ public class VTree extends FocusElementPanel implements Paintable, protected void constructDom() { addStyleName(CLASSNAME); - // workaround for a very weird IE6 issue #1245 - if (BrowserInfo.get().isIE6()) { - ie6compatnode = DOM.createDiv(); - setStyleName(ie6compatnode, CLASSNAME + "-ie6compatnode"); - DOM.setInnerText(ie6compatnode, " "); - DOM.appendChild(getElement(), ie6compatnode); - - DOM.sinkEvents(ie6compatnode, Event.ONCLICK); - } nodeCaptionDiv = DOM.createDiv(); DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME @@ -972,7 +830,7 @@ public class VTree extends FocusElementPanel implements Paintable, DOM.appendChild(nodeCaptionDiv, wrapper); DOM.appendChild(wrapper, nodeCaptionSpan); - if (isIE6OrOpera()) { + if (BrowserInfo.get().isOpera()) { /* * Focus the caption div of the node to get keyboard navigation * to work without scrolling up or down when focusing a node. @@ -985,76 +843,6 @@ public class VTree extends FocusElementPanel implements Paintable, setWidget(childNodeContainer); } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - setText(uidl.getStringAttribute("caption")); - key = uidl.getStringAttribute("key"); - - keyToNode.put(key, this); - - if (uidl.hasAttribute("al")) { - actionKeys = uidl.getStringArrayAttribute("al"); - } - - if (uidl.getTag().equals("node")) { - if (uidl.getChildCount() == 0) { - childNodeContainer.setVisible(false); - } else { - renderChildNodes(uidl.getChildIterator()); - childrenLoaded = true; - } - } else { - addStyleName(CLASSNAME + "-leaf"); - } - if (uidl.hasAttribute("style")) { - addStyleName(CLASSNAME + "-" + uidl.getStringAttribute("style")); - Widget.setStyleName(nodeCaptionDiv, CLASSNAME + "-caption-" - + uidl.getStringAttribute("style"), true); - childNodeContainer.addStyleName(CLASSNAME + "-children-" - + uidl.getStringAttribute("style")); - } - - String description = uidl.getStringAttribute("descr"); - if (description != null && client != null) { - // Set tooltip - TooltipInfo info = new TooltipInfo(description); - client.registerTooltip(VTree.this, key, info); - } else { - // Remove possible previous tooltip - client.registerTooltip(VTree.this, key, null); - } - - if (uidl.getBooleanAttribute("expanded") && !getState()) { - setState(true, false); - } - - if (uidl.getBooleanAttribute("selected")) { - setSelected(true); - // ensure that identifier is in selectedIds array (this may be a - // partial update) - selectedIds.add(key); - } - - if (uidl.hasAttribute("icon")) { - if (icon == null) { - onloadHandled = false; - icon = new Icon(client); - DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv), - icon.getElement(), nodeCaptionSpan); - } - icon.setUri(uidl.getStringAttribute("icon")); - } else { - if (icon != null) { - DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv), - icon.getElement()); - icon = null; - } - } - - if (BrowserInfo.get().isIE6() && isAttached()) { - fixWidth(); - } - } - public boolean isLeaf() { String[] styleNames = getStyleName().split(" "); for (String styleName : styleNames) { @@ -1065,7 +853,7 @@ public class VTree extends FocusElementPanel implements Paintable, return false; } - private void setState(boolean state, boolean notifyServer) { + void setState(boolean state, boolean notifyServer) { if (open == state) { return; } @@ -1096,43 +884,14 @@ public class VTree extends FocusElementPanel implements Paintable, } } - private boolean getState() { + boolean getState() { return open; } - private void setText(String text) { + void setText(String text) { DOM.setInnerText(nodeCaptionSpan, text); } - private void renderChildNodes(Iterator<?> i) { - childNodeContainer.clear(); - childNodeContainer.setVisible(true); - while (i.hasNext()) { - final UIDL childUidl = (UIDL) i.next(); - // actions are in bit weird place, don't mix them with children, - // but current node's actions - if ("actions".equals(childUidl.getTag())) { - updateActionMap(childUidl); - continue; - } - final TreeNode childTree = new TreeNode(); - if (ie6compatnode != null) { - childNodeContainer.add(childTree); - } - childTree.updateFromUIDL(childUidl, client); - if (ie6compatnode == null) { - childNodeContainer.add(childTree); - } - if (!i.hasNext()) { - childTree - .addStyleDependentName(childTree.isLeaf() ? "leaf-last" - : "last"); - childTree.childNodeContainer.addStyleDependentName("last"); - } - } - childrenLoaded = true; - } - public boolean isChildrenLoaded() { return childrenLoaded; } @@ -1233,32 +992,6 @@ public class VTree extends FocusElementPanel implements Paintable, } /* - * We need to fix the width of TreeNodes so that the float in - * ie6compatNode does not wrap (see ticket #1245) - */ - private void fixWidth() { - nodeCaptionDiv.getStyle().setProperty("styleFloat", "left"); - nodeCaptionDiv.getStyle().setProperty("display", "inline"); - nodeCaptionDiv.getStyle().setProperty("marginLeft", "0"); - final int captionWidth = ie6compatnode.getOffsetWidth() - + nodeCaptionDiv.getOffsetWidth(); - setWidth(captionWidth + "px"); - } - - /* - * (non-Javadoc) - * - * @see com.google.gwt.user.client.ui.Widget#onAttach() - */ - @Override - public void onAttach() { - super.onAttach(); - if (ie6compatnode != null) { - fixWidth(); - } - } - - /* * (non-Javadoc) * * @see com.google.gwt.user.client.ui.Widget#onDetach() @@ -1288,19 +1021,14 @@ public class VTree extends FocusElementPanel implements Paintable, public void setFocused(boolean focused) { if (!this.focused && focused) { nodeCaptionDiv.addClassName(CLASSNAME_FOCUSED); - if (BrowserInfo.get().isIE6()) { - ie6compatnode.addClassName(CLASSNAME_FOCUSED); - } + this.focused = focused; - if (isIE6OrOpera()) { + if (BrowserInfo.get().isOpera()) { nodeCaptionDiv.focus(); } treeHasFocus = true; } else if (this.focused && !focused) { nodeCaptionDiv.removeClassName(CLASSNAME_FOCUSED); - if (BrowserInfo.get().isIE6()) { - ie6compatnode.removeClassName(CLASSNAME_FOCUSED); - } this.focused = focused; treeHasFocus = false; } @@ -1313,6 +1041,34 @@ public class VTree extends FocusElementPanel implements Paintable, Util.scrollIntoViewVertically(nodeCaptionDiv); } + public void setIcon(String iconUrl) { + if (iconUrl != null) { + // Add icon if not present + if (icon == null) { + icon = new Icon(client); + DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv), + icon.getElement(), nodeCaptionSpan); + } + icon.setUri(iconUrl); + } else { + // Remove icon if present + if (icon != null) { + DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv), + icon.getElement()); + icon = null; + } + } + } + + public void setNodeStyleName(String styleName) { + addStyleName(TreeNode.CLASSNAME + "-" + styleName); + setStyleName(nodeCaptionDiv, TreeNode.CLASSNAME + "-caption-" + + styleName, true); + childNodeContainer.addStyleName(TreeNode.CLASSNAME + "-children-" + + styleName); + + } + } public VDropHandler getDropHandler() { @@ -2187,7 +1943,7 @@ public class VTree extends FocusElementPanel implements Paintable, */ public Element getSubPartElement(String subPart) { if ("fe".equals(subPart)) { - if (isIE6OrOpera() && focusedNode != null) { + if (BrowserInfo.get().isOpera() && focusedNode != null) { return focusedNode.getElement(); } return getFocusElement(); @@ -2219,11 +1975,7 @@ public class VTree extends FocusElementPanel implements Paintable, } if (expandCollapse) { - if (treeNode.ie6compatnode != null) { - return treeNode.ie6compatnode; - } else { - return treeNode.getElement(); - } + return treeNode.getElement(); } else { return treeNode.nodeCaptionSpan; } @@ -2267,8 +2019,7 @@ public class VTree extends FocusElementPanel implements Paintable, return null; } - if (subElement == treeNode.getElement() - || subElement == treeNode.ie6compatnode) { + if (subElement == treeNode.getElement()) { // Targets expand/collapse arrow isExpandCollapse = true; } @@ -2330,7 +2081,22 @@ public class VTree extends FocusElementPanel implements Paintable, } } - private boolean isIE6OrOpera() { - return BrowserInfo.get().isIE6() || BrowserInfo.get().isOpera(); + public void registerAction(String key, String caption, String iconUrl) { + actionMap.put(key + "_c", caption); + if (iconUrl != null) { + actionMap.put(key + "_i", iconUrl); + } else { + actionMap.remove(key + "_i"); + } + + } + + public void registerNode(TreeNode treeNode) { + keyToNode.put(treeNode.key, treeNode); } + + public void clearNodeToKeyMap() { + keyToNode.clear(); + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/treetable/TreeTableConnector.java b/src/com/vaadin/terminal/gwt/client/ui/treetable/TreeTableConnector.java new file mode 100644 index 0000000000..f81771781b --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/treetable/TreeTableConnector.java @@ -0,0 +1,102 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.treetable; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.FocusableScrollPanel; +import com.vaadin.terminal.gwt.client.ui.table.TableConnector; +import com.vaadin.terminal.gwt.client.ui.table.VScrollTable.VScrollTableBody.VScrollTableRow; +import com.vaadin.terminal.gwt.client.ui.treetable.VTreeTable.PendingNavigationEvent; +import com.vaadin.ui.TreeTable; + +@Connect(TreeTable.class) +public class TreeTableConnector extends TableConnector { + public static final String ATTRIBUTE_HIERARCHY_COLUMN_INDEX = "hci"; + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + FocusableScrollPanel widget = null; + int scrollPosition = 0; + if (getWidget().collapseRequest) { + widget = (FocusableScrollPanel) getWidget().getWidget(1); + scrollPosition = widget.getScrollPosition(); + } + getWidget().animationsEnabled = uidl.getBooleanAttribute("animate"); + getWidget().colIndexOfHierarchy = uidl + .hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl + .getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0; + int oldTotalRows = getWidget().getTotalRows(); + super.updateFromUIDL(uidl, client); + if (getWidget().collapseRequest) { + if (getWidget().collapsedRowKey != null + && getWidget().scrollBody != null) { + VScrollTableRow row = getWidget().getRenderedRowByKey( + getWidget().collapsedRowKey); + if (row != null) { + getWidget().setRowFocus(row); + getWidget().focus(); + } + } + + int scrollPosition2 = widget.getScrollPosition(); + if (scrollPosition != scrollPosition2) { + widget.setScrollPosition(scrollPosition); + } + + // check which rows are needed from the server and initiate a + // deferred fetch + getWidget().onScroll(null); + } + // Recalculate table size if collapse request, or if page length is zero + // (not sent by server) and row count changes (#7908). + if (getWidget().collapseRequest + || (!uidl.hasAttribute("pagelength") && getWidget() + .getTotalRows() != oldTotalRows)) { + /* + * Ensure that possibly removed/added scrollbars are considered. + * Triggers row calculations, removes cached rows etc. Basically + * cleans up state. Be careful if touching this, you will break + * pageLength=0 if you remove this. + */ + getWidget().triggerLazyColumnAdjustment(true); + + getWidget().collapseRequest = false; + } + if (uidl.hasAttribute("focusedRow")) { + String key = uidl.getStringAttribute("focusedRow"); + getWidget().setRowFocus(getWidget().getRenderedRowByKey(key)); + getWidget().focusParentResponsePending = false; + } else if (uidl.hasAttribute("clearFocusPending")) { + // Special case to detect a response to a focusParent request that + // does not return any focusedRow because the selected node has no + // parent + getWidget().focusParentResponsePending = false; + } + + while (!getWidget().collapseRequest + && !getWidget().focusParentResponsePending + && !getWidget().pendingNavigationEvents.isEmpty()) { + // Keep replaying any queued events as long as we don't have any + // potential content changes pending + PendingNavigationEvent event = getWidget().pendingNavigationEvents + .removeFirst(); + getWidget() + .handleNavigation(event.keycode, event.ctrl, event.shift); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VTreeTable.class); + } + + @Override + public VTreeTable getWidget() { + return (VTreeTable) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java b/src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java index 8e55400f31..2e15e7c445 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.treetable; import java.util.ArrayList; import java.util.Iterator; @@ -24,21 +24,19 @@ 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.Widget; -import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.ComputedStyle; -import com.vaadin.terminal.gwt.client.RenderSpace; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow; -import com.vaadin.terminal.gwt.client.ui.VTreeTable.VTreeTableScrollBody.VTreeTableRow; +import com.vaadin.terminal.gwt.client.ui.table.VScrollTable; +import com.vaadin.terminal.gwt.client.ui.treetable.VTreeTable.VTreeTableScrollBody.VTreeTableRow; public class VTreeTable extends VScrollTable { - private static class PendingNavigationEvent { - private final int keycode; - private final boolean ctrl; - private final boolean shift; + static class PendingNavigationEvent { + final int keycode; + final boolean ctrl; + final boolean shift; public PendingNavigationEvent(int keycode, boolean ctrl, boolean shift) { this.keycode = keycode; @@ -59,82 +57,14 @@ public class VTreeTable extends VScrollTable { } } - public static final String ATTRIBUTE_HIERARCHY_COLUMN_INDEX = "hci"; - private boolean collapseRequest; + boolean collapseRequest; private boolean selectionPending; - private int colIndexOfHierarchy; - private String collapsedRowKey; - private VTreeTableScrollBody scrollBody; - private boolean animationsEnabled; - private LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTable.PendingNavigationEvent>(); - private boolean focusParentResponsePending; - - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - FocusableScrollPanel widget = null; - int scrollPosition = 0; - if (collapseRequest) { - widget = (FocusableScrollPanel) getWidget(1); - scrollPosition = widget.getScrollPosition(); - } - animationsEnabled = uidl.getBooleanAttribute("animate"); - colIndexOfHierarchy = uidl - .hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl - .getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0; - int oldTotalRows = getTotalRows(); - super.updateFromUIDL(uidl, client); - if (collapseRequest) { - if (collapsedRowKey != null && scrollBody != null) { - VScrollTableRow row = getRenderedRowByKey(collapsedRowKey); - if (row != null) { - setRowFocus(row); - focus(); - } - } - - int scrollPosition2 = widget.getScrollPosition(); - if (scrollPosition != scrollPosition2) { - widget.setScrollPosition(scrollPosition); - } - - // check which rows are needed from the server and initiate a - // deferred fetch - onScroll(null); - } - // Recalculate table size if collapse request, or if page length is zero - // (not sent by server) and row count changes (#7908). - if (collapseRequest - || (!uidl.hasAttribute("pagelength") && getTotalRows() != oldTotalRows)) { - /* - * Ensure that possibly removed/added scrollbars are considered. - * Triggers row calculations, removes cached rows etc. Basically - * cleans up state. Be careful if touching this, you will break - * pageLength=0 if you remove this. - */ - triggerLazyColumnAdjustment(true); - - collapseRequest = false; - } - if (uidl.hasAttribute("focusedRow")) { - String key = uidl.getStringAttribute("focusedRow"); - setRowFocus(getRenderedRowByKey(key)); - focusParentResponsePending = false; - } else if (uidl.hasAttribute("clearFocusPending")) { - // Special case to detect a response to a focusParent request that - // does not return any focusedRow because the selected node has no - // parent - focusParentResponsePending = false; - } - - while (!collapseRequest && !focusParentResponsePending - && !pendingNavigationEvents.isEmpty()) { - // Keep replaying any queued events as long as we don't have any - // potential content changes pending - PendingNavigationEvent event = pendingNavigationEvents - .removeFirst(); - handleNavigation(event.keycode, event.ctrl, event.shift); - } - } + int colIndexOfHierarchy; + String collapsedRowKey; + VTreeTableScrollBody scrollBody; + boolean animationsEnabled; + LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTable.PendingNavigationEvent>(); + boolean focusParentResponsePending; @Override protected VScrollTableBody createScrollBody() { @@ -169,7 +99,7 @@ public class VTreeTable extends VScrollTable { private boolean browserSupportsAnimation() { BrowserInfo bi = BrowserInfo.get(); - return !(bi.isIE6() || bi.isIE7() || bi.isSafari4()); + return !(bi.isSafari4()); } class VTreeTableScrollBody extends VScrollTable.VScrollTableBody { @@ -293,29 +223,6 @@ public class VTreeTable extends VScrollTable { } } - @Override - public RenderSpace getAllocatedSpace(Widget child) { - if (widgetInHierarchyColumn == child) { - final int hierarchyAndIconWidth = getHierarchyAndIconWidth(); - final RenderSpace allocatedSpace = super - .getAllocatedSpace(child); - return new RenderSpace() { - @Override - public int getWidth() { - return allocatedSpace.getWidth() - - hierarchyAndIconWidth; - } - - @Override - public int getHeight() { - return allocatedSpace.getHeight(); - } - - }; - } - return super.getAllocatedSpace(child); - } - private int getHierarchyAndIconWidth() { int consumedSpace = treeSpacer.getOffsetWidth(); if (treeSpacer.getParentElement().getChildCount() > 2) { @@ -894,4 +801,5 @@ public class VTreeTable extends VScrollTable { int newTotalRows = uidl.getIntAttribute("totalrows"); setTotalRows(newTotalRows); } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/twincolselect/TwinColSelectConnector.java b/src/com/vaadin/terminal/gwt/client/ui/twincolselect/TwinColSelectConnector.java new file mode 100644 index 0000000000..328d0fc18b --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/twincolselect/TwinColSelectConnector.java @@ -0,0 +1,69 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.twincolselect; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.DirectionalManagedLayout; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.optiongroup.OptionGroupBaseConnector; +import com.vaadin.ui.TwinColSelect; + +@Connect(TwinColSelect.class) +public class TwinColSelectConnector extends OptionGroupBaseConnector implements + DirectionalManagedLayout { + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + // Captions are updated before super call to ensure the widths are set + // correctly + if (isRealUpdate(uidl)) { + getWidget().updateCaptions(uidl); + getLayoutManager().setNeedsHorizontalLayout(this); + } + + super.updateFromUIDL(uidl, client); + } + + @Override + protected void init() { + getLayoutManager().registerDependency(this, + getWidget().captionWrapper.getElement()); + } + + @Override + public void onUnregister() { + getLayoutManager().unregisterDependency(this, + getWidget().captionWrapper.getElement()); + } + + @Override + protected Widget createWidget() { + return GWT.create(VTwinColSelect.class); + } + + @Override + public VTwinColSelect getWidget() { + return (VTwinColSelect) super.getWidget(); + } + + public void layoutVertically() { + if (isUndefinedHeight()) { + getWidget().clearInternalHeights(); + } else { + getWidget().setInternalHeights(); + } + } + + public void layoutHorizontally() { + if (isUndefinedWidth()) { + getWidget().clearInternalWidths(); + } else { + getWidget().setInternalWidths(); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java b/src/com/vaadin/terminal/gwt/client/ui/twincolselect/VTwinColSelect.java index b569dbc94e..8f1ea09b8f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/twincolselect/VTwinColSelect.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.twincolselect; import java.util.ArrayList; import java.util.HashSet; @@ -26,10 +26,11 @@ import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.Panel; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.SubPartAware; +import com.vaadin.terminal.gwt.client.ui.button.VButton; +import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroupBase; public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, MouseDownHandler, DoubleClickHandler, SubPartAware { @@ -46,7 +47,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, private final DoubleClickListBox selections; - private FlowPanel captionWrapper; + FlowPanel captionWrapper; private HTML optionsCaption = null; @@ -60,8 +61,6 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, private final Panel panel; - private boolean widthSet = false; - /** * A ListBox which catches double clicks * @@ -157,18 +156,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, return selectionsCaption; } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - // Captions are updated before super call to ensure the widths are set - // correctly - if (!uidl.getBooleanAttribute("cached")) { - updateCaptions(uidl); - } - - super.updateFromUIDL(uidl, client); - } - - private void updateCaptions(UIDL uidl) { + protected void updateCaptions(UIDL uidl) { String leftCaption = (uidl.hasAttribute(ATTRIBUTE_LEFT_CAPTION) ? uidl .getStringAttribute(ATTRIBUTE_LEFT_CAPTION) : null); String rightCaption = (uidl.hasAttribute(ATTRIBUTE_RIGHT_CAPTION) ? uidl @@ -238,32 +226,6 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, } } - int cols = -1; - if (getColumns() > 0) { - cols = getColumns(); - } else if (!widthSet) { - cols = DEFAULT_COLUMN_COUNT; - } - - if (cols >= 0) { - String colWidth = cols + "em"; - String containerWidth = (2 * cols + 4) + "em"; - // Caption wrapper width == optionsSelect + buttons + - // selectionsSelect - String captionWrapperWidth = (2 * cols + 4 - 0.5) + "em"; - - options.setWidth(colWidth); - if (optionsCaption != null) { - optionsCaption.setWidth(colWidth); - } - selections.setWidth(colWidth); - if (selectionsCaption != null) { - selectionsCaption.setWidth(colWidth); - } - buttons.setWidth("3.5em"); - optionsContainer.setWidth(containerWidth); - captionWrapper.setWidth(captionWrapperWidth); - } if (getRows() > 0) { options.setVisibleItemCount(getRows()); selections.setVisibleItemCount(getRows()); @@ -297,7 +259,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, Set<String> movedItems = moveSelectedItems(options, selections); selectedKeys.addAll(movedItems); - client.updateVariable(id, "selected", + client.updateVariable(paintableId, "selected", selectedKeys.toArray(new String[selectedKeys.size()]), isImmediate()); } @@ -306,7 +268,7 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, Set<String> movedItems = moveSelectedItems(selections, options); selectedKeys.removeAll(movedItems); - client.updateVariable(id, "selected", + client.updateVariable(paintableId, "selected", selectedKeys.toArray(new String[selectedKeys.size()]), isImmediate()); } @@ -372,35 +334,15 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, } } - @Override - public void setHeight(String height) { - super.setHeight(height); - if ("".equals(height)) { - options.setHeight(""); - selections.setHeight(""); - } else { - setInternalHeights(); - } + void clearInternalHeights() { + selections.setHeight(""); + options.setHeight(""); } - private void setInternalHeights() { - int captionHeight = 0; - int totalHeight; - if (BrowserInfo.get().isIE6()) { - String o = getElement().getStyle().getOverflow(); + void setInternalHeights() { + int captionHeight = Util.getRequiredHeight(captionWrapper); + int totalHeight = getOffsetHeight(); - getElement().getStyle().setOverflow(Overflow.HIDDEN); - totalHeight = getOffsetHeight(); - getElement().getStyle().setProperty("overflow", o); - } else { - totalHeight = getOffsetHeight(); - } - - if (optionsCaption != null) { - captionHeight = Util.getRequiredHeight(optionsCaption); - } else if (selectionsCaption != null) { - captionHeight = Util.getRequiredHeight(selectionsCaption); - } String selectHeight = (totalHeight - captionHeight) + "px"; selections.setHeight(selectHeight); @@ -408,27 +350,40 @@ public class VTwinColSelect extends VOptionGroupBase implements KeyDownHandler, } - @Override - public void setWidth(String width) { - super.setWidth(width); - if (!"".equals(width) && width != null) { - setInternalWidths(); - widthSet = true; + void clearInternalWidths() { + int cols = -1; + if (getColumns() > 0) { + cols = getColumns(); } else { - widthSet = false; + cols = DEFAULT_COLUMN_COUNT; + } + + if (cols >= 0) { + String colWidth = cols + "em"; + String containerWidth = (2 * cols + 4) + "em"; + // Caption wrapper width == optionsSelect + buttons + + // selectionsSelect + String captionWrapperWidth = (2 * cols + 4 - 0.5) + "em"; + + options.setWidth(colWidth); + if (optionsCaption != null) { + optionsCaption.setWidth(colWidth); + } + selections.setWidth(colWidth); + if (selectionsCaption != null) { + selectionsCaption.setWidth(colWidth); + } + buttons.setWidth("3.5em"); + optionsContainer.setWidth(containerWidth); + captionWrapper.setWidth(captionWrapperWidth); } } - private void setInternalWidths() { + void setInternalWidths() { DOM.setStyleAttribute(getElement(), "position", "relative"); int bordersAndPaddings = Util.measureHorizontalPaddingAndBorder( buttons.getElement(), 0); - if (BrowserInfo.get().isIE6()) { - // IE6 sets a border on selects by default.. - bordersAndPaddings += 4; - } - int buttonWidth = Util.getRequiredWidth(buttons); int totalWidth = getOffsetWidth(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/upload/UploadConnector.java b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadConnector.java new file mode 100644 index 0000000000..0a2c0b241e --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadConnector.java @@ -0,0 +1,67 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.upload; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.ui.Upload; + +@Connect(value = Upload.class, loadStyle = LoadStyle.LAZY) +public class UploadConnector extends AbstractComponentConnector implements + Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + if (uidl.hasAttribute("notStarted")) { + getWidget().t.schedule(400); + return; + } + if (uidl.hasAttribute("forceSubmit")) { + getWidget().submit(); + return; + } + getWidget().setImmediate(getState().isImmediate()); + getWidget().client = client; + getWidget().paintableId = uidl.getId(); + getWidget().nextUploadId = uidl.getIntAttribute("nextid"); + final String action = client.translateVaadinUri(uidl + .getStringVariable("action")); + getWidget().element.setAction(action); + if (uidl.hasAttribute("buttoncaption")) { + getWidget().submitButton.setText(uidl + .getStringAttribute("buttoncaption")); + getWidget().submitButton.setVisible(true); + } else { + getWidget().submitButton.setVisible(false); + } + getWidget().fu.setName(getWidget().paintableId + "_file"); + + if (!isEnabled() || isReadOnly()) { + getWidget().disableUpload(); + } else if (!uidl.getBooleanAttribute("state")) { + // Enable the button only if an upload is not in progress + getWidget().enableUpload(); + getWidget().ensureTargetFrame(); + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VUpload.class); + } + + @Override + public VUpload getWidget() { + return (VUpload) super.getWidget(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategy.java b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java index 455a9bf601..18cfc643d3 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategy.java +++ b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategy.java @@ -1,16 +1,16 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.upload; public class UploadIFrameOnloadStrategy { native void hookEvents(com.google.gwt.dom.client.Element iframe, VUpload upload) /*-{ - iframe.onload = $entry(function() { - upload.@com.vaadin.terminal.gwt.client.ui.VUpload::onSubmitComplete()(); - }); + iframe.onload = function() { + upload.@com.vaadin.terminal.gwt.client.ui.upload.VUpload::onSubmitComplete()(); + }; }-*/; /** diff --git a/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategyIE.java b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java index b23d82fa22..19d38a8a95 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategyIE.java +++ b/src/com/vaadin/terminal/gwt/client/ui/upload/UploadIFrameOnloadStrategyIE.java @@ -1,7 +1,7 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.upload; import com.google.gwt.dom.client.Element; @@ -13,11 +13,11 @@ public class UploadIFrameOnloadStrategyIE extends UploadIFrameOnloadStrategy { @Override native void hookEvents(Element iframe, VUpload upload) /*-{ - iframe.onreadystatechange = $entry(function() { + iframe.onreadystatechange = function() { if (iframe.readyState == 'complete') { - upload.@com.vaadin.terminal.gwt.client.ui.VUpload::onSubmitComplete()(); + upload.@com.vaadin.terminal.gwt.client.ui.upload.VUpload::onSubmitComplete()(); } - }); + }; }-*/; @Override diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java b/src/com/vaadin/terminal/gwt/client/ui/upload/VUpload.java index f3105b70a1..4fe53fb89c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java +++ b/src/com/vaadin/terminal/gwt/client/ui/upload/VUpload.java @@ -2,7 +2,7 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.upload; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; @@ -23,10 +23,9 @@ import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.SimplePanel; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VTooltip; +import com.vaadin.terminal.gwt.client.ui.button.VButton; /** * @@ -34,7 +33,7 @@ import com.vaadin.terminal.gwt.client.VTooltip; * events even though the upload component is already detached. * */ -public class VUpload extends SimplePanel implements Paintable { +public class VUpload extends SimplePanel { private final class MyFileUpload extends FileUpload { @Override @@ -72,19 +71,19 @@ public class VUpload extends SimplePanel implements Paintable { ApplicationConnection client; - private String paintableId; + protected String paintableId; /** * Button that initiates uploading */ - private final VButton submitButton; + protected final VButton submitButton; /** * When expecting big files, programmer may initiate some UI changes when * uploading the file starts. Bit after submitting file we'll visit the * server to check possible changes. */ - private Timer t; + protected Timer t; /** * some browsers tries to send form twice if submit is called in button @@ -99,11 +98,11 @@ public class VUpload extends SimplePanel implements Paintable { private Hidden maxfilesize = new Hidden(); - private FormElement element; + protected FormElement element; private com.google.gwt.dom.client.Element synthesizedFrame; - private int nextUploadId; + protected int nextUploadId; public VUpload() { super(com.google.gwt.dom.client.Document.get().createFormElement()); @@ -144,47 +143,9 @@ public class VUpload extends SimplePanel implements Paintable { private static native void setEncoding(Element form, String encoding) /*-{ form.enctype = encoding; - // For IE6 - form.encoding = encoding; }-*/; - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { - return; - } - if (uidl.hasAttribute("notStarted")) { - t.schedule(400); - return; - } - if (uidl.hasAttribute("forceSubmit")) { - submit(); - return; - } - setImmediate(uidl.getBooleanAttribute("immediate")); - this.client = client; - paintableId = uidl.getId(); - nextUploadId = uidl.getIntAttribute("nextid"); - final String action = client.translateVaadinUri(uidl - .getStringVariable("action")); - element.setAction(action); - if (uidl.hasAttribute("buttoncaption")) { - submitButton.setText(uidl.getStringAttribute("buttoncaption")); - submitButton.setVisible(true); - } else { - submitButton.setVisible(false); - } - fu.setName(paintableId + "_file"); - - if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) { - disableUpload(); - } else if (!uidl.getBooleanAttribute("state")) { - // Enable the button only if an upload is not in progress - enableUpload(); - ensureTargetFrame(); - } - } - - private void setImmediate(boolean booleanAttribute) { + protected void setImmediate(boolean booleanAttribute) { if (immediate != booleanAttribute) { immediate = booleanAttribute; if (immediate) { @@ -278,7 +239,7 @@ public class VUpload extends SimplePanel implements Paintable { }); } - private void submit() { + protected void submit() { if (fu.getFilename().length() == 0 || submitted || !enabled) { VConsole.log("Submit cancelled (disabled, no file or already submitted)"); return; @@ -316,15 +277,12 @@ public class VUpload extends SimplePanel implements Paintable { } } - private void ensureTargetFrame() { + protected void ensureTargetFrame() { if (synthesizedFrame == null) { // Attach a hidden IFrame to the form. This is the target iframe to - // which - // the form will be submitted. We have to create the iframe using - // innerHTML, - // because setting an iframe's 'name' property dynamically doesn't - // work on - // most browsers. + // which the form will be submitted. We have to create the iframe + // using innerHTML, because setting an iframe's 'name' property + // dynamically doesn't work on most browsers. DivElement dummy = Document.get().createDivElement(); dummy.setInnerHTML("<iframe src=\"javascript:''\" name='" + getFrameName() @@ -355,5 +313,4 @@ public class VUpload extends SimplePanel implements Paintable { synthesizedFrame = null; } } - } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVideo.java b/src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java index 8599ffb279..484000b8d1 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VVideo.java +++ b/src/com/vaadin/terminal/gwt/client/ui/video/VVideo.java @@ -2,18 +2,16 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.video; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.VideoElement; import com.google.gwt.user.client.Element; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.ui.VMediaBase; public class VVideo extends VMediaBase { - public static final String ATTR_POSTER = "poster"; private static String CLASSNAME = "v-video"; @@ -27,22 +25,6 @@ public class VVideo extends VMediaBase { updateDimensionsWhenMetadataLoaded(getElement()); } - @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { - return; - } - super.updateFromUIDL(uidl, client); - setPosterFromUIDL(uidl); - } - - private void setPosterFromUIDL(UIDL uidl) { - if (uidl.hasAttribute(ATTR_POSTER)) { - video.setPoster(client.translateVaadinUri(uidl - .getStringAttribute(ATTR_POSTER))); - } - } - /** * Registers a listener that updates the dimensions of the widget when the * video metadata has been loaded. @@ -53,7 +35,7 @@ public class VVideo extends VMediaBase { /*-{ var self = this; el.addEventListener('loadedmetadata', $entry(function(e) { - self.@com.vaadin.terminal.gwt.client.ui.VVideo::updateElementDynamicSize(II)(el.videoWidth, el.videoHeight); + self.@com.vaadin.terminal.gwt.client.ui.video.VVideo::updateElementDynamicSize(II)(el.videoWidth, el.videoHeight); }), false); }-*/; @@ -74,4 +56,9 @@ public class VVideo extends VMediaBase { protected String getDefaultAltHtml() { return "Your browser does not support the <code>video</code> element."; } + + public void setPoster(String poster) { + video.setPoster(poster); + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/video/VideoConnector.java b/src/com/vaadin/terminal/gwt/client/ui/video/VideoConnector.java new file mode 100644 index 0000000000..ec763fff07 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/video/VideoConnector.java @@ -0,0 +1,46 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.video; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.MediaBaseConnector; +import com.vaadin.ui.Video; + +@Connect(Video.class) +public class VideoConnector extends MediaBaseConnector { + public static final String ATTR_POSTER = "poster"; + + @Override + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + super.updateFromUIDL(uidl, client); + if (!isRealUpdate(uidl)) { + return; + } + super.updateFromUIDL(uidl, client); + setPosterFromUIDL(uidl); + } + + private void setPosterFromUIDL(UIDL uidl) { + if (uidl.hasAttribute(ATTR_POSTER)) { + getWidget().setPoster( + getConnection().translateVaadinUri( + uidl.getStringAttribute(ATTR_POSTER))); + } + } + + @Override + public VVideo getWidget() { + return (VVideo) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VVideo.class); + } + +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java index 103979927a..d08387fc6d 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java @@ -2,57 +2,52 @@ @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; +package com.vaadin.terminal.gwt.client.ui.window; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.Iterator; -import java.util.Set; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.DomEvent.Type; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.ScrollEvent; import com.google.gwt.event.dom.client.ScrollHandler; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; 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.Window; -import com.google.gwt.user.client.ui.Frame; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; import com.vaadin.terminal.gwt.client.Console; -import com.vaadin.terminal.gwt.client.Container; import com.vaadin.terminal.gwt.client.EventId; import com.vaadin.terminal.gwt.client.Focusable; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.RenderSpace; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.LayoutManager; import com.vaadin.terminal.gwt.client.Util; -import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; +import com.vaadin.terminal.gwt.client.ui.FocusableScrollPanel; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; +import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; +import com.vaadin.terminal.gwt.client.ui.VOverlay; /** * "Sub window" component. * * @author Vaadin Ltd */ -public class VWindow extends VOverlay implements Container, - ShortcutActionHandlerOwner, ScrollHandler, KeyDownHandler, - FocusHandler, BlurHandler, BeforeShortcutActionListener, Focusable { +public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, + ScrollHandler, KeyDownHandler, FocusHandler, BlurHandler, Focusable { /** * Minimum allowed height of a window. This refers to the content area, not @@ -72,34 +67,21 @@ public class VWindow extends VOverlay implements Container, public static final String CLASSNAME = "v-window"; - /** - * Difference between offsetWidth and inner width for the content area. - */ - private int contentAreaBorderPadding = -1; - /** - * Pixels used by inner borders and paddings horizontally (calculated only - * once). This is the difference between the width of the root element and - * the content area, such that if root element width is set to "XYZpx" the - * inner width (width-border-padding) of the content area is - * X-contentAreaRootDifference. - */ - private int contentAreaToRootDifference = -1; - private static final int STACKING_OFFSET_PIXELS = 15; public static final int Z_INDEX = 10000; - private Paintable layout; + ComponentConnector layout; - private Element contents; + Element contents; - private Element header; + Element header; - private Element footer; + Element footer; private Element resizeBox; - private final FocusableScrollPanel contentPanel = new FocusableScrollPanel(); + final FocusableScrollPanel contentPanel = new FocusableScrollPanel(); private boolean dragging; @@ -117,11 +99,11 @@ public class VWindow extends VOverlay implements Container, private int origH; - private Element closeBox; + Element closeBox; protected ApplicationConnection client; - private String id; + String id; ShortcutActionHandler shortcutHandler; @@ -131,13 +113,13 @@ public class VWindow extends VOverlay implements Container, /** Last known positiony read from UIDL or updated to application connection */ private int uidlPositionY = -1; - private boolean vaadinModality = false; + boolean vaadinModality = false; - private boolean resizable = true; + boolean resizable = true; private boolean draggable = true; - private boolean resizeLazy = false; + boolean resizeLazy = false; private Element modalityCurtain; private Element draggingCurtain; @@ -147,40 +129,18 @@ public class VWindow extends VOverlay implements Container, private boolean closable = true; - boolean dynamicWidth = false; - boolean dynamicHeight = false; - boolean layoutRelativeWidth = false; - boolean layoutRelativeHeight = false; - // If centered (via UIDL), the window should stay in the centered -mode // until a position is received from the server, or the user moves or // resizes the window. boolean centered = false; - private RenderSpace renderSpace = new RenderSpace(MIN_CONTENT_AREA_WIDTH, - MIN_CONTENT_AREA_HEIGHT, true); - - private String width; + boolean immediate; - private String height; + private Element wrapper; - private boolean immediate; + boolean visibilityChangesDisabled; - private Element wrapper, wrapper2; - - private ClickEventHandler clickEventHandler = new ClickEventHandler(this, - VPanel.CLICK_EVENT_IDENTIFIER) { - - @Override - protected <H extends EventHandler> HandlerRegistration registerHandler( - H handler, Type<H> type) { - return addDomHandler(handler, type); - } - }; - - private boolean visibilityChangesDisabled; - - private int bringToFrontSequence = -1; + int bringToFrontSequence = -1; private VLazyExecutor delayedContentsSizeUpdater = new VLazyExecutor(200, new ScheduledCommand() { @@ -195,12 +155,7 @@ public class VWindow extends VOverlay implements Container, // Different style of shadow for windows setShadowStyle("window"); - final int order = windowOrder.size(); - setWindowOrder(order); - windowOrder.add(this); constructDOM(); - setPopupPosition(order * STACKING_OFFSET_PIXELS, order - * STACKING_OFFSET_PIXELS); contentPanel.addScrollHandler(this); contentPanel.addKeyDownHandler(this); contentPanel.addFocusHandler(this); @@ -224,7 +179,26 @@ public class VWindow extends VOverlay implements Container, * @return */ private boolean isActive() { - return windowOrder.get(windowOrder.size() - 1).equals(this); + return equals(getTopmostWindow()); + } + + private static VWindow getTopmostWindow() { + return windowOrder.get(windowOrder.size() - 1); + } + + void setWindowOrderAndPosition() { + // This cannot be done in the constructor as the widgets are created in + // a different order than on they should appear on screen + if (windowOrder.contains(this)) { + // Already set + return; + } + final int order = windowOrder.size(); + setWindowOrder(order); + windowOrder.add(this); + setPopupPosition(order * STACKING_OFFSET_PIXELS, order + * STACKING_OFFSET_PIXELS); + } private void setWindowOrder(int order) { @@ -267,15 +241,11 @@ public class VWindow extends VOverlay implements Container, wrapper = DOM.createDiv(); DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap"); - wrapper2 = DOM.createDiv(); - DOM.setElementProperty(wrapper2, "className", CLASSNAME + "-wrap2"); - - DOM.appendChild(wrapper2, closeBox); - DOM.appendChild(wrapper2, header); + DOM.appendChild(wrapper, header); + DOM.appendChild(wrapper, closeBox); DOM.appendChild(header, headerText); - DOM.appendChild(wrapper2, contents); - DOM.appendChild(wrapper2, footer); - DOM.appendChild(wrapper, wrapper2); + DOM.appendChild(wrapper, contents); + DOM.appendChild(wrapper, footer); DOM.appendChild(super.getContainerElement(), wrapper); sinkEvents(Event.MOUSEEVENTS | Event.TOUCHEVENTS | Event.ONCLICK @@ -285,236 +255,12 @@ public class VWindow extends VOverlay implements Container, } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - id = uidl.getId(); - this.client = client; - - // Workaround needed for Testing Tools (GWT generates window DOM - // slightly different in different browsers). - DOM.setElementProperty(closeBox, "id", id + "_window_close"); - - if (uidl.hasAttribute("invisible")) { - hide(); - return; - } - - if (!uidl.hasAttribute("cached")) { - if (uidl.getBooleanAttribute("modal") != vaadinModality) { - setVaadinModality(!vaadinModality); - } - if (!isAttached()) { - setVisible(false); // hide until possible centering - show(); - } - if (uidl.getBooleanAttribute("resizable") != resizable) { - setResizable(!resizable); - } - resizeLazy = uidl.hasAttribute(VView.RESIZE_LAZY); - - setDraggable(!uidl.hasAttribute("fixedposition")); - - // Caption must be set before required header size is measured. If - // the caption attribute is missing the caption should be cleared. - setCaption(uidl.getStringAttribute("caption"), - uidl.getStringAttribute("icon")); - } - - visibilityChangesDisabled = true; - if (client.updateComponent(this, uidl, false)) { - return; - } - visibilityChangesDisabled = false; - - clickEventHandler.handleEventHandlerRegistration(client); - - immediate = uidl.hasAttribute("immediate"); - - setClosable(!uidl.getBooleanAttribute("readonly")); - - // Initialize the position form UIDL - int positionx = uidl.getIntVariable("positionx"); - int positiony = uidl.getIntVariable("positiony"); - if (positionx >= 0 || positiony >= 0) { - if (positionx < 0) { - positionx = 0; - } - if (positiony < 0) { - positiony = 0; - } - setPopupPosition(positionx, positiony); - } - - boolean showingUrl = false; - int childIndex = 0; - UIDL childUidl = uidl.getChildUIDL(childIndex++); - while ("open".equals(childUidl.getTag())) { - // TODO multiple opens with the same target will in practice just - // open the last one - should we fix that somehow? - final String parsedUri = client.translateVaadinUri(childUidl - .getStringAttribute("src")); - if (!childUidl.hasAttribute("name")) { - final Frame frame = new Frame(); - DOM.setStyleAttribute(frame.getElement(), "width", "100%"); - DOM.setStyleAttribute(frame.getElement(), "height", "100%"); - DOM.setStyleAttribute(frame.getElement(), "border", "0px"); - frame.setUrl(parsedUri); - contentPanel.setWidget(frame); - showingUrl = true; - } else { - final String target = childUidl.getStringAttribute("name"); - Window.open(parsedUri, target, ""); - } - childUidl = uidl.getChildUIDL(childIndex++); - } - - final Paintable lo = client.getPaintable(childUidl); - if (layout != null) { - if (layout != lo) { - // remove old - client.unregisterPaintable(layout); - contentPanel.remove((Widget) layout); - // add new - if (!showingUrl) { - contentPanel.setWidget((Widget) lo); - } - layout = lo; - } - } else if (!showingUrl) { - contentPanel.setWidget((Widget) lo); - layout = lo; - } - - dynamicWidth = !uidl.hasAttribute("width"); - dynamicHeight = !uidl.hasAttribute("height"); - - layoutRelativeWidth = uidl.hasAttribute("layoutRelativeWidth"); - layoutRelativeHeight = uidl.hasAttribute("layoutRelativeHeight"); - - if (dynamicWidth && layoutRelativeWidth) { - /* - * Relative layout width, fix window width before rendering (width - * according to caption) - */ - setNaturalWidth(); - } - - layout.updateFromUIDL(childUidl, client); - if (!dynamicHeight && layoutRelativeWidth) { - /* - * Relative layout width, and fixed height. Must update the size to - * be able to take scrollbars into account (layout gets narrower - * space if it is higher than the window) -> only vertical scrollbar - */ - client.runDescendentsLayout(this); - } - - /* - * No explicit width is set and the layout does not have relative width - * so fix the size according to the layout. - */ - if (dynamicWidth && !layoutRelativeWidth) { - setNaturalWidth(); - } - - if (dynamicHeight && layoutRelativeHeight) { - // Prevent resizing until height has been fixed - resizable = false; - } - - // we may have actions and notifications - if (uidl.getChildCount() > 1) { - final int cnt = uidl.getChildCount(); - for (int i = 1; i < cnt; i++) { - childUidl = uidl.getChildUIDL(i); - if (childUidl.getTag().equals("actions")) { - if (shortcutHandler == null) { - shortcutHandler = new ShortcutActionHandler(id, client); - } - shortcutHandler.updateActionMap(childUidl); - } else if (childUidl.getTag().equals("notifications")) { - for (final Iterator<?> it = childUidl.getChildIterator(); it - .hasNext();) { - final UIDL notification = (UIDL) it.next(); - VNotification.showNotification(client, notification); - } - } - } - - } - - // setting scrollposition must happen after children is rendered - contentPanel.setScrollPosition(uidl.getIntVariable("scrollTop")); - contentPanel.setHorizontalScrollPosition(uidl - .getIntVariable("scrollLeft")); - - // Center this window on screen if requested - // This has to be here because we might not know the content size before - // everything is painted into the window - if (uidl.getBooleanAttribute("center")) { - // mark as centered - this is unset on move/resize - centered = true; - center(); - } else { - // don't try to center the window anymore - centered = false; - } - updateShadowSizeAndPosition(); - setVisible(true); - - boolean sizeReduced = false; - // ensure window is not larger than browser window - if (getOffsetWidth() > Window.getClientWidth()) { - setWidth(Window.getClientWidth() + "px"); - sizeReduced = true; - } - if (getOffsetHeight() > Window.getClientHeight()) { - setHeight(Window.getClientHeight() + "px"); - sizeReduced = true; - } - - if (dynamicHeight && layoutRelativeHeight) { - /* - * Window height is undefined, layout is 100% high so the layout - * should define the initial window height but on resize the layout - * should be as high as the window. We fix the height to deal with - * this. - */ - - int h = contents.getOffsetHeight() + getExtraHeight(); - int w = getElement().getOffsetWidth(); - - client.updateVariable(id, "height", h, false); - client.updateVariable(id, "width", w, true); - } - - if (sizeReduced) { - // If we changed the size we need to update the size of the child - // component if it is relative (#3407) - client.runDescendentsLayout(this); - } - - Util.runWebkitOverflowAutoFix(contentPanel.getElement()); - - client.getView().scrollIntoView(uidl); - - if (uidl.hasAttribute("bringToFront")) { - /* - * Focus as a side-efect. Will be overridden by - * ApplicationConnection if another component was focused by the - * server side. - */ - contentPanel.focus(); - bringToFrontSequence = uidl.getIntAttribute("bringToFront"); - deferOrdering(); - } - } - /** * Calling this method will defer ordering algorithm, to order windows based * on servers bringToFront and modality instructions. Non changed windows * will be left intact. */ - private static void deferOrdering() { + static void deferOrdering() { if (!orderingDefered) { orderingDefered = true; Scheduler.get().scheduleFinally(new Command() { @@ -569,7 +315,7 @@ public class VWindow extends VOverlay implements Container, } } - private void setDraggable(boolean draggable) { + void setDraggable(boolean draggable) { if (this.draggable == draggable) { return; } @@ -589,69 +335,6 @@ public class VWindow extends VOverlay implements Container, } } - private void setNaturalWidth() { - /* - * Use max(layout width, window width) i.e layout content width or - * caption width. We remove the previous set width so the width is - * allowed to shrink. All widths are measured as outer sizes, i.e. the - * borderWidth is added to the content. - */ - - DOM.setStyleAttribute(getElement(), "width", ""); - - String oldHeaderWidth = ""; // Only for IE6 - if (BrowserInfo.get().isIE6()) { - /* - * For some reason IE6 has title DIV set to width 100% which - * interferes with the header measuring. Also IE6 has width set to - * the contentPanel. - */ - oldHeaderWidth = headerText.getStyle().getProperty("width"); - DOM.setStyleAttribute(contentPanel.getElement(), "width", "auto"); - DOM.setStyleAttribute(contentPanel.getElement(), "zoom", "1"); - headerText.getStyle().setProperty("width", "auto"); - } - - // Content - int contentWidth = contentPanel.getElement().getScrollWidth(); - contentWidth += getContentAreaToRootDifference(); - - // Window width (caption) - int windowCaptionWidth = getOffsetWidth(); - - int naturalWidth = (contentWidth > windowCaptionWidth ? contentWidth - : windowCaptionWidth); - - if (BrowserInfo.get().isIE6()) { - headerText.getStyle().setProperty("width", oldHeaderWidth); - } - - setWidth(naturalWidth + "px"); - } - - private int getContentAreaToRootDifference() { - if (contentAreaToRootDifference < 0) { - measure(); - } - return contentAreaToRootDifference; - } - - private void measure() { - if (!isAttached()) { - return; - } - - contentAreaBorderPadding = Util.measureHorizontalPaddingAndBorder( - contents, 4); - int wrapperPaddingBorder = Util.measureHorizontalPaddingAndBorder( - wrapper, 0) - + Util.measureHorizontalPaddingAndBorder(wrapper2, 0); - - contentAreaToRootDifference = wrapperPaddingBorder - + contentAreaBorderPadding; - - } - /** * Sets the closable state of the window. Additionally hides/shows the close * button according to the new state. @@ -697,42 +380,6 @@ public class VWindow extends VOverlay implements Container, showModalityCurtain(); } super.show(); - - setFF2CaretFixEnabled(true); - fixFF3OverflowBug(); - } - - /** Disable overflow auto with FF3 to fix #1837. */ - private void fixFF3OverflowBug() { - if (BrowserInfo.get().isFF3()) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - DOM.setStyleAttribute(getElement(), "overflow", ""); - } - }); - } - } - - /** - * Fix "missing cursor" browser bug workaround for FF2 in Windows and Linux. - * - * Calling this method has no effect on other browsers than the ones based - * on Gecko 1.8 - * - * @param enable - */ - private void setFF2CaretFixEnabled(boolean enable) { - if (BrowserInfo.get().isFF2()) { - if (enable) { - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - DOM.setStyleAttribute(getElement(), "overflow", "auto"); - } - }); - } else { - DOM.setStyleAttribute(getElement(), "overflow", ""); - } - } } @Override @@ -747,7 +394,7 @@ public class VWindow extends VOverlay implements Container, windowOrder.remove(this); } - private void setVaadinModality(boolean modality) { + void setVaadinModality(boolean modality) { vaadinModality = modality; if (vaadinModality) { if (isAttached()) { @@ -765,14 +412,6 @@ public class VWindow extends VOverlay implements Container, } private void showModalityCurtain() { - if (BrowserInfo.get().isFF2()) { - DOM.setStyleAttribute( - getModalityCurtain(), - "height", - DOM.getElementPropertyInt(RootPanel.getBodyElement(), - "offsetHeight") + "px"); - DOM.setStyleAttribute(getModalityCurtain(), "position", "absolute"); - } DOM.setStyleAttribute(getModalityCurtain(), "zIndex", "" + (windowOrder.indexOf(this) + Z_INDEX)); if (isShowing()) { @@ -792,15 +431,11 @@ public class VWindow extends VOverlay implements Container, * iframes (etc) do not steal event. */ private void showDraggingCurtain() { - setFF2CaretFixEnabled(false); // makes FF2 slow - DOM.appendChild(RootPanel.getBodyElement(), getDraggingCurtain()); } private void hideDraggingCurtain() { if (draggingCurtain != null) { - setFF2CaretFixEnabled(true); // makes FF2 slow - DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain); } } @@ -810,15 +445,11 @@ public class VWindow extends VOverlay implements Container, * that iframes (etc) do not steal event. */ private void showResizingCurtain() { - setFF2CaretFixEnabled(false); // makes FF2 slow - DOM.appendChild(RootPanel.getBodyElement(), getResizingCurtain()); } private void hideResizingCurtain() { if (resizingCurtain != null) { - setFF2CaretFixEnabled(true); // makes FF2 slow - DOM.removeChild(RootPanel.getBodyElement(), resizingCurtain); } } @@ -854,7 +485,7 @@ public class VWindow extends VOverlay implements Container, return curtain; } - private void setResizable(boolean resizability) { + void setResizable(boolean resizability) { resizable = resizability; if (resizability) { DOM.setElementProperty(footer, "className", CLASSNAME + "-footer"); @@ -1044,13 +675,15 @@ public class VWindow extends VOverlay implements Container, } int w = Util.getTouchOrMouseClientX(event) - startX + origW; - if (w < MIN_CONTENT_AREA_WIDTH + getContentAreaToRootDifference()) { - w = MIN_CONTENT_AREA_WIDTH + getContentAreaToRootDifference(); + int minWidth = getMinWidth(); + if (w < minWidth) { + w = minWidth; } int h = Util.getTouchOrMouseClientY(event) - startY + origH; - if (h < MIN_CONTENT_AREA_HEIGHT + getExtraHeight()) { - h = MIN_CONTENT_AREA_HEIGHT + getExtraHeight(); + int minHeight = getMinHeight(); + if (h < minHeight) { + h = minHeight; } setWidth(w + "px"); @@ -1074,121 +707,30 @@ public class VWindow extends VOverlay implements Container, private void updateContentsSize() { // Update child widget dimensions if (client != null) { - client.handleComponentRelativeSize((Widget) layout); - client.runDescendentsLayout((HasWidgets) layout); + client.handleComponentRelativeSize(layout.getWidget()); + client.runDescendentsLayout((HasWidgets) layout.getWidget()); } - Util.runWebkitOverflowAutoFix(contentPanel.getElement()); + LayoutManager layoutManager = LayoutManager.get(client); + layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector( + this)); + layoutManager.layoutNow(); } @Override - /** - * Width is set to the out-most element (v-window). - * - * This function should never be called with percentage values (it will - * throw an exception) - */ public void setWidth(String width) { - this.width = width; - if (!isAttached()) { - return; - } - if (width != null && !"".equals(width)) { - int rootPixelWidth = -1; - if (width.indexOf("px") < 0) { - /* - * Convert non-pixel values to pixels by setting the width and - * then measuring it. Updates the "width" variable with the - * pixel width. - */ - DOM.setStyleAttribute(getElement(), "width", width); - rootPixelWidth = getElement().getOffsetWidth(); - width = rootPixelWidth + "px"; - } else { - rootPixelWidth = Integer.parseInt(width.substring(0, - width.indexOf("px"))); - } - - // "width" now contains the new width in pixels - - if (BrowserInfo.get().isIE6()) { - getElement().getStyle().setProperty("overflow", "hidden"); - } - - // Apply the new pixel width - getElement().getStyle().setProperty("width", width); - - // Caculate the inner width of the content area - int contentAreaInnerWidth = rootPixelWidth - - getContentAreaToRootDifference(); - if (contentAreaInnerWidth < MIN_CONTENT_AREA_WIDTH) { - contentAreaInnerWidth = MIN_CONTENT_AREA_WIDTH; - int rootWidth = contentAreaInnerWidth - + getContentAreaToRootDifference(); - DOM.setStyleAttribute(getElement(), "width", rootWidth + "px"); - } - - // IE6 needs the actual inner content width on the content element, - // otherwise it won't wrap the content properly (no scrollbars - // appear, content flows out of window) - if (BrowserInfo.get().isIE6()) { - DOM.setStyleAttribute(contentPanel.getElement(), "width", - contentAreaInnerWidth + "px"); - } - - renderSpace.setWidth(contentAreaInnerWidth); - - updateShadowSizeAndPosition(); - } + // Override PopupPanel which sets the width to the contents + getElement().getStyle().setProperty("width", width); + // Update v-has-width in case undefined window is resized + setStyleName("v-has-width", width != null && width.length() > 0); } @Override - /** - * Height is set to the out-most element (v-window). - * - * This function should never be called with percentage values (it will - * throw an exception) - * - * @param height A CSS string specifying the new height of the window. - * An empty string or null clears the height and lets - * the browser to compute it based on the window contents. - */ public void setHeight(String height) { - if (!isAttached() - || (height == null ? this.height == null : height - .equals(this.height))) { - return; - } - if (height == null || "".equals(height)) { - getElement().getStyle().clearHeight(); - contentPanel.getElement().getStyle().clearHeight(); - // Reset to default, the exact value does not actually - // matter as an undefined-height parent should not have - // a relative-height child anyway. - renderSpace.setHeight(MIN_CONTENT_AREA_HEIGHT); - } else { - getElement().getStyle().setProperty("height", height); - int contentHeight = getElement().getOffsetHeight() - - getExtraHeight(); - if (contentHeight < MIN_CONTENT_AREA_HEIGHT) { - contentHeight = MIN_CONTENT_AREA_HEIGHT; - int rootHeight = contentHeight + getExtraHeight(); - getElement().getStyle() - .setProperty("height", rootHeight + "px"); - } - renderSpace.setHeight(contentHeight); - contentPanel.getElement().getStyle() - .setProperty("height", contentHeight + "px"); - } - this.height = height; - updateShadowSizeAndPosition(); - } - - private int extraH = 0; - - private int getExtraHeight() { - extraH = header.getOffsetHeight() + footer.getOffsetHeight(); - return extraH; + // Override PopupPanel which sets the height to the contents + getElement().getStyle().setProperty("height", height); + // Update v-has-height in case undefined window is resized + setStyleName("v-has-height", height != null && height.length() > 0); } private void onDragEvent(Event event) { @@ -1264,22 +806,34 @@ public class VWindow extends VOverlay implements Container, } else if (resizing) { onResizeEvent(event); return false; - } else if (vaadinModality) { - // return false when modal and outside window - final Element target = event.getEventTarget().cast(); + } + + // TODO This is probably completely unnecessary as the modality curtain + // prevents events from reaching other windows and any security check + // must be done on the server side and not here. + // The code here is also run many times as each VWindow has an event + // preview but we cannot check only the current VWindow here (e.g. + // if(isTopMost) {...}) because PopupPanel will cause all events that + // are not cancelled here and target this window to be consume():d + // meaning the event won't be sent to the rest of the preview handlers. + + if (getTopmostWindow().vaadinModality) { + // Topmost window is modal. Cancel the event if it targets something + // outside that window (except debug console...) if (DOM.getCaptureElement() != null) { // Allow events when capture is set return true; } - if (!DOM.isOrHasChild(getElement(), target)) { + final Element target = event.getEventTarget().cast(); + if (!DOM.isOrHasChild(getTopmostWindow().getElement(), target)) { // not within the modal window, but let's see if it's in the // debug window Widget w = Util.findWidget(target, null); while (w != null) { if (w instanceof Console) { return true; // allow debug-window clicks - } else if (w instanceof Paintable) { + } else if (ConnectorMap.get(client).isConnector(w)) { return false; } w = w.getParent(); @@ -1298,52 +852,6 @@ public class VWindow extends VOverlay implements Container, true); } - @Override - protected void onAttach() { - super.onAttach(); - - setWidth(width); - setHeight(height); - } - - public RenderSpace getAllocatedSpace(Widget child) { - if (child == layout) { - return renderSpace; - } else { - // Exception ?? - return null; - } - } - - public boolean hasChildComponent(Widget component) { - if (component == layout) { - return true; - } else { - return false; - } - } - - public void replaceChildComponent(Widget oldComponent, Widget newComponent) { - contentPanel.setWidget(newComponent); - } - - public boolean requestLayout(Set<Paintable> child) { - if (dynamicWidth && !layoutRelativeWidth) { - setNaturalWidth(); - } - if (centered) { - center(); - } - updateShadowSizeAndPosition(); - // layout size change may affect its available space (scrollbars) - client.handleComponentRelativeSize((Widget) layout); - return true; - } - - public void updateCaption(Paintable component, UIDL uidl) { - // NOP, window has own caption, layout captio not rendered - } - public ShortcutActionHandler getShortcutActionHandler() { return shortcutHandler; } @@ -1376,13 +884,29 @@ public class VWindow extends VOverlay implements Container, } } - public void onBeforeShortcutAction(Event e) { - // NOP, nothing to update just avoid workaround ( causes excess - // blur/focus ) - } - public void focus() { contentPanel.focus(); } + public int getMinHeight() { + return MIN_CONTENT_AREA_HEIGHT + getDecorationHeight(); + } + + private int getDecorationHeight() { + LayoutManager lm = layout.getLayoutManager(); + int headerHeight = lm.getOuterHeight(header); + int footerHeight = lm.getOuterHeight(footer); + return headerHeight + footerHeight; + } + + public int getMinWidth() { + return MIN_CONTENT_AREA_WIDTH + getDecorationWidth(); + } + + private int getDecorationWidth() { + LayoutManager layoutManager = layout.getLayoutManager(); + return layoutManager.getOuterWidth(getElement()) + - contentPanel.getElement().getOffsetWidth(); + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java b/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java new file mode 100644 index 0000000000..6979982a9c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/window/WindowConnector.java @@ -0,0 +1,305 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.window; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Position; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorHierarchyChangeEvent; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.communication.RpcProxy; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentContainerConnector; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.PostLayoutListener; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; +import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.BeforeShortcutActionListener; +import com.vaadin.terminal.gwt.client.ui.SimpleManagedLayout; +import com.vaadin.terminal.gwt.client.ui.layout.MayScrollChildren; + +@Connect(value = com.vaadin.ui.Window.class) +public class WindowConnector extends AbstractComponentContainerConnector + implements Paintable, BeforeShortcutActionListener, + SimpleManagedLayout, PostLayoutListener, MayScrollChildren { + + private ClickEventHandler clickEventHandler = new ClickEventHandler(this) { + @Override + protected void fireClick(NativeEvent event, + MouseEventDetails mouseDetails) { + rpc.click(mouseDetails); + } + }; + + private WindowServerRpc rpc; + + boolean minWidthChecked = false; + + @Override + public boolean delegateCaptionHandling() { + return false; + }; + + @Override + protected void init() { + super.init(); + rpc = RpcProxy.create(WindowServerRpc.class, this); + + getLayoutManager().registerDependency(this, + getWidget().contentPanel.getElement()); + getLayoutManager().registerDependency(this, getWidget().header); + getLayoutManager().registerDependency(this, getWidget().footer); + } + + @Override + public void onUnregister() { + LayoutManager lm = getLayoutManager(); + VWindow window = getWidget(); + lm.unregisterDependency(this, window.contentPanel.getElement()); + lm.unregisterDependency(this, window.header); + lm.unregisterDependency(this, window.footer); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + getWidget().id = getConnectorId(); + getWidget().client = client; + + // Workaround needed for Testing Tools (GWT generates window DOM + // slightly different in different browsers). + DOM.setElementProperty(getWidget().closeBox, "id", getConnectorId() + + "_window_close"); + + if (isRealUpdate(uidl)) { + if (getState().isModal() != getWidget().vaadinModality) { + getWidget().setVaadinModality(!getWidget().vaadinModality); + } + if (!getWidget().isAttached()) { + getWidget().setVisible(false); // hide until + // possible centering + getWidget().show(); + } + if (getState().isResizable() != getWidget().resizable) { + getWidget().setResizable(getState().isResizable()); + } + getWidget().resizeLazy = getState().isResizeLazy(); + + getWidget().setDraggable(getState().isDraggable()); + + // Caption must be set before required header size is measured. If + // the caption attribute is missing the caption should be cleared. + String iconURL = null; + if (getState().getIcon() != null) { + iconURL = getState().getIcon().getURL(); + } + getWidget().setCaption(getState().getCaption(), iconURL); + } + + getWidget().visibilityChangesDisabled = true; + if (!isRealUpdate(uidl)) { + return; + } + getWidget().visibilityChangesDisabled = false; + + clickEventHandler.handleEventHandlerRegistration(); + + getWidget().immediate = getState().isImmediate(); + + getWidget().setClosable(!isReadOnly()); + + // Initialize the position form UIDL + int positionx = getState().getPositionX(); + int positiony = getState().getPositionY(); + if (positionx >= 0 || positiony >= 0) { + if (positionx < 0) { + positionx = 0; + } + if (positiony < 0) { + positiony = 0; + } + getWidget().setPopupPosition(positionx, positiony); + } + + int childIndex = 0; + + // we may have actions + for (int i = 0; i < uidl.getChildCount(); i++) { + UIDL childUidl = uidl.getChildUIDL(i); + if (childUidl.getTag().equals("actions")) { + if (getWidget().shortcutHandler == null) { + getWidget().shortcutHandler = new ShortcutActionHandler( + getConnectorId(), client); + } + getWidget().shortcutHandler.updateActionMap(childUidl); + } + + } + + // setting scrollposition must happen after children is rendered + getWidget().contentPanel.setScrollPosition(getState().getScrollTop()); + getWidget().contentPanel.setHorizontalScrollPosition(getState() + .getScrollLeft()); + + // Center this window on screen if requested + // This had to be here because we might not know the content size before + // everything is painted into the window + + // centered is this is unset on move/resize + getWidget().centered = getState().isCentered(); + getWidget().setVisible(true); + + // ensure window is not larger than browser window + if (getWidget().getOffsetWidth() > Window.getClientWidth()) { + getWidget().setWidth(Window.getClientWidth() + "px"); + } + if (getWidget().getOffsetHeight() > Window.getClientHeight()) { + getWidget().setHeight(Window.getClientHeight() + "px"); + } + + if (uidl.hasAttribute("bringToFront")) { + /* + * Focus as a side-effect. Will be overridden by + * ApplicationConnection if another component was focused by the + * server side. + */ + getWidget().contentPanel.focus(); + getWidget().bringToFrontSequence = uidl + .getIntAttribute("bringToFront"); + VWindow.deferOrdering(); + } + } + + public void updateCaption(ComponentConnector component) { + // NOP, window has own caption, layout caption not rendered + } + + public void onBeforeShortcutAction(Event e) { + // NOP, nothing to update just avoid workaround ( causes excess + // blur/focus ) + } + + @Override + public VWindow getWidget() { + return (VWindow) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VWindow.class); + } + + @Override + public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { + super.onConnectorHierarchyChange(event); + + // We always have 1 child, unless the child is hidden + Widget newChildWidget = null; + ComponentConnector newChild = null; + if (getChildren().size() == 1) { + newChild = getChildren().get(0); + newChildWidget = newChild.getWidget(); + } + + getWidget().layout = newChild; + getWidget().contentPanel.setWidget(newChildWidget); + } + + public void layout() { + LayoutManager lm = getLayoutManager(); + VWindow window = getWidget(); + ComponentConnector layout = window.layout; + Element contentElement = window.contentPanel.getElement(); + + if (!minWidthChecked) { + boolean needsMinWidth = !isUndefinedWidth() + || layout.isRelativeWidth(); + int minWidth = window.getMinWidth(); + if (needsMinWidth && lm.getInnerWidth(contentElement) < minWidth) { + minWidthChecked = true; + // Use minimum width if less than a certain size + window.setWidth(minWidth + "px"); + } + minWidthChecked = true; + } + + boolean needsMinHeight = !isUndefinedHeight() + || layout.isRelativeHeight(); + int minHeight = window.getMinHeight(); + if (needsMinHeight && lm.getInnerHeight(contentElement) < minHeight) { + // Use minimum height if less than a certain size + window.setHeight(minHeight + "px"); + } + + Style contentStyle = window.contents.getStyle(); + + int headerHeight = lm.getOuterHeight(window.header); + contentStyle.setPaddingTop(headerHeight, Unit.PX); + contentStyle.setMarginTop(-headerHeight, Unit.PX); + + int footerHeight = lm.getOuterHeight(window.footer); + contentStyle.setPaddingBottom(footerHeight, Unit.PX); + contentStyle.setMarginBottom(-footerHeight, Unit.PX); + + /* + * Must set absolute position if the child has relative height and + * there's a chance of horizontal scrolling as some browsers will + * otherwise not take the scrollbar into account when calculating the + * height. + */ + Element layoutElement = layout.getWidget().getElement(); + Style childStyle = layoutElement.getStyle(); + if (layout.isRelativeHeight() && !BrowserInfo.get().isIE9()) { + childStyle.setPosition(Position.ABSOLUTE); + + Style wrapperStyle = contentElement.getStyle(); + if (window.getElement().getStyle().getWidth().length() == 0 + && !layout.isRelativeWidth()) { + /* + * Need to lock width to make undefined width work even with + * absolute positioning + */ + int contentWidth = lm.getOuterWidth(layoutElement); + wrapperStyle.setWidth(contentWidth, Unit.PX); + } else { + wrapperStyle.clearWidth(); + } + } else { + childStyle.clearPosition(); + } + } + + public void postLayout() { + minWidthChecked = false; + VWindow window = getWidget(); + if (window.centered) { + window.center(); + } + window.updateShadowSizeAndPosition(); + } + + @Override + public WindowState getState() { + return (WindowState) super.getState(); + } + + /** + * Gives the WindowConnector an order number. As a side effect, moves the + * window according to its order number so the windows are stacked. This + * method should be called for each window in the order they should appear. + */ + public void setWindowOrderAndPosition() { + getWidget().setWindowOrderAndPosition(); + } +} diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRpc.java b/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRpc.java new file mode 100644 index 0000000000..4723c55786 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/window/WindowServerRpc.java @@ -0,0 +1,10 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.window; + +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.ui.ClickRpc; + +public interface WindowServerRpc extends ClickRpc, ServerRpc { +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/WindowState.java b/src/com/vaadin/terminal/gwt/client/ui/window/WindowState.java new file mode 100644 index 0000000000..b057d76b16 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/client/ui/window/WindowState.java @@ -0,0 +1,73 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.window; + +import com.vaadin.terminal.gwt.client.ui.panel.PanelState; + +public class WindowState extends PanelState { + private boolean modal = false; + private boolean resizable = true; + private boolean resizeLazy = false; + private boolean draggable = true; + private boolean centered = false;; + private int positionX = -1; + private int positionY = -1; + + public boolean isModal() { + return modal; + } + + public void setModal(boolean modal) { + this.modal = modal; + } + + public boolean isResizable() { + return resizable; + } + + public void setResizable(boolean resizable) { + this.resizable = resizable; + } + + public boolean isResizeLazy() { + return resizeLazy; + } + + public void setResizeLazy(boolean resizeLazy) { + this.resizeLazy = resizeLazy; + } + + public boolean isDraggable() { + return draggable; + } + + public void setDraggable(boolean draggable) { + this.draggable = draggable; + } + + public boolean isCentered() { + return centered; + } + + public void setCentered(boolean centered) { + this.centered = centered; + } + + public int getPositionX() { + return positionX; + } + + public void setPositionX(int positionX) { + this.positionX = positionX; + } + + public int getPositionY() { + return positionY; + } + + public void setPositionY(int positionY) { + this.positionY = positionY; + } + +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index a5923cb47f..58d6a18592 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -14,14 +14,10 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.security.GeneralSecurityException; -import java.util.Date; import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; -import java.util.logging.Level; import java.util.logging.Logger; import javax.portlet.ActionRequest; @@ -30,19 +26,16 @@ import javax.portlet.EventRequest; import javax.portlet.EventResponse; import javax.portlet.GenericPortlet; import javax.portlet.MimeResponse; -import javax.portlet.PortalContext; import javax.portlet.PortletConfig; import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; -import javax.portlet.PortletURL; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; -import javax.portlet.ResourceURL; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; @@ -50,12 +43,15 @@ import javax.servlet.http.HttpServletResponse; import com.liferay.portal.kernel.util.PortalClassInvoker; import com.liferay.portal.kernel.util.PropsUtil; import com.vaadin.Application; +import com.vaadin.Application.ApplicationStartEvent; import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.DownloadStream; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.gwt.client.ApplicationConfiguration; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.Window; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; +import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; +import com.vaadin.ui.Root; /** * Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0 @@ -71,46 +67,256 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet private static final Logger logger = Logger .getLogger(AbstractApplicationPortlet.class.getName()); + private static class WrappedHttpAndPortletRequest extends + WrappedPortletRequest { + + public WrappedHttpAndPortletRequest(PortletRequest request, + HttpServletRequest originalRequest, + DeploymentConfiguration deploymentConfiguration) { + super(request, deploymentConfiguration); + this.originalRequest = originalRequest; + } + + private final HttpServletRequest originalRequest; + + @Override + public String getParameter(String name) { + String parameter = super.getParameter(name); + if (parameter == null) { + parameter = originalRequest.getParameter(name); + } + return parameter; + } + + @Override + public String getRemoteAddr() { + return originalRequest.getRemoteAddr(); + } + + @Override + public String getHeader(String name) { + String header = super.getHeader(name); + if (header == null) { + header = originalRequest.getHeader(name); + } + return header; + } + + @Override + public Map<String, String[]> getParameterMap() { + Map<String, String[]> parameterMap = super.getParameterMap(); + if (parameterMap == null) { + parameterMap = originalRequest.getParameterMap(); + } + return parameterMap; + } + } + + private static class WrappedGateinRequest extends + WrappedHttpAndPortletRequest { + public WrappedGateinRequest(PortletRequest request, + DeploymentConfiguration deploymentConfiguration) { + super(request, getOriginalRequest(request), deploymentConfiguration); + } + + private static final HttpServletRequest getOriginalRequest( + PortletRequest request) { + try { + Method getRealReq = request.getClass().getMethod( + "getRealRequest"); + HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq + .invoke(request); + return origRequest; + } catch (Exception e) { + throw new IllegalStateException("GateIn request not detected", + e); + } + } + } + + private static class WrappedLiferayRequest extends + WrappedHttpAndPortletRequest { + + public WrappedLiferayRequest(PortletRequest request, + DeploymentConfiguration deploymentConfiguration) { + super(request, getOriginalRequest(request), deploymentConfiguration); + } + + @Override + public String getPortalProperty(String name) { + return PropsUtil.get(name); + } + + private static HttpServletRequest getOriginalRequest( + PortletRequest request) { + try { + // httpRequest = PortalUtil.getHttpServletRequest(request); + HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker + .invoke("com.liferay.portal.util.PortalUtil", + "getHttpServletRequest", request); + + // httpRequest = + // PortalUtil.getOriginalServletRequest(httpRequest); + httpRequest = (HttpServletRequest) PortalClassInvoker.invoke( + "com.liferay.portal.util.PortalUtil", + "getOriginalServletRequest", httpRequest); + return httpRequest; + } catch (Exception e) { + throw new IllegalStateException("Liferay request not detected", + e); + } + } + + } + + private static class AbstractApplicationPortletWrapper implements Callback { + + private final AbstractApplicationPortlet portlet; + + public AbstractApplicationPortletWrapper( + AbstractApplicationPortlet portlet) { + this.portlet = portlet; + } + + public void criticalNotification(WrappedRequest request, + WrappedResponse response, String cap, String msg, + String details, String outOfSyncURL) throws IOException { + PortletRequest portletRequest = WrappedPortletRequest.cast(request) + .getPortletRequest(); + PortletResponse portletResponse = ((WrappedPortletResponse) response) + .getPortletResponse(); + portlet.criticalNotification(portletRequest, + (MimeResponse) portletResponse, cap, msg, details, + outOfSyncURL); + } + } + /** * This portlet parameter is used to add styles to the main element. E.g * "height:500px" generates a style="height:500px" to the main element. */ public static final String PORTLET_PARAMETER_STYLE = "style"; - private static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; + /** + * This portal parameter is used to define the name of the Vaadin theme that + * is used for all Vaadin applications in the portal. + */ + public static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; // TODO some parts could be shared with AbstractApplicationServlet // TODO Can we close the application when the portlet is removed? Do we know // when the portlet is removed? - // TODO What happens when the portlet window is resized? Do we know when the - // window is resized? - private Properties applicationProperties; private boolean productionMode = false; + private DeploymentConfiguration deploymentConfiguration = new DeploymentConfiguration() { + public String getConfiguredWidgetset(WrappedRequest request) { + + String widgetset = getApplicationOrSystemProperty( + PARAMETER_WIDGETSET, null); + + if (widgetset == null) { + // If no widgetset defined for the application, check the portal + // property + widgetset = WrappedPortletRequest.cast(request) + .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET); + } + + if (widgetset == null) { + // If no widgetset defined for the portal, use the default + widgetset = DEFAULT_WIDGETSET; + } + + return widgetset; + } + + public String getConfiguredTheme(WrappedRequest request) { + + // is the default theme defined by the portal? + String themeName = WrappedPortletRequest.cast(request) + .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME); + + if (themeName == null) { + // no, using the default theme defined by Vaadin + themeName = DEFAULT_THEME_NAME; + } + + return themeName; + } + + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue) { + return AbstractApplicationPortlet.this + .getApplicationOrSystemProperty(propertyName, defaultValue); + } + + public boolean isStandalone(WrappedRequest request) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation + * (com.vaadin.terminal.WrappedRequest) + * + * Return the URL from where static files, e.g. the widgetset and the + * theme, are served. In a standard configuration the VAADIN folder + * inside the returned folder is what is used for widgetsets and themes. + * + * @return The location of static resources (inside which there should + * be a VAADIN directory). Does not end with a slash (/). + */ + public String getStaticFileLocation(WrappedRequest request) { + String staticFileLocation = WrappedPortletRequest.cast(request) + .getPortalProperty( + Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH); + if (staticFileLocation != null) { + // remove trailing slash if any + while (staticFileLocation.endsWith(".")) { + staticFileLocation = staticFileLocation.substring(0, + staticFileLocation.length() - 1); + } + return staticFileLocation; + } else { + // default for Liferay + return "/html"; + } + } + + public ClassLoader getClassLoader() { + // Custom class loaders not currently supported in portlets (see + // #8574) + return null; + } + }; + @Override public void init(PortletConfig config) throws PortletException { super.init(config); - // Stores the application parameters into Properties object applicationProperties = new Properties(); - for (final Enumeration<String> e = config.getInitParameterNames(); e + + // Read default parameters from the context + final PortletContext context = config.getPortletContext(); + for (final Enumeration<String> e = context.getInitParameterNames(); e .hasMoreElements();) { final String name = e.nextElement(); applicationProperties.setProperty(name, - config.getInitParameter(name)); + context.getInitParameter(name)); } - // Overrides with server.xml parameters - final PortletContext context = config.getPortletContext(); - for (final Enumeration<String> e = context.getInitParameterNames(); e + // Override with application settings from portlet.xml + for (final Enumeration<String> e = config.getInitParameterNames(); e .hasMoreElements();) { final String name = e.nextElement(); applicationProperties.setProperty(name, - context.getInitParameter(name)); + config.getInitParameter(name)); } + checkProductionMode(); checkCrossSiteProtection(); } @@ -133,25 +339,21 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet * * @param request */ - private void checkWidgetsetVersion(PortletRequest request) { - if (!AbstractApplicationServlet.VERSION.equals(getHTTPRequestParameter( - request, "wsver"))) { + private void checkWidgetsetVersion(WrappedRequest request) { + if (!AbstractApplicationServlet.VERSION.equals(request + .getParameter("wsver"))) { logger.warning(String.format(WIDGETSET_MISMATCH_INFO, AbstractApplicationServlet.VERSION, - getHTTPRequestParameter(request, "wsver"))); + request.getParameter("wsver"))); } } private void checkProductionMode() { + // TODO Identical code in AbstractApplicationServlet -> refactor // Check if the application is in production mode. - // We are in production mode if Debug=false or productionMode=true - if (getApplicationOrSystemProperty(SERVLET_PARAMETER_DEBUG, "true") - .equals("false")) { - // "Debug=true" is the old way and should no longer be used - productionMode = true; - } else if (getApplicationOrSystemProperty( - SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) { - // "productionMode=true" is the real way to do it + // We are in production mode if productionMode=true + if (getApplicationOrSystemProperty(SERVLET_PARAMETER_PRODUCTION_MODE, + "false").equals("true")) { productionMode = true; } @@ -241,48 +443,24 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet return defaultValue; } - /** - * Return the URL from where static files, e.g. the widgetset and the theme, - * are served. In a standard configuration the VAADIN folder inside the - * returned folder is what is used for widgetsets and themes. - * - * @param request - * @return The location of static resources (inside which there should be a - * VAADIN directory). Does not end with a slash (/). - */ - protected String getStaticFilesLocation(PortletRequest request) { - // TODO allow overriding on portlet level? - String staticFileLocation = getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH, - request.getPortalContext()); - if (staticFileLocation != null) { - // remove trailing slash if any - while (staticFileLocation.endsWith(".")) { - staticFileLocation = staticFileLocation.substring(0, - staticFileLocation.length() - 1); - } - return staticFileLocation; - } else { - // default for Liferay - return "/html"; - } - } - protected enum RequestType { - FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN; + FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS; } protected RequestType getRequestType(PortletRequest request) { if (request instanceof RenderRequest) { return RequestType.RENDER; } else if (request instanceof ResourceRequest) { - if (isUIDLRequest((ResourceRequest) request)) { + ResourceRequest resourceRequest = (ResourceRequest) request; + if (isUIDLRequest(resourceRequest)) { return RequestType.UIDL; - } else if (isFileUploadRequest((ResourceRequest) request)) { + } else if (isBrowserDetailsRequeset(resourceRequest)) { + return RequestType.BROWSER_DETAILS; + } else if (isFileUploadRequest(resourceRequest)) { return RequestType.FILE_UPLOAD; - } else if (isApplicationResourceRequest((ResourceRequest) request)) { + } else if (isApplicationResourceRequest(resourceRequest)) { return RequestType.APPLICATION_RESOURCE; - } else if (isDummyRequest((ResourceRequest) request)) { + } else if (isDummyRequest(resourceRequest)) { return RequestType.DUMMY; } else { return RequestType.STATIC_FILE; @@ -295,6 +473,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet return RequestType.UNKNOWN; } + private boolean isBrowserDetailsRequeset(ResourceRequest request) { + return request.getResourceID() != null + && request.getResourceID().equals("browserDetails"); + } + private boolean isApplicationResourceRequest(ResourceRequest request) { return request.getResourceID() != null && request.getResourceID().startsWith("APP"); @@ -326,8 +509,27 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet protected void handleRequest(PortletRequest request, PortletResponse response) throws PortletException, IOException { - RequestTimer.RequestWrapper wrappedRequest = new RequestTimer.RequestWrapper( - request); + AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( + this); + + WrappedPortletRequest wrappedRequest; + + String portalInfo = request.getPortalContext().getPortalInfo() + .toLowerCase(); + if (portalInfo.contains("liferay")) { + wrappedRequest = new WrappedLiferayRequest(request, + getDeploymentConfiguration()); + } else if (portalInfo.contains("gatein")) { + wrappedRequest = new WrappedGateinRequest(request, + getDeploymentConfiguration()); + } else { + wrappedRequest = new WrappedPortletRequest(request, + getDeploymentConfiguration()); + } + + WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( + response, getDeploymentConfiguration()); + RequestTimer requestTimer = RequestTimer.get(wrappedRequest); requestTimer.start(wrappedRequest); @@ -360,10 +562,12 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet // TODO What about PARAM_UNLOADBURST & redirectToApplication?? /* Find out which application this request is related to */ - application = findApplicationInstance(request, requestType); + application = findApplicationInstance(wrappedRequest, + requestType); if (application == null) { return; } + Application.setCurrentApplication(application); /* * Get or create an application context and an application @@ -378,8 +582,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet .getApplicationManager(application); /* Update browser information from request */ - updateBrowserProperties(applicationContext.getBrowser(), - request); + applicationContext.getBrowser().updateRequestDetails( + wrappedRequest); /* * Call application requestStart before Application.init() is @@ -404,20 +608,36 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet /* Notify listeners */ // Finds the window within the application - Window window = null; + Root root = null; synchronized (application) { if (application.isRunning()) { switch (requestType) { + case RENDER: + case ACTION: + // Both action requests and render requests are ok + // without a Root as they render the initial HTML + // and then do a second request + try { + root = application + .getRootForRequest(wrappedRequest); + } catch (RootRequiresMoreInformationException e) { + // Ignore problem and continue without root + } + break; + case BROWSER_DETAILS: + // Should not try to find a root here as the + // combined request details might change the root + break; case FILE_UPLOAD: // no window break; case APPLICATION_RESOURCE: // use main window - should not need any window - window = application.getMainWindow(); + // root = application.getRoot(); break; default: - window = applicationManager.getApplicationWindow( - request, this, application, null); + root = application + .getRootForRequest(wrappedRequest); } // if window not found, not a problem - use null } @@ -427,37 +647,39 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet // starts? if (request instanceof RenderRequest) { applicationContext.firePortletRenderRequest(application, - window, (RenderRequest) request, + root, (RenderRequest) request, (RenderResponse) response); } else if (request instanceof ActionRequest) { applicationContext.firePortletActionRequest(application, - window, (ActionRequest) request, + root, (ActionRequest) request, (ActionResponse) response); } else if (request instanceof EventRequest) { applicationContext.firePortletEventRequest(application, - window, (EventRequest) request, + root, (EventRequest) request, (EventResponse) response); } else if (request instanceof ResourceRequest) { applicationContext.firePortletResourceRequest(application, - window, (ResourceRequest) request, + root, (ResourceRequest) request, (ResourceResponse) response); } /* Handle the request */ if (requestType == RequestType.FILE_UPLOAD) { - applicationManager.handleFileUpload( - (ResourceRequest) request, - (ResourceResponse) response); + applicationManager.handleFileUpload(wrappedRequest, + wrappedResponse); + return; + } else if (requestType == RequestType.BROWSER_DETAILS) { + applicationManager.handleBrowserDetailsRequest( + wrappedRequest, wrappedResponse, application); return; } else if (requestType == RequestType.UIDL) { // Handles AJAX UIDL requests if (isRepaintAll(request)) { // warn if versions do not match - checkWidgetsetVersion(request); + checkWidgetsetVersion(wrappedRequest); } - applicationManager.handleUidlRequest( - (ResourceRequest) request, - (ResourceResponse) response, this, window); + applicationManager.handleUidlRequest(wrappedRequest, + wrappedResponse, portletWrapper, root); return; } else { /* @@ -468,8 +690,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet return; } - handleOtherRequest(request, response, requestType, - application, window, applicationContext, + handleOtherRequest(wrappedRequest, wrappedResponse, + requestType, application, applicationContext, applicationManager); } } catch (final SessionExpiredException e) { @@ -490,10 +712,15 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet .endTransaction(application, request); } } finally { - if (requestStarted) { - ((PortletRequestListener) application).onRequestEnd( - request, response); + try { + if (requestStarted) { + ((PortletRequestListener) application) + .onRequestEnd(request, response); + } + } finally { + Root.setCurrentRoot(null); + Application.setCurrentApplication(null); } requestTimer.stop(); @@ -503,6 +730,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } } + private DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } + private void handleUnknownRequest(PortletRequest request, PortletResponse response) { logger.warning("Unknown request type"); @@ -525,37 +756,18 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet * @throws IOException * @throws MalformedURLException */ - private void handleOtherRequest(PortletRequest request, - PortletResponse response, RequestType requestType, - Application application, Window window, + private void handleOtherRequest(WrappedPortletRequest request, + WrappedResponse response, RequestType requestType, + Application application, PortletApplicationContext2 applicationContext, PortletCommunicationManager applicationManager) throws PortletException, IOException, MalformedURLException { - if (window == null) { - throw new PortletException(ERROR_NO_WINDOW_FOUND); - } - - /* - * Sets terminal type for the window, if not already set - */ - if (window.getTerminal() == null) { - window.setTerminal(applicationContext.getBrowser()); - } - - /* - * Handle parameters - */ - final Map<String, String[]> parameters = request.getParameterMap(); - if (window != null && parameters != null) { - window.handleParameters(parameters); - } - - if (requestType == RequestType.APPLICATION_RESOURCE) { - handleURI(applicationManager, window, (ResourceRequest) request, - (ResourceResponse) response); - } else if (requestType == RequestType.RENDER) { - writeAjaxPage((RenderRequest) request, (RenderResponse) response, - window, application); + if (requestType == RequestType.APPLICATION_RESOURCE + || requestType == RequestType.RENDER) { + if (!applicationManager.handleApplicationRequest(request, response)) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + "Not found"); + } } else if (requestType == RequestType.EVENT) { // nothing to do, listeners do all the work } else if (requestType == RequestType.ACTION) { @@ -566,126 +778,12 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } } - private void updateBrowserProperties(WebBrowser browser, - PortletRequest request) { - String userAgent = getHTTPHeader(request, "user-agent"); - browser.updateRequestDetails(request.getLocale(), null, - request.isSecure(), userAgent); - if (getHTTPRequestParameter(request, "repaintAll") != null) { - browser.updateClientSideDetails( - getHTTPRequestParameter(request, "sw"), - getHTTPRequestParameter(request, "sh"), - getHTTPRequestParameter(request, "cw"), - getHTTPRequestParameter(request, "ch"), - getHTTPRequestParameter(request, "tzo"), - getHTTPRequestParameter(request, "rtzo"), - getHTTPRequestParameter(request, "dstd"), - getHTTPRequestParameter(request, "dstActive"), - getHTTPRequestParameter(request, "curdate"), - getHTTPRequestParameter(request, "td") != null); - } - } - @Override public void processEvent(EventRequest request, EventResponse response) throws PortletException, IOException { handleRequest(request, response); } - private boolean handleURI(PortletCommunicationManager applicationManager, - Window window, ResourceRequest request, ResourceResponse response) - throws IOException { - // Handles the URI - DownloadStream download = applicationManager.handleURI(window, request, - response, this); - - // A download request - if (download != null) { - // Client downloads an resource - handleDownload(download, request, response); - return true; - } - - return false; - } - - private void handleDownload(DownloadStream stream, ResourceRequest request, - ResourceResponse response) throws IOException { - - if (stream.getParameter("Location") != null) { - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(HttpServletResponse.SC_MOVED_TEMPORARILY)); - response.setProperty("Location", stream.getParameter("Location")); - return; - } - - // Download from given stream - final InputStream data = stream.getStream(); - if (data != null) { - - OutputStream out = null; - try { - - // Sets content type - response.setContentType(stream.getContentType()); - - // Sets cache headers - final long cacheTime = stream.getCacheTime(); - if (cacheTime <= 0) { - response.setProperty("Cache-Control", "no-cache"); - response.setProperty("Pragma", "no-cache"); - response.setProperty("Expires", "0"); - } else { - response.setProperty("Cache-Control", "max-age=" - + cacheTime / 1000); - response.setProperty("Expires", - "" + System.currentTimeMillis() + cacheTime); - // Required to apply caching in some Tomcats - response.setProperty("Pragma", "cache"); - } - - // Copy download stream parameters directly - // to HTTP headers. - final Iterator<String> i = stream.getParameterNames(); - if (i != null) { - while (i.hasNext()) { - final String param = i.next(); - response.setProperty(param, stream.getParameter(param)); - } - } - - // suggest local filename from DownloadStream if - // Content-Disposition - // not explicitly set - String contentDispositionValue = stream - .getParameter("Content-Disposition"); - if (contentDispositionValue == null) { - contentDispositionValue = "filename=\"" - + stream.getFileName() + "\""; - response.setProperty("Content-Disposition", - contentDispositionValue); - } - - int bufferSize = stream.getBufferSize(); - if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) { - bufferSize = DEFAULT_BUFFER_SIZE; - } - final byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - - out = response.getPortletOutputStream(); - - while ((bytesRead = data.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - out.flush(); - } - } finally { - AbstractCommunicationManager.tryToCloseStream(data); - AbstractCommunicationManager.tryToCloseStream(out); - } - } - } - private void serveStaticResources(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { final String resourceID = request.getResourceID(); @@ -774,7 +872,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet Locale locale = request.getLocale(); application.setLocale(locale); // No application URL when running inside a portlet - application.start(null, applicationProperties, context); + application.start(new ApplicationStartEvent(null, + applicationProperties, context, isProductionMode())); } } @@ -788,9 +887,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet // Do not send any redirects when running inside a portlet. } - private Application findApplicationInstance(PortletRequest request, - RequestType requestType) throws PortletException, - SessionExpiredException, MalformedURLException { + private Application findApplicationInstance( + WrappedPortletRequest wrappedRequest, RequestType requestType) + throws PortletException, SessionExpiredException, + MalformedURLException { + PortletRequest request = wrappedRequest.getPortletRequest(); boolean requestCanCreateApplication = requestCanCreateApplication( request, requestType); @@ -805,10 +906,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet * user not specifically requested to close or restart it. */ - final boolean restartApplication = (getHTTPRequestParameter( - request, URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (getHTTPRequestParameter(request, - URL_PARAMETER_CLOSE_APPLICATION) != null); + final boolean restartApplication = (wrappedRequest + .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); + final boolean closeApplication = (wrappedRequest + .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); if (restartApplication) { closeApplication(application, request.getPortletSession(false)); @@ -878,436 +979,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet return null; } - /** - * Returns the URL from which the widgetset is served on the portal. - * - * @param widgetset - * @param request - * @return - */ - protected String getWidgetsetURL(String widgetset, PortletRequest request) { - return getStaticFilesLocation(request) + "/" + WIDGETSET_DIRECTORY_PATH - + widgetset + "/" + widgetset + ".nocache.js?" - + new Date().getTime(); - } - - /** - * Returns the theme URI for the named theme on the portal. - * - * Note that this is not the only location referring to the theme URI - also - * e.g. PortletCommunicationManager uses its own way to access the portlet - * 2.0 theme resources. - * - * @param themeName - * @param request - * @return - */ - protected String getThemeURI(String themeName, PortletRequest request) { - return getStaticFilesLocation(request) + "/" + THEME_DIRECTORY_PATH - + themeName; - } - - /** - * Writes the html host page (aka kickstart page) that starts the actual - * Vaadin application. - * - * If one needs to override parts of the portlet HTML contents creation, it - * is suggested that one overrides one of several submethods including: - * <ul> - * <li> - * {@link #writeAjaxPageHtmlMainDiv(RenderRequest, RenderResponse, BufferedWriter, String)} - * <li> - * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)} - * <li> - * {@link #writeAjaxPageHtmlVaadinScripts(RenderRequest, RenderResponse, BufferedWriter, Application, String)} - * </ul> - * - * @param request - * the portlet request. - * @param response - * the portlet response to write to. - * @param window - * @param application - * @throws IOException - * if the writing failed due to input/output error. - * @throws MalformedURLException - * if the application is denied access the persistent data store - * represented by the given URL. - * @throws PortletException - */ - protected void writeAjaxPage(RenderRequest request, - RenderResponse response, Window window, Application application) - throws IOException, MalformedURLException, PortletException { - - response.setContentType("text/html"); - final BufferedWriter page = new BufferedWriter(new OutputStreamWriter( - response.getPortletOutputStream(), "UTF-8")); - - // TODO Currently, we can only load widgetsets and themes from the - // portal - - String themeName = getThemeForWindow(request, window); - - writeAjaxPageHtmlVaadinScripts(request, response, page, application, - themeName); - - /*- Add classnames; - * .v-app - * .v-app-loading - * .v-app-<simpleName for app class> - * .v-theme-<themeName, remove non-alphanum> - */ - String appClass = "v-app-"; - try { - appClass += getApplicationClass().getSimpleName(); - } catch (ClassNotFoundException e) { - appClass += "unknown"; - logger.log(Level.SEVERE, "Could not find application class", e); - } - String themeClass = "v-theme-" - + themeName.replaceAll("[^a-zA-Z0-9]", ""); - - String classNames = "v-app " + themeClass + " " + appClass; - - String style = getApplicationProperty(PORTLET_PARAMETER_STYLE); - String divStyle = ""; - if (style != null) { - divStyle = "style=\"" + style + "\""; - } - - writeAjaxPageHtmlMainDiv(request, response, page, - getApplicationDomId(request), classNames, divStyle); - - page.close(); - } - - /** - * Creates and returns a unique ID for the DIV where the application is to - * be rendered. We need to generate a unique ID because some portals already - * create a DIV with the portlet's Window ID as the DOM ID. - * - * @param request - * PortletRequest - * @return the id to use in the DOM - */ - private String getApplicationDomId(PortletRequest request) { - return "v-" + request.getWindowID(); - } - - /** - * This method writes the scripts to load the widgetset and the themes as - * well as define Vaadin configuration parameters on the HTML fragment that - * starts the actual Vaadin application. - * - * @param request - * @param response - * @param writer - * @param application - * @param themeName - * @throws IOException - * @throws PortletException - */ - protected void writeAjaxPageHtmlVaadinScripts(RenderRequest request, - RenderResponse response, final BufferedWriter writer, - Application application, String themeName) throws IOException, - PortletException { - String themeURI = getThemeURI(themeName, request); - - // fixed base theme to use - all portal pages with Vaadin - // applications will load this exactly once - String portalTheme = getPortalProperty(PORTAL_PARAMETER_VAADIN_THEME, - request.getPortalContext()); - - writer.write("<script type=\"text/javascript\">\n"); - writer.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n " - + "if(!vaadin) { var vaadin = {}} \n" - + "vaadin.vaadinConfigurations = {};\n" - + "if (!vaadin.themesLoaded) { vaadin.themesLoaded = {}; }\n"); - if (!isProductionMode()) { - writer.write("vaadin.debug = true;\n"); - } - - writeAjaxPageScriptWidgetset(request, response, writer); - - Map<String, String> config = getVaadinConfigurationMap(request, - response, application, themeURI); - writeAjaxPageScriptConfigurations(request, response, writer, config); - - writer.write("</script>\n"); - - writeAjaxPageHtmlTheme(request, writer, themeName, themeURI, - portalTheme); - - // TODO Warn if widgetset has not been loaded after 15 seconds - } - - /** - * Writes the script to load the widgetset on the HTML fragment created by - * the portlet. - * - * @param request - * @param response - * @param writer - * @throws IOException - */ - protected void writeAjaxPageScriptWidgetset(RenderRequest request, - RenderResponse response, final BufferedWriter writer) - throws IOException { - String requestWidgetset = getApplicationOrSystemProperty( - PARAMETER_WIDGETSET, null); - String sharedWidgetset = getPortalProperty( - PORTAL_PARAMETER_VAADIN_WIDGETSET, request.getPortalContext()); - - String widgetset; - if (requestWidgetset != null) { - widgetset = requestWidgetset; - } else if (sharedWidgetset != null) { - widgetset = sharedWidgetset; - } else { - widgetset = DEFAULT_WIDGETSET; - } - String widgetsetURL = getWidgetsetURL(widgetset, request); - writer.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" " - + "style=\"position:absolute;width:0;height:0;border:0;overflow:" - + "hidden;opacity:0;top:-100px;left:-100px;\" src=\"javascript:false\"></iframe>');\n"); - writer.write("document.write(\"<script language='javascript' src='" - + widgetsetURL + "'><\\/script>\");\n}\n"); - } - - /** - * Returns the configuration parameters to pass to the client. - * - * To add configuration parameters for the client, override, call the super - * method and then modify the map. Overriding this method may also require - * client side changes in {@link ApplicationConnection} and - * {@link ApplicationConfiguration}. - * - * Note that this method must escape and quote the values when appropriate. - * - * The map returned is typically a {@link LinkedHashMap} to preserve - * insertion order, but it is not guaranteed to be one. - * - * @param request - * @param response - * @param application - * @param themeURI - * @return modifiable Map from parameter name to its full value - * @throws PortletException - */ - protected Map<String, String> getVaadinConfigurationMap( - RenderRequest request, RenderResponse response, - Application application, String themeURI) throws PortletException { - Map<String, String> config = new LinkedHashMap<String, String>(); - - /* - * We need this in order to get uploads to work. TODO this is not needed - * for uploads anymore, check if this is needed for some other things - */ - PortletURL appUri = response.createActionURL(); - config.put("appUri", "'" + appUri.toString() + "'"); - config.put("usePortletURLs", "true"); - ResourceURL uidlUrlBase = response.createResourceURL(); - uidlUrlBase.setResourceID("UIDL"); - config.put("portletUidlURLBase", "'" + uidlUrlBase.toString() + "'"); - config.put("pathInfo", "''"); - config.put("themeUri", "'" + themeURI + "'"); - - String versionInfo = "{vaadinVersion:\"" - + AbstractApplicationServlet.VERSION - + "\",applicationVersion:\"" + application.getVersion() + "\"}"; - config.put("versionInfo", versionInfo); - - // Get system messages - Application.SystemMessages systemMessages = null; - try { - systemMessages = getSystemMessages(); - } catch (SystemMessageException e) { - // failing to get the system messages is always a problem - throw new PortletException("Failed to obtain system messages!", e); - } - if (systemMessages != null) { - // Write the CommunicationError -message to client - String caption = systemMessages.getCommunicationErrorCaption(); - if (caption != null) { - caption = "\"" + caption + "\""; - } - String message = systemMessages.getCommunicationErrorMessage(); - if (message != null) { - message = "\"" + message + "\""; - } - String url = systemMessages.getCommunicationErrorURL(); - if (url != null) { - url = "\"" + url + "\""; - } - - config.put("\"comErrMsg\"", "{" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}"); - - // Write the AuthenticationError -message to client - caption = systemMessages.getAuthenticationErrorCaption(); - if (caption != null) { - caption = "\"" + caption + "\""; - } - message = systemMessages.getAuthenticationErrorMessage(); - if (message != null) { - message = "\"" + message + "\""; - } - url = systemMessages.getAuthenticationErrorURL(); - if (url != null) { - url = "\"" + url + "\""; - } - - config.put("\"authErrMsg\"", "{" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}"); - } - - return config; - } - - /** - * Constructs the Vaadin configuration section for - * {@link ApplicationConnection} and {@link ApplicationConfiguration}. - * - * Typically this method should not be overridden. Instead, modify - * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)} - * . - * - * @param request - * @param response - * @param writer - * @param config - * @throws IOException - * @throws PortletException - */ - protected void writeAjaxPageScriptConfigurations(RenderRequest request, - RenderResponse response, final BufferedWriter writer, - Map<String, String> config) throws IOException, PortletException { - - writer.write("vaadin.vaadinConfigurations[\"" - + getApplicationDomId(request) + "\"] = {"); - - Iterator<String> keyIt = config.keySet().iterator(); - while (keyIt.hasNext()) { - String key = keyIt.next(); - writer.write(key + ": " + config.get(key)); - if (keyIt.hasNext()) { - writer.write(", "); - } - } - - writer.write("};\n"); - } - - /** - * Writes the Vaadin theme loading section of the portlet HTML. Loads both - * the portal theme and the portlet theme in this order, skipping loading of - * themes that are already loaded (matched by name). - * - * @param request - * @param writer - * @param themeName - * @param themeURI - * @param portalTheme - * @throws IOException - */ - protected void writeAjaxPageHtmlTheme(RenderRequest request, - final BufferedWriter writer, String themeName, String themeURI, - String portalTheme) throws IOException { - writer.write("<script type=\"text/javascript\">\n"); - - if (portalTheme == null) { - portalTheme = DEFAULT_THEME_NAME; - } - - writer.write("if(!vaadin.themesLoaded['" + portalTheme + "']) {\n"); - writer.write("var defaultStylesheet = document.createElement('link');\n"); - writer.write("defaultStylesheet.setAttribute('rel', 'stylesheet');\n"); - writer.write("defaultStylesheet.setAttribute('type', 'text/css');\n"); - writer.write("defaultStylesheet.setAttribute('href', '" - + getThemeURI(portalTheme, request) + "/styles.css');\n"); - writer.write("document.getElementsByTagName('head')[0].appendChild(defaultStylesheet);\n"); - writer.write("vaadin.themesLoaded['" + portalTheme + "'] = true;\n}\n"); - - if (!portalTheme.equals(themeName)) { - writer.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n"); - writer.write("var stylesheet = document.createElement('link');\n"); - writer.write("stylesheet.setAttribute('rel', 'stylesheet');\n"); - writer.write("stylesheet.setAttribute('type', 'text/css');\n"); - writer.write("stylesheet.setAttribute('href', '" + themeURI - + "/styles.css');\n"); - writer.write("document.getElementsByTagName('head')[0].appendChild(stylesheet);\n"); - writer.write("vaadin.themesLoaded['" + themeName - + "'] = true;\n}\n"); - } - - writer.write("</script>\n"); - } - - /** - * Method to write the div element into which that actual Vaadin application - * is rendered. - * <p> - * Override this method if you want to add some custom html around around - * the div element into which the actual Vaadin application will be - * rendered. - * - * @param request - * @param response - * @param writer - * @param id - * @param classNames - * @param divStyle - * @throws IOException - */ - protected void writeAjaxPageHtmlMainDiv(RenderRequest request, - RenderResponse response, final BufferedWriter writer, String id, - String classNames, String divStyle) throws IOException { - writer.write("<div id=\"" + id + "\" class=\"" + classNames + "\" " - + divStyle + ">"); - writer.write("<div class=\"v-app-loading\"></div>"); - writer.write("</div>\n"); - writer.write("<noscript>" + getNoScriptMessage() + "</noscript>"); - } - - /** - * Returns a message printed for browsers without scripting support or if - * browsers scripting support is disabled. - */ - protected String getNoScriptMessage() { - return "You have to enable javascript in your browser to use an application built with Vaadin."; - } - - /** - * Returns the theme for given request/window - * - * @param request - * @param window - * @return - */ - protected String getThemeForWindow(PortletRequest request, Window window) { - // Finds theme name - String themeName; - - // theme defined for the window? - themeName = window.getTheme(); - - if (themeName == null) { - // no, is the default theme defined by the portal? - themeName = getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_THEME, - request.getPortalContext()); - } - - if (themeName == null) { - // no, using the default theme defined by Vaadin - themeName = DEFAULT_THEME_NAME; - } - - return themeName; - } - protected abstract Class<? extends Application> getApplicationClass() throws ClassNotFoundException; @@ -1315,6 +986,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet throws PortletException { try { final Application application = getApplicationClass().newInstance(); + application.setRootPreserved(true); return application; } catch (final IllegalAccessException e) { throw new PortletException("getNewApplication failed", e); @@ -1462,162 +1134,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } /** - * Returns a portal configuration property. - * - * Liferay is handled separately as - * {@link PortalContext#getProperty(String)} does not return portal - * properties from e.g. portal-ext.properties . - * - * @param name - * @param context - * @return - */ - protected static String getPortalProperty(String name, PortalContext context) { - boolean isLifeRay = context.getPortalInfo().toLowerCase() - .contains("liferay"); - - // TODO test on non-LifeRay platforms - - String value; - if (isLifeRay) { - value = getLifeRayPortalProperty(name); - } else { - value = context.getProperty(name); - } - - return value; - } - - private static String getLifeRayPortalProperty(String name) { - String value; - try { - value = PropsUtil.get(name); - } catch (Exception e) { - value = null; - } - return value; - } - - /** - * Try to get an HTTP header value from a request using portal specific - * APIs. - * - * @param name - * HTTP header name - * @return the value of the header (empty string if defined without a value, - * null if the parameter is not present or retrieving it failed) - */ - private static String getHTTPHeader(PortletRequest request, String name) { - String value = null; - String portalInfo = request.getPortalContext().getPortalInfo() - .toLowerCase(); - if (portalInfo.contains("liferay")) { - value = getLiferayHTTPHeader(request, name); - } else if (portalInfo.contains("gatein")) { - value = getGateInHTTPHeader(request, name); - } - return value; - } - - /** - * Try to get the value of a HTTP request parameter from a portlet request - * using portal specific APIs. It is not possible to get the HTTP request - * parameters using the official Portlet 2.0 API. - * - * @param name - * HTTP request parameter name - * @return the value of the parameter (empty string if parameter defined - * without a value, null if the parameter is not present or - * retrieving it failed) - */ - private static String getHTTPRequestParameter(PortletRequest request, - String name) { - String value = request.getParameter(name); - if (value == null) { - String portalInfo = request.getPortalContext().getPortalInfo() - .toLowerCase(); - if (portalInfo.contains("liferay")) { - value = getLiferayHTTPRequestParameter(request, name); - } else if (portalInfo.contains("gatein")) { - value = getGateInHTTPRequestParameter(request, name); - } - } - return value; - } - - private static String getGateInHTTPRequestParameter(PortletRequest request, - String name) { - String value = null; - try { - Method getRealReq = request.getClass().getMethod("getRealRequest"); - HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq - .invoke(request); - value = origRequest.getParameter(name); - } catch (Exception e) { - // do nothing - not on GateIn simple-portal - } - return value; - } - - private static String getLiferayHTTPRequestParameter( - PortletRequest request, String name) { - try { - // httpRequest = PortalUtil.getHttpServletRequest(request); - HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker - .invoke("com.liferay.portal.util.PortalUtil", - "getHttpServletRequest", request); - - // httpRequest = - // PortalUtil.getOriginalServletRequest(httpRequest); - httpRequest = (HttpServletRequest) PortalClassInvoker.invoke( - "com.liferay.portal.util.PortalUtil", - "getOriginalServletRequest", httpRequest); - if (httpRequest != null) { - return httpRequest.getParameter(name); - } - } catch (Exception e) { - // ignore and return null - unable to get the original request - } - return null; - } - - private static String getGateInHTTPHeader(PortletRequest request, - String name) { - String value = null; - try { - Method getRealReq = request.getClass().getMethod("getRealRequest"); - HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq - .invoke(request); - value = origRequest.getHeader(name); - } catch (Exception e) { - // do nothing - not on GateIn simple-portal - } - return value; - } - - private static String getLiferayHTTPHeader(PortletRequest request, - String name) { - try { - // httpRequest = PortalUtil.getHttpServletRequest(request); - HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker - .invoke("com.liferay.portal.util.PortalUtil", - "getHttpServletRequest", request); - - // httpRequest = - // PortalUtil.getOriginalServletRequest(httpRequest); - httpRequest = (HttpServletRequest) PortalClassInvoker.invoke( - "com.liferay.portal.util.PortalUtil", - "getOriginalServletRequest", httpRequest); - if (httpRequest != null) { - return httpRequest.getHeader(name); - } - } catch (Exception e) { - // ignore and return null - unable to get the original request - } - return null; - } - - /** * * Gets the application context for a PortletSession. If no context is * currently stored in a session a new context is created and stored in the diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index 04ea423004..799271b979 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -15,15 +15,14 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.security.GeneralSecurityException; import java.util.Arrays; import java.util.Collection; -import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; -import java.util.Map; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,14 +36,16 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.vaadin.Application; +import com.vaadin.Application.ApplicationStartEvent; import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.ParameterHandler; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.ThemeResource; -import com.vaadin.terminal.URIHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.Window; +import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; +import com.vaadin.ui.Root; /** * Abstract implementation of the ApplicationServlet which handles all @@ -64,6 +65,25 @@ import com.vaadin.ui.Window; public abstract class AbstractApplicationServlet extends HttpServlet implements Constants { + private static class AbstractApplicationServletWrapper implements Callback { + + private final AbstractApplicationServlet servlet; + + public AbstractApplicationServletWrapper( + AbstractApplicationServlet servlet) { + this.servlet = servlet; + } + + public void criticalNotification(WrappedRequest request, + WrappedResponse response, String cap, String msg, + String details, String outOfSyncURL) throws IOException { + servlet.criticalNotification( + WrappedHttpServletRequest.cast(request), + ((WrappedHttpServletResponse) response), cap, msg, details, + outOfSyncURL); + } + } + // TODO Move some (all?) of the constants to a separate interface (shared // with portlet) @@ -115,67 +135,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } } - /** - * If the attribute is present in the request, a html fragment will be - * written instead of a whole page. - * - * It is set to "true" by the {@link ApplicationPortlet} (Portlet 1.0) and - * read by {@link AbstractApplicationServlet}. - */ - public static final String REQUEST_FRAGMENT = ApplicationServlet.class - .getName() + ".fragment"; - /** - * This request attribute forces widgetsets to be loaded from under the - * specified base path; e.g shared widgetset for all portlets in a portal. - * - * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on - * {@link Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH} and read by - * {@link AbstractApplicationServlet}. - */ - public static final String REQUEST_VAADIN_STATIC_FILE_PATH = ApplicationServlet.class - .getName() + ".widgetsetPath"; - /** - * This request attribute forces widgetset used; e.g for portlets that can - * not have different widgetsets. - * - * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on - * {@link ApplicationPortlet.PORTLET_PARAMETER_WIDGETSET} and read by - * {@link AbstractApplicationServlet}. - */ - public static final String REQUEST_WIDGETSET = ApplicationServlet.class - .getName() + ".widgetset"; - /** - * This request attribute indicates the shared widgetset (e.g. portal-wide - * default widgetset). - * - * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on - * {@link Constants.PORTAL_PARAMETER_VAADIN_WIDGETSET} and read by - * {@link AbstractApplicationServlet}. - */ - public static final String REQUEST_SHARED_WIDGETSET = ApplicationServlet.class - .getName() + ".sharedWidgetset"; - /** - * If set, do not load the default theme but assume that loading it is - * handled e.g. by ApplicationPortlet. - * - * It is set by the {@link ApplicationPortlet} (Portlet 1.0) based on - * {@link Constants.PORTAL_PARAMETER_VAADIN_THEME} and read by - * {@link AbstractApplicationServlet}. - */ - public static final String REQUEST_DEFAULT_THEME = ApplicationServlet.class - .getName() + ".defaultThemeUri"; - /** - * This request attribute is used to add styles to the main element. E.g - * "height:500px" generates a style="height:500px" to the main element, - * useful from some embedding situations (e.g portlet include.) - * - * It is typically set by the {@link ApplicationPortlet} (Portlet 1.0) based - * on {@link ApplicationPortlet.PORTLET_PARAMETER_STYLE} and read by - * {@link AbstractApplicationServlet}. - */ - public static final String REQUEST_APPSTYLE = ApplicationServlet.class - .getName() + ".style"; - private Properties applicationProperties; private boolean productionMode = false; @@ -183,6 +142,45 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements private final String resourcePath = null; private int resourceCacheTime = 3600; + + private DeploymentConfiguration deploymentConfiguration = new DeploymentConfiguration() { + public String getStaticFileLocation(WrappedRequest request) { + HttpServletRequest servletRequest = WrappedHttpServletRequest + .cast(request); + return AbstractApplicationServlet.this + .getStaticFilesLocation(servletRequest); + } + + public String getConfiguredWidgetset(WrappedRequest request) { + return getApplicationOrSystemProperty( + AbstractApplicationServlet.PARAMETER_WIDGETSET, + AbstractApplicationServlet.DEFAULT_WIDGETSET); + } + + public String getConfiguredTheme(WrappedRequest request) { + // Use the default + return AbstractApplicationServlet.getDefaultTheme(); + } + + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue) { + return AbstractApplicationServlet.this + .getApplicationOrSystemProperty(propertyName, defaultValue); + } + + public boolean isStandalone(WrappedRequest request) { + return true; + } + + public ClassLoader getClassLoader() { + try { + return AbstractApplicationServlet.this.getClassLoader(); + } catch (ServletException e) { + throw new RuntimeException(e); + } + } + }; + static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/"; /** @@ -201,17 +199,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements public void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException { super.init(servletConfig); - - // Stores the application parameters into Properties object applicationProperties = new Properties(); - for (final Enumeration<String> e = servletConfig - .getInitParameterNames(); e.hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - servletConfig.getInitParameter(name)); - } - // Overrides with server.xml parameters + // Read default parameters from server.xml final ServletContext context = servletConfig.getServletContext(); for (final Enumeration<String> e = context.getInitParameterNames(); e .hasMoreElements();) { @@ -219,6 +209,15 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements applicationProperties.setProperty(name, context.getInitParameter(name)); } + + // Override with application config from web.xml + for (final Enumeration<String> e = servletConfig + .getInitParameterNames(); e.hasMoreElements();) { + final String name = e.nextElement(); + applicationProperties.setProperty(name, + servletConfig.getInitParameter(name)); + } + checkProductionMode(); checkCrossSiteProtection(); checkResourceCacheTime(); @@ -251,14 +250,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements private void checkProductionMode() { // Check if the application is in production mode. - // We are in production mode if Debug=false or productionMode=true - if (getApplicationOrSystemProperty(SERVLET_PARAMETER_DEBUG, "true") - .equals("false")) { - // "Debug=true" is the old way and should no longer be used - productionMode = true; - } else if (getApplicationOrSystemProperty( - SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) { - // "productionMode=true" is the real way to do it + // We are in production mode if productionMode=true + if (getApplicationOrSystemProperty(SERVLET_PARAMETER_PRODUCTION_MODE, + "false").equals("true")) { productionMode = true; } @@ -341,7 +335,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements * the Default to be used. * @return String value or default if not found */ - private String getApplicationOrSystemProperty(String parameterName, + String getApplicationOrSystemProperty(String parameterName, String defaultValue) { String val = null; @@ -397,14 +391,20 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements * @throws IOException * if the request for the TRACE cannot be handled. */ - @SuppressWarnings("unchecked") @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - RequestTimer.RequestWrapper wrappedRequest = new RequestTimer.RequestWrapper( - request); - RequestTimer requestTimer = RequestTimer.get(wrappedRequest); - requestTimer.start(wrappedRequest); + service(createWrappedRequest(request), createWrappedResponse(response)); + } + + private void service(WrappedHttpServletRequest request, + WrappedHttpServletResponse response) throws ServletException, + IOException { + AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( + this); + + RequestTimer requestTimer = RequestTimer.get(request); + requestTimer.start(request); RequestType requestType = getRequestType(request); if (!ensureCookiesEnabled(requestType, request, response)) { @@ -449,6 +449,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements if (application == null) { return; } + Application.setCurrentApplication(application); /* * Get or create a WebApplicationContext and an ApplicationManager @@ -460,7 +461,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements .getApplicationManager(application, this); /* Update browser information from the request */ - updateBrowserProperties(webApplicationContext.getBrowser(), request); + webApplicationContext.getBrowser().updateRequestDetails(request); /* * Call application requestStart before Application.init() is called @@ -472,7 +473,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements requestStarted = true; } - // Start the newly created application + // Start the application if it's newly created startApplication(request, application, webApplicationContext); /* @@ -484,14 +485,21 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements /* Handle the request */ if (requestType == RequestType.FILE_UPLOAD) { - applicationManager.handleFileUpload(request, response); + applicationManager.handleFileUpload(application, request, + response); return; } else if (requestType == RequestType.UIDL) { // Handles AJAX UIDL requests - Window window = applicationManager.getApplicationWindow( - request, this, application, null); - applicationManager.handleUidlRequest(request, response, this, - window); + Root root = application.getRootForRequest(request); + if (root == null) { + throw new ServletException(ERROR_NO_WINDOW_FOUND); + } + applicationManager.handleUidlRequest(request, response, + servletWrapper, root); + return; + } else if (requestType == RequestType.BROWSER_DETAILS) { + applicationManager.handleBrowserDetailsRequest(request, + response, application); return; } @@ -502,34 +510,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return; } - // Finds the window within the application - Window window = getApplicationWindow(request, applicationManager, - application); - if (window == null) { - throw new ServletException(ERROR_NO_WINDOW_FOUND); - } - - // Sets terminal type for the window, if not already set - if (window.getTerminal() == null) { - window.setTerminal(webApplicationContext.getBrowser()); - } - - // Handle parameters - final Map<String, String[]> parameters = request.getParameterMap(); - if (window != null && parameters != null) { - window.handleParameters(parameters); - } - - /* - * Call the URI handlers and if this turns out to be a download - * request, send the file to the client - */ - if (handleURI(applicationManager, window, request, response)) { + if (applicationManager.handleApplicationRequest(request, response)) { return; } - - // Send initial AJAX page that kickstarts a Vaadin application - writeAjaxPage(request, response, window, application); + // TODO Should return 404 error here and not do anything more } catch (final SessionExpiredException e) { // Session has expired, notify user @@ -548,18 +532,53 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } } finally { - if (requestStarted) { - ((HttpServletRequestListener) application).onRequestEnd( - request, response); + try { + if (requestStarted) { + ((HttpServletRequestListener) application) + .onRequestEnd(request, response); + } + } finally { + Root.setCurrentRoot(null); + Application.setCurrentApplication(null); } requestTimer.stop(); - RequestTimer.set(wrappedRequest, requestTimer); + RequestTimer.set(request, requestTimer); } } } + private WrappedHttpServletResponse createWrappedResponse( + HttpServletResponse response) { + WrappedHttpServletResponse wrappedResponse = new WrappedHttpServletResponse( + response, getDeploymentConfiguration()); + return wrappedResponse; + } + + /** + * Create a wrapped request for a http servlet request. This method can be + * overridden if the wrapped request should have special properties. + * + * @param request + * the original http servlet request + * @return a wrapped request for the original request + */ + protected WrappedHttpServletRequest createWrappedRequest( + HttpServletRequest request) { + return new WrappedHttpServletRequest(request, + getDeploymentConfiguration()); + } + + /** + * Gets a the deployment configuration for this servlet. + * + * @return the deployment configuration + */ + protected DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } + /** * Check that cookie support is enabled in the browser. Only checks UIDL * requests. @@ -593,23 +612,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return true; } - private void updateBrowserProperties(WebBrowser browser, - HttpServletRequest request) { - // request based details updated always - browser.updateRequestDetails(request.getLocale(), - request.getRemoteAddr(), request.isSecure(), - request.getHeader("user-agent")); - if (request.getParameter("repaintAll") != null) { - browser.updateClientSideDetails(request.getParameter("sw"), - request.getParameter("sh"), request.getParameter("cw"), - request.getParameter("ch"), request.getParameter("tzo"), - request.getParameter("rtzo"), request.getParameter("dstd"), - request.getParameter("dston"), - request.getParameter("curdate"), - request.getParameter("td") != null); - } - } - protected ClassLoader getClassLoader() throws ServletException { // Gets custom class loader final String classLoaderName = getApplicationOrSystemProperty( @@ -818,7 +820,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements /* * UIDL request contains valid repaintAll=1 event, the user probably * wants to initiate a new application through a custom index.html - * without using writeAjaxPage. + * without using the bootstrap page. */ return true; @@ -864,101 +866,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } /** - * Handles the requested URI. An application can add handlers to do special - * processing, when a certain URI is requested. The handlers are invoked - * before any windows URIs are processed and if a DownloadStream is returned - * it is sent to the client. - * - * @param stream - * the download stream. - * - * @param request - * the HTTP request instance. - * @param response - * the HTTP response to write to. - * @throws IOException - * - * @see com.vaadin.terminal.URIHandler - */ - private void handleDownload(DownloadStream stream, - HttpServletRequest request, HttpServletResponse response) - throws IOException { - - if (stream.getParameter("Location") != null) { - response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - response.addHeader("Location", stream.getParameter("Location")); - return; - } - - // Download from given stream - final InputStream data = stream.getStream(); - if (data != null) { - - OutputStream out = null; - try { - // Sets content type - response.setContentType(stream.getContentType()); - - // Sets cache headers - final long cacheTime = stream.getCacheTime(); - if (cacheTime <= 0) { - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - } else { - response.setHeader("Cache-Control", "max-age=" + cacheTime - / 1000); - response.setDateHeader("Expires", - System.currentTimeMillis() + cacheTime); - response.setHeader("Pragma", "cache"); // Required to apply - // caching in some - // Tomcats - } - - // Copy download stream parameters directly - // to HTTP headers. - final Iterator<String> i = stream.getParameterNames(); - if (i != null) { - while (i.hasNext()) { - final String param = i.next(); - response.setHeader(param, stream.getParameter(param)); - } - } - - // suggest local filename from DownloadStream if - // Content-Disposition - // not explicitly set - String contentDispositionValue = stream - .getParameter("Content-Disposition"); - if (contentDispositionValue == null) { - contentDispositionValue = "filename=\"" - + stream.getFileName() + "\""; - response.setHeader("Content-Disposition", - contentDispositionValue); - } - - int bufferSize = stream.getBufferSize(); - if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE) { - bufferSize = DEFAULT_BUFFER_SIZE; - } - final byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - - out = response.getOutputStream(); - - while ((bytesRead = data.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - out.flush(); - } - } finally { - AbstractCommunicationManager.tryToCloseStream(out); - AbstractCommunicationManager.tryToCloseStream(data); - } - } - - } - - /** * Creates a new application and registers it into WebApplicationContext * (aka session). This is not meant to be overridden. Override * getNewApplication to create the application instance in a custom way. @@ -1002,42 +909,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } /** - * Returns the theme for given request/window - * - * @param request - * @param window - * @return - */ - private String getThemeForWindow(HttpServletRequest request, Window window) { - // Finds theme name - String themeName; - - if (request.getParameter(URL_PARAMETER_THEME) != null) { - themeName = request.getParameter(URL_PARAMETER_THEME); - } else { - themeName = window.getTheme(); - } - - if (themeName == null) { - // no explicit theme for window defined - if (request.getAttribute(REQUEST_DEFAULT_THEME) != null) { - // the default theme is defined in request (by portal) - themeName = (String) request - .getAttribute(REQUEST_DEFAULT_THEME); - } else { - // using the default theme defined by Vaadin - themeName = getDefaultTheme(); - } - } - - // XSS preventation, theme names shouldn't contain special chars anyway. - // The servlet denies them via url parameter. - themeName = stripSpecialChars(themeName); - - return themeName; - } - - /** * A helper method to strip away characters that might somehow be used for * XSS attacs. Leaves at least alphanumeric characters intact. Also removes * eg. ( and ), so values should be safe in javascript too. @@ -1070,34 +941,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return DEFAULT_THEME_NAME; } - /** - * Calls URI handlers for the request. If an URI handler returns a - * DownloadStream the stream is passed to the client for downloading. - * - * @param applicationManager - * @param window - * @param request - * @param response - * @return true if an DownloadStream was sent to the client, false otherwise - * @throws IOException - */ - protected boolean handleURI(CommunicationManager applicationManager, - Window window, HttpServletRequest request, - HttpServletResponse response) throws IOException { - // Handles the URI - DownloadStream download = applicationManager.handleURI(window, request, - response, this); - - // A download request - if (download != null) { - // Client downloads an resource - handleDownload(download, request, response); - return true; - } - - return false; - } - void handleServiceSessionExpired(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -1205,8 +1048,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements // Initial locale comes from the request Locale locale = request.getLocale(); application.setLocale(locale); - application.start(applicationUrl, applicationProperties, - webApplicationContext); + application.start(new ApplicationStartEvent(applicationUrl, + applicationProperties, webApplicationContext, + isProductionMode())); } } @@ -1293,8 +1137,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements // Find the modification timestamp long lastModifiedTime = 0; + URLConnection connection = null; try { - lastModifiedTime = resourceUrl.openConnection().getLastModified(); + connection = resourceUrl.openConnection(); + lastModifiedTime = connection.getLastModified(); // Remove milliseconds to avoid comparison problems (milliseconds // are not returned by the browser in the "If-Modified-Since" // header). @@ -1310,6 +1156,21 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements Level.FINEST, "Failed to find out last modified timestamp. Continuing without it.", e); + } finally { + if (connection instanceof URLConnection) { + try { + // Explicitly close the input stream to prevent it + // from remaining hanging + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4257700 + InputStream is = connection.getInputStream(); + if (is != null) { + is.close(); + } + } catch (IOException e) { + logger.log(Level.INFO, + "Error closing URLConnection input stream", e); + } + } } // Set type mime type if we can determine it based on the filename @@ -1441,12 +1302,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } protected enum RequestType { - FILE_UPLOAD, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE; + FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE; } protected RequestType getRequestType(HttpServletRequest request) { if (isFileUploadRequest(request)) { return RequestType.FILE_UPLOAD; + } else if (isBrowserDetailsRequest(request)) { + return RequestType.BROWSER_DETAILS; } else if (isUIDLRequest(request)) { return RequestType.UIDL; } else if (isStaticResourceRequest(request)) { @@ -1460,6 +1323,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } + private static boolean isBrowserDetailsRequest(HttpServletRequest request) { + return "POST".equals(request.getMethod()) + && request.getParameter("browserDetails") != null; + } + private boolean isApplicationRequest(HttpServletRequest request) { String path = getRequestPathInfo(request); if (path != null && path.startsWith("/APP/")) { @@ -1526,13 +1394,25 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements * @return */ protected SystemMessages getSystemMessages() { + Class<? extends Application> appCls = null; try { - Class<? extends Application> appCls = getApplicationClass(); - Method m = appCls.getMethod("getSystemMessages", (Class[]) null); - return (Application.SystemMessages) m.invoke(null, (Object[]) null); + appCls = getApplicationClass(); } catch (ClassNotFoundException e) { - // This should never happen + // Previous comment claimed that this should never happen throw new SystemMessageException(e); + } + return getSystemMessages(appCls); + } + + public static SystemMessages getSystemMessages( + Class<? extends Application> appCls) { + try { + if (appCls != null) { + Method m = appCls + .getMethod("getSystemMessages", (Class[]) null); + return (Application.SystemMessages) m.invoke(null, + (Object[]) null); + } } catch (SecurityException e) { throw new SystemMessageException( "Application.getSystemMessage() should be static public", e); @@ -1568,15 +1448,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements */ protected String getStaticFilesLocation(HttpServletRequest request) { - // request may have an attribute explicitly telling location (portal - // case) - String staticFileLocation = (String) request - .getAttribute(REQUEST_VAADIN_STATIC_FILE_PATH); - if (staticFileLocation != null) { - // TODO remove trailing slash if any? - return staticFileLocation; - } - return getWebApplicationsStaticFileLocation(request); } @@ -1659,484 +1530,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } /** - * This method writes the html host page (aka kickstart page) that starts - * the actual Vaadin application. - * <p> - * If one needs to override parts of the host page, it is suggested that one - * overrides on of several submethods which are called by this method: - * <ul> - * <li> {@link #setAjaxPageHeaders(HttpServletResponse)} - * <li> - * {@link #writeAjaxPageHtmlHeadStart(BufferedWriter, HttpServletRequest)} - * <li> - * {@link #writeAjaxPageHtmlHeader(BufferedWriter, String, String, HttpServletRequest)} - * <li> - * {@link #writeAjaxPageHtmlBodyStart(BufferedWriter, HttpServletRequest)} - * <li> - * {@link #writeAjaxPageHtmlVaadinScripts(Window, String, Application, BufferedWriter, String, String, String, HttpServletRequest)} - * <li> - * {@link #writeAjaxPageHtmlMainDiv(BufferedWriter, String, String, String, HttpServletRequest)} - * <li> {@link #writeAjaxPageHtmlBodyEnd(BufferedWriter)} - * </ul> - * - * @param request - * the HTTP request. - * @param response - * the HTTP response to write to. - * @param out - * @param unhandledParameters - * @param window - * @param terminalType - * @param theme - * @throws IOException - * if the writing failed due to input/output error. - * @throws MalformedURLException - * if the application is denied access the persistent data store - * represented by the given URL. - */ - protected void writeAjaxPage(HttpServletRequest request, - HttpServletResponse response, Window window, Application application) - throws IOException, MalformedURLException, ServletException { - - // e.g portlets only want a html fragment - boolean fragment = (request.getAttribute(REQUEST_FRAGMENT) != null); - if (fragment) { - // if this is a fragment request, the actual application is put to - // request so ApplicationPortlet can save it for a later use - request.setAttribute(Application.class.getName(), application); - } - - final BufferedWriter page = new BufferedWriter(new OutputStreamWriter( - response.getOutputStream(), "UTF-8")); - - String title = ((window.getCaption() == null) ? "Vaadin 6" : window - .getCaption()); - - /* Fetch relative url to application */ - // don't use server and port in uri. It may cause problems with some - // virtual server configurations which lose the server name - String appUrl = getApplicationUrl(request).getPath(); - if (appUrl.endsWith("/")) { - appUrl = appUrl.substring(0, appUrl.length() - 1); - } - - String themeName = getThemeForWindow(request, window); - - String themeUri = getThemeUri(themeName, request); - - if (!fragment) { - setAjaxPageHeaders(response); - writeAjaxPageHtmlHeadStart(page, request); - writeAjaxPageHtmlHeader(page, title, themeUri, request); - writeAjaxPageHtmlBodyStart(page, request); - } - - String appId = appUrl; - if ("".equals(appUrl)) { - appId = "ROOT"; - } - appId = appId.replaceAll("[^a-zA-Z0-9]", ""); - // Add hashCode to the end, so that it is still (sort of) predictable, - // but indicates that it should not be used in CSS and such: - int hashCode = appId.hashCode(); - if (hashCode < 0) { - hashCode = -hashCode; - } - appId = appId + "-" + hashCode; - - writeAjaxPageHtmlVaadinScripts(window, themeName, application, page, - appUrl, themeUri, appId, request); - - /*- Add classnames; - * .v-app - * .v-app-loading - * .v-app-<simpleName for app class> - * .v-theme-<themeName, remove non-alphanum> - */ - - String appClass = "v-app-" + getApplicationCSSClassName(); - - String themeClass = ""; - if (themeName != null) { - themeClass = "v-theme-" + themeName.replaceAll("[^a-zA-Z0-9]", ""); - } else { - themeClass = "v-theme-" - + getDefaultTheme().replaceAll("[^a-zA-Z0-9]", ""); - } - - String classNames = "v-app " + themeClass + " " + appClass; - - String divStyle = null; - if (request.getAttribute(REQUEST_APPSTYLE) != null) { - divStyle = "style=\"" + request.getAttribute(REQUEST_APPSTYLE) - + "\""; - } - - writeAjaxPageHtmlMainDiv(page, appId, classNames, divStyle, request); - - if (!fragment) { - page.write("</body>\n</html>\n"); - } - - page.close(); - - } - - /** - * Returns the application class identifier for use in the application CSS - * class name in the root DIV. The application CSS class name is of form - * "v-app-"+getApplicationCSSClassName(). - * - * This method should normally not be overridden. - * - * @return The CSS class name to use in combination with "v-app-". - */ - protected String getApplicationCSSClassName() { - try { - return getApplicationClass().getSimpleName(); - } catch (ClassNotFoundException e) { - logger.log(Level.WARNING, "getApplicationCSSClassName failed", e); - return "unknown"; - } - } - - /** - * Get the URI for the application theme. - * - * A portal-wide default theme is fetched from the portal shared resource - * directory (if any), other themes from the portlet. - * - * @param themeName - * @param request - * @return - */ - private String getThemeUri(String themeName, HttpServletRequest request) { - final String staticFilePath; - if (themeName.equals(request.getAttribute(REQUEST_DEFAULT_THEME))) { - // our window theme is the portal wide default theme, make it load - // from portals directory is defined - staticFilePath = getStaticFilesLocation(request); - } else { - /* - * theme is a custom theme, which is not necessarily located in - * portals VAADIN directory. Let the default servlet conf decide - * (omitting request parameter) the location. Note that theme can - * still be placed to portal directory with servlet parameter. - */ - staticFilePath = getWebApplicationsStaticFileLocation(request); - } - return staticFilePath + "/" + THEME_DIRECTORY_PATH + themeName; - } - - /** - * Method to write the div element into which that actual Vaadin application - * is rendered. - * <p> - * Override this method if you want to add some custom html around around - * the div element into which the actual Vaadin application will be - * rendered. - * - * @param page - * @param appId - * @param classNames - * @param divStyle - * @param request - * @throws IOException - */ - protected void writeAjaxPageHtmlMainDiv(final BufferedWriter page, - String appId, String classNames, String divStyle, - HttpServletRequest request) throws IOException { - page.write("<div id=\"" + appId + "\" class=\"" + classNames + "\" " - + (divStyle != null ? divStyle : "") + ">"); - page.write("<div class=\"v-app-loading\"></div>"); - page.write("</div>\n"); - page.write("<noscript>" + getNoScriptMessage() + "</noscript>"); - } - - /** - * Method to write the script part of the page which loads needed Vaadin - * scripts and themes. - * <p> - * Override this method if you want to add some custom html around scripts. - * - * @param window - * @param themeName - * @param application - * @param page - * @param appUrl - * @param themeUri - * @param appId - * @param request - * @throws ServletException - * @throws IOException - */ - protected void writeAjaxPageHtmlVaadinScripts(Window window, - String themeName, Application application, - final BufferedWriter page, String appUrl, String themeUri, - String appId, HttpServletRequest request) throws ServletException, - IOException { - - // request widgetset takes precedence (e.g portlet include) - String requestWidgetset = (String) request - .getAttribute(REQUEST_WIDGETSET); - String sharedWidgetset = (String) request - .getAttribute(REQUEST_SHARED_WIDGETSET); - if (requestWidgetset == null && sharedWidgetset == null) { - // Use the value from configuration or DEFAULT_WIDGETSET. - // If no shared widgetset is specified, the default widgetset is - // assumed to be in the servlet/portlet itself. - requestWidgetset = getApplicationOrSystemProperty( - PARAMETER_WIDGETSET, DEFAULT_WIDGETSET); - } - - String widgetset; - String widgetsetBasePath; - if (requestWidgetset != null) { - widgetset = requestWidgetset; - widgetsetBasePath = getWebApplicationsStaticFileLocation(request); - } else { - widgetset = sharedWidgetset; - widgetsetBasePath = getStaticFilesLocation(request); - } - - widgetset = stripSpecialChars(widgetset); - - final String widgetsetFilePath = widgetsetBasePath + "/" - + WIDGETSET_DIRECTORY_PATH + widgetset + "/" + widgetset - + ".nocache.js" + createPreventCachingQueryString(); - - // Get system messages - Application.SystemMessages systemMessages = null; - try { - systemMessages = getSystemMessages(); - } catch (SystemMessageException e) { - // failing to get the system messages is always a problem - throw new ServletException("CommunicationError!", e); - } - - page.write("<script type=\"text/javascript\">\n"); - page.write("//<![CDATA[\n"); - page.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n " - + "if(!vaadin) { var vaadin = {}} \n" - + "vaadin.vaadinConfigurations = {};\n" - + "if (!vaadin.themesLoaded) { vaadin.themesLoaded = {}; }\n"); - if (!isProductionMode()) { - page.write("vaadin.debug = true;\n"); - } - page.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" " - + "style=\"position:absolute;width:0;height:0;border:0;overflow:" - + "hidden;\" src=\"javascript:false\"></iframe>');\n"); - page.write("document.write(\"<script language='javascript' src='" - + widgetsetFilePath + "'><\\/script>\");\n}\n"); - - page.write("vaadin.vaadinConfigurations[\"" + appId + "\"] = {"); - page.write("appUri:'" + appUrl + "', "); - - if (window != application.getMainWindow()) { - page.write("windowName: \"" - + JsonPaintTarget.escapeJSON(window.getName()) + "\", "); - } - if (isStandalone()) { - page.write("standalone: true, "); - } - page.write("themeUri:"); - page.write(themeUri != null ? "\"" + themeUri + "\"" : "null"); - page.write(", versionInfo : {vaadinVersion:\""); - page.write(VERSION); - page.write("\",applicationVersion:\""); - page.write(JsonPaintTarget.escapeJSON(application.getVersion())); - page.write("\"}"); - if (systemMessages != null) { - // Write the CommunicationError -message to client - String caption = systemMessages.getCommunicationErrorCaption(); - if (caption != null) { - caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\""; - } - String message = systemMessages.getCommunicationErrorMessage(); - if (message != null) { - message = "\"" + JsonPaintTarget.escapeJSON(message) + "\""; - } - String url = systemMessages.getCommunicationErrorURL(); - if (url != null) { - url = "\"" + JsonPaintTarget.escapeJSON(url) + "\""; - } - - page.write(",\"comErrMsg\": {" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}"); - - // Write the AuthenticationError -message to client - caption = systemMessages.getAuthenticationErrorCaption(); - if (caption != null) { - caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\""; - } - message = systemMessages.getAuthenticationErrorMessage(); - if (message != null) { - message = "\"" + JsonPaintTarget.escapeJSON(message) + "\""; - } - url = systemMessages.getAuthenticationErrorURL(); - if (url != null) { - url = "\"" + JsonPaintTarget.escapeJSON(url) + "\""; - } - - page.write(",\"authErrMsg\": {" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}"); - } - page.write("};\n//]]>\n</script>\n"); - - if (themeName != null) { - // Custom theme's stylesheet, load only once, in different - // script - // tag to be dominate styles injected by widget - // set - page.write("<script type=\"text/javascript\">\n"); - page.write("//<![CDATA[\n"); - page.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n"); - page.write("var stylesheet = document.createElement('link');\n"); - page.write("stylesheet.setAttribute('rel', 'stylesheet');\n"); - page.write("stylesheet.setAttribute('type', 'text/css');\n"); - page.write("stylesheet.setAttribute('href', '" + themeUri - + "/styles.css');\n"); - page.write("document.getElementsByTagName('head')[0].appendChild(stylesheet);\n"); - page.write("vaadin.themesLoaded['" + themeName + "'] = true;\n}\n"); - page.write("//]]>\n</script>\n"); - } - - // Warn if the widgetset has not been loaded after 15 seconds on - // inactivity - page.write("<script type=\"text/javascript\">\n"); - page.write("//<![CDATA[\n"); - page.write("setTimeout('if (typeof " + widgetset.replace('.', '_') - + " == \"undefined\") {alert(\"Failed to load the widgetset: " - + widgetsetFilePath + "\")};',15000);\n" + "//]]>\n</script>\n"); - } - - /** - * To ensure the GWT kickstart scritp is downloaded each time (even if - * server caching is not set up right), we add a unique query parameter to - * the end of the script file. - * - * @return - */ - protected String createPreventCachingQueryString() { - return "?" + new Date().getTime(); - } - - /** - * @return true if the served application is considered to be the only or - * main content of the host page. E.g. various embedding solutions - * should override this to false. - */ - protected boolean isStandalone() { - return true; - } - - /** - * - * Method to open the body tag of the html kickstart page. - * <p> - * This method is responsible for closing the head tag and opening the body - * tag. - * <p> - * Override this method if you want to add some custom html to the page. - * - * @param page - * @param request - * @throws IOException - */ - protected void writeAjaxPageHtmlBodyStart(final BufferedWriter page, - final HttpServletRequest request) throws IOException { - page.write("\n</head>\n<body scroll=\"auto\" class=\"" - + ApplicationConnection.GENERATED_BODY_CLASSNAME + "\">\n"); - } - - /** - * Method to write the contents of head element in html kickstart page. - * <p> - * Override this method if you want to add some custom html to the header of - * the page. - * - * @param page - * @param title - * @param themeUri - * @param request - * @throws IOException - */ - protected void writeAjaxPageHtmlHeader(final BufferedWriter page, - String title, String themeUri, final HttpServletRequest request) - throws IOException { - page.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"); - - WebBrowser browser = getApplicationContext(request.getSession()) - .getBrowser(); - if (browser.isIE()) { - // Chrome frame in all versions of IE (only if Chrome frame is - // installed) - page.write("<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\"/>\n"); - } - - page.write("<style type=\"text/css\">" - + "html, body {height:100%;margin:0;}</style>"); - - // Add favicon links - page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\"" - + themeUri + "/favicon.ico\" />"); - page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\"" - + themeUri + "/favicon.ico\" />"); - - page.write("<title>" + safeEscapeForHtml(title) + "</title>"); - } - - /** - * Method to write the beginning of the html page. - * <p> - * This method is responsible for writing appropriate doc type declarations - * and to open html and head tags. - * <p> - * Override this method if you want to add some custom html to the very - * beginning of the page. - * - * @param page - * @param request - * @throws IOException - */ - protected void writeAjaxPageHtmlHeadStart(final BufferedWriter page, - final HttpServletRequest request) throws IOException { - // write html header - page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD " - + "XHTML 1.0 Transitional//EN\" " - + "\"http://www.w3.org/TR/xhtml1/" - + "DTD/xhtml1-transitional.dtd\">\n"); - - page.write("<html xmlns=\"http://www.w3.org/1999/xhtml\"" - + ">\n<head>\n"); - } - - /** - * Method to set http request headers for the Vaadin kickstart page. - * <p> - * Override this method if you need to customize http headers of the page. - * - * @param response - */ - protected void setAjaxPageHeaders(HttpServletResponse response) { - // Window renders are not cacheable - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - response.setContentType("text/html; charset=UTF-8"); - } - - /** - * Returns a message printed for browsers without scripting support or if - * browsers scripting support is disabled. - */ - protected String getNoScriptMessage() { - return "You have to enable javascript in your browser to use an application built with Vaadin."; - } - - /** * Gets the current application URL from request. * * @param request @@ -2264,52 +1657,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } /** - * Gets the existing application or create a new one. Get a window within an - * application based on the requested URI. - * - * @param request - * the HTTP Request. - * @param application - * the Application to query for window. - * @return Window matching the given URI or null if not found. - * @throws ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - protected Window getApplicationWindow(HttpServletRequest request, - CommunicationManager applicationManager, Application application) - throws ServletException { - - // Finds the window where the request is handled - Window assumedWindow = null; - String path = getRequestPathInfo(request); - - // Main window as the URI is empty - if (!(path == null || path.length() == 0 || path.equals("/"))) { - if (path.startsWith("/APP/")) { - // Use main window for application resources - return application.getMainWindow(); - } - String windowName = null; - if (path.charAt(0) == '/') { - path = path.substring(1); - } - final int index = path.indexOf('/'); - if (index < 0) { - windowName = path; - path = ""; - } else { - windowName = path.substring(0, index); - } - assumedWindow = application.getWindow(windowName); - - } - - return applicationManager.getApplicationWindow(request, this, - application, assumedWindow); - } - - /** * Returns the path info; note that this _can_ be different than * request.getPathInfo(). Examples where this might be useful: * <ul> @@ -2379,75 +1726,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements return WebApplicationContext.getApplicationContext(session); } - /** - * Implementation of ParameterHandler.ErrorEvent interface. - */ - public class ParameterHandlerErrorImpl implements - ParameterHandler.ErrorEvent, Serializable { - - private ParameterHandler owner; - - private Throwable throwable; - - /** - * Gets the contained throwable. - * - * @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable() - */ - public Throwable getThrowable() { - return throwable; - } - - /** - * Gets the source ParameterHandler. - * - * @see com.vaadin.terminal.ParameterHandler.ErrorEvent#getParameterHandler() - */ - public ParameterHandler getParameterHandler() { - return owner; - } - - } - - /** - * Implementation of URIHandler.ErrorEvent interface. - */ - public class URIHandlerErrorImpl implements URIHandler.ErrorEvent, - Serializable { - - private final URIHandler owner; - - private final Throwable throwable; - - /** - * - * @param owner - * @param throwable - */ - private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) { - this.owner = owner; - this.throwable = throwable; - } - - /** - * Gets the contained throwable. - * - * @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable() - */ - public Throwable getThrowable() { - return throwable; - } - - /** - * Gets the source URIHandler. - * - * @see com.vaadin.terminal.URIHandler.ErrorEvent#getURIHandler() - */ - public URIHandler getURIHandler() { - return owner; - } - } - public class RequestError implements Terminal.ErrorEvent, Serializable { private final Throwable throwable; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 9a6bccebb8..b780f66a23 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -14,9 +14,10 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Serializable; +import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URL; +import java.lang.reflect.Type; import java.security.GeneralSecurityException; import java.text.CharacterIterator; import java.text.DateFormat; @@ -37,36 +38,43 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.StringTokenizer; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - import com.vaadin.Application; import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.external.json.JSONArray; +import com.vaadin.external.json.JSONException; +import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.CombinedRequest; +import com.vaadin.terminal.LegacyPaint; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Paintable; -import com.vaadin.terminal.Paintable.RepaintRequestEvent; +import com.vaadin.terminal.RequestHandler; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.StreamVariable.StreamingEndEvent; import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; import com.vaadin.terminal.Terminal.ErrorEvent; import com.vaadin.terminal.Terminal.ErrorListener; -import com.vaadin.terminal.URIHandler; +import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.VariableOwner; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.server.BootstrapHandler.BootstrapContext; import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractField; import com.vaadin.ui.Component; +import com.vaadin.ui.DirtyConnectorTracker; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.Panel; +import com.vaadin.ui.Root; import com.vaadin.ui.Window; /** @@ -75,196 +83,30 @@ import com.vaadin.ui.Window; * JavaScript) and the server side components. Its client side counterpart is * {@link ApplicationConnection}. * - * A server side component sends its state to the client in a paint request (see - * {@link Paintable} and {@link PaintTarget} on the server side). The client - * widget receives these paint requests as calls to - * {@link com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL()}. The client - * component communicates back to the server by sending a list of variable - * changes (see {@link ApplicationConnection#updateVariable()} and - * {@link VariableOwner#changeVariables(Object, Map)}). - * * TODO Document better! */ @SuppressWarnings("serial") -public abstract class AbstractCommunicationManager implements - Paintable.RepaintRequestListener, Serializable { +public abstract class AbstractCommunicationManager implements Serializable { private static final String DASHDASH = "--"; private static final Logger logger = Logger .getLogger(AbstractCommunicationManager.class.getName()); - /** - * Generic interface of a (HTTP or Portlet) request to the application. - * - * This is a wrapper interface that allows - * {@link AbstractCommunicationManager} to use a unified API. - * - * @see javax.servlet.ServletRequest - * @see javax.portlet.PortletRequest - * - * @author peholmst - */ - public interface Request { - - /** - * Gets a {@link Session} wrapper implementation representing the - * session for which this request was sent. - * - * Multiple Vaadin applications can be associated with a single session. - * - * @return Session - */ - public Session getSession(); - - /** - * Are the applications in this session running in a portlet or directly - * as servlets. - * - * @return true if in a portlet - */ - public boolean isRunningInPortlet(); - - /** - * Get the named HTTP or portlet request parameter. - * - * @see javax.servlet.ServletRequest#getParameter(String) - * @see javax.portlet.PortletRequest#getParameter(String) - * - * @param name - * @return - */ - public String getParameter(String name); - - /** - * Returns the length of the request content that can be read from the - * input stream returned by {@link #getInputStream()}. - * - * @return content length in bytes - */ - public int getContentLength(); - - /** - * Returns an input stream from which the request content can be read. - * The request content length can be obtained with - * {@link #getContentLength()} without reading the full stream contents. - * - * @return - * @throws IOException - */ - public InputStream getInputStream() throws IOException; - - /** - * Returns the request identifier that identifies the target Vaadin - * window for the request. - * - * @return String identifier for the request target window - */ - public String getRequestID(); - - /** - * @see javax.servlet.ServletRequest#getAttribute(String) - * @see javax.portlet.PortletRequest#getAttribute(String) - */ - public Object getAttribute(String name); - - /** - * @see javax.servlet.ServletRequest#setAttribute(String, Object) - * @see javax.portlet.PortletRequest#setAttribute(String, Object) - */ - public void setAttribute(String name, Object value); - - /** - * Gets the underlying request object. The request is typically either a - * {@link ServletRequest} or a {@link PortletRequest}. - * - * @return wrapped request object - */ - public Object getWrappedRequest(); + private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler(); - } - - /** - * Generic interface of a (HTTP or Portlet) response from the application. - * - * This is a wrapper interface that allows - * {@link AbstractCommunicationManager} to use a unified API. - * - * @see javax.servlet.ServletResponse - * @see javax.portlet.PortletResponse - * - * @author peholmst - */ - public interface Response { - - /** - * Gets the output stream to which the response can be written. - * - * @return - * @throws IOException - */ - public OutputStream getOutputStream() throws IOException; - - /** - * Sets the MIME content type for the response to be communicated to the - * browser. - * - * @param type - */ - public void setContentType(String type); - - /** - * Gets the wrapped response object, usually a class implementing either - * {@link ServletResponse} or {@link PortletResponse}. - * - * @return wrapped request object - */ - public Object getWrappedResponse(); - - } - - /** - * Generic wrapper interface for a (HTTP or Portlet) session. - * - * Several applications can be associated with a single session. - * - * TODO Document me! - * - * @see javax.servlet.http.HttpSession - * @see javax.portlet.PortletSession - * - * @author peholmst - */ - protected interface Session { - - public boolean isNew(); - - public Object getAttribute(String name); - - public void setAttribute(String name, Object o); - - public int getMaxInactiveInterval(); - - public Object getWrappedSession(); - - } + private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler(); /** * TODO Document me! * * @author peholmst */ - public interface Callback { - - public void criticalNotification(Request request, Response response, - String cap, String msg, String details, String outOfSyncURL) - throws IOException; - - public String getRequestPathInfo(Request request); - - public InputStream getThemeResourceAsStream(String themeName, - String resource) throws IOException; + public interface Callback extends Serializable { + public void criticalNotification(WrappedRequest request, + WrappedResponse response, String cap, String msg, + String details, String outOfSyncURL) throws IOException; } static class UploadInterruptedException extends Exception { @@ -280,33 +122,11 @@ public abstract class AbstractCommunicationManager implements private static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken"; /* Variable records indexes */ - private static final int VAR_PID = 1; - private static final int VAR_NAME = 2; - private static final int VAR_TYPE = 3; - private static final int VAR_VALUE = 0; - - private static final char VTYPE_PAINTABLE = 'p'; - private static final char VTYPE_BOOLEAN = 'b'; - private static final char VTYPE_DOUBLE = 'd'; - private static final char VTYPE_FLOAT = 'f'; - private static final char VTYPE_LONG = 'l'; - private static final char VTYPE_INTEGER = 'i'; - private static final char VTYPE_STRING = 's'; - private static final char VTYPE_ARRAY = 'a'; - private static final char VTYPE_STRINGARRAY = 'c'; - private static final char VTYPE_MAP = 'm'; - - private static final char VAR_RECORD_SEPARATOR = '\u001e'; - - private static final char VAR_FIELD_SEPARATOR = '\u001f'; - public static final char VAR_BURST_SEPARATOR = '\u001d'; - public static final char VAR_ARRAYITEM_SEPARATOR = '\u001c'; - public static final char VAR_ESCAPE_CHARACTER = '\u001b'; - private final HashMap<String, OpenWindowCache> currentlyOpenWindowsInClient = new HashMap<String, OpenWindowCache>(); + private final HashMap<Integer, ClientCache> rootToClientCache = new HashMap<Integer, ClientCache>(); private static final int MAX_BUFFER_SIZE = 64 * 1024; @@ -315,20 +135,8 @@ public abstract class AbstractCommunicationManager implements private static final String GET_PARAM_ANALYZE_LAYOUTS = "analyzeLayouts"; - private final ArrayList<Paintable> dirtyPaintables = new ArrayList<Paintable>(); - - private final HashMap<Paintable, String> paintableIdMap = new HashMap<Paintable, String>(); - - private final HashMap<String, Paintable> idPaintableMap = new HashMap<String, Paintable>(); - - private int idSequence = 0; - private final Application application; - // Note that this is only accessed from synchronized block and - // thus should be thread-safe. - private String closingWindowName = null; - private List<String> locales; private int pendingLocalesIndex; @@ -341,7 +149,7 @@ public abstract class AbstractCommunicationManager implements private int maxInactiveInterval; - private static int nextUnusedWindowSuffix = 1; + private Connector highlightedConnector; /** * TODO New constructor - document me! @@ -350,6 +158,9 @@ public abstract class AbstractCommunicationManager implements */ public AbstractCommunicationManager(Application application) { this.application = application; + application.addRequestHandler(getBootstrapHandler()); + application.addRequestHandler(APP_RESOURCE_HANDLER); + application.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER); requireLocale(application.getLocale().toString()); } @@ -365,8 +176,6 @@ public abstract class AbstractCommunicationManager implements private static final String GET_PARAM_HIGHLIGHT_COMPONENT = "highlightComponent"; - private Paintable highLightedPaintable; - private static String readLine(InputStream stream) throws IOException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); int readByte = stream.read(); @@ -390,9 +199,9 @@ public abstract class AbstractCommunicationManager implements * @param boundary * @throws IOException */ - protected void doHandleSimpleMultipartFileUpload(Request request, - Response response, StreamVariable streamVariable, - String variableName, VariableOwner owner, String boundary) + protected void doHandleSimpleMultipartFileUpload(WrappedRequest request, + WrappedResponse response, StreamVariable streamVariable, + String variableName, Connector owner, String boundary) throws IOException { // multipart parsing, supports only one file for request, but that is // fine for our current terminal @@ -489,9 +298,10 @@ public abstract class AbstractCommunicationManager implements * @param contentLength * @throws IOException */ - protected void doHandleXhrFilePost(Request request, Response response, - StreamVariable streamVariable, String variableName, - VariableOwner owner, int contentLength) throws IOException { + protected void doHandleXhrFilePost(WrappedRequest request, + WrappedResponse response, StreamVariable streamVariable, + String variableName, Connector owner, int contentLength) + throws IOException { // These are unknown in filexhr ATM, maybe add to Accept header that // is accessible in portlets @@ -628,17 +438,6 @@ public abstract class AbstractCommunicationManager implements } } - static void tryToCloseStream(InputStream in) { - try { - // try to close output stream (e.g. file handle) - if (in != null) { - in.close(); - } - } catch (IOException e1) { - // NOP - } - } - /** * Removes any possible path information from the filename and returns the * filename. Separators / and \\ are used. @@ -661,8 +460,8 @@ public abstract class AbstractCommunicationManager implements * @param response * @throws IOException */ - protected void sendUploadResponse(Request request, Response response) - throws IOException { + protected void sendUploadResponse(WrappedRequest request, + WrappedResponse response) throws IOException { response.setContentType("text/html"); final OutputStream out = response.getOutputStream(); final PrintWriter outWriter = new PrintWriter(new BufferedWriter( @@ -676,7 +475,7 @@ public abstract class AbstractCommunicationManager implements * Internally process a UIDL request from the client. * * This method calls - * {@link #handleVariables(Request, Response, Callback, Application, Window)} + * {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, Root)} * to process any changes to variables by the client and then repaints * affected components using {@link #paintAfterVariableChanges()}. * @@ -690,18 +489,18 @@ public abstract class AbstractCommunicationManager implements * @param request * @param response * @param callback - * @param window + * @param root * target window for the UIDL request, can be null if target not * found * @throws IOException * @throws InvalidUIDLSecurityKeyException */ - protected void doHandleUidlRequest(Request request, Response response, - Callback callback, Window window) throws IOException, - InvalidUIDLSecurityKeyException { + public void handleUidlRequest(WrappedRequest request, + WrappedResponse response, Callback callback, Root root) + throws IOException, InvalidUIDLSecurityKeyException { requestThemeName = request.getParameter("theme"); - maxInactiveInterval = request.getSession().getMaxInactiveInterval(); + maxInactiveInterval = request.getSessionMaxInactiveInterval(); // repaint requested or session has timed out and new one is created boolean repaintAll; final OutputStream out; @@ -718,8 +517,8 @@ public abstract class AbstractCommunicationManager implements if (request.getParameter(GET_PARAM_HIGHLIGHT_COMPONENT) != null) { String pid = request .getParameter(GET_PARAM_HIGHLIGHT_COMPONENT); - highLightedPaintable = idPaintableMap.get(pid); - highlightPaintable(highLightedPaintable); + highlightedConnector = root.getApplication().getConnector(pid); + highlightConnector(highlightedConnector); } } @@ -734,11 +533,10 @@ public abstract class AbstractCommunicationManager implements // Finds the window within the application if (application.isRunning()) { // Returns if no window found - if (window == null) { + if (root == null) { // This should not happen, no windows exists but // application is still open. - logger.warning("Could not get window for application with request ID " - + request.getRequestID()); + logger.warning("Could not get root for application"); return; } } else { @@ -748,8 +546,7 @@ public abstract class AbstractCommunicationManager implements } // Change all variables based on request parameters - if (!handleVariables(request, response, callback, application, - window)) { + if (!handleVariables(request, response, callback, application, root)) { // var inconsistency; the client is probably out-of-sync SystemMessages ci = null; @@ -780,27 +577,36 @@ public abstract class AbstractCommunicationManager implements } paintAfterVariableChanges(request, response, callback, repaintAll, - outWriter, window, analyzeLayouts); - - if (closingWindowName != null) { - currentlyOpenWindowsInClient.remove(closingWindowName); - closingWindowName = null; - } + outWriter, root, analyzeLayouts); + postPaint(root); } outWriter.close(); requestThemeName = null; } - protected void highlightPaintable(Paintable highLightedPaintable2) { + /** + * Method called after the paint phase while still being synchronized on the + * application + * + * @param root + * + */ + protected void postPaint(Root root) { + // Remove connectors that have been detached from the application during + // handling of the request + root.getApplication().cleanConnectorMap(); + } + + protected void highlightConnector(Connector highlightedConnector) { StringBuilder sb = new StringBuilder(); sb.append("*** Debug details of a component: *** \n"); sb.append("Type: "); - sb.append(highLightedPaintable2.getClass().getName()); - if (highLightedPaintable2 instanceof AbstractComponent) { - AbstractComponent component = (AbstractComponent) highLightedPaintable2; + sb.append(highlightedConnector.getClass().getName()); + if (highlightedConnector instanceof AbstractComponent) { + AbstractComponent component = (AbstractComponent) highlightedConnector; sb.append("\nId:"); - sb.append(paintableIdMap.get(component)); + sb.append(highlightedConnector.getConnectorId()); if (component.getCaption() != null) { sb.append("\nCaption:"); sb.append(component.getCaption()); @@ -864,14 +670,10 @@ public abstract class AbstractCommunicationManager implements * @throws PaintException * @throws IOException */ - private void paintAfterVariableChanges(Request request, Response response, - Callback callback, boolean repaintAll, final PrintWriter outWriter, - Window window, boolean analyzeLayouts) throws PaintException, - IOException { - - if (repaintAll) { - makeAllPaintablesDirty(window); - } + private void paintAfterVariableChanges(WrappedRequest request, + WrappedResponse response, Callback callback, boolean repaintAll, + final PrintWriter outWriter, Root root, boolean analyzeLayouts) + throws PaintException, IOException { // Removes application if it has stopped during variable changes if (!application.isRunning()) { @@ -886,180 +688,242 @@ public abstract class AbstractCommunicationManager implements .getAttribute(WRITE_SECURITY_TOKEN_FLAG); if (writeSecurityTokenFlag != null) { - String seckey = (String) request.getSession().getAttribute( - ApplicationConnection.UIDL_SECURITY_TOKEN_ID); - if (seckey == null) { - seckey = UUID.randomUUID().toString(); - request.getSession().setAttribute( - ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey); - } - outWriter.print("\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID - + "\":\""); - outWriter.print(seckey); - outWriter.print("\","); + outWriter.print(getSecurityKeyUIDL(request)); } - // If the browser-window has been closed - we do not need to paint it at - // all - if (window.getName().equals(closingWindowName)) { - outWriter.print("\"changes\":[]"); - } else { - // re-get window - may have been changed - Window newWindow = doGetApplicationWindow(request, callback, - application, window); - if (newWindow != window) { - window = newWindow; - repaintAll = true; - } - - writeUidlResponse(request, callback, repaintAll, outWriter, window, - analyzeLayouts); + writeUidlResponse(request, repaintAll, outWriter, root, analyzeLayouts); - } closeJsonMessage(outWriter); outWriter.close(); } - public void writeUidlResponse(Request request, Callback callback, - boolean repaintAll, final PrintWriter outWriter, Window window, - boolean analyzeLayouts) throws PaintException { - outWriter.print("\"changes\":["); - - ArrayList<Paintable> paintables = null; - - List<InvalidLayout> invalidComponentRelativeSizes = null; + /** + * Gets the security key (and generates one if needed) as UIDL. + * + * @param request + * @return the security key UIDL or "" if the feature is turned off + */ + public String getSecurityKeyUIDL(WrappedRequest request) { + final String seckey = getSecurityKey(request); + if (seckey != null) { + return "\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID + + "\":\"" + seckey + "\","; + } else { + return ""; + } + } - JsonPaintTarget paintTarget = new JsonPaintTarget(this, outWriter, - !repaintAll); - OpenWindowCache windowCache = currentlyOpenWindowsInClient.get(window - .getName()); - if (windowCache == null) { - windowCache = new OpenWindowCache(); - currentlyOpenWindowsInClient.put(window.getName(), windowCache); + /** + * Gets the security key (and generates one if needed). + * + * @param request + * @return the security key + */ + protected String getSecurityKey(WrappedRequest request) { + String seckey = null; + seckey = (String) request + .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID); + if (seckey == null) { + seckey = UUID.randomUUID().toString(); + request.setSessionAttribute( + ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey); } + return seckey; + } + + @SuppressWarnings("unchecked") + public void writeUidlResponse(WrappedRequest request, boolean repaintAll, + final PrintWriter outWriter, Root root, boolean analyzeLayouts) + throws PaintException { + ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>(); + Application application = root.getApplication(); // Paints components + DirtyConnectorTracker rootConnectorTracker = root + .getDirtyConnectorTracker(); + logger.log(Level.FINE, "* Creating response to client"); if (repaintAll) { - paintables = new ArrayList<Paintable>(); - paintables.add(window); + getClientCache(root).clear(); + rootConnectorTracker.markAllComponentsDirty(); // Reset sent locales locales = null; requireLocale(application.getLocale().toString()); + } - } else { - // remove detached components from paintableIdMap so they - // can be GC'ed - /* - * TODO figure out if we could move this beyond the painting phase, - * "respond as fast as possible, then do the cleanup". Beware of - * painting the dirty detatched components. - */ - for (Iterator<Paintable> it = paintableIdMap.keySet().iterator(); it - .hasNext();) { - Component p = (Component) it.next(); - if (p.getApplication() == null) { - unregisterPaintable(p); - // Take into account that some other component may have - // reused p's ID by now (this can happen when manually - // assigning IDs with setDebugId().) See #8090. - String pid = paintableIdMap.get(p); - if (idPaintableMap.get(pid) == p) { - idPaintableMap.remove(pid); - } - it.remove(); - dirtyPaintables.remove(p); + dirtyVisibleConnectors + .addAll(getDirtyVisibleComponents(rootConnectorTracker)); + + logger.log(Level.FINE, "Found " + dirtyVisibleConnectors.size() + + " dirty connectors to paint"); + for (ClientConnector connector : dirtyVisibleConnectors) { + if (connector instanceof Component) { + ((Component) connector).updateState(); + } + } + rootConnectorTracker.markAllComponentsClean(); + + outWriter.print("\"changes\":["); + + List<InvalidLayout> invalidComponentRelativeSizes = null; + + JsonPaintTarget paintTarget = new JsonPaintTarget(this, outWriter, + !repaintAll); + legacyPaint(paintTarget, dirtyVisibleConnectors); + + if (analyzeLayouts) { + invalidComponentRelativeSizes = ComponentSizeValidator + .validateComponentRelativeSizes(root.getContent(), null, + null); + + // Also check any existing subwindows + if (root.getWindows() != null) { + for (Window subWindow : root.getWindows()) { + invalidComponentRelativeSizes = ComponentSizeValidator + .validateComponentRelativeSizes( + subWindow.getContent(), + invalidComponentRelativeSizes, null); } } - paintables = getDirtyVisibleComponents(window); - } - if (paintables != null) { - - // We need to avoid painting children before parent. - // This is ensured by ordering list by depth in component - // tree - Collections.sort(paintables, new Comparator<Paintable>() { - public int compare(Paintable o1, Paintable o2) { - Component c1 = (Component) o1; - Component c2 = (Component) o2; - int d1 = 0; - while (c1.getParent() != null) { - d1++; - c1 = c1.getParent(); - } - int d2 = 0; - while (c2.getParent() != null) { - d2++; - c2 = c2.getParent(); - } - if (d1 < d2) { - return -1; - } - if (d1 > d2) { - return 1; - } - return 0; + } + + paintTarget.close(); + outWriter.print("], "); // close changes + + // send shared state to client + + // for now, send the complete state of all modified and new + // components + + // Ideally, all this would be sent before "changes", but that causes + // complications with legacy components that create sub-components + // in their paint phase. Nevertheless, this will be processed on the + // client after component creation but before legacy UIDL + // processing. + JSONObject sharedStates = new JSONObject(); + for (Connector connector : dirtyVisibleConnectors) { + SharedState state = connector.getState(); + if (null != state) { + // encode and send shared state + try { + // FIXME Use declared type + JSONArray stateJsonArray = JsonCodec.encode(state, + state.getClass(), application); + sharedStates + .put(connector.getConnectorId(), stateJsonArray); + } catch (JSONException e) { + throw new PaintException( + "Failed to serialize shared state for connector " + + connector.getClass().getName() + " (" + + connector.getConnectorId() + "): " + + e.getMessage()); } - }); + } + } + outWriter.print("\"state\":"); + outWriter.append(sharedStates.toString()); + outWriter.print(", "); // close states - for (final Iterator<Paintable> i = paintables.iterator(); i - .hasNext();) { - final Paintable p = i.next(); + // TODO This should be optimized. The type only needs to be + // sent once for each connector id + on refresh. Use the same cache as + // widget mapping - // TODO CLEAN - if (p instanceof Window) { - final Window w = (Window) p; - if (w.getTerminal() == null) { - w.setTerminal(application.getMainWindow().getTerminal()); + JSONObject connectorTypes = new JSONObject(); + for (ClientConnector connector : dirtyVisibleConnectors) { + String connectorType = paintTarget.getTag(connector); + try { + connectorTypes.put(connector.getConnectorId(), connectorType); + } catch (JSONException e) { + throw new PaintException( + "Failed to send connector type for connector " + + connector.getConnectorId() + ": " + + e.getMessage()); + } + } + outWriter.print("\"types\":"); + outWriter.append(connectorTypes.toString()); + outWriter.print(", "); // close states + + // Send update hierarchy information to the client. + + // This could be optimized aswell to send only info if hierarchy has + // actually changed. Much like with the shared state. Note though + // that an empty hierarchy is information aswell (e.g. change from 1 + // child to 0 children) + + outWriter.print("\"hierarchy\":"); + + JSONObject hierarchyInfo = new JSONObject(); + for (Connector connector : dirtyVisibleConnectors) { + if (connector instanceof HasComponents) { + HasComponents parent = (HasComponents) connector; + String parentConnectorId = parent.getConnectorId(); + JSONArray children = new JSONArray(); + + for (Component child : getChildComponents(parent)) { + if (isVisible(child)) { + children.put(child.getConnectorId()); } } - /* - * This does not seem to happen in tk5, but remember this case: - * else if (p instanceof Component) { if (((Component) - * p).getParent() == null || ((Component) p).getApplication() == - * null) { // Component requested repaint, but is no // longer - * attached: skip paintablePainted(p); continue; } } - */ + try { + hierarchyInfo.put(parentConnectorId, children); + } catch (JSONException e) { + throw new PaintException( + "Failed to send hierarchy information about " + + parentConnectorId + " to the client: " + + e.getMessage()); + } + } + } + outWriter.append(hierarchyInfo.toString()); + outWriter.print(", "); // close hierarchy - // TODO we may still get changes that have been - // rendered already (changes with only cached flag) - if (paintTarget.needsToBePainted(p)) { - paintTarget.startTag("change"); - paintTarget.addAttribute("format", "uidl"); - final String pid = getPaintableId(p); - paintTarget.addAttribute("pid", pid); + // send server to client RPC calls for components in the root, in call + // order - p.paint(paintTarget); + // collect RPC calls from components in the root in the order in + // which they were performed, remove the calls from components - paintTarget.endTag("change"); - } - paintablePainted(p); + LinkedList<ClientConnector> rpcPendingQueue = new LinkedList<ClientConnector>( + dirtyVisibleConnectors); + List<ClientMethodInvocation> pendingInvocations = collectPendingRpcCalls(dirtyVisibleConnectors); - if (analyzeLayouts) { - Window w = (Window) p; - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes(w.getContent(), - null, null); - - // Also check any existing subwindows - if (w.getChildWindows() != null) { - for (Window subWindow : w.getChildWindows()) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes( - subWindow.getContent(), - invalidComponentRelativeSizes, null); - } - } + JSONArray rpcCalls = new JSONArray(); + for (ClientMethodInvocation invocation : pendingInvocations) { + // add invocation to rpcCalls + try { + JSONArray invocationJson = new JSONArray(); + invocationJson.put(invocation.getConnector().getConnectorId()); + invocationJson.put(invocation.getInterfaceName()); + invocationJson.put(invocation.getMethodName()); + JSONArray paramJson = new JSONArray(); + for (int i = 0; i < invocation.getParameterTypes().length; ++i) { + paramJson.put(JsonCodec.encode( + invocation.getParameters()[i], + invocation.getParameterTypes()[i], application)); } + invocationJson.put(paramJson); + rpcCalls.put(invocationJson); + } catch (JSONException e) { + throw new PaintException( + "Failed to serialize RPC method call parameters for connector " + + invocation.getConnector().getConnectorId() + + " method " + invocation.getInterfaceName() + + "." + invocation.getMethodName() + ": " + + e.getMessage()); } + } - paintTarget.close(); - outWriter.print("]"); // close changes + if (rpcCalls.length() > 0) { + outWriter.print("\"rpc\" : "); + outWriter.append(rpcCalls.toString()); + outWriter.print(", "); // close rpc + } - outWriter.print(", \"meta\" : {"); + outWriter.print("\"meta\" : {"); boolean metaOpen = false; if (repaintAll) { @@ -1081,11 +945,11 @@ public abstract class AbstractCommunicationManager implements } outWriter.write("]"); } - if (highLightedPaintable != null) { + if (highlightedConnector != null) { outWriter.write(", \"hl\":\""); - outWriter.write(paintableIdMap.get(highLightedPaintable)); + outWriter.write(highlightedConnector.getConnectorId()); outWriter.write("\""); - highLightedPaintable = null; + highlightedConnector = null; } } @@ -1140,8 +1004,7 @@ public abstract class AbstractCommunicationManager implements final String resource = (String) i.next(); InputStream is = null; try { - is = callback.getThemeResourceAsStream(getTheme(window), - resource); + is = getThemeResourceAsStream(root, getTheme(root), resource); } catch (final Exception e) { // FIXME: Handle exception logger.log(Level.FINER, "Failed to get theme resource stream.", @@ -1175,11 +1038,13 @@ public abstract class AbstractCommunicationManager implements } outWriter.print("}"); - Collection<Class<? extends Paintable>> usedPaintableTypes = paintTarget - .getUsedPaintableTypes(); + Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget + .getUsedClientConnectors(); boolean typeMappingsOpen = false; - for (Class<? extends Paintable> class1 : usedPaintableTypes) { - if (windowCache.cache(class1)) { + ClientCache clientCache = getClientCache(root); + + for (Class<? extends ClientConnector> class1 : usedClientConnectors) { + if (clientCache.cache(class1)) { // client does not know the mapping key for this type, send // mapping to client if (!typeMappingsOpen) { @@ -1199,6 +1064,32 @@ public abstract class AbstractCommunicationManager implements outWriter.print(" }"); } + boolean typeInheritanceMapOpen = false; + if (typeMappingsOpen) { + // send the whole type inheritance map if any new mappings + for (Class<? extends ClientConnector> class1 : usedClientConnectors) { + if (!ClientConnector.class.isAssignableFrom(class1 + .getSuperclass())) { + continue; + } + if (!typeInheritanceMapOpen) { + typeInheritanceMapOpen = true; + outWriter.print(", \"typeInheritanceMap\" : { "); + } else { + outWriter.print(" , "); + } + outWriter.print("\""); + outWriter.print(getTagForType(class1)); + outWriter.print("\" : "); + outWriter + .print(getTagForType((Class<? extends ClientConnector>) class1 + .getSuperclass())); + } + if (typeInheritanceMapOpen) { + outWriter.print(" }"); + } + } + // add any pending locale definitions requested by the client printLocaleDeclarations(outWriter); @@ -1213,7 +1104,7 @@ public abstract class AbstractCommunicationManager implements * Adds the performance timing data used by TestBench 3 to the UIDL * response. */ - private void writePerformanceDataForTestBench(final Request request, + private void writePerformanceDataForTestBench(final WrappedRequest request, final PrintWriter outWriter) { Long totalTime = (Long) request.getAttribute("TOTAL"); Long lastRequestTime = (Long) request.getAttribute("LASTREQUEST"); @@ -1221,12 +1112,174 @@ public abstract class AbstractCommunicationManager implements lastRequestTime)); } + private void legacyPaint(PaintTarget paintTarget, + ArrayList<ClientConnector> dirtyVisibleConnectors) + throws PaintException { + List<Vaadin6Component> legacyComponents = new ArrayList<Vaadin6Component>(); + for (Connector connector : dirtyVisibleConnectors) { + // All Components that want to use paintContent must implement + // Vaadin6Component + if (connector instanceof Vaadin6Component) { + legacyComponents.add((Vaadin6Component) connector); + } + } + sortByHierarchy((List) legacyComponents); + for (Vaadin6Component c : legacyComponents) { + logger.fine("Painting Vaadin6Component " + c.getClass().getName() + + "@" + Integer.toHexString(c.hashCode())); + paintTarget.startTag("change"); + final String pid = c.getConnectorId(); + paintTarget.addAttribute("pid", pid); + LegacyPaint.paint(c, paintTarget); + paintTarget.endTag("change"); + } + + } + + private void sortByHierarchy(List<Component> paintables) { + // Vaadin 6 requires parents to be painted before children as component + // containers rely on that their updateFromUIDL method has been called + // before children start calling e.g. updateCaption + Collections.sort(paintables, new Comparator<Component>() { + public int compare(Component c1, Component c2) { + int depth1 = 0; + while (c1.getParent() != null) { + depth1++; + c1 = c1.getParent(); + } + int depth2 = 0; + while (c2.getParent() != null) { + depth2++; + c2 = c2.getParent(); + } + if (depth1 < depth2) { + return -1; + } + if (depth1 > depth2) { + return 1; + } + return 0; + } + }); + + } + + private ClientCache getClientCache(Root root) { + Integer rootId = Integer.valueOf(root.getRootId()); + ClientCache cache = rootToClientCache.get(rootId); + if (cache == null) { + cache = new ClientCache(); + rootToClientCache.put(rootId, cache); + } + return cache; + } + + /** + * Checks if the component is visible in context, i.e. returns false if the + * child is hidden, the parent is hidden or the parent says the child should + * not be rendered (using + * {@link HasComponents#isComponentVisible(Component)} + * + * @param child + * The child to check + * @return true if the child is visible to the client, false otherwise + */ + static boolean isVisible(Component child) { + HasComponents parent = child.getParent(); + if (parent == null || !child.isVisible()) { + return child.isVisible(); + } + + return parent.isComponentVisible(child) && isVisible(parent); + } + + private static class NullIterator<E> implements Iterator<E> { + + public boolean hasNext() { + return false; + } + + public E next() { + return null; + } + + public void remove() { + } + + } + + public static Iterable<Component> getChildComponents(HasComponents cc) { + // TODO This must be moved to Root/Panel + if (cc instanceof Root) { + Root root = (Root) cc; + List<Component> children = new ArrayList<Component>(); + if (root.getContent() != null) { + children.add(root.getContent()); + } + for (Window w : root.getWindows()) { + children.add(w); + } + return children; + } else if (cc instanceof Panel) { + // This is so wrong.. (#2924) + if (((Panel) cc).getContent() == null) { + return Collections.emptyList(); + } else { + return Collections.singleton((Component) ((Panel) cc) + .getContent()); + } + } + return cc; + } + + /** + * Collects all pending RPC calls from listed {@link ClientConnector}s and + * clears their RPC queues. + * + * @param rpcPendingQueue + * list of {@link ClientConnector} of interest + * @return ordered list of pending RPC calls + */ + private List<ClientMethodInvocation> collectPendingRpcCalls( + List<ClientConnector> rpcPendingQueue) { + List<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>(); + for (ClientConnector connector : rpcPendingQueue) { + List<ClientMethodInvocation> paintablePendingRpc = connector + .retrievePendingRpcCalls(); + if (null != paintablePendingRpc && !paintablePendingRpc.isEmpty()) { + List<ClientMethodInvocation> oldPendingRpc = pendingInvocations; + int totalCalls = pendingInvocations.size() + + paintablePendingRpc.size(); + pendingInvocations = new ArrayList<ClientMethodInvocation>( + totalCalls); + + // merge two ordered comparable lists + for (int destIndex = 0, oldIndex = 0, paintableIndex = 0; destIndex < totalCalls; destIndex++) { + if (paintableIndex >= paintablePendingRpc.size() + || (oldIndex < oldPendingRpc.size() && ((Comparable<ClientMethodInvocation>) oldPendingRpc + .get(oldIndex)) + .compareTo(paintablePendingRpc + .get(paintableIndex)) <= 0)) { + pendingInvocations.add(oldPendingRpc.get(oldIndex++)); + } else { + pendingInvocations.add(paintablePendingRpc + .get(paintableIndex++)); + } + } + } + } + return pendingInvocations; + } + + protected abstract InputStream getThemeResourceAsStream(Root root, + String themeName, String resource); + private int getTimeoutInterval() { return maxInactiveInterval; } - private String getTheme(Window window) { - String themeName = window.getTheme(); + private String getTheme(Root root) { + String themeName = root.getApplication().getThemeForRoot(root); String requestThemeName = getRequestTheme(); if (requestThemeName != null) { @@ -1242,32 +1295,16 @@ public abstract class AbstractCommunicationManager implements return requestThemeName; } - public void makeAllPaintablesDirty(Window window) { - // If repaint is requested, clean all ids in this root window - for (final Iterator<String> it = idPaintableMap.keySet().iterator(); it - .hasNext();) { - final Component c = (Component) idPaintableMap.get(it.next()); - if (isChildOf(window, c)) { - it.remove(); - paintableIdMap.remove(c); - } - } - // clean WindowCache - OpenWindowCache openWindowCache = currentlyOpenWindowsInClient - .get(window.getName()); - if (openWindowCache != null) { - openWindowCache.clear(); - } - } - /** - * Called when communication manager stops listening for repaints for given - * component. + * Returns false if the cross site request forgery protection is turned off. * - * @param p + * @param application + * @return false if the XSRF is turned off, true otherwise */ - protected void unregisterPaintable(Component p) { - p.removeListener(this); + public boolean isXSRFEnabled(Application application) { + return !"true" + .equals(application + .getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)); } /** @@ -1279,9 +1316,10 @@ public abstract class AbstractCommunicationManager implements * * @return true if successful, false if there was an inconsistency */ - private boolean handleVariables(Request request, Response response, - Callback callback, Application application2, Window window) - throws IOException, InvalidUIDLSecurityKeyException { + private boolean handleVariables(WrappedRequest request, + WrappedResponse response, Callback callback, + Application application2, Root root) throws IOException, + InvalidUIDLSecurityKeyException { boolean success = true; String changes = getRequestPayload(request); @@ -1293,9 +1331,7 @@ public abstract class AbstractCommunicationManager implements // Security: double cookie submission pattern unless disabled by // property - if (!"true" - .equals(application2 - .getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION))) { + if (isXSRFEnabled(application2)) { if (bursts.length == 1 && "init".equals(bursts[0])) { // init request; don't handle any variables, key sent in // response. @@ -1304,8 +1340,8 @@ public abstract class AbstractCommunicationManager implements } else { // ApplicationServlet has stored the security token in the // session; check that it matched the one sent in the UIDL - String sessId = (String) request.getSession().getAttribute( - ApplicationConnection.UIDL_SECURITY_TOKEN_ID); + String sessId = (String) request + .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID); if (sessId == null || !sessId.equals(bursts[0])) { throw new InvalidUIDLSecurityKeyException( @@ -1316,9 +1352,9 @@ public abstract class AbstractCommunicationManager implements } for (int bi = 1; bi < bursts.length; bi++) { - final String burst = bursts[bi]; - success = handleVariableBurst(request, application2, success, - burst); + // unescape any encoded separator characters in the burst + final String burst = unescapeBurst(bursts[bi]); + success &= handleBurst(request, application2, burst); // In case that there were multiple bursts, we know that this is // a special synchronous case for closing window. Thus we are @@ -1333,7 +1369,7 @@ public abstract class AbstractCommunicationManager implements new CharArrayWriter()); paintAfterVariableChanges(request, response, callback, - true, outWriter, window, false); + true, outWriter, root, false); } @@ -1345,127 +1381,250 @@ public abstract class AbstractCommunicationManager implements * we don't have the required logic implemented on the server side. E.g. * a component is removed in a previous burst. */ - return success || closingWindowName != null; + return success; } - public boolean handleVariableBurst(Object source, Application app, - boolean success, final String burst) { - // extract variables to two dim string array - final String[] tmp = burst.split(String.valueOf(VAR_RECORD_SEPARATOR)); - final String[][] variableRecords = new String[tmp.length][4]; - for (int i = 0; i < tmp.length; i++) { - variableRecords[i] = tmp[i].split(String - .valueOf(VAR_FIELD_SEPARATOR)); - } - - for (int i = 0; i < variableRecords.length; i++) { - String[] variable = variableRecords[i]; - String[] nextVariable = null; - if (i + 1 < variableRecords.length) { - nextVariable = variableRecords[i + 1]; + /** + * Processes a message burst received from the client. + * + * A burst can contain any number of RPC calls, including legacy variable + * change calls that are processed separately. + * + * Consecutive changes to the value of the same variable are combined and + * changeVariables() is only called once for them. This preserves the Vaadin + * 6 semantics for components and add-ons that do not use Vaadin 7 RPC + * directly. + * + * @param source + * @param app + * application receiving the burst + * @param burst + * the content of the burst as a String to be parsed + * @return true if the processing of the burst was successful and there were + * no messages to non-existent components + */ + public boolean handleBurst(Object source, Application app, + final String burst) { + boolean success = true; + try { + Set<Connector> enabledConnectors = new HashSet<Connector>(); + + List<MethodInvocation> invocations = parseInvocations(burst); + for (MethodInvocation invocation : invocations) { + final ClientConnector connector = getConnector(app, + invocation.getConnectorId()); + + if (connector != null && connector.isConnectorEnabled()) { + enabledConnectors.add(connector); + } } - final VariableOwner owner = getVariableOwner(variable[VAR_PID]); - if (owner != null && owner.isEnabled()) { - Map<String, Object> m; - if (nextVariable != null - && variable[VAR_PID].equals(nextVariable[VAR_PID])) { - // we have more than one value changes in row for - // one variable owner, collect them in HashMap - m = new HashMap<String, Object>(); - m.put(variable[VAR_NAME], - convertVariableValue(variable[VAR_TYPE].charAt(0), - variable[VAR_VALUE])); - } else { - // use optimized single value map - m = Collections.singletonMap( - variable[VAR_NAME], - convertVariableValue(variable[VAR_TYPE].charAt(0), - variable[VAR_VALUE])); + for (int i = 0; i < invocations.size(); i++) { + MethodInvocation invocation = invocations.get(i); + + final ClientConnector connector = getConnector(app, + invocation.getConnectorId()); + + if (connector == null) { + logger.log( + Level.WARNING, + "RPC call to " + invocation.getInterfaceName() + + "." + invocation.getMethodName() + + " received for connector " + + invocation.getConnectorId() + + " but no such connector could be found"); + continue; } - // collect following variable changes for this owner - while (nextVariable != null - && variable[VAR_PID].equals(nextVariable[VAR_PID])) { - i++; - variable = nextVariable; - if (i + 1 < variableRecords.length) { - nextVariable = variableRecords[i + 1]; - } else { - nextVariable = null; - } - m.put(variable[VAR_NAME], - convertVariableValue(variable[VAR_TYPE].charAt(0), - variable[VAR_VALUE])); - } - try { - changeVariables(source, owner, m); - - // Special-case of closing browser-level windows: - // track browser-windows currently open in client - if (owner instanceof Window - && ((Window) owner).getParent() == null) { - final Boolean close = (Boolean) m.get("close"); - if (close != null && close.booleanValue()) { - closingWindowName = ((Window) owner).getName(); + if (!enabledConnectors.contains(connector)) { + + if (invocation instanceof LegacyChangeVariablesInvocation) { + LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; + // TODO convert window close to a separate RPC call and + // handle above - not a variable change + + // Handle special case where window-close is called + // after the window has been removed from the + // application or the application has closed + Map<String, Object> changes = legacyInvocation + .getVariableChanges(); + if (changes.size() == 1 && changes.containsKey("close") + && Boolean.TRUE.equals(changes.get("close"))) { + // Silently ignore this + continue; } } - } catch (Exception e) { - Component errorComponent = null; - if (owner instanceof Component) { - errorComponent = (Component) owner; - } else if (owner instanceof DragAndDropService) { - if (m.get("dhowner") instanceof Component) { - errorComponent = (Component) m.get("dhowner"); + + // Connector is disabled, log a warning and move to the next + String msg = "Ignoring RPC call for disabled connector " + + connector.getClass().getName(); + if (connector instanceof Component) { + String caption = ((Component) connector).getCaption(); + if (caption != null) { + msg += ", caption=" + caption; } } - - handleChangeVariablesError(app, errorComponent, e, m); - } - } else { - - // Handle special case where window-close is called - // after the window has been removed from the - // application or the application has closed - if ("close".equals(variable[VAR_NAME]) - && "true".equals(variable[VAR_VALUE])) { - // Silently ignore this + logger.warning(msg); continue; } - // Ignore variable change - String msg = "Warning: Ignoring variable change for "; - if (owner != null) { - msg += "disabled component " + owner.getClass(); - String caption = ((Component) owner).getCaption(); - if (caption != null) { - msg += ", caption=" + caption; - } + if (invocation instanceof ServerRpcMethodInvocation) { + ServerRpcManager.applyInvocation(connector, + (ServerRpcMethodInvocation) invocation); } else { - msg += "non-existent component, VAR_PID=" - + variable[VAR_PID]; - success = false; + + // All code below is for legacy variable changes + LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; + Map<String, Object> changes = legacyInvocation + .getVariableChanges(); + try { + changeVariables(source, (VariableOwner) connector, + changes); + } catch (Exception e) { + Component errorComponent = null; + if (connector instanceof Component) { + errorComponent = (Component) connector; + } else if (connector instanceof DragAndDropService) { + Object dropHandlerOwner = changes.get("dhowner"); + if (dropHandlerOwner instanceof Component) { + errorComponent = (Component) dropHandlerOwner; + } + } + handleChangeVariablesError(app, errorComponent, e, + changes); + + } } - logger.warning(msg); - continue; } + + } catch (JSONException e) { + logger.warning("Unable to parse RPC call from the client: " + + e.getMessage()); + // TODO or return success = false? + throw new RuntimeException(e); } + return success; } + /** + * Parse a message burst from the client into a list of MethodInvocation + * instances. + * + * @param burst + * message string (JSON) + * @return list of MethodInvocation to perform + * @throws JSONException + */ + private List<MethodInvocation> parseInvocations(final String burst) + throws JSONException { + JSONArray invocationsJson = new JSONArray(burst); + + ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>(); + + MethodInvocation previousInvocation = null; + // parse JSON to MethodInvocations + for (int i = 0; i < invocationsJson.length(); ++i) { + + JSONArray invocationJson = invocationsJson.getJSONArray(i); + + MethodInvocation invocation = parseInvocation(invocationJson, + previousInvocation); + if (invocation != null) { + // Can be null iff the invocation was a legacy invocation and it + // was merged with the previous one + invocations.add(invocation); + previousInvocation = invocation; + } + } + return invocations; + } + + private MethodInvocation parseInvocation(JSONArray invocationJson, + MethodInvocation previousInvocation) throws JSONException { + String connectorId = invocationJson.getString(0); + String interfaceName = invocationJson.getString(1); + String methodName = invocationJson.getString(2); + + JSONArray parametersJson = invocationJson.getJSONArray(3); + + if (LegacyChangeVariablesInvocation.isLegacyVariableChange( + interfaceName, methodName)) { + if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) { + previousInvocation = null; + } + + return parseLegacyChangeVariablesInvocation(connectorId, + interfaceName, methodName, + (LegacyChangeVariablesInvocation) previousInvocation, + parametersJson); + } else { + return parseServerRpcInvocation(connectorId, interfaceName, + methodName, parametersJson); + } + + } + + private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation( + String connectorId, String interfaceName, String methodName, + LegacyChangeVariablesInvocation previousInvocation, + JSONArray parametersJson) throws JSONException { + if (parametersJson.length() != 2) { + throw new JSONException( + "Invalid parameters in legacy change variables call. Expected 2, was " + + parametersJson.length()); + } + String variableName = (String) JsonCodec + .decodeInternalType(String.class, true, + parametersJson.getJSONArray(0), application); + Object value = JsonCodec.decodeInternalType( + parametersJson.getJSONArray(1), application); + + if (previousInvocation != null + && previousInvocation.getConnectorId().equals(connectorId)) { + previousInvocation.setVariableChange(variableName, value); + return null; + } else { + return new LegacyChangeVariablesInvocation(connectorId, + variableName, value); + } + } + + private ServerRpcMethodInvocation parseServerRpcInvocation( + String connectorId, String interfaceName, String methodName, + JSONArray parametersJson) throws JSONException { + ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation( + connectorId, interfaceName, methodName, parametersJson.length()); + + Object[] parameters = new Object[parametersJson.length()]; + Type[] declaredRpcMethodParameterTypes = invocation.getMethod() + .getGenericParameterTypes(); + + for (int j = 0; j < parametersJson.length(); ++j) { + JSONArray parameterJson = parametersJson.getJSONArray(j); + Type parameterType = declaredRpcMethodParameterTypes[j]; + parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType, + parameterJson, application); + } + invocation.setParameters(parameters); + return invocation; + } + protected void changeVariables(Object source, final VariableOwner owner, Map<String, Object> m) { owner.changeVariables(source, m); } - protected VariableOwner getVariableOwner(String string) { - VariableOwner owner = (VariableOwner) idPaintableMap.get(string); - if (owner == null && string.startsWith("DD")) { + protected ClientConnector getConnector(Application app, String connectorId) { + ClientConnector c = app.getConnector(connectorId); + if (c == null + && connectorId.equals(getDragAndDropService().getConnectorId())) { return getDragAndDropService(); } - return owner; + + return c; } - private VariableOwner getDragAndDropService() { + private DragAndDropService getDragAndDropService() { if (dragAndDropService == null) { dragAndDropService = new DragAndDropService(this); } @@ -1480,7 +1639,8 @@ public abstract class AbstractCommunicationManager implements * @return * @throws IOException */ - protected String getRequestPayload(Request request) throws IOException { + protected String getRequestPayload(WrappedRequest request) + throws IOException { int requestLength = request.getContentLength(); if (requestLength == 0) { @@ -1544,7 +1704,7 @@ public abstract class AbstractCommunicationManager implements if (owner instanceof AbstractField) { try { - handled = ((AbstractField) owner).handleError(errorEvent); + handled = ((AbstractField<?>) owner).handleError(errorEvent); } catch (Exception handlerException) { /* * If there is an error in the component error handler we pass @@ -1563,111 +1723,15 @@ public abstract class AbstractCommunicationManager implements } - private Object convertVariableValue(char variableType, String strValue) { - Object val = null; - switch (variableType) { - case VTYPE_ARRAY: - val = convertArray(strValue); - break; - case VTYPE_MAP: - val = convertMap(strValue); - break; - case VTYPE_STRINGARRAY: - val = convertStringArray(strValue); - break; - case VTYPE_STRING: - // decode encoded separators - val = decodeVariableValue(strValue); - break; - case VTYPE_INTEGER: - val = Integer.valueOf(strValue); - break; - case VTYPE_LONG: - val = Long.valueOf(strValue); - break; - case VTYPE_FLOAT: - val = Float.valueOf(strValue); - break; - case VTYPE_DOUBLE: - val = Double.valueOf(strValue); - break; - case VTYPE_BOOLEAN: - val = Boolean.valueOf(strValue); - break; - case VTYPE_PAINTABLE: - val = idPaintableMap.get(strValue); - break; - } - - return val; - } - - private Object convertMap(String strValue) { - String[] parts = strValue - .split(String.valueOf(VAR_ARRAYITEM_SEPARATOR)); - HashMap<String, Object> map = new HashMap<String, Object>(); - for (int i = 0; i < parts.length; i += 2) { - String key = parts[i]; - if (key.length() > 0) { - char variabletype = key.charAt(0); - // decode encoded separators - String decodedValue = decodeVariableValue(parts[i + 1]); - String decodedKey = decodeVariableValue(key.substring(1)); - Object value = convertVariableValue(variabletype, decodedValue); - map.put(decodedKey, value); - } - } - return map; - } - - private String[] convertStringArray(String strValue) { - // need to return delimiters and filter them out; otherwise empty - // strings are lost - // an extra empty delimiter at the end is automatically eliminated - final String arrayItemSeparator = String - .valueOf(VAR_ARRAYITEM_SEPARATOR); - StringTokenizer tokenizer = new StringTokenizer(strValue, - arrayItemSeparator, true); - List<String> tokens = new ArrayList<String>(); - String prevToken = arrayItemSeparator; - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - if (!arrayItemSeparator.equals(token)) { - // decode encoded separators - tokens.add(decodeVariableValue(token)); - } else if (arrayItemSeparator.equals(prevToken)) { - tokens.add(""); - } - prevToken = token; - } - return tokens.toArray(new String[tokens.size()]); - } - - private Object convertArray(String strValue) { - String[] val = strValue.split(String.valueOf(VAR_ARRAYITEM_SEPARATOR)); - if (val.length == 0 || (val.length == 1 && val[0].length() == 0)) { - return new Object[0]; - } - Object[] values = new Object[val.length]; - for (int i = 0; i < values.length; i++) { - String string = val[i]; - // first char of string is type - char variableType = string.charAt(0); - values[i] = convertVariableValue(variableType, string.substring(1)); - } - return values; - } - /** - * Decode encoded burst, record, field and array item separator characters - * in a variable value String received from the client. This protects from - * separator injection attacks. + * Unescape encoded burst separator characters in a burst received from the + * client. This protects from separator injection attacks. * * @param encodedValue * to decode * @return decoded value */ - protected String decodeVariableValue(String encodedValue) { + protected String unescapeBurst(String encodedValue) { final StringBuilder result = new StringBuilder(); final StringCharacterIterator iterator = new StringCharacterIterator( encodedValue); @@ -1681,9 +1745,6 @@ public abstract class AbstractCommunicationManager implements result.append(VAR_ESCAPE_CHARACTER); break; case VAR_BURST_SEPARATOR + 0x30: - case VAR_RECORD_SEPARATOR + 0x30: - case VAR_FIELD_SEPARATOR + 0x30: - case VAR_ARRAYITEM_SEPARATOR + 0x30: // +0x30 makes these letters for easier reading result.append((char) (character - 0x30)); break; @@ -1843,108 +1904,6 @@ public abstract class AbstractCommunicationManager implements } /** - * TODO New method - document me! - * - * @param request - * @param callback - * @param application - * @param assumedWindow - * @return - */ - protected Window doGetApplicationWindow(Request request, Callback callback, - Application application, Window assumedWindow) { - - Window window = null; - - // If the client knows which window to use, use it if possible - String windowClientRequestedName = request.getParameter("windowName"); - - if (assumedWindow != null - && application.getWindows().contains(assumedWindow)) { - windowClientRequestedName = assumedWindow.getName(); - } - if (windowClientRequestedName != null) { - window = application.getWindow(windowClientRequestedName); - if (window != null) { - return window; - } - } - - // If client does not know what window it wants - if (window == null && !request.isRunningInPortlet()) { - // This is only supported if the application is running inside a - // servlet - - // Get the path from URL - String path = callback.getRequestPathInfo(request); - - /* - * If the path is specified, create name from it. - * - * An exception is if UIDL request have come this far. This happens - * if main window is refreshed. In that case we always return main - * window (infamous hacky support for refreshes if only main window - * is used). However we are not returning with main window here (we - * will later if things work right), because the code is so cryptic - * that nobody really knows what it does. - */ - boolean pathMayContainWindowName = path != null - && path.length() > 0 && !path.equals("/"); - if (pathMayContainWindowName) { - boolean uidlRequest = path.startsWith("/UIDL"); - if (!uidlRequest) { - String windowUrlName = null; - if (path.charAt(0) == '/') { - path = path.substring(1); - } - final int index = path.indexOf('/'); - if (index < 0) { - windowUrlName = path; - path = ""; - } else { - windowUrlName = path.substring(0, index); - path = path.substring(index + 1); - } - - window = application.getWindow(windowUrlName); - } - } - - } - - // By default, use mainwindow - if (window == null) { - window = application.getMainWindow(); - // Return null if no main window was found - if (window == null) { - return null; - } - } - - // If the requested window is already open, resolve conflict - if (currentlyOpenWindowsInClient.containsKey(window.getName())) { - String newWindowName = window.getName(); - - synchronized (AbstractCommunicationManager.class) { - while (currentlyOpenWindowsInClient.containsKey(newWindowName)) { - newWindowName = window.getName() + "_" - + nextUnusedWindowSuffix++; - } - } - - window = application.getWindow(newWindowName); - - // If everything else fails, use main window even in case of - // conflicts - if (window == null) { - window = application.getMainWindow(); - } - } - - return window; - } - - /** * Ends the Application. * * The browser is redirected to the Application logout URL set with @@ -1960,8 +1919,9 @@ public abstract class AbstractCommunicationManager implements * @throws IOException * if the writing failed due to input/output error. */ - private void endApplication(Request request, Response response, - Application application) throws IOException { + private void endApplication(WrappedRequest request, + WrappedResponse response, Application application) + throws IOException { String logoutUrl = application.getLogoutURL(); if (logoutUrl == null) { @@ -1992,7 +1952,8 @@ public abstract class AbstractCommunicationManager implements * @param outWriter * @param response */ - protected void openJsonMessage(PrintWriter outWriter, Response response) { + protected void openJsonMessage(PrintWriter outWriter, + WrappedResponse response) { // Sets the response type response.setContentType("application/json; charset=UTF-8"); // some dirt to prevent cross site scripting @@ -2000,47 +1961,6 @@ public abstract class AbstractCommunicationManager implements } /** - * Gets the Paintable Id. If Paintable has debug id set it will be used - * prefixed with "PID_S". Otherwise a sequenced ID is created. - * - * @param paintable - * @return the paintable Id. - */ - public String getPaintableId(Paintable paintable) { - - String id = paintableIdMap.get(paintable); - if (id == null) { - // use testing identifier as id if set - String debugId = paintable.getDebugId(); - if (debugId == null) { - id = "PID" + idSequence++; - } else { - id = "PID_S" + debugId; - for (int seq = 0;; ++seq) { - // In case of a duplicate debug id, uniquify the PID by - // inserting a sequential integer. Try successive numbers - // until finding a PID that is either not used at all or - // used by a detached component. See #5109. - Paintable old = idPaintableMap.get(id); - if (old == null - || (old instanceof Component && ((Component) old) - .getApplication() == null)) { - break; - } - id = "PID_" + seq + "S" + debugId; - } - } - idPaintableMap.put(id, paintable); - paintableIdMap.put(paintable, id); - } - return id; - } - - public boolean hasPaintableId(Paintable paintable) { - return paintableIdMap.containsKey(paintable); - } - - /** * Returns dirty components which are in given window. Components in an * invisible subtrees are omitted. * @@ -2048,110 +1968,16 @@ public abstract class AbstractCommunicationManager implements * root window for which dirty components is to be fetched * @return */ - private ArrayList<Paintable> getDirtyVisibleComponents(Window w) { - final ArrayList<Paintable> resultset = new ArrayList<Paintable>( - dirtyPaintables); - - // The following algorithm removes any components that would be painted - // as a direct descendant of other components from the dirty components - // list. The result is that each component should be painted exactly - // once and any unmodified components will be painted as "cached=true". - - for (final Iterator<Paintable> i = dirtyPaintables.iterator(); i - .hasNext();) { - final Paintable p = i.next(); - if (p instanceof Component) { - final Component component = (Component) p; - if (component.getApplication() == null) { - // component is detached after requestRepaint is called - resultset.remove(p); - i.remove(); - } else { - Window componentsRoot = component.getWindow(); - if (componentsRoot == null) { - // This should not happen unless somebody has overriden - // getApplication or getWindow in an illegal way. - throw new IllegalStateException( - "component.getWindow() returned null for a component attached to the application"); - } - if (componentsRoot.getParent() != null) { - // this is a subwindow - componentsRoot = componentsRoot.getParent(); - } - if (componentsRoot != w) { - resultset.remove(p); - } else if (component.getParent() != null - && !component.getParent().isVisible()) { - /* - * Do not return components in an invisible subtree. - * - * Components that are invisible in visible subree, must - * be rendered (to let client know that they need to be - * hidden). - */ - resultset.remove(p); - } - } + private ArrayList<Component> getDirtyVisibleComponents( + DirtyConnectorTracker dirtyConnectorTracker) { + ArrayList<Component> dirtyComponents = new ArrayList<Component>(); + for (Component c : dirtyConnectorTracker.getDirtyComponents()) { + if (isVisible(c)) { + dirtyComponents.add(c); } } - return resultset; - } - - /** - * @see com.vaadin.terminal.Paintable.RepaintRequestListener#repaintRequested(com.vaadin.terminal.Paintable.RepaintRequestEvent) - */ - public void repaintRequested(RepaintRequestEvent event) { - final Paintable p = event.getPaintable(); - if (!dirtyPaintables.contains(p)) { - dirtyPaintables.add(p); - } - } - - /** - * Internally mark a {@link Paintable} as painted and start collecting new - * repaint requests for it. - * - * @param paintable - */ - private void paintablePainted(Paintable paintable) { - dirtyPaintables.remove(paintable); - paintable.requestRepaintRequests(); - } - - /** - * Implementation of {@link URIHandler.ErrorEvent} interface. - */ - public class URIHandlerErrorImpl implements URIHandler.ErrorEvent, - Serializable { - - private final URIHandler owner; - - private final Throwable throwable; - - /** - * - * @param owner - * @param throwable - */ - private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) { - this.owner = owner; - this.throwable = throwable; - } - - /** - * @see com.vaadin.terminal.Terminal.ErrorEvent#getThrowable() - */ - public Throwable getThrowable() { - return throwable; - } - - /** - * @see com.vaadin.terminal.URIHandler.ErrorEvent#getURIHandler() - */ - public URIHandler getURIHandler() { - return owner; - } + return dirtyComponents; } /** @@ -2196,23 +2022,6 @@ public abstract class AbstractCommunicationManager implements } } - /** - * Helper method to test if a component contains another - * - * @param parent - * @param child - */ - private static boolean isChildOf(Component parent, Component child) { - Component p = child.getParent(); - while (p != null) { - if (parent == p) { - return true; - } - p = p.getParent(); - } - return false; - } - protected class InvalidUIDLSecurityKeyException extends GeneralSecurityException { @@ -2222,87 +2031,19 @@ public abstract class AbstractCommunicationManager implements } - /** - * Calls the Window URI handler for a request and returns the - * {@link DownloadStream} returned by the handler. - * - * If the window is the main window of an application, the (deprecated) - * {@link Application#handleURI(java.net.URL, String)} is called first to - * handle {@link ApplicationResource}s, and the window handler is only - * called if it returns null. - * - * @param window - * the target window of the request - * @param request - * the request instance - * @param response - * the response to write to - * @return DownloadStream if the request was handled and further processing - * should be suppressed, null otherwise. - * @see com.vaadin.terminal.URIHandler - */ - @SuppressWarnings("deprecation") - protected DownloadStream handleURI(Window window, Request request, - Response response, Callback callback) { - - String uri = callback.getRequestPathInfo(request); - - // If no URI is available - if (uri == null) { - uri = ""; - } else { - // Removes the leading / - while (uri.startsWith("/") && uri.length() > 0) { - uri = uri.substring(1); - } - } - - // Handles the uri - try { - URL context = application.getURL(); - if (window == application.getMainWindow()) { - DownloadStream stream = null; - /* - * Application.handleURI run first. Handles possible - * ApplicationResources. - */ - stream = application.handleURI(context, uri); - if (stream == null) { - stream = window.handleURI(context, uri); - } - return stream; - } else { - // Resolve the prefix end index - final int index = uri.indexOf('/'); - if (index > 0) { - String prefix = uri.substring(0, index); - URL windowContext; - windowContext = new URL(context, prefix + "/"); - final String windowUri = (uri.length() > prefix.length() + 1) ? uri - .substring(prefix.length() + 1) : ""; - return window.handleURI(windowContext, windowUri); - } else { - return null; - } - } - - } catch (final Throwable t) { - application.getErrorHandler().terminalError( - new URIHandlerErrorImpl(application, t)); - return null; - } - } - - private final HashMap<Class<? extends Paintable>, Integer> typeToKey = new HashMap<Class<? extends Paintable>, Integer>(); + private final HashMap<Class<? extends ClientConnector>, Integer> typeToKey = new HashMap<Class<? extends ClientConnector>, Integer>(); private int nextTypeKey = 0; - String getTagForType(Class<? extends Paintable> class1) { - Integer object = typeToKey.get(class1); - if (object == null) { - object = nextTypeKey++; - typeToKey.put(class1, object); + private BootstrapHandler bootstrapHandler; + + String getTagForType(Class<? extends ClientConnector> class1) { + Integer id = typeToKey.get(class1); + if (id == null) { + id = nextTypeKey++; + typeToKey.put(class1, id); + logger.log(Level.FINE, "Mapping " + class1.getName() + " to " + id); } - return object.toString(); + return id.toString(); } /** @@ -2311,7 +2052,7 @@ public abstract class AbstractCommunicationManager implements * * TODO make customlayout templates (from theme) to be cached here. */ - class OpenWindowCache implements Serializable { + class ClientCache implements Serializable { private final Set<Object> res = new HashSet<Object>(); @@ -2330,10 +2071,116 @@ public abstract class AbstractCommunicationManager implements } - abstract String getStreamVariableTargetUrl(VariableOwner owner, - String name, StreamVariable value); + abstract String getStreamVariableTargetUrl(Connector owner, String name, + StreamVariable value); - abstract protected void cleanStreamVariable(VariableOwner owner, String name); + abstract protected void cleanStreamVariable(Connector owner, String name); + + /** + * Gets the bootstrap handler that should be used for generating the pages + * bootstrapping applications for this communication manager. + * + * @return the bootstrap handler to use + */ + private BootstrapHandler getBootstrapHandler() { + if (bootstrapHandler == null) { + bootstrapHandler = createBootstrapHandler(); + } + + return bootstrapHandler; + } + + protected abstract BootstrapHandler createBootstrapHandler(); + + protected boolean handleApplicationRequest(WrappedRequest request, + WrappedResponse response) throws IOException { + return application.handleRequest(request, response); + } + + public void handleBrowserDetailsRequest(WrappedRequest request, + WrappedResponse response, Application application) + throws IOException { + + // if we do not yet have a currentRoot, it should be initialized + // shortly, and we should send the initial UIDL + boolean sendUIDL = Root.getCurrentRoot() == null; + + try { + CombinedRequest combinedRequest = new CombinedRequest(request); + + Root root = application.getRootForRequest(combinedRequest); + response.setContentType("application/json; charset=UTF-8"); + + // Use the same logic as for determined roots + BootstrapHandler bootstrapHandler = getBootstrapHandler(); + BootstrapContext context = bootstrapHandler.createContext( + combinedRequest, response, application, root.getRootId()); + + String widgetset = context.getWidgetsetName(); + String theme = context.getThemeName(); + String themeUri = bootstrapHandler.getThemeUri(context, theme); + + // TODO These are not required if it was only the init of the root + // that was delayed + JSONObject params = new JSONObject(); + params.put("widgetset", widgetset); + params.put("themeUri", themeUri); + // Root id might have changed based on e.g. window.name + params.put(ApplicationConnection.ROOT_ID_PARAMETER, + root.getRootId()); + if (sendUIDL) { + String initialUIDL = getInitialUIDL(combinedRequest, root); + params.put("uidl", initialUIDL); + } + + // NOTE! GateIn requires, for some weird reason, getOutputStream + // to be used instead of getWriter() (it seems to interpret + // application/json as a binary content type) + final OutputStream out = response.getOutputStream(); + final PrintWriter outWriter = new PrintWriter(new BufferedWriter( + new OutputStreamWriter(out, "UTF-8"))); + + outWriter.write(params.toString()); + // NOTE GateIn requires the buffers to be flushed to work + outWriter.flush(); + out.flush(); + } catch (RootRequiresMoreInformationException e) { + // Requiring more information at this point is not allowed + // TODO handle in a better way + throw new RuntimeException(e); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Generates the initial UIDL message that can e.g. be included in a html + * page to avoid a separate round trip just for getting the UIDL. + * + * @param request + * the request that caused the initialization + * @param root + * the root for which the UIDL should be generated + * @return a string with the initial UIDL message + * @throws PaintException + * if an exception occurs while painting + */ + protected String getInitialUIDL(WrappedRequest request, Root root) + throws PaintException { + // TODO maybe unify writeUidlResponse()? + StringWriter sWriter = new StringWriter(); + PrintWriter pWriter = new PrintWriter(sWriter); + pWriter.print("{"); + if (isXSRFEnabled(root.getApplication())) { + pWriter.print(getSecurityKeyUIDL(request)); + } + writeUidlResponse(request, true, pWriter, root, false); + pWriter.print("}"); + String initialUIDL = sWriter.toString(); + logger.log(Level.FINE, "Initial UIDL:" + initialUIDL); + return initialUIDL; + } /** * Stream that extracts content from another stream until the boundary @@ -2484,4 +2331,5 @@ public abstract class AbstractCommunicationManager implements return b; } } + } diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java deleted file mode 100644 index f971bcbc90..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet.java +++ /dev/null @@ -1,250 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.PortalContext; -import javax.portlet.Portlet; -import javax.portlet.PortletConfig; -import javax.portlet.PortletException; -import javax.portlet.PortletRequestDispatcher; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import com.liferay.portal.kernel.util.PropsUtil; -import com.vaadin.Application; - -/** - * Portlet main class for Portlet 1.0 (JSR-168) portlets which consist of a - * portlet and a servlet. For Portlet 2.0 (JSR-286, no servlet required), use - * {@link ApplicationPortlet2} instead. - */ -@SuppressWarnings("serial") -public class ApplicationPortlet implements Portlet, Serializable { - // portlet configuration parameters - private static final String PORTLET_PARAMETER_APPLICATION = "application"; - private static final String PORTLET_PARAMETER_STYLE = "style"; - private static final String PORTLET_PARAMETER_WIDGETSET = "widgetset"; - - // The application to show - protected String app = null; - // some applications might require forced height (and, more seldom, width) - protected String style = null; // e.g "height:500px;" - // force the portlet to use this widgetset - portlet level setting - protected String portletWidgetset = null; - - public void destroy() { - - } - - public void init(PortletConfig config) throws PortletException { - app = config.getInitParameter(PORTLET_PARAMETER_APPLICATION); - if (app == null) { - throw new PortletException( - "No porlet application url defined in portlet.xml. Define the '" - + PORTLET_PARAMETER_APPLICATION - + "' init parameter to be the servlet deployment path."); - } - style = config.getInitParameter(PORTLET_PARAMETER_STYLE); - // enable forcing the selection of the widgetset in portlet - // configuration for a single portlet (backwards compatibility) - portletWidgetset = config.getInitParameter(PORTLET_PARAMETER_WIDGETSET); - } - - public void processAction(ActionRequest request, ActionResponse response) - throws PortletException, IOException { - PortletApplicationContext.dispatchRequest(this, request, response); - } - - public void render(RenderRequest request, RenderResponse response) - throws PortletException, IOException { - - // display the Vaadin application - writeAjaxWindow(request, response); - } - - protected void writeAjaxWindow(RenderRequest request, - RenderResponse response) throws IOException { - - response.setContentType("text/html"); - if (app != null) { - PortletSession sess = request.getPortletSession(); - PortletApplicationContext ctx = PortletApplicationContext - .getApplicationContext(sess); - - PortletRequestDispatcher dispatcher = sess.getPortletContext() - .getRequestDispatcher("/" + app); - - try { - // portal-wide settings - PortalContext portalCtx = request.getPortalContext(); - - boolean isLifeRay = portalCtx.getPortalInfo().toLowerCase() - .contains("liferay"); - - request.setAttribute(ApplicationServlet.REQUEST_FRAGMENT, - "true"); - - // fixed base theme to use - all portal pages with Vaadin - // applications will load this exactly once - String portalTheme = getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_THEME, portalCtx); - - String portalWidgetset = getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_WIDGETSET, portalCtx); - - // location of the widgetset(s) and default theme (to which - // /VAADIN/widgetsets/... - // is appended) - String portalResourcePath = getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH, - portalCtx); - - if (portalResourcePath != null) { - // if portalResourcePath is defined, set it as a request - // parameter which will override the default location in - // servlet - request.setAttribute( - ApplicationServlet.REQUEST_VAADIN_STATIC_FILE_PATH, - portalResourcePath); - } - - // - if the user has specified a widgetset for this portlet, use - // it from the portlet (not fully supported) - // - otherwise, if specified, use the portal-wide widgetset - // and widgetset path settings (recommended) - // - finally, default to use the default widgetset if nothing - // else is found - if (portletWidgetset != null) { - request.setAttribute(ApplicationServlet.REQUEST_WIDGETSET, - portletWidgetset); - } - if (portalWidgetset != null) { - request.setAttribute( - ApplicationServlet.REQUEST_SHARED_WIDGETSET, - portalWidgetset); - } - - if (style != null) { - request.setAttribute(ApplicationServlet.REQUEST_APPSTYLE, - style); - } - - // portalTheme is only used if the shared portal resource - // directory is defined - if (portalTheme != null && portalResourcePath != null) { - request.setAttribute( - ApplicationServlet.REQUEST_DEFAULT_THEME, - portalTheme); - - String defaultThemeUri = null; - defaultThemeUri = portalResourcePath + "/" - + AbstractApplicationServlet.THEME_DIRECTORY_PATH - + portalTheme; - /* - * Make sure portal default Vaadin theme is included in DOM. - * Vaadin portlet themes do not "inherit" base theme, so we - * need to force loading of the common base theme. - */ - OutputStream out = response.getPortletOutputStream(); - - // Using portal-wide theme - String loadDefaultTheme = ("<script type=\"text/javascript\">\n" - + "if(!vaadin) { var vaadin = {} } \n" - + "if(!vaadin.themesLoaded) { vaadin.themesLoaded = {} } \n" - + "if(!vaadin.themesLoaded['" - + portalTheme - + "']) {\n" - + "var stylesheet = document.createElement('link');\n" - + "stylesheet.setAttribute('rel', 'stylesheet');\n" - + "stylesheet.setAttribute('type', 'text/css');\n" - + "stylesheet.setAttribute('href', '" - + defaultThemeUri - + "/styles.css');\n" - + "document.getElementsByTagName('head')[0].appendChild(stylesheet);\n" - + "vaadin.themesLoaded['" - + portalTheme - + "'] = true;\n}\n" + "</script>\n"); - out.write(loadDefaultTheme.getBytes()); - } - - dispatcher.include(request, response); - - if (isLifeRay) { - /* - * Temporary support to heartbeat Liferay session when using - * Vaadin based portlet. We hit an extra xhr to liferay - * servlet to extend the session lifetime after each Vaadin - * request. This hack can be removed when supporting portlet - * 2.0 and resourceRequests. - * - * TODO make this configurable, this is not necessary with - * some custom session configurations. - */ - OutputStream out = response.getPortletOutputStream(); - - String lifeRaySessionHearbeatHack = ("<script type=\"text/javascript\">" - + "if(!vaadin.postRequestHooks) {" - + " vaadin.postRequestHooks = {};" - + "}" - + "vaadin.postRequestHooks.liferaySessionHeartBeat = function() {" - + " if (Liferay && Liferay.Session && Liferay.Session.setCookie) {" - + " Liferay.Session.setCookie();" - + " }" - + "};" + "</script>"); - out.write(lifeRaySessionHearbeatHack.getBytes()); - } - - } catch (PortletException e) { - PrintWriter out = response.getWriter(); - out.print("<h1>Servlet include failed!</h1>"); - Logger.getLogger(AbstractApplicationPortlet.class.getName()) - .log(Level.WARNING, "Servlet include failed", e); - ctx.setPortletApplication(this, null); - return; - } - - Application app = (Application) request - .getAttribute(Application.class.getName()); - ctx.setPortletApplication(this, app); - ctx.firePortletRenderRequest(this, request, response); - - } - } - - private String getPortalProperty(String name, PortalContext context) { - boolean isLifeRay = context.getPortalInfo().toLowerCase() - .contains("liferay"); - - // TODO test on non-LifeRay platforms - - String value; - if (isLifeRay) { - value = getLifeRayPortalProperty(name); - } else { - value = context.getProperty(name); - } - - return value; - } - - private String getLifeRayPortalProperty(String name) { - String value; - try { - value = PropsUtil.get(name); - } catch (Exception e) { - value = null; - } - return value; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java index 3e15c1cf8f..7a46a07e6c 100644 --- a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java +++ b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java @@ -8,6 +8,7 @@ import javax.portlet.PortletConfig; import javax.portlet.PortletException; import com.vaadin.Application; +import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; /** * TODO Write documentation, fix JavaDoc tags. @@ -18,23 +19,16 @@ public class ApplicationPortlet2 extends AbstractApplicationPortlet { private Class<? extends Application> applicationClass; - @SuppressWarnings("unchecked") @Override public void init(PortletConfig config) throws PortletException { super.init(config); - final String applicationClassName = config - .getInitParameter("application"); - if (applicationClassName == null) { - throw new PortletException( - "Application not specified in portlet parameters"); - } - try { - applicationClass = (Class<? extends Application>) getClassLoader() - .loadClass(applicationClassName); - } catch (final ClassNotFoundException e) { - throw new PortletException("Failed to load application class: " - + applicationClassName); + applicationClass = ServletPortletHelper.getApplicationClass( + config.getInitParameter("application"), + config.getInitParameter(Application.ROOT_PARAMETER), + getClassLoader()); + } catch (ApplicationClassException e) { + throw new PortletException(e); } } diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java new file mode 100644 index 0000000000..7cf66d5fcf --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java @@ -0,0 +1,54 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletResponse; + +import com.vaadin.Application; +import com.vaadin.terminal.ApplicationResource; +import com.vaadin.terminal.DownloadStream; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; + +public class ApplicationResourceHandler implements RequestHandler { + private static final Pattern APP_RESOURCE_PATTERN = Pattern + .compile("^/?APP/(\\d+)/.*"); + + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + // Check for application resources + String requestPath = request.getRequestPathInfo(); + if (requestPath == null) { + return false; + } + Matcher resourceMatcher = APP_RESOURCE_PATTERN.matcher(requestPath); + + if (resourceMatcher.matches()) { + ApplicationResource resource = application + .getResource(resourceMatcher.group(1)); + if (resource != null) { + DownloadStream stream = resource.getStream(); + if (stream != null) { + stream.setCacheTime(resource.getCacheTime()); + stream.writeTo(response); + return true; + } + } + // We get here if the url looks like an application resource but no + // resource can be served + response.sendError(HttpServletResponse.SC_NOT_FOUND, + request.getRequestPathInfo() + " can not be found"); + return true; + } + + return false; + } +} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java index 8ad763f5d1..2c4d38ef24 100644 --- a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java @@ -8,6 +8,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import com.vaadin.Application; +import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; /** * This servlet connects a Vaadin Application to Web. @@ -35,7 +36,6 @@ public class ApplicationServlet extends AbstractApplicationServlet { * if an exception has occurred that interferes with the * servlet's normal operation. */ - @SuppressWarnings("unchecked") @Override public void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException { @@ -44,20 +44,13 @@ public class ApplicationServlet extends AbstractApplicationServlet { // Loads the application class using the same class loader // as the servlet itself - // Gets the application class name - final String applicationClassName = servletConfig - .getInitParameter("application"); - if (applicationClassName == null) { - throw new ServletException( - "Application not specified in servlet parameters"); - } - try { - applicationClass = (Class<? extends Application>) getClassLoader() - .loadClass(applicationClassName); - } catch (final ClassNotFoundException e) { - throw new ServletException("Failed to load application class: " - + applicationClassName); + applicationClass = ServletPortletHelper.getApplicationClass( + servletConfig.getInitParameter("application"), + servletConfig.getInitParameter(Application.ROOT_PARAMETER), + getClassLoader()); + } catch (ApplicationClassException e) { + throw new ServletException(e); } } @@ -84,4 +77,4 @@ public class ApplicationServlet extends AbstractApplicationServlet { throws ClassNotFoundException { return applicationClass; } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java new file mode 100644 index 0000000000..84f87124d3 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java @@ -0,0 +1,602 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Serializable; +import java.io.Writer; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.external.json.JSONException; +import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.PaintException; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.ui.Root; + +public abstract class BootstrapHandler implements RequestHandler { + + protected class BootstrapContext implements Serializable { + + private final WrappedResponse response; + private final WrappedRequest request; + private final Application application; + private final Integer rootId; + + private Writer writer; + private Root root; + private String widgetsetName; + private String themeName; + private String appId; + + private boolean rootFetched = false; + + public BootstrapContext(WrappedResponse response, + WrappedRequest request, Application application, Integer rootId) { + this.response = response; + this.request = request; + this.application = application; + this.rootId = rootId; + } + + public WrappedResponse getResponse() { + return response; + } + + public WrappedRequest getRequest() { + return request; + } + + public Application getApplication() { + return application; + } + + public Writer getWriter() throws IOException { + if (writer == null) { + response.setContentType("text/html"); + writer = new BufferedWriter(new OutputStreamWriter( + response.getOutputStream(), "UTF-8")); + } + return writer; + } + + public Integer getRootId() { + return rootId; + } + + public Root getRoot() { + if (!rootFetched) { + root = Root.getCurrentRoot(); + rootFetched = true; + } + return root; + } + + public String getWidgetsetName() { + if (widgetsetName == null) { + Root root = getRoot(); + if (root != null) { + widgetsetName = getWidgetsetForRoot(this); + } + } + return widgetsetName; + } + + public String getThemeName() { + if (themeName == null) { + Root root = getRoot(); + if (root != null) { + themeName = findAndEscapeThemeName(this); + } + } + return themeName; + } + + public String getAppId() { + if (appId == null) { + appId = getApplicationId(this); + } + return appId; + } + + } + + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + + // TODO Should all urls be handled here? + Integer rootId = null; + try { + Root root = application.getRootForRequest(request); + if (root == null) { + writeError(response, new Throwable("No Root found")); + return true; + } + + rootId = Integer.valueOf(root.getRootId()); + } catch (RootRequiresMoreInformationException e) { + // Just keep going without rootId + } + + try { + writeBootstrapPage(request, response, application, rootId); + } catch (JSONException e) { + writeError(response, e); + } + + return true; + } + + protected final void writeBootstrapPage(WrappedRequest request, + WrappedResponse response, Application application, Integer rootId) + throws IOException, JSONException { + + BootstrapContext context = createContext(request, response, + application, rootId); + + DeploymentConfiguration deploymentConfiguration = request + .getDeploymentConfiguration(); + + boolean standalone = deploymentConfiguration.isStandalone(request); + if (standalone) { + setBootstrapPageHeaders(context); + writeBootstrapPageHtmlHeadStart(context); + writeBootstrapPageHtmlHeader(context); + writeBootstrapPageHtmlBodyStart(context); + } + + // TODO include initial UIDL in the scripts? + writeBootstrapPageHtmlVaadinScripts(context); + + writeBootstrapPageHtmlMainDiv(context); + + Writer page = context.getWriter(); + if (standalone) { + page.write("</body>\n</html>\n"); + } + + page.close(); + } + + public BootstrapContext createContext(WrappedRequest request, + WrappedResponse response, Application application, Integer rootId) { + BootstrapContext context = new BootstrapContext(response, request, + application, rootId); + return context; + } + + protected String getMainDivStyle(BootstrapContext context) { + return null; + } + + /** + * Creates and returns a unique ID for the DIV where the application is to + * be rendered. + * + * @param context + * + * @return the id to use in the DOM + */ + protected abstract String getApplicationId(BootstrapContext context); + + public String getWidgetsetForRoot(BootstrapContext context) { + Root root = context.getRoot(); + WrappedRequest request = context.getRequest(); + + String widgetset = root.getApplication().getWidgetsetForRoot(root); + if (widgetset == null) { + widgetset = request.getDeploymentConfiguration() + .getConfiguredWidgetset(request); + } + + widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset); + return widgetset; + } + + /** + * Method to write the div element into which that actual Vaadin application + * is rendered. + * <p> + * Override this method if you want to add some custom html around around + * the div element into which the actual Vaadin application will be + * rendered. + * + * @param context + * + * @throws IOException + */ + protected void writeBootstrapPageHtmlMainDiv(BootstrapContext context) + throws IOException { + Writer page = context.getWriter(); + String style = getMainDivStyle(context); + + /*- Add classnames; + * .v-app + * .v-app-loading + * .v-app-<simpleName for app class> + *- Additionally added from javascript: + * .v-theme-<themeName, remove non-alphanum> + */ + + String appClass = "v-app-" + + getApplicationCSSClassName(context.getApplication()); + + String classNames = "v-app " + appClass; + + if (style != null && style.length() != 0) { + style = " style=\"" + style + "\""; + } + page.write("<div id=\"" + context.getAppId() + "\" class=\"" + + classNames + "\"" + style + ">"); + page.write("<div class=\"v-app-loading\"></div>"); + page.write("</div>\n"); + page.write("<noscript>" + getNoScriptMessage() + "</noscript>"); + } + + /** + * Returns a message printed for browsers without scripting support or if + * browsers scripting support is disabled. + */ + protected String getNoScriptMessage() { + return "You have to enable javascript in your browser to use an application built with Vaadin."; + } + + /** + * Returns the application class identifier for use in the application CSS + * class name in the root DIV. The application CSS class name is of form + * "v-app-"+getApplicationCSSClassName(). + * + * This method should normally not be overridden. + * + * @return The CSS class name to use in combination with "v-app-". + */ + protected String getApplicationCSSClassName(Application application) { + return application.getClass().getSimpleName(); + } + + /** + * + * Method to open the body tag of the html kickstart page. + * <p> + * This method is responsible for closing the head tag and opening the body + * tag. + * <p> + * Override this method if you want to add some custom html to the page. + * + * @throws IOException + */ + protected void writeBootstrapPageHtmlBodyStart(BootstrapContext context) + throws IOException { + Writer page = context.getWriter(); + page.write("\n</head>\n<body scroll=\"auto\" class=\"" + + ApplicationConnection.GENERATED_BODY_CLASSNAME + "\">\n"); + } + + /** + * Method to write the script part of the page which loads needed Vaadin + * scripts and themes. + * <p> + * Override this method if you want to add some custom html around scripts. + * + * @param context + * + * @throws IOException + * @throws JSONException + */ + protected void writeBootstrapPageHtmlVaadinScripts(BootstrapContext context) + throws IOException, JSONException { + WrappedRequest request = context.getRequest(); + Writer page = context.getWriter(); + + DeploymentConfiguration deploymentConfiguration = request + .getDeploymentConfiguration(); + String staticFileLocation = deploymentConfiguration + .getStaticFileLocation(request); + + page.write("<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" " + + "style=\"position:absolute;width:0;height:0;border:0;overflow:" + + "hidden;\" src=\"javascript:false\"></iframe>"); + + String bootstrapLocation = staticFileLocation + + "/VAADIN/vaadinBootstrap.js"; + page.write("<script type=\"text/javascript\" src=\""); + page.write(bootstrapLocation); + page.write("\"></script>\n"); + + page.write("<script type=\"text/javascript\">\n"); + page.write("//<![CDATA[\n"); + page.write("if (!window.vaadin) alert(" + + JSONObject.quote("Failed to load the bootstrap javascript: " + + bootstrapLocation) + ");\n"); + + writeMainScriptTagContents(context); + page.write("//]]>\n</script>\n"); + } + + protected void writeMainScriptTagContents(BootstrapContext context) + throws JSONException, IOException { + JSONObject defaults = getDefaultParameters(context); + JSONObject appConfig = getApplicationParameters(context); + + boolean isDebug = !context.getApplication().isProductionMode(); + Writer page = context.getWriter(); + + page.write("vaadin.setDefaults("); + printJsonObject(page, defaults, isDebug); + page.write(");\n"); + + page.write("vaadin.initApplication(\""); + page.write(context.getAppId()); + page.write("\","); + printJsonObject(page, appConfig, isDebug); + page.write(");\n"); + } + + private static void printJsonObject(Writer page, JSONObject jsonObject, + boolean isDebug) throws IOException, JSONException { + if (isDebug) { + page.write(jsonObject.toString(4)); + } else { + page.write(jsonObject.toString()); + } + } + + protected JSONObject getApplicationParameters(BootstrapContext context) + throws JSONException, PaintException { + Application application = context.getApplication(); + Integer rootId = context.getRootId(); + + JSONObject appConfig = new JSONObject(); + + if (rootId != null) { + appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId); + } + + if (context.getThemeName() != null) { + appConfig.put("themeUri", + getThemeUri(context, context.getThemeName())); + } + + JSONObject versionInfo = new JSONObject(); + versionInfo.put("vaadinVersion", AbstractApplicationServlet.VERSION); + versionInfo.put("applicationVersion", application.getVersion()); + appConfig.put("versionInfo", versionInfo); + + appConfig.put("widgetset", context.getWidgetsetName()); + + if (rootId == null || application.isRootInitPending(rootId.intValue())) { + appConfig.put("initialPath", context.getRequest() + .getRequestPathInfo()); + + Map<String, String[]> parameterMap = context.getRequest() + .getParameterMap(); + appConfig.put("initialParams", parameterMap); + } else { + // write the initial UIDL into the config + appConfig.put("uidl", + getInitialUIDL(context.getRequest(), context.getRoot())); + } + + return appConfig; + } + + protected JSONObject getDefaultParameters(BootstrapContext context) + throws JSONException { + JSONObject defaults = new JSONObject(); + + WrappedRequest request = context.getRequest(); + Application application = context.getApplication(); + + // Get system messages + Application.SystemMessages systemMessages = AbstractApplicationServlet + .getSystemMessages(application.getClass()); + if (systemMessages != null) { + // Write the CommunicationError -message to client + JSONObject comErrMsg = new JSONObject(); + comErrMsg.put("caption", + systemMessages.getCommunicationErrorCaption()); + comErrMsg.put("message", + systemMessages.getCommunicationErrorMessage()); + comErrMsg.put("url", systemMessages.getCommunicationErrorURL()); + + defaults.put("comErrMsg", comErrMsg); + + JSONObject authErrMsg = new JSONObject(); + authErrMsg.put("caption", + systemMessages.getAuthenticationErrorCaption()); + authErrMsg.put("message", + systemMessages.getAuthenticationErrorMessage()); + authErrMsg.put("url", systemMessages.getAuthenticationErrorURL()); + + defaults.put("authErrMsg", authErrMsg); + } + + DeploymentConfiguration deploymentConfiguration = request + .getDeploymentConfiguration(); + String staticFileLocation = deploymentConfiguration + .getStaticFileLocation(request); + String widgetsetBase = staticFileLocation + "/" + + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH; + defaults.put("widgetsetBase", widgetsetBase); + + if (!application.isProductionMode()) { + defaults.put("debug", true); + } + + if (deploymentConfiguration.isStandalone(request)) { + defaults.put("standalone", true); + } + + defaults.put("appUri", getAppUri(context)); + + return defaults; + } + + protected abstract String getAppUri(BootstrapContext context); + + /** + * Method to write the contents of head element in html kickstart page. + * <p> + * Override this method if you want to add some custom html to the header of + * the page. + * + * @throws IOException + */ + protected void writeBootstrapPageHtmlHeader(BootstrapContext context) + throws IOException { + Writer page = context.getWriter(); + String themeName = context.getThemeName(); + + page.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"); + + // Chrome frame in all versions of IE (only if Chrome frame is + // installed) + page.write("<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\"/>\n"); + + page.write("<style type=\"text/css\">" + + "html, body {height:100%;margin:0;}</style>"); + + // Add favicon links + if (themeName != null) { + String themeUri = getThemeUri(context, themeName); + page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\"" + + themeUri + "/favicon.ico\" />"); + page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\"" + + themeUri + "/favicon.ico\" />"); + } + + Root root = context.getRoot(); + String title = ((root == null || root.getCaption() == null) ? "Vaadin " + + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption()); + + page.write("<title>" + + AbstractApplicationServlet.safeEscapeForHtml(title) + + "</title>"); + } + + /** + * Method to set http request headers for the Vaadin kickstart page. + * <p> + * Override this method if you need to customize http headers of the page. + * + * @param context + */ + protected void setBootstrapPageHeaders(BootstrapContext context) { + WrappedResponse response = context.getResponse(); + + // Window renders are not cacheable + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Pragma", "no-cache"); + response.setDateHeader("Expires", 0); + response.setContentType("text/html; charset=UTF-8"); + } + + /** + * Method to write the beginning of the html page. + * <p> + * This method is responsible for writing appropriate doc type declarations + * and to open html and head tags. + * <p> + * Override this method if you want to add some custom html to the very + * beginning of the page. + * + * @param context + * @throws IOException + */ + protected void writeBootstrapPageHtmlHeadStart(BootstrapContext context) + throws IOException { + Writer page = context.getWriter(); + + // write html header + page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD " + + "XHTML 1.0 Transitional//EN\" " + + "\"http://www.w3.org/TR/xhtml1/" + + "DTD/xhtml1-transitional.dtd\">\n"); + + page.write("<html xmlns=\"http://www.w3.org/1999/xhtml\"" + + ">\n<head>\n"); + } + + /** + * Get the URI for the application theme. + * + * A portal-wide default theme is fetched from the portal shared resource + * directory (if any), other themes from the portlet. + * + * @param context + * @param themeName + * + * @return + */ + public String getThemeUri(BootstrapContext context, String themeName) { + WrappedRequest request = context.getRequest(); + final String staticFilePath = request.getDeploymentConfiguration() + .getStaticFileLocation(request); + return staticFilePath + "/" + + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName; + } + + /** + * Override if required + * + * @param context + * @return + */ + public String getThemeName(BootstrapContext context) { + return context.getApplication().getThemeForRoot(context.getRoot()); + } + + /** + * Don not override. + * + * @param context + * @return + */ + public String findAndEscapeThemeName(BootstrapContext context) { + String themeName = getThemeName(context); + if (themeName == null) { + WrappedRequest request = context.getRequest(); + themeName = request.getDeploymentConfiguration() + .getConfiguredTheme(request); + } + + // XSS preventation, theme names shouldn't contain special chars anyway. + // The servlet denies them via url parameter. + themeName = AbstractApplicationServlet.stripSpecialChars(themeName); + + return themeName; + } + + protected void writeError(WrappedResponse response, Throwable e) + throws IOException { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + e.getLocalizedMessage()); + } + + /** + * Gets the initial UIDL message to send to the client. + * + * @param request + * the originating request + * @param root + * the root for which the UIDL should be generated + * @return a string with the initial UIDL message + * @throws PaintException + * if an exception occurs while painting the components + */ + protected abstract String getInitialUIDL(WrappedRequest request, Root root) + throws PaintException; + +} diff --git a/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/src/com/vaadin/terminal/gwt/server/ClientConnector.java new file mode 100644 index 0000000000..7a1f0fad68 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ClientConnector.java @@ -0,0 +1,38 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.server; + +import java.util.List; + +import com.vaadin.terminal.gwt.client.Connector; + +/** + * Interface implemented by all connectors that are capable of communicating + * with the client side + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public interface ClientConnector extends Connector, RpcTarget { + /** + * Returns the list of pending server to client RPC calls and clears the + * list. + * + * @return an unmodifiable ordered list of pending server to client method + * calls (not null) + * + * @since 7.0 + */ + public List<ClientMethodInvocation> retrievePendingRpcCalls(); + + /** + * Checks if the communicator is enabled. An enabled communicator is allowed + * to receive messages from its counter-part. + * + * @return true if the connector can receive messages, false otherwise + */ + public boolean isConnectorEnabled(); +} diff --git a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java new file mode 100644 index 0000000000..99633a13d6 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java @@ -0,0 +1,69 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.Serializable; +import java.lang.reflect.Method; + +/** + * Internal class for keeping track of pending server to client method + * invocations for a Connector. + * + * @since 7.0 + */ +public class ClientMethodInvocation implements Serializable, + Comparable<ClientMethodInvocation> { + private final ClientConnector connector; + private final String interfaceName; + private final String methodName; + private final Object[] parameters; + private Class<?>[] parameterTypes; + + // used for sorting calls between different connectors in the same Root + private final long sequenceNumber; + // TODO may cause problems when clustering etc. + private static long counter = 0; + + public ClientMethodInvocation(ClientConnector connector, + String interfaceName, Method method, Object[] parameters) { + this.connector = connector; + this.interfaceName = interfaceName; + methodName = method.getName(); + parameterTypes = method.getParameterTypes(); + this.parameters = (null != parameters) ? parameters : new Object[0]; + sequenceNumber = ++counter; + } + + public Class<?>[] getParameterTypes() { + return parameterTypes; + } + + public ClientConnector getConnector() { + return connector; + } + + public String getInterfaceName() { + return interfaceName; + } + + public String getMethodName() { + return methodName; + } + + public Object[] getParameters() { + return parameters; + } + + protected long getSequenceNumber() { + return sequenceNumber; + } + + public int compareTo(ClientMethodInvocation o) { + if (null == o) { + return 0; + } + return Long.signum(getSequenceNumber() - o.getSequenceNumber()); + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java index 9c67a03bb3..3dd2eb97fd 100644 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java @@ -6,24 +6,21 @@ package com.vaadin.terminal.gwt.server; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; +import java.net.URL; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.UUID; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import javax.servlet.ServletContext; import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.Paintable; +import com.vaadin.terminal.PaintException; import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.ui.Component; -import com.vaadin.ui.Window; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.ui.Root; /** * Application manager processes changes and paints for single application @@ -42,150 +39,6 @@ import com.vaadin.ui.Window; public class CommunicationManager extends AbstractCommunicationManager { /** - * Concrete wrapper class for {@link HttpServletRequest}. - * - * @see Request - */ - private static class HttpServletRequestWrapper implements Request { - - private final HttpServletRequest request; - - public HttpServletRequestWrapper(HttpServletRequest request) { - this.request = request; - } - - public Object getAttribute(String name) { - return request.getAttribute(name); - } - - public int getContentLength() { - return request.getContentLength(); - } - - public InputStream getInputStream() throws IOException { - return request.getInputStream(); - } - - public String getParameter(String name) { - return request.getParameter(name); - } - - public String getRequestID() { - return "RequestURL:" + request.getRequestURI(); - } - - public Session getSession() { - return new HttpSessionWrapper(request.getSession()); - } - - public Object getWrappedRequest() { - return request; - } - - public boolean isRunningInPortlet() { - return false; - } - - public void setAttribute(String name, Object o) { - request.setAttribute(name, o); - } - } - - /** - * Concrete wrapper class for {@link HttpServletResponse}. - * - * @see Response - */ - private static class HttpServletResponseWrapper implements Response { - - private final HttpServletResponse response; - - public HttpServletResponseWrapper(HttpServletResponse response) { - this.response = response; - } - - public OutputStream getOutputStream() throws IOException { - return response.getOutputStream(); - } - - public Object getWrappedResponse() { - return response; - } - - public void setContentType(String type) { - response.setContentType(type); - } - - } - - /** - * Concrete wrapper class for {@link HttpSession}. - * - * @see Session - */ - private static class HttpSessionWrapper implements Session { - - private final HttpSession session; - - public HttpSessionWrapper(HttpSession session) { - this.session = session; - } - - public Object getAttribute(String name) { - return session.getAttribute(name); - } - - public int getMaxInactiveInterval() { - return session.getMaxInactiveInterval(); - } - - public Object getWrappedSession() { - return session; - } - - public boolean isNew() { - return session.isNew(); - } - - public void setAttribute(String name, Object o) { - session.setAttribute(name, o); - } - - } - - private static class AbstractApplicationServletWrapper implements Callback { - - private final AbstractApplicationServlet servlet; - - public AbstractApplicationServletWrapper( - AbstractApplicationServlet servlet) { - this.servlet = servlet; - } - - public void criticalNotification(Request request, Response response, - String cap, String msg, String details, String outOfSyncURL) - throws IOException { - servlet.criticalNotification( - (HttpServletRequest) request.getWrappedRequest(), - (HttpServletResponse) response.getWrappedResponse(), cap, - msg, details, outOfSyncURL); - } - - public String getRequestPathInfo(Request request) { - return servlet.getRequestPathInfo((HttpServletRequest) request - .getWrappedRequest()); - } - - public InputStream getThemeResourceAsStream(String themeName, - String resource) throws IOException { - return servlet.getServletContext().getResourceAsStream( - "/" + AbstractApplicationServlet.THEME_DIRECTORY_PATH - + themeName + "/" + resource); - } - - } - - /** * @deprecated use {@link #CommunicationManager(Application)} instead * @param application * @param applicationServlet @@ -208,6 +61,8 @@ public class CommunicationManager extends AbstractCommunicationManager { /** * Handles file upload request submitted via Upload component. * + * @param application + * * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable) * * @param request @@ -215,15 +70,15 @@ public class CommunicationManager extends AbstractCommunicationManager { * @throws IOException * @throws InvalidUIDLSecurityKeyException */ - public void handleFileUpload(HttpServletRequest request, - HttpServletResponse response) throws IOException, - InvalidUIDLSecurityKeyException { + public void handleFileUpload(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException, InvalidUIDLSecurityKeyException { /* * URI pattern: APP/UPLOAD/[PID]/[NAME]/[SECKEY] See #createReceiverUrl */ - String pathInfo = request.getPathInfo(); + String pathInfo = request.getRequestPathInfo(); // strip away part until the data we are interested starts int startOfData = pathInfo .indexOf(AbstractApplicationServlet.UPLOAD_URL_PREFIX) @@ -238,22 +93,18 @@ public class CommunicationManager extends AbstractCommunicationManager { String secKey = streamVariableToSeckey.get(streamVariable); if (secKey.equals(parts[2])) { - VariableOwner source = getVariableOwner(paintableId); + Connector source = getConnector(application, paintableId); String contentType = request.getContentType(); - if (request.getContentType().contains("boundary")) { + if (contentType.contains("boundary")) { // Multipart requests contain boundary string - doHandleSimpleMultipartFileUpload( - new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), + doHandleSimpleMultipartFileUpload(request, response, streamVariable, variableName, source, contentType.split("boundary=")[1]); } else { // if boundary string does not exist, the posted file is from // XHR2.post(File) - doHandleXhrFilePost(new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), - streamVariable, variableName, source, - request.getContentLength()); + doHandleXhrFilePost(request, response, streamVariable, + variableName, source, request.getContentLength()); } } else { throw new InvalidUIDLSecurityKeyException( @@ -262,95 +113,27 @@ public class CommunicationManager extends AbstractCommunicationManager { } - /** - * Handles UIDL request - * - * TODO document - * - * @param request - * @param response - * @param applicationServlet - * @param window - * target window of the UIDL request, can be null if window not - * found - * @throws IOException - * @throws ServletException - */ - public void handleUidlRequest(HttpServletRequest request, - HttpServletResponse response, - AbstractApplicationServlet applicationServlet, Window window) - throws IOException, ServletException, - InvalidUIDLSecurityKeyException { - doHandleUidlRequest(new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), - new AbstractApplicationServletWrapper(applicationServlet), - window); - } - - /** - * Gets the existing application or creates a new one. Get a window within - * an application based on the requested URI. - * - * @param request - * the HTTP Request. - * @param application - * the Application to query for window. - * @param assumedWindow - * if the window has been already resolved once, this parameter - * must contain the window. - * @return Window matching the given URI or null if not found. - * @throws ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - Window getApplicationWindow(HttpServletRequest request, - AbstractApplicationServlet applicationServlet, - Application application, Window assumedWindow) - throws ServletException { - return doGetApplicationWindow(new HttpServletRequestWrapper(request), - new AbstractApplicationServletWrapper(applicationServlet), - application, assumedWindow); - } - - /** - * Calls the Window URI handler for a request and returns the - * {@link DownloadStream} returned by the handler. - * - * If the window is the main window of an application, the deprecated - * {@link Application#handleURI(java.net.URL, String)} is called first to - * handle {@link ApplicationResource}s and the window handler is only called - * if it returns null. - * - * @see AbstractCommunicationManager#handleURI(Window, Request, Response, - * Callback) - * - * @param window - * @param request - * @param response - * @param applicationServlet - * @return - */ - DownloadStream handleURI(Window window, HttpServletRequest request, - HttpServletResponse response, - AbstractApplicationServlet applicationServlet) { - return handleURI(window, new HttpServletRequestWrapper(request), - new HttpServletResponseWrapper(response), - new AbstractApplicationServletWrapper(applicationServlet)); - } - @Override - protected void unregisterPaintable(Component p) { - /* Cleanup possible receivers */ + protected void postPaint(Root root) { + super.postPaint(root); + + Application application = root.getApplication(); if (pidToNameToStreamVariable != null) { - Map<String, StreamVariable> removed = pidToNameToStreamVariable - .remove(getPaintableId(p)); - if (removed != null) { - for (String key : removed.keySet()) { - streamVariableToSeckey.remove(removed.get(key)); + Iterator<String> iterator = pidToNameToStreamVariable.keySet() + .iterator(); + while (iterator.hasNext()) { + String connectorId = iterator.next(); + if (application.getConnector(connectorId) == null) { + // Owner is no longer attached to the application + Map<String, StreamVariable> removed = pidToNameToStreamVariable + .get(connectorId); + for (String key : removed.keySet()) { + streamVariableToSeckey.remove(removed.get(key)); + } + iterator.remove(); } } } - super.unregisterPaintable(p); } @@ -359,7 +142,7 @@ public class CommunicationManager extends AbstractCommunicationManager { private Map<StreamVariable, String> streamVariableToSeckey; @Override - String getStreamVariableTargetUrl(VariableOwner owner, String name, + String getStreamVariableTargetUrl(Connector owner, String name, StreamVariable value) { /* * We will use the same APP/* URI space as ApplicationResources but @@ -373,7 +156,7 @@ public class CommunicationManager extends AbstractCommunicationManager { * NAME and PID from URI forms a key to fetch StreamVariable when * handling post */ - String paintableId = getPaintableId((Paintable) owner); + String paintableId = owner.getConnectorId(); String key = paintableId + "/" + name; if (pidToNameToStreamVariable == null) { @@ -402,13 +185,81 @@ public class CommunicationManager extends AbstractCommunicationManager { } @Override - protected void cleanStreamVariable(VariableOwner owner, String name) { + protected void cleanStreamVariable(Connector owner, String name) { Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable - .get(getPaintableId((Paintable) owner)); + .get(owner.getConnectorId()); nameToStreamVar.remove("name"); if (nameToStreamVar.isEmpty()) { - pidToNameToStreamVariable.remove(getPaintableId((Paintable) owner)); + pidToNameToStreamVariable.remove(owner.getConnectorId()); } } + @Override + protected BootstrapHandler createBootstrapHandler() { + return new BootstrapHandler() { + @Override + protected String getApplicationId(BootstrapContext context) { + String appUrl = getAppUri(context); + + String appId = appUrl; + if ("".equals(appUrl)) { + appId = "ROOT"; + } + appId = appId.replaceAll("[^a-zA-Z0-9]", ""); + // Add hashCode to the end, so that it is still (sort of) + // predictable, but indicates that it should not be used in CSS + // and + // such: + int hashCode = appId.hashCode(); + if (hashCode < 0) { + hashCode = -hashCode; + } + appId = appId + "-" + hashCode; + return appId; + } + + @Override + protected String getAppUri(BootstrapContext context) { + /* Fetch relative url to application */ + // don't use server and port in uri. It may cause problems with + // some + // virtual server configurations which lose the server name + Application application = context.getApplication(); + URL url = application.getURL(); + String appUrl = url.getPath(); + if (appUrl.endsWith("/")) { + appUrl = appUrl.substring(0, appUrl.length() - 1); + } + return appUrl; + } + + @Override + public String getThemeName(BootstrapContext context) { + String themeName = context.getRequest().getParameter( + AbstractApplicationServlet.URL_PARAMETER_THEME); + if (themeName == null) { + themeName = super.getThemeName(context); + } + return themeName; + } + + @Override + protected String getInitialUIDL(WrappedRequest request, Root root) + throws PaintException { + return CommunicationManager.this.getInitialUIDL(request, root); + } + }; + } + + @Override + protected InputStream getThemeResourceAsStream(Root root, String themeName, + String resource) { + WebApplicationContext context = (WebApplicationContext) root + .getApplication().getContext(); + ServletContext servletContext = context.getHttpSession() + .getServletContext(); + return servletContext.getResourceAsStream("/" + + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName + + "/" + resource); + } } diff --git a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java b/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java index 7889968e63..335067ca7a 100644 --- a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java +++ b/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java @@ -16,8 +16,9 @@ import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; -import com.vaadin.terminal.Sizeable; +import com.vaadin.terminal.Sizeable.Unit; import com.vaadin.ui.AbstractOrderedLayout; +import com.vaadin.ui.AbstractSplitPanel; import com.vaadin.ui.Component; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.CustomComponent; @@ -25,9 +26,7 @@ import com.vaadin.ui.Form; import com.vaadin.ui.GridLayout; import com.vaadin.ui.GridLayout.Area; import com.vaadin.ui.Layout; -import com.vaadin.ui.OrderedLayout; import com.vaadin.ui.Panel; -import com.vaadin.ui.SplitPanel; import com.vaadin.ui.TabSheet; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; @@ -186,7 +185,7 @@ public class ComponentSizeValidator implements Serializable { clientJSON.write("{"); Component parent = component.getParent(); - String paintableId = communicationManager.getPaintableId(component); + String paintableId = component.getConnectorId(); clientJSON.print("id:\"" + paintableId + "\""); @@ -198,11 +197,7 @@ public class ComponentSizeValidator implements Serializable { AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; boolean vertical = false; - if (ol instanceof OrderedLayout) { - if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) { - vertical = true; - } - } else if (ol instanceof VerticalLayout) { + if (ol instanceof VerticalLayout) { vertical = true; } @@ -231,11 +226,7 @@ public class ComponentSizeValidator implements Serializable { AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; boolean horizontal = true; - if (ol instanceof OrderedLayout) { - if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) { - horizontal = false; - } - } else if (ol instanceof VerticalLayout) { + if (ol instanceof VerticalLayout) { horizontal = false; } @@ -323,7 +314,7 @@ public class ComponentSizeValidator implements Serializable { width += "MAIN WINDOW"; } else if (component.getWidth() >= 0) { width += "ABSOLUTE, " + component.getWidth() + " " - + Sizeable.UNIT_SYMBOLS[component.getWidthUnits()]; + + component.getWidthUnits().getSymbol(); } else { width += "UNDEFINED"; } @@ -339,7 +330,7 @@ public class ComponentSizeValidator implements Serializable { height += "MAIN WINDOW"; } else if (component.getHeight() > 0) { height += "ABSOLUTE, " + component.getHeight() + " " - + Sizeable.UNIT_SYMBOLS[component.getHeightUnits()]; + + component.getHeightUnits().getSymbol(); } else { height += "UNDEFINED"; } @@ -417,18 +408,13 @@ public class ComponentSizeValidator implements Serializable { if (parent.getHeight() < 0) { // Undefined height if (parent instanceof Window) { - Window w = (Window) parent; - if (w.getParent() == null) { - // main window is considered to have size - return true; - } + // Sub window with undefined size has a min-height + return true; } if (parent instanceof AbstractOrderedLayout) { boolean horizontal = true; - if (parent instanceof OrderedLayout) { - horizontal = ((OrderedLayout) parent).getOrientation() == OrderedLayout.ORIENTATION_HORIZONTAL; - } else if (parent instanceof VerticalLayout) { + if (parent instanceof VerticalLayout) { horizontal = false; } if (horizontal @@ -460,7 +446,7 @@ public class ComponentSizeValidator implements Serializable { } } - if (parent instanceof Panel || parent instanceof SplitPanel + if (parent instanceof Panel || parent instanceof AbstractSplitPanel || parent instanceof TabSheet || parent instanceof CustomComponent) { // height undefined, we know how how component works and no @@ -488,7 +474,7 @@ public class ComponentSizeValidator implements Serializable { } private static boolean hasRelativeHeight(Component component) { - return (component.getHeightUnits() == Sizeable.UNITS_PERCENTAGE && component + return (component.getHeightUnits() == Unit.PERCENTAGE && component .getHeight() > 0); } @@ -504,7 +490,7 @@ public class ComponentSizeValidator implements Serializable { private static boolean hasRelativeWidth(Component paintable) { return paintable.getWidth() > 0 - && paintable.getWidthUnits() == Sizeable.UNITS_PERCENTAGE; + && paintable.getWidthUnits() == Unit.PERCENTAGE; } public static boolean parentCanDefineWidth(Component component) { @@ -514,12 +500,8 @@ public class ComponentSizeValidator implements Serializable { return true; } if (parent instanceof Window) { - Window w = (Window) parent; - if (w.getParent() == null) { - // main window is considered to have size - return true; - } - + // Sub window with undefined size has a min-width + return true; } if (parent.getWidth() < 0) { @@ -528,11 +510,7 @@ public class ComponentSizeValidator implements Serializable { if (parent instanceof AbstractOrderedLayout) { AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; boolean horizontal = true; - if (ol instanceof OrderedLayout) { - if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) { - horizontal = false; - } - } else if (ol instanceof VerticalLayout) { + if (ol instanceof VerticalLayout) { horizontal = false; } @@ -567,7 +545,7 @@ public class ComponentSizeValidator implements Serializable { * the component width */ return hasNonRelativeWidthComponent((Form) parent); - } else if (parent instanceof SplitPanel + } else if (parent instanceof AbstractSplitPanel || parent instanceof TabSheet || parent instanceof CustomComponent) { // FIXME Could we use com.vaadin package name here and diff --git a/src/com/vaadin/terminal/gwt/server/Constants.java b/src/com/vaadin/terminal/gwt/server/Constants.java index e243bd7dae..7c467aa7f4 100644 --- a/src/com/vaadin/terminal/gwt/server/Constants.java +++ b/src/com/vaadin/terminal/gwt/server/Constants.java @@ -43,7 +43,6 @@ public interface Constants { static final String URL_PARAMETER_REPAINT_ALL = "repaintAll"; static final String URL_PARAMETER_THEME = "theme"; - static final String SERVLET_PARAMETER_DEBUG = "Debug"; static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode"; static final String SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION = "disable-xsrf-protection"; static final String SERVLET_PARAMETER_RESOURCE_CACHE_TIME = "resourceCacheTime"; diff --git a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java index 3a923c1840..d3fe5a890b 100644 --- a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java +++ b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java @@ -4,6 +4,7 @@ package com.vaadin.terminal.gwt.server; import java.io.PrintWriter; +import java.util.List; import java.util.Map; import java.util.logging.Logger; @@ -18,10 +19,12 @@ import com.vaadin.event.dd.TargetDetailsImpl; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.VariableOwner; +import com.vaadin.terminal.gwt.client.communication.SharedState; +import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager.DragEventType; import com.vaadin.ui.Component; -public class DragAndDropService implements VariableOwner { +public class DragAndDropService implements VariableOwner, ClientConnector { private static final Logger logger = Logger .getLogger(DragAndDropService.class.getName()); @@ -177,7 +180,7 @@ public class DragAndDropService implements VariableOwner { } public boolean isEnabled() { - return true; + return isConnectorEnabled(); } public boolean isImmediate() { @@ -212,4 +215,27 @@ public class DragAndDropService implements VariableOwner { } return false; } + + public SharedState getState() { + // TODO Auto-generated method stub + return null; + } + + public String getConnectorId() { + return VDragAndDropManager.DD_SERVICE; + } + + public boolean isConnectorEnabled() { + // Drag'n'drop can't be disabled + return true; + } + + public List<ClientMethodInvocation> retrievePendingRpcCalls() { + return null; + } + + public RpcManager getRpcManager(Class<?> rpcInterface) { + // TODO Use rpc for drag'n'drop + return null; + } } diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java new file mode 100644 index 0000000000..375cce4161 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -0,0 +1,587 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.vaadin.Application; +import com.vaadin.external.json.JSONArray; +import com.vaadin.external.json.JSONException; +import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.communication.JsonEncoder; +import com.vaadin.ui.Component; + +/** + * Decoder for converting RPC parameters and other values from JSON in transfer + * between the client and the server and vice versa. + * + * @since 7.0 + */ +public class JsonCodec implements Serializable { + + private static Map<Class<?>, String> typeToTransportType = new HashMap<Class<?>, String>(); + + /** + * Note! This does not contain primitives. + * <p> + */ + private static Map<String, Class<?>> transportTypeToType = new HashMap<String, Class<?>>(); + + static { + registerType(String.class, JsonEncoder.VTYPE_STRING); + registerType(Connector.class, JsonEncoder.VTYPE_CONNECTOR); + registerType(Boolean.class, JsonEncoder.VTYPE_BOOLEAN); + registerType(boolean.class, JsonEncoder.VTYPE_BOOLEAN); + registerType(Integer.class, JsonEncoder.VTYPE_INTEGER); + registerType(int.class, JsonEncoder.VTYPE_INTEGER); + registerType(Float.class, JsonEncoder.VTYPE_FLOAT); + registerType(float.class, JsonEncoder.VTYPE_FLOAT); + registerType(Double.class, JsonEncoder.VTYPE_DOUBLE); + registerType(double.class, JsonEncoder.VTYPE_DOUBLE); + registerType(Long.class, JsonEncoder.VTYPE_LONG); + registerType(long.class, JsonEncoder.VTYPE_LONG); + registerType(String[].class, JsonEncoder.VTYPE_STRINGARRAY); + registerType(Object[].class, JsonEncoder.VTYPE_ARRAY); + registerType(Map.class, JsonEncoder.VTYPE_MAP); + registerType(List.class, JsonEncoder.VTYPE_LIST); + registerType(Set.class, JsonEncoder.VTYPE_SET); + } + + private static void registerType(Class<?> type, String transportType) { + typeToTransportType.put(type, transportType); + if (!type.isPrimitive()) { + transportTypeToType.put(transportType, type); + } + } + + public static boolean isInternalTransportType(String transportType) { + return transportTypeToType.containsKey(transportType); + } + + public static boolean isInternalType(Type type) { + if (type instanceof Class && ((Class<?>) type).isPrimitive()) { + // All primitive types are handled internally + return true; + } + return typeToTransportType.containsKey(getClassForType(type)); + } + + private static Class<?> getClassForType(Type type) { + if (type instanceof ParameterizedType) { + return (Class<?>) (((ParameterizedType) type).getRawType()); + } else { + return (Class<?>) type; + } + } + + public static String getTransportType(JSONArray encodedValue) + throws JSONException { + return encodedValue.getString(0); + } + + private static Class<?> getType(String transportType) { + return transportTypeToType.get(transportType); + } + + /** + * Decodes the given value and type, restricted to using only internal + * types. + * + * @param valueAndType + * @param application + * @throws JSONException + */ + @Deprecated + public static Object decodeInternalType(JSONArray valueAndType, + Application application) throws JSONException { + String transportType = getTransportType(valueAndType); + return decodeInternalType(getType(transportType), true, valueAndType, + application); + } + + public static Object decodeInternalOrCustomType(Type targetType, + JSONArray valueAndType, Application application) + throws JSONException { + if (isInternalType(targetType)) { + return decodeInternalType(targetType, false, valueAndType, + application); + } else { + return decodeCustomType(targetType, valueAndType, application); + } + } + + public static Object decodeCustomType(Type targetType, + JSONArray valueAndType, Application application) + throws JSONException { + if (isInternalType(targetType)) { + throw new JSONException("decodeCustomType cannot be used for " + + targetType + ", which is an internal type"); + } + String transportType = getCustomTransportType(getClassForType(targetType)); + String encodedTransportType = valueAndType.getString(0); + if (!transportTypesCompatible(encodedTransportType, transportType)) { + throw new JSONException("Expected a value of type " + transportType + + ", received " + encodedTransportType); + } + + // Try to decode object using fields + return decodeObject(targetType, (JSONObject) valueAndType.get(1), + application); + } + + /** + * Decodes a value that is of an internal type. + * <p> + * Ensures the encoded value is of the same type as target type. + * </p> + * <p> + * Allows restricting collections so that they must be declared using + * generics. If this is used then all objects in the collection are encoded + * using the declared type. Otherwise only internal types are allowed in + * collections. + * </p> + * + * @param targetType + * The type that should be returned by this method + * @param valueAndType + * The encoded value and type array + * @param application + * A reference to the application + * @param enforceGenericsInCollections + * true if generics should be enforce, false to only allow + * internal types in collections + * @return + * @throws JSONException + */ + public static Object decodeInternalType(Type targetType, + boolean restrictToInternalTypes, JSONArray valueAndType, + Application application) throws JSONException { + String encodedTransportType = valueAndType.getString(0); + if (!isInternalType(targetType)) { + throw new JSONException("Type " + targetType + + " is not a supported internal type."); + } + String transportType = getInternalTransportType(targetType); + if (!transportTypesCompatible(encodedTransportType, transportType)) { + throw new JSONException("Expected a value of type " + targetType + + ", received " + getType(encodedTransportType)); + } + + Object encodedJsonValue = valueAndType.get(1); + + if (JsonEncoder.VTYPE_NULL.equals(encodedTransportType)) { + return null; + } + // Collections + if (JsonEncoder.VTYPE_LIST.equals(transportType)) { + return decodeList(targetType, restrictToInternalTypes, + (JSONArray) encodedJsonValue, application); + } else if (JsonEncoder.VTYPE_SET.equals(transportType)) { + return decodeSet(targetType, restrictToInternalTypes, + (JSONArray) encodedJsonValue, application); + } else if (JsonEncoder.VTYPE_MAP_CONNECTOR.equals(transportType)) { + return decodeConnectorToObjectMap(targetType, + restrictToInternalTypes, (JSONObject) encodedJsonValue, + application); + } else if (JsonEncoder.VTYPE_MAP.equals(transportType)) { + return decodeStringToObjectMap(targetType, restrictToInternalTypes, + (JSONObject) encodedJsonValue, application); + } + + // Arrays + if (JsonEncoder.VTYPE_ARRAY.equals(transportType)) { + + return decodeObjectArray(targetType, (JSONArray) encodedJsonValue, + application); + + } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(transportType)) { + return decodeStringArray((JSONArray) encodedJsonValue); + } + + // Special Vaadin types + + String stringValue = String.valueOf(encodedJsonValue); + + if (JsonEncoder.VTYPE_CONNECTOR.equals(transportType)) { + return application.getConnector(stringValue); + } + + // Standard Java types + + if (JsonEncoder.VTYPE_STRING.equals(transportType)) { + return stringValue; + } else if (JsonEncoder.VTYPE_INTEGER.equals(transportType)) { + return Integer.valueOf(stringValue); + } else if (JsonEncoder.VTYPE_LONG.equals(transportType)) { + return Long.valueOf(stringValue); + } else if (JsonEncoder.VTYPE_FLOAT.equals(transportType)) { + return Float.valueOf(stringValue); + } else if (JsonEncoder.VTYPE_DOUBLE.equals(transportType)) { + return Double.valueOf(stringValue); + } else if (JsonEncoder.VTYPE_BOOLEAN.equals(transportType)) { + return Boolean.valueOf(stringValue); + } + + throw new JSONException("Unknown type " + transportType); + } + + private static boolean transportTypesCompatible( + String encodedTransportType, String transportType) { + if (encodedTransportType == null) { + return false; + } + if (encodedTransportType.equals(transportType)) { + return true; + } + if (encodedTransportType.equals(JsonEncoder.VTYPE_NULL)) { + return true; + } + + return false; + } + + @Deprecated + private static Map<String, Object> decodeStringToObjectMap(Type targetType, + boolean restrictToInternalTypes, JSONObject jsonMap, + Application application) throws JSONException { + HashMap<String, Object> map = new HashMap<String, Object>(); + Iterator<String> it = jsonMap.keys(); + while (it.hasNext()) { + String key = it.next(); + JSONArray encodedValueAndType = jsonMap.getJSONArray(key); + Object decodedChild = decodeChild(targetType, + restrictToInternalTypes, 1, encodedValueAndType, + application); + map.put(key, decodedChild); + } + return map; + } + + @Deprecated + private static Map<Connector, Object> decodeConnectorToObjectMap( + Type targetType, boolean restrictToInternalTypes, + JSONObject jsonMap, Application application) throws JSONException { + HashMap<Connector, Object> map = new HashMap<Connector, Object>(); + Iterator<String> it = jsonMap.keys(); + while (it.hasNext()) { + String connectorId = it.next(); + Connector connector = application.getConnector(connectorId); + JSONArray encodedValueAndType = jsonMap.getJSONArray(connectorId); + Object decodedChild = decodeChild(targetType, + restrictToInternalTypes, 1, encodedValueAndType, + application); + map.put(connector, decodedChild); + } + return map; + } + + /** + * @param targetType + * @param restrictToInternalTypes + * @param typeIndex + * The index of a generic type to use to define the child type + * that should be decoded + * @param encodedValueAndType + * @param application + * @return + * @throws JSONException + */ + private static Object decodeChild(Type targetType, + boolean restrictToInternalTypes, int typeIndex, + JSONArray encodedValueAndType, Application application) + throws JSONException { + if (!restrictToInternalTypes && targetType instanceof ParameterizedType) { + Type childType = ((ParameterizedType) targetType) + .getActualTypeArguments()[typeIndex]; + // Only decode the given type + return decodeInternalOrCustomType(childType, encodedValueAndType, + application); + } else { + // Only internal types when not enforcing a given type to avoid + // security issues + return decodeInternalType(encodedValueAndType, application); + } + } + + private static String[] decodeStringArray(JSONArray jsonArray) + throws JSONException { + int length = jsonArray.length(); + List<String> tokens = new ArrayList<String>(length); + for (int i = 0; i < length; ++i) { + tokens.add(jsonArray.getString(i)); + } + return tokens.toArray(new String[tokens.size()]); + } + + private static Object[] decodeObjectArray(Type targetType, + JSONArray jsonArray, Application application) throws JSONException { + List list = decodeList(List.class, true, jsonArray, application); + return list.toArray(new Object[list.size()]); + } + + private static List<Object> decodeList(Type targetType, + boolean restrictToInternalTypes, JSONArray jsonArray, + Application application) throws JSONException { + List<Object> list = new ArrayList<Object>(); + for (int i = 0; i < jsonArray.length(); ++i) { + // each entry always has two elements: type and value + JSONArray encodedValueAndType = jsonArray.getJSONArray(i); + Object decodedChild = decodeChild(targetType, + restrictToInternalTypes, 0, encodedValueAndType, + application); + list.add(decodedChild); + } + return list; + } + + private static Set<Object> decodeSet(Type targetType, + boolean restrictToInternalTypes, JSONArray jsonArray, + Application application) throws JSONException { + HashSet<Object> set = new HashSet<Object>(); + set.addAll(decodeList(List.class, restrictToInternalTypes, jsonArray, + application)); + return set; + } + + /** + * Returns the name that should be used as field name in the JSON. We strip + * "set" from the setter, keeping the result - this is easy to do on both + * server and client, avoiding some issues with cASE. E.g setZIndex() + * becomes "ZIndex". Also ensures that both getter and setter are present, + * returning null otherwise. + * + * @param pd + * @return the name to be used or null if both getter and setter are not + * found. + */ + private static String getTransportFieldName(PropertyDescriptor pd) { + if (pd.getReadMethod() == null || pd.getWriteMethod() == null) { + return null; + } + return pd.getWriteMethod().getName().substring(3); + } + + private static Object decodeObject(Type targetType, + JSONObject serializedObject, Application application) + throws JSONException { + + Class<?> targetClass = getClassForType(targetType); + try { + Object decodedObject = targetClass.newInstance(); + for (PropertyDescriptor pd : Introspector.getBeanInfo(targetClass) + .getPropertyDescriptors()) { + + String fieldName = getTransportFieldName(pd); + if (fieldName == null) { + continue; + } + JSONArray encodedFieldValue = serializedObject + .getJSONArray(fieldName); + Type fieldType = pd.getReadMethod().getGenericReturnType(); + Object decodedFieldValue = decodeInternalOrCustomType( + fieldType, encodedFieldValue, application); + + pd.getWriteMethod().invoke(decodedObject, decodedFieldValue); + } + + return decodedObject; + } catch (IllegalArgumentException e) { + throw new JSONException(e); + } catch (IllegalAccessException e) { + throw new JSONException(e); + } catch (InvocationTargetException e) { + throw new JSONException(e); + } catch (InstantiationException e) { + throw new JSONException(e); + } catch (IntrospectionException e) { + throw new JSONException(e); + } + } + + @Deprecated + private static JSONArray encode(Object value, Application application) + throws JSONException { + return encode(value, null, application); + } + + public static JSONArray encode(Object value, Class<?> valueType, + Application application) throws JSONException { + + if (null == value) { + return encodeNull(); + } + + if (valueType == null) { + valueType = value.getClass(); + } + + String internalTransportType = getInternalTransportType(valueType); + if (value instanceof String[]) { + String[] array = (String[]) value; + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < array.length; ++i) { + jsonArray.put(array[i]); + } + return combineTypeAndValue(JsonEncoder.VTYPE_STRINGARRAY, jsonArray); + } else if (value instanceof String) { + return combineTypeAndValue(JsonEncoder.VTYPE_STRING, value); + } else if (value instanceof Boolean) { + return combineTypeAndValue(JsonEncoder.VTYPE_BOOLEAN, value); + } else if (value instanceof Number) { + return combineTypeAndValue(internalTransportType, value); + } else if (value instanceof Collection) { + if (internalTransportType == null) { + throw new RuntimeException( + "Unable to serialize unsupported type: " + valueType); + } + Collection<?> collection = (Collection<?>) value; + JSONArray jsonArray = encodeCollection(collection, application); + + return combineTypeAndValue(internalTransportType, jsonArray); + } else if (value instanceof Object[]) { + Object[] array = (Object[]) value; + JSONArray jsonArray = encodeArrayContents(array, application); + return combineTypeAndValue(JsonEncoder.VTYPE_ARRAY, jsonArray); + } else if (value instanceof Map) { + Map<Object, Object> map = (Map<Object, Object>) value; + JSONObject jsonMap = encodeMapContents(map, application); + // Hack to support Connector as map key. Should be fixed by # + if (!map.isEmpty() + && map.keySet().iterator().next() instanceof Connector) { + return combineTypeAndValue(JsonEncoder.VTYPE_MAP_CONNECTOR, + jsonMap); + } else { + return combineTypeAndValue(JsonEncoder.VTYPE_MAP, jsonMap); + } + } else if (value instanceof Connector) { + Connector connector = (Connector) value; + if (value instanceof Component + && !(AbstractCommunicationManager + .isVisible((Component) value))) { + return encodeNull(); + } + return combineTypeAndValue(JsonEncoder.VTYPE_CONNECTOR, + connector.getConnectorId()); + } else if (internalTransportType != null) { + return combineTypeAndValue(internalTransportType, + String.valueOf(value)); + } else { + // Any object that we do not know how to encode we encode by looping + // through fields + return combineTypeAndValue(getCustomTransportType(valueType), + encodeObject(value, application)); + } + } + + private static JSONArray encodeNull() { + return combineTypeAndValue(JsonEncoder.VTYPE_NULL, JSONObject.NULL); + } + + private static Object encodeObject(Object value, Application application) + throws JSONException { + JSONObject jsonMap = new JSONObject(); + + try { + for (PropertyDescriptor pd : Introspector.getBeanInfo( + value.getClass()).getPropertyDescriptors()) { + Class<?> fieldType = pd.getPropertyType(); + String fieldName = getTransportFieldName(pd); + if (fieldName == null) { + continue; + } + Method getterMethod = pd.getReadMethod(); + Object fieldValue = getterMethod.invoke(value, (Object[]) null); + jsonMap.put(fieldName, + encode(fieldValue, fieldType, application)); + } + } catch (Exception e) { + // TODO: Should exceptions be handled in a different way? + throw new JSONException(e); + } + return jsonMap; + } + + private static JSONArray encodeArrayContents(Object[] array, + Application application) throws JSONException { + JSONArray jsonArray = new JSONArray(); + for (Object o : array) { + jsonArray.put(encode(o, null, application)); + } + return jsonArray; + } + + private static JSONArray encodeCollection(Collection collection, + Application application) throws JSONException { + JSONArray jsonArray = new JSONArray(); + for (Object o : collection) { + jsonArray.put(encode(o, application)); + } + return jsonArray; + } + + private static JSONObject encodeMapContents(Map<Object, Object> map, + Application application) throws JSONException { + JSONObject jsonMap = new JSONObject(); + for (Object mapKey : map.keySet()) { + Object mapValue = map.get(mapKey); + + if (mapKey instanceof ClientConnector) { + mapKey = ((ClientConnector) mapKey).getConnectorId(); + } + if (!(mapKey instanceof String)) { + throw new JSONException( + "Only maps with String/Connector keys are currently supported (#8602)"); + } + + jsonMap.put((String) mapKey, encode(mapValue, null, application)); + } + return jsonMap; + } + + private static JSONArray combineTypeAndValue(String type, Object value) { + if (type == null) { + throw new RuntimeException("Type for value " + value + + " cannot be null!"); + } + JSONArray outerArray = new JSONArray(); + outerArray.put(type); + outerArray.put(value); + return outerArray; + } + + /** + * Gets the transport type for the given class. Returns null if no transport + * type can be found. + * + * @param valueType + * The type that should be transported + * @return + * @throws JSONException + */ + private static String getInternalTransportType(Type valueType) { + return typeToTransportType.get(getClassForType(valueType)); + } + + private static String getCustomTransportType(Class<?> targetType) { + return targetType.getName(); + } + +} diff --git a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java index d6c53a2da6..0140c0f799 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java +++ b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java @@ -4,23 +4,15 @@ package com.vaadin.terminal.gwt.server; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Serializable; -import java.io.StringWriter; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.Vector; -import java.util.logging.Level; import java.util.logging.Logger; import com.vaadin.Application; @@ -28,14 +20,12 @@ import com.vaadin.terminal.ApplicationResource; import com.vaadin.terminal.ExternalResource; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Paintable; import com.vaadin.terminal.Resource; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.ThemeResource; import com.vaadin.terminal.VariableOwner; +import com.vaadin.terminal.gwt.client.Connector; import com.vaadin.ui.Alignment; -import com.vaadin.ui.ClientWidget; -import com.vaadin.ui.Component; import com.vaadin.ui.CustomLayout; /** @@ -63,6 +53,10 @@ public class JsonPaintTarget implements PaintTarget { private final Stack<JsonTag> openJsonTags; + // these match each other element-wise + private final Stack<ClientConnector> openPaintables; + private final Stack<String> openPaintableTags; + private final PrintWriter uidlBuffer; private boolean closed = false; @@ -77,20 +71,13 @@ public class JsonPaintTarget implements PaintTarget { private JsonTag tag; - private int errorsOpen; - private boolean cacheEnabled = false; - private final Collection<Paintable> paintedComponents = new HashSet<Paintable>(); - - private Collection<Paintable> identifiersCreatedDueRefPaint; - - private final Collection<Class<? extends Paintable>> usedPaintableTypes = new LinkedList<Class<? extends Paintable>>(); + private final Set<Class<? extends ClientConnector>> usedClientConnectors = new HashSet<Class<? extends ClientConnector>>(); /** - * Creates a new XMLPrintWriter, without automatic line flushing. + * Creates a new JsonPaintTarget. * - * @param variableMap * @param manager * @param outWriter * A character-output stream. @@ -112,6 +99,10 @@ public class JsonPaintTarget implements PaintTarget { // Initialize tag-writing mOpenTags = new Stack<String>(); openJsonTags = new Stack<JsonTag>(); + + openPaintables = new Stack<ClientConnector>(); + openPaintableTags = new Stack<String>(); + cacheEnabled = cachingRequired; } @@ -155,10 +146,6 @@ public class JsonPaintTarget implements PaintTarget { tag = new JsonTag(tagName); - if ("error".equals(tagName)) { - errorsOpen++; - } - customLayoutArgumentsOpen = false; } @@ -197,19 +184,7 @@ public class JsonPaintTarget implements PaintTarget { + tagName + "' expected: '" + lastTag + "'."); } - // simple hack which writes error uidl structure into attribute - if ("error".equals(lastTag)) { - if (errorsOpen == 1) { - parent.addAttribute("\"error\":[\"error\",{}" - + tag.getData() + "]"); - } else { - // sub error - parent.addData(tag.getJSON()); - } - errorsOpen--; - } else { - parent.addData(tag.getJSON()); - } + parent.addData(tag.getJSON()); tag = parent; } else { @@ -424,9 +399,9 @@ public class JsonPaintTarget implements PaintTarget { } - public void addAttribute(String name, Paintable value) + public void addAttribute(String name, ClientConnector value) throws PaintException { - final String id = getPaintIdentifier(value); + final String id = value.getConnectorId(); addAttribute(name, id); } @@ -442,9 +417,8 @@ public class JsonPaintTarget implements PaintTarget { Object key = it.next(); Object mapValue = value.get(key); sb.append("\""); - if (key instanceof Paintable) { - Paintable paintable = (Paintable) key; - sb.append(getPaintIdentifier(paintable)); + if (key instanceof ClientConnector) { + sb.append(((ClientConnector) key).getConnectorId()); } else { sb.append(escapeJSON(key.toString())); } @@ -493,10 +467,9 @@ public class JsonPaintTarget implements PaintTarget { tag.addVariable(new StringVariable(owner, name, escapeJSON(value))); } - public void addVariable(VariableOwner owner, String name, Paintable value) - throws PaintException { - tag.addVariable(new StringVariable(owner, name, - getPaintIdentifier(value))); + public void addVariable(VariableOwner owner, String name, + ClientConnector value) throws PaintException { + tag.addVariable(new StringVariable(owner, name, value.getConnectorId())); } public void addVariable(VariableOwner owner, String name, int value) @@ -669,41 +642,48 @@ public class JsonPaintTarget implements PaintTarget { /* * (non-Javadoc) * - * @see com.vaadin.terminal.PaintTarget#startTag(com.vaadin.terminal + * @see com.vaadin.terminal.PaintTarget#startPaintable(com.vaadin.terminal * .Paintable, java.lang.String) */ - public boolean startTag(Paintable paintable, String tagName) + public PaintStatus startPaintable(ClientConnector connector, String tagName) throws PaintException { + boolean topLevelPaintable = openPaintables.isEmpty(); + + logger.fine("startPaintable for " + connector.getClass().getName() + + "@" + Integer.toHexString(connector.hashCode())); startTag(tagName, true); - final boolean isPreviouslyPainted = manager.hasPaintableId(paintable) - && (identifiersCreatedDueRefPaint == null || !identifiersCreatedDueRefPaint - .contains(paintable)); - final String id = manager.getPaintableId(paintable); - paintable.addListener(manager); - addAttribute("id", id); - paintedComponents.add(paintable); - - if (paintable instanceof CustomLayout) { - customLayoutArgumentsOpen = true; + + openPaintables.push(connector); + openPaintableTags.push(tagName); + + addAttribute("id", connector.getConnectorId()); + + // Only paint top level paintables. All sub paintables are marked as + // queued and painted separately later. + if (!topLevelPaintable) { + return PaintStatus.CACHED; } - return cacheEnabled && isPreviouslyPainted; + if (connector instanceof CustomLayout) { + customLayoutArgumentsOpen = true; + } + return PaintStatus.PAINTING; } - @Deprecated - public void paintReference(Paintable paintable, String referenceName) - throws PaintException { - addAttribute(referenceName, paintable); - } + public void endPaintable(ClientConnector paintable) throws PaintException { + logger.fine("endPaintable for " + paintable.getClass().getName() + "@" + + Integer.toHexString(paintable.hashCode())); - public String getPaintIdentifier(Paintable paintable) throws PaintException { - if (!manager.hasPaintableId(paintable)) { - if (identifiersCreatedDueRefPaint == null) { - identifiersCreatedDueRefPaint = new HashSet<Paintable>(); - } - identifiersCreatedDueRefPaint.add(paintable); + ClientConnector openPaintable = openPaintables.peek(); + if (paintable != openPaintable) { + throw new PaintException("Invalid UIDL: closing wrong paintable: '" + + paintable.getConnectorId() + "' expected: '" + + openPaintable.getConnectorId() + "'."); } - return manager.getPaintableId(paintable); + // remove paintable from the stack + openPaintables.pop(); + String openTag = openPaintableTags.pop(); + endTag(openTag); } /* @@ -980,178 +960,32 @@ public class JsonPaintTarget implements PaintTarget { return usedResources; } - /** - * Method to check if paintable is already painted into this target. - * - * @param p - * @return true if is not yet painted into this target and is connected to - * app - */ - public boolean needsToBePainted(Paintable p) { - if (paintedComponents.contains(p)) { - return false; - } else if (((Component) p).getApplication() == null) { - return false; - } else { - return true; - } - } - - private static final Map<Class<? extends Paintable>, Class<? extends Paintable>> widgetMappingCache = new HashMap<Class<? extends Paintable>, Class<? extends Paintable>>(); - @SuppressWarnings("unchecked") - public String getTag(Paintable paintable) { - Class<? extends Paintable> class1; - synchronized (widgetMappingCache) { - class1 = widgetMappingCache.get(paintable.getClass()); + public String getTag(ClientConnector clientConnector) { + Class<? extends ClientConnector> clientConnectorClass = clientConnector + .getClass(); + while (clientConnectorClass.isAnonymousClass()) { + clientConnectorClass = (Class<? extends ClientConnector>) clientConnectorClass + .getSuperclass(); } - if (class1 == null) { - /* - * Client widget annotation is searched from component hierarchy to - * detect the component that presumably has client side - * implementation. The server side name is used in the - * transportation, but encoded into integer strings to optimized - * transferred data. - */ - class1 = paintable.getClass(); - while (!hasClientWidgetMapping(class1)) { - Class<?> superclass = class1.getSuperclass(); - if (superclass != null - && Paintable.class.isAssignableFrom(superclass)) { - class1 = (Class<? extends Paintable>) superclass; - } else { - logger.warning("No superclass of " - + paintable.getClass().getName() - + " has a @ClientWidget" - + " annotation. Component will not be mapped correctly on client side."); - break; - } - } - synchronized (widgetMappingCache) { - widgetMappingCache.put(paintable.getClass(), class1); - } - } - - usedPaintableTypes.add(class1); - return manager.getTagForType(class1); - - } - - private boolean hasClientWidgetMapping(Class<? extends Paintable> class1) { - try { - return class1.isAnnotationPresent(ClientWidget.class); - } catch (NoClassDefFoundError e) { - String stacktrace = getStacktraceString(e); - if (stacktrace - .contains("com.ibm.oti.reflect.AnnotationParser.parseClass")) { - // #7479 IBM JVM apparently tries to eagerly load the classes - // referred to by annotations. Checking the annotation from byte - // code to be sure that we are dealing the this case and not - // some other class loading issue. - if (bytecodeContainsClientWidgetAnnotation(class1)) { - return true; - } - } else { - // throw exception forward - throw e; - } - } catch (LinkageError e) { - String stacktrace = getStacktraceString(e); - if (stacktrace - .contains("org.jboss.modules.ModuleClassLoader.defineClass")) { - // #7822 JBoss AS 7 apparently tries to eagerly load the classes - // referred to by annotations. Checking the annotation from byte - // code to be sure that we are dealing the this case and not - // some other class loading issue. - if (bytecodeContainsClientWidgetAnnotation(class1)) { - // Seems that JBoss still prints a stacktrace to the logs - // even though the LinkageError has been caught - return true; - } - } else { - // throw exception forward - throw e; - } - } catch (RuntimeException e) { - if (e.getStackTrace()[0].getClassName().equals( - "org.glassfish.web.loader.WebappClassLoader")) { - - // See #3920 - // Glassfish 3 is darn eager to load the value class, even - // though we just want to check if the annotation exists. - - // In some situations (depending on class loading order) it - // would be enough to return true here, but it is safer to check - // the annotation from byte code - - if (bytecodeContainsClientWidgetAnnotation(class1)) { - return true; - } - } else { - // throw exception forward - throw e; - } - } - return false; - } - - private static String getStacktraceString(Throwable e) { - StringWriter writer = new StringWriter(); - e.printStackTrace(new PrintWriter(writer)); - String stacktrace = writer.toString(); - return stacktrace; - } - - private boolean bytecodeContainsClientWidgetAnnotation( - Class<? extends Paintable> class1) { - - try { - String name = class1.getName().replace('.', '/') + ".class"; - - InputStream stream = class1.getClassLoader().getResourceAsStream( - name); - BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(stream)); - try { - String line; - boolean atSourcefile = false; - while ((line = bufferedReader.readLine()) != null) { - if (line.startsWith("SourceFile")) { - atSourcefile = true; - } - if (atSourcefile) { - if (line.contains("ClientWidget")) { - return true; - } - } - // TODO could optimize to quit at the end attribute - } - } catch (IOException e1) { - logger.log(Level.SEVERE, - "An error occurred while finding widget mapping.", e1); - } finally { - try { - bufferedReader.close(); - } catch (IOException e1) { - logger.log(Level.SEVERE, "Could not close reader.", e1); - - } - } - } catch (Throwable t) { - logger.log(Level.SEVERE, - "An error occurred while finding widget mapping.", t); + Class<?> clazz = clientConnectorClass; + while (!usedClientConnectors.contains(clazz) + && clazz.getSuperclass() != null + && ClientConnector.class.isAssignableFrom(clazz)) { + usedClientConnectors.add((Class<? extends ClientConnector>) clazz); + clazz = clazz.getSuperclass(); } - - return false; + return manager.getTagForType(clientConnectorClass); } - Collection<Class<? extends Paintable>> getUsedPaintableTypes() { - return usedPaintableTypes; + Collection<Class<? extends ClientConnector>> getUsedClientConnectors() { + return usedClientConnectors; } public void addVariable(VariableOwner owner, String name, StreamVariable value) throws PaintException { - String url = manager.getStreamVariableTargetUrl(owner, name, value); + String url = manager.getStreamVariableTargetUrl((Connector) owner, + name, value); if (url != null) { addVariable(owner, name, url); } // else { //NOP this was just a cleanup by component } diff --git a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java new file mode 100644 index 0000000000..42fa3ab5a5 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java @@ -0,0 +1,38 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.server; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; + +public class LegacyChangeVariablesInvocation extends MethodInvocation { + private Map<String, Object> variableChanges = new HashMap<String, Object>(); + + public LegacyChangeVariablesInvocation(String connectorId, + String variableName, Object value) { + super(connectorId, ApplicationConnection.UPDATE_VARIABLE_INTERFACE, + ApplicationConnection.UPDATE_VARIABLE_METHOD); + setVariableChange(variableName, value); + } + + public static boolean isLegacyVariableChange(String interfaceName, + String methodName) { + return ApplicationConnection.UPDATE_VARIABLE_METHOD + .equals(interfaceName) + && ApplicationConnection.UPDATE_VARIABLE_METHOD + .equals(methodName); + } + + public void setVariableChange(String name, Object value) { + variableChanges.put(name, value); + } + + public Map<String, Object> getVariableChanges() { + return variableChanges; + } + +} diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java deleted file mode 100644 index 362fee1cc7..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext.java +++ /dev/null @@ -1,186 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.Portlet; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.servlet.http.HttpSession; - -import com.vaadin.Application; - -/** - * @author marc - */ -public class PortletApplicationContext extends WebApplicationContext implements - Serializable { - - protected transient PortletSession portletSession; - - protected Map<Application, Set<PortletListener>> portletListeners = new HashMap<Application, Set<PortletListener>>(); - - protected Map<Portlet, Application> portletToApplication = new HashMap<Portlet, Application>(); - - PortletApplicationContext() { - - } - - static public PortletApplicationContext getApplicationContext( - PortletSession session) { - WebApplicationContext cx = (WebApplicationContext) session - .getAttribute(WebApplicationContext.class.getName(), - PortletSession.APPLICATION_SCOPE); - if (cx == null) { - cx = new PortletApplicationContext(); - } - if (!(cx instanceof PortletApplicationContext)) { - // TODO Should we even try this? And should we leave original as-is? - PortletApplicationContext pcx = new PortletApplicationContext(); - pcx.applications.addAll(cx.applications); - cx.applications.clear(); - pcx.browser = cx.browser; - cx.browser = null; - pcx.listeners = cx.listeners; - cx.listeners = null; - pcx.session = cx.session; - cx = pcx; - } - if (((PortletApplicationContext) cx).portletSession == null) { - ((PortletApplicationContext) cx).portletSession = session; - } - session.setAttribute(WebApplicationContext.class.getName(), cx, - PortletSession.APPLICATION_SCOPE); - return (PortletApplicationContext) cx; - } - - static public WebApplicationContext getApplicationContext( - HttpSession session) { - WebApplicationContext cx = (WebApplicationContext) session - .getAttribute(WebApplicationContext.class.getName()); - if (cx == null) { - cx = new PortletApplicationContext(); - } - if (cx.session == null) { - cx.session = session; - } - session.setAttribute(WebApplicationContext.class.getName(), cx); - return cx; - } - - @Override - protected void removeApplication(Application application) { - portletListeners.remove(application); - for (Iterator<Application> it = portletToApplication.values() - .iterator(); it.hasNext();) { - Application value = it.next(); - if (value == application) { - // values().iterator() is backed by the map - it.remove(); - } - } - super.removeApplication(application); - } - - /** - * Reinitializing the session is not supported from portlets. - * - * @see com.vaadin.terminal.gwt.server.WebApplicationContext#reinitializeSession() - */ - @Override - public void reinitializeSession() { - throw new UnsupportedOperationException( - "Reinitializing the session is not supported from portlets"); - } - - public void setPortletApplication(Portlet portlet, Application app) { - portletToApplication.put(portlet, app); - } - - public Application getPortletApplication(Portlet portlet) { - return portletToApplication.get(portlet); - } - - public PortletSession getPortletSession() { - return portletSession; - } - - public void addPortletListener(Application app, PortletListener listener) { - Set<PortletListener> l = portletListeners.get(app); - if (l == null) { - l = new LinkedHashSet<PortletListener>(); - portletListeners.put(app, l); - } - l.add(listener); - } - - public void removePortletListener(Application app, PortletListener listener) { - Set<PortletListener> l = portletListeners.get(app); - if (l != null) { - l.remove(listener); - } - } - - public static void dispatchRequest(Portlet portlet, RenderRequest request, - RenderResponse response) { - PortletApplicationContext ctx = getApplicationContext(request - .getPortletSession()); - if (ctx != null) { - ctx.firePortletRenderRequest(portlet, request, response); - } - } - - public static void dispatchRequest(Portlet portlet, ActionRequest request, - ActionResponse response) { - PortletApplicationContext ctx = getApplicationContext(request - .getPortletSession()); - if (ctx != null) { - ctx.firePortletActionRequest(portlet, request, response); - } - } - - public void firePortletRenderRequest(Portlet portlet, - RenderRequest request, RenderResponse response) { - Application app = getPortletApplication(portlet); - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleRenderRequest(request, new RestrictedRenderResponse( - response)); - } - } - } - - public void firePortletActionRequest(Portlet portlet, - ActionRequest request, ActionResponse response) { - Application app = getPortletApplication(portlet); - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleActionRequest(request, response); - } - } - } - - public interface PortletListener extends Serializable { - public void handleRenderRequest(RenderRequest request, - RenderResponse response); - - public void handleActionRequest(ActionRequest request, - ActionResponse response); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java index dce1a1a78c..661da57af6 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java +++ b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java @@ -35,8 +35,7 @@ import javax.xml.namespace.QName; import com.vaadin.Application; import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.ExternalResource; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root; /** * TODO Write documentation, fix JavaDoc tags. @@ -172,18 +171,18 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { } } - public void firePortletRenderRequest(Application app, Window window, + public void firePortletRenderRequest(Application app, Root root, RenderRequest request, RenderResponse response) { Set<PortletListener> listeners = portletListeners.get(app); if (listeners != null) { for (PortletListener l : listeners) { l.handleRenderRequest(request, new RestrictedRenderResponse( - response), window); + response), root); } } } - public void firePortletActionRequest(Application app, Window window, + public void firePortletActionRequest(Application app, Root root, ActionRequest request, ActionResponse response) { String key = request.getParameter(ActionRequest.ACTION_NAME); if (eventActionDestinationMap.containsKey(key)) { @@ -205,28 +204,28 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { Set<PortletListener> listeners = portletListeners.get(app); if (listeners != null) { for (PortletListener l : listeners) { - l.handleActionRequest(request, response, window); + l.handleActionRequest(request, response, root); } } } } - public void firePortletEventRequest(Application app, Window window, + public void firePortletEventRequest(Application app, Root root, EventRequest request, EventResponse response) { Set<PortletListener> listeners = portletListeners.get(app); if (listeners != null) { for (PortletListener l : listeners) { - l.handleEventRequest(request, response, window); + l.handleEventRequest(request, response, root); } } } - public void firePortletResourceRequest(Application app, Window window, + public void firePortletResourceRequest(Application app, Root root, ResourceRequest request, ResourceResponse response) { Set<PortletListener> listeners = portletListeners.get(app); if (listeners != null) { for (PortletListener l : listeners) { - l.handleResourceRequest(request, response, window); + l.handleResourceRequest(request, response, root); } } } @@ -234,16 +233,16 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { public interface PortletListener extends Serializable { public void handleRenderRequest(RenderRequest request, - RenderResponse response, Window window); + RenderResponse response, Root root); public void handleActionRequest(ActionRequest request, - ActionResponse response, Window window); + ActionResponse response, Root root); public void handleEventRequest(EventRequest request, - EventResponse response, Window window); + EventResponse response, Root root); public void handleResourceRequest(ResourceRequest request, - ResourceResponse response, Window window); + ResourceResponse response, Root root); } /** @@ -308,7 +307,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { * Event names for events sent and received by a portlet need to be declared * in portlet.xml . * - * @param window + * @param root * a window in which a temporary action URL can be opened if * necessary * @param name @@ -317,7 +316,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { * event value object that is Serializable and, if appropriate, * has a valid JAXB annotation */ - public void sendPortletEvent(Window window, QName name, Serializable value) + public void sendPortletEvent(Root root, QName name, Serializable value) throws IllegalStateException { if (response instanceof MimeResponse) { String actionKey = "" + System.currentTimeMillis(); @@ -328,7 +327,9 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { if (actionUrl != null) { eventActionDestinationMap.put(actionKey, name); eventActionValueMap.put(actionKey, value); - window.open(new ExternalResource(actionUrl.toString())); + throw new RuntimeException( + "Root.open has not yet been implemented"); + // root.open(new ExternalResource(actionUrl.toString())); } else { // this should never happen as we already know the response is a // MimeResponse @@ -355,7 +356,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { * Shared parameters set or read by a portlet need to be declared in * portlet.xml . * - * @param window + * @param root * a window in which a temporary action URL can be opened if * necessary * @param name @@ -363,8 +364,8 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { * @param value * parameter value */ - public void setSharedRenderParameter(Window window, String name, - String value) throws IllegalStateException { + public void setSharedRenderParameter(Root root, String name, String value) + throws IllegalStateException { if (response instanceof MimeResponse) { String actionKey = "" + System.currentTimeMillis(); while (sharedParameterActionNameMap.containsKey(actionKey)) { @@ -374,7 +375,9 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { if (actionUrl != null) { sharedParameterActionNameMap.put(actionKey, name); sharedParameterActionValueMap.put(actionKey, value); - window.open(new ExternalResource(actionUrl.toString())); + throw new RuntimeException( + "Root.open has not yet been implemented"); + // root.open(new ExternalResource(actionUrl.toString())); } else { // this should never happen as we already know the response is a // MimeResponse @@ -394,7 +397,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { * * Portlet modes used by a portlet need to be declared in portlet.xml . * - * @param window + * @param root * a window in which the render URL can be opened if necessary * @param portletMode * the portlet mode to switch to @@ -402,12 +405,13 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext { * if the portlet mode is not allowed for some reason * (configuration, permissions etc.) */ - public void setPortletMode(Window window, PortletMode portletMode) + public void setPortletMode(Root root, PortletMode portletMode) throws IllegalStateException, PortletModeException { if (response instanceof MimeResponse) { PortletURL url = ((MimeResponse) response).createRenderURL(); url.setPortletMode(portletMode); - window.open(new ExternalResource(url.toString())); + throw new RuntimeException("Root.open has not yet been implemented"); + // root.open(new ExternalResource(url.toString())); } else if (response instanceof StateAwareResponse) { ((StateAwareResponse) response).setPortletMode(portletMode); } else { diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java index ffa8ad4054..b3ec33a9e0 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java @@ -5,29 +5,29 @@ package com.vaadin.terminal.gwt.server; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Method; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; -import javax.portlet.ClientDataRequest; import javax.portlet.MimeResponse; +import javax.portlet.PortletContext; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; -import javax.portlet.PortletSession; -import javax.portlet.ResourceRequest; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; import javax.portlet.ResourceResponse; import javax.portlet.ResourceURL; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequestWrapper; import com.vaadin.Application; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.Paintable; +import com.vaadin.external.json.JSONException; +import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.PaintException; import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.ui.Component; -import com.vaadin.ui.Window; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.ui.Root; /** * TODO document me! @@ -40,241 +40,65 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { private transient ResourceResponse currentUidlResponse; - private static class PortletRequestWrapper implements Request { - - private final PortletRequest request; - - public PortletRequestWrapper(PortletRequest request) { - this.request = request; - } - - public Object getAttribute(String name) { - return request.getAttribute(name); - } - - public int getContentLength() { - return ((ClientDataRequest) request).getContentLength(); - } - - public InputStream getInputStream() throws IOException { - return ((ClientDataRequest) request).getPortletInputStream(); - } - - public String getParameter(String name) { - String value = request.getParameter(name); - if (value == null) { - // for GateIn portlet container simple-portal - try { - Method getRealReq = request.getClass().getMethod( - "getRealRequest"); - HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq - .invoke(request); - value = origRequest.getParameter(name); - } catch (Exception e) { - // do nothing - not on GateIn simple-portal - } - } - return value; - } - - public String getRequestID() { - return "WindowID:" + request.getWindowID(); - } - - public Session getSession() { - return new PortletSessionWrapper(request.getPortletSession()); - } - - public Object getWrappedRequest() { - return request; - } - - public boolean isRunningInPortlet() { - return true; - } - - public void setAttribute(String name, Object o) { - request.setAttribute(name, o); - } - - } - - private static class PortletResponseWrapper implements Response { - - private final PortletResponse response; - - public PortletResponseWrapper(PortletResponse response) { - this.response = response; - } - - public OutputStream getOutputStream() throws IOException { - return ((MimeResponse) response).getPortletOutputStream(); - } - - public Object getWrappedResponse() { - return response; - } - - public void setContentType(String type) { - ((MimeResponse) response).setContentType(type); - } - } - - private static class PortletSessionWrapper implements Session { - - private final PortletSession session; - - public PortletSessionWrapper(PortletSession session) { - this.session = session; - } - - public Object getAttribute(String name) { - return session.getAttribute(name); - } - - public int getMaxInactiveInterval() { - return session.getMaxInactiveInterval(); - } - - public Object getWrappedSession() { - return session; - } - - public boolean isNew() { - return session.isNew(); - } - - public void setAttribute(String name, Object o) { - session.setAttribute(name, o); - } - - } - - private static class AbstractApplicationPortletWrapper implements Callback { - - private final AbstractApplicationPortlet portlet; - - public AbstractApplicationPortletWrapper( - AbstractApplicationPortlet portlet) { - this.portlet = portlet; - } - - public void criticalNotification(Request request, Response response, - String cap, String msg, String details, String outOfSyncURL) - throws IOException { - portlet.criticalNotification( - (PortletRequest) request.getWrappedRequest(), - (MimeResponse) response.getWrappedResponse(), cap, msg, - details, outOfSyncURL); - } - - public String getRequestPathInfo(Request request) { - if (request.getWrappedRequest() instanceof ResourceRequest) { - return ((ResourceRequest) request.getWrappedRequest()) - .getResourceID(); - } else { - // We do not use paths in portlet mode - throw new UnsupportedOperationException( - "PathInfo only available when using ResourceRequests"); - } - } - - public InputStream getThemeResourceAsStream(String themeName, - String resource) throws IOException { - return portlet.getPortletContext().getResourceAsStream( - "/" + AbstractApplicationPortlet.THEME_DIRECTORY_PATH - + themeName + "/" + resource); - } - - } - public PortletCommunicationManager(Application application) { super(application); } - public void handleFileUpload(ResourceRequest request, - ResourceResponse response) throws IOException { + public void handleFileUpload(WrappedRequest request, + WrappedResponse response) throws IOException { String contentType = request.getContentType(); String name = request.getParameter("name"); String ownerId = request.getParameter("rec-owner"); - VariableOwner variableOwner = getVariableOwner(ownerId); - StreamVariable streamVariable = ownerToNameToStreamVariable.get( - variableOwner).get(name); + Connector owner = getConnector(getApplication(), ownerId); + StreamVariable streamVariable = ownerToNameToStreamVariable.get(owner) + .get(name); if (contentType.contains("boundary")) { - doHandleSimpleMultipartFileUpload( - new PortletRequestWrapper(request), - new PortletResponseWrapper(response), streamVariable, name, - variableOwner, contentType.split("boundary=")[1]); + doHandleSimpleMultipartFileUpload(request, response, + streamVariable, name, owner, + contentType.split("boundary=")[1]); } else { - doHandleXhrFilePost(new PortletRequestWrapper(request), - new PortletResponseWrapper(response), streamVariable, name, - variableOwner, request.getContentLength()); + doHandleXhrFilePost(request, response, streamVariable, name, owner, + request.getContentLength()); } } @Override - protected void unregisterPaintable(Component p) { - super.unregisterPaintable(p); + protected void postPaint(Root root) { + super.postPaint(root); + + Application application = root.getApplication(); if (ownerToNameToStreamVariable != null) { - ownerToNameToStreamVariable.remove(p); + Iterator<Connector> iterator = ownerToNameToStreamVariable.keySet() + .iterator(); + while (iterator.hasNext()) { + Connector owner = iterator.next(); + if (application.getConnector(owner.getConnectorId()) == null) { + // Owner is no longer attached to the application + iterator.remove(); + } + } } } - public void handleUidlRequest(ResourceRequest request, - ResourceResponse response, - AbstractApplicationPortlet applicationPortlet, Window window) - throws InvalidUIDLSecurityKeyException, IOException { - currentUidlResponse = response; - doHandleUidlRequest(new PortletRequestWrapper(request), - new PortletResponseWrapper(response), - new AbstractApplicationPortletWrapper(applicationPortlet), - window); + @Override + public void handleUidlRequest(WrappedRequest request, + WrappedResponse response, Callback callback, Root root) + throws IOException, InvalidUIDLSecurityKeyException { + currentUidlResponse = (ResourceResponse) ((WrappedPortletResponse) response) + .getPortletResponse(); + super.handleUidlRequest(request, response, callback, root); currentUidlResponse = null; } - DownloadStream handleURI(Window window, ResourceRequest request, - ResourceResponse response, - AbstractApplicationPortlet applicationPortlet) { - return handleURI(window, new PortletRequestWrapper(request), - new PortletResponseWrapper(response), - new AbstractApplicationPortletWrapper(applicationPortlet)); - } - - /** - * Gets the existing application or creates a new one. Get a window within - * an application based on the requested URI. - * - * @param request - * the portlet Request. - * @param applicationPortlet - * @param application - * the Application to query for window. - * @param assumedWindow - * if the window has been already resolved once, this parameter - * must contain the window. - * @return Window matching the given URI or null if not found. - * @throws ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - Window getApplicationWindow(PortletRequest request, - AbstractApplicationPortlet applicationPortlet, - Application application, Window assumedWindow) { - - return doGetApplicationWindow(new PortletRequestWrapper(request), - new AbstractApplicationPortletWrapper(applicationPortlet), - application, assumedWindow); - } - - private Map<VariableOwner, Map<String, StreamVariable>> ownerToNameToStreamVariable; + private Map<Connector, Map<String, StreamVariable>> ownerToNameToStreamVariable; @Override - String getStreamVariableTargetUrl(VariableOwner owner, String name, + String getStreamVariableTargetUrl(Connector owner, String name, StreamVariable value) { if (ownerToNameToStreamVariable == null) { - ownerToNameToStreamVariable = new HashMap<VariableOwner, Map<String, StreamVariable>>(); + ownerToNameToStreamVariable = new HashMap<Connector, Map<String, StreamVariable>>(); } Map<String, StreamVariable> nameToReceiver = ownerToNameToStreamVariable .get(owner); @@ -286,14 +110,14 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { ResourceURL resurl = currentUidlResponse.createResourceURL(); resurl.setResourceID("UPLOAD"); resurl.setParameter("name", name); - resurl.setParameter("rec-owner", getPaintableId((Paintable) owner)); + resurl.setParameter("rec-owner", owner.getConnectorId()); resurl.setProperty("name", name); - resurl.setProperty("rec-owner", getPaintableId((Paintable) owner)); + resurl.setProperty("rec-owner", owner.getConnectorId()); return resurl.toString(); } @Override - protected void cleanStreamVariable(VariableOwner owner, String name) { + protected void cleanStreamVariable(Connector owner, String name) { Map<String, StreamVariable> map = ownerToNameToStreamVariable .get(owner); map.remove(name); @@ -302,4 +126,131 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { } } + @Override + protected BootstrapHandler createBootstrapHandler() { + return new BootstrapHandler() { + @Override + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + PortletRequest portletRequest = WrappedPortletRequest.cast( + request).getPortletRequest(); + if (portletRequest instanceof RenderRequest) { + return super.handleRequest(application, request, response); + } else { + return false; + } + } + + @Override + protected String getApplicationId(BootstrapContext context) { + PortletRequest portletRequest = WrappedPortletRequest.cast( + context.getRequest()).getPortletRequest(); + /* + * We need to generate a unique ID because some portals already + * create a DIV with the portlet's Window ID as the DOM ID. + */ + return "v-" + portletRequest.getWindowID(); + } + + @Override + protected String getAppUri(BootstrapContext context) { + return getRenderResponse(context).createActionURL().toString(); + } + + private RenderResponse getRenderResponse(BootstrapContext context) { + PortletResponse response = ((WrappedPortletResponse) context + .getResponse()).getPortletResponse(); + + RenderResponse renderResponse = (RenderResponse) response; + return renderResponse; + } + + @Override + protected JSONObject getDefaultParameters(BootstrapContext context) + throws JSONException { + /* + * We need this in order to get uploads to work. TODO this is + * not needed for uploads anymore, check if this is needed for + * some other things + */ + JSONObject defaults = super.getDefaultParameters(context); + defaults.put("usePortletURLs", true); + + ResourceURL uidlUrlBase = getRenderResponse(context) + .createResourceURL(); + uidlUrlBase.setResourceID("UIDL"); + defaults.put("portletUidlURLBase", uidlUrlBase.toString()); + defaults.put("pathInfo", ""); + + return defaults; + } + + @Override + protected void writeMainScriptTagContents(BootstrapContext context) + throws JSONException, IOException { + // fixed base theme to use - all portal pages with Vaadin + // applications will load this exactly once + String portalTheme = WrappedPortletRequest + .cast(context.getRequest()) + .getPortalProperty( + AbstractApplicationPortlet.PORTAL_PARAMETER_VAADIN_THEME); + if (portalTheme != null + && !portalTheme.equals(context.getThemeName())) { + String portalThemeUri = getThemeUri(context, portalTheme); + // XSS safe - originates from portal properties + context.getWriter().write( + "vaadin.loadTheme('" + portalThemeUri + "');"); + } + + super.writeMainScriptTagContents(context); + } + + @Override + protected String getMainDivStyle(BootstrapContext context) { + DeploymentConfiguration deploymentConfiguration = context + .getRequest().getDeploymentConfiguration(); + return deploymentConfiguration.getApplicationOrSystemProperty( + AbstractApplicationPortlet.PORTLET_PARAMETER_STYLE, + null); + } + + @Override + protected String getInitialUIDL(WrappedRequest request, Root root) + throws PaintException { + return PortletCommunicationManager.this.getInitialUIDL(request, + root); + } + + @Override + protected JSONObject getApplicationParameters( + BootstrapContext context) throws JSONException, + PaintException { + JSONObject parameters = super.getApplicationParameters(context); + WrappedPortletResponse wrappedPortletResponse = (WrappedPortletResponse) context + .getResponse(); + MimeResponse portletResponse = (MimeResponse) wrappedPortletResponse + .getPortletResponse(); + ResourceURL resourceURL = portletResponse.createResourceURL(); + resourceURL.setResourceID("browserDetails"); + parameters.put("browserDetailsUrl", resourceURL.toString()); + return parameters; + } + + }; + + } + + @Override + protected InputStream getThemeResourceAsStream(Root root, String themeName, + String resource) { + PortletApplicationContext2 context = (PortletApplicationContext2) root + .getApplication().getContext(); + PortletContext portletContext = context.getPortletSession() + .getPortletContext(); + return portletContext.getResourceAsStream("/" + + AbstractApplicationPortlet.THEME_DIRECTORY_PATH + themeName + + "/" + resource); + } + } diff --git a/src/com/vaadin/terminal/gwt/server/RequestTimer.java b/src/com/vaadin/terminal/gwt/server/RequestTimer.java index 5ed89c2d29..d47f444bef 100644 --- a/src/com/vaadin/terminal/gwt/server/RequestTimer.java +++ b/src/com/vaadin/terminal/gwt/server/RequestTimer.java @@ -4,10 +4,7 @@ package com.vaadin.terminal.gwt.server; -import javax.portlet.PortletRequest; -import javax.portlet.PortletSession; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; +import com.vaadin.terminal.WrappedRequest; /** * Times the handling of requests and stores the information as an attribute in @@ -25,72 +22,13 @@ public class RequestTimer { private long lastRequestTime = -1; /** - * This class acts as a proxy for setting and getting session and request - * attributes on HttpServletRequests and PortletRequests. Using this class - * we don't need to duplicate code everywhere. - */ - static class RequestWrapper { - private final HttpServletRequest servletRequest; - private final PortletRequest portletRequest; - - public RequestWrapper(HttpServletRequest servletRequest) { - this.servletRequest = servletRequest; - portletRequest = null; - } - - public RequestWrapper(PortletRequest portletRequest) { - this.portletRequest = portletRequest; - servletRequest = null; - } - - public void setAttribute(String name, Object value) { - if (servletRequest != null) { - servletRequest.setAttribute(name, value); - } else { - portletRequest.setAttribute(name, value); - } - } - - public void setSessionAttribute(String name, Object value) { - if (servletRequest != null) { - HttpSession session = servletRequest.getSession(); - if (session != null) { - session.setAttribute(name, value); - } - } else { - PortletSession portletSession = portletRequest - .getPortletSession(); - if (portletSession != null) { - portletSession.setAttribute(name, value); - } - } - } - - public Object getSessionAttribute(String name) { - if (servletRequest != null) { - HttpSession session = servletRequest.getSession(); - if (session != null) { - return session.getAttribute(name); - } - } else { - PortletSession portletSession = portletRequest - .getPortletSession(); - if (portletSession != null) { - return portletSession.getAttribute(name); - } - } - return null; - } - } - - /** * Starts the timing of a request. This should be called before any * processing of the request. * * @param request * the request. */ - public void start(RequestWrapper request) { + public void start(WrappedRequest request) { requestStartTime = System.nanoTime(); request.setAttribute("TOTAL", totalSessionTime); request.setAttribute("LASTREQUEST", lastRequestTime); @@ -116,7 +54,7 @@ public class RequestTimer { * the request for which to get a valid timer. * @return a valid timer. */ - public static RequestTimer get(RequestWrapper request) { + public static RequestTimer get(WrappedRequest request) { RequestTimer timer = (RequestTimer) request .getSessionAttribute(SESSION_ATTR_ID); if (timer == null) { @@ -136,7 +74,7 @@ public class RequestTimer { * @param requestTimer * the timer. */ - public static void set(RequestWrapper request, RequestTimer requestTimer) { + public static void set(WrappedRequest request, RequestTimer requestTimer) { request.setSessionAttribute(RequestTimer.SESSION_ATTR_ID, requestTimer); } } diff --git a/src/com/vaadin/terminal/gwt/server/ResourceReference.java b/src/com/vaadin/terminal/gwt/server/ResourceReference.java new file mode 100644 index 0000000000..56f2bed896 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ResourceReference.java @@ -0,0 +1,51 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.server; + +import com.vaadin.Application; +import com.vaadin.terminal.ApplicationResource; +import com.vaadin.terminal.ExternalResource; +import com.vaadin.terminal.Resource; +import com.vaadin.terminal.ThemeResource; +import com.vaadin.terminal.gwt.client.communication.URLReference; + +public class ResourceReference extends URLReference { + + private Resource resource; + + public ResourceReference(Resource resource) { + this.resource = resource; + } + + public Resource getResource() { + return resource; + } + + @Override + public String getURL() { + if (resource instanceof ExternalResource) { + return ((ExternalResource) resource).getURL(); + } else if (resource instanceof ApplicationResource) { + final ApplicationResource r = (ApplicationResource) resource; + final Application a = r.getApplication(); + if (a == null) { + throw new RuntimeException( + "An ApplicationResource (" + + r.getClass().getName() + + " must be attached to an application when it is sent to the client."); + } + final String uri = a.getRelativeLocation(r); + return uri; + } else if (resource instanceof ThemeResource) { + final String uri = "theme://" + + ((ThemeResource) resource).getResourceId(); + return uri; + } else { + throw new RuntimeException(getClass().getSimpleName() + + " does not support resources of type: " + + resource.getClass().getName()); + } + + } +} diff --git a/src/com/vaadin/terminal/gwt/server/RpcManager.java b/src/com/vaadin/terminal/gwt/server/RpcManager.java new file mode 100644 index 0000000000..d240ab8467 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/RpcManager.java @@ -0,0 +1,17 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.Serializable; + +/** + * Server side RPC manager that can invoke methods based on RPC calls received + * from the client. + * + * @since 7.0 + */ +public interface RpcManager extends Serializable { + public void applyInvocation(ServerRpcMethodInvocation invocation); +} diff --git a/src/com/vaadin/terminal/gwt/server/RpcTarget.java b/src/com/vaadin/terminal/gwt/server/RpcTarget.java new file mode 100644 index 0000000000..b280f5c6b5 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/RpcTarget.java @@ -0,0 +1,28 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.Serializable; + +import com.vaadin.terminal.VariableOwner; + +/** + * Marker interface for server side classes that can receive RPC calls. + * + * This plays a role similar to that of {@link VariableOwner}. + * + * @since 7.0 + */ +public interface RpcTarget extends Serializable { + /** + * Returns the RPC manager instance to use when receiving calls for an RPC + * interface. + * + * @param rpcInterface + * interface for which the call was made + * @return RpcManager or null if none found for the interface + */ + public RpcManager getRpcManager(Class<?> rpcInterface); +} diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java new file mode 100644 index 0000000000..07f83864c2 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java @@ -0,0 +1,138 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.vaadin.terminal.gwt.client.Connector; + +/** + * Server side RPC manager that handles RPC calls coming from the client. + * + * Each {@link RpcTarget} (typically a {@link ClientConnector}) should have its + * own instance of {@link ServerRpcManager} if it wants to receive RPC calls + * from the client. + * + * @since 7.0 + */ +public class ServerRpcManager<T> implements RpcManager { + + private final T implementation; + private final Class<T> rpcInterface; + + private static final Map<Class<?>, Class<?>> boxedTypes = new HashMap<Class<?>, Class<?>>(); + static { + try { + Class<?>[] boxClasses = new Class<?>[] { Boolean.class, Byte.class, + Short.class, Character.class, Integer.class, Long.class, + Float.class, Double.class }; + for (Class<?> boxClass : boxClasses) { + Field typeField = boxClass.getField("TYPE"); + Class<?> primitiveType = (Class<?>) typeField.get(boxClass); + boxedTypes.put(primitiveType, boxClass); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Create a RPC manager for an RPC target. + * + * @param target + * RPC call target (normally a {@link Connector}) + * @param implementation + * RPC interface implementation for the target + * @param rpcInterface + * RPC interface type + */ + public ServerRpcManager(T implementation, Class<T> rpcInterface) { + this.implementation = implementation; + this.rpcInterface = rpcInterface; + } + + /** + * Invoke a method in a server side RPC target class. This method is to be + * used by the RPC framework and unit testing tools only. + * + * @param target + * non-null target of the RPC call + * @param invocation + * method invocation to perform + */ + public static void applyInvocation(RpcTarget target, + ServerRpcMethodInvocation invocation) { + RpcManager manager = target.getRpcManager(invocation + .getInterfaceClass()); + if (manager != null) { + manager.applyInvocation(invocation); + } else { + getLogger() + .log(Level.WARNING, + "RPC call received for RpcTarget " + + target.getClass().getName() + + " (" + + invocation.getConnectorId() + + ") but the target has not registered any RPC interfaces"); + } + } + + /** + * Returns the RPC interface implementation for the RPC target. + * + * @return RPC interface implementation + */ + protected T getImplementation() { + return implementation; + } + + /** + * Returns the RPC interface type managed by this RPC manager instance. + * + * @return RPC interface type + */ + protected Class<T> getRpcInterface() { + return rpcInterface; + } + + /** + * Invoke a method in a server side RPC target class. This method is to be + * used by the RPC framework and unit testing tools only. + * + * @param invocation + * method invocation to perform + */ + public void applyInvocation(ServerRpcMethodInvocation invocation) { + Method method = invocation.getMethod(); + Class<?>[] parameterTypes = method.getParameterTypes(); + Object[] args = new Object[parameterTypes.length]; + Object[] arguments = invocation.getParameters(); + for (int i = 0; i < args.length; i++) { + // no conversion needed for basic cases + // Class<?> type = parameterTypes[i]; + // if (type.isPrimitive()) { + // type = boxedTypes.get(type); + // } + args[i] = arguments[i]; + } + try { + method.invoke(implementation, args); + } catch (Exception e) { + throw new RuntimeException("Unable to invoke method " + + invocation.getMethodName() + " in " + + invocation.getInterfaceName(), e); + } + } + + private static Logger getLogger() { + return Logger.getLogger(ServerRpcManager.class.getName()); + } + +} diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java new file mode 100644 index 0000000000..6f278f7797 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java @@ -0,0 +1,107 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.server; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public class ServerRpcMethodInvocation extends MethodInvocation { + + private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>( + 128, 0.75f, 1); + + private final Method method; + + private Class<? extends ServerRpc> interfaceClass; + + public ServerRpcMethodInvocation(String connectorId, String interfaceName, + String methodName, int parameterCount) { + super(connectorId, interfaceName, methodName); + + interfaceClass = findClass(); + method = findInvocationMethod(interfaceClass, methodName, + parameterCount); + } + + private Class<? extends ServerRpc> findClass() { + try { + Class<?> rpcInterface = Class.forName(getInterfaceName()); + if (!ServerRpc.class.isAssignableFrom(rpcInterface)) { + throw new IllegalArgumentException("The interface " + + getInterfaceName() + "is not a server RPC interface."); + } + return (Class<? extends ServerRpc>) rpcInterface; + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("The server RPC interface " + + getInterfaceName() + " could not be found", e); + } finally { + + } + } + + public Class<? extends ServerRpc> getInterfaceClass() { + return interfaceClass; + } + + public Method getMethod() { + return method; + } + + /** + * Tries to find the method from the cache or alternatively by invoking + * {@link #doFindInvocationMethod(Class, String, int)} and updating the + * cache. + * + * @param targetType + * @param methodName + * @param parameterCount + * @return + */ + private Method findInvocationMethod(Class<?> targetType, String methodName, + int parameterCount) { + // TODO currently only using method name and number of parameters as the + // signature + String signature = targetType.getName() + "." + methodName + "(" + + parameterCount; + Method invocationMethod = invocationMethodCache.get(signature); + + if (invocationMethod == null) { + invocationMethod = doFindInvocationMethod(targetType, methodName, + parameterCount); + + if (invocationMethod != null) { + invocationMethodCache.put(signature, invocationMethod); + } + } + + return invocationMethod; + } + + /** + * Tries to find the method from the class by looping through available + * methods. + * + * @param targetType + * @param methodName + * @param parameterCount + * @return + */ + private Method doFindInvocationMethod(Class<?> targetType, + String methodName, int parameterCount) { + Method[] methods = targetType.getMethods(); + for (Method method : methods) { + Class<?>[] parameterTypes = method.getParameterTypes(); + if (method.getName().equals(methodName) + && parameterTypes.length == parameterCount) { + return method; + } + } + return null; + } + +} diff --git a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java new file mode 100644 index 0000000000..9b1e60e621 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java @@ -0,0 +1,73 @@ +package com.vaadin.terminal.gwt.server; + +import java.io.Serializable; + +import com.vaadin.Application; +import com.vaadin.ui.Root; + +/* + @VaadinApache2LicenseForJavaFiles@ + */ + +class ServletPortletHelper implements Serializable { + public static class ApplicationClassException extends Exception { + + public ApplicationClassException(String message, Throwable cause) { + super(message, cause); + } + + public ApplicationClassException(String message) { + super(message); + } + } + + static Class<? extends Application> getApplicationClass( + String applicationParameter, String rootParameter, + ClassLoader classLoader) throws ApplicationClassException { + if (applicationParameter == null) { + + // Validate the parameter value + verifyRootClass(rootParameter, classLoader); + + // Application can be used if a valid rootLayout is defined + return Application.class; + } + + try { + return (Class<? extends Application>) classLoader + .loadClass(applicationParameter); + } catch (final ClassNotFoundException e) { + throw new ApplicationClassException( + "Failed to load application class: " + applicationParameter, + e); + } + } + + private static void verifyRootClass(String className, + ClassLoader classLoader) throws ApplicationClassException { + if (className == null) { + throw new ApplicationClassException(Application.ROOT_PARAMETER + + " init parameter not defined"); + } + + // Check that the root layout class can be found + try { + Class<?> rootClass = classLoader.loadClass(className); + if (!Root.class.isAssignableFrom(rootClass)) { + throw new ApplicationClassException(className + + " does not implement Root"); + } + // Try finding a default constructor, else throw exception + rootClass.getConstructor(); + } catch (ClassNotFoundException e) { + throw new ApplicationClassException(className + + " could not be loaded", e); + } catch (SecurityException e) { + throw new ApplicationClassException("Could not access " + className + + " class", e); + } catch (NoSuchMethodException e) { + throw new ApplicationClassException(className + + " doesn't have a public no-args constructor"); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java b/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java new file mode 100644 index 0000000000..334a7acf8d --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java @@ -0,0 +1,88 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.server; + +import java.io.IOException; +import java.io.Writer; + +import com.vaadin.Application; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; + +/** + * A {@link RequestHandler} that presents an informative page if the browser in + * use is unsupported. Recognizes Chrome Frame and allow it to be used. + * + * <p> + * This handler is usually added to the application by + * {@link AbstractCommunicationManager}. + * </p> + */ +@SuppressWarnings("serial") +public class UnsupportedBrowserHandler implements RequestHandler { + + /** Cookie used to ignore browser checks */ + public static final String FORCE_LOAD_COOKIE = "vaadinforceload=1"; + + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + + if (request.getBrowserDetails() != null) { + // Check if the browser is supported + // If Chrome Frame is available we'll assume it's ok + WebBrowser b = request.getBrowserDetails().getWebBrowser(); + if (b.isTooOldToFunctionProperly() && !b.isChromeFrameCapable()) { + // bypass if cookie set + String c = request.getHeader("Cookie"); + if (c == null || !c.contains(FORCE_LOAD_COOKIE)) { + writeBrowserTooOldPage(request, response); + return true; // request handled + } + } + } + + return false; // pass to next handler + } + + /** + * Writes a page encouraging the user to upgrade to a more current browser. + * + * @param request + * @param response + * @throws IOException + */ + protected void writeBrowserTooOldPage(WrappedRequest request, + WrappedResponse response) throws IOException { + Writer page = response.getWriter(); + WebBrowser b = request.getBrowserDetails().getWebBrowser(); + + page.write("<html><body><h1>I'm sorry, but your browser is not supported</h1>" + + "<p>The version (" + + b.getBrowserMajorVersion() + + "." + + b.getBrowserMinorVersion() + + ") of the browser you are using " + + " is outdated and not supported.</p>" + + "<p>You should <b>consider upgrading</b> to a more up-to-date browser.</p> " + + "<p>The most popular browsers are <b>" + + " <a href=\"https://www.google.com/chrome\">Chrome</a>," + + " <a href=\"http://www.mozilla.com/firefox\">Firefox</a>," + + (b.isWindows() ? " <a href=\"http://windows.microsoft.com/en-US/internet-explorer/downloads/ie\">Internet Explorer</a>," + : "") + + " <a href=\"http://www.opera.com/browser\">Opera</a>" + + " and <a href=\"http://www.apple.com/safari\">Safari</a>.</b><br/>" + + "Upgrading to the latest version of one of these <b>will make the web safer, faster and better looking.</b></p>" + + (b.isIE() ? "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js\"></script>" + + "<p>If you can not upgrade your browser, please consider trying <a onclick=\"CFInstall.check({mode:'overlay'});return false;\" href=\"http://www.google.com/chromeframe\">Chrome Frame</a>.</p>" + : "") // + + "<p><sub><a onclick=\"document.cookie='" + + FORCE_LOAD_COOKIE + + "';window.location.reload();return false;\" href=\"#\">Continue without updating</a> (not recommended)</sub></p>" + + "</body>\n" + "</html>"); + + page.close(); + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WebBrowser.java b/src/com/vaadin/terminal/gwt/server/WebBrowser.java index a57a4c65d2..358f6f38fb 100644 --- a/src/com/vaadin/terminal/gwt/server/WebBrowser.java +++ b/src/com/vaadin/terminal/gwt/server/WebBrowser.java @@ -8,6 +8,7 @@ import java.util.Date; import java.util.Locale; import com.vaadin.terminal.Terminal; +import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.gwt.client.VBrowserDetails; /** @@ -189,6 +190,34 @@ public class WebBrowser implements Terminal { } /** + * Tests whether the user is using Chrome Frame. + * + * @return true if the user is using Chrome Frame, false if the user is not + * using Chrome or if no information on the browser is present + */ + public boolean isChromeFrame() { + if (browserDetails == null) { + return false; + } + + return browserDetails.isChromeFrame(); + } + + /** + * Tests whether the user's browser is Chrome Frame capable. + * + * @return true if the user can use Chrome Frame, false if the user can not + * or if no information on the browser is present + */ + public boolean isChromeFrameCapable() { + if (browserDetails == null) { + return false; + } + + return browserDetails.isChromeFrameCapable(); + } + + /** * Gets the major version of the browser the user is using. * * <p> @@ -417,25 +446,50 @@ public class WebBrowser implements Terminal { * only. Updates all properties in the class according to the given * information. * - * @param locale - * The browser primary locale - * @param address - * The browser ip address - * @param secureConnection - * true if using an https connection - * @param agent - * Raw userAgent string from the browser + * @param request + * the wrapped request to read the information from */ - void updateRequestDetails(Locale locale, String address, - boolean secureConnection, String agent) { - this.locale = locale; - this.address = address; - this.secureConnection = secureConnection; + void updateRequestDetails(WrappedRequest request) { + locale = request.getLocale(); + address = request.getRemoteAddr(); + secureConnection = request.isSecure(); + String agent = request.getHeader("user-agent"); + if (agent != null) { browserApplication = agent; browserDetails = new VBrowserDetails(agent); } + if (request.getParameter("sw") != null) { + updateClientSideDetails(request.getParameter("sw"), + request.getParameter("sh"), request.getParameter("cw"), + request.getParameter("ch"), request.getParameter("tzo"), + request.getParameter("rtzo"), request.getParameter("dstd"), + request.getParameter("dston"), + request.getParameter("curdate"), + request.getParameter("td") != null); + } + } + + /** + * Checks if the browser is so old that it simply won't work with a Vaadin + * application. Can be used to redirect to an alternative page, show + * alternative content or similar. + * + * When this method returns true chances are very high that the browser + * won't work and it does not make sense to direct the user to the Vaadin + * application. + * + * @return true if the browser won't work, false if not the browser is + * supported or might work + */ + public boolean isTooOldToFunctionProperly() { + if (browserDetails == null) { + // Don't know, so assume it will work + return false; + } + + return browserDetails.isTooOldToFunctionProperly(); } } diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java new file mode 100644 index 0000000000..b6f1a192cb --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java @@ -0,0 +1,109 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import com.vaadin.Application; +import com.vaadin.terminal.CombinedRequest; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.WrappedRequest; + +/** + * Wrapper for {@link HttpServletRequest}. + * + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedRequest + * @see WrappedHttpServletResponse + */ +public class WrappedHttpServletRequest extends HttpServletRequestWrapper + implements WrappedRequest { + + private final DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a http servlet request and associates with a deployment + * configuration + * + * @param request + * the http servlet request to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ + public WrappedHttpServletRequest(HttpServletRequest request, + DeploymentConfiguration deploymentConfiguration) { + super(request); + this.deploymentConfiguration = deploymentConfiguration; + } + + public String getRequestPathInfo() { + return getPathInfo(); + } + + public int getSessionMaxInactiveInterval() { + return getSession().getMaxInactiveInterval(); + } + + public Object getSessionAttribute(String name) { + return getSession().getAttribute(name); + } + + public void setSessionAttribute(String name, Object attribute) { + getSession().setAttribute(name, attribute); + } + + /** + * Gets the original, unwrapped HTTP servlet request. + * + * @return the servlet request + */ + public HttpServletRequest getHttpServletRequest() { + return this; + } + + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } + + public BrowserDetails getBrowserDetails() { + return new BrowserDetails() { + public String getUriFragment() { + return null; + } + + public String getWindowName() { + return null; + } + + public WebBrowser getWebBrowser() { + WebApplicationContext context = (WebApplicationContext) Application + .getCurrentApplication().getContext(); + return context.getBrowser(); + } + }; + } + + /** + * Helper method to get a <code>WrappedHttpServletRequest</code> from a + * <code>WrappedRequest</code>. Aside from casting, this method also takes + * care of situations where there's another level of wrapping. + * + * @param request + * a wrapped request + * @return a wrapped http servlet request + * @throws ClassCastException + * if the wrapped request doesn't wrap a http servlet request + */ + public static WrappedHttpServletRequest cast(WrappedRequest request) { + if (request instanceof CombinedRequest) { + CombinedRequest combinedRequest = (CombinedRequest) request; + request = combinedRequest.getSecondRequest(); + } + return (WrappedHttpServletRequest) request; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java new file mode 100644 index 0000000000..14a391b21f --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java @@ -0,0 +1,73 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.WrappedResponse; + +/** + * Wrapper for {@link HttpServletResponse}. + * + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedResponse + * @see WrappedHttpServletRequest + */ +public class WrappedHttpServletResponse extends HttpServletResponseWrapper + implements WrappedResponse { + + private DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a http servlet response and an associated deployment configuration + * + * @param response + * the http servlet response to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ + public WrappedHttpServletResponse(HttpServletResponse response, + DeploymentConfiguration deploymentConfiguration) { + super(response); + this.deploymentConfiguration = deploymentConfiguration; + } + + /** + * Gets the original unwrapped <code>HttpServletResponse</code> + * + * @return the unwrapped response + */ + public HttpServletResponse getHttpServletResponse() { + return this; + } + + public void setCacheTime(long milliseconds) { + doSetCacheTime(this, milliseconds); + } + + // Implementation shared with WrappedPortletResponse + static void doSetCacheTime(WrappedResponse response, long milliseconds) { + if (milliseconds <= 0) { + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Pragma", "no-cache"); + response.setDateHeader("Expires", 0); + } else { + response.setHeader("Cache-Control", "max-age=" + milliseconds + / 1000); + response.setDateHeader("Expires", System.currentTimeMillis() + + milliseconds); + // Required to apply caching in some Tomcats + response.setHeader("Pragma", "cache"); + } + } + + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java new file mode 100644 index 0000000000..3838695aa3 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java @@ -0,0 +1,189 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; +import java.util.Map; + +import javax.portlet.ClientDataRequest; +import javax.portlet.PortletRequest; +import javax.portlet.ResourceRequest; + +import com.vaadin.Application; +import com.vaadin.terminal.CombinedRequest; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.WrappedRequest; + +/** + * Wrapper for {@link PortletRequest} and its subclasses. + * + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedRequest + * @see WrappedPortletResponse + */ +public class WrappedPortletRequest implements WrappedRequest { + + private final PortletRequest request; + private final DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a portlet request and an associated deployment configuration + * + * @param request + * the portlet request to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ + public WrappedPortletRequest(PortletRequest request, + DeploymentConfiguration deploymentConfiguration) { + this.request = request; + this.deploymentConfiguration = deploymentConfiguration; + } + + public Object getAttribute(String name) { + return request.getAttribute(name); + } + + public int getContentLength() { + try { + return ((ClientDataRequest) request).getContentLength(); + } catch (ClassCastException e) { + throw new IllegalStateException( + "Content lenght only available for ClientDataRequests"); + } + } + + public InputStream getInputStream() throws IOException { + try { + return ((ClientDataRequest) request).getPortletInputStream(); + } catch (ClassCastException e) { + throw new IllegalStateException( + "Input data only available for ClientDataRequests"); + } + } + + public String getParameter(String name) { + return request.getParameter(name); + } + + public Map<String, String[]> getParameterMap() { + return request.getParameterMap(); + } + + public void setAttribute(String name, Object o) { + request.setAttribute(name, o); + } + + public String getRequestPathInfo() { + if (request instanceof ResourceRequest) { + return ((ResourceRequest) request).getResourceID(); + } else { + return null; + } + } + + public int getSessionMaxInactiveInterval() { + return request.getPortletSession().getMaxInactiveInterval(); + } + + public Object getSessionAttribute(String name) { + return request.getPortletSession().getAttribute(name); + } + + public void setSessionAttribute(String name, Object attribute) { + request.getPortletSession().setAttribute(name, attribute); + } + + /** + * Gets the original, unwrapped portlet request. + * + * @return the unwrapped portlet request + */ + public PortletRequest getPortletRequest() { + return request; + } + + public String getContentType() { + try { + return ((ResourceRequest) request).getContentType(); + } catch (ClassCastException e) { + throw new IllegalStateException( + "Content type only available for ResourceRequests"); + } + } + + public BrowserDetails getBrowserDetails() { + return new BrowserDetails() { + public String getUriFragment() { + return null; + } + + public String getWindowName() { + return null; + } + + public WebBrowser getWebBrowser() { + PortletApplicationContext2 context = (PortletApplicationContext2) Application + .getCurrentApplication().getContext(); + return context.getBrowser(); + } + }; + } + + public Locale getLocale() { + return request.getLocale(); + } + + public String getRemoteAddr() { + return null; + } + + public boolean isSecure() { + return request.isSecure(); + } + + public String getHeader(String string) { + return null; + } + + /** + * Reads a portal property from the portal context of the wrapped request. + * + * @param name + * a string with the name of the portal property to get + * @return a string with the value of the property, or <code>null</code> if + * the property is not defined + */ + public String getPortalProperty(String name) { + return request.getPortalContext().getProperty(name); + } + + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } + + /** + * Helper method to get a <code>WrappedPortlettRequest</code> from a + * <code>WrappedRequest</code>. Aside from casting, this method also takes + * care of situations where there's another level of wrapping. + * + * @param request + * a wrapped request + * @return a wrapped portlet request + * @throws ClassCastException + * if the wrapped request doesn't wrap a portlet request + */ + public static WrappedPortletRequest cast(WrappedRequest request) { + if (request instanceof CombinedRequest) { + CombinedRequest combinedRequest = (CombinedRequest) request; + request = combinedRequest.getSecondRequest(); + } + return (WrappedPortletRequest) request; + } +} diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java new file mode 100644 index 0000000000..8824396352 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java @@ -0,0 +1,102 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.server; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import javax.portlet.MimeResponse; +import javax.portlet.PortletResponse; +import javax.portlet.ResourceResponse; + +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.WrappedResponse; + +/** + * Wrapper for {@link PortletResponse} and its subclasses. + * + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedResponse + * @see WrappedPortletRequest + */ +public class WrappedPortletResponse implements WrappedResponse { + private static final DateFormat HTTP_DATE_FORMAT = new SimpleDateFormat( + "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); + static { + HTTP_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + private final PortletResponse response; + private DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a portlet response and an associated deployment configuration + * + * @param response + * the portlet response to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ + public WrappedPortletResponse(PortletResponse response, + DeploymentConfiguration deploymentConfiguration) { + this.response = response; + this.deploymentConfiguration = deploymentConfiguration; + } + + public OutputStream getOutputStream() throws IOException { + return ((MimeResponse) response).getPortletOutputStream(); + } + + /** + * Gets the original, unwrapped portlet response. + * + * @return the unwrapped portlet response + */ + public PortletResponse getPortletResponse() { + return response; + } + + public void setContentType(String type) { + ((MimeResponse) response).setContentType(type); + } + + public PrintWriter getWriter() throws IOException { + return ((MimeResponse) response).getWriter(); + } + + public void setStatus(int responseStatus) { + response.setProperty(ResourceResponse.HTTP_STATUS_CODE, + Integer.toString(responseStatus)); + } + + public void setHeader(String name, String value) { + response.setProperty(name, value); + } + + public void setDateHeader(String name, long timestamp) { + response.setProperty(name, HTTP_DATE_FORMAT.format(new Date(timestamp))); + } + + public void setCacheTime(long milliseconds) { + WrappedHttpServletResponse.doSetCacheTime(this, milliseconds); + } + + public void sendError(int errorCode, String message) throws IOException { + setStatus(errorCode); + getWriter().write(message); + } + + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java index 2e4ce39513..6a0aa0f4c2 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/ClassPathExplorer.java @@ -31,8 +31,7 @@ import java.util.logging.Logger; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.event.dd.acceptcriteria.ClientCriterion; -import com.vaadin.terminal.Paintable; -import com.vaadin.ui.ClientWidget; +import com.vaadin.terminal.gwt.server.ClientConnector; /** * Utility class to collect widgetset related information from classpath. @@ -93,29 +92,27 @@ public class ClassPathExplorer { } /** - * Finds server side widgets with {@link ClientWidget} annotation on the - * class path (entries that can contain widgets/widgetsets - see - * {@link #getRawClasspathEntries()}). + * Finds server side widgets with ClientWidget annotation on the class path + * (entries that can contain widgets/widgetsets - see + * getRawClasspathEntries()). * * As a side effect, also accept criteria are searched under the same class * path entries and added into the acceptCriterion collection. * - * @return a collection of {@link Paintable} classes + * @return a collection of {@link ClientConnector} classes */ - public static Collection<Class<? extends Paintable>> getPaintablesHavingWidgetAnnotation() { - logger.info("Searching for paintables.."); + public static void findAcceptCriteria() { + logger.info("Searching for accept criteria.."); long start = System.currentTimeMillis(); - Collection<Class<? extends Paintable>> paintables = new HashSet<Class<? extends Paintable>>(); Set<String> keySet = classpathLocations.keySet(); for (String url : keySet) { - logger.fine("Searching for paintables in " + logger.fine("Searching for accept criteria in " + classpathLocations.get(url)); - searchForPaintables(classpathLocations.get(url), url, paintables); + searchForPaintables(classpathLocations.get(url), url); } long end = System.currentTimeMillis(); logger.info("Search took " + (end - start) + "ms"); - return paintables; } @@ -129,7 +126,7 @@ public class ClassPathExplorer { if (acceptCriterion.isEmpty()) { // accept criterion are searched as a side effect, normally after // paintable detection - getPaintablesHavingWidgetAnnotation(); + findAcceptCriteria(); } return acceptCriterion; } @@ -449,7 +446,7 @@ public class ClassPathExplorer { /** * Searches for all paintable classes and accept criteria under a location - * based on {@link ClientWidget} and {@link ClientCriterion} annotations. + * based on {@link ClientCriterion} annotations. * * Note that client criteria are updated directly to the * {@link #acceptCriterion} field, whereas paintables are added to the @@ -457,11 +454,9 @@ public class ClassPathExplorer { * * @param location * @param locationString - * @param paintables */ private final static void searchForPaintables(URL location, - String locationString, - Collection<Class<? extends Paintable>> paintables) { + String locationString) { // Get a File object for the package File directory = new File(location.getFile()); @@ -478,7 +473,7 @@ public class ClassPathExplorer { String packageName = locationString .substring(locationString.lastIndexOf("/") + 1); classname = packageName + "." + classname; - tryToAdd(classname, paintables); + tryToAdd(classname); } } } else { @@ -510,7 +505,7 @@ public class ClassPathExplorer { classname = classname.substring(1); } classname = classname.replace('/', '.'); - tryToAdd(classname, paintables); + tryToAdd(classname); } } } @@ -542,17 +537,13 @@ public class ClassPathExplorer { private static Set<Class<? extends AcceptCriterion>> acceptCriterion = new HashSet<Class<? extends AcceptCriterion>>(); /** - * Checks a class for the {@link ClientWidget} and {@link ClientCriterion} - * annotations, and adds it to the appropriate collection if it has either. + * Checks a class for the {@link ClientCriterion} annotations, and adds it + * to the appropriate collection. * * @param fullclassName - * @param paintables - * the collection to which to add server side classes with - * {@link ClientWidget} annotation */ @SuppressWarnings("unchecked") - private static void tryToAdd(final String fullclassName, - Collection<Class<? extends Paintable>> paintables) { + private static void tryToAdd(final String fullclassName) { PrintStream out = System.out; PrintStream err = System.err; Throwable errorToShow = null; @@ -563,10 +554,7 @@ public class ClassPathExplorer { Class<?> c = Class.forName(fullclassName); - if (c.getAnnotation(ClientWidget.class) != null) { - paintables.add((Class<? extends Paintable>) c); - // System.out.println("Found paintable " + fullclassName); - } else if (c.getAnnotation(ClientCriterion.class) != null) { + if (c.getAnnotation(ClientCriterion.class) != null) { acceptCriterion.add((Class<? extends AcceptCriterion>) c); } } catch (UnsupportedClassVersionError e) { @@ -667,10 +655,9 @@ public class ClassPathExplorer { * Test method for helper tool */ public static void main(String[] args) { - Collection<Class<? extends Paintable>> paintables = ClassPathExplorer - .getPaintablesHavingWidgetAnnotation(); - logger.info("Found annotated paintables:"); - for (Class<? extends Paintable> cls : paintables) { + ClassPathExplorer.findAcceptCriteria(); + logger.info("Found client criteria:"); + for (Class<? extends AcceptCriterion> cls : acceptCriterion) { logger.info(cls.getCanonicalName()); } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/CustomWidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/CustomWidgetMapGenerator.java index 4ea4cbb8fe..f0d6f0453b 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/CustomWidgetMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/CustomWidgetMapGenerator.java @@ -6,57 +6,58 @@ package com.vaadin.terminal.gwt.widgetsetutils; import java.util.Collection; import java.util.HashSet; -import com.vaadin.terminal.Paintable; -import com.vaadin.ui.ClientWidget; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; /** * An abstract helper class that can be used to easily build a widgetset with * customized load styles for each components. In three abstract methods one can - * override the default values given in {@link ClientWidget} annotations. + * override the default values given in {@link Connect} annotations. * * @see WidgetMapGenerator * */ public abstract class CustomWidgetMapGenerator extends WidgetMapGenerator { - private Collection<Class<? extends Paintable>> eagerPaintables = new HashSet<Class<? extends Paintable>>(); - private Collection<Class<? extends Paintable>> lazyPaintables = new HashSet<Class<? extends Paintable>>(); - private Collection<Class<? extends Paintable>> deferredPaintables = new HashSet<Class<? extends Paintable>>(); + private Collection<Class<? extends ComponentConnector>> eagerPaintables = new HashSet<Class<? extends ComponentConnector>>(); + private Collection<Class<? extends ComponentConnector>> lazyPaintables = new HashSet<Class<? extends ComponentConnector>>(); + private Collection<Class<? extends ComponentConnector>> deferredPaintables = new HashSet<Class<? extends ComponentConnector>>(); @Override - protected LoadStyle getLoadStyle(Class<? extends Paintable> paintableType) { + protected LoadStyle getLoadStyle( + Class<? extends ComponentConnector> connector) { if (eagerPaintables == null) { init(); } - if (eagerPaintables.contains(paintableType)) { + if (eagerPaintables.contains(connector)) { return LoadStyle.EAGER; } - if (lazyPaintables.contains(paintableType)) { + if (lazyPaintables.contains(connector)) { return LoadStyle.LAZY; } - if (deferredPaintables.contains(paintableType)) { + if (deferredPaintables.contains(connector)) { return LoadStyle.DEFERRED; } - return super.getLoadStyle(paintableType); + return super.getLoadStyle(connector); } private void init() { - Class<? extends Paintable>[] eagerComponents = getEagerComponents(); + Class<? extends ComponentConnector>[] eagerComponents = getEagerComponents(); if (eagerComponents != null) { - for (Class<? extends Paintable> class1 : eagerComponents) { + for (Class<? extends ComponentConnector> class1 : eagerComponents) { eagerPaintables.add(class1); } } - Class<? extends Paintable>[] lazyComponents = getEagerComponents(); + Class<? extends ComponentConnector>[] lazyComponents = getEagerComponents(); if (lazyComponents != null) { - for (Class<? extends Paintable> class1 : lazyComponents) { + for (Class<? extends ComponentConnector> class1 : lazyComponents) { lazyPaintables.add(class1); } } - Class<? extends Paintable>[] deferredComponents = getEagerComponents(); + Class<? extends ComponentConnector>[] deferredComponents = getEagerComponents(); if (deferredComponents != null) { - for (Class<? extends Paintable> class1 : deferredComponents) { + for (Class<? extends ComponentConnector> class1 : deferredComponents) { deferredPaintables.add(class1); } } @@ -66,18 +67,18 @@ public abstract class CustomWidgetMapGenerator extends WidgetMapGenerator { * @return an array of components whose load style should be overridden to * {@link LoadStyle#EAGER} */ - protected abstract Class<? extends Paintable>[] getEagerComponents(); + protected abstract Class<? extends ComponentConnector>[] getEagerComponents(); /** * @return an array of components whose load style should be overridden to * {@link LoadStyle#LAZY} */ - protected abstract Class<? extends Paintable>[] getLazyComponents(); + protected abstract Class<? extends ComponentConnector>[] getLazyComponents(); /** * @return an array of components whose load style should be overridden to * {@link LoadStyle#DEFERRED} */ - protected abstract Class<? extends Paintable>[] getDeferredComponents(); + protected abstract Class<? extends ComponentConnector>[] getDeferredComponents(); } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/EagerWidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/EagerWidgetMapGenerator.java index 6381a3b4cb..8a1dfee3b5 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/EagerWidgetMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/EagerWidgetMapGenerator.java @@ -3,8 +3,8 @@ */ package com.vaadin.terminal.gwt.widgetsetutils; -import com.vaadin.terminal.Paintable; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; /** * WidgetMap generator that builds a widgetset that packs all included widgets @@ -21,8 +21,10 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * */ public class EagerWidgetMapGenerator extends WidgetMapGenerator { + @Override - protected LoadStyle getLoadStyle(Class<? extends Paintable> paintableType) { + protected LoadStyle getLoadStyle( + Class<? extends ComponentConnector> connector) { return LoadStyle.EAGER; } } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/LazyWidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/LazyWidgetMapGenerator.java index 7de72f09ce..729a999a21 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/LazyWidgetMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/LazyWidgetMapGenerator.java @@ -3,8 +3,8 @@ */ package com.vaadin.terminal.gwt.widgetsetutils; -import com.vaadin.terminal.Paintable; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; /** * WidgetMap generator that builds a widgetset that optimizes the transferred @@ -16,7 +16,8 @@ import com.vaadin.ui.ClientWidget.LoadStyle; */ public class LazyWidgetMapGenerator extends WidgetMapGenerator { @Override - protected LoadStyle getLoadStyle(Class<? extends Paintable> paintableType) { + protected LoadStyle getLoadStyle( + Class<? extends ComponentConnector> connector) { return LoadStyle.LAZY; } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java new file mode 100644 index 0000000000..2899061204 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcManagerGenerator.java @@ -0,0 +1,197 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.widgetsetutils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ServerConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.communication.ClientRpc; +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; +import com.vaadin.terminal.gwt.client.communication.RpcManager; + +/** + * GWT generator that creates an implementation for {@link RpcManager} on the + * client side classes for executing RPC calls received from the the server. + * + * @since 7.0 + */ +public class RpcManagerGenerator extends Generator { + + @Override + public String generate(TreeLogger logger, GeneratorContext context, + String typeName) throws UnableToCompleteException { + + String packageName = null; + String className = null; + try { + TypeOracle typeOracle = context.getTypeOracle(); + + // get classType and save instance variables + JClassType classType = typeOracle.getType(typeName); + packageName = classType.getPackage().getName(); + className = classType.getSimpleSourceName() + "Impl"; + // Generate class source code for SerializerMapImpl + generateClass(logger, context, packageName, className); + } catch (Exception e) { + logger.log(TreeLogger.ERROR, + "SerializerMapGenerator creation failed", e); + } + // return the fully qualifed name of the class generated + return packageName + "." + className; + } + + /** + * Generate source code for RpcManagerImpl + * + * @param logger + * Logger object + * @param context + * Generator context + * @param packageName + * package name for the class to generate + * @param className + * class name for the class to generate + */ + private void generateClass(TreeLogger logger, GeneratorContext context, + String packageName, String className) { + // get print writer that receives the source code + PrintWriter printWriter = null; + printWriter = context.tryCreate(logger, packageName, className); + // print writer if null, source code has ALREADY been generated + if (printWriter == null) { + return; + } + logger.log(Type.INFO, + "Detecting server to client RPC interface types..."); + Date date = new Date(); + TypeOracle typeOracle = context.getTypeOracle(); + JClassType serverToClientRpcType = typeOracle.findType(ClientRpc.class + .getName()); + JClassType[] rpcInterfaceSubtypes = serverToClientRpcType.getSubtypes(); + + // init composer, set class properties, create source writer + ClassSourceFileComposerFactory composer = null; + composer = new ClassSourceFileComposerFactory(packageName, className); + composer.addImport("com.google.gwt.core.client.GWT"); + composer.addImplementedInterface(RpcManager.class.getName()); + SourceWriter sourceWriter = composer.createSourceWriter(context, + printWriter); + sourceWriter.indent(); + + List<JClassType> rpcInterfaces = new ArrayList<JClassType>(); + + // iterate over RPC interfaces and create helper methods for each + // interface + for (JClassType type : rpcInterfaceSubtypes) { + if (null == type.isInterface()) { + // only interested in interfaces here, not implementations + continue; + } + rpcInterfaces.add(type); + // generate method to call methods of an RPC interface + sourceWriter.println("private void " + getInvokeMethodName(type) + + "(" + MethodInvocation.class.getName() + " invocation, " + + ConnectorMap.class.getName() + " connectorMap) {"); + sourceWriter.indent(); + + // loop over the methods of the interface and its superinterfaces + // methods + for (JClassType currentType : type.getFlattenedSupertypeHierarchy()) { + for (JMethod method : currentType.getMethods()) { + sourceWriter.println("if (\"" + method.getName() + + "\".equals(invocation.getMethodName())) {"); + sourceWriter.indent(); + // construct parameter string with appropriate casts + String paramString = ""; + JType[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; ++i) { + paramString = paramString + "(" + + parameterTypes[i].getQualifiedSourceName() + + ") invocation.getParameters()[" + i + "]"; + if (i < parameterTypes.length - 1) { + paramString = paramString + ", "; + } + } + sourceWriter + .println(ServerConnector.class.getName() + + " connector = connectorMap.getConnector(invocation.getConnectorId());"); + sourceWriter + .println("for (" + + ClientRpc.class.getName() + + " rpcImplementation : connector.getRpcImplementations(\"" + + type.getQualifiedSourceName() + "\")) {"); + sourceWriter.indent(); + sourceWriter.println("((" + type.getQualifiedSourceName() + + ") rpcImplementation)." + method.getName() + "(" + + paramString + ");"); + sourceWriter.outdent(); + sourceWriter.println("}"); + sourceWriter.println("return;"); + sourceWriter.outdent(); + sourceWriter.println("}"); + } + } + + sourceWriter.outdent(); + sourceWriter.println("}"); + + logger.log(Type.DEBUG, + "Constructed helper method for server to client RPC for " + + type.getName()); + } + + // generate top-level "switch-case" method to select the correct + // previously generated method based on the RPC interface + sourceWriter.println("public void applyInvocation(" + + MethodInvocation.class.getName() + " invocation, " + + ConnectorMap.class.getName() + " connectorMap) {"); + sourceWriter.indent(); + + for (JClassType type : rpcInterfaces) { + sourceWriter.println("if (\"" + type.getQualifiedSourceName() + + "\".equals(invocation.getInterfaceName())) {"); + sourceWriter.indent(); + sourceWriter.println(getInvokeMethodName(type) + + "(invocation, connectorMap);"); + sourceWriter.println("return;"); + sourceWriter.outdent(); + sourceWriter.println("}"); + + logger.log(Type.INFO, + "Configured server to client RPC for " + type.getName()); + } + sourceWriter.outdent(); + sourceWriter.println("}"); + + // close generated class + sourceWriter.outdent(); + sourceWriter.println("}"); + // commit generated class + context.commit(logger, printWriter); + logger.log(Type.INFO, + "Done. (" + (new Date().getTime() - date.getTime()) / 1000 + + "seconds)"); + + } + + private String getInvokeMethodName(JClassType type) { + return "invoke" + type.getQualifiedSourceName().replaceAll("\\.", "_"); + } +} diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java new file mode 100644 index 0000000000..040715fccf --- /dev/null +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyCreatorGenerator.java @@ -0,0 +1,126 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.widgetsetutils; + +import java.io.PrintWriter; +import java.util.Date; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ServerConnector; +import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc; +import com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +public class RpcProxyCreatorGenerator extends Generator { + + @Override + public String generate(TreeLogger logger, GeneratorContext ctx, + String requestedClassName) throws UnableToCompleteException { + logger.log(TreeLogger.DEBUG, "Running RpcProxyCreatorGenerator"); + TypeOracle typeOracle = ctx.getTypeOracle(); + assert (typeOracle != null); + + JClassType requestedType = typeOracle.findType(requestedClassName); + String packageName = requestedType.getPackage().getName(); + String className = requestedType.getSimpleSourceName() + "Impl"; + if (requestedType == null) { + logger.log(TreeLogger.ERROR, "Unable to find metadata for type '" + + requestedClassName + "'", null); + throw new UnableToCompleteException(); + } + + createType(logger, ctx, packageName, className); + return packageName + "." + className; + } + + private void createType(TreeLogger logger, GeneratorContext context, + String packageName, String className) { + ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( + packageName, className); + + PrintWriter printWriter = context.tryCreate(logger, + composer.getCreatedPackage(), + composer.getCreatedClassShortName()); + if (printWriter == null) { + // print writer is null if source code has already been generated + return; + } + Date date = new Date(); + TypeOracle typeOracle = context.getTypeOracle(); + + // init composer, set class properties, create source writer + composer.addImport(GWT.class.getCanonicalName()); + composer.addImport(ServerRpc.class.getCanonicalName()); + composer.addImport(ServerConnector.class.getCanonicalName()); + composer.addImport(InitializableServerRpc.class.getCanonicalName()); + composer.addImport(IllegalArgumentException.class.getCanonicalName()); + composer.addImplementedInterface(RpcProxyCreator.class + .getCanonicalName()); + + SourceWriter sourceWriter = composer.createSourceWriter(context, + printWriter); + sourceWriter.indent(); + + sourceWriter + .println("public <T extends ServerRpc> T create(Class<T> rpcInterface, ServerConnector connector) {"); + sourceWriter.indent(); + + sourceWriter + .println("if (rpcInterface == null || connector == null) {"); + sourceWriter.indent(); + sourceWriter + .println("throw new IllegalArgumentException(\"RpcInterface and/or connector cannot be null\");"); + sourceWriter.outdent(); + + JClassType initializableInterface = typeOracle.findType(ServerRpc.class + .getCanonicalName()); + + for (JClassType rpcType : initializableInterface.getSubtypes()) { + String rpcClassName = rpcType.getQualifiedSourceName(); + if (InitializableServerRpc.class.getCanonicalName().equals( + rpcClassName)) { + // InitializableClientToServerRpc is a special marker interface + // that should not get a generated class + continue; + } + sourceWriter.println("} else if (rpcInterface == " + rpcClassName + + ".class) {"); + sourceWriter.indent(); + sourceWriter.println(rpcClassName + " rpc = GWT.create(" + + rpcClassName + ".class);"); + sourceWriter.println("((" + InitializableServerRpc.class.getName() + + ") rpc).initRpc(connector);"); + sourceWriter.println("return (T) rpc;"); + sourceWriter.outdent(); + } + + sourceWriter.println("} else {"); + sourceWriter.indent(); + sourceWriter + .println("throw new IllegalArgumentException(\"No RpcInterface of type \"+ rpcInterface.getName() + \" was found.\");"); + sourceWriter.outdent(); + // End of if + sourceWriter.println("}"); + // End of method + sourceWriter.println("}"); + + // close generated class + sourceWriter.outdent(); + sourceWriter.println("}"); + // commit generated class + context.commit(logger, printWriter); + logger.log(Type.INFO, composer.getCreatedClassName() + " created in " + + (new Date().getTime() - date.getTime()) / 1000 + "seconds"); + + } +} diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java new file mode 100644 index 0000000000..ad4e513049 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/RpcProxyGenerator.java @@ -0,0 +1,142 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.widgetsetutils; + +import java.io.PrintWriter; + +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JParameter; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ServerConnector; +import com.vaadin.terminal.gwt.client.communication.InitializableServerRpc; +import com.vaadin.terminal.gwt.client.communication.MethodInvocation; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; + +/** + * GWT generator that creates client side proxy classes for making RPC calls + * from the client to the server. + * + * GWT.create() calls for interfaces extending {@link ServerRpc} are affected, + * and a proxy implementation is created. Note that the init(...) method of the + * proxy must be called before the proxy is used. + * + * @since 7.0 + */ +public class RpcProxyGenerator extends Generator { + @Override + public String generate(TreeLogger logger, GeneratorContext ctx, + String requestedClassName) throws UnableToCompleteException { + logger.log(TreeLogger.DEBUG, "Running RpcProxyGenerator", null); + + TypeOracle typeOracle = ctx.getTypeOracle(); + assert (typeOracle != null); + + JClassType requestedType = typeOracle.findType(requestedClassName); + if (requestedType == null) { + logger.log(TreeLogger.ERROR, "Unable to find metadata for type '" + + requestedClassName + "'", null); + throw new UnableToCompleteException(); + } + + String generatedClassName = "ServerRpc_" + + requestedType.getName().replaceAll("[$.]", "_"); + + JClassType initializableInterface = typeOracle + .findType(InitializableServerRpc.class.getCanonicalName()); + + ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( + requestedType.getPackage().getName(), generatedClassName); + composer.addImplementedInterface(requestedType.getQualifiedSourceName()); + composer.addImplementedInterface(initializableInterface + .getQualifiedSourceName()); + composer.addImport(MethodInvocation.class.getCanonicalName()); + + PrintWriter printWriter = ctx.tryCreate(logger, + composer.getCreatedPackage(), + composer.getCreatedClassShortName()); + if (printWriter != null) { + logger.log(Type.INFO, "Generating client proxy for RPC interface '" + + requestedType.getQualifiedSourceName() + "'"); + SourceWriter writer = composer.createSourceWriter(ctx, printWriter); + + // constructor + writer.println("public " + generatedClassName + "() {}"); + + // initialization etc. + writeCommonFieldsAndMethods(logger, writer, typeOracle); + + // actual proxy methods forwarding calls to the server + writeRemoteProxyMethods(logger, writer, typeOracle, requestedType, + requestedType.isClassOrInterface().getInheritableMethods()); + + // End of class + writer.outdent(); + writer.println("}"); + + ctx.commit(logger, printWriter); + } + + return composer.getCreatedClassName(); + } + + private void writeCommonFieldsAndMethods(TreeLogger logger, + SourceWriter writer, TypeOracle typeOracle) { + JClassType applicationConnectionClass = typeOracle + .findType(ApplicationConnection.class.getCanonicalName()); + + // fields + writer.println("private " + ServerConnector.class.getName() + + " connector;"); + + // init method from the RPC interface + writer.println("public void initRpc(" + ServerConnector.class.getName() + + " connector) {"); + writer.indent(); + writer.println("this.connector = connector;"); + writer.outdent(); + writer.println("}"); + } + + private static void writeRemoteProxyMethods(TreeLogger logger, + SourceWriter writer, TypeOracle typeOracle, + JClassType requestedType, JMethod[] methods) { + for (JMethod m : methods) { + writer.print(m.getReadableDeclaration(false, false, false, false, + true)); + writer.println(" {"); + writer.indent(); + + writer.print("connector.getConnection().addMethodInvocationToQueue(new MethodInvocation(connector.getConnectorId(), \"" + + requestedType.getQualifiedBinaryName() + "\", \""); + writer.print(m.getName()); + writer.print("\", new Object[] {"); + // new Object[] { ... } for parameters - autoboxing etc. by the + // compiler + JParameter[] parameters = m.getParameters(); + boolean first = true; + for (JParameter p : parameters) { + if (!first) { + writer.print(", "); + } + first = false; + + writer.print(p.getName()); + } + writer.println("}), true);"); + + writer.outdent(); + writer.println("}"); + } + } +} diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java new file mode 100644 index 0000000000..d3ed9fe484 --- /dev/null +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java @@ -0,0 +1,272 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.widgetsetutils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JPrimitiveType; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.communication.JSONSerializer; +import com.vaadin.terminal.gwt.client.communication.JsonDecoder; +import com.vaadin.terminal.gwt.client.communication.JsonEncoder; +import com.vaadin.terminal.gwt.client.communication.SerializerMap; + +/** + * GWT generator for creating serializer classes for custom classes sent from + * server to client. + * + * Only fields with a correspondingly named setter are deserialized. + * + * @since 7.0 + */ +public class SerializerGenerator extends Generator { + + private static final String SUBTYPE_SEPARATOR = "___"; + private static String beanSerializerPackageName = SerializerMap.class + .getPackage().getName(); + + @Override + public String generate(TreeLogger logger, GeneratorContext context, + String beanTypeName) throws UnableToCompleteException { + JClassType beanType = context.getTypeOracle().findType(beanTypeName); + String beanSerializerClassName = getSerializerSimpleClassName(beanType); + try { + // Generate class source code + generateClass(logger, context, beanType, beanSerializerPackageName, + beanSerializerClassName); + } catch (Exception e) { + logger.log(TreeLogger.ERROR, "SerializerGenerator failed for " + + beanType.getQualifiedSourceName(), e); + throw new UnableToCompleteException(); + } + + // return the fully qualifed name of the class generated + return getFullyQualifiedSerializerClassName(beanType); + } + + /** + * Generate source code for a VaadinSerializer implementation. + * + * @param logger + * Logger object + * @param context + * Generator context + * @param beanType + * @param beanTypeName + * bean type for which the serializer is to be generated + * @param beanSerializerTypeName + * name of the serializer class to generate + */ + private void generateClass(TreeLogger logger, GeneratorContext context, + JClassType beanType, String serializerPackageName, + String serializerClassName) { + // get print writer that receives the source code + PrintWriter printWriter = null; + printWriter = context.tryCreate(logger, serializerPackageName, + serializerClassName); + + // print writer if null, source code has ALREADY been generated + if (printWriter == null) { + return; + } + Date date = new Date(); + TypeOracle typeOracle = context.getTypeOracle(); + String beanQualifiedSourceName = beanType.getQualifiedSourceName(); + logger.log(Type.DEBUG, "Processing serializable type " + + beanQualifiedSourceName + "..."); + + // init composer, set class properties, create source writer + ClassSourceFileComposerFactory composer = null; + composer = new ClassSourceFileComposerFactory(serializerPackageName, + serializerClassName); + composer.addImport(GWT.class.getName()); + composer.addImport(JSONArray.class.getName()); + // composer.addImport(JSONObject.class.getName()); + // composer.addImport(VPaintableMap.class.getName()); + composer.addImport(JsonDecoder.class.getName()); + // composer.addImport(VaadinSerializer.class.getName()); + + composer.addImplementedInterface(JSONSerializer.class.getName()); + + SourceWriter sourceWriter = composer.createSourceWriter(context, + printWriter); + sourceWriter.indent(); + + // Serializer + + // public JSONValue serialize(Object value, ConnectorMap idMapper, + // ApplicationConnection connection) { + sourceWriter.println("public " + JSONObject.class.getName() + + " serialize(" + Object.class.getName() + " value, " + + ConnectorMap.class.getName() + " idMapper, " + + ApplicationConnection.class.getName() + " connection) {"); + sourceWriter.indent(); + // MouseEventDetails castedValue = (MouseEventDetails) value; + sourceWriter.println(beanQualifiedSourceName + " castedValue = (" + + beanQualifiedSourceName + ") value;"); + // JSONObject json = new JSONObject(); + sourceWriter.println(JSONObject.class.getName() + " json = new " + + JSONObject.class.getName() + "();"); + + for (JMethod setterMethod : getSetters(beanType)) { + String setterName = setterMethod.getName(); + String fieldName = setterName.substring(3); // setZindex() -> ZIndex + String getterName = findGetter(beanType, setterMethod); + + if (getterName == null) { + logger.log(TreeLogger.ERROR, "No getter found for " + fieldName + + ". Serialization will likely fail"); + } + // json.put("button", + // JsonEncoder.encode(castedValue.getButton(), idMapper, + // connection)); + sourceWriter.println("json.put(\"" + fieldName + "\", " + + JsonEncoder.class.getName() + ".encode(castedValue." + + getterName + "(), idMapper, connection));"); + } + // return json; + sourceWriter.println("return json;"); + // } + sourceWriter.println("}"); + + // Deserializer + sourceWriter.println("public " + beanQualifiedSourceName + + " deserialize(" + JSONObject.class.getName() + " jsonValue, " + + ConnectorMap.class.getName() + " idMapper, " + + ApplicationConnection.class.getName() + " connection) {"); + sourceWriter.indent(); + + // VButtonState state = GWT.create(VButtonState.class); + sourceWriter.println(beanQualifiedSourceName + " state = GWT.create(" + + beanQualifiedSourceName + ".class);"); + for (JMethod method : getSetters(beanType)) { + String setterName = method.getName(); + String fieldName = setterName.substring(3); // setZIndex() -> ZIndex + JType setterParameterType = method.getParameterTypes()[0]; + + logger.log(Type.DEBUG, "* Processing field " + fieldName + " in " + + beanQualifiedSourceName + " (" + beanType.getName() + ")"); + + String jsonFieldName = "json_" + fieldName; + // JSONArray json_Height = (JSONArray) jsonValue.get("height"); + sourceWriter.println("JSONArray " + jsonFieldName + + " = (JSONArray) jsonValue.get(\"" + fieldName + "\");"); + + // state.setHeight((String) + // JsonDecoder.decodeValue(jsonFieldValue,idMapper, connection)); + + String fieldType; + JPrimitiveType primitiveType = setterParameterType.isPrimitive(); + if (primitiveType != null) { + // This is a primitive type -> must used the boxed type + fieldType = primitiveType.getQualifiedBoxedSourceName(); + } else { + fieldType = setterParameterType.getQualifiedSourceName(); + } + + sourceWriter.println("state." + setterName + "((" + fieldType + + ") " + JsonDecoder.class.getName() + ".decodeValue(" + + jsonFieldName + ", idMapper, connection));"); + } + + // return state; + sourceWriter.println("return state;"); + sourceWriter.println("}"); + sourceWriter.outdent(); + + // End of class + sourceWriter.println("}"); + sourceWriter.outdent(); + + // commit generated class + context.commit(logger, printWriter); + logger.log(TreeLogger.INFO, "Generated Serializer class " + + getFullyQualifiedSerializerClassName(beanType)); + + } + + private String findGetter(JClassType beanType, JMethod setterMethod) { + JType setterParameterType = setterMethod.getParameterTypes()[0]; + String fieldName = setterMethod.getName().substring(3); + if (setterParameterType.getQualifiedSourceName().equals( + boolean.class.getName())) { + return "is" + fieldName; + } else { + return "get" + fieldName; + } + } + + /** + * Returns a list of all setters found in the beanType or its parent class + * + * @param beanType + * The type to check + * @return A list of setter methods from the class and its parents + */ + protected static List<JMethod> getSetters(JClassType beanType) { + + List<JMethod> setterMethods = new ArrayList<JMethod>(); + + while (beanType != null + && !beanType.getQualifiedSourceName().equals( + Object.class.getName())) { + for (JMethod method : beanType.getMethods()) { + // Process all setters that have corresponding fields + if (!method.isPublic() || method.isStatic() + || !method.getName().startsWith("set") + || method.getParameterTypes().length != 1) { + // Not setter, skip to next method + continue; + } + setterMethods.add(method); + } + beanType = beanType.getSuperclass(); + } + + return setterMethods; + } + + private String decapitalize(String name) { + return name.substring(0, 1).toLowerCase() + name.substring(1); + } + + private static String getSerializerSimpleClassName(JClassType beanType) { + return getSimpleClassName(beanType) + "_Serializer"; + } + + private static String getSimpleClassName(JClassType type) { + if (type.isMemberType()) { + // Assumed to be static sub class + String baseName = getSimpleClassName(type.getEnclosingType()); + String name = baseName + SUBTYPE_SEPARATOR + + type.getSimpleSourceName(); + return name; + } + return type.getSimpleSourceName(); + } + + public static String getFullyQualifiedSerializerClassName(JClassType type) { + return beanSerializerPackageName + "." + + getSerializerSimpleClassName(type); + } +} diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java new file mode 100644 index 0000000000..013df4710c --- /dev/null +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerMapGenerator.java @@ -0,0 +1,320 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.widgetsetutils; + +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.TreeLogger.Type; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JParameterizedType; +import com.google.gwt.core.ext.typeinfo.JType; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.communication.ClientRpc; +import com.vaadin.terminal.gwt.client.communication.JSONSerializer; +import com.vaadin.terminal.gwt.client.communication.SerializerMap; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.client.communication.SharedState; + +/** + * GWT generator that creates a {@link SerializerMap} implementation (mapper + * from type string to serializer instance) and serializer classes for all + * subclasses of {@link SharedState}. + * + * @since 7.0 + */ +public class SerializerMapGenerator extends Generator { + + private String packageName; + private String className; + + @Override + public String generate(TreeLogger logger, GeneratorContext context, + String typeName) throws UnableToCompleteException { + + try { + TypeOracle typeOracle = context.getTypeOracle(); + Set<JClassType> typesNeedingSerializers = findTypesNeedingSerializers( + typeOracle, logger); + warnIfNotJavaSerializable(typesNeedingSerializers, typeOracle, + logger); + Set<JClassType> typesWithExistingSerializers = findTypesWithExistingSerializers( + typeOracle, logger); + Set<JClassType> serializerMappings = new HashSet<JClassType>(); + serializerMappings.addAll(typesNeedingSerializers); + serializerMappings.addAll(typesWithExistingSerializers); + // get classType and save instance variables + JClassType classType = typeOracle.getType(typeName); + packageName = classType.getPackage().getName(); + className = classType.getSimpleSourceName() + "Impl"; + // Generate class source code for SerializerMapImpl + generateSerializerMap(serializerMappings, logger, context); + + SerializerGenerator sg = new SerializerGenerator(); + for (JClassType type : typesNeedingSerializers) { + sg.generate(logger, context, type.getQualifiedSourceName()); + } + } catch (Exception e) { + logger.log(TreeLogger.ERROR, + "SerializerMapGenerator creation failed", e); + throw new UnableToCompleteException(); + } + // return the fully qualifed name of the class generated + return packageName + "." + className; + } + + /** + * Emits a warning for all classes that are used in communication but do not + * implement java.io.Serializable. Implementing java.io.Serializable is not + * needed for communication but for the server side Application to be + * serializable i.e. work in GAE for instance. + * + * @param typesNeedingSerializers + * @param typeOracle + * @param logger + */ + private void warnIfNotJavaSerializable( + Set<JClassType> typesNeedingSerializers, TypeOracle typeOracle, + TreeLogger logger) { + JClassType javaSerializable = typeOracle.findType(Serializable.class + .getName()); + for (JClassType type : typesNeedingSerializers) { + boolean serializable = type.isAssignableTo(javaSerializable); + if (!serializable) { + logger.log( + Type.ERROR, + type + + " is used in RPC or shared state but does not implement " + + Serializable.class.getName() + + ". Communication will work but the Application on server side cannot be serialized if it refers to objects of this type."); + } + } + } + + private Set<JClassType> findTypesWithExistingSerializers( + TypeOracle typeOracle, TreeLogger logger) { + JClassType serializerInterface = typeOracle + .findType(JSONSerializer.class.getName()); + Set<JClassType> types = new HashSet<JClassType>(); + for (JClassType serializer : serializerInterface.getSubtypes()) { + JType[] deserializeParamTypes = new JType[] { + typeOracle.findType(JSONObject.class.getName()), + typeOracle.findType(ConnectorMap.class.getName()), + typeOracle.findType(ApplicationConnection.class.getName()) }; + JMethod deserializeMethod = serializer.findMethod("deserialize", + deserializeParamTypes); + if (deserializeMethod == null) { + continue; + } + + types.add(deserializeMethod.getReturnType().isClass()); + } + return types; + } + + /** + * Generate source code for SerializerMapImpl + * + * @param typesNeedingSerializers + * + * @param logger + * Logger object + * @param context + * Generator context + */ + private void generateSerializerMap(Set<JClassType> typesNeedingSerializers, + TreeLogger logger, GeneratorContext context) { + // get print writer that receives the source code + PrintWriter printWriter = null; + printWriter = context.tryCreate(logger, packageName, className); + // print writer if null, source code has ALREADY been generated + if (printWriter == null) { + return; + } + Date date = new Date(); + TypeOracle typeOracle = context.getTypeOracle(); + + // init composer, set class properties, create source writer + ClassSourceFileComposerFactory composer = null; + composer = new ClassSourceFileComposerFactory(packageName, className); + composer.addImport("com.google.gwt.core.client.GWT"); + composer.addImplementedInterface(SerializerMap.class.getName()); + SourceWriter sourceWriter = composer.createSourceWriter(context, + printWriter); + sourceWriter.indent(); + + sourceWriter.println("public " + JSONSerializer.class.getName() + + " getSerializer(String type) {"); + sourceWriter.indent(); + + // TODO cache serializer instances in a map + for (JClassType type : typesNeedingSerializers) { + sourceWriter.println("if (type.equals(\"" + + type.getQualifiedBinaryName() + "\")) {"); + sourceWriter.indent(); + String serializerName = SerializerGenerator + .getFullyQualifiedSerializerClassName(type); + sourceWriter.println("return GWT.create(" + serializerName + + ".class);"); + sourceWriter.outdent(); + sourceWriter.println("}"); + logger.log(Type.INFO, "Configured serializer (" + serializerName + + ") for " + type.getName()); + } + sourceWriter + .println("throw new RuntimeException(\"No serializer found for class \"+type);"); + sourceWriter.outdent(); + sourceWriter.println("}"); + + // close generated class + sourceWriter.outdent(); + sourceWriter.println("}"); + // commit generated class + context.commit(logger, printWriter); + logger.log(Type.INFO, + "Done. (" + (new Date().getTime() - date.getTime()) / 1000 + + "seconds)"); + + } + + public Set<JClassType> findTypesNeedingSerializers(TypeOracle typeOracle, + TreeLogger logger) { + logger.log(Type.DEBUG, "Detecting serializable data types..."); + + HashSet<JClassType> types = new HashSet<JClassType>(); + + // Generate serializer classes for each subclass of SharedState + JClassType serializerType = typeOracle.findType(SharedState.class + .getName()); + JClassType[] serializerSubtypes = serializerType.getSubtypes(); + for (JClassType type : serializerSubtypes) { + types.add(type); + } + + // Serializer classes might also be needed for RPC methods + for (Class<?> cls : new Class[] { ServerRpc.class, ClientRpc.class }) { + JClassType rpcType = typeOracle.findType(cls.getName()); + JClassType[] serverRpcSubtypes = rpcType.getSubtypes(); + for (JClassType type : serverRpcSubtypes) { + addMethodParameterTypes(type, types, logger); + } + } + + // Add all types used from/in the types + for (Object t : types.toArray()) { + findSubTypesNeedingSerializers((JClassType) t, types); + } + logger.log(Type.DEBUG, "Serializable data types: " + types.toString()); + + return types; + } + + private void addMethodParameterTypes(JClassType classContainingMethods, + Set<JClassType> types, TreeLogger logger) { + for (JMethod method : classContainingMethods.getMethods()) { + if (method.getName().equals("initRpc")) { + continue; + } + for (JType type : method.getParameterTypes()) { + addTypeIfNeeded(types, type); + } + } + } + + public void findSubTypesNeedingSerializers(JClassType type, + Set<JClassType> serializableTypes) { + // Find all setters and look at their parameter type to determine if a + // new serializer is needed + for (JMethod setterMethod : SerializerGenerator.getSetters(type)) { + // The one and only parameter for the setter + JType setterType = setterMethod.getParameterTypes()[0]; + addTypeIfNeeded(serializableTypes, setterType); + } + } + + private void addTypeIfNeeded(Set<JClassType> serializableTypes, JType type) { + if (serializableTypes.contains(type)) { + return; + } + JParameterizedType parametrized = type.isParameterized(); + if (parametrized != null) { + for (JClassType parameterType : parametrized.getTypeArgs()) { + addTypeIfNeeded(serializableTypes, parameterType); + } + } + + if (serializationHandledByFramework(type)) { + return; + } + + if (serializableTypes.contains(type)) { + return; + } + + JClassType typeClass = type.isClass(); + if (typeClass != null) { + // setterTypeClass is null at least for List<String>. It is + // possible that we need to handle the cases somehow, for + // instance for List<MyObject>. + serializableTypes.add(typeClass); + findSubTypesNeedingSerializers(typeClass, serializableTypes); + } + } + + Set<Class<?>> frameworkHandledTypes = new HashSet<Class<?>>(); + { + frameworkHandledTypes.add(String.class); + frameworkHandledTypes.add(Boolean.class); + frameworkHandledTypes.add(Integer.class); + frameworkHandledTypes.add(Float.class); + frameworkHandledTypes.add(Double.class); + frameworkHandledTypes.add(Long.class); + frameworkHandledTypes.add(Enum.class); + frameworkHandledTypes.add(String[].class); + frameworkHandledTypes.add(Object[].class); + frameworkHandledTypes.add(Map.class); + frameworkHandledTypes.add(List.class); + frameworkHandledTypes.add(Set.class); + + } + + private boolean serializationHandledByFramework(JType setterType) { + // Some types are handled by the framework at the moment. See #8449 + // This method should be removed at some point. + if (setterType.isArray() != null) { + return true; + } + if (setterType.isEnum() != null) { + return true; + } + if (setterType.isPrimitive() != null) { + return true; + } + + String qualifiedName = setterType.getQualifiedSourceName(); + for (Class<?> cls : frameworkHandledTypes) { + if (qualifiedName.equals(cls.getName())) { + return true; + } + } + + return false; + } +} diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java index c1f9134e7b..6d4289b173 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/WidgetMapGenerator.java @@ -22,18 +22,20 @@ import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; -import com.vaadin.terminal.Paintable; -import com.vaadin.terminal.gwt.client.ui.VView; -import com.vaadin.ui.ClientWidget; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle; +import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector; +import com.vaadin.terminal.gwt.client.ui.root.RootConnector; +import com.vaadin.terminal.gwt.server.ClientConnector; /** * WidgetMapGenerator's are GWT generator to build WidgetMapImpl dynamically - * based on {@link ClientWidget} annotations available in workspace. By - * modifying the generator it is possible to do some fine tuning for the - * generated widgetset (aka client side engine). The components to be included - * in the client side engine can modified be overriding - * {@link #getUsedPaintables()}. + * based on {@link Connect} annotations available in workspace. By modifying the + * generator it is possible to do some fine tuning for the generated widgetset + * (aka client side engine). The components to be included in the client side + * engine can modified be overriding {@link #getUsedConnectors()}. * <p> * The generator also decides how the client side component implementations are * loaded to the browser. The default generator is @@ -41,11 +43,11 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * that loads all widget implementation on application initialization. This has * been the only option until Vaadin 6.4. * <p> - * This generator uses the loadStyle hints from the {@link ClientWidget} - * annotations. Depending on the {@link LoadStyle} used, the widget may be - * included in the initially loaded JavaScript, loaded when the application has - * started and there is no communication to server or lazy loaded when the - * implementation is absolutely needed. + * This generator uses the loadStyle hints from the {@link Connect} annotations. + * Depending on the {@link LoadStyle} used, the widget may be included in the + * initially loaded JavaScript, loaded when the application has started and + * there is no communication to server or lazy loaded when the implementation is + * absolutely needed. * <p> * The GWT module description file of the widgetset ( * <code>...Widgetset.gwt.xml</code>) can be used to define the @@ -69,6 +71,9 @@ import com.vaadin.ui.ClientWidget.LoadStyle; */ public class WidgetMapGenerator extends Generator { + private static String componentConnectorClassName = ComponentConnector.class + .getName(); + private String packageName; private String className; @@ -123,15 +128,15 @@ public class WidgetMapGenerator extends Generator { SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter); - Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation = getUsedPaintables(); + Collection<Class<? extends ComponentConnector>> connectors = getUsedConnectors(context + .getTypeOracle()); - validatePaintables(logger, context, paintablesHavingWidgetAnnotation); + validateConnectors(logger, connectors); + logConnectors(logger, context, connectors); // generator constructor source code - generateImplementationDetector(sourceWriter, - paintablesHavingWidgetAnnotation); - generateInstantiatorMethod(sourceWriter, - paintablesHavingWidgetAnnotation); + generateImplementationDetector(sourceWriter, connectors); + generateInstantiatorMethod(sourceWriter, connectors); // close generated class sourceWriter.outdent(); sourceWriter.println("}"); @@ -143,47 +148,43 @@ public class WidgetMapGenerator extends Generator { } - /** - * Verifies that all client side components are available for client side - * GWT module. - * - * @param logger - * @param context - * @param paintablesHavingWidgetAnnotation - */ - private void validatePaintables( - TreeLogger logger, - GeneratorContext context, - Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) { - TypeOracle typeOracle = context.getTypeOracle(); - - for (Iterator<Class<? extends Paintable>> iterator = paintablesHavingWidgetAnnotation - .iterator(); iterator.hasNext();) { - Class<? extends Paintable> class1 = iterator.next(); - - ClientWidget annotation = class1.getAnnotation(ClientWidget.class); - - if (typeOracle.findType(annotation.value().getName()) == null) { - // GWT widget not inherited - logger.log(Type.WARN, "Widget class " - + annotation.value().getName() - + " was not found. The component " + class1.getName() - + " will not be included in the widgetset."); - iterator.remove(); + private void validateConnectors(TreeLogger logger, + Collection<Class<? extends ComponentConnector>> connectors) { + + Iterator<Class<? extends ComponentConnector>> iter = connectors + .iterator(); + while (iter.hasNext()) { + Class<? extends ComponentConnector> connectorClass = iter.next(); + Connect annotation = connectorClass.getAnnotation(Connect.class); + if (!ClientConnector.class.isAssignableFrom(annotation.value())) { + logger.log( + Type.WARN, + "Connector class " + + annotation.value().getName() + + " defined in @Connect annotation is not a subclass of " + + ClientConnector.class.getName() + + ". The component connector " + + connectorClass.getName() + + " will not be included in the widgetset."); + iter.remove(); } - } + + } + + private void logConnectors(TreeLogger logger, GeneratorContext context, + Collection<Class<? extends ComponentConnector>> connectors) { logger.log(Type.INFO, - "Widget set will contain implementations for following components: "); + "Widget set will contain implementations for following component connectors: "); TreeSet<String> classNames = new TreeSet<String>(); HashMap<String, String> loadStyle = new HashMap<String, String>(); - for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) { - String className = class1.getCanonicalName(); + for (Class<? extends ComponentConnector> connectorClass : connectors) { + String className = connectorClass.getCanonicalName(); classNames.add(className); - if (getLoadStyle(class1) == LoadStyle.DEFERRED) { + if (getLoadStyle(connectorClass) == LoadStyle.DEFERRED) { loadStyle.put(className, "DEFERRED"); - } else if (getLoadStyle(class1) == LoadStyle.LAZY) { + } else if (getLoadStyle(connectorClass) == LoadStyle.LAZY) { loadStyle.put(className, "LAZY"); } @@ -206,57 +207,72 @@ public class WidgetMapGenerator extends Generator { * @return a collections of Vaadin components that will be added to * widgetset */ - protected Collection<Class<? extends Paintable>> getUsedPaintables() { - return ClassPathExplorer.getPaintablesHavingWidgetAnnotation(); + @SuppressWarnings("unchecked") + private Collection<Class<? extends ComponentConnector>> getUsedConnectors( + TypeOracle typeOracle) { + JClassType connectorType = typeOracle.findType(Connector.class + .getName()); + Collection<Class<? extends ComponentConnector>> connectors = new HashSet<Class<? extends ComponentConnector>>(); + for (JClassType jClassType : connectorType.getSubtypes()) { + Connect annotation = jClassType.getAnnotation(Connect.class); + if (annotation != null) { + try { + Class<? extends ComponentConnector> clazz = (Class<? extends ComponentConnector>) Class + .forName(jClassType.getQualifiedSourceName()); + connectors.add(clazz); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + } + return connectors; } /** * Returns true if the widget for given component will be lazy loaded by the * client. The default implementation reads the information from the - * {@link ClientWidget} annotation. + * {@link Connect} annotation. * <p> * The method can be overridden to optimize the widget loading mechanism. If * the Widgetset is wanted to be optimized for a network with a high latency * or for a one with a very fast throughput, it may be good to return false * for every component. * - * @param paintableType + * @param connector * @return true iff the widget for given component should be lazy loaded by * the client side engine */ - protected LoadStyle getLoadStyle(Class<? extends Paintable> paintableType) { - ClientWidget annotation = paintableType - .getAnnotation(ClientWidget.class); + protected LoadStyle getLoadStyle( + Class<? extends ComponentConnector> connector) { + Connect annotation = connector.getAnnotation(Connect.class); return annotation.loadStyle(); } private void generateInstantiatorMethod( SourceWriter sourceWriter, - Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) { + Collection<Class<? extends ComponentConnector>> connectorsHavingComponentAnnotation) { Collection<Class<?>> deferredWidgets = new LinkedList<Class<?>>(); // TODO detect if it would be noticably faster to instantiate with a // lookup with index than with the hashmap - sourceWriter - .println("public void ensureInstantiator(Class<? extends Paintable> classType) {"); + sourceWriter.println("public void ensureInstantiator(Class<? extends " + + componentConnectorClassName + "> classType) {"); sourceWriter.println("if(!instmap.containsKey(classType)){"); boolean first = true; - ArrayList<Class<? extends Paintable>> lazyLoadedWidgets = new ArrayList<Class<? extends Paintable>>(); - - HashSet<Class<? extends com.vaadin.terminal.gwt.client.Paintable>> widgetsWithInstantiator = new HashSet<Class<? extends com.vaadin.terminal.gwt.client.Paintable>>(); - - for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) { - ClientWidget annotation = class1.getAnnotation(ClientWidget.class); - Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation - .value(); - if(widgetsWithInstantiator.contains(clientClass)) { + ArrayList<Class<? extends ComponentConnector>> lazyLoadedWidgets = new ArrayList<Class<? extends ComponentConnector>>(); + + HashSet<Class<? extends com.vaadin.terminal.gwt.client.ComponentConnector>> connectorsWithInstantiator = new HashSet<Class<? extends com.vaadin.terminal.gwt.client.ComponentConnector>>(); + + for (Class<? extends ComponentConnector> class1 : connectorsHavingComponentAnnotation) { + Class<? extends ComponentConnector> clientClass = class1; + if (connectorsWithInstantiator.contains(clientClass)) { continue; } - if (clientClass == VView.class) { - // VView's are not instantiated by widgetset + if (clientClass == RootConnector.class) { + // Roots are not instantiated by widgetset continue; } if (!first) { @@ -267,8 +283,10 @@ public class WidgetMapGenerator extends Generator { sourceWriter.print("if( classType == " + clientClass.getName() + ".class) {"); - String instantiator = "new WidgetInstantiator() {\n public Paintable get() {\n return GWT.create(" - + clientClass.getName() + ".class );\n}\n}\n"; + String instantiator = "new WidgetInstantiator() {\n public " + + componentConnectorClassName + + " get() {\n return GWT.create(" + clientClass.getName() + + ".class );\n}\n}\n"; LoadStyle loadStyle = getLoadStyle(class1); @@ -295,15 +313,16 @@ public class WidgetMapGenerator extends Generator { sourceWriter.print(");"); } sourceWriter.print("}"); - widgetsWithInstantiator.add(clientClass); + connectorsWithInstantiator.add(clientClass); } sourceWriter.println("}"); sourceWriter.println("}"); - sourceWriter - .println("public Class<? extends Paintable>[] getDeferredLoadedWidgets() {"); + sourceWriter.println("public Class<? extends " + + componentConnectorClassName + + ">[] getDeferredLoadedWidgets() {"); sourceWriter.println("return new Class[] {"); first = true; @@ -312,10 +331,7 @@ public class WidgetMapGenerator extends Generator { sourceWriter.println(","); } first = false; - ClientWidget annotation = class2.getAnnotation(ClientWidget.class); - Class<? extends com.vaadin.terminal.gwt.client.Paintable> value = annotation - .value(); - sourceWriter.print(value.getName() + ".class"); + sourceWriter.print(class2.getName() + ".class"); } sourceWriter.println("};"); @@ -328,11 +344,12 @@ public class WidgetMapGenerator extends Generator { // TODO an index of last ensured widget in array - sourceWriter - .println("public Paintable instantiate(Class<? extends Paintable> classType) {"); + sourceWriter.println("public " + componentConnectorClassName + + " instantiate(Class<? extends " + componentConnectorClassName + + "> classType) {"); sourceWriter.indent(); - sourceWriter - .println("Paintable p = super.instantiate(classType); if(p!= null) return p;"); + sourceWriter.println(componentConnectorClassName + + " p = super.instantiate(classType); if(p!= null) return p;"); sourceWriter.println("return instmap.get(classType).get();"); sourceWriter.outdent(); @@ -348,30 +365,36 @@ public class WidgetMapGenerator extends Generator { */ private void generateImplementationDetector( SourceWriter sourceWriter, - Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation) { + Collection<Class<? extends ComponentConnector>> paintablesHavingWidgetAnnotation) { sourceWriter - .println("public Class<? extends Paintable> " - + "getImplementationByServerSideClassName(String fullyQualifiedName) {"); + .println("public Class<? extends " + + componentConnectorClassName + + "> " + + "getConnectorClassForServerSideClassName(String fullyQualifiedName) {"); sourceWriter.indent(); sourceWriter .println("fullyQualifiedName = fullyQualifiedName.intern();"); - for (Class<? extends Paintable> class1 : paintablesHavingWidgetAnnotation) { - ClientWidget annotation = class1.getAnnotation(ClientWidget.class); - Class<? extends com.vaadin.terminal.gwt.client.Paintable> clientClass = annotation - .value(); + for (Class<? extends ComponentConnector> connectorClass : paintablesHavingWidgetAnnotation) { + Class<? extends ClientConnector> clientConnectorClass = getClientConnectorClass(connectorClass); sourceWriter.print("if ( fullyQualifiedName == \""); - sourceWriter.print(class1.getName()); + sourceWriter.print(clientConnectorClass.getName()); sourceWriter.print("\" ) { ensureInstantiator(" - + clientClass.getName() + ".class); return "); - sourceWriter.print(clientClass.getName()); + + connectorClass.getName() + ".class); return "); + sourceWriter.print(connectorClass.getName()); sourceWriter.println(".class;}"); sourceWriter.print("else "); } - sourceWriter - .println("return com.vaadin.terminal.gwt.client.ui.VUnknownComponent.class;"); + sourceWriter.println("return " + + UnknownComponentConnector.class.getName() + ".class;"); sourceWriter.outdent(); sourceWriter.println("}"); } + + private static Class<? extends ClientConnector> getClientConnectorClass( + Class<? extends ComponentConnector> connectorClass) { + Connect annotation = connectorClass.getAnnotation(Connect.class); + return (Class<? extends ClientConnector>) annotation.value(); + } } diff --git a/src/com/vaadin/tools/ReflectTools.java b/src/com/vaadin/tools/ReflectTools.java index 9f0667f90e..ea2afae301 100644 --- a/src/com/vaadin/tools/ReflectTools.java +++ b/src/com/vaadin/tools/ReflectTools.java @@ -3,6 +3,9 @@ */ package com.vaadin.tools; +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** @@ -37,4 +40,87 @@ public class ReflectTools { throw new ExceptionInInitializerError(e); } } + + /** + * Returns the value of the java field. + * <p> + * Uses getter if present, otherwise tries to access even private fields + * directly. + * + * @param object + * The object containing the field + * @param field + * The field we want to get the value for + * @return The value of the field in the object + * @throws InvocationTargetException + * If the value could not be retrieved + * @throws IllegalAccessException + * If the value could not be retrieved + * @throws IllegalArgumentException + * If the value could not be retrieved + */ + public static Object getJavaFieldValue(Object object, + java.lang.reflect.Field field) throws IllegalArgumentException, + IllegalAccessException, InvocationTargetException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + Method getter = pd.getReadMethod(); + if (getter != null) { + return getter.invoke(object, (Object[]) null); + } + } catch (IntrospectionException e1) { + // Ignore this and try to get directly using the field + } + + // Try to get the value or throw an exception + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + return field.get(object); + } + + /** + * Sets the value of a java field. + * <p> + * Uses setter if present, otherwise tries to access even private fields + * directly. + * + * @param object + * The object containing the field + * @param field + * The field we want to set the value for + * @param value + * The value to set + * @throws IllegalAccessException + * If the value could not be assigned to the field + * @throws IllegalArgumentException + * If the value could not be assigned to the field + * @throws InvocationTargetException + * If the value could not be assigned to the field + */ + public static void setJavaFieldValue(Object object, + java.lang.reflect.Field field, Object value) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + PropertyDescriptor pd; + try { + pd = new PropertyDescriptor(field.getName(), object.getClass()); + Method setter = pd.getWriteMethod(); + if (setter != null) { + // Exceptions are thrown forward if this fails + setter.invoke(object, value); + } + } catch (IntrospectionException e1) { + // Ignore this and try to set directly using the field + } + + // Try to set the value directly to the field or throw an exception + if (!field.isAccessible()) { + // Try to gain access even if field is private + field.setAccessible(true); + } + field.set(object, value); + } } diff --git a/src/com/vaadin/ui/AbsoluteLayout.java b/src/com/vaadin/ui/AbsoluteLayout.java index 7872e05774..9ba005f75a 100644 --- a/src/com/vaadin/ui/AbsoluteLayout.java +++ b/src/com/vaadin/ui/AbsoluteLayout.java @@ -4,20 +4,20 @@ package com.vaadin.ui; import java.io.Serializable; -import java.util.Collection; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashSet; +import java.util.LinkedHashMap; import java.util.Map; import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.absolutelayout.AbsoluteLayoutServerRpc; +import com.vaadin.terminal.gwt.client.ui.absolutelayout.AbsoluteLayoutState; /** * AbsoluteLayout is a layout implementation that mimics html absolute @@ -25,31 +25,39 @@ import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout; * */ @SuppressWarnings("serial") -@ClientWidget(VAbsoluteLayout.class) public class AbsoluteLayout extends AbstractLayout implements LayoutClickNotifier { - private static final String CLICK_EVENT = EventId.LAYOUT_CLICK; - - // The components in the layout - private Collection<Component> components = new LinkedHashSet<Component>(); + private AbsoluteLayoutServerRpc rpc = new AbsoluteLayoutServerRpc() { + public void layoutClick(MouseEventDetails mouseDetails, + Connector clickedConnector) { + fireEvent(LayoutClickEvent.createEvent(AbsoluteLayout.this, + mouseDetails, clickedConnector)); + } + }; // Maps each component to a position - private Map<Component, ComponentPosition> componentToCoordinates = new HashMap<Component, ComponentPosition>(); + private LinkedHashMap<Component, ComponentPosition> componentToCoordinates = new LinkedHashMap<Component, ComponentPosition>(); /** * Creates an AbsoluteLayout with full size. */ public AbsoluteLayout() { + registerRpc(rpc); setSizeFull(); } + @Override + public AbsoluteLayoutState getState() { + return (AbsoluteLayoutState) super.getState(); + } + /** * Gets an iterator for going through all components enclosed in the * absolute layout. */ public Iterator<Component> getComponentIterator() { - return components.iterator(); + return componentToCoordinates.keySet().iterator(); } /** @@ -59,7 +67,7 @@ public class AbsoluteLayout extends AbstractLayout implements * @return the number of contained components */ public int getComponentCount() { - return components.size(); + return componentToCoordinates.size(); } /** @@ -69,8 +77,7 @@ public class AbsoluteLayout extends AbstractLayout implements public void replaceComponent(Component oldComponent, Component newComponent) { ComponentPosition position = getPosition(oldComponent); removeComponent(oldComponent); - addComponent(newComponent); - componentToCoordinates.put(newComponent, position); + addComponent(newComponent, position); } /* @@ -82,29 +89,7 @@ public class AbsoluteLayout extends AbstractLayout implements */ @Override public void addComponent(Component c) { - components.add(c); - try { - super.addComponent(c); - requestRepaint(); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui - * .Component) - */ - @Override - public void removeComponent(Component c) { - components.remove(c); - componentToCoordinates.remove(c); - super.removeComponent(c); - requestRepaint(); + addComponent(c, new ComponentPosition()); } /** @@ -122,28 +107,90 @@ public class AbsoluteLayout extends AbstractLayout implements * The css position string */ public void addComponent(Component c, String cssPosition) { + ComponentPosition position = new ComponentPosition(); + position.setCSSString(cssPosition); + addComponent(c, position); + } + + /** + * Adds the component using the given position. Ensures the position is only + * set if the component is added correctly. + * + * @param c + * The component to add + * @param position + * The position info for the component. Must not be null. + * @throws IllegalArgumentException + * If adding the component failed + */ + private void addComponent(Component c, ComponentPosition position) + throws IllegalArgumentException { /* * Create position instance and add it to componentToCoordinates map. We * need to do this before we call addComponent so the attachListeners * can access this position. #6368 */ - ComponentPosition position = new ComponentPosition(); - position.setCSSString(cssPosition); - componentToCoordinates.put(c, position); - + internalSetPosition(c, position); try { - addComponent(c); - + super.addComponent(c); } catch (IllegalArgumentException e) { - // Remove component coordinates if adding fails - componentToCoordinates.remove(c); + internalRemoveComponent(c); throw e; } + requestRepaint(); + } + + /** + * Removes the component from all internal data structures. Does not + * actually remove the component from the layout (this is assumed to have + * been done by the caller). + * + * @param c + * The component to remove + */ + private void internalRemoveComponent(Component c) { + componentToCoordinates.remove(c); + } + + @Override + public void updateState() { + super.updateState(); + + // This could be in internalRemoveComponent and internalSetComponent if + // Map<Connector,String> was supported. We cannot get the child + // connectorId unless the component is attached to the application so + // the String->String map cannot be populated in internal* either. + Map<String, String> connectorToPosition = new HashMap<String, String>(); + for (Component c : this) { + connectorToPosition.put(c.getConnectorId(), getPosition(c) + .getCSSString()); + } + getState().setConnectorToCssPosition(connectorToPosition); + + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui + * .Component) + */ + @Override + public void removeComponent(Component c) { + internalRemoveComponent(c); + super.removeComponent(c); + requestRepaint(); } /** * Gets the position of a component in the layout. Returns null if component * is not attached to the layout. + * <p> + * Note that you cannot update the position by updating this object. Call + * {@link #setPosition(Component, ComponentPosition)} with the updated + * {@link ComponentPosition} object. + * </p> * * @param component * The component which position is needed @@ -152,15 +199,36 @@ public class AbsoluteLayout extends AbstractLayout implements * layout. */ public ComponentPosition getPosition(Component component) { - if (component.getParent() != this) { - return null; - } else if (componentToCoordinates.containsKey(component)) { - return componentToCoordinates.get(component); - } else { - ComponentPosition coords = new ComponentPosition(); - componentToCoordinates.put(component, coords); - return coords; + return componentToCoordinates.get(component); + } + + /** + * Sets the position of a component in the layout. + * + * @param component + * @param position + */ + public void setPosition(Component component, ComponentPosition position) { + if (!componentToCoordinates.containsKey(component)) { + throw new IllegalArgumentException( + "Component must be a child of this layout"); } + internalSetPosition(component, position); + } + + /** + * Updates the position for a component. Caller must ensure component is a + * child of this layout. + * + * @param component + * The component. Must be a child for this layout. Not enforced. + * @param position + * New position. Must not be null. + */ + private void internalSetPosition(Component component, + ComponentPosition position) { + componentToCoordinates.put(component, position); + requestRepaint(); } /** @@ -176,10 +244,10 @@ public class AbsoluteLayout extends AbstractLayout implements private Float bottomValue = null; private Float leftValue = null; - private int topUnits; - private int rightUnits; - private int bottomUnits; - private int leftUnits; + private Unit topUnits = Unit.PIXELS; + private Unit rightUnits = Unit.PIXELS; + private Unit bottomUnits = Unit.PIXELS; + private Unit leftUnits = Unit.PIXELS; /** * Sets the position attributes using CSS syntax. Attributes not @@ -193,7 +261,7 @@ public class AbsoluteLayout extends AbstractLayout implements */ public void setCSSString(String css) { topValue = rightValue = bottomValue = leftValue = null; - topUnits = rightUnits = bottomUnits = leftUnits = 0; + topUnits = rightUnits = bottomUnits = leftUnits = Unit.PIXELS; zIndex = -1; if (css == null) { return; @@ -215,24 +283,25 @@ public class AbsoluteLayout extends AbstractLayout implements } else { value = ""; } - String unit = value.replaceAll("[0-9\\.\\-]+", ""); - if (!unit.equals("")) { - value = value.substring(0, value.indexOf(unit)).trim(); + String symbol = value.replaceAll("[0-9\\.\\-]+", ""); + if (!symbol.equals("")) { + value = value.substring(0, value.indexOf(symbol)) + .trim(); } float v = Float.parseFloat(value); - int unitInt = parseCssUnit(unit); + Unit unit = Unit.getUnitFromSymbol(symbol); if (key.equals("top")) { topValue = v; - topUnits = unitInt; + topUnits = unit; } else if (key.equals("right")) { rightValue = v; - rightUnits = unitInt; + rightUnits = unit; } else if (key.equals("bottom")) { bottomValue = v; - bottomUnits = unitInt; + bottomUnits = unit; } else if (key.equals("left")) { leftValue = v; - leftUnits = unitInt; + leftUnits = unit; } } } @@ -240,23 +309,6 @@ public class AbsoluteLayout extends AbstractLayout implements } /** - * Parses a string and checks if a unit is found. If a unit is not found - * from the string the unit pixels is used. - * - * @param string - * The string to parse the unit from - * @return The found unit - */ - private int parseCssUnit(String string) { - for (int i = 0; i < UNIT_SYMBOLS.length; i++) { - if (UNIT_SYMBOLS[i].equals(string)) { - return i; - } - } - return 0; // defaults to px (eg. top:0;) - } - - /** * Converts the internal values into a valid CSS string. * * @return A valid CSS string @@ -264,16 +316,16 @@ public class AbsoluteLayout extends AbstractLayout implements public String getCSSString() { String s = ""; if (topValue != null) { - s += "top:" + topValue + UNIT_SYMBOLS[topUnits] + ";"; + s += "top:" + topValue + topUnits.getSymbol() + ";"; } if (rightValue != null) { - s += "right:" + rightValue + UNIT_SYMBOLS[rightUnits] + ";"; + s += "right:" + rightValue + rightUnits.getSymbol() + ";"; } if (bottomValue != null) { - s += "bottom:" + bottomValue + UNIT_SYMBOLS[bottomUnits] + ";"; + s += "bottom:" + bottomValue + bottomUnits.getSymbol() + ";"; } if (leftValue != null) { - s += "left:" + leftValue + UNIT_SYMBOLS[leftUnits] + ";"; + s += "left:" + leftValue + leftUnits.getSymbol() + ";"; } if (zIndex >= 0) { s += "z-index:" + zIndex + ";"; @@ -291,7 +343,7 @@ public class AbsoluteLayout extends AbstractLayout implements * The unit of the 'top' attribute. See UNIT_SYMBOLS for a * description of the available units. */ - public void setTop(Float topValue, int topUnits) { + public void setTop(Float topValue, Unit topUnits) { this.topValue = topValue; this.topUnits = topUnits; requestRepaint(); @@ -307,7 +359,7 @@ public class AbsoluteLayout extends AbstractLayout implements * The unit of the 'right' attribute. See UNIT_SYMBOLS for a * description of the available units. */ - public void setRight(Float rightValue, int rightUnits) { + public void setRight(Float rightValue, Unit rightUnits) { this.rightValue = rightValue; this.rightUnits = rightUnits; requestRepaint(); @@ -323,7 +375,7 @@ public class AbsoluteLayout extends AbstractLayout implements * The unit of the 'bottom' attribute. See UNIT_SYMBOLS for a * description of the available units. */ - public void setBottom(Float bottomValue, int bottomUnits) { + public void setBottom(Float bottomValue, Unit bottomUnits) { this.bottomValue = bottomValue; this.bottomUnits = bottomUnits; requestRepaint(); @@ -339,7 +391,7 @@ public class AbsoluteLayout extends AbstractLayout implements * The unit of the 'left' attribute. See UNIT_SYMBOLS for a * description of the available units. */ - public void setLeft(Float leftValue, int leftUnits) { + public void setLeft(Float leftValue, Unit leftUnits) { this.leftValue = leftValue; this.leftUnits = leftUnits; requestRepaint(); @@ -456,7 +508,7 @@ public class AbsoluteLayout extends AbstractLayout implements * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public int getTopUnits() { + public Unit getTopUnits() { return topUnits; } @@ -467,7 +519,7 @@ public class AbsoluteLayout extends AbstractLayout implements * See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public void setTopUnits(int topUnits) { + public void setTopUnits(Unit topUnits) { this.topUnits = topUnits; requestRepaint(); } @@ -478,7 +530,7 @@ public class AbsoluteLayout extends AbstractLayout implements * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public int getRightUnits() { + public Unit getRightUnits() { return rightUnits; } @@ -489,7 +541,7 @@ public class AbsoluteLayout extends AbstractLayout implements * See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public void setRightUnits(int rightUnits) { + public void setRightUnits(Unit rightUnits) { this.rightUnits = rightUnits; requestRepaint(); } @@ -500,7 +552,7 @@ public class AbsoluteLayout extends AbstractLayout implements * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public int getBottomUnits() { + public Unit getBottomUnits() { return bottomUnits; } @@ -511,7 +563,7 @@ public class AbsoluteLayout extends AbstractLayout implements * See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public void setBottomUnits(int bottomUnits) { + public void setBottomUnits(Unit bottomUnits) { this.bottomUnits = bottomUnits; requestRepaint(); } @@ -522,7 +574,7 @@ public class AbsoluteLayout extends AbstractLayout implements * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public int getLeftUnits() { + public Unit getLeftUnits() { return leftUnits; } @@ -533,7 +585,7 @@ public class AbsoluteLayout extends AbstractLayout implements * See {@link Sizeable} UNIT_SYMBOLS for a description of the * available units. */ - public void setLeftUnits(int leftUnits) { + public void setLeftUnits(Unit leftUnits) { this.leftUnits = leftUnits; requestRepaint(); } @@ -559,31 +611,15 @@ public class AbsoluteLayout extends AbstractLayout implements } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.AbstractLayout#paintContent(com.vaadin.terminal.PaintTarget - * ) - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - for (Component component : components) { - target.startTag("cc"); - target.addAttribute("css", getPosition(component).getCSSString()); - component.paint(target); - target.endTag("cc"); - } - } - public void addListener(LayoutClickListener listener) { - addListener(CLICK_EVENT, LayoutClickEvent.class, listener, + addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener, LayoutClickListener.clickMethod); } public void removeListener(LayoutClickListener listener) { - removeListener(CLICK_EVENT, LayoutClickEvent.class, listener); + removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener); } } diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java index 0ca9cc6bd4..79a07ae00e 100644 --- a/src/com/vaadin/ui/AbstractComponent.java +++ b/src/com/vaadin/ui/AbstractComponent.java @@ -5,28 +5,41 @@ package com.vaadin.ui; import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.vaadin.Application; +import com.vaadin.event.ActionManager; import com.vaadin.event.EventRouter; import com.vaadin.event.MethodEventSource; +import com.vaadin.event.ShortcutListener; import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; import com.vaadin.terminal.Terminal; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.communication.ClientRpc; +import com.vaadin.terminal.gwt.client.communication.ServerRpc; +import com.vaadin.terminal.gwt.server.ClientMethodInvocation; import com.vaadin.terminal.gwt.server.ComponentSizeValidator; +import com.vaadin.terminal.gwt.server.ResourceReference; +import com.vaadin.terminal.gwt.server.RpcManager; +import com.vaadin.terminal.gwt.server.RpcTarget; +import com.vaadin.terminal.gwt.server.ServerRpcManager; import com.vaadin.tools.ReflectTools; /** @@ -46,50 +59,15 @@ public abstract class AbstractComponent implements Component, MethodEventSource /* Private members */ /** - * Style names. - */ - private ArrayList<String> styles; - - /** - * Caption text. - */ - private String caption; - - /** * Application specific data object. The component does not use or modify * this. */ private Object applicationData; /** - * Icon to be shown together with caption. - */ - private Resource icon; - - /** - * Is the component enabled (its normal usage is allowed). - */ - private boolean enabled = true; - - /** - * Is the component visible (it is rendered). - */ - private boolean visible = true; - - /** - * Is the component read-only ? - */ - private boolean readOnly = false; - - /** - * Description of the usage (XML). - */ - private String description = null; - - /** * The container this component resides in. */ - private Component parent = null; + private HasComponents parent = null; /** * The EventRouter used for the event model. @@ -97,22 +75,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource private EventRouter eventRouter = null; /** - * A set of event identifiers with registered listeners. - */ - private Set<String> eventIdentifiers = null; - - /** * The internal error message of the component. */ private ErrorMessage componentError = null; /** - * Immediate mode: if true, all variable changes are required to be sent - * from the terminal immediately. - */ - private boolean immediate = false; - - /** * Locale of this component. */ private Locale locale; @@ -127,24 +94,48 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ private LinkedList<RepaintRequestListener> repaintRequestListeners = null; - /** - * Are all the repaint listeners notified about recent changes ? - */ - private boolean repaintRequestListenersNotified = false; - - private String testingId; - /* Sizeable fields */ private float width = SIZE_UNDEFINED; private float height = SIZE_UNDEFINED; - private int widthUnit = UNITS_PIXELS; - private int heightUnit = UNITS_PIXELS; + private Unit widthUnit = Unit.PIXELS; + private Unit heightUnit = Unit.PIXELS; private static final Pattern sizePattern = Pattern .compile("^(-?\\d+(\\.\\d+)?)(%|px|em|ex|in|cm|mm|pt|pc)?$"); private ComponentErrorHandler errorHandler = null; + /** + * Keeps track of the Actions added to this component; the actual + * handling/notifying is delegated, usually to the containing window. + */ + private ActionManager actionManager; + + /** + * A map from client to server RPC interface class to the RPC call manager + * that handles incoming RPC calls for that interface. + */ + private Map<Class<?>, RpcManager> rpcManagerMap = new HashMap<Class<?>, RpcManager>(); + + /** + * A map from server to client RPC interface class to the RPC proxy that + * sends ourgoing RPC calls for that interface. + */ + private Map<Class<?>, ClientRpc> rpcProxyMap = new HashMap<Class<?>, ClientRpc>(); + + /** + * Shared state object to be communicated from the server to the client when + * modified. + */ + private ComponentState sharedState; + + /** + * Pending RPC method invocations to be sent. + */ + private ArrayList<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>(); + + private String connectorId; + /* Constructor */ /** @@ -157,11 +148,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource /* Get/Set component properties */ public void setDebugId(String id) { - testingId = id; + getState().setDebugId(id); } public String getDebugId() { - return testingId; + return getState().getDebugId(); } /** @@ -179,8 +170,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource /** * Sets and replaces all previous style names of the component. This method - * will trigger a {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * will trigger a {@link RepaintRequestEvent}. * * @param style * the new style of the component. @@ -199,8 +189,9 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ public String getStyleName() { String s = ""; - if (styles != null) { - for (final Iterator<String> it = styles.iterator(); it.hasNext();) { + if (getState().getStyles() != null) { + for (final Iterator<String> it = getState().getStyles().iterator(); it + .hasNext();) { s += it.next(); if (it.hasNext()) { s += " "; @@ -216,13 +207,14 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ public void setStyleName(String style) { if (style == null || "".equals(style)) { - styles = null; + getState().setStyles(null); requestRepaint(); return; } - if (styles == null) { - styles = new ArrayList<String>(); + if (getState().getStyles() == null) { + getState().setStyles(new ArrayList<String>()); } + List<String> styles = getState().getStyles(); styles.clear(); String[] styleParts = style.split(" +"); for (String part : styleParts) { @@ -237,9 +229,18 @@ public abstract class AbstractComponent implements Component, MethodEventSource if (style == null || "".equals(style)) { return; } - if (styles == null) { - styles = new ArrayList<String>(); + if (style.contains(" ")) { + // Split space separated style names and add them one by one. + for (String realStyle : style.split(" ")) { + addStyleName(realStyle); + } + return; } + + if (getState().getStyles() == null) { + getState().setStyles(new ArrayList<String>()); + } + List<String> styles = getState().getStyles(); if (!styles.contains(style)) { styles.add(style); requestRepaint(); @@ -247,11 +248,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource } public void removeStyleName(String style) { - if (styles != null) { + if (getState().getStyles() != null) { String[] styleParts = style.split(" +"); for (String part : styleParts) { if (part.length() > 0) { - styles.remove(part); + getState().getStyles().remove(part); } } requestRepaint(); @@ -263,20 +264,19 @@ public abstract class AbstractComponent implements Component, MethodEventSource * the default documentation from implemented interface. */ public String getCaption() { - return caption; + return getState().getCaption(); } /** * Sets the component's caption <code>String</code>. Caption is the visible * name of the component. This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * {@link RepaintRequestEvent}. * * @param caption * the new caption <code>String</code> for the component. */ public void setCaption(String caption) { - this.caption = caption; + getState().setCaption(caption); requestRepaint(); } @@ -319,6 +319,8 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ public void setLocale(Locale locale) { this.locale = locale; + + // FIXME: Reload value if there is a converter requestRepaint(); } @@ -327,58 +329,71 @@ public abstract class AbstractComponent implements Component, MethodEventSource * use the default documentation from implemented interface. */ public Resource getIcon() { - return icon; + ResourceReference ref = ((ResourceReference) getState().getIcon()); + if (ref == null) { + return null; + } else { + return ref.getResource(); + } } /** * Sets the component's icon. This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * {@link RepaintRequestEvent}. * * @param icon * the icon to be shown with the component's caption. */ public void setIcon(Resource icon) { - this.icon = icon; + if (icon == null) { + getState().setIcon(null); + } else { + getState().setIcon(new ResourceReference(icon)); + } requestRepaint(); } /* - * Tests if the component is enabled or not. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. + * (non-Javadoc) + * + * @see com.vaadin.ui.Component#isEnabled() */ public boolean isEnabled() { - return enabled && (parent == null || parent.isEnabled()) && isVisible(); + return getState().isEnabled(); } /* - * Enables or disables the component. Don't add a JavaDoc comment here, we - * use the default documentation from implemented interface. + * (non-Javadoc) + * + * @see com.vaadin.ui.Component#setEnabled(boolean) */ public void setEnabled(boolean enabled) { - if (this.enabled != enabled) { - boolean wasEnabled = this.enabled; - boolean wasEnabledInContext = isEnabled(); - - this.enabled = enabled; - - boolean isEnabled = enabled; - boolean isEnabledInContext = isEnabled(); - - // If the actual enabled state (as rendered, in context) has not - // changed we do not need to repaint except if the parent is - // invisible. - // If the parent is invisible we must request a repaint so the - // component is repainted with the new enabled state when the parent - // is set visible again. This workaround is needed as isEnabled - // checks isVisible. - boolean needRepaint = (wasEnabledInContext != isEnabledInContext) - || (wasEnabled != isEnabled && (getParent() == null || !getParent() - .isVisible())); - - if (needRepaint) { - requestRepaint(); + if (getState().isEnabled() != enabled) { + getState().setEnabled(enabled); + requestRepaint(); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.Connector#isConnectorEnabled() + */ + public boolean isConnectorEnabled() { + if (getParent() == null) { + // No parent -> the component cannot receive updates from the client + return false; + } else { + boolean thisEnabledAndVisible = isEnabled() && isVisible(); + if (!thisEnabledAndVisible) { + return false; + } + + if (!getParent().isConnectorEnabled()) { + return false; } + + return getParent().isComponentVisible(this); } } @@ -388,13 +403,12 @@ public abstract class AbstractComponent implements Component, MethodEventSource * interface. */ public boolean isImmediate() { - return immediate; + return getState().isImmediate(); } /** * Sets the component's immediate mode to the specified status. This method - * will trigger a {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * will trigger a {@link RepaintRequestEvent}. * * @param immediate * the boolean value specifying if the component should be in the @@ -402,7 +416,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see Component#isImmediate() */ public void setImmediate(boolean immediate) { - this.immediate = immediate; + getState().setImmediate(immediate); requestRepaint(); } @@ -412,7 +426,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see com.vaadin.ui.Component#isVisible() */ public boolean isVisible() { - return visible && (getParent() == null || getParent().isVisible()); + return getState().isVisible(); } /* @@ -421,14 +435,16 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see com.vaadin.ui.Component#setVisible(boolean) */ public void setVisible(boolean visible) { + if (getState().isVisible() == visible) { + return; + } - if (this.visible != visible) { - this.visible = visible; - // Instead of requesting repaint normally we - // fire the event directly to assure that the - // event goes through event in the component might - // now be invisible - fireRequestRepaintEvent(null); + getState().setVisible(visible); + requestRepaint(); + if (getParent() != null) { + // Must always repaint the parent (at least the hierarchy) when + // visibility of a child component changes. + getParent().requestRepaint(); } } @@ -490,14 +506,13 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @return component's description <code>String</code> */ public String getDescription() { - return description; + return getState().getDescription(); } /** * Sets the component's description. See {@link #getDescription()} for more * information on what the description is. This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * {@link RepaintRequestEvent}. * * The description is displayed as HTML/XHTML in tooltips or directly in * certain components so care should be taken to avoid creating the @@ -507,7 +522,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * the new description string for the component. */ public void setDescription(String description) { - this.description = description; + getState().setDescription(description); requestRepaint(); } @@ -515,15 +530,40 @@ public abstract class AbstractComponent implements Component, MethodEventSource * Gets the component's parent component. Don't add a JavaDoc comment here, * we use the default documentation from implemented interface. */ - public Component getParent() { + public HasComponents getParent() { return parent; } + /** + * Returns the closest ancestor with the given type. + * <p> + * To find the Window that contains the component, use {@code Window w = + * getParent(Window.class);} + * </p> + * + * @param <T> + * The type of the ancestor + * @param parentType + * The ancestor class we are looking for + * @return The first ancestor that can be assigned to the given class. Null + * if no ancestor with the correct type could be found. + */ + public <T extends HasComponents> T findAncestor(Class<T> parentType) { + HasComponents p = getParent(); + while (p != null) { + if (parentType.isAssignableFrom(p.getClass())) { + return parentType.cast(p); + } + p = p.getParent(); + } + return null; + } + /* * Sets the parent component. Don't add a JavaDoc comment here, we use the * default documentation from implemented interface. */ - public void setParent(Component parent) { + public void setParent(HasComponents parent) { // If the parent is not changed, don't do anything if (parent == this.parent) { @@ -593,7 +633,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * here, we use the default documentation from implemented interface. */ public boolean isReadOnly() { - return readOnly; + return getState().isReadOnly(); } /* @@ -601,7 +641,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * use the default documentation from implemented interface. */ public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; + getState().setReadOnly(readOnly); requestRepaint(); } @@ -609,11 +649,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource * Gets the parent window of the component. Don't add a JavaDoc comment * here, we use the default documentation from implemented interface. */ - public Window getWindow() { + public Root getRoot() { if (parent == null) { return null; } else { - return parent.getWindow(); + return parent.getRoot(); } } @@ -623,18 +663,12 @@ public abstract class AbstractComponent implements Component, MethodEventSource * interface. */ public void attach() { + getRoot().componentAttached(this); requestRepaint(); - if (!visible) { - /* - * Bypass the repaint optimization in childRequestedRepaint method - * when attaching. When reattaching (possibly moving) -> must - * repaint - */ - fireRequestRepaintEvent(null); - } if (delayedFocus) { focus(); } + setActionManagerViewer(); } /* @@ -642,6 +676,12 @@ public abstract class AbstractComponent implements Component, MethodEventSource * we use the default documentation from implemented interface. */ public void detach() { + if (actionManager != null) { + // Remove any existing viewer. Root cast is just to make the + // compiler happy + actionManager.setViewer((Root) null); + } + getRoot().componentDetached(this); } /** @@ -651,7 +691,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource if (this instanceof Focusable) { final Application app = getApplication(); if (app != null) { - getWindow().setFocusedComponent((Focusable) this); + getRoot().setFocusedComponent((Focusable) this); delayedFocus = false; } else { delayedFocus = true; @@ -686,115 +726,16 @@ public abstract class AbstractComponent implements Component, MethodEventSource } } - /* Component painting */ - - /* Documented in super interface */ - public void requestRepaintRequests() { - repaintRequestListenersNotified = false; - } - - /** - * - * <p> - * Paints the Paintable into a UIDL stream. This method creates the UIDL - * sequence describing it and outputs it to the given UIDL stream. - * </p> - * - * <p> - * It is called when the contents of the component should be painted in - * response to the component first being shown or having been altered so - * that its visual representation is changed. - * </p> - * - * <p> - * <b>Do not override this to paint your component.</b> Override - * {@link #paintContent(PaintTarget)} instead. - * </p> - * - * - * @param target - * the target UIDL stream where the component should paint itself - * to. - * @throws PaintException - * if the paint operation failed. - */ - public void paint(PaintTarget target) throws PaintException { - final String tag = target.getTag(this); - if (!target.startTag(this, tag) || repaintRequestListenersNotified) { - - // Paint the contents of the component - - // Only paint content of visible components. - if (isVisible()) { - if (getHeight() >= 0 - && (getHeightUnits() != UNITS_PERCENTAGE || ComponentSizeValidator - .parentCanDefineHeight(this))) { - target.addAttribute("height", "" + getCSSHeight()); - } - - if (getWidth() >= 0 - && (getWidthUnits() != UNITS_PERCENTAGE || ComponentSizeValidator - .parentCanDefineWidth(this))) { - target.addAttribute("width", "" + getCSSWidth()); - } - if (styles != null && styles.size() > 0) { - target.addAttribute("style", getStyle()); - } - if (isReadOnly()) { - target.addAttribute("readonly", true); - } - - if (isImmediate()) { - target.addAttribute("immediate", true); - } - if (!isEnabled()) { - target.addAttribute("disabled", true); - } - if (getCaption() != null) { - target.addAttribute("caption", getCaption()); - } - if (getIcon() != null) { - target.addAttribute("icon", getIcon()); - } - - if (getDescription() != null && getDescription().length() > 0) { - target.addAttribute("description", getDescription()); - } - - if (eventIdentifiers != null) { - target.addAttribute("eventListeners", - eventIdentifiers.toArray()); - } - - paintContent(target); - - final ErrorMessage error = getErrorMessage(); - if (error != null) { - error.paint(target); - } - } else { - target.addAttribute("invisible", true); - } - } else { - - // Contents have not changed, only cached presentation can be used - target.addAttribute("cached", true); - } - target.endTag(tag); - - repaintRequestListenersNotified = false; - } - /** * Build CSS compatible string representation of height. * * @return CSS height */ private String getCSSHeight() { - if (getHeightUnits() == UNITS_PIXELS) { - return ((int) getHeight()) + UNIT_SYMBOLS[getHeightUnits()]; + if (getHeightUnits() == Unit.PIXELS) { + return ((int) getHeight()) + getHeightUnits().getSymbol(); } else { - return getHeight() + UNIT_SYMBOLS[getHeightUnits()]; + return getHeight() + getHeightUnits().getSymbol(); } } @@ -804,47 +745,106 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @return CSS width */ private String getCSSWidth() { - if (getWidthUnits() == UNITS_PIXELS) { - return ((int) getWidth()) + UNIT_SYMBOLS[getWidthUnits()]; + if (getWidthUnits() == Unit.PIXELS) { + return ((int) getWidth()) + getWidthUnits().getSymbol(); } else { - return getWidth() + UNIT_SYMBOLS[getWidthUnits()]; + return getWidth() + getWidthUnits().getSymbol(); } } /** - * Paints any needed component-specific things to the given UIDL stream. The - * more general {@link #paint(PaintTarget)} method handles all general - * attributes common to all components, and it calls this method to paint - * any component-specific attributes to the UIDL stream. + * Returns the shared state bean with information to be sent from the server + * to the client. * - * @param target - * the target UIDL stream where the component should paint itself - * to - * @throws PaintException - * if the paint operation failed. + * Subclasses should override this method and set any relevant fields of the + * state returned by super.getState(). + * + * @since 7.0 + * + * @return updated component shared state + */ + public ComponentState getState() { + if (null == sharedState) { + sharedState = createState(); + } + return sharedState; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.Component#updateState() */ - public void paintContent(PaintTarget target) throws PaintException { + public void updateState() { + // TODO This logic should be on the client side and the state should + // simply be a data object with "width" and "height". + if (getHeight() >= 0 + && (getHeightUnits() != Unit.PERCENTAGE || ComponentSizeValidator + .parentCanDefineHeight(this))) { + getState().setHeight("" + getCSSHeight()); + } else { + getState().setHeight(""); + } + + if (getWidth() >= 0 + && (getWidthUnits() != Unit.PERCENTAGE || ComponentSizeValidator + .parentCanDefineWidth(this))) { + getState().setWidth("" + getCSSWidth()); + } else { + getState().setWidth(""); + } + ErrorMessage error = getErrorMessage(); + if (null != error) { + getState().setErrorMessage(error.getFormattedHtmlMessage()); + } else { + getState().setErrorMessage(null); + } } - /* Documentation copied from interface */ - public void requestRepaint() { + /** + * Creates the shared state bean to be used in server to client + * communication. + * <p> + * By default a state object of the defined return type of + * {@link #getState()} is created. Subclasses can override this method and + * return a new instance of the correct state class but this should rarely + * be necessary. + * </p> + * <p> + * No configuration of the values of the state should be performed in + * {@link #createState()}. + * + * @since 7.0 + * + * @return new shared state object + */ + protected ComponentState createState() { + try { + Method m = getClass().getMethod("getState", (Class[]) null); + Class<? extends ComponentState> type = (Class<? extends ComponentState>) m + .getReturnType(); + return type.newInstance(); + } catch (Exception e) { + getLogger().log( + Level.INFO, + "Error determining state object class for " + + getClass().getName()); + } - // The effect of the repaint request is identical to case where a - // child requests repaint - childRequestedRepaint(null); + // Fall back to ComponentState if detection fails for some reason. + return new ComponentState(); } /* Documentation copied from interface */ - public void childRequestedRepaint( - Collection<RepaintRequestListener> alreadyNotified) { + public void requestRepaint() { // Invisible components (by flag in this particular component) do not // need repaints - if (!visible) { + if (!getState().isVisible()) { return; } - fireRequestRepaintEvent(alreadyNotified); + fireRequestRepaintEvent(); } /** @@ -852,33 +852,15 @@ public abstract class AbstractComponent implements Component, MethodEventSource * * @param alreadyNotified */ - private void fireRequestRepaintEvent( - Collection<RepaintRequestListener> alreadyNotified) { - // Notify listeners only once - if (!repaintRequestListenersNotified) { - // Notify the listeners - if (repaintRequestListeners != null - && !repaintRequestListeners.isEmpty()) { - final Object[] listeners = repaintRequestListeners.toArray(); - final RepaintRequestEvent event = new RepaintRequestEvent(this); - for (int i = 0; i < listeners.length; i++) { - if (alreadyNotified == null) { - alreadyNotified = new LinkedList<RepaintRequestListener>(); - } - if (!alreadyNotified.contains(listeners[i])) { - ((RepaintRequestListener) listeners[i]) - .repaintRequested(event); - alreadyNotified - .add((RepaintRequestListener) listeners[i]); - repaintRequestListenersNotified = true; - } - } - } - - // Notify the parent - final Component parent = getParent(); - if (parent != null) { - parent.childRequestedRepaint(alreadyNotified); + // Notify listeners only once + private void fireRequestRepaintEvent() { + // Notify the listeners + if (repaintRequestListeners != null + && !repaintRequestListeners.isEmpty()) { + final Object[] listeners = repaintRequestListeners.toArray(); + final RepaintRequestEvent event = new RepaintRequestEvent(this); + for (int i = 0; i < listeners.length; i++) { + ((RepaintRequestListener) listeners[i]).repaintRequested(event); } } } @@ -903,17 +885,6 @@ public abstract class AbstractComponent implements Component, MethodEventSource } } - /* Component variable changes */ - - /* - * Invoked when the value of a variable has changed. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - public void changeVariables(Object source, Map<String, Object> variables) { - - } - /* General event framework */ private static final Method COMPONENT_EVENT_METHOD = ReflectTools @@ -955,14 +926,11 @@ public abstract class AbstractComponent implements Component, MethodEventSource if (eventRouter == null) { eventRouter = new EventRouter(); } - if (eventIdentifiers == null) { - eventIdentifiers = new HashSet<String>(); - } boolean needRepaint = !eventRouter.hasListeners(eventType); eventRouter.addListener(eventType, target, method); if (needRepaint) { - eventIdentifiers.add(eventIdentifier); + getState().addRegisteredEventListener(eventIdentifier); requestRepaint(); } } @@ -1011,7 +979,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource if (eventRouter != null) { eventRouter.removeListener(eventType, target); if (!eventRouter.hasListeners(eventType)) { - eventIdentifiers.remove(eventIdentifier); + getState().removeRegisteredEventListener(eventIdentifier); requestRepaint(); } } @@ -1283,7 +1251,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource * * @see com.vaadin.terminal.Sizeable#getHeightUnits() */ - public int getHeightUnits() { + public Unit getHeightUnits() { return heightUnit; } @@ -1301,36 +1269,19 @@ public abstract class AbstractComponent implements Component, MethodEventSource * * @see com.vaadin.terminal.Sizeable#getWidthUnits() */ - public int getWidthUnits() { + public Unit getWidthUnits() { return widthUnit; } /* * (non-Javadoc) * - * @see com.vaadin.terminal.Sizeable#setHeight(float) - */ - @Deprecated - public void setHeight(float height) { - setHeight(height, getHeightUnits()); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setHeightUnits(int) - */ - @Deprecated - public void setHeightUnits(int unit) { - setHeight(getHeight(), unit); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setHeight(float, int) + * @see com.vaadin.terminal.Sizeable#setHeight(float, Unit) */ - public void setHeight(float height, int unit) { + public void setHeight(float height, Unit unit) { + if (unit == null) { + throw new IllegalArgumentException("Unit can not be null"); + } this.height = height; heightUnit = unit; requestRepaint(); @@ -1343,8 +1294,8 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see com.vaadin.terminal.Sizeable#setSizeFull() */ public void setSizeFull() { - setWidth(100, UNITS_PERCENTAGE); - setHeight(100, UNITS_PERCENTAGE); + setWidth(100, Unit.PERCENTAGE); + setHeight(100, Unit.PERCENTAGE); } /* @@ -1353,36 +1304,19 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see com.vaadin.terminal.Sizeable#setSizeUndefined() */ public void setSizeUndefined() { - setWidth(-1, UNITS_PIXELS); - setHeight(-1, UNITS_PIXELS); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setWidth(float) - */ - @Deprecated - public void setWidth(float width) { - setWidth(width, getWidthUnits()); + setWidth(-1, Unit.PIXELS); + setHeight(-1, Unit.PIXELS); } /* * (non-Javadoc) * - * @see com.vaadin.terminal.Sizeable#setWidthUnits(int) + * @see com.vaadin.terminal.Sizeable#setWidth(float, Unit) */ - @Deprecated - public void setWidthUnits(int unit) { - setWidth(getWidth(), unit); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setWidth(float, int) - */ - public void setWidth(float width, int unit) { + public void setWidth(float width, Unit unit) { + if (unit == null) { + throw new IllegalArgumentException("Unit can not be null"); + } this.width = width; widthUnit = unit; requestRepaint(); @@ -1395,8 +1329,12 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see com.vaadin.terminal.Sizeable#setWidth(java.lang.String) */ public void setWidth(String width) { - float[] p = parseStringSize(width); - setWidth(p[0], (int) p[1]); + Size size = parseStringSize(width); + if (size != null) { + setWidth(size.getSize(), size.getUnit()); + } else { + setWidth(-1, Unit.PIXELS); + } } /* @@ -1405,58 +1343,61 @@ public abstract class AbstractComponent implements Component, MethodEventSource * @see com.vaadin.terminal.Sizeable#setHeight(java.lang.String) */ public void setHeight(String height) { - float[] p = parseStringSize(height); - setHeight(p[0], (int) p[1]); + Size size = parseStringSize(height); + if (size != null) { + setHeight(size.getSize(), size.getUnit()); + } else { + setHeight(-1, Unit.PIXELS); + } } /* * Returns array with size in index 0 unit in index 1. Null or empty string - * will produce {-1,UNITS_PIXELS} + * will produce {-1,Unit#PIXELS} */ - private static float[] parseStringSize(String s) { - float[] values = { -1, UNITS_PIXELS }; + private static Size parseStringSize(String s) { if (s == null) { - return values; + return null; } s = s.trim(); if ("".equals(s)) { - return values; + return null; } - + float size = 0; + Unit unit = null; Matcher matcher = sizePattern.matcher(s); if (matcher.find()) { - values[0] = Float.parseFloat(matcher.group(1)); - if (values[0] < 0) { - values[0] = -1; + size = Float.parseFloat(matcher.group(1)); + if (size < 0) { + size = -1; + unit = Unit.PIXELS; } else { - String unit = matcher.group(3); - if (unit == null) { - values[1] = UNITS_PIXELS; - } else if (unit.equals("px")) { - values[1] = UNITS_PIXELS; - } else if (unit.equals("%")) { - values[1] = UNITS_PERCENTAGE; - } else if (unit.equals("em")) { - values[1] = UNITS_EM; - } else if (unit.equals("ex")) { - values[1] = UNITS_EX; - } else if (unit.equals("in")) { - values[1] = UNITS_INCH; - } else if (unit.equals("cm")) { - values[1] = UNITS_CM; - } else if (unit.equals("mm")) { - values[1] = UNITS_MM; - } else if (unit.equals("pt")) { - values[1] = UNITS_POINTS; - } else if (unit.equals("pc")) { - values[1] = UNITS_PICAS; - } + String symbol = matcher.group(3); + unit = Unit.getUnitFromSymbol(symbol); } } else { throw new IllegalArgumentException("Invalid size argument: \"" + s + "\" (should match " + sizePattern.pattern() + ")"); } - return values; + return new Size(size, unit); + } + + private static class Size implements Serializable { + float size; + Unit unit; + + public Size(float size, Unit unit) { + this.size = size; + this.unit = unit; + } + + public float getSize() { + return size; + } + + public Unit getUnit() { + return unit; + } } public interface ComponentErrorEvent extends Terminal.ErrorEvent { @@ -1517,4 +1458,206 @@ public abstract class AbstractComponent implements Component, MethodEventSource } -}
\ No newline at end of file + /* + * Actions + */ + + /** + * Gets the {@link ActionManager} used to manage the + * {@link ShortcutListener}s added to this {@link Field}. + * + * @return the ActionManager in use + */ + protected ActionManager getActionManager() { + if (actionManager == null) { + actionManager = new ActionManager(); + setActionManagerViewer(); + } + return actionManager; + } + + /** + * Set a viewer for the action manager to be the parent sub window (if the + * component is in a window) or the root (otherwise). This is still a + * simplification of the real case as this should be handled by the parent + * VOverlay (on the client side) if the component is inside an VOverlay + * component. + */ + private void setActionManagerViewer() { + if (actionManager != null && getRoot() != null) { + // Attached and has action manager + Window w = findAncestor(Window.class); + if (w != null) { + actionManager.setViewer(w); + } else { + actionManager.setViewer(getRoot()); + } + } + + } + + public void addShortcutListener(ShortcutListener shortcut) { + getActionManager().addAction(shortcut); + } + + public void removeShortcutListener(ShortcutListener shortcut) { + if (actionManager != null) { + actionManager.removeAction(shortcut); + } + } + + /** + * Registers an RPC interface implementation for this component. + * + * A component can listen to multiple RPC interfaces, and subclasses can + * register additional implementations. + * + * @since 7.0 + * + * @param implementation + * RPC interface implementation + * @param rpcInterfaceType + * RPC interface class for which the implementation should be + * registered + */ + protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) { + rpcManagerMap.put(rpcInterfaceType, new ServerRpcManager<T>( + implementation, rpcInterfaceType)); + } + + /** + * Registers an RPC interface implementation for this component. + * + * A component can listen to multiple RPC interfaces, and subclasses can + * register additional implementations. + * + * @since 7.0 + * + * @param implementation + * RPC interface implementation. Also used to deduce the type. + */ + protected <T extends ServerRpc> void registerRpc(T implementation) { + Class<?> cls = implementation.getClass(); + Class<?>[] interfaces = cls.getInterfaces(); + while (interfaces.length == 0) { + // Search upwards until an interface is found. It must be found as T + // extends ServerRpc + cls = cls.getSuperclass(); + interfaces = cls.getInterfaces(); + } + if (interfaces.length != 1 + || !(ServerRpc.class.isAssignableFrom(interfaces[0]))) { + throw new RuntimeException( + "Use registerRpc(T implementation, Class<T> rpcInterfaceType) if the Rpc implementation implements more than one interface"); + } + Class<T> type = (Class<T>) interfaces[0]; + registerRpc(implementation, type); + } + + /** + * Returns an RPC proxy for a given server to client RPC interface for this + * component. + * + * TODO more javadoc, subclasses, ... + * + * @param rpcInterface + * RPC interface type + * + * @since 7.0 + */ + public <T extends ClientRpc> T getRpcProxy(final Class<T> rpcInterface) { + // create, initialize and return a dynamic proxy for RPC + try { + if (!rpcProxyMap.containsKey(rpcInterface)) { + Class<T> proxyClass = (Class) Proxy.getProxyClass( + rpcInterface.getClassLoader(), rpcInterface); + Constructor<T> constructor = proxyClass + .getConstructor(InvocationHandler.class); + T rpcProxy = constructor.newInstance(new RpcInvoicationHandler( + rpcInterface)); + // cache the proxy + rpcProxyMap.put(rpcInterface, rpcProxy); + } + return (T) rpcProxyMap.get(rpcInterface); + } catch (Exception e) { + // TODO exception handling? + throw new RuntimeException(e); + } + } + + private class RpcInvoicationHandler implements InvocationHandler, + Serializable { + + private String rpcInterfaceName; + + public RpcInvoicationHandler(Class<?> rpcInterface) { + rpcInterfaceName = rpcInterface.getName().replaceAll("\\$", "."); + } + + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable { + addMethodInvocationToQueue(rpcInterfaceName, method, args); + // TODO no need to do full repaint if only RPC calls + requestRepaint(); + return null; + } + + } + + /** + * For internal use: adds a method invocation to the pending RPC call queue. + * + * @param interfaceName + * RPC interface name + * @param methodName + * RPC method name + * @param parameters + * RPC vall parameters + * + * @since 7.0 + */ + protected void addMethodInvocationToQueue(String interfaceName, + Method method, Object[] parameters) { + // add to queue + pendingInvocations.add(new ClientMethodInvocation(this, interfaceName, + method, parameters)); + } + + /** + * @see RpcTarget#getRpcManager(Class) + * + * @param rpcInterface + * RPC interface for which a call was made + * @return RPC Manager handling calls for the interface + * + * @since 7.0 + */ + public RpcManager getRpcManager(Class<?> rpcInterface) { + return rpcManagerMap.get(rpcInterface); + } + + public List<ClientMethodInvocation> retrievePendingRpcCalls() { + if (pendingInvocations.isEmpty()) { + return Collections.emptyList(); + } else { + List<ClientMethodInvocation> result = pendingInvocations; + pendingInvocations = new ArrayList<ClientMethodInvocation>(); + return Collections.unmodifiableList(result); + } + } + + public String getConnectorId() { + if (connectorId == null) { + if (getApplication() == null) { + throw new RuntimeException( + "Component must be attached to an application when getConnectorId() is called for the first time"); + } + connectorId = getApplication().createConnectorId(this); + } + return connectorId; + } + + private Logger getLogger() { + return Logger.getLogger(AbstractComponent.class.getName()); + } +} diff --git a/src/com/vaadin/ui/AbstractComponentContainer.java b/src/com/vaadin/ui/AbstractComponentContainer.java index 5d5218307a..1c857a03cd 100644 --- a/src/com/vaadin/ui/AbstractComponentContainer.java +++ b/src/com/vaadin/ui/AbstractComponentContainer.java @@ -215,18 +215,20 @@ public abstract class AbstractComponentContainer extends AbstractComponent } @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - if (getParent() != null && !getParent().isEnabled()) { - // some ancestor still disabled, don't update children + public void setVisible(boolean visible) { + if (getState().isVisible() == visible) { return; - } else { - requestRepaintAll(); } + + super.setVisible(visible); + // If the visibility state is toggled it might affect all children + // aswell, e.g. make container visible should make children visible if + // they were only hidden because the container was hidden. + requestRepaintAll(); } @Override - public void setWidth(float width, int unit) { + public void setWidth(float width, Unit unit) { /* * child tree repaints may be needed, due to our fall back support for * invalid relative sizes @@ -237,9 +239,9 @@ public abstract class AbstractComponentContainer extends AbstractComponent // children currently in invalid state may need repaint dirtyChildren = getInvalidSizedChildren(false); } else if ((width == SIZE_UNDEFINED && getWidth() != SIZE_UNDEFINED) - || (unit == UNITS_PERCENTAGE - && getWidthUnits() != UNITS_PERCENTAGE && !ComponentSizeValidator - .parentCanDefineWidth(this))) { + || (unit == Unit.PERCENTAGE + && getWidthUnits() != Unit.PERCENTAGE && !ComponentSizeValidator + .parentCanDefineWidth(this))) { /* * relative width children may get to invalid state if width becomes * invalid. Width may also become invalid if units become percentage @@ -326,7 +328,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent } @Override - public void setHeight(float height, int unit) { + public void setHeight(float height, Unit unit) { /* * child tree repaints may be needed, due to our fall back support for * invalid relative sizes @@ -337,9 +339,9 @@ public abstract class AbstractComponentContainer extends AbstractComponent // children currently in invalid state may need repaint dirtyChildren = getInvalidSizedChildren(true); } else if ((height == SIZE_UNDEFINED && getHeight() != SIZE_UNDEFINED) - || (unit == UNITS_PERCENTAGE - && getHeightUnits() != UNITS_PERCENTAGE && !ComponentSizeValidator - .parentCanDefineHeight(this))) { + || (unit == Unit.PERCENTAGE + && getHeightUnits() != Unit.PERCENTAGE && !ComponentSizeValidator + .parentCanDefineHeight(this))) { /* * relative height children may get to invalid state if height * becomes invalid. Height may also become invalid if units become @@ -354,22 +356,56 @@ public abstract class AbstractComponentContainer extends AbstractComponent } public void requestRepaintAll() { - requestRepaint(); - for (Iterator<Component> childIterator = getComponentIterator(); childIterator - .hasNext();) { + requestRepaintAll(this); + } + + /** + * Helper that implements the logic needed by requestRepaintAll. Calls + * requestRepaintAll/requestRepaint for the component container and all its + * children recursively. + * + * @param container + */ + public static void requestRepaintAll(HasComponents container) { + container.requestRepaint(); + if (container instanceof Panel) { + Panel p = (Panel) container; + // #2924 Panel is invalid, really invalid. + // Panel.getComponentIterator returns the children of content, not + // of Panel... + if (p.getContent() != null) { + p.getContent().requestRepaint(); + } + } + for (Iterator<Component> childIterator = container + .getComponentIterator(); childIterator.hasNext();) { Component c = childIterator.next(); - if (c instanceof Form) { - // Form has children in layout, but is not ComponentContainer - c.requestRepaint(); - ((Form) c).getLayout().requestRepaintAll(); - } else if (c instanceof Table) { - ((Table) c).requestRepaintAll(); - } else if (c instanceof ComponentContainer) { - ((ComponentContainer) c).requestRepaintAll(); + if (c instanceof HasComponents) { + requestRepaintAll((HasComponents) c); } else { c.requestRepaint(); } } } + /** + * Returns an iterator for the child components. + * + * @return An iterator for the child components. + * @see #getComponentIterator() + * @since 7.0.0 + */ + public Iterator<Component> iterator() { + return getComponentIterator(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.HasComponents#isComponentVisible(com.vaadin.ui.Component) + */ + public boolean isComponentVisible(Component childComponent) { + return true; + } }
\ No newline at end of file diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index e1d3270225..4efed11e2c 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -6,25 +6,29 @@ package com.vaadin.ui; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; -import java.util.Map; +import java.util.List; +import java.util.logging.Logger; +import com.vaadin.Application; import com.vaadin.data.Buffered; import com.vaadin.data.Property; import com.vaadin.data.Validatable; import com.vaadin.data.Validator; import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.ConverterFactory; import com.vaadin.event.Action; -import com.vaadin.event.ActionManager; import com.vaadin.event.ShortcutAction; import com.vaadin.event.ShortcutListener; +import com.vaadin.terminal.AbstractErrorMessage; import com.vaadin.terminal.CompositeErrorMessage; import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; +import com.vaadin.terminal.gwt.client.AbstractFieldState; /** * <p> @@ -53,21 +57,29 @@ import com.vaadin.terminal.PaintTarget; * @since 3.0 */ @SuppressWarnings("serial") -public abstract class AbstractField extends AbstractComponent implements Field, - Property.ReadOnlyStatusChangeListener, +public abstract class AbstractField<T> extends AbstractComponent implements + Field<T>, Property.ReadOnlyStatusChangeListener, Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier { /* Private members */ + private static final Logger logger = Logger.getLogger(AbstractField.class + .getName()); + /** * Value of the abstract field. */ - private Object value; + private T value; /** + * A converter used to convert from the data model type to the field type + * and vice versa. + */ + private Converter<T, Object> converter = null; + /** * Connected data-source. */ - private Property dataSource = null; + private Property<?> dataSource = null; /** * The list of validators. @@ -85,11 +97,6 @@ public abstract class AbstractField extends AbstractComponent implements Field, private boolean readThroughMode = true; /** - * Is the field modified but not committed. - */ - private boolean modified = false; - - /** * Flag to indicate that the field is currently committing its value to the * datasource. */ @@ -111,31 +118,20 @@ public abstract class AbstractField extends AbstractComponent implements Field, private boolean invalidCommitted = false; /** - * The tab order number of this field. - */ - private int tabIndex = 0; - - /** - * Required field. - */ - private boolean required = false; - - /** * The error message for the exception that is thrown when the field is * required but empty. */ private String requiredError = ""; /** - * Is automatic validation enabled. + * The error message that is shown when the field value cannot be converted. */ - private boolean validationVisible = true; + private String conversionError = "Could not convert value to {0}"; /** - * Keeps track of the Actions added to this component; the actual - * handling/notifying is delegated, usually to the containing window. + * Is automatic validation enabled. */ - private ActionManager actionManager; + private boolean validationVisible = true; private boolean valueWasModifiedByDataSourceDuringCommit; @@ -155,29 +151,6 @@ public abstract class AbstractField extends AbstractComponent implements Field, * Paints the field. Don't add a JavaDoc comment here, we use the default * documentation from the implemented interface. */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - - // The tab ordering number - if (getTabIndex() != 0) { - target.addAttribute("tabindex", getTabIndex()); - } - - // If the field is modified, but not committed, set modified attribute - if (isModified()) { - target.addAttribute("modified", true); - } - - // Adds the required attribute - if (!isReadOnly() && isRequired()) { - target.addAttribute("required", true); - } - - // Hide the error indicator if needed - if (shouldHideErrors()) { - target.addAttribute("hideErrors", true); - } - } /** * Returns true if the error indicator be hidden when painting the component @@ -191,15 +164,21 @@ public abstract class AbstractField extends AbstractComponent implements Field, * to show it when there are errors */ protected boolean shouldHideErrors() { - return isRequired() && isEmpty() && getComponentError() == null - && getErrorMessage() != null; + // getErrorMessage() can still return something else than null based on + // validation etc. + return isRequired() && isEmpty() && getComponentError() == null; } - /* - * Gets the field type Don't add a JavaDoc comment here, we use the default - * documentation from the implemented interface. + /** + * Returns the type of the Field. The methods <code>getValue</code> and + * <code>setValue</code> must be compatible with this type: one must be able + * to safely cast the value returned from <code>getValue</code> to the given + * type and pass any variable assignable to this type as an argument to + * <code>setValue</code>. + * + * @return the type of the Field */ - public abstract Class<?> getType(); + public abstract Class<? extends T> getType(); /** * The abstract field is read only also if the data source is in read only @@ -247,23 +226,21 @@ public abstract class AbstractField extends AbstractComponent implements Field, public void commit() throws Buffered.SourceException, InvalidValueException { if (dataSource != null && !dataSource.isReadOnly()) { if ((isInvalidCommitted() || isValid())) { - final Object newValue = getValue(); try { // Commits the value to datasource. valueWasModifiedByDataSourceDuringCommit = false; committingValueToDataSource = true; - dataSource.setValue(newValue); - + getPropertyDataSource().setValue(getConvertedValue()); } catch (final Throwable e) { // Sets the buffering state. - currentBufferedSourceException = new Buffered.SourceException( + SourceException sourceException = new Buffered.SourceException( this, e); - requestRepaint(); + setCurrentBufferedSourceException(sourceException); // Throws the source exception. - throw currentBufferedSourceException; + throw sourceException; } finally { committingValueToDataSource = false; } @@ -273,25 +250,19 @@ public abstract class AbstractField extends AbstractComponent implements Field, } } - boolean repaintNeeded = false; - // The abstract field is not modified anymore - if (modified) { - modified = false; - repaintNeeded = true; + if (isModified()) { + setModified(false); } // If successful, remove set the buffering state to be ok - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - repaintNeeded = true; + if (getCurrentBufferedSourceException() != null) { + setCurrentBufferedSourceException(null); } if (valueWasModifiedByDataSourceDuringCommit) { valueWasModifiedByDataSourceDuringCommit = false; fireValueChange(false); - } else if (repaintNeeded) { - requestRepaint(); } } @@ -304,19 +275,18 @@ public abstract class AbstractField extends AbstractComponent implements Field, if (dataSource != null) { // Gets the correct value from datasource - Object newValue; + T newFieldValue; try { // Discards buffer by overwriting from datasource - newValue = String.class == getType() ? dataSource.toString() - : dataSource.getValue(); + newFieldValue = convertFromDataSource(getDataSourceValue()); // If successful, remove set the buffering state to be ok - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - requestRepaint(); + if (getCurrentBufferedSourceException() != null) { + setCurrentBufferedSourceException(null); } } catch (final Throwable e) { + // FIXME: What should really be done here if conversion fails? // Sets the buffering state currentBufferedSourceException = new Buffered.SourceException( @@ -328,29 +298,58 @@ public abstract class AbstractField extends AbstractComponent implements Field, } final boolean wasModified = isModified(); - modified = false; + setModified(false); // If the new value differs from the previous one - if ((newValue == null && value != null) - || (newValue != null && !newValue.equals(value))) { - setInternalValue(newValue); + if (!equals(newFieldValue, getInternalValue())) { + setInternalValue(newFieldValue); fireValueChange(false); - } - - // If the value did not change, but the modification status did - else if (wasModified) { + } else if (wasModified) { + // If the value did not change, but the modification status did requestRepaint(); } } } + /** + * Gets the value from the data source. This is only here because of clarity + * in the code that handles both the data model value and the field value. + * + * @return The value of the property data source + */ + private Object getDataSourceValue() { + return dataSource.getValue(); + } + + /** + * Returns the field value. This is always identical to {@link #getValue()} + * and only here because of clarity in the code that handles both the data + * model value and the field value. + * + * @return The value of the field + */ + private T getFieldValue() { + // Give the value from abstract buffers if the field if possible + if (dataSource == null || !isReadThrough() || isModified()) { + return getInternalValue(); + } + + // There is no buffered value so use whatever the data model provides + return convertFromDataSource(getDataSourceValue()); + } + /* * Has the field been modified since the last commit()? Don't add a JavaDoc * comment here, we use the default documentation from the implemented * interface. */ public boolean isModified() { - return modified; + return getState().isModified(); + } + + private void setModified(boolean modified) { + getState().setModified(modified); + requestRepaint(); } /* @@ -361,11 +360,28 @@ public abstract class AbstractField extends AbstractComponent implements Field, return writeThroughMode; } - /* - * Sets the field's write-through mode to the specified status Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. + /** + * Sets the field's write-through mode to the specified status. When + * switching the write-through mode on, a {@link #commit()} will be + * performed. + * + * @see #setBuffered(boolean) for an easier way to control read through and + * write through modes + * + * @param writeThrough + * Boolean value to indicate if the object should be in + * write-through mode after the call. + * @throws SourceException + * If the operation fails because of an exception is thrown by + * the data source. + * @throws InvalidValueException + * If the implicit commit operation fails because of a + * validation error. + * @deprecated Use {@link #setBuffered(boolean)} instead. Note that + * setReadThrough(true), setWriteThrough(true) equals + * setBuffered(false) */ + @Deprecated public void setWriteThrough(boolean writeThrough) throws Buffered.SourceException, InvalidValueException { if (writeThroughMode == writeThrough) { @@ -385,38 +401,96 @@ public abstract class AbstractField extends AbstractComponent implements Field, return readThroughMode; } - /* - * Sets the field's read-through mode to the specified status Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. + /** + * Sets the field's read-through mode to the specified status. When + * switching read-through mode on, the object's value is updated from the + * data source. + * + * @see #setBuffered(boolean) for an easier way to control read through and + * write through modes + * + * @param readThrough + * Boolean value to indicate if the object should be in + * read-through mode after the call. + * + * @throws SourceException + * If the operation fails because of an exception is thrown by + * the data source. The cause is included in the exception. + * @deprecated Use {@link #setBuffered(boolean)} instead. Note that + * setReadThrough(true), setWriteThrough(true) equals + * setBuffered(false) */ + @Deprecated public void setReadThrough(boolean readThrough) throws Buffered.SourceException { if (readThroughMode == readThrough) { return; } readThroughMode = readThrough; - if (!isModified() && readThroughMode && dataSource != null) { - setInternalValue(String.class == getType() ? dataSource.toString() - : dataSource.getValue()); + if (!isModified() && readThroughMode && getPropertyDataSource() != null) { + setInternalValue(convertFromDataSource(getDataSourceValue())); fireValueChange(false); } } + /** + * Sets the buffered mode of this Field. + * <p> + * When the field is in buffered mode, changes will not be committed to the + * property data source until {@link #commit()} is called. + * </p> + * <p> + * Changing buffered mode will change the read through and write through + * state for the field. + * </p> + * <p> + * Mixing calls to {@link #setBuffered(boolean)} and + * {@link #setReadThrough(boolean)} or {@link #setWriteThrough(boolean)} is + * generally a bad idea. + * </p> + * + * @param buffered + * true if buffered mode should be turned on, false otherwise + */ + public void setBuffered(boolean buffered) { + setReadThrough(!buffered); + setWriteThrough(!buffered); + } + + /** + * Checks the buffered mode of this Field. + * <p> + * This method only returns true if both read and write buffering is used. + * + * @return true if buffered mode is on, false otherwise + */ + public boolean isBuffered() { + return !isReadThrough() && !isWriteThrough(); + } + /* Property interface implementation */ /** - * Returns the value of the Property in human readable textual format. + * Returns the (field) value converted to a String using toString(). * * @see java.lang.Object#toString() + * @deprecated Instead use {@link #getValue()} to get the value of the + * field, {@link #getConvertedValue()} to get the field value + * converted to the data model type or + * {@link #getPropertyDataSource()} .getValue() to get the value + * of the data source. */ + @Deprecated @Override public String toString() { - final Object value = getValue(); + logger.warning("You are using AbstractField.toString() to get the value for a " + + getClass().getSimpleName() + + ". This is not recommended and will not be supported in future versions."); + final Object value = getFieldValue(); if (value == null) { return null; } - return getValue().toString(); + return value.toString(); } /** @@ -424,67 +498,63 @@ public abstract class AbstractField extends AbstractComponent implements Field, * * <p> * This is the visible, modified and possible invalid value the user have - * entered to the field. In the read-through mode, the abstract buffer is - * also updated and validation is performed. + * entered to the field. * </p> * * <p> * Note that the object returned is compatible with getType(). For example, * if the type is String, this returns Strings even when the underlying - * datasource is of some other type. In order to access the datasources - * native type, use getPropertyDatasource().getValue() instead. + * datasource is of some other type. In order to access the converted value, + * use {@link #getConvertedValue()} and to access the value of the property + * data source, use {@link Property#getValue()} for the property data + * source. * </p> * * <p> - * Note that when you extend AbstractField, you must reimplement this method - * if datasource.getValue() is not assignable to class returned by getType() - * AND getType() is not String. In case of Strings, getValue() calls - * datasource.toString() instead of datasource.getValue(). + * Since Vaadin 7.0, no implicit conversions between other data types and + * String are performed, but a converter is used if set. * </p> * * @return the current value of the field. */ - public Object getValue() { - - // Give the value from abstract buffers if the field if possible - if (dataSource == null || !isReadThrough() || isModified()) { - return value; - } - - Object newValue = String.class == getType() ? dataSource.toString() - : dataSource.getValue(); - - return newValue; + public T getValue() { + return getFieldValue(); } /** * Sets the value of the field. * - * @param newValue + * @param newFieldValue * the New value of the field. * @throws Property.ReadOnlyException - * @throws Property.ConversionException */ - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException { - setValue(newValue, false); + public void setValue(Object newFieldValue) + throws Property.ReadOnlyException, Converter.ConversionException { + // This check is needed as long as setValue accepts Object instead of T + if (newFieldValue != null) { + if (!getType().isAssignableFrom(newFieldValue.getClass())) { + throw new Converter.ConversionException("Value of type " + + newFieldValue.getClass() + " cannot be assigned to " + + getType().getName()); + } + } + setValue((T) newFieldValue, false); } /** * Sets the value of the field. * - * @param newValue + * @param newFieldValue * the New value of the field. * @param repaintIsNotNeeded * True iff caller is sure that repaint is not needed. * @throws Property.ReadOnlyException - * @throws Property.ConversionException */ - protected void setValue(Object newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Property.ConversionException { + protected void setValue(T newFieldValue, boolean repaintIsNotNeeded) + throws Property.ReadOnlyException, Converter.ConversionException, + InvalidValueException { - if ((newValue == null && value != null) - || (newValue != null && !newValue.equals(value))) { + if (!equals(newFieldValue, getInternalValue())) { // Read only fields can not be changed if (isReadOnly()) { @@ -493,24 +563,24 @@ public abstract class AbstractField extends AbstractComponent implements Field, // Repaint is needed even when the client thinks that it knows the // new state if validity of the component may change - if (repaintIsNotNeeded && (isRequired() || getValidators() != null)) { + if (repaintIsNotNeeded + && (isRequired() || getValidators() != null || getConverter() != null)) { repaintIsNotNeeded = false; } - // If invalid values are not allowed, the value must be checked if (!isInvalidAllowed()) { - final Collection<Validator> v = getValidators(); - if (v != null) { - for (final Iterator<Validator> i = v.iterator(); i - .hasNext();) { - (i.next()).validate(newValue); - } - } + /* + * If invalid values are not allowed the value must be validated + * before it is set. If validation fails, the + * InvalidValueException is thrown and the internal value is not + * updated. + */ + validate(newFieldValue); } // Changes the value - setInternalValue(newValue); - modified = dataSource != null; + setInternalValue(newFieldValue); + setModified(dataSource != null); valueWasModifiedByDataSourceDuringCommit = false; // In write through mode , try to commit @@ -520,10 +590,11 @@ public abstract class AbstractField extends AbstractComponent implements Field, // Commits the value to datasource committingValueToDataSource = true; - dataSource.setValue(newValue); + getPropertyDataSource().setValue( + convertToDataSource(newFieldValue)); // The buffer is now unmodified - modified = false; + setModified(false); } catch (final Throwable e) { @@ -540,9 +611,8 @@ public abstract class AbstractField extends AbstractComponent implements Field, } // If successful, remove set the buffering state to be ok - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - requestRepaint(); + if (getCurrentBufferedSourceException() != null) { + setCurrentBufferedSourceException(null); } if (valueWasModifiedByDataSourceDuringCommit) { @@ -559,6 +629,13 @@ public abstract class AbstractField extends AbstractComponent implements Field, } } + private static boolean equals(Object value1, Object value2) { + if (value1 == null) { + return value2 == null; + } + return value1.equals(value2); + } + /* External data source */ /** @@ -612,25 +689,42 @@ public abstract class AbstractField extends AbstractComponent implements Field, public void setPropertyDataSource(Property newDataSource) { // Saves the old value - final Object oldValue = value; + final Object oldValue = getInternalValue(); // Stop listening to the old data source removePropertyListeners(); // Sets the new data source dataSource = newDataSource; - + getState().setPropertyReadOnly( + dataSource == null ? false : dataSource.isReadOnly()); + + // Check if the current converter is compatible. + if (newDataSource != null + && (getConverter() == null || !newDataSource.getType() + .isAssignableFrom(getConverter().getModelType()))) { + // Changing from e.g. Number -> Double should set a new converter, + // changing from Double -> Number can keep the old one (Property + // accepts Number) + + // Set a new converter if there is a new data source and + // there is no old converter or the old is incompatible. + setConverter(newDataSource.getType()); + } // Gets the value from source try { if (dataSource != null) { - setInternalValue(String.class == getType() ? dataSource - .toString() : dataSource.getValue()); + T fieldValue = convertFromDataSource(getDataSourceValue()); + setInternalValue(fieldValue); + } + setModified(false); + if (getCurrentBufferedSourceException() != null) { + setCurrentBufferedSourceException(null); } - modified = false; } catch (final Throwable e) { - currentBufferedSourceException = new Buffered.SourceException(this, - e); - modified = true; + setCurrentBufferedSourceException(new Buffered.SourceException( + this, e)); + setModified(true); } // Listen to new data source if possible @@ -649,12 +743,159 @@ public abstract class AbstractField extends AbstractComponent implements Field, } // Fires value change if the value has changed + T value = getInternalValue(); if ((value != oldValue) && ((value != null && !value.equals(oldValue)) || value == null)) { fireValueChange(false); } } + /** + * Retrieves a converter for the field from the converter factory defined + * for the application. Clears the converter if no application reference is + * available or if the factory returns null. + * + * @param datamodelType + * The type of the data model that we want to be able to convert + * from + */ + public void setConverter(Class<?> datamodelType) { + Converter<T, ?> converter = null; + + Application app = Application.getCurrentApplication(); + if (app != null) { + ConverterFactory factory = app.getConverterFactory(); + converter = (Converter<T, ?>) factory.createConverter(getType(), + datamodelType); + } + setConverter(converter); + } + + /** + * Convert the given value from the data source type to the UI type. + * + * @param newValue + * The data source value to convert. + * @return The converted value that is compatible with the UI type or the + * original value if its type is compatible and no converter is set. + * @throws Converter.ConversionException + * if there is no converter and the type is not compatible with + * the data source type. + */ + @SuppressWarnings("unchecked") + private T convertFromDataSource(Object newValue) + throws Converter.ConversionException { + if (converter != null) { + return converter.convertToPresentation(newValue, getLocale()); + } + if (newValue == null) { + return null; + } + + if (getType().isAssignableFrom(newValue.getClass())) { + return (T) newValue; + } else { + throw new Converter.ConversionException( + "Unable to convert value of type " + + newValue.getClass().getName() + + " to " + + getType() + + ". No converter is set and the types are not compatible."); + } + } + + /** + * Convert the given value from the UI type to the data source type. + * + * @param fieldValue + * The value to convert. Typically returned by + * {@link #getFieldValue()} + * @return The converted value that is compatible with the data source type. + * @throws Converter.ConversionException + * if there is no converter and the type is not compatible with + * the data source type. + */ + private Object convertToDataSource(T fieldValue) + throws Converter.ConversionException { + if (converter != null) { + /* + * If there is a converter, always use it. It must convert or throw + * an exception. + */ + try { + return converter.convertToModel(fieldValue, getLocale()); + } catch (com.vaadin.data.util.converter.Converter.ConversionException e) { + throw new Converter.ConversionException( + getConversionError(converter.getModelType()), e); + } + } + + if (fieldValue == null) { + // Null should always be passed through the converter but if there + // is no converter we can safely return null + return null; + } + + // check that the value class is compatible with the data source type + // (if data source set) or field type + Class<?> type; + if (getPropertyDataSource() != null) { + type = getPropertyDataSource().getType(); + } else { + type = getType(); + } + + if (type.isAssignableFrom(fieldValue.getClass())) { + return fieldValue; + } else { + throw new Converter.ConversionException(getConversionError(type)); + } + } + + /** + * Returns the conversion error with {0} replaced by the data source type. + * + * @param dataSourceType + * The type of the data source + * @return The value conversion error string with parameters replaced. + */ + protected String getConversionError(Class<?> dataSourceType) { + if (dataSourceType == null) { + return getConversionError(); + } else { + return getConversionError().replace("{0}", + dataSourceType.getSimpleName()); + } + } + + /** + * Returns the current value (as returned by {@link #getValue()}) converted + * to the data source type. + * <p> + * This returns the same as {@link AbstractField#getValue()} if no converter + * has been set. The value is not necessarily the same as the data source + * value e.g. if the field is in buffered mode and has been modified. + * </p> + * + * @return The converted value that is compatible with the data source type + */ + public Object getConvertedValue() { + return convertToDataSource(getFieldValue()); + } + + /** + * Sets the value of the field using a value of the data source type. The + * value given is converted to the field type and then assigned to the + * field. This will update the property data source in the same way as when + * {@link #setValue(Object)} is called. + * + * @param value + * The value to set. Must be the same type as the data source. + */ + public void setConvertedValue(Object value) { + setValue(convertFromDataSource(value)); + } + /* Validation */ /** @@ -713,102 +954,99 @@ public abstract class AbstractField extends AbstractComponent implements Field, * empty. If the field is empty it is considered valid if it is not required * and invalid otherwise. Validators are never checked for empty fields. * + * In most cases, {@link #validate()} should be used instead of + * {@link #isValid()} to also get the error message. + * * @return <code>true</code> if all registered validators claim that the * current value is valid or if the field is empty and not required, * <code>false</code> otherwise. */ public boolean isValid() { - if (isEmpty()) { - if (isRequired()) { - return false; - } else { - return true; - } - } - - if (validators == null) { + try { + validate(); return true; + } catch (InvalidValueException e) { + return false; } - - final Object value = getValue(); - for (final Iterator<Validator> i = validators.iterator(); i.hasNext();) { - if (!(i.next()).isValid(value)) { - return false; - } - } - - return true; } /** - * Checks the validity of the Validatable by validating the field with all - * attached validators except when the field is empty. An empty field is - * invalid if it is required and valid otherwise. + * Checks the validity of the Field. + * + * A field is invalid if it is set as required (using + * {@link #setRequired(boolean)} and is empty, if one or several of the + * validators added to the field indicate it is invalid or if the value + * cannot be converted provided a converter has been set. * * The "required" validation is a built-in validation feature. If the field - * is required, but empty, validation will throw an EmptyValueException with - * the error message set with setRequiredError(). + * is required and empty this method throws an EmptyValueException with the + * error message set using {@link #setRequiredError(String)}. * * @see com.vaadin.data.Validatable#validate() */ public void validate() throws Validator.InvalidValueException { - if (isEmpty()) { - if (isRequired()) { - throw new Validator.EmptyValueException(requiredError); - } else { - return; - } + if (isRequired() && isEmpty()) { + throw new Validator.EmptyValueException(requiredError); } + validate(getFieldValue()); + } - // If there is no validator, there can not be any errors - if (validators == null) { - return; - } + /** + * Validates that the given value pass the validators for the field. + * <p> + * This method does not check the requiredness of the field. + * + * @param fieldValue + * The value to check + * @throws Validator.InvalidValueException + * if one or several validators fail + */ + protected void validate(T fieldValue) + throws Validator.InvalidValueException { - // Initialize temps - Validator.InvalidValueException firstError = null; - LinkedList<InvalidValueException> errors = null; - final Object value = getValue(); + Object valueToValidate = fieldValue; - // Gets all the validation errors - for (final Iterator<Validator> i = validators.iterator(); i.hasNext();) { + // If there is a converter we start by converting the value as we want + // to validate the converted value + if (getConverter() != null) { try { - (i.next()).validate(value); - } catch (final Validator.InvalidValueException e) { - if (firstError == null) { - firstError = e; - } else { - if (errors == null) { - errors = new LinkedList<InvalidValueException>(); - errors.add(firstError); - } - errors.add(e); + valueToValidate = getConverter().convertToModel(fieldValue, + getLocale()); + } catch (Exception e) { + throw new InvalidValueException( + getConversionError(getConverter().getModelType())); + } + } + + List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>(); + if (validators != null) { + // Gets all the validation errors + for (Validator v : validators) { + try { + v.validate(valueToValidate); + } catch (final Validator.InvalidValueException e) { + validationExceptions.add(e); } } } - // If there were no error - if (firstError == null) { + // If there were no errors + if (validationExceptions.isEmpty()) { return; } // If only one error occurred, throw it forwards - if (errors == null) { - throw firstError; + if (validationExceptions.size() == 1) { + throw validationExceptions.get(0); } - // Creates composite validator - final Validator.InvalidValueException[] exceptions = new Validator.InvalidValueException[errors - .size()]; - int index = 0; - for (final Iterator<InvalidValueException> i = errors.iterator(); i - .hasNext();) { - exceptions[index++] = i.next(); - } + InvalidValueException[] exceptionArray = validationExceptions + .toArray(new InvalidValueException[validationExceptions.size()]); - throw new Validator.InvalidValueException(null, exceptions); + // Create a composite validator and include all exceptions + throw new Validator.InvalidValueException(null, exceptionArray); } /** @@ -856,7 +1094,7 @@ public abstract class AbstractField extends AbstractComponent implements Field, * the requiredError string. For these fields the exclamation mark will * be hidden but the error must still be sent to the client. */ - ErrorMessage validationError = null; + Validator.InvalidValueException validationError = null; if (isValidationVisible()) { try { validate(); @@ -872,13 +1110,18 @@ public abstract class AbstractField extends AbstractComponent implements Field, // Return if there are no errors at all if (superError == null && validationError == null - && currentBufferedSourceException == null) { + && getCurrentBufferedSourceException() == null) { return null; } // Throw combination of the error types - return new CompositeErrorMessage(new ErrorMessage[] { superError, - validationError, currentBufferedSourceException }); + return new CompositeErrorMessage( + new ErrorMessage[] { + superError, + AbstractErrorMessage + .getErrorMessageForException(validationError), + AbstractErrorMessage + .getErrorMessageForException(getCurrentBufferedSourceException()) }); } @@ -952,6 +1195,7 @@ public abstract class AbstractField extends AbstractComponent implements Field, * @see Property.ReadOnlyStatusChangeListener */ public void readOnlyStatusChange(Property.ReadOnlyStatusChangeEvent event) { + getState().setPropertyReadOnly(event.getProperty().isReadOnly()); requestRepaint(); } @@ -964,8 +1208,8 @@ public abstract class AbstractField extends AbstractComponent implements Field, * @VERSION@ * @since 3.0 */ - public class ReadOnlyStatusChangeEvent extends Component.Event implements - Property.ReadOnlyStatusChangeEvent, Serializable { + public static class ReadOnlyStatusChangeEvent extends Component.Event + implements Property.ReadOnlyStatusChangeEvent, Serializable { /** * New instance of text change event. @@ -1029,10 +1273,8 @@ public abstract class AbstractField extends AbstractComponent implements Field, public void valueChange(Property.ValueChangeEvent event) { if (isReadThrough()) { if (committingValueToDataSource) { - boolean propertyNotifiesOfTheBufferedValue = event - .getProperty().getValue() == value - || (value != null && value.equals(event.getProperty() - .getValue())); + boolean propertyNotifiesOfTheBufferedValue = equals(event + .getProperty().getValue(), getInternalValue()); if (!propertyNotifiesOfTheBufferedValue) { /* * Property (or chained property like PropertyFormatter) now @@ -1055,12 +1297,7 @@ public abstract class AbstractField extends AbstractComponent implements Field, } private void readValueFromProperty(Property.ValueChangeEvent event) { - setInternalValue(event.getProperty().getValue()); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); + setInternalValue(convertFromDataSource(event.getProperty().getValue())); } /** @@ -1071,32 +1308,13 @@ public abstract class AbstractField extends AbstractComponent implements Field, super.focus(); } - /** - * Creates abstract field by the type of the property. - * - * <p> - * This returns most suitable field type for editing property of given type. - * </p> - * - * @param propertyType - * the Type of the property, that needs to be edited. - * @deprecated use e.g. - * {@link DefaultFieldFactory#createFieldByPropertyType(Class)} - * instead - */ - @Deprecated - public static AbstractField constructField(Class<?> propertyType) { - return (AbstractField) DefaultFieldFactory - .createFieldByPropertyType(propertyType); - } - /* * (non-Javadoc) * * @see com.vaadin.ui.Component.Focusable#getTabIndex() */ public int getTabIndex() { - return tabIndex; + return getState().getTabIndex(); } /* @@ -1105,20 +1323,39 @@ public abstract class AbstractField extends AbstractComponent implements Field, * @see com.vaadin.ui.Component.Focusable#setTabIndex(int) */ public void setTabIndex(int tabIndex) { - this.tabIndex = tabIndex; + getState().setTabIndex(tabIndex); requestRepaint(); } /** + * Returns the internal field value, which might not match the data source + * value e.g. if the field has been modified and is not in write-through + * mode. + * + * This method can be overridden by subclasses together with + * {@link #setInternalValue(Object)} to compute internal field value at + * runtime. When doing so, typically also {@link #isModified()} needs to be + * overridden and care should be taken in the management of the empty state + * and buffering support. + * + * @return internal field value + */ + protected T getInternalValue() { + return value; + } + + /** * Sets the internal field value. This is purely used by AbstractField to * change the internal Field value. It does not trigger valuechange events. * It can be overridden by the inheriting classes to update all dependent * variables. * + * Subclasses can also override {@link #getInternalValue()} if necessary. + * * @param newValue * the new value to be set. */ - protected void setInternalValue(Object newValue) { + protected void setInternalValue(T newValue) { value = newValue; if (validators != null && !validators.isEmpty()) { requestRepaint(); @@ -1133,9 +1370,6 @@ public abstract class AbstractField extends AbstractComponent implements Field, @Override public void attach() { super.attach(); - if (actionManager != null) { - actionManager.setViewer(getWindow()); - } if (!isListeningToPropertyEvents) { addPropertyListeners(); @@ -1149,9 +1383,6 @@ public abstract class AbstractField extends AbstractComponent implements Field, @Override public void detach() { super.detach(); - if (actionManager != null) { - actionManager.setViewer((Window) null); - } // Stop listening to data source events on detach to avoid a potential // memory leak. See #6155. removePropertyListeners(); @@ -1170,11 +1401,11 @@ public abstract class AbstractField extends AbstractComponent implements Field, * field isEmpty() regardless of any attached validators. * * - * @return <code>true</code> if the field is required .otherwise + * @return <code>true</code> if the field is required, otherwise * <code>false</code>. */ public boolean isRequired() { - return required; + return getState().isRequired(); } /** @@ -1193,7 +1424,7 @@ public abstract class AbstractField extends AbstractComponent implements Field, * Is the field required. */ public void setRequired(boolean required) { - this.required = required; + getState().setRequired(required); requestRepaint(); } @@ -1216,13 +1447,36 @@ public abstract class AbstractField extends AbstractComponent implements Field, } /** + * Gets the error that is shown if the field value cannot be converted to + * the data source type. + * + * @return The error that is shown if conversion of the field value fails + */ + public String getConversionError() { + return conversionError; + } + + /** + * Sets the error that is shown if the field value cannot be converted to + * the data source type. If {0} is present in the message, it will be + * replaced by the simple name of the data source type. + * + * @param valueConversionError + * Message to be shown when conversion of the value fails + */ + public void setConversionError(String valueConversionError) { + this.conversionError = valueConversionError; + requestRepaint(); + } + + /** * Is the field empty? * * In general, "empty" state is same as null. As an exception, TextField * also treats empty string as "empty". */ protected boolean isEmpty() { - return (getValue() == null); + return (getFieldValue() == null); } /** @@ -1270,34 +1524,13 @@ public abstract class AbstractField extends AbstractComponent implements Field, requestRepaint(); } - /* - * Actions - */ - /** - * Gets the {@link ActionManager} used to manage the - * {@link ShortcutListener}s added to this {@link Field}. + * Gets the current buffered source exception. * - * @return the ActionManager in use + * @return The current source exception */ - protected ActionManager getActionManager() { - if (actionManager == null) { - actionManager = new ActionManager(); - if (getWindow() != null) { - actionManager.setViewer(getWindow()); - } - } - return actionManager; - } - - public void addShortcutListener(ShortcutListener shortcut) { - getActionManager().addAction(shortcut); - } - - public void removeShortcutListener(ShortcutListener shortcut) { - if (actionManager != null) { - actionManager.removeAction(shortcut); - } + protected Buffered.SourceException getCurrentBufferedSourceException() { + return currentBufferedSourceException; } /** @@ -1357,6 +1590,42 @@ public abstract class AbstractField extends AbstractComponent implements Field, } /** + * Gets the converter used to convert the property data source value to the + * field value. + * + * @return The converter or null if none is set. + */ + public Converter<T, Object> getConverter() { + return converter; + } + + /** + * Sets the converter used to convert the field value to property data + * source type. The converter must have a presentation type that matches the + * field type. + * + * @param converter + * The new converter to use. + */ + public void setConverter(Converter<T, ?> converter) { + this.converter = (Converter<T, Object>) converter; + requestRepaint(); + } + + @Override + public AbstractFieldState getState() { + return (AbstractFieldState) super.getState(); + } + + @Override + public void updateState() { + super.updateState(); + + // Hide the error indicator if needed + getState().setHideErrors(shouldHideErrors()); + } + + /** * Registers this as an event listener for events sent by the data source * (if any). Does nothing if * <code>isListeningToPropertyEvents == true</code>. @@ -1391,4 +1660,4 @@ public abstract class AbstractField extends AbstractComponent implements Field, isListeningToPropertyEvents = false; } } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/ui/AbstractLayout.java b/src/com/vaadin/ui/AbstractLayout.java index 378a59a4ad..4876b40265 100644 --- a/src/com/vaadin/ui/AbstractLayout.java +++ b/src/com/vaadin/ui/AbstractLayout.java @@ -4,14 +4,7 @@ package com.vaadin.ui; -import java.util.Map; - -import com.vaadin.event.LayoutEvents.LayoutClickEvent; -import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.AbstractLayoutState; import com.vaadin.ui.Layout.MarginHandler; /** @@ -27,10 +20,13 @@ import com.vaadin.ui.Layout.MarginHandler; public abstract class AbstractLayout extends AbstractComponentContainer implements Layout, MarginHandler { - private static final String CLICK_EVENT = EventId.LAYOUT_CLICK; - protected MarginInfo margins = new MarginInfo(false); + @Override + public AbstractLayoutState getState() { + return (AbstractLayoutState) super.getState(); + } + /* * (non-Javadoc) * @@ -38,6 +34,7 @@ public abstract class AbstractLayout extends AbstractComponentContainer */ public void setMargin(boolean enabled) { margins.setMargins(enabled); + getState().setMarginsBitmask(margins.getBitMask()); requestRepaint(); } @@ -57,6 +54,7 @@ public abstract class AbstractLayout extends AbstractComponentContainer */ public void setMargin(MarginInfo marginInfo) { margins.setMargins(marginInfo); + getState().setMarginsBitmask(margins.getBitMask()); requestRepaint(); } @@ -68,62 +66,8 @@ public abstract class AbstractLayout extends AbstractComponentContainer public void setMargin(boolean topEnabled, boolean rightEnabled, boolean bottomEnabled, boolean leftEnabled) { margins.setMargins(topEnabled, rightEnabled, bottomEnabled, leftEnabled); + getState().setMarginsBitmask(margins.getBitMask()); requestRepaint(); } - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractComponent#paintContent(com.vaadin - * .terminal.PaintTarget) - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - - // Add margin info. Defaults to false. - target.addAttribute("margins", margins.getBitMask()); - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - @SuppressWarnings("unchecked") - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - // not all subclasses use these events - if (this instanceof LayoutClickNotifier - && variables.containsKey(CLICK_EVENT)) { - fireClick((Map<String, Object>) variables.get(CLICK_EVENT)); - } - - } - - /** - * Fire a layout click event. - * - * Note that this method is only used by the subclasses that implement - * {@link LayoutClickNotifier}, and can be overridden for custom click event - * firing. - * - * @param parameters - * The parameters received from the client side implementation - */ - protected void fireClick(Map<String, Object> parameters) { - MouseEventDetails mouseDetails = MouseEventDetails - .deSerialize((String) parameters.get("mouseDetails")); - Component clickedComponent = (Component) parameters.get("component"); - Component childComponent = clickedComponent; - while (childComponent != null && childComponent.getParent() != this) { - childComponent = childComponent.getParent(); - } - - fireEvent(new LayoutClickEvent(this, mouseDetails, clickedComponent, - childComponent)); - } - } diff --git a/src/com/vaadin/ui/AbstractMedia.java b/src/com/vaadin/ui/AbstractMedia.java index 9117bce997..09cfd5ff12 100644 --- a/src/com/vaadin/ui/AbstractMedia.java +++ b/src/com/vaadin/ui/AbstractMedia.java @@ -8,18 +8,22 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VMediaBase; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.MediaBaseConnector; +import com.vaadin.terminal.gwt.client.ui.MediaBaseConnector.MediaControl; /** * Abstract base class for the HTML5 media components. * * @author Vaadin Ltd */ -public class AbstractMedia extends AbstractComponent { +public class AbstractMedia extends AbstractComponent implements + Vaadin6Component { private List<Resource> sources = new ArrayList<Resource>(); @@ -33,10 +37,6 @@ public class AbstractMedia extends AbstractComponent { private boolean muted; - private boolean pause; - - private boolean play; - /** * Sets a single media file as the source of the media component. * @@ -182,47 +182,35 @@ public class AbstractMedia extends AbstractComponent { * Pauses the media. */ public void pause() { - // cancel any possible play command - play = false; - - pause = true; - requestRepaint(); + getRpcProxy(MediaControl.class).pause(); } /** * Starts playback of the media. */ public void play() { - // cancel any possible pause command. - pause = false; - - play = true; - requestRepaint(); + getRpcProxy(MediaControl.class).play(); } - @Override public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - target.addAttribute(VMediaBase.ATTR_CONTROLS, isShowControls()); + target.addAttribute(MediaBaseConnector.ATTR_CONTROLS, isShowControls()); if (getAltText() != null) { - target.addAttribute(VMediaBase.ATTR_ALT_TEXT, getAltText()); + target.addAttribute(MediaBaseConnector.ATTR_ALT_TEXT, getAltText()); } - target.addAttribute(VMediaBase.ATTR_HTML, isHtmlContentAllowed()); - target.addAttribute(VMediaBase.ATTR_AUTOPLAY, isAutoplay()); + target.addAttribute(MediaBaseConnector.ATTR_HTML, + isHtmlContentAllowed()); + target.addAttribute(MediaBaseConnector.ATTR_AUTOPLAY, isAutoplay()); for (Resource r : getSources()) { - target.startTag(VMediaBase.TAG_SOURCE); - target.addAttribute(VMediaBase.ATTR_RESOURCE, r); - target.addAttribute(VMediaBase.ATTR_RESOURCE_TYPE, r.getMIMEType()); - target.endTag(VMediaBase.TAG_SOURCE); - } - target.addAttribute(VMediaBase.ATTR_MUTED, isMuted()); - if (play) { - target.addAttribute(VMediaBase.ATTR_PLAY, true); - play = false; - } - if (pause) { - target.addAttribute(VMediaBase.ATTR_PAUSE, true); - pause = false; + target.startTag(MediaBaseConnector.TAG_SOURCE); + target.addAttribute(MediaBaseConnector.ATTR_RESOURCE, r); + target.addAttribute(MediaBaseConnector.ATTR_RESOURCE_TYPE, + r.getMIMEType()); + target.endTag(MediaBaseConnector.TAG_SOURCE); } + target.addAttribute(MediaBaseConnector.ATTR_MUTED, isMuted()); + } + + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented } } diff --git a/src/com/vaadin/ui/AbstractOrderedLayout.java b/src/com/vaadin/ui/AbstractOrderedLayout.java index fc3ef5056d..3606fa6572 100644 --- a/src/com/vaadin/ui/AbstractOrderedLayout.java +++ b/src/com/vaadin/ui/AbstractOrderedLayout.java @@ -15,13 +15,26 @@ import com.vaadin.event.LayoutEvents.LayoutClickNotifier; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.gwt.client.EventId; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutServerRpc; +import com.vaadin.terminal.gwt.client.ui.orderedlayout.AbstractOrderedLayoutState; @SuppressWarnings("serial") public abstract class AbstractOrderedLayout extends AbstractLayout implements - Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier { + Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier, + Vaadin6Component { - private static final String CLICK_EVENT = EventId.LAYOUT_CLICK; + private AbstractOrderedLayoutServerRpc rpc = new AbstractOrderedLayoutServerRpc() { + + public void layoutClick(MouseEventDetails mouseDetails, + Connector clickedConnector) { + fireEvent(LayoutClickEvent.createEvent(AbstractOrderedLayout.this, + mouseDetails, clickedConnector)); + } + }; public static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT; @@ -39,10 +52,14 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements private final Map<Component, Float> componentToExpandRatio = new HashMap<Component, Float>(); - /** - * Is spacing between contained components enabled. Defaults to false. - */ - private boolean spacing = false; + public AbstractOrderedLayout() { + registerRpc(rpc); + } + + @Override + public AbstractOrderedLayoutState getState() { + return (AbstractOrderedLayoutState) super.getState(); + } /** * Add a component into this container. The component is added to the right @@ -54,7 +71,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements @Override public void addComponent(Component c) { // Add to components before calling super.addComponent - // so that it is available to AttachListeners + // so that it is available to AttachListeners components.add(c); try { super.addComponent(c); @@ -75,7 +92,7 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements public void addComponentAsFirst(Component c) { // If c is already in this, we must remove it before proceeding // see ticket #7668 - if(c.getParent() == this) { + if (c.getParent() == this) { removeComponent(c); } components.addFirst(c); @@ -100,9 +117,9 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements public void addComponent(Component c, int index) { // If c is already in this, we must remove it before proceeding // see ticket #7668 - if(c.getParent() == this) { + if (c.getParent() == this) { // When c is removed, all components after it are shifted down - if(index > getComponentIndex(c)) { + if (index > getComponentIndex(c)) { index--; } removeComponent(c); @@ -160,26 +177,16 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements * @throws PaintException * if the paint operation failed. */ - @Override public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - // Add spacing attribute (omitted if false) - if (spacing) { - target.addAttribute("spacing", spacing); - } - - // Adds all items in all the locations - for (Component c : components) { - // Paint child component UIDL - c.paint(target); - } - // Add child component alignment info to layout tag target.addAttribute("alignments", componentToAlignment); target.addAttribute("expandRatios", componentToExpandRatio); } + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented + } + /* Documented in superclass */ public void replaceComponent(Component oldComponent, Component newComponent) { @@ -275,8 +282,8 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements * * @see com.vaadin.ui.Layout.SpacingHandler#setSpacing(boolean) */ - public void setSpacing(boolean enabled) { - spacing = enabled; + public void setSpacing(boolean spacing) { + getState().setSpacing(spacing); requestRepaint(); } @@ -285,18 +292,8 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements * * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing() */ - @Deprecated - public boolean isSpacingEnabled() { - return spacing; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing() - */ public boolean isSpacing() { - return spacing; + return getState().isSpacing(); } /** @@ -350,29 +347,15 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements return (ratio == null) ? 0 : ratio.floatValue(); } - /** - * Sets the component alignment using a short hand string notation. - * - * @deprecated Replaced by - * {@link #setComponentAlignment(Component, Alignment)} - * - * @param component - * A child component in this layout - * @param alignment - * A short hand notation described in {@link AlignmentUtils} - */ - @Deprecated - public void setComponentAlignment(Component component, String alignment) { - AlignmentUtils.setComponentAlignment(this, component, alignment); - } - public void addListener(LayoutClickListener listener) { - addListener(CLICK_EVENT, LayoutClickEvent.class, listener, + addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener, LayoutClickListener.clickMethod); } public void removeListener(LayoutClickListener listener) { - removeListener(CLICK_EVENT, LayoutClickEvent.class, listener); + removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener); } /** diff --git a/src/com/vaadin/ui/AbstractSelect.java b/src/com/vaadin/ui/AbstractSelect.java index bb49626741..e586810b2d 100644 --- a/src/com/vaadin/ui/AbstractSelect.java +++ b/src/com/vaadin/ui/AbstractSelect.java @@ -32,9 +32,11 @@ import com.vaadin.terminal.KeyMapper; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; +import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.gwt.client.ui.dd.VIsOverId; import com.vaadin.terminal.gwt.client.ui.dd.VItemIdIs; import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; +import com.vaadin.ui.AbstractSelect.ItemCaptionMode; /** * <p> @@ -55,46 +57,91 @@ import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; * @since 5.0 */ @SuppressWarnings("serial") -public abstract class AbstractSelect extends AbstractField implements +// TODO currently cannot specify type more precisely in case of multi-select +public abstract class AbstractSelect extends AbstractField<Object> implements Container, Container.Viewer, Container.PropertySetChangeListener, Container.PropertySetChangeNotifier, Container.ItemSetChangeNotifier, - Container.ItemSetChangeListener { + Container.ItemSetChangeListener, Vaadin6Component { + + public enum ItemCaptionMode { + /** + * Item caption mode: Item's ID's <code>String</code> representation is + * used as caption. + */ + ID, + /** + * Item caption mode: Item's <code>String</code> representation is used + * as caption. + */ + ITEM, + /** + * Item caption mode: Index of the item is used as caption. The index + * mode can only be used with the containers implementing the + * {@link com.vaadin.data.Container.Indexed} interface. + */ + INDEX, + /** + * Item caption mode: If an Item has a caption it's used, if not, Item's + * ID's <code>String</code> representation is used as caption. <b>This + * is the default</b>. + */ + EXPLICIT_DEFAULTS_ID, + /** + * Item caption mode: Captions must be explicitly specified. + */ + EXPLICIT, + /** + * Item caption mode: Only icons are shown, captions are hidden. + */ + ICON_ONLY, + /** + * Item caption mode: Item captions are read from property specified + * with <code>setItemCaptionPropertyId</code>. + */ + PROPERTY; + } /** - * Item caption mode: Item's ID's <code>String</code> representation is used - * as caption. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_ID = 0; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_ID = ItemCaptionMode.ID; + /** - * Item caption mode: Item's <code>String</code> representation is used as - * caption. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_ITEM = 1; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_ITEM = ItemCaptionMode.ITEM; + /** - * Item caption mode: Index of the item is used as caption. The index mode - * can only be used with the containers implementing the - * {@link com.vaadin.data.Container.Indexed} interface. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_INDEX = 2; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_INDEX = ItemCaptionMode.INDEX; + /** - * Item caption mode: If an Item has a caption it's used, if not, Item's - * ID's <code>String</code> representation is used as caption. <b>This is - * the default</b>. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = 3; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = ItemCaptionMode.EXPLICIT_DEFAULTS_ID; + /** - * Item caption mode: Captions must be explicitly specified. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_EXPLICIT = 4; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT = ItemCaptionMode.EXPLICIT; + /** - * Item caption mode: Only icons are shown, captions are hidden. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_ICON_ONLY = 5; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_ICON_ONLY = ItemCaptionMode.ICON_ONLY; + /** - * Item caption mode: Item captions are read from property specified with - * <code>setItemCaptionPropertyId</code>. + * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead */ - public static final int ITEM_CAPTION_MODE_PROPERTY = 6; + @Deprecated + public static final ItemCaptionMode ITEM_CAPTION_MODE_PROPERTY = ItemCaptionMode.PROPERTY; /** * Interface for option filtering, used to filter options based on user @@ -159,7 +206,7 @@ public abstract class AbstractSelect extends AbstractField implements /** * Keymapper used to map key values. */ - protected KeyMapper itemIdMapper = new KeyMapper(); + protected KeyMapper<Object> itemIdMapper = new KeyMapper<Object>(); /** * Item icons. @@ -174,7 +221,7 @@ public abstract class AbstractSelect extends AbstractField implements /** * Item caption mode. */ - private int itemCaptionMode = ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID; + private ItemCaptionMode itemCaptionMode = ItemCaptionMode.EXPLICIT_DEFAULTS_ID; /** * Item caption source property id. @@ -276,12 +323,8 @@ public abstract class AbstractSelect extends AbstractField implements * @throws PaintException * if the paint operation failed. */ - @Override public void paintContent(PaintTarget target) throws PaintException { - // Paints field properties - super.paintContent(target); - // Paints select attributes if (isMultiSelect()) { target.addAttribute("selectmode", "multi"); @@ -382,9 +425,7 @@ public abstract class AbstractSelect extends AbstractField implements * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, * java.util.Map) */ - @Override public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); // New option entered (and it is allowed) if (isNewItemsAllowed()) { @@ -515,16 +556,9 @@ public abstract class AbstractSelect extends AbstractField implements // Sets the caption property, if used if (getItemCaptionPropertyId() != null) { - try { - getContainerProperty(newItemCaption, - getItemCaptionPropertyId()).setValue( - newItemCaption); - } catch (final Property.ConversionException ignored) { - /* - * The conversion exception is safely ignored, the - * caption is just missing - */ - } + getContainerProperty(newItemCaption, + getItemCaptionPropertyId()) + .setValue(newItemCaption); } if (isMultiSelect()) { Set values = new HashSet((Collection) getValue()); @@ -543,10 +577,7 @@ public abstract class AbstractSelect extends AbstractField implements * to the terminal or null if no items is visible. */ public Collection<?> getVisibleItemIds() { - if (isVisible()) { - return getItemIds(); - } - return null; + return getItemIds(); } /* Property methods */ @@ -614,8 +645,7 @@ public abstract class AbstractSelect extends AbstractField implements * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object) */ @Override - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException { + public void setValue(Object newValue) throws Property.ReadOnlyException { if (newValue == getNullSelectionItemId()) { newValue = null; } @@ -641,7 +671,7 @@ public abstract class AbstractSelect extends AbstractField implements */ @Override protected void setValue(Object newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Property.ConversionException { + throws Property.ReadOnlyException { if (isMultiSelect()) { if (newValue == null) { @@ -729,7 +759,7 @@ public abstract class AbstractSelect extends AbstractField implements * * @see com.vaadin.data.Container#getContainerProperty(Object, Object) */ - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { return items.getContainerProperty(itemId, propertyId); } @@ -939,10 +969,13 @@ public abstract class AbstractSelect extends AbstractField implements } /** - * Sets the multiselect mode. Setting multiselect mode false may loose + * Sets the multiselect mode. Setting multiselect mode false may lose * selection information: if selected items set contains one or more * selected items, only one of the selected items is kept as selected. * + * Subclasses of AbstractSelect can choose not to support changing the + * multiselect mode, and may throw {@link UnsupportedOperationException}. + * * @param multiSelect * the New value of property multiSelect. */ @@ -1045,11 +1078,11 @@ public abstract class AbstractSelect extends AbstractField implements switch (getItemCaptionMode()) { - case ITEM_CAPTION_MODE_ID: + case ID: caption = itemId.toString(); break; - case ITEM_CAPTION_MODE_INDEX: + case INDEX: if (items instanceof Container.Indexed) { caption = String.valueOf(((Container.Indexed) items) .indexOfId(itemId)); @@ -1058,29 +1091,32 @@ public abstract class AbstractSelect extends AbstractField implements } break; - case ITEM_CAPTION_MODE_ITEM: + case ITEM: final Item i = getItem(itemId); if (i != null) { caption = i.toString(); } break; - case ITEM_CAPTION_MODE_EXPLICIT: + case EXPLICIT: caption = itemCaptions.get(itemId); break; - case ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID: + case EXPLICIT_DEFAULTS_ID: caption = itemCaptions.get(itemId); if (caption == null) { caption = itemId.toString(); } break; - case ITEM_CAPTION_MODE_PROPERTY: - final Property p = getContainerProperty(itemId, + case PROPERTY: + final Property<?> p = getContainerProperty(itemId, getItemCaptionPropertyId()); if (p != null) { - caption = p.toString(); + Object value = p.getValue(); + if (value != null) { + caption = value.toString(); + } } break; } @@ -1090,7 +1126,7 @@ public abstract class AbstractSelect extends AbstractField implements } /** - * Sets the icon for an item. + * Sets tqhe icon for an item. * * @param itemId * the id of the item to be assigned an icon. @@ -1125,7 +1161,7 @@ public abstract class AbstractSelect extends AbstractField implements return null; } - final Property ip = getContainerProperty(itemId, + final Property<?> ip = getContainerProperty(itemId, getItemIconPropertyId()); if (ip == null) { return null; @@ -1167,8 +1203,8 @@ public abstract class AbstractSelect extends AbstractField implements * @param mode * the One of the modes listed above. */ - public void setItemCaptionMode(int mode) { - if (ITEM_CAPTION_MODE_ID <= mode && mode <= ITEM_CAPTION_MODE_PROPERTY) { + public void setItemCaptionMode(ItemCaptionMode mode) { + if (mode != null) { itemCaptionMode = mode; requestRepaint(); } @@ -1202,7 +1238,7 @@ public abstract class AbstractSelect extends AbstractField implements * * @return the One of the modes listed above. */ - public int getItemCaptionMode() { + public ItemCaptionMode getItemCaptionMode() { return itemCaptionMode; } @@ -1216,7 +1252,9 @@ public abstract class AbstractSelect extends AbstractField implements * null resets the item caption mode to * <code>ITEM_CAPTION_EXPLICIT_DEFAULTS_ID</code>. * </p> - * + * <p> + * Note that the type of the property used for caption must be String + * </p> * <p> * Setting the property id to null disables this feature. The id is null by * default @@ -1691,7 +1729,7 @@ public abstract class AbstractSelect extends AbstractField implements public void addNotifierForItem(Object itemId) { switch (getItemCaptionMode()) { - case ITEM_CAPTION_MODE_ITEM: + case ITEM: final Item i = getItem(itemId); if (i == null) { return; @@ -1704,7 +1742,7 @@ public abstract class AbstractSelect extends AbstractField implements Collection<?> pids = i.getItemPropertyIds(); if (pids != null) { for (Iterator<?> it = pids.iterator(); it.hasNext();) { - Property p = i.getItemProperty(it.next()); + Property<?> p = i.getItemProperty(it.next()); if (p != null && p instanceof Property.ValueChangeNotifier) { ((Property.ValueChangeNotifier) p) @@ -1715,8 +1753,8 @@ public abstract class AbstractSelect extends AbstractField implements } break; - case ITEM_CAPTION_MODE_PROPERTY: - final Property p = getContainerProperty(itemId, + case PROPERTY: + final Property<?> p = getContainerProperty(itemId, getItemCaptionPropertyId()); if (p != null && p instanceof Property.ValueChangeNotifier) { ((Property.ValueChangeNotifier) p) diff --git a/src/com/vaadin/ui/AbstractSplitPanel.java b/src/com/vaadin/ui/AbstractSplitPanel.java index b507b88478..5205952621 100644 --- a/src/com/vaadin/ui/AbstractSplitPanel.java +++ b/src/com/vaadin/ui/AbstractSplitPanel.java @@ -7,15 +7,15 @@ package com.vaadin.ui; import java.io.Serializable; import java.lang.reflect.Method; import java.util.Iterator; -import java.util.Map; import com.vaadin.event.ComponentEventListener; import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Sizeable; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VSplitPanel; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelRpc; +import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState; +import com.vaadin.terminal.gwt.client.ui.splitpanel.AbstractSplitPanelState.SplitterState; import com.vaadin.tools.ReflectTools; /** @@ -29,21 +29,26 @@ import com.vaadin.tools.ReflectTools; * @VERSION@ * @since 6.5 */ -public abstract class AbstractSplitPanel extends AbstractLayout { +public abstract class AbstractSplitPanel extends AbstractComponentContainer { - private Component firstComponent; + private Unit posUnit; - private Component secondComponent; + private AbstractSplitPanelRpc rpc = new AbstractSplitPanelRpc() { - private float pos = 50; - - private int posUnit = UNITS_PERCENTAGE; - - private boolean posReversed = false; + public void splitterClick(MouseEventDetails mouseDetails) { + fireEvent(new SplitterClickEvent(AbstractSplitPanel.this, + mouseDetails)); + } - private boolean locked = false; + public void setSplitterPosition(float position) { + getState().getSplitterState().setPosition(position); + } + }; - private static final String SPLITTER_CLICK_EVENT = VSplitPanel.SPLITTER_CLICK_EVENT_IDENTIFIER; + public AbstractSplitPanel() { + registerRpc(rpc); + setSplitPosition(50, Unit.PERCENTAGE, false); + } /** * Modifiable and Serializable Iterator for the components, used by @@ -67,17 +72,17 @@ public abstract class AbstractSplitPanel extends AbstractLayout { } i++; if (i == 1) { - return firstComponent == null ? secondComponent - : firstComponent; + return (getFirstComponent() == null ? getSecondComponent() + : getFirstComponent()); } else if (i == 2) { - return secondComponent; + return getSecondComponent(); } return null; } public void remove() { if (i == 1) { - if (firstComponent != null) { + if (getFirstComponent() != null) { setFirstComponent(null); i = 0; } else { @@ -98,60 +103,83 @@ public abstract class AbstractSplitPanel extends AbstractLayout { */ @Override public void addComponent(Component c) { - if (firstComponent == null) { - firstComponent = c; - } else if (secondComponent == null) { - secondComponent = c; + if (getFirstComponent() == null) { + setFirstComponent(c); + } else if (getSecondComponent() == null) { + setSecondComponent(c); } else { throw new UnsupportedOperationException( "Split panel can contain only two components"); } - super.addComponent(c); - requestRepaint(); } + /** + * Sets the first component of this split panel. Depending on the direction + * the first component is shown at the top or to the left. + * + * @param c + * The component to use as first component + */ public void setFirstComponent(Component c) { - if (firstComponent == c) { + if (getFirstComponent() == c) { // Nothing to do return; } - if (firstComponent != null) { + if (getFirstComponent() != null) { // detach old - removeComponent(firstComponent); + removeComponent(getFirstComponent()); } - firstComponent = c; - super.addComponent(c); + getState().setFirstChild(c); + if (c != null) { + super.addComponent(c); + } + requestRepaint(); } + /** + * Sets the second component of this split panel. Depending on the direction + * the second component is shown at the bottom or to the left. + * + * @param c + * The component to use as first component + */ public void setSecondComponent(Component c) { - if (c == secondComponent) { + if (getSecondComponent() == c) { // Nothing to do return; } - if (secondComponent != null) { + if (getSecondComponent() != null) { // detach old - removeComponent(secondComponent); + removeComponent(getSecondComponent()); + } + getState().setSecondChild(c); + if (c != null) { + super.addComponent(c); } - secondComponent = c; - super.addComponent(c); requestRepaint(); } /** - * @return the first component of this SplitPanel. + * Gets the first component of this split panel. Depending on the direction + * this is either the component shown at the top or to the left. + * + * @return the first component of this split panel */ public Component getFirstComponent() { - return firstComponent; + return (Component) getState().getFirstChild(); } /** - * @return the second component of this SplitPanel. + * Gets the second component of this split panel. Depending on the direction + * this is either the component shown at the top or to the left. + * + * @return the second component of this split panel */ public Component getSecondComponent() { - return secondComponent; + return (Component) getState().getSecondChild(); } /** @@ -163,10 +191,10 @@ public abstract class AbstractSplitPanel extends AbstractLayout { @Override public void removeComponent(Component c) { super.removeComponent(c); - if (c == firstComponent) { - firstComponent = null; - } else if (c == secondComponent) { - secondComponent = null; + if (c == getFirstComponent()) { + getState().setFirstChild(null); + } else if (c == getSecondComponent()) { + getState().setSecondChild(null); } requestRepaint(); } @@ -188,58 +216,20 @@ public abstract class AbstractSplitPanel extends AbstractLayout { */ public int getComponentCount() { int count = 0; - if (firstComponent != null) { + if (getFirstComponent() != null) { count++; } - if (secondComponent != null) { + if (getSecondComponent() != null) { count++; } return count; } - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - final String position = pos + UNIT_SYMBOLS[posUnit]; - - target.addAttribute("position", position); - - if (isLocked()) { - target.addAttribute("locked", true); - } - - target.addAttribute("reversed", posReversed); - - if (firstComponent != null) { - firstComponent.paint(target); - } else { - VerticalLayout temporaryComponent = new VerticalLayout(); - temporaryComponent.setParent(this); - temporaryComponent.paint(target); - } - if (secondComponent != null) { - secondComponent.paint(target); - } else { - VerticalLayout temporaryComponent = new VerticalLayout(); - temporaryComponent.setParent(this); - temporaryComponent.paint(target); - } - } - /* Documented in superclass */ public void replaceComponent(Component oldComponent, Component newComponent) { - if (oldComponent == firstComponent) { + if (oldComponent == getFirstComponent()) { setFirstComponent(newComponent); - } else if (oldComponent == secondComponent) { + } else if (oldComponent == getSecondComponent()) { setSecondComponent(newComponent); } requestRepaint(); @@ -254,7 +244,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * unit is percentage. */ public void setSplitPosition(float pos) { - setSplitPosition(pos, posUnit, true, false); + setSplitPosition(pos, posUnit, false); } /** @@ -270,7 +260,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * second region else it is measured by the first region */ public void setSplitPosition(float pos, boolean reverse) { - setSplitPosition(pos, posUnit, true, reverse); + setSplitPosition(pos, posUnit, reverse); } /** @@ -282,8 +272,8 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * @param unit * the unit (from {@link Sizeable}) in which the size is given. */ - public void setSplitPosition(float pos, int unit) { - setSplitPosition(pos, unit, true, false); + public void setSplitPosition(float pos, Unit unit) { + setSplitPosition(pos, unit, false); } /** @@ -299,8 +289,21 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * second region else it is measured by the first region * */ - public void setSplitPosition(float pos, int unit, boolean reverse) { - setSplitPosition(pos, unit, true, reverse); + public void setSplitPosition(float pos, Unit unit, boolean reverse) { + if (unit != Unit.PERCENTAGE && unit != Unit.PIXELS) { + throw new IllegalArgumentException( + "Only percentage and pixel units are allowed"); + } + if (unit != Unit.PERCENTAGE) { + pos = Math.round(pos); + } + SplitterState splitterState = getState().getSplitterState(); + splitterState.setPosition(pos); + splitterState.setPositionUnit(unit.getSymbol()); + splitterState.setPositionReversed(reverse); + posUnit = unit; + + requestRepaint(); } /** @@ -310,7 +313,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * @return position of the splitter */ public float getSplitPosition() { - return pos; + return getState().getSplitterState().getPosition(); } /** @@ -318,41 +321,11 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * * @return unit of position of the splitter */ - public int getSplitPositionUnit() { + public Unit getSplitPositionUnit() { return posUnit; } /** - * Moves the position of the splitter. - * - * @param pos - * the new size of the first region. Fractions are only allowed - * when unit is percentage. - * @param unit - * the unit (from {@link Sizeable}) in which the size is given. - * @param repaintNotNeeded - * true if client side needs to be updated. Use false if the - * position info has come from the client side, thus it already - * knows the position. - */ - private void setSplitPosition(float pos, int unit, boolean repaintNeeded, - boolean reverse) { - if (unit != UNITS_PERCENTAGE && unit != UNITS_PIXELS) { - throw new IllegalArgumentException( - "Only percentage and pixel units are allowed"); - } - if (unit != UNITS_PERCENTAGE) { - pos = Math.round(pos); - } - this.pos = pos; - posUnit = unit; - posReversed = reverse; - if (repaintNeeded) { - requestRepaint(); - } - } - - /** * Lock the SplitPanels position, disabling the user from dragging the split * handle. * @@ -360,7 +333,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * Set <code>true</code> if locked, <code>false</code> otherwise. */ public void setLocked(boolean locked) { - this.locked = locked; + getState().getSplitterState().setLocked(locked); requestRepaint(); } @@ -371,37 +344,7 @@ public abstract class AbstractSplitPanel extends AbstractLayout { * @return <code>true</code> if locked, <code>false</code> otherwise. */ public boolean isLocked() { - return locked; - } - - /* - * Invoked when a variable of the component changes. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @SuppressWarnings("unchecked") - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - - super.changeVariables(source, variables); - - if (variables.containsKey("position") && !isLocked()) { - Float newPos = (Float) variables.get("position"); - setSplitPosition(newPos, posUnit, posReversed); - } - - if (variables.containsKey(SPLITTER_CLICK_EVENT)) { - fireClick((Map<String, Object>) variables.get(SPLITTER_CLICK_EVENT)); - } - - } - - @Override - protected void fireClick(Map<String, Object> parameters) { - MouseEventDetails mouseDetails = MouseEventDetails - .deSerialize((String) parameters.get("mouseDetails")); - - fireEvent(new SplitterClickEvent(this, mouseDetails)); + return getState().getSplitterState().isLocked(); } /** @@ -436,12 +379,19 @@ public abstract class AbstractSplitPanel extends AbstractLayout { } public void addListener(SplitterClickListener listener) { - addListener(SPLITTER_CLICK_EVENT, SplitterClickEvent.class, listener, + addListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, + SplitterClickEvent.class, listener, SplitterClickListener.clickMethod); } public void removeListener(SplitterClickListener listener) { - removeListener(SPLITTER_CLICK_EVENT, SplitterClickEvent.class, listener); + removeListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, + SplitterClickEvent.class, listener); + } + + @Override + public AbstractSplitPanelState getState() { + return (AbstractSplitPanelState) super.getState(); } } diff --git a/src/com/vaadin/ui/AbstractTextField.java b/src/com/vaadin/ui/AbstractTextField.java index 346d370bd5..acb1d71ed8 100644 --- a/src/com/vaadin/ui/AbstractTextField.java +++ b/src/com/vaadin/ui/AbstractTextField.java @@ -18,10 +18,11 @@ import com.vaadin.event.FieldEvents.TextChangeListener; import com.vaadin.event.FieldEvents.TextChangeNotifier; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VTextField; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; -public abstract class AbstractTextField extends AbstractField implements - BlurNotifier, FocusNotifier, TextChangeNotifier { +public abstract class AbstractTextField extends AbstractField<String> implements + BlurNotifier, FocusNotifier, TextChangeNotifier, Vaadin6Component { /** * Value formatter used to format the string contents. @@ -99,9 +100,7 @@ public abstract class AbstractTextField extends AbstractField implements super(); } - @Override public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); if (getMaxLength() >= 0) { target.addAttribute("maxLength", getMaxLength()); @@ -173,8 +172,8 @@ public abstract class AbstractTextField extends AbstractField implements } @Override - public Object getValue() { - Object v = super.getValue(); + public String getValue() { + String v = super.getValue(); if (format == null || v == null) { return v; } @@ -185,12 +184,10 @@ public abstract class AbstractTextField extends AbstractField implements } } - @Override public void changeVariables(Object source, Map<String, Object> variables) { changingVariables = true; try { - super.changeVariables(source, variables); if (variables.containsKey(VTextField.VAR_CURSOR)) { Integer object = (Integer) variables.get(VTextField.VAR_CURSOR); @@ -252,7 +249,7 @@ public abstract class AbstractTextField extends AbstractField implements } @Override - public Class getType() { + public Class<String> getType() { return String.class; } @@ -375,7 +372,7 @@ public abstract class AbstractTextField extends AbstractField implements @Override protected boolean isEmpty() { - return super.isEmpty() || toString().length() == 0; + return super.isEmpty() || getValue().length() == 0; } /** @@ -463,7 +460,7 @@ public abstract class AbstractTextField extends AbstractField implements } @Override - protected void setInternalValue(Object newValue) { + protected void setInternalValue(String newValue) { if (changingVariables && !textChangeEventPending) { /* @@ -505,8 +502,7 @@ public abstract class AbstractTextField extends AbstractField implements } @Override - public void setValue(Object newValue) throws ReadOnlyException, - ConversionException { + public void setValue(Object newValue) throws ReadOnlyException { super.setValue(newValue); /* * Make sure w reset lastKnownTextContent field on value change. The @@ -515,7 +511,7 @@ public abstract class AbstractTextField extends AbstractField implements * case. AbstractField optimizes value change if the existing value is * reset. Also we need to force repaint if the flag is on. */ - if(lastKnownTextContent != null) { + if (lastKnownTextContent != null) { lastKnownTextContent = null; requestRepaint(); } @@ -753,4 +749,4 @@ public abstract class AbstractTextField extends AbstractField implements removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); } -}
\ No newline at end of file +} diff --git a/src/com/vaadin/ui/Accordion.java b/src/com/vaadin/ui/Accordion.java index 5cf805615c..b937c7bc2b 100644 --- a/src/com/vaadin/ui/Accordion.java +++ b/src/com/vaadin/ui/Accordion.java @@ -3,8 +3,6 @@ */ package com.vaadin.ui; -import com.vaadin.terminal.gwt.client.ui.VAccordion; - /** * An accordion is a component similar to a {@link TabSheet}, but with a * vertical orientation and the selected component presented between tabs. @@ -16,8 +14,6 @@ import com.vaadin.terminal.gwt.client.ui.VAccordion; * * @see TabSheet */ -@SuppressWarnings("serial") -@ClientWidget(VAccordion.class) public class Accordion extends TabSheet { } diff --git a/src/com/vaadin/ui/AlignmentUtils.java b/src/com/vaadin/ui/AlignmentUtils.java deleted file mode 100644 index 029fc8c9b5..0000000000 --- a/src/com/vaadin/ui/AlignmentUtils.java +++ /dev/null @@ -1,151 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import com.vaadin.ui.Layout.AlignmentHandler; - -/** - * Helper class for setting alignments using a short notation. - * - * Supported notation is: - * - * t,top for top alignment - * - * m,middle for vertical center alignment - * - * b,bottom for bottom alignment - * - * l,left for left alignment - * - * c,center for horizontal center alignment - * - * r,right for right alignment - * - * @deprecated {@code AlignmentUtils} has been replaced by {@link Alignment}. - */ -@SuppressWarnings({ "serial" }) -@Deprecated -public class AlignmentUtils implements Serializable { - - private static int horizontalMask = AlignmentHandler.ALIGNMENT_LEFT - | AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER - | AlignmentHandler.ALIGNMENT_RIGHT; - - private static int verticalMask = AlignmentHandler.ALIGNMENT_TOP - | AlignmentHandler.ALIGNMENT_VERTICAL_CENTER - | AlignmentHandler.ALIGNMENT_BOTTOM; - - private static Map<String, Integer> alignmentStrings = new HashMap<String, Integer>(); - - private static void addMapping(int alignment, String... values) { - for (String s : values) { - alignmentStrings.put(s, alignment); - } - } - - static { - addMapping(AlignmentHandler.ALIGNMENT_TOP, "t", "top"); - addMapping(AlignmentHandler.ALIGNMENT_BOTTOM, "b", "bottom"); - addMapping(AlignmentHandler.ALIGNMENT_VERTICAL_CENTER, "m", "middle"); - - addMapping(AlignmentHandler.ALIGNMENT_LEFT, "l", "left"); - addMapping(AlignmentHandler.ALIGNMENT_RIGHT, "r", "right"); - addMapping(AlignmentHandler.ALIGNMENT_HORIZONTAL_CENTER, "c", "center"); - } - - /** - * Set the alignment for the component using short notation - * - * @param parent - * @param component - * @param alignment - * String containing one or two alignment strings. If short - * notation "r","t",etc is used valid strings include - * "r","rt","tr","t". If the longer notation is used the - * alignments should be separated by a space e.g. - * "right","right top","top right","top". It is valid to mix - * short and long notation but they must be separated by a space - * e.g. "r top". - * @throws IllegalArgumentException - */ - public static void setComponentAlignment(AlignmentHandler parent, - Component component, String alignment) - throws IllegalArgumentException { - if (alignment == null || alignment.length() == 0) { - throw new IllegalArgumentException( - "alignment for setComponentAlignment() cannot be null or empty"); - } - - Integer currentAlignment = parent.getComponentAlignment(component) - .getBitMask(); - - if (alignment.length() == 1) { - // Use short form "t","l",... - currentAlignment = parseAlignment(alignment.substring(0, 1), - currentAlignment); - } else if (alignment.length() == 2) { - // Use short form "tr","lb",... - currentAlignment = parseAlignment(alignment.substring(0, 1), - currentAlignment); - currentAlignment = parseAlignment(alignment.substring(1, 2), - currentAlignment); - } else { - // Alignments are separated by space - String[] strings = alignment.split(" "); - if (strings.length > 2) { - throw new IllegalArgumentException( - "alignment for setComponentAlignment() should not contain more than 2 alignments"); - } - for (String alignmentString : strings) { - currentAlignment = parseAlignment(alignmentString, - currentAlignment); - } - } - - int horizontalAlignment = currentAlignment & horizontalMask; - int verticalAlignment = currentAlignment & verticalMask; - parent.setComponentAlignment(component, new Alignment( - horizontalAlignment + verticalAlignment)); - } - - /** - * Parse alignmentString which contains one alignment (horizontal or - * vertical) and return and updated version of the passed alignment where - * the alignment in one direction has been changed. If the passed - * alignmentString is unknown an exception is thrown - * - * @param alignmentString - * @param alignment - * @return - * @throws IllegalArgumentException - */ - private static int parseAlignment(String alignmentString, int alignment) - throws IllegalArgumentException { - Integer parsed = alignmentStrings.get(alignmentString.toLowerCase()); - - if (parsed == null) { - throw new IllegalArgumentException( - "Could not parse alignment string '" + alignmentString - + "'"); - } - - if ((parsed & horizontalMask) != 0) { - // Get the vertical alignment from the current alignment - int vertical = (alignment & verticalMask); - // Add the parsed horizontal alignment - alignment = (vertical | parsed); - } else { - // Get the horizontal alignment from the current alignment - int horizontal = (alignment & horizontalMask); - // Add the parsed vertical alignment - alignment = (horizontal | parsed); - } - - return alignment; - } -} diff --git a/src/com/vaadin/ui/Audio.java b/src/com/vaadin/ui/Audio.java index 574c1f4186..ac2ee869a6 100644 --- a/src/com/vaadin/ui/Audio.java +++ b/src/com/vaadin/ui/Audio.java @@ -5,7 +5,6 @@ package com.vaadin.ui; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VAudio; /** * The Audio component translates into an HTML5 <audio> element and as @@ -28,7 +27,6 @@ import com.vaadin.terminal.gwt.client.ui.VAudio; * @author Vaadin Ltd * @since 6.7.0 */ -@ClientWidget(VAudio.class) public class Audio extends AbstractMedia { public Audio() { diff --git a/src/com/vaadin/ui/BaseFieldFactory.java b/src/com/vaadin/ui/BaseFieldFactory.java deleted file mode 100644 index fe271aabe4..0000000000 --- a/src/com/vaadin/ui/BaseFieldFactory.java +++ /dev/null @@ -1,90 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * Default implementation of the the following Field types are used by default: - * <p> - * <b>Boolean</b>: Button(switchMode:true).<br/> - * <b>Date</b>: DateField(resolution: day).<br/> - * <b>Item</b>: Form. <br/> - * <b>default field type</b>: TextField. - * <p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.1 - * @deprecated use {@link DefaultFieldFactory} or own implementations on - * {@link FormFieldFactory} or {@link TableFieldFactory} instead. - */ - -@Deprecated -@SuppressWarnings("serial") -public class BaseFieldFactory implements FieldFactory { - - /** - * Creates the field based on type of data. - * - * - * @param type - * the type of data presented in field. - * @param uiContext - * the context where the Field is presented. - * - * @see com.vaadin.ui.FieldFactory#createField(Class, Component) - */ - public Field createField(Class<?> type, Component uiContext) { - return DefaultFieldFactory.createFieldByPropertyType(type); - } - - /** - * Creates the field based on the datasource property. - * - * @see com.vaadin.ui.FieldFactory#createField(Property, Component) - */ - public Field createField(Property property, Component uiContext) { - if (property != null) { - return createField(property.getType(), uiContext); - } else { - return null; - } - } - - /** - * Creates the field based on the item and property id. - * - * @see com.vaadin.ui.FieldFactory#createField(Item, Object, Component) - */ - public Field createField(Item item, Object propertyId, Component uiContext) { - if (item != null && propertyId != null) { - final Field f = createField(item.getItemProperty(propertyId), - uiContext); - if (f instanceof AbstractComponent) { - String name = DefaultFieldFactory - .createCaptionByPropertyId(propertyId); - f.setCaption(name); - } - return f; - } else { - return null; - } - } - - /** - * @see com.vaadin.ui.FieldFactory#createField(com.vaadin.data.Container, - * java.lang.Object, java.lang.Object, com.vaadin.ui.Component) - */ - public Field createField(Container container, Object itemId, - Object propertyId, Component uiContext) { - return createField(container.getContainerProperty(itemId, propertyId), - uiContext); - } - -} diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java index 3c99784592..f5e45ef3ef 100644 --- a/src/com/vaadin/ui/Button.java +++ b/src/com/vaadin/ui/Button.java @@ -4,27 +4,25 @@ package com.vaadin.ui; -import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Method; -import java.util.Map; -import com.vaadin.data.Property; +import com.vaadin.event.Action; import com.vaadin.event.FieldEvents; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; +import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.ShortcutAction; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutAction.ModifierKey; import com.vaadin.event.ShortcutListener; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VButton; -import com.vaadin.ui.ClientWidget.LoadStyle; -import com.vaadin.ui.themes.BaseTheme; +import com.vaadin.terminal.gwt.client.ui.button.ButtonServerRpc; +import com.vaadin.terminal.gwt.client.ui.button.ButtonState; +import com.vaadin.tools.ReflectTools; +import com.vaadin.ui.Component.Focusable; /** * A generic button component. @@ -35,29 +33,39 @@ import com.vaadin.ui.themes.BaseTheme; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(value = VButton.class, loadStyle = LoadStyle.EAGER) -public class Button extends AbstractField implements FieldEvents.BlurNotifier, - FieldEvents.FocusNotifier { +public class Button extends AbstractComponent implements + FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable, + Action.ShortcutNotifier { - /* Private members */ + private ButtonServerRpc rpc = new ButtonServerRpc() { + public void click(MouseEventDetails mouseEventDetails) { + fireClick(mouseEventDetails); + } - boolean switchMode = false; + public void disableOnClick() { + // Could be optimized so the button is not repainted because of + // this (client side has already disabled the button) + setEnabled(false); + } + }; - boolean disableOnClick = false; + FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) { + @Override + protected void fireEvent(Event event) { + Button.this.fireEvent(event); + } + }; /** - * Creates a new push button. The value of the push button is false and it - * is immediate by default. - * + * Creates a new push button. */ public Button() { - setValue(Boolean.FALSE); + registerRpc(rpc); + registerRpc(focusBlurRpc); } /** - * Creates a new push button. - * - * The value of the push button is false and it is immediate by default. + * Creates a new push button with the given caption. * * @param caption * the Button caption. @@ -68,7 +76,7 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, } /** - * Creates a new push button with click listener. + * Creates a new push button with a click listener. * * @param caption * the Button caption. @@ -81,239 +89,6 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, } /** - * Creates a new push button with a method listening button clicks. Using - * this method is discouraged because it cannot be checked during - * compilation. Use - * {@link #Button(String, com.vaadin.ui.Button.ClickListener)} instead. The - * method must have either no parameters, or only one parameter of - * Button.ClickEvent type. - * - * @param caption - * the Button caption. - * @param target - * the Object having the method for listening button clicks. - * @param methodName - * the name of the method in target object, that receives button - * click events. - */ - public Button(String caption, Object target, String methodName) { - this(caption); - addListener(ClickEvent.class, target, methodName); - } - - /** - * Creates a new switch button with initial value. - * - * @param state - * the Initial state of the switch-button. - * @param initialState - * @deprecated use {@link CheckBox} instead of Button in "switchmode" - */ - @Deprecated - public Button(String caption, boolean initialState) { - setCaption(caption); - setValue(Boolean.valueOf(initialState)); - setSwitchMode(true); - } - - /** - * Creates a new switch button that is connected to a boolean property. - * - * @param state - * the Initial state of the switch-button. - * @param dataSource - * @deprecated use {@link CheckBox} instead of Button in "switchmode" - */ - @Deprecated - public Button(String caption, Property dataSource) { - setCaption(caption); - setSwitchMode(true); - setPropertyDataSource(dataSource); - } - - /** - * Paints the content of this component. - * - * @param event - * the PaintEvent. - * @throws IOException - * if the writing failed due to input/output error. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - if (isSwitchMode()) { - target.addAttribute("type", "switch"); - } - target.addVariable(this, "state", booleanValue()); - - if (isDisableOnClick()) { - target.addAttribute(VButton.ATTR_DISABLE_ON_CLICK, true); - } - if (clickShortcut != null) { - target.addAttribute("keycode", clickShortcut.getKeyCode()); - } - } - - /** - * Invoked when the value of a variable has changed. Button listeners are - * notified if the button is clicked. - * - * @param source - * @param variables - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - - if (variables.containsKey("disabledOnClick")) { - // Could be optimized so the button is not repainted because of this - // (client side has already disabled the button) - setEnabled(false); - } - - if (!isReadOnly() && variables.containsKey("state")) { - // Gets the new and old button states - final Boolean newValue = (Boolean) variables.get("state"); - final Boolean oldValue = (Boolean) getValue(); - - if (isSwitchMode()) { - - // For switch button, the event is only sent if the - // switch state is changed - if (newValue != null && !newValue.equals(oldValue) - && !isReadOnly()) { - setValue(newValue); - if (variables.containsKey("mousedetails")) { - fireClick(MouseEventDetails - .deSerialize((String) variables - .get("mousedetails"))); - } else { - // for compatibility with custom implementations which - // don't send mouse details - fireClick(); - } - } - } else { - - // Only send click event if the button is pushed - if (newValue.booleanValue()) { - if (variables.containsKey("mousedetails")) { - fireClick(MouseEventDetails - .deSerialize((String) variables - .get("mousedetails"))); - } else { - // for compatibility with custom implementations which - // don't send mouse details - fireClick(); - } - } - - // If the button is true for some reason, release it - if (null == oldValue || oldValue.booleanValue()) { - setValue(Boolean.FALSE); - } - } - } - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - } - - /** - * Checks if it is switchMode. - * - * @return <code>true</code> if it is in Switch Mode, otherwise - * <code>false</code>. - * @deprecated the {@link CheckBox} component should be used instead of - * Button in switch mode - */ - @Deprecated - public boolean isSwitchMode() { - return switchMode; - } - - /** - * Sets the switchMode. - * - * @param switchMode - * The switchMode to set. - * @deprecated the {@link CheckBox} component should be used instead of - * Button in switch mode - */ - @Deprecated - public void setSwitchMode(boolean switchMode) { - this.switchMode = switchMode; - if (!switchMode) { - setImmediate(true); - if (booleanValue()) { - setValue(Boolean.FALSE); - } - } - } - - /** - * Get the boolean value of the button state. - * - * @return True iff the button is pressed down or checked. - */ - public boolean booleanValue() { - Boolean value = (Boolean) getValue(); - return (null == value) ? false : value.booleanValue(); - } - - /** - * Sets immediate mode. Push buttons can not be set in non-immediate mode. - * - * @see com.vaadin.ui.AbstractComponent#setImmediate(boolean) - */ - @Override - public void setImmediate(boolean immediate) { - // Push buttons are always immediate - super.setImmediate(!isSwitchMode() || immediate); - } - - /** - * The type of the button as a property. - * - * @see com.vaadin.data.Property#getType() - */ - @Override - public Class getType() { - return Boolean.class; - } - - /* Click event */ - - private static final Method BUTTON_CLICK_METHOD; - - /** - * Button style with no decorations. Looks like a link, acts like a button - * - * @deprecated use {@link BaseTheme#BUTTON_LINK} instead. - */ - @Deprecated - public static final String STYLE_LINK = "link"; - - static { - try { - BUTTON_CLICK_METHOD = ClickListener.class.getDeclaredMethod( - "buttonClick", new Class[] { ClickEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in Button"); - } - } - - /** * Click event. This event is thrown, when the button is clicked. * * @author Vaadin Ltd. @@ -484,6 +259,10 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, */ public interface ClickListener extends Serializable { + public static final Method BUTTON_CLICK_METHOD = ReflectTools + .findMethod(ClickListener.class, "buttonClick", + ClickEvent.class); + /** * Called when a {@link Button} has been clicked. A reference to the * button is given by {@link ClickEvent#getButton()}. @@ -502,7 +281,8 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, * the Listener to be added. */ public void addListener(ClickListener listener) { - addListener(ClickEvent.class, listener, BUTTON_CLICK_METHOD); + addListener(ClickEvent.class, listener, + ClickListener.BUTTON_CLICK_METHOD); } /** @@ -512,7 +292,8 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, * the Listener to be removed. */ public void removeListener(ClickListener listener) { - removeListener(ClickEvent.class, listener, BUTTON_CLICK_METHOD); + removeListener(ClickEvent.class, listener, + ClickListener.BUTTON_CLICK_METHOD); } /** @@ -549,16 +330,6 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, fireEvent(new Button.ClickEvent(this, details)); } - @Override - protected void setInternalValue(Object newValue) { - // Make sure only booleans get through - if (null != newValue && !(newValue instanceof Boolean)) { - throw new IllegalArgumentException(getClass().getSimpleName() - + " only accepts Boolean values"); - } - super.setInternalValue(newValue); - } - public void addListener(BlurListener listener) { addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, BlurListener.blurMethod); @@ -584,6 +355,8 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, protected ClickShortcut clickShortcut; + private int tabIndex = 0; + /** * Makes it possible to invoke a click on this button by pressing the given * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> @@ -601,6 +374,7 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, } clickShortcut = new ClickShortcut(this, keyCode, modifiers); addShortcutListener(clickShortcut); + getState().setClickShortcutKeyCode(clickShortcut.getKeyCode()); } /** @@ -611,6 +385,7 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, if (clickShortcut != null) { removeShortcutListener(clickShortcut); clickShortcut = null; + getState().setClickShortcutKeyCode(0); } } @@ -678,7 +453,7 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, * @return true if the button is disabled when clicked, false otherwise */ public boolean isDisableOnClick() { - return disableOnClick; + return getState().isDisableOnClick(); } /** @@ -690,8 +465,28 @@ public class Button extends AbstractField implements FieldEvents.BlurNotifier, * true to disable button when it is clicked, false otherwise */ public void setDisableOnClick(boolean disableOnClick) { - this.disableOnClick = disableOnClick; + getState().setDisableOnClick(disableOnClick); requestRepaint(); } + public int getTabIndex() { + return tabIndex; + } + + public void setTabIndex(int tabIndex) { + this.tabIndex = tabIndex; + + } + + @Override + public void focus() { + // Overridden only to make public + super.focus(); + } + + @Override + public ButtonState getState() { + return (ButtonState) super.getState(); + } + } diff --git a/src/com/vaadin/ui/CheckBox.java b/src/com/vaadin/ui/CheckBox.java index 00a248cdf3..147a270059 100644 --- a/src/com/vaadin/ui/CheckBox.java +++ b/src/com/vaadin/ui/CheckBox.java @@ -4,110 +4,137 @@ package com.vaadin.ui; -import java.lang.reflect.Method; - import com.vaadin.data.Property; +import com.vaadin.event.FieldEvents.BlurEvent; +import com.vaadin.event.FieldEvents.BlurListener; +import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; +import com.vaadin.event.FieldEvents.FocusEvent; +import com.vaadin.event.FieldEvents.FocusListener; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.checkbox.CheckBoxServerRpc; +import com.vaadin.terminal.gwt.client.ui.checkbox.CheckBoxState; -@ClientWidget(com.vaadin.terminal.gwt.client.ui.VCheckBox.class) -public class CheckBox extends Button { - /** - * Creates a new switch button. - */ - public CheckBox() { - setSwitchMode(true); - } +public class CheckBox extends AbstractField<Boolean> { + + private CheckBoxServerRpc rpc = new CheckBoxServerRpc() { + + public void setChecked(boolean checked, + MouseEventDetails mouseEventDetails) { + if (isReadOnly()) { + return; + } + + final Boolean oldValue = getValue(); + final Boolean newValue = checked; + + if (!newValue.equals(oldValue)) { + // The event is only sent if the switch state is changed + setValue(newValue); + } + + } + }; + + FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) { + @Override + protected void fireEvent(Event event) { + CheckBox.this.fireEvent(event); + } + }; /** - * Creates a new switch button with a caption and a set initial state. - * - * @param caption - * the caption of the switch button - * @param initialState - * the initial state of the switch button + * Creates a new checkbox. */ - @SuppressWarnings("deprecation") - public CheckBox(String caption, boolean initialState) { - super(caption, initialState); + public CheckBox() { + registerRpc(rpc); + registerRpc(focusBlurRpc); + setValue(Boolean.FALSE); } /** - * Creates a new switch button with a caption and a click listener. + * Creates a new checkbox with a set caption. * * @param caption - * the caption of the switch button - * @param listener - * the click listener + * the Checkbox caption. */ - public CheckBox(String caption, ClickListener listener) { - super(caption, listener); - setSwitchMode(true); + public CheckBox(String caption) { + this(); + setCaption(caption); } /** - * Convenience method for creating a new switch button with a method - * listening button clicks. Using this method is discouraged because it - * cannot be checked during compilation. Use - * {@link #addListener(Class, Object, Method)} or - * {@link #addListener(com.vaadin.ui.Component.Listener)} instead. The - * method must have either no parameters, or only one parameter of - * Button.ClickEvent type. + * Creates a new checkbox with a caption and a set initial state. * * @param caption - * the Button caption. - * @param target - * the Object having the method for listening button clicks. - * @param methodName - * the name of the method in target object, that receives button - * click events. + * the caption of the checkbox + * @param initialState + * the initial state of the checkbox */ - public CheckBox(String caption, Object target, String methodName) { - super(caption, target, methodName); - setSwitchMode(true); + public CheckBox(String caption, boolean initialState) { + this(caption); + setValue(initialState); } /** - * Creates a new switch button that is connected to a boolean property. + * Creates a new checkbox that is connected to a boolean property. * * @param state * the Initial state of the switch-button. * @param dataSource */ - @SuppressWarnings("deprecation") - public CheckBox(String caption, Property dataSource) { - super(caption, dataSource); - setSwitchMode(true); + public CheckBox(String caption, Property<?> dataSource) { + this(caption); + setPropertyDataSource(dataSource); } - /** - * Creates a new push button with a set caption. - * - * The value of the push button is always false and they are immediate by - * default. - * - * @param caption - * the Button caption. - */ + @Override + public Class<Boolean> getType() { + return Boolean.class; + } - @SuppressWarnings("deprecation") - public CheckBox(String caption) { - super(caption, false); + @Override + public CheckBoxState getState() { + return (CheckBoxState) super.getState(); } - @Deprecated @Override - public void setSwitchMode(boolean switchMode) - throws UnsupportedOperationException { - if (this.switchMode && !switchMode) { - throw new UnsupportedOperationException( - "CheckBox is always in switch mode (consider using a Button)"); + protected void setInternalValue(Boolean newValue) { + super.setInternalValue(newValue); + if (newValue == null) { + newValue = false; } - super.setSwitchMode(true); + getState().setChecked(newValue); } - @Override - public void setDisableOnClick(boolean disableOnClick) { - throw new UnsupportedOperationException( - "CheckBox does not support disable on click"); + public void addListener(BlurListener listener) { + addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, + BlurListener.blurMethod); + } + + public void removeListener(BlurListener listener) { + removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); + } + + public void addListener(FocusListener listener) { + addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, + FocusListener.focusMethod); } + public void removeListener(FocusListener listener) { + removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); + } + + /** + * Get the boolean value of the button state. + * + * @return True iff the button is pressed down or checked. + * + * @deprecated Use {@link #getValue()} instead and, if needed, handle null + * values. + */ + @Deprecated + public boolean booleanValue() { + Boolean value = getValue(); + return (null == value) ? false : value.booleanValue(); + } } diff --git a/src/com/vaadin/ui/ComboBox.java b/src/com/vaadin/ui/ComboBox.java index bc7ab6f994..6286dad124 100644 --- a/src/com/vaadin/ui/ComboBox.java +++ b/src/com/vaadin/ui/ComboBox.java @@ -9,7 +9,7 @@ import java.util.Collection; import com.vaadin.data.Container; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VFilterSelect; +import com.vaadin.terminal.gwt.client.ui.combobox.VFilterSelect; /** * A filtering dropdown single-select. Suitable for newItemsAllowed, but it's @@ -20,7 +20,6 @@ import com.vaadin.terminal.gwt.client.ui.VFilterSelect; * */ @SuppressWarnings("serial") -@ClientWidget(VFilterSelect.class) public class ComboBox extends Select { private String inputPrompt = null; @@ -33,36 +32,24 @@ public class ComboBox extends Select { private boolean textInputAllowed = true; public ComboBox() { - setMultiSelect(false); setNewItemsAllowed(false); } public ComboBox(String caption, Collection<?> options) { super(caption, options); - setMultiSelect(false); setNewItemsAllowed(false); } public ComboBox(String caption, Container dataSource) { super(caption, dataSource); - setMultiSelect(false); setNewItemsAllowed(false); } public ComboBox(String caption) { super(caption); - setMultiSelect(false); setNewItemsAllowed(false); } - @Override - public void setMultiSelect(boolean multiSelect) { - if (multiSelect && !isMultiSelect()) { - throw new UnsupportedOperationException("Multiselect not supported"); - } - super.setMultiSelect(multiSelect); - } - /** * Gets the current input prompt. * diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java index b32aad2fca..3632c4ca5e 100644 --- a/src/com/vaadin/ui/Component.java +++ b/src/com/vaadin/ui/Component.java @@ -5,7 +5,6 @@ package com.vaadin.ui; import java.io.Serializable; -import java.util.Collection; import java.util.EventListener; import java.util.EventObject; import java.util.Locale; @@ -13,10 +12,11 @@ import java.util.Locale; import com.vaadin.Application; import com.vaadin.event.FieldEvents; import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.Paintable; import com.vaadin.terminal.Resource; import com.vaadin.terminal.Sizeable; import com.vaadin.terminal.VariableOwner; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.server.ClientConnector; /** * {@code Component} is the top-level interface that is and must be implemented @@ -51,8 +51,7 @@ import com.vaadin.terminal.VariableOwner; * @VERSION@ * @since 3.0 */ -public interface Component extends Paintable, VariableOwner, Sizeable, - Serializable { +public interface Component extends ClientConnector, Sizeable, Serializable { /** * Gets all user-defined CSS style names of a component. If the component @@ -115,9 +114,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </p> * * <p> - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * This method will trigger a {@link RepaintRequestEvent}. * </p> * * @param style @@ -159,9 +156,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </pre> * * <p> - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * This method will trigger a {@link RepaintRequestEvent}. * </p> * * @param style @@ -183,9 +178,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * style names defined in Vaadin or GWT can not be removed. * </p> * - * * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * * This method will trigger a {@link RepaintRequestEvent}. * * @param style * the style name or style names to be removed @@ -202,8 +195,14 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * component are also disabled. Components are enabled by default. * * <p> - * As a security feature, all variable change events for disabled components - * are blocked on the server-side. + * As a security feature, all updates for disabled components are blocked on + * the server-side. + * </p> + * + * <p> + * Note that this method only returns the status of the component and does + * not take parents into account. Even though this method returns true the + * component can be disabled to the user if a parent is disabled. * </p> * * @return <code>true</code> if the component and its parent are enabled, @@ -216,9 +215,6 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * Enables or disables the component. The user can not interact disabled * components, which are shown with a style that indicates the status, * usually shaded in light gray color. Components are enabled by default. - * Children of a disabled component are automatically disabled; if a child - * component is explicitly set as disabled, changes in the disabled status - * of its parents do not change its status. * * <pre> * Button enabled = new Button("Enabled"); @@ -231,10 +227,9 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </pre> * * <p> - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent} for the component and, if it is a - * {@link ComponentContainer}, for all its children recursively. + * This method will trigger a {@link RepaintRequestEvent} for the component + * and, if it is a {@link ComponentContainer}, for all its children + * recursively. * </p> * * @param enabled @@ -248,27 +243,22 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * * <p> * Visible components are drawn in the user interface, while invisible ones - * are not. The effect is not merely a cosmetic CSS change, but the entire - * HTML element will be empty. Making a component invisible through this - * property can alter the positioning of other components. + * are not. The effect is not merely a cosmetic CSS change - no information + * about an invisible component will be sent to the client. The effect is + * thus the same as removing the component from its parent. Making a + * component invisible through this property can alter the positioning of + * other components. * </p> * * <p> - * A component is visible only if all its parents are also visible. Notice - * that if a child component is explicitly set as invisible, changes in the - * visibility status of its parents do not change its status. + * A component is visible only if all its parents are also visible. This is + * not checked by this method though, so even if this method returns true, + * the component can be hidden from the user because a parent is set to + * invisible. * </p> * - * <p> - * This method does not check whether the component is attached (see - * {@link #attach()}). The component and all its parents may be considered - * "visible", but not necessarily attached to application. To test if - * component will actually be drawn, check both its visibility and that - * {@link #getApplication()} does not return {@code null}. - * </p> - * - * @return <code>true</code> if the component is visible in the user - * interface, <code>false</code> if not + * @return <code>true</code> if the component has been set to be visible in + * the user interface, <code>false</code> if not * @see #setVisible(boolean) * @see #attach() */ @@ -279,8 +269,9 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * * <p> * Visible components are drawn in the user interface, while invisible ones - * are not. The effect is not merely a cosmetic CSS change, but the entire - * HTML element will be empty. + * are not. The effect is not merely a cosmetic CSS change - no information + * about an invisible component will be sent to the client. The effect is + * thus the same as removing the component from its parent. * </p> * * <pre> @@ -315,7 +306,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * @return the parent component * @see #setParent(Component) */ - public Component getParent(); + public HasComponents getParent(); /** * Sets the parent component of the component. @@ -327,7 +318,6 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * is attached to the application, {@link #detach()} is called for the * component. * </p> - * * <p> * This method is rarely called directly. The * {@link ComponentContainer#addComponent(Component)} method is normally @@ -346,7 +336,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * if a parent is given even though the component already has a * parent */ - public void setParent(Component parent); + public void setParent(HasComponents parent); /** * Tests whether the component is in the read-only mode. The user can not @@ -389,9 +379,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </p> * * <p> - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * This method will trigger a {@link RepaintRequestEvent}. * </p> * * @param readOnly @@ -458,10 +446,8 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * </p> * * <p> - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. A reimplementation should call the superclass - * implementation. + * This method will trigger a {@link RepaintRequestEvent}. A + * reimplementation should call the superclass implementation. * </p> * * @param caption @@ -531,9 +517,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * {@code v-caption} . * </p> * - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * This method will trigger a {@link RepaintRequestEvent}. * * @param icon * the icon of the component. If null, no icon is shown and it @@ -560,7 +544,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * @return the parent window of the component or <code>null</code> if it is * not attached to a window or is itself a window */ - public Window getWindow(); + public Root getRoot(); /** * Gets the application object to which the component is attached. @@ -593,7 +577,7 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * <p> * Reimplementing the {@code attach()} method is useful for tasks that need * to get a reference to the parent, window, or application object with the - * {@link #getParent()}, {@link #getWindow()}, and {@link #getApplication()} + * {@link #getParent()}, {@link #getRoot()}, and {@link #getApplication()} * methods. A component does not yet know these objects in the constructor, * so in such case, the methods will return {@code null}. For example, the * following is invalid: @@ -618,6 +602,11 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * application, the {@code attach()} is called immediately from * {@link #setParent(Component)}. * </p> + * <p> + * This method must call {@link Root#componentAttached(Component)} to let + * the Root know that a new Component has been attached. + * </p> + * * * <pre> * public class AttachExample extends CustomComponent { @@ -648,11 +637,16 @@ public interface Component extends Paintable, VariableOwner, Sizeable, * Notifies the component that it is detached from the application. * * <p> - * The {@link #getApplication()} and {@link #getWindow()} methods might - * return <code>null</code> after this method is called. + * The {@link #getApplication()} and {@link #getRoot()} methods might return + * <code>null</code> after this method is called. * </p> * * <p> + * This method must call {@link Root#componentDetached(Component)} to let + * the Root know that a new Component has been attached. + * </p> + * * + * <p> * The caller of this method is {@link #setParent(Component)} if the parent * is in the application. When the parent is detached from the application * it is its response to call {@link #detach()} for all the children and to @@ -685,31 +679,114 @@ public interface Component extends Paintable, VariableOwner, Sizeable, public Locale getLocale(); /** - * The child components of the component must call this method when they - * need repainting. The call must be made even in the case in which the - * children sent the repaint request themselves. + * Returns the current shared state bean for the component. The state (or + * changes to it) is communicated from the server to the client. * - * <p> - * A repaint request is ignored if the component is invisible. - * </p> + * Subclasses can use a more specific return type for this method. + * + * @return The state object for the component * + * @since 7.0 + */ + public ComponentState getState(); + + /** + * Called before the shared state is sent to the client. Gives the component + * an opportunity to set computed/dynamic state values e.g. state values + * that depend on other component features. * <p> - * This method is called automatically by {@link AbstractComponent}, which - * also provides a default implementation of it. As this is a somewhat - * internal feature, it is rarely necessary to reimplement this or call it - * explicitly. + * This method must not alter the component hierarchy in any way. * </p> * - * @param alreadyNotified - * the collection of repaint request listeners that have been - * already notified by the child. This component should not - * re-notify the listed listeners again. The container given as - * parameter must be modifiable as the component might modify it - * and pass it forward. A {@code null} parameter is interpreted - * as an empty collection. + * @since 7.0 + */ + public void updateState(); + + /** + * Adds an unique id for component that get's transferred to terminal for + * testing purposes. Keeping identifiers unique is the responsibility of the + * programmer. + * + * @param id + * An alphanumeric id + */ + public void setDebugId(String id); + + /** + * Get's currently set debug identifier + * + * @return current debug id, null if not set */ - public void childRequestedRepaint( - Collection<RepaintRequestListener> alreadyNotified); + public String getDebugId(); + + /** + * Requests that the component should be repainted as soon as possible. + */ + public void requestRepaint(); + + /** + * Repaint request event is thrown when the connector needs to be repainted. + * This is typically done when the <code>paint</code> method would return + * dissimilar UIDL from the previous call of the method. + */ + @SuppressWarnings("serial") + public static class RepaintRequestEvent extends EventObject { + + /** + * Constructs a new event. + * + * @param source + * the paintable needing repaint. + */ + public RepaintRequestEvent(ClientConnector source) { + super(source); + } + + /** + * Gets the connector needing repainting. + * + * @return Paintable for which the <code>paint</code> method will return + * dissimilar UIDL from the previous call of the method. + */ + public ClientConnector getConnector() { + return (ClientConnector) getSource(); + } + } + + /** + * Listens repaint requests. The <code>repaintRequested</code> method is + * called when the paintable needs to be repainted. This is typically done + * when the <code>paint</code> method would return dissimilar UIDL from the + * previous call of the method. + */ + public interface RepaintRequestListener extends Serializable { + + /** + * Receives repaint request events. + * + * @param event + * the repaint request event specifying the paintable source. + */ + public void repaintRequested(RepaintRequestEvent event); + } + + /** + * Adds repaint request listener. In order to assure that no repaint + * requests are missed, the new repaint listener should paint the paintable + * right after adding itself as listener. + * + * @param listener + * the listener to be added. + */ + public void addListener(RepaintRequestListener listener); + + /** + * Removes repaint request listener. + * + * @param listener + * the listener to be removed. + */ + public void removeListener(RepaintRequestListener listener); /* Component event framework */ @@ -1099,4 +1176,5 @@ public interface Component extends Paintable, VariableOwner, Sizeable, public void setTabIndex(int tabIndex); } + } diff --git a/src/com/vaadin/ui/ComponentContainer.java b/src/com/vaadin/ui/ComponentContainer.java index 1e1f0796ca..8182d54b56 100644 --- a/src/com/vaadin/ui/ComponentContainer.java +++ b/src/com/vaadin/ui/ComponentContainer.java @@ -5,7 +5,6 @@ package com.vaadin.ui; import java.io.Serializable; -import java.util.Iterator; /** * Extension to the {@link Component} interface which adds to it the capacity to @@ -17,7 +16,7 @@ import java.util.Iterator; * @VERSION@ * @since 3.0 */ -public interface ComponentContainer extends Component { +public interface ComponentContainer extends HasComponents { /** * Adds the component into this container. @@ -61,22 +60,13 @@ public interface ComponentContainer extends Component { public void replaceComponent(Component oldComponent, Component newComponent); /** - * Gets an iterator to the collection of contained components. Using this - * iterator it is possible to step through all components contained in this - * container. + * Gets the number of children this {@link ComponentContainer} has. This + * must be symmetric with what {@link #getComponentIterator()} returns. * - * @return the component iterator. + * @return The number of child components this container has. + * @since 7.0.0 */ - public Iterator<Component> getComponentIterator(); - - /** - * Causes a repaint of this component, and all components below it. - * - * This should only be used in special cases, e.g when the state of a - * descendant depends on the state of a ancestor. - * - */ - public void requestRepaintAll(); + public int getComponentCount(); /** * Moves all components from an another container into this container. The diff --git a/src/com/vaadin/ui/CssLayout.java b/src/com/vaadin/ui/CssLayout.java index b9432df6b6..0a2656af31 100644 --- a/src/com/vaadin/ui/CssLayout.java +++ b/src/com/vaadin/ui/CssLayout.java @@ -3,18 +3,17 @@ */ package com.vaadin.ui; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Paintable; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.ui.VCssLayout; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.csslayout.CssLayoutServerRpc; +import com.vaadin.terminal.gwt.client.ui.csslayout.CssLayoutState; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; /** * CssLayout is a layout component that can be used in browser environment only. @@ -57,16 +56,25 @@ import com.vaadin.terminal.gwt.client.ui.VCssLayout; * @since 6.1 brought in from "FastLayouts" incubator project * */ -@ClientWidget(VCssLayout.class) public class CssLayout extends AbstractLayout implements LayoutClickNotifier { - private static final String CLICK_EVENT = EventId.LAYOUT_CLICK; + private CssLayoutServerRpc rpc = new CssLayoutServerRpc() { + public void layoutClick(MouseEventDetails mouseDetails, + Connector clickedConnector) { + fireEvent(LayoutClickEvent.createEvent(CssLayout.this, + mouseDetails, clickedConnector)); + } + }; /** * Custom layout slots containing the components. */ protected LinkedList<Component> components = new LinkedList<Component>(); + public CssLayout() { + registerRpc(rpc); + } + /** * Add a component into this container. The component is added to the right * or under the previous component. @@ -173,33 +181,22 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { return components.size(); } - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - HashMap<Paintable, String> componentCss = null; - // Adds all items in all the locations - for (Component c : components) { - // Paint child component UIDL - c.paint(target); - String componentCssString = getCss(c); + public void updateState() { + super.updateState(); + getState().getChildCss().clear(); + for (Component child : this) { + String componentCssString = getCss(child); if (componentCssString != null) { - if (componentCss == null) { - componentCss = new HashMap<Paintable, String>(); - } - componentCss.put(c, componentCssString); + getState().getChildCss().put(child, componentCssString); } + } - if (componentCss != null) { - target.addAttribute("css", componentCss); - } + } + + @Override + public CssLayoutState getState() { + return (CssLayoutState) super.getState(); } /** @@ -267,12 +264,14 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { } public void addListener(LayoutClickListener listener) { - addListener(CLICK_EVENT, LayoutClickEvent.class, listener, + addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener, LayoutClickListener.clickMethod); } public void removeListener(LayoutClickListener listener) { - removeListener(CLICK_EVENT, LayoutClickEvent.class, listener); + removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener); } /** diff --git a/src/com/vaadin/ui/CustomComponent.java b/src/com/vaadin/ui/CustomComponent.java index 21eda08909..98d650f6db 100644 --- a/src/com/vaadin/ui/CustomComponent.java +++ b/src/com/vaadin/ui/CustomComponent.java @@ -7,11 +7,6 @@ package com.vaadin.ui; import java.io.Serializable; import java.util.Iterator; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VCustomComponent; -import com.vaadin.ui.ClientWidget.LoadStyle; - /** * Custom component provides simple implementation of Component interface for * creation of new UI components by composition of existing components. @@ -27,7 +22,6 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(value = VCustomComponent.class, loadStyle = LoadStyle.EAGER) public class CustomComponent extends AbstractComponentContainer { /** @@ -36,11 +30,6 @@ public class CustomComponent extends AbstractComponentContainer { private Component root = null; /** - * Type of the component. - */ - private String componentType = null; - - /** * Constructs a new custom component. * * <p> @@ -107,51 +96,6 @@ public class CustomComponent extends AbstractComponentContainer { /* Basic component features ------------------------------------------ */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (root == null) { - throw new IllegalStateException("Composition root must be set to" - + " non-null value before the " + getClass().getName() - + " can be painted"); - } - - if (getComponentType() != null) { - target.addAttribute("type", getComponentType()); - } - root.paint(target); - } - - /** - * Gets the component type. - * - * The component type is textual type of the component. This is included in - * the UIDL as component tag attribute. - * - * @deprecated not more useful as the whole tag system has been removed - * - * @return the component type. - */ - @Deprecated - public String getComponentType() { - return componentType; - } - - /** - * Sets the component type. - * - * The component type is textual type of the component. This is included in - * the UIDL as component tag attribute. - * - * @deprecated not more useful as the whole tag system has been removed - * - * @param componentType - * the componentType to set. - */ - @Deprecated - public void setComponentType(String componentType) { - this.componentType = componentType; - } - private class ComponentIterator implements Iterator<Component>, Serializable { boolean first = getCompositionRoot() != null; diff --git a/src/com/vaadin/ui/CustomField.java b/src/com/vaadin/ui/CustomField.java new file mode 100644 index 0000000000..806ee91335 --- /dev/null +++ b/src/com/vaadin/ui/CustomField.java @@ -0,0 +1,230 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.ui; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Iterator; + +import com.vaadin.data.Property; + +/** + * A {@link Field} whose UI content can be constructed by the user, enabling the + * creation of e.g. form fields by composing Vaadin components. Customization of + * both the visual presentation and the logic of the field is possible. + * + * Subclasses must implement {@link #getType()} and {@link #initContent()}. + * + * Most custom fields can simply compose a user interface that calls the methods + * {@link #setInternalValue(Object)} and {@link #getInternalValue()} when + * necessary. + * + * It is also possible to override {@link #validate()}, + * {@link #setInternalValue(Object)}, {@link #commit()}, + * {@link #setPropertyDataSource(Property)}, {@link #isEmpty()} and other logic + * of the field. Methods overriding {@link #setInternalValue(Object)} should + * also call the corresponding superclass method. + * + * @param <T> + * field value type + * + * @since 7.0 + */ +public abstract class CustomField<T> extends AbstractField<T> implements + ComponentContainer { + + /** + * The root component implementing the custom component. + */ + private Component root = null; + + /** + * Constructs a new custom field. + * + * <p> + * The component is implemented by wrapping the methods of the composition + * root component given as parameter. The composition root must be set + * before the component can be used. + * </p> + */ + public CustomField() { + // expand horizontally by default + setWidth(100, Unit.PERCENTAGE); + } + + /** + * Constructs the content and notifies it that the {@link CustomField} is + * attached to a window. + * + * @see com.vaadin.ui.Component#attach() + */ + @Override + public void attach() { + root = getContent(); + super.attach(); + getContent().setParent(this); + getContent().attach(); + + fireComponentAttachEvent(getContent()); + } + + /** + * Notifies the content that the {@link CustomField} is detached from a + * window. + * + * @see com.vaadin.ui.Component#detach() + */ + @Override + public void detach() { + super.detach(); + getContent().detach(); + } + + /** + * Returns the content (UI) of the custom component. + * + * @return Component + */ + protected Component getContent() { + if (null == root) { + root = initContent(); + } + return root; + } + + /** + * Create the content component or layout for the field. Subclasses of + * {@link CustomField} should implement this method. + * + * Note that this method is called when the CustomField is attached to a + * layout or when {@link #getContent()} is called explicitly for the first + * time. It is only called once for a {@link CustomField}. + * + * @return {@link Component} representing the UI of the CustomField + */ + protected abstract Component initContent(); + + // Size related methods + // TODO might not be necessary to override but following the pattern from + // AbstractComponentContainer + + @Override + public void setHeight(float height, Unit unit) { + super.setHeight(height, unit); + requestRepaintAll(); + } + + @Override + public void setWidth(float height, Unit unit) { + super.setWidth(height, unit); + requestRepaintAll(); + } + + // ComponentContainer methods + + private class ComponentIterator implements Iterator<Component>, + Serializable { + boolean first = (root != null); + + public boolean hasNext() { + return first; + } + + public Component next() { + first = false; + return getContent(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public Iterator<Component> getComponentIterator() { + return new ComponentIterator(); + } + + public Iterator<Component> iterator() { + return getComponentIterator(); + } + + public int getComponentCount() { + return (null != getContent()) ? 1 : 0; + } + + public void requestRepaintAll() { + AbstractComponentContainer.requestRepaintAll(this); + } + + /** + * Fires the component attached event. This should be called by the + * addComponent methods after the component have been added to this + * container. + * + * @param component + * the component that has been added to this container. + */ + protected void fireComponentAttachEvent(Component component) { + fireEvent(new ComponentAttachEvent(this, component)); + } + + // TODO remove these methods when ComponentContainer interface is cleaned up + + public void addComponent(Component c) { + throw new UnsupportedOperationException(); + } + + public void removeComponent(Component c) { + throw new UnsupportedOperationException(); + } + + public void removeAllComponents() { + throw new UnsupportedOperationException(); + } + + public void replaceComponent(Component oldComponent, Component newComponent) { + throw new UnsupportedOperationException(); + } + + public void moveComponentsFrom(ComponentContainer source) { + throw new UnsupportedOperationException(); + } + + private static final Method COMPONENT_ATTACHED_METHOD; + + static { + try { + COMPONENT_ATTACHED_METHOD = ComponentAttachListener.class + .getDeclaredMethod("componentAttachedToContainer", + new Class[] { ComponentAttachEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in CustomField"); + } + } + + public void addListener(ComponentAttachListener listener) { + addListener(ComponentContainer.ComponentAttachEvent.class, listener, + COMPONENT_ATTACHED_METHOD); + } + + public void removeListener(ComponentAttachListener listener) { + removeListener(ComponentContainer.ComponentAttachEvent.class, listener, + COMPONENT_ATTACHED_METHOD); + } + + public void addListener(ComponentDetachListener listener) { + // content never detached + } + + public void removeListener(ComponentDetachListener listener) { + // content never detached + } + + public boolean isComponentVisible(Component childComponent) { + return true; + } +} diff --git a/src/com/vaadin/ui/CustomLayout.java b/src/com/vaadin/ui/CustomLayout.java index dc473fb549..97cea1c49d 100644 --- a/src/com/vaadin/ui/CustomLayout.java +++ b/src/com/vaadin/ui/CustomLayout.java @@ -9,10 +9,14 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; +import java.util.Map; +import java.util.Set; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VCustomLayout; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.customlayout.CustomLayoutState; +import com.vaadin.terminal.gwt.server.JsonPaintTarget; /** * <p> @@ -44,8 +48,7 @@ import com.vaadin.terminal.gwt.client.ui.VCustomLayout; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VCustomLayout.class) -public class CustomLayout extends AbstractLayout { +public class CustomLayout extends AbstractLayout implements Vaadin6Component { private static final int BUFFER_SIZE = 10000; @@ -54,10 +57,6 @@ public class CustomLayout extends AbstractLayout { */ private final HashMap<String, Component> slots = new HashMap<String, Component>(); - private String templateContents = null; - - private String templateName = null; - /** * Default constructor only used by subclasses. Subclasses are responsible * for setting the appropriate fields. Either @@ -90,7 +89,7 @@ public class CustomLayout extends AbstractLayout { */ public CustomLayout(String template) { this(); - templateName = template; + setTemplateName(template); } protected void initTemplateContentsFromInputStream( @@ -110,7 +109,12 @@ public class CustomLayout extends AbstractLayout { } } - templateContents = b.toString(); + setTemplateContents(b.toString()); + } + + @Override + public CustomLayoutState getState() { + return (CustomLayoutState) super.getState(); } /** @@ -128,6 +132,7 @@ public class CustomLayout extends AbstractLayout { removeComponent(old); } slots.put(location, c); + getState().getChildLocations().put(c, location); c.setParent(this); fireComponentAttachEvent(c); requestRepaint(); @@ -159,6 +164,7 @@ public class CustomLayout extends AbstractLayout { return; } slots.values().remove(c); + getState().getChildLocations().remove(c); super.removeComponent(c); requestRepaint(); } @@ -205,37 +211,6 @@ public class CustomLayout extends AbstractLayout { return slots.get(location); } - /** - * Paints the content of this component. - * - * @param target - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - if (templateName != null) { - target.addAttribute("template", templateName); - } else { - target.addAttribute("templateContents", templateContents); - } - // Adds all items in all the locations - for (final Iterator<String> i = slots.keySet().iterator(); i.hasNext();) { - // Gets the (location,component) - final String location = i.next(); - final Component c = slots.get(location); - if (c != null) { - // Writes the item - target.startTag("location"); - target.addAttribute("name", location); - c.paint(target); - target.endTag("location"); - } - } - } - /* Documented in superclass */ public void replaceComponent(Component oldComponent, Component newComponent) { @@ -261,32 +236,20 @@ public class CustomLayout extends AbstractLayout { } else { slots.put(newLocation, oldComponent); slots.put(oldLocation, newComponent); + getState().getChildLocations().put(newComponent, oldLocation); + getState().getChildLocations().put(oldComponent, newLocation); requestRepaint(); } } - /** - * CustomLayout's template selecting was previously implemented with - * setStyle. Overriding to improve backwards compatibility. - * - * @param name - * template name - * @deprecated Use {@link #setTemplateName(String)} instead - */ - @Deprecated - @Override - public void setStyle(String name) { - setTemplateName(name); - } - /** Get the name of the template */ public String getTemplateName() { - return templateName; + return getState().getTemplateName(); } /** Get the contents of the template */ public String getTemplateContents() { - return templateContents; + return getState().getTemplateContents(); } /** @@ -299,8 +262,8 @@ public class CustomLayout extends AbstractLayout { * @param templateName */ public void setTemplateName(String templateName) { - this.templateName = templateName; - templateContents = null; + getState().setTemplateName(templateName); + getState().setTemplateContents(null); requestRepaint(); } @@ -310,8 +273,8 @@ public class CustomLayout extends AbstractLayout { * @param templateContents */ public void setTemplateContents(String templateContents) { - this.templateContents = templateContents; - templateName = null; + getState().setTemplateContents(templateContents); + getState().setTemplateName(null); requestRepaint(); } @@ -342,4 +305,20 @@ public class CustomLayout extends AbstractLayout { "CustomLayout does not support margins."); } + public void changeVariables(Object source, Map<String, Object> variables) { + // Nothing to see here + } + + public void paintContent(PaintTarget target) throws PaintException { + // Workaround to make the CommunicationManager read the template file + // and send it to the client + String templateName = getState().getTemplateName(); + if (templateName != null && templateName.length() != 0) { + Set<Object> usedResources = ((JsonPaintTarget) target) + .getUsedResources(); + String resourceName = "layouts/" + templateName + ".html"; + usedResources.add(resourceName); + } + } + } diff --git a/src/com/vaadin/ui/DateField.java b/src/com/vaadin/ui/DateField.java index ef67345aab..55ff67229c 100644 --- a/src/com/vaadin/ui/DateField.java +++ b/src/com/vaadin/ui/DateField.java @@ -4,11 +4,13 @@ package com.vaadin.ui; -import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; @@ -16,6 +18,7 @@ import java.util.TimeZone; import com.vaadin.data.Property; import com.vaadin.data.Validator; import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.util.converter.Converter; import com.vaadin.event.FieldEvents; import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; @@ -23,8 +26,8 @@ import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VDateField; -import com.vaadin.terminal.gwt.client.ui.VPopupCalendar; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.datefield.VDateField; /** * <p> @@ -47,56 +50,128 @@ import com.vaadin.terminal.gwt.client.ui.VPopupCalendar; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VPopupCalendar.class) -public class DateField extends AbstractField implements - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier { - - /* Private members */ +public class DateField extends AbstractField<Date> implements + FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Vaadin6Component { /** - * Resolution identifier: milliseconds. + * Resolutions for DateFields + * + * @author Vaadin Ltd. + * @version + * @VERSION@ + * @since 7.0 */ - public static final int RESOLUTION_MSEC = 0; + public enum Resolution { + SECOND(Calendar.SECOND), MINUTE(Calendar.MINUTE), HOUR( + Calendar.HOUR_OF_DAY), DAY(Calendar.DAY_OF_MONTH), MONTH( + Calendar.MONTH), YEAR(Calendar.YEAR); + + private int calendarField; + + private Resolution(int calendarField) { + this.calendarField = calendarField; + } + + /** + * Returns the field in {@link Calendar} that corresponds to this + * resolution. + * + * @return one of the field numbers used by Calendar + */ + public int getCalendarField() { + return calendarField; + } + + /** + * Returns the resolutions that are higher or equal to the given + * resolution, starting from the given resolution. In other words + * passing DAY to this methods returns DAY,MONTH,YEAR + * + * @param r + * The resolution to start from + * @return An iterable for the resolutions higher or equal to r + */ + public static Iterable<Resolution> getResolutionsHigherOrEqualTo( + Resolution r) { + List<Resolution> resolutions = new ArrayList<DateField.Resolution>(); + Resolution[] values = Resolution.values(); + for (int i = r.ordinal(); i < values.length; i++) { + resolutions.add(values[i]); + } + return resolutions; + } + + /** + * Returns the resolutions that are lower than the given resolution, + * starting from the given resolution. In other words passing DAY to + * this methods returns HOUR,MINUTE,SECOND. + * + * @param r + * The resolution to start from + * @return An iterable for the resolutions lower than r + */ + public static List<Resolution> getResolutionsLowerThan(Resolution r) { + List<Resolution> resolutions = new ArrayList<DateField.Resolution>(); + Resolution[] values = Resolution.values(); + for (int i = r.ordinal() - 1; i >= 0; i--) { + resolutions.add(values[i]); + } + return resolutions; + } + }; /** * Resolution identifier: seconds. + * + * @deprecated Use {@link Resolution#SECOND} */ - public static final int RESOLUTION_SEC = 1; + @Deprecated + public static final Resolution RESOLUTION_SEC = Resolution.SECOND; /** * Resolution identifier: minutes. + * + * @deprecated Use {@link Resolution#MINUTE} */ - public static final int RESOLUTION_MIN = 2; + @Deprecated + public static final Resolution RESOLUTION_MIN = Resolution.MINUTE; /** * Resolution identifier: hours. + * + * @deprecated Use {@link Resolution#HOUR} */ - public static final int RESOLUTION_HOUR = 3; + @Deprecated + public static final Resolution RESOLUTION_HOUR = Resolution.HOUR; /** * Resolution identifier: days. + * + * @deprecated Use {@link Resolution#DAY} */ - public static final int RESOLUTION_DAY = 4; + @Deprecated + public static final Resolution RESOLUTION_DAY = Resolution.DAY; /** * Resolution identifier: months. + * + * @deprecated Use {@link Resolution#MONTH} */ - public static final int RESOLUTION_MONTH = 5; + @Deprecated + public static final Resolution RESOLUTION_MONTH = Resolution.MONTH; /** * Resolution identifier: years. + * + * @deprecated Use {@link Resolution#YEAR} */ - public static final int RESOLUTION_YEAR = 6; - - /** - * Specified smallest modifiable unit. - */ - private int resolution = RESOLUTION_MSEC; + @Deprecated + public static final Resolution RESOLUTION_YEAR = Resolution.YEAR; /** - * Specified largest modifiable unit. + * Specified smallest modifiable unit for the date field. */ - private static final int largestModifiable = RESOLUTION_YEAR; + private Resolution resolution = Resolution.DAY; /** * The internal calendar to be used in java.utl.Date conversions. @@ -129,6 +204,16 @@ public class DateField extends AbstractField implements private TimeZone timeZone = null; + private static Map<Resolution, String> variableNameForResolution = new HashMap<DateField.Resolution, String>(); + { + variableNameForResolution.put(Resolution.SECOND, "sec"); + variableNameForResolution.put(Resolution.MINUTE, "min"); + variableNameForResolution.put(Resolution.HOUR, "hour"); + variableNameForResolution.put(Resolution.DAY, "day"); + variableNameForResolution.put(Resolution.MONTH, "month"); + variableNameForResolution.put(Resolution.YEAR, "year"); + } + /* Constructors */ /** @@ -201,9 +286,7 @@ public class DateField extends AbstractField implements * Paints this component. Don't add a JavaDoc comment here, we use the * default documentation from implemented interface. */ - @Override public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); // Adds the locale as attribute final Locale l = getLocale(); @@ -228,51 +311,21 @@ public class DateField extends AbstractField implements // Gets the calendar final Calendar calendar = getCalendar(); - final Date currentDate = (Date) getValue(); - - for (int r = resolution; r <= largestModifiable; r++) { - switch (r) { - case RESOLUTION_MSEC: - target.addVariable( - this, - "msec", - currentDate != null ? calendar - .get(Calendar.MILLISECOND) : -1); - break; - case RESOLUTION_SEC: - target.addVariable(this, "sec", - currentDate != null ? calendar.get(Calendar.SECOND) - : -1); - break; - case RESOLUTION_MIN: - target.addVariable(this, "min", - currentDate != null ? calendar.get(Calendar.MINUTE) - : -1); - break; - case RESOLUTION_HOUR: - target.addVariable( - this, - "hour", - currentDate != null ? calendar - .get(Calendar.HOUR_OF_DAY) : -1); - break; - case RESOLUTION_DAY: - target.addVariable( - this, - "day", - currentDate != null ? calendar - .get(Calendar.DAY_OF_MONTH) : -1); - break; - case RESOLUTION_MONTH: - target.addVariable(this, "month", - currentDate != null ? calendar.get(Calendar.MONTH) + 1 - : -1); - break; - case RESOLUTION_YEAR: - target.addVariable(this, "year", - currentDate != null ? calendar.get(Calendar.YEAR) : -1); - break; + final Date currentDate = getValue(); + + // Only paint variables for the resolution and up, e.g. Resolution DAY + // paints DAY,MONTH,YEAR + for (Resolution res : Resolution + .getResolutionsHigherOrEqualTo(resolution)) { + int value = -1; + if (currentDate != null) { + value = calendar.get(res.getCalendarField()); + if (res == Resolution.MONTH) { + // Calendar month is zero based + value++; + } } + target.addVariable(this, variableNameForResolution.get(res), value); } } @@ -286,9 +339,7 @@ public class DateField extends AbstractField implements * comment here, we use the default documentation from implemented * interface. */ - @Override public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); if (!isReadOnly() && (variables.containsKey("year") @@ -298,10 +349,10 @@ public class DateField extends AbstractField implements || variables.containsKey("min") || variables.containsKey("sec") || variables.containsKey("msec") || variables - .containsKey("dateString"))) { + .containsKey("dateString"))) { // Old and new dates - final Date oldDate = (Date) getValue(); + final Date oldDate = getValue(); Date newDate = null; // this enables analyzing invalid input on the server @@ -309,59 +360,50 @@ public class DateField extends AbstractField implements dateString = newDateString; // Gets the new date in parts - // Null values are converted to negative values. - int year = variables.containsKey("year") ? (variables.get("year") == null ? -1 - : ((Integer) variables.get("year")).intValue()) - : -1; - int month = variables.containsKey("month") ? (variables - .get("month") == null ? -1 : ((Integer) variables - .get("month")).intValue() - 1) : -1; - int day = variables.containsKey("day") ? (variables.get("day") == null ? -1 - : ((Integer) variables.get("day")).intValue()) - : -1; - int hour = variables.containsKey("hour") ? (variables.get("hour") == null ? -1 - : ((Integer) variables.get("hour")).intValue()) - : -1; - int min = variables.containsKey("min") ? (variables.get("min") == null ? -1 - : ((Integer) variables.get("min")).intValue()) - : -1; - int sec = variables.containsKey("sec") ? (variables.get("sec") == null ? -1 - : ((Integer) variables.get("sec")).intValue()) - : -1; - int msec = variables.containsKey("msec") ? (variables.get("msec") == null ? -1 - : ((Integer) variables.get("msec")).intValue()) - : -1; - - // If all of the components is < 0 use the previous value - if (year < 0 && month < 0 && day < 0 && hour < 0 && min < 0 - && sec < 0 && msec < 0) { + boolean hasChanges = false; + Map<Resolution, Integer> calendarFieldChanges = new HashMap<DateField.Resolution, Integer>(); + + for (Resolution r : Resolution + .getResolutionsHigherOrEqualTo(resolution)) { + // Only handle what the client is allowed to send. The same + // resolutions that are painted + String variableName = variableNameForResolution.get(r); + + if (variables.containsKey(variableName)) { + Integer value = (Integer) variables.get(variableName); + if (r == Resolution.MONTH) { + // Calendar MONTH is zero based + value--; + } + if (value >= 0) { + hasChanges = true; + calendarFieldChanges.put(r, value); + } + } + } + + // If no new variable values were received, use the previous value + if (!hasChanges) { newDate = null; } else { - // Clone the calendar for date operation final Calendar cal = getCalendar(); - // Make sure that meaningful values exists - // Use the previous value if some of the variables - // have not been changed. - year = year < 0 ? cal.get(Calendar.YEAR) : year; - month = month < 0 ? cal.get(Calendar.MONTH) : month; - day = day < 0 ? cal.get(Calendar.DAY_OF_MONTH) : day; - hour = hour < 0 ? cal.get(Calendar.HOUR_OF_DAY) : hour; - min = min < 0 ? cal.get(Calendar.MINUTE) : min; - sec = sec < 0 ? cal.get(Calendar.SECOND) : sec; - msec = msec < 0 ? cal.get(Calendar.MILLISECOND) : msec; - - // Sets the calendar fields - cal.set(Calendar.YEAR, year); - cal.set(Calendar.MONTH, month); - cal.set(Calendar.DAY_OF_MONTH, day); - cal.set(Calendar.HOUR_OF_DAY, hour); - cal.set(Calendar.MINUTE, min); - cal.set(Calendar.SECOND, sec); - cal.set(Calendar.MILLISECOND, msec); - - // Assigns the date + // Update the value based on the received info + // Must set in this order to avoid invalid dates (or wrong + // dates if lenient is true) in calendar + for (int r = Resolution.YEAR.ordinal(); r >= 0; r--) { + Resolution res = Resolution.values()[r]; + if (calendarFieldChanges.containsKey(res)) { + + // Field resolution should be included. Others are + // skipped so that client can not make unexpected + // changes (e.g. day change even though resolution is + // year). + Integer newValue = calendarFieldChanges.get(res); + cal.set(res.getCalendarField(), newValue); + } + } newDate = cal.getTime(); } @@ -377,7 +419,7 @@ public class DateField extends AbstractField implements * this case the invalid text remains in the DateField. */ requestRepaint(); - } catch (ConversionException e) { + } catch (Converter.ConversionException e) { /* * Datefield now contains some text that could't be parsed @@ -445,7 +487,7 @@ public class DateField extends AbstractField implements * This method is called to handle a non-empty date string from the client * if the client could not parse it as a Date. * - * By default, a Property.ConversionException is thrown, and the current + * By default, a Converter.ConversionException is thrown, and the current * value is not modified. * * This can be overridden to handle conversions, to return null (equivalent @@ -453,13 +495,13 @@ public class DateField extends AbstractField implements * * @param dateString * @return parsed Date - * @throws Property.ConversionException + * @throws Converter.ConversionException * to keep the old value and indicate an error */ protected Date handleUnparsableDateString(String dateString) - throws Property.ConversionException { + throws Converter.ConversionException { currentParseErrorMessage = null; - throw new Property.ConversionException(getParseErrorMessage()); + throw new Converter.ConversionException(getParseErrorMessage()); } /* Property features */ @@ -469,7 +511,7 @@ public class DateField extends AbstractField implements * the default documentation from implemented interface. */ @Override - public Class<?> getType() { + public Class<Date> getType() { return Date.class; } @@ -479,8 +521,8 @@ public class DateField extends AbstractField implements * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object, boolean) */ @Override - protected void setValue(Object newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Property.ConversionException { + protected void setValue(Date newValue, boolean repaintIsNotNeeded) + throws Property.ReadOnlyException { /* * First handle special case when the client side component have a date @@ -513,23 +555,7 @@ public class DateField extends AbstractField implements return; } - if (newValue == null || newValue instanceof Date) { - super.setValue(newValue, repaintIsNotNeeded); - } else { - // Try to parse the given string value to Date - try { - final SimpleDateFormat parser = new SimpleDateFormat(); - final TimeZone currentTimeZone = getTimeZone(); - if (currentTimeZone != null) { - parser.setTimeZone(currentTimeZone); - } - final Date val = parser.parse(newValue.toString()); - super.setValue(val, repaintIsNotNeeded); - } catch (final ParseException e) { - uiHasValidDateString = false; - throw new Property.ConversionException(getParseErrorMessage()); - } - } + super.setValue(newValue, repaintIsNotNeeded); } /** @@ -544,7 +570,7 @@ public class DateField extends AbstractField implements Form f = (Form) parenOfDateField; Collection<?> visibleItemProperties = f.getItemPropertyIds(); for (Object fieldId : visibleItemProperties) { - Field field = f.getField(fieldId); + Field<?> field = f.getField(fieldId); if (field == this) { /* * this datefield is logically in a form. Do the same @@ -564,24 +590,8 @@ public class DateField extends AbstractField implements } } - /** - * Sets the DateField datasource. Datasource type must assignable to Date. - * - * @see com.vaadin.data.Property.Viewer#setPropertyDataSource(Property) - */ @Override - public void setPropertyDataSource(Property newDataSource) { - if (newDataSource == null - || Date.class.isAssignableFrom(newDataSource.getType())) { - super.setPropertyDataSource(newDataSource); - } else { - throw new IllegalArgumentException( - "DateField only supports Date properties"); - } - } - - @Override - protected void setInternalValue(Object newValue) { + protected void setInternalValue(Date newValue) { // Also set the internal dateString if (newValue != null) { dateString = newValue.toString(); @@ -604,17 +614,19 @@ public class DateField extends AbstractField implements * * @return int */ - public int getResolution() { + public Resolution getResolution() { return resolution; } /** * Sets the resolution of the DateField. * + * The default resolution is {@link Resolution#DAY} since Vaadin 7.0. + * * @param resolution * the resolution to set. */ - public void setResolution(int resolution) { + public void setResolution(Resolution resolution) { this.resolution = resolution; requestRepaint(); } @@ -636,13 +648,19 @@ public class DateField extends AbstractField implements // Makes sure we have an calendar instance if (calendar == null) { calendar = Calendar.getInstance(); + // Start by a zeroed calendar to avoid having values for lower + // resolution variables e.g. time when resolution is day + for (Resolution r : Resolution.getResolutionsLowerThan(resolution)) { + calendar.set(r.getCalendarField(), 0); + } + calendar.set(Calendar.MILLISECOND, 0); } // Clone the instance final Calendar newCal = (Calendar) calendar.clone(); // Assigns the current time tom calendar. - final Date currentDate = (Date) getValue(); + final Date currentDate = getValue(); if (currentDate != null) { newCal.setTime(currentDate); } @@ -752,19 +770,14 @@ public class DateField extends AbstractField implements } /** - * Tests the current value against registered validators if the field is not - * empty. Note that DateField is considered empty (value == null) and + * Validates the current value against registered validators if the field is + * not empty. Note that DateField is considered empty (value == null) and * invalid if it contains text typed in by the user that couldn't be parsed * into a Date value. * - * @see com.vaadin.ui.AbstractField#isValid() + * @see com.vaadin.ui.AbstractField#validate() */ @Override - public boolean isValid() { - return uiHasValidDateString && super.isValid(); - } - - @Override public void validate() throws InvalidValueException { /* * To work properly in form we must throw exception if there is diff --git a/src/com/vaadin/ui/DefaultFieldFactory.java b/src/com/vaadin/ui/DefaultFieldFactory.java index 1e55d2795f..9d096094e3 100644 --- a/src/com/vaadin/ui/DefaultFieldFactory.java +++ b/src/com/vaadin/ui/DefaultFieldFactory.java @@ -35,19 +35,20 @@ public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory protected DefaultFieldFactory() { } - public Field createField(Item item, Object propertyId, Component uiContext) { + public Field<?> createField(Item item, Object propertyId, + Component uiContext) { Class<?> type = item.getItemProperty(propertyId).getType(); - Field field = createFieldByPropertyType(type); + Field<?> field = createFieldByPropertyType(type); field.setCaption(createCaptionByPropertyId(propertyId)); return field; } - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { - Property containerProperty = container.getContainerProperty(itemId, + Property<?> containerProperty = container.getContainerProperty(itemId, propertyId); Class<?> type = containerProperty.getType(); - Field field = createFieldByPropertyType(type); + Field<?> field = createFieldByPropertyType(type); field.setCaption(createCaptionByPropertyId(propertyId)); return field; } @@ -63,6 +64,10 @@ public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory String name = propertyId.toString(); if (name.length() > 0) { + int dotLocation = name.lastIndexOf('.'); + if (dotLocation > 0 && dotLocation < name.length() - 1) { + name = name.substring(dotLocation + 1); + } if (name.indexOf(' ') < 0 && name.charAt(0) == Character.toLowerCase(name.charAt(0)) && name.charAt(0) != Character.toUpperCase(name.charAt(0))) { @@ -110,7 +115,7 @@ public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory * the type of the property * @return the most suitable generic {@link Field} for given type */ - public static Field createFieldByPropertyType(Class<?> type) { + public static Field<?> createFieldByPropertyType(Class<?> type) { // Null typed properties can not be edited if (type == null) { return null; diff --git a/src/com/vaadin/ui/DirtyConnectorTracker.java b/src/com/vaadin/ui/DirtyConnectorTracker.java new file mode 100644 index 0000000000..84df7e7c7c --- /dev/null +++ b/src/com/vaadin/ui/DirtyConnectorTracker.java @@ -0,0 +1,132 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.ui; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.vaadin.terminal.gwt.server.AbstractCommunicationManager; +import com.vaadin.terminal.gwt.server.ClientConnector; +import com.vaadin.ui.Component.RepaintRequestEvent; +import com.vaadin.ui.Component.RepaintRequestListener; + +/** + * A class that tracks dirty {@link ClientConnector}s. A {@link ClientConnector} + * is dirty when an operation has been performed on it on the server and as a + * result of this operation new information needs to be sent to its client side + * counterpart. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public class DirtyConnectorTracker implements RepaintRequestListener { + private Set<Component> dirtyComponents = new HashSet<Component>(); + private Root root; + + /** + * Gets a logger for this class + * + * @return A logger instance for logging within this class + * + */ + public static Logger getLogger() { + return Logger.getLogger(DirtyConnectorTracker.class.getName()); + } + + public DirtyConnectorTracker(Root root) { + this.root = root; + } + + public void repaintRequested(RepaintRequestEvent event) { + markDirty((Component) event.getConnector()); + } + + public void componentAttached(Component component) { + component.addListener(this); + markDirty(component); + } + + private void markDirty(Component component) { + if (getLogger().isLoggable(Level.FINE)) { + if (!dirtyComponents.contains(component)) { + getLogger() + .fine(getDebugInfo(component) + " " + "is now dirty"); + } + } + + dirtyComponents.add(component); + } + + private void markClean(Component component) { + if (getLogger().isLoggable(Level.FINE)) { + if (dirtyComponents.contains(component)) { + getLogger().fine( + getDebugInfo(component) + " " + "is no longer dirty"); + } + } + + dirtyComponents.remove(component); + } + + private String getDebugInfo(Component component) { + String message = getObjectString(component); + if (component.getParent() != null) { + message += " (parent: " + getObjectString(component.getParent()) + + ")"; + } + return message; + } + + private String getObjectString(Object component) { + return component.getClass().getName() + "@" + + Integer.toHexString(component.hashCode()); + } + + public void componentDetached(Component component) { + component.removeListener(this); + markClean(component); + } + + public void markAllComponentsDirty() { + markComponentsDirtyRecursively(root); + getLogger().fine("All components are now dirty"); + } + + public void markAllComponentsClean() { + dirtyComponents.clear(); + getLogger().fine("All components are now clean"); + } + + /** + * Marks all visible components dirty, starting from the given component and + * going downwards in the hierarchy. + * + * @param c + * The component to start iterating downwards from + */ + private void markComponentsDirtyRecursively(Component c) { + if (!c.isVisible()) { + return; + } + markDirty(c); + if (c instanceof HasComponents) { + HasComponents container = (HasComponents) c; + for (Component child : AbstractCommunicationManager + .getChildComponents(container)) { + markComponentsDirtyRecursively(child); + } + } + + } + + public Collection<Component> getDirtyComponents() { + return dirtyComponents; + } + +} diff --git a/src/com/vaadin/ui/DragAndDropWrapper.java b/src/com/vaadin/ui/DragAndDropWrapper.java index c6522f15c7..b623197a4c 100644 --- a/src/com/vaadin/ui/DragAndDropWrapper.java +++ b/src/com/vaadin/ui/DragAndDropWrapper.java @@ -20,15 +20,15 @@ import com.vaadin.event.dd.TargetDetailsImpl; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.StreamVariable; +import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper; import com.vaadin.terminal.gwt.client.ui.dd.HorizontalDropLocation; import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; +import com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper; @SuppressWarnings("serial") -@ClientWidget(VDragAndDropWrapper.class) public class DragAndDropWrapper extends CustomComponent implements DropTarget, - DragSource { + DragSource, Vaadin6Component { public class WrapperTransferable extends TransferableImpl { @@ -214,9 +214,11 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget, requestRepaint(); } - @Override + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented + } + public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); target.addAttribute(VDragAndDropWrapper.DRAG_START_MODE, dragStartMode.ordinal()); if (getDropHandler() != null) { diff --git a/src/com/vaadin/ui/Embedded.java b/src/com/vaadin/ui/Embedded.java index 181cbbfb96..1bcd984666 100644 --- a/src/com/vaadin/ui/Embedded.java +++ b/src/com/vaadin/ui/Embedded.java @@ -13,8 +13,11 @@ import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; +import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VEmbedded; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.embedded.EmbeddedConnector; +import com.vaadin.terminal.gwt.client.ui.embedded.EmbeddedServerRpc; /** * Component for embedding external objects. @@ -25,10 +28,7 @@ import com.vaadin.terminal.gwt.client.ui.VEmbedded; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VEmbedded.class) -public class Embedded extends AbstractComponent { - - private static final String CLICK_EVENT = VEmbedded.CLICK_EVENT_IDENTIFIER; +public class Embedded extends AbstractComponent implements Vaadin6Component { /** * General object type. @@ -80,10 +80,17 @@ public class Embedded extends AbstractComponent { private String altText; + private EmbeddedServerRpc rpc = new EmbeddedServerRpc() { + public void click(MouseEventDetails mouseDetails) { + fireEvent(new ClickEvent(Embedded.this, mouseDetails)); + } + }; + /** * Creates a new empty Embedded object. */ public Embedded() { + registerRpc(rpc); } /** @@ -92,6 +99,7 @@ public class Embedded extends AbstractComponent { * @param caption */ public Embedded(String caption) { + this(); setCaption(caption); } @@ -105,14 +113,13 @@ public class Embedded extends AbstractComponent { * the Source of the embedded object. */ public Embedded(String caption, Resource source) { - setCaption(caption); + this(caption); setSource(source); } /** * Invoked when the component state should be painted. */ - @Override public void paintContent(PaintTarget target) throws PaintException { switch (type) { @@ -149,7 +156,7 @@ public class Embedded extends AbstractComponent { target.addAttribute("archive", archive); } if (altText != null && !"".equals(altText)) { - target.addAttribute(VEmbedded.ALTERNATE_TEXT, altText); + target.addAttribute(EmbeddedConnector.ALTERNATE_TEXT, altText); } // Params @@ -498,8 +505,8 @@ public class Embedded extends AbstractComponent { * The listener to add */ public void addListener(ClickListener listener) { - addListener(CLICK_EVENT, ClickEvent.class, listener, - ClickListener.clickMethod); + addListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, ClickEvent.class, + listener, ClickListener.clickMethod); } /** @@ -510,35 +517,12 @@ public class Embedded extends AbstractComponent { * The listener to remove */ public void removeListener(ClickListener listener) { - removeListener(CLICK_EVENT, ClickEvent.class, listener); + removeListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, + ClickEvent.class, listener); } - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - @SuppressWarnings("unchecked") - @Override public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - if (variables.containsKey(CLICK_EVENT)) { - fireClick((Map<String, Object>) variables.get(CLICK_EVENT)); - } - - } - - /** - * Notifies click-listeners that a mouse click event has occurred. - * - * @param parameters - */ - private void fireClick(Map<String, Object> parameters) { - MouseEventDetails mouseDetails = MouseEventDetails - .deSerialize((String) parameters.get("mouseDetails")); - - fireEvent(new ClickEvent(this, mouseDetails)); + // TODO Remove once Vaadin6Component is no longer implemented } } diff --git a/src/com/vaadin/ui/ExpandLayout.java b/src/com/vaadin/ui/ExpandLayout.java deleted file mode 100644 index 55ee2ffdcf..0000000000 --- a/src/com/vaadin/ui/ExpandLayout.java +++ /dev/null @@ -1,101 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -/** - * A layout that will give one of it's components as much space as possible, - * while still showing the other components in the layout. The other components - * will in effect be given a fixed sized space, while the space given to the - * expanded component will grow/shrink to fill the rest of the space available - - * for instance when re-sizing the window. - * - * Note that this layout is 100% in both directions by default ({link - * {@link #setSizeFull()}). Remember to set the units if you want to specify a - * fixed size. If the layout fails to show up, check that the parent layout is - * actually giving some space. - * - * @deprecated Deprecated in favor of the new OrderedLayout - */ -@SuppressWarnings("serial") -@Deprecated -public class ExpandLayout extends OrderedLayout { - - private Component expanded = null; - - public ExpandLayout() { - this(ORIENTATION_VERTICAL); - } - - public ExpandLayout(int orientation) { - super(orientation); - - setSizeFull(); - } - - /** - * @param c - * Component which container will be maximized - */ - public void expand(Component c) { - if (expanded != null) { - try { - setExpandRatio(expanded, 0.0f); - } catch (IllegalArgumentException e) { - // Ignore error if component has been removed - } - } - - expanded = c; - if (expanded != null) { - setExpandRatio(expanded, 1.0f); - } - - requestRepaint(); - } - - @Override - public void addComponent(Component c, int index) { - super.addComponent(c, index); - if (expanded == null) { - expand(c); - } - } - - @Override - public void addComponent(Component c) { - super.addComponent(c); - if (expanded == null) { - expand(c); - } - } - - @Override - public void addComponentAsFirst(Component c) { - super.addComponentAsFirst(c); - if (expanded == null) { - expand(c); - } - } - - @Override - public void removeComponent(Component c) { - super.removeComponent(c); - if (c == expanded) { - if (getComponentIterator().hasNext()) { - expand(getComponentIterator().next()); - } else { - expand(null); - } - } - } - - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - super.replaceComponent(oldComponent, newComponent); - if (oldComponent == expanded) { - expand(newComponent); - } - } -} diff --git a/src/com/vaadin/ui/Field.java b/src/com/vaadin/ui/Field.java index 0cd6cd2d87..3a66db47b0 100644 --- a/src/com/vaadin/ui/Field.java +++ b/src/com/vaadin/ui/Field.java @@ -9,30 +9,21 @@ import com.vaadin.data.Property; import com.vaadin.ui.Component.Focusable; /** + * TODO document + * * @author Vaadin Ltd. * + * @param T + * the type of values in the field, which might not be the same type + * as that of the data source if converters are used + * + * @author IT Mill Ltd. */ -public interface Field extends Component, BufferedValidatable, Property, +public interface Field<T> extends Component, BufferedValidatable, Property<T>, Property.ValueChangeNotifier, Property.ValueChangeListener, Property.Editor, Focusable { /** - * Sets the Caption. - * - * @param caption - */ - void setCaption(String caption); - - String getDescription(); - - /** - * Sets the Description. - * - * @param caption - */ - void setDescription(String caption); - - /** * Is this field required. * * Required fields must filled by the user. @@ -80,7 +71,7 @@ public interface Field extends Component, BufferedValidatable, Property, * @since 3.0 */ @SuppressWarnings("serial") - public class ValueChangeEvent extends Component.Event implements + public static class ValueChangeEvent extends Component.Event implements Property.ValueChangeEvent { /** diff --git a/src/com/vaadin/ui/FieldFactory.java b/src/com/vaadin/ui/FieldFactory.java deleted file mode 100644 index d18918640e..0000000000 --- a/src/com/vaadin/ui/FieldFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.data.Property; - -/** - * Factory for creating new Field-instances based on type, datasource and/or - * context. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.1 - * @deprecated FieldFactory was split into two lighter interfaces in 6.0 Use - * FormFieldFactory or TableFieldFactory or both instead. - */ -@Deprecated -public interface FieldFactory extends FormFieldFactory, TableFieldFactory { - - /** - * Creates a field based on type of data. - * - * @param type - * the type of data presented in field. - * @param uiContext - * the component where the field is presented. - * @return Field the field suitable for editing the specified data. - * - */ - Field createField(Class<?> type, Component uiContext); - - /** - * Creates a field based on the property datasource. - * - * @param property - * the property datasource. - * @param uiContext - * the component where the field is presented. - * @return Field the field suitable for editing the specified data. - */ - Field createField(Property property, Component uiContext); - -}
\ No newline at end of file diff --git a/src/com/vaadin/ui/Form.java b/src/com/vaadin/ui/Form.java index c3bb725edf..5f5516b21f 100644 --- a/src/com/vaadin/ui/Form.java +++ b/src/com/vaadin/ui/Form.java @@ -4,6 +4,7 @@ package com.vaadin.ui; +import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -17,16 +18,20 @@ import com.vaadin.data.Property; import com.vaadin.data.Validatable; import com.vaadin.data.Validator; import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.fieldgroup.FieldGroup; import com.vaadin.data.util.BeanItem; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.event.Action.ShortcutNotifier; import com.vaadin.event.ActionManager; +import com.vaadin.terminal.AbstractErrorMessage; import com.vaadin.terminal.CompositeErrorMessage; import com.vaadin.terminal.ErrorMessage; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VForm; +import com.vaadin.terminal.UserError; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.form.FormState; /** * Form component provides easy way of creating and managing sets fields. @@ -58,20 +63,17 @@ import com.vaadin.terminal.gwt.client.ui.VForm; * @version * @VERSION@ * @since 3.0 + * @deprecated Use {@link FieldGroup} instead of {@link Form} for more + * flexibility. */ -@SuppressWarnings("serial") -@ClientWidget(VForm.class) -public class Form extends AbstractField implements Item.Editor, Buffered, Item, - Validatable, Action.Notifier { +@Deprecated +public class Form extends AbstractField<Object> implements Item.Editor, + Buffered, Item, Validatable, Action.Notifier, HasComponents, + Vaadin6Component { private Object propertyValue; /** - * Layout of the form. - */ - private Layout layout; - - /** * Item connected to this form as datasource. */ private Item itemDatasource; @@ -99,12 +101,12 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, /** * Mapping from propertyName to corresponding field. */ - private final HashMap<Object, Field> fields = new HashMap<Object, Field>(); + private final HashMap<Object, Field<?>> fields = new HashMap<Object, Field<?>>(); /** * Form may act as an Item, its own properties are stored here. */ - private final HashMap<Object, Property> ownProperties = new HashMap<Object, Property>(); + private final HashMap<Object, Property<?>> ownProperties = new HashMap<Object, Property<?>>(); /** * Field factory for this form. @@ -129,8 +131,6 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } }; - private Layout formFooter; - /** * If this is true, commit implicitly calls setValidationVisible(true). */ @@ -182,30 +182,25 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, public Form(Layout formLayout, FormFieldFactory fieldFactory) { super(); setLayout(formLayout); + setFooter(null); setFormFieldFactory(fieldFactory); setValidationVisible(false); setWidth(100, UNITS_PERCENTAGE); } - /* Documented in interface */ @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - layout.paint(target); - if (formFooter != null) { - formFooter.paint(target); - } + public FormState getState() { + return (FormState) super.getState(); + } + /* Documented in interface */ + public void paintContent(PaintTarget target) throws PaintException { if (ownActionManager != null) { ownActionManager.paintActions(null, target); } } - @Override public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - // Actions if (ownActionManager != null) { ownActionManager.handleActions(variables, this); @@ -238,15 +233,13 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, if (validationError != null) { // Show caption as error for fields with empty errors if ("".equals(validationError.toString())) { - validationError = new Validator.InvalidValueException( - field.getCaption()); + validationError = new UserError(field.getCaption()); } break; - } else if (f instanceof Field && !((Field) f).isValid()) { + } else if (f instanceof Field && !((Field<?>) f).isValid()) { // Something is wrong with the field, but no proper // error is given. Generate one. - validationError = new Validator.InvalidValueException( - field.getCaption()); + validationError = new UserError(field.getCaption()); break; } } @@ -260,9 +253,12 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } // Throw combination of the error types - return new CompositeErrorMessage(new ErrorMessage[] { - getComponentError(), validationError, - currentBufferedSourceException }); + return new CompositeErrorMessage( + new ErrorMessage[] { + getComponentError(), + validationError, + AbstractErrorMessage + .getErrorMessageForException(currentBufferedSourceException) }); } /** @@ -321,7 +317,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, // Try to commit all for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { try { - final Field f = (fields.get(i.next())); + final Field<?> f = (fields.get(i.next())); // Commit only non-readonly fields. if (!f.isReadOnly()) { f.commit(); @@ -408,7 +404,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, @Override public boolean isModified() { for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - final Field f = fields.get(i.next()); + final Field<?> f = fields.get(i.next()); if (f != null && f.isModified()) { return true; } @@ -422,6 +418,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * we use the default one from the interface. */ @Override + @Deprecated public boolean isReadThrough() { return readThrough; } @@ -431,6 +428,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * we use the default one from the interface. */ @Override + @Deprecated public boolean isWriteThrough() { return writeThrough; } @@ -485,7 +483,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, ownProperties.put(id, property); // Gets suitable field - final Field field = fieldFactory.createField(this, id, this); + final Field<?> field = fieldFactory.createField(this, id, this); if (field == null) { return false; } @@ -516,7 +514,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * @param field * the field which should be added to the form. */ - public void addField(Object propertyId, Field field) { + public void addField(Object propertyId, Field<?> field) { registerField(propertyId, field); attachField(propertyId, field); requestRepaint(); @@ -536,7 +534,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * @param field * the Field that should be registered */ - private void registerField(Object propertyId, Field field) { + private void registerField(Object propertyId, Field<?> field) { if (propertyId == null || field == null) { return; } @@ -580,6 +578,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, return; } + Layout layout = getLayout(); if (layout instanceof CustomLayout) { ((CustomLayout) layout).addComponent(field, propertyId.toString()); } else { @@ -599,13 +598,13 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * * @see com.vaadin.data.Item#getItemProperty(Object) */ - public Property getItemProperty(Object id) { - final Field field = fields.get(id); + public Property<?> getItemProperty(Object id) { + final Field<?> field = fields.get(id); if (field == null) { // field does not exist or it is not (yet) created for this property return ownProperties.get(id); } - final Property property = field.getPropertyDataSource(); + final Property<?> property = field.getPropertyDataSource(); if (property != null) { return property; @@ -620,7 +619,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * @param propertyId * the id of the property. */ - public Field getField(Object propertyId) { + public Field<?> getField(Object propertyId) { return fields.get(propertyId); } @@ -637,7 +636,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, public boolean removeItemProperty(Object id) { ownProperties.remove(id); - final Field field = fields.get(id); + final Field<?> field = fields.get(id); if (field != null) { propertyIds.remove(id); @@ -722,8 +721,8 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, */ public void setItemDataSource(Item newDataSource, Collection<?> propertyIds) { - if (layout instanceof GridLayout) { - GridLayout gl = (GridLayout) layout; + if (getLayout() instanceof GridLayout) { + GridLayout gl = (GridLayout) getLayout(); if (gridlayoutCursorX == -1) { // first setItemDataSource, remember initial cursor gridlayoutCursorX = gl.getCursorX(); @@ -750,9 +749,9 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, // Adds all the properties to this form for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) { final Object id = i.next(); - final Property property = itemDatasource.getItemProperty(id); + final Property<?> property = itemDatasource.getItemProperty(id); if (id != null && property != null) { - final Field f = fieldFactory.createField(itemDatasource, id, + final Field<?> f = fieldFactory.createField(itemDatasource, id, this); if (f != null) { bindPropertyToField(id, property, f); @@ -799,25 +798,24 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * @return the Layout of the form. */ public Layout getLayout() { - return layout; + return (Layout) getState().getLayout(); } /** * Sets the layout of the form. * * <p> - * By default form uses <code>OrderedLayout</code> with <code>form</code> - * -style. + * If set to null then Form uses a FormLayout by default. * </p> * - * @param newLayout - * the Layout of the form. + * @param layout + * the layout of the form. */ - public void setLayout(Layout newLayout) { + public void setLayout(Layout layout) { // Use orderedlayout by default - if (newLayout == null) { - newLayout = new FormLayout(); + if (layout == null) { + layout = new FormLayout(); } // reset cursor memory @@ -825,26 +823,29 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, gridlayoutCursorY = -1; // Move fields from previous layout - if (layout != null) { + if (getLayout() != null) { final Object[] properties = propertyIds.toArray(); for (int i = 0; i < properties.length; i++) { - Field f = getField(properties[i]); + Field<?> f = getField(properties[i]); detachField(f); - if (newLayout instanceof CustomLayout) { - ((CustomLayout) newLayout).addComponent(f, + if (layout instanceof CustomLayout) { + ((CustomLayout) layout).addComponent(f, properties[i].toString()); } else { - newLayout.addComponent(f); + layout.addComponent(f); } } - layout.setParent(null); + getLayout().setParent(null); } // Replace the previous layout - newLayout.setParent(this); - layout = newLayout; + layout.setParent(this); + getState().setLayout(layout); + // Hierarchy has changed so we need to repaint (this could be a + // hierarchy repaint only) + requestRepaint(); } /** @@ -856,13 +857,16 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * match. Null values are not supported. * </p> * + * Note: since Vaadin 7.0, returns an {@link AbstractSelect} instead of a + * {@link Select}. + * * @param propertyId * the id of the property. * @param values * @param descriptions * @return the select property generated */ - public Select replaceWithSelect(Object propertyId, Object[] values, + public AbstractSelect replaceWithSelect(Object propertyId, Object[] values, Object[] descriptions) { // Checks the parameters @@ -875,7 +879,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } // Gets the old field - final Field oldField = fields.get(propertyId); + final Field<?> oldField = fields.get(propertyId); if (oldField == null) { throw new IllegalArgumentException("Field with given propertyid '" + propertyId.toString() + "' can not be found."); @@ -922,10 +926,8 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } // Creates the new field matching to old field parameters - final Select newField = new Select(); - if (isMultiselect) { - newField.setMultiSelect(true); - } + final AbstractSelect newField = isMultiselect ? new ListSelect() + : new Select(); newField.setCaption(oldField.getCaption()); newField.setReadOnly(oldField.isReadOnly()); newField.setReadThrough(oldField.isReadThrough()); @@ -952,12 +954,12 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } // Sets the property data source - final Property property = oldField.getPropertyDataSource(); + final Property<?> property = oldField.getPropertyDataSource(); oldField.setPropertyDataSource(null); newField.setPropertyDataSource(property); // Replaces the old field with new one - layout.replaceComponent(oldField, newField); + getLayout().replaceComponent(oldField, newField); fields.put(propertyId, newField); newField.addListener(fieldValueChangeListener); oldField.removeListener(fieldValueChangeListener); @@ -973,9 +975,9 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, @Override public void attach() { super.attach(); - layout.attach(); - if (formFooter != null) { - formFooter.attach(); + getLayout().attach(); + if (getFooter() != null) { + getFooter().attach(); } } @@ -987,28 +989,14 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, @Override public void detach() { super.detach(); - layout.detach(); - if (formFooter != null) { - formFooter.detach(); + getLayout().detach(); + if (getFooter() != null) { + getFooter().detach(); } } /** - * Tests the current value of the object against all registered validators - * - * @see com.vaadin.data.Validatable#isValid() - */ - @Override - public boolean isValid() { - boolean valid = true; - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - valid &= (fields.get(i.next())).isValid(); - } - return valid && super.isValid(); - } - - /** - * Checks the validity of the validatable. + * Checks the validity of the Form and all of its fields. * * @see com.vaadin.data.Validatable#validate() */ @@ -1055,23 +1043,6 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } /** - * Sets the field factory of Form. - * - * <code>FieldFactory</code> is used to create fields for form properties. - * By default the form uses BaseFieldFactory to create Field instances. - * - * @param fieldFactory - * the New factory used to create the fields. - * @see Field - * @see FormFieldFactory - * @deprecated use {@link #setFormFieldFactory(FormFieldFactory)} instead - */ - @Deprecated - public void setFieldFactory(FieldFactory fieldFactory) { - this.fieldFactory = fieldFactory; - } - - /** * Sets the field factory used by this Form to genarate Fields for * properties. * @@ -1097,23 +1068,6 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } /** - * Get the field factory of the form. - * - * @return the FieldFactory Factory used to create the fields. - * @deprecated Use {@link #getFormFieldFactory()} instead. Set the - * FormFieldFactory using - * {@link #setFormFieldFactory(FormFieldFactory)}. - */ - @Deprecated - public FieldFactory getFieldFactory() { - if (fieldFactory instanceof FieldFactory) { - return (FieldFactory) fieldFactory; - - } - return null; - } - - /** * Gets the field type. * * @see com.vaadin.ui.AbstractField#getType() @@ -1155,11 +1109,11 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * * @return the Field. */ - private Field getFirstFocusableField() { + private Field<?> getFirstFocusableField() { if (getItemPropertyIds() != null) { for (Object id : getItemPropertyIds()) { if (id != null) { - Field field = getField(id); + Field<?> field = getField(id); if (field.isEnabled() && !field.isReadOnly()) { return field; } @@ -1248,7 +1202,7 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, */ @Override public void focus() { - final Field f = getFirstFocusableField(); + final Field<?> f = getFirstFocusableField(); if (f != null) { f.focus(); } @@ -1274,8 +1228,8 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, @Override public void setImmediate(boolean immediate) { super.setImmediate(immediate); - for (Iterator<Field> i = fields.values().iterator(); i.hasNext();) { - Field f = i.next(); + for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) { + Field<?> f = i.next(); if (f instanceof AbstractComponent) { ((AbstractComponent) f).setImmediate(immediate); } @@ -1286,10 +1240,10 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, @Override protected boolean isEmpty() { - for (Iterator<Field> i = fields.values().iterator(); i.hasNext();) { - Field f = i.next(); + for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) { + Field<?> f = i.next(); if (f instanceof AbstractField) { - if (!((AbstractField) f).isEmpty()) { + if (!((AbstractField<?>) f).isEmpty()) { return false; } } @@ -1315,25 +1269,32 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, * @return layout rendered below normal form contents. */ public Layout getFooter() { - if (formFooter == null) { - formFooter = new HorizontalLayout(); - formFooter.setParent(this); - } - return formFooter; + return (Layout) getState().getFooter(); } /** - * Sets the layout that is rendered below normal form contens. + * Sets the layout that is rendered below normal form contents. Setting this + * to null will cause an empty HorizontalLayout to be rendered in the + * footer. * - * @param newFormFooter - * the new Layout + * @param footer + * the new footer layout */ - public void setFooter(Layout newFormFooter) { - if (formFooter != null) { - formFooter.setParent(null); + public void setFooter(Layout footer) { + if (getFooter() != null) { + getFooter().setParent(null); } - formFooter = newFormFooter; - formFooter.setParent(this); + if (footer == null) { + footer = new HorizontalLayout(); + } + + getState().setFooter(footer); + footer.setParent(this); + + // Hierarchy has changed so we need to repaint (this could be a + // hierarchy repaint only) + requestRepaint(); + } @Override @@ -1399,4 +1360,74 @@ public class Form extends AbstractField implements Item.Editor, Buffered, Item, } } + public Iterator<Component> iterator() { + return getComponentIterator(); + } + + /** + * Modifiable and Serializable Iterator for the components, used by + * {@link Form#getComponentIterator()}. + */ + private class ComponentIterator implements Iterator<Component>, + Serializable { + + int i = 0; + + public boolean hasNext() { + if (i < getComponentCount()) { + return true; + } + return false; + } + + public Component next() { + if (!hasNext()) { + return null; + } + i++; + if (i == 1) { + return getLayout() != null ? getLayout() : getFooter(); + } else if (i == 2) { + return getFooter(); + } + return null; + } + + public void remove() { + if (i == 1) { + if (getLayout() != null) { + setLayout(null); + i = 0; + } else { + setFooter(null); + } + } else if (i == 2) { + setFooter(null); + } + } + } + + public Iterator<Component> getComponentIterator() { + return new ComponentIterator(); + } + + public void requestRepaintAll() { + AbstractComponentContainer.requestRepaintAll(this); + } + + public int getComponentCount() { + int count = 0; + if (getLayout() != null) { + count++; + } + if (getFooter() != null) { + count++; + } + + return count; + } + + public boolean isComponentVisible(Component childComponent) { + return true; + }; } diff --git a/src/com/vaadin/ui/FormFieldFactory.java b/src/com/vaadin/ui/FormFieldFactory.java index 52ecfcd8c2..1efa05c5f5 100644 --- a/src/com/vaadin/ui/FormFieldFactory.java +++ b/src/com/vaadin/ui/FormFieldFactory.java @@ -37,5 +37,5 @@ public interface FormFieldFactory extends Serializable { * creating it. * @return Field the field suitable for editing the specified data. */ - Field createField(Item item, Object propertyId, Component uiContext); + Field<?> createField(Item item, Object propertyId, Component uiContext); } diff --git a/src/com/vaadin/ui/FormLayout.java b/src/com/vaadin/ui/FormLayout.java index f61f5d544e..c0be784a7b 100644 --- a/src/com/vaadin/ui/FormLayout.java +++ b/src/com/vaadin/ui/FormLayout.java @@ -4,8 +4,6 @@ package com.vaadin.ui; -import com.vaadin.terminal.gwt.client.ui.VFormLayout; - /** * FormLayout is used by {@link Form} to layout fields. It may also be used * separately without {@link Form}. @@ -21,14 +19,13 @@ import com.vaadin.terminal.gwt.client.ui.VFormLayout; * bottom are by default on. * */ -@SuppressWarnings({ "deprecation", "serial" }) -@ClientWidget(VFormLayout.class) -public class FormLayout extends OrderedLayout { +public class FormLayout extends AbstractOrderedLayout { public FormLayout() { super(); setSpacing(true); setMargin(true, false, true, false); + setWidth(100, UNITS_PERCENTAGE); } } diff --git a/src/com/vaadin/ui/GridLayout.java b/src/com/vaadin/ui/GridLayout.java index 90122cddf9..0ab729ce5c 100644 --- a/src/com/vaadin/ui/GridLayout.java +++ b/src/com/vaadin/ui/GridLayout.java @@ -15,10 +15,15 @@ import java.util.Map.Entry; import com.vaadin.event.LayoutEvents.LayoutClickEvent; import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.event.LayoutEvents.LayoutClickNotifier; +import com.vaadin.terminal.LegacyPaint; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.EventId; -import com.vaadin.terminal.gwt.client.ui.VGridLayout; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.gridlayout.GridLayoutServerRpc; +import com.vaadin.terminal.gwt.client.ui.gridlayout.GridLayoutState; /** * A layout where the components are laid out on a grid using cell coordinates. @@ -47,22 +52,19 @@ import com.vaadin.terminal.gwt.client.ui.VGridLayout; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VGridLayout.class) public class GridLayout extends AbstractLayout implements - Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier { + Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier, + Vaadin6Component { - private static final String CLICK_EVENT = EventId.LAYOUT_CLICK; + private GridLayoutServerRpc rpc = new GridLayoutServerRpc() { - /** - * Initial grid columns. - */ - private int cols = 0; - - /** - * Initial grid rows. - */ - private int rows = 0; + public void layoutClick(MouseEventDetails mouseDetails, + Connector clickedConnector) { + fireEvent(LayoutClickEvent.createEvent(GridLayout.this, + mouseDetails, clickedConnector)); + } + }; /** * Cursor X position: this is where the next component with unspecified x,y * is inserted @@ -91,11 +93,6 @@ public class GridLayout extends AbstractLayout implements */ private Map<Component, Alignment> componentToAlignment = new HashMap<Component, Alignment>(); - /** - * Is spacing between contained components enabled. Defaults to false. - */ - private boolean spacing = false; - private static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT; /** @@ -121,6 +118,7 @@ public class GridLayout extends AbstractLayout implements public GridLayout(int columns, int rows) { setColumns(columns); setRows(rows); + registerRpc(rpc); } /** @@ -130,6 +128,11 @@ public class GridLayout extends AbstractLayout implements this(1, 1); } + @Override + public GridLayoutState getState() { + return (GridLayoutState) super.getState(); + } + /** * <p> * Adds a component to the grid in the specified area. The area is defined @@ -185,7 +188,8 @@ public class GridLayout extends AbstractLayout implements throw new IllegalArgumentException( "Illegal coordinates for the component"); } - if (column1 < 0 || row1 < 0 || column2 >= cols || row2 >= rows) { + if (column1 < 0 || row1 < 0 || column2 >= getColumns() + || row2 >= getRows()) { throw new OutOfBoundsException(area); } @@ -228,7 +232,7 @@ public class GridLayout extends AbstractLayout implements && cursorY <= row2) { // cursor within area cursorX = column2 + 1; // one right of area - if (cursorX >= cols) { + if (cursorX >= getColumns()) { // overflowed columns cursorX = 0; // first col // move one row down, or one row under the area @@ -310,7 +314,7 @@ public class GridLayout extends AbstractLayout implements */ public void space() { cursorX++; - if (cursorX >= cols) { + if (cursorX >= getColumns()) { cursorX = 0; cursorY++; } @@ -342,8 +346,12 @@ public class GridLayout extends AbstractLayout implements } // Extends the grid if needed - cols = cursorX >= cols ? cursorX + 1 : cols; - rows = cursorY >= rows ? cursorY + 1 : rows; + if (cursorX >= getColumns()) { + setColumns(cursorX + 1); + } + if (cursorY >= getRows()) { + setRows(cursorY + 1); + } addComponent(component, cursorX, cursorY); } @@ -423,6 +431,10 @@ public class GridLayout extends AbstractLayout implements return components.size(); } + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented + } + /** * Paints the contents of this component. * @@ -431,22 +443,11 @@ public class GridLayout extends AbstractLayout implements * @throws PaintException * if the paint operation failed. */ - @Override public void paintContent(PaintTarget target) throws PaintException { - - super.paintContent(target); - // TODO refactor attribute names in future release. - target.addAttribute("h", rows); - target.addAttribute("w", cols); - target.addAttribute("structuralChange", structuralChange); structuralChange = false; - if (spacing) { - target.addAttribute("spacing", spacing); - } - // Area iterator final Iterator<Area> areaiterator = areas.iterator(); @@ -460,22 +461,22 @@ public class GridLayout extends AbstractLayout implements int emptyCells = 0; final String[] alignmentsArray = new String[components.size()]; - final Integer[] columnExpandRatioArray = new Integer[cols]; - final Integer[] rowExpandRatioArray = new Integer[rows]; + final Integer[] columnExpandRatioArray = new Integer[getColumns()]; + final Integer[] rowExpandRatioArray = new Integer[getRows()]; int realColExpandRatioSum = 0; float colSum = getExpandRatioSum(columnExpandRatio); if (colSum == 0) { // no columns has been expanded, all cols have same expand // rate - float equalSize = 1 / (float) cols; + float equalSize = 1 / (float) getColumns(); int myRatio = Math.round(equalSize * 1000); - for (int i = 0; i < cols; i++) { + for (int i = 0; i < getColumns(); i++) { columnExpandRatioArray[i] = myRatio; } - realColExpandRatioSum = myRatio * cols; + realColExpandRatioSum = myRatio * getColumns(); } else { - for (int i = 0; i < cols; i++) { + for (int i = 0; i < getColumns(); i++) { int myRatio = Math .round((getColumnExpandRatio(i) / colSum) * 1000); columnExpandRatioArray[i] = myRatio; @@ -489,18 +490,18 @@ public class GridLayout extends AbstractLayout implements if (rowSum == 0) { // no rows have been expanded equallyDividedRows = true; - float equalSize = 1 / (float) rows; + float equalSize = 1 / (float) getRows(); int myRatio = Math.round(equalSize * 1000); - for (int i = 0; i < rows; i++) { + for (int i = 0; i < getRows(); i++) { rowExpandRatioArray[i] = myRatio; } - realRowExpandRatioSum = myRatio * rows; + realRowExpandRatioSum = myRatio * getRows(); } int index = 0; // Iterates every applicable row - for (int cury = 0; cury < rows; cury++) { + for (int cury = 0; cury < getRows(); cury++) { target.startTag("gr"); if (!equallyDividedRows) { @@ -511,7 +512,7 @@ public class GridLayout extends AbstractLayout implements } // Iterates every applicable column - for (int curx = 0; curx < cols; curx++) { + for (int curx = 0; curx < getColumns(); curx++) { // Checks if current item is located at curx,cury if (area != null && (area.row1 == cury) @@ -543,7 +544,7 @@ public class GridLayout extends AbstractLayout implements if (rows > 1) { target.addAttribute("h", rows); } - area.getComponent().paint(target); + LegacyPaint.paint(area.getComponent(), target); alignmentsArray[index++] = String .valueOf(getComponentAlignment(area.getComponent()) @@ -621,7 +622,7 @@ public class GridLayout extends AbstractLayout implements // Checks if empty cell needs to be rendered if (emptyCells > 0) { target.startTag("gc"); - target.addAttribute("x", cols - emptyCells); + target.addAttribute("x", getColumns() - emptyCells); target.addAttribute("y", cury); if (emptyCells > 1) { target.addAttribute("w", emptyCells); @@ -967,12 +968,12 @@ public class GridLayout extends AbstractLayout implements } // In case of no change - if (cols == columns) { + if (getColumns() == columns) { return; } // Checks for overlaps - if (cols > columns) { + if (getColumns() > columns) { for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { final Area area = i.next(); if (area.column2 >= columns) { @@ -981,7 +982,7 @@ public class GridLayout extends AbstractLayout implements } } - cols = columns; + getState().setColumns(columns); requestRepaint(); } @@ -992,7 +993,7 @@ public class GridLayout extends AbstractLayout implements * @return the number of columns in the grid. */ public int getColumns() { - return cols; + return getState().getColumns(); } /** @@ -1011,12 +1012,12 @@ public class GridLayout extends AbstractLayout implements } // In case of no change - if (this.rows == rows) { + if (getRows() == rows) { return; } // Checks for overlaps - if (this.rows > rows) { + if (getRows() > rows) { for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { final Area area = i.next(); if (area.row2 >= rows) { @@ -1025,7 +1026,7 @@ public class GridLayout extends AbstractLayout implements } } - this.rows = rows; + getState().setRows(rows); requestRepaint(); } @@ -1036,7 +1037,7 @@ public class GridLayout extends AbstractLayout implements * @return the number of rows in the grid. */ public int getRows() { - return rows; + return getState().getRows(); } /** @@ -1160,8 +1161,8 @@ public class GridLayout extends AbstractLayout implements * * @see com.vaadin.ui.Layout.SpacingHandler#setSpacing(boolean) */ - public void setSpacing(boolean enabled) { - spacing = enabled; + public void setSpacing(boolean spacing) { + getState().setSpacing(spacing); requestRepaint(); } @@ -1170,18 +1171,8 @@ public class GridLayout extends AbstractLayout implements * * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing() */ - @Deprecated - public boolean isSpacingEnabled() { - return spacing; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing() - */ public boolean isSpacing() { - return spacing; + return getState().isSpacing(); } /** @@ -1192,9 +1183,9 @@ public class GridLayout extends AbstractLayout implements * The leftmost row has index 0. */ public void insertRow(int row) { - if (row > rows) { + if (row > getRows()) { throw new IllegalArgumentException("Cannot insert row at " + row - + " in a gridlayout with height " + rows); + + " in a gridlayout with height " + getRows()); } for (Iterator<Area> i = areas.iterator(); i.hasNext();) { @@ -1215,7 +1206,7 @@ public class GridLayout extends AbstractLayout implements cursorY++; } - setRows(rows + 1); + setRows(getRows() + 1); structuralChange = true; requestRepaint(); } @@ -1238,9 +1229,9 @@ public class GridLayout extends AbstractLayout implements * Index of the row to remove. The leftmost row has index 0. */ public void removeRow(int row) { - if (row >= rows) { + if (row >= getRows()) { throw new IllegalArgumentException("Cannot delete row " + row - + " from a gridlayout with height " + rows); + + " from a gridlayout with height " + getRows()); } // Remove all components in row @@ -1260,7 +1251,7 @@ public class GridLayout extends AbstractLayout implements } } - if (rows == 1) { + if (getRows() == 1) { /* * Removing the last row means that the dimensions of the Grid * layout will be truncated to 1 empty row and the cursor is moved @@ -1269,7 +1260,7 @@ public class GridLayout extends AbstractLayout implements cursorX = 0; cursorY = 0; } else { - setRows(rows - 1); + setRows(getRows() - 1); if (cursorY > row) { cursorY--; } @@ -1397,29 +1388,15 @@ public class GridLayout extends AbstractLayout implements return null; } - /** - * Sets the component alignment using a shorthand string notation. - * - * @deprecated Replaced by - * {@link #setComponentAlignment(Component, Alignment)} - * - * @param component - * A child component in this layout - * @param alignment - * A short hand notation described in {@link AlignmentUtils} - */ - @Deprecated - public void setComponentAlignment(Component component, String alignment) { - AlignmentUtils.setComponentAlignment(this, component, alignment); - } - public void addListener(LayoutClickListener listener) { - addListener(CLICK_EVENT, LayoutClickEvent.class, listener, + addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener, LayoutClickListener.clickMethod); } public void removeListener(LayoutClickListener listener) { - removeListener(CLICK_EVENT, LayoutClickEvent.class, listener); + removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, + LayoutClickEvent.class, listener); } } diff --git a/src/com/vaadin/ui/HasComponents.java b/src/com/vaadin/ui/HasComponents.java new file mode 100644 index 0000000000..eca89ddcd2 --- /dev/null +++ b/src/com/vaadin/ui/HasComponents.java @@ -0,0 +1,54 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.ui; + +import java.util.Iterator; + +/** + * Interface that must be implemented by all {@link Component}s that contain + * other {@link Component}s. + * + * @author Vaadin Ltd + * @version @VERSION@ + * @since 7.0.0 + * + */ +public interface HasComponents extends Component, Iterable<Component> { + /** + * Gets an iterator to the collection of contained components. Using this + * iterator it is possible to step through all components contained in this + * container. + * + * @return the component iterator. + */ + public Iterator<Component> getComponentIterator(); + + /** + * Checks if the child component is visible. This method allows hiding a + * child component from updates and communication to and from the client. + * This is useful for components that show only a limited number of its + * children at any given time and want to allow updates only for the + * children that are visible (e.g. TabSheet has one tab open at a time). + * <p> + * Note that this will prevent updates from reaching the child even though + * the child itself is set to visible. Also if a child is set to invisible + * this will not force it to be visible. + * </p> + * + * @param childComponent + * The child component to check + * @return true if the child component is visible to the user, false + * otherwise + */ + public boolean isComponentVisible(Component childComponent); + + /** + * Causes a repaint of this component, and all components below it. + * + * This should only be used in special cases, e.g when the state of a + * descendant depends on the state of a ancestor. + */ + public void requestRepaintAll(); + +} diff --git a/src/com/vaadin/ui/HorizontalLayout.java b/src/com/vaadin/ui/HorizontalLayout.java index ed1cad8184..b9dc1c13ca 100644 --- a/src/com/vaadin/ui/HorizontalLayout.java +++ b/src/com/vaadin/ui/HorizontalLayout.java @@ -3,9 +3,6 @@ */ package com.vaadin.ui; -import com.vaadin.terminal.gwt.client.ui.VHorizontalLayout; -import com.vaadin.ui.ClientWidget.LoadStyle; - /** * Horizontal layout * @@ -18,7 +15,6 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @since 5.3 */ @SuppressWarnings("serial") -@ClientWidget(value = VHorizontalLayout.class, loadStyle = LoadStyle.EAGER) public class HorizontalLayout extends AbstractOrderedLayout { public HorizontalLayout() { diff --git a/src/com/vaadin/ui/HorizontalSplitPanel.java b/src/com/vaadin/ui/HorizontalSplitPanel.java index d9368635df..5bd6c8a075 100644 --- a/src/com/vaadin/ui/HorizontalSplitPanel.java +++ b/src/com/vaadin/ui/HorizontalSplitPanel.java @@ -3,9 +3,6 @@ */ package com.vaadin.ui; -import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal; -import com.vaadin.ui.ClientWidget.LoadStyle; - /** * A horizontal split panel contains two components and lays them horizontally. * The first component is on the left side. @@ -29,7 +26,6 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @VERSION@ * @since 6.5 */ -@ClientWidget(value = VSplitPanelHorizontal.class, loadStyle = LoadStyle.EAGER) public class HorizontalSplitPanel extends AbstractSplitPanel { public HorizontalSplitPanel() { super(); diff --git a/src/com/vaadin/ui/InlineDateField.java b/src/com/vaadin/ui/InlineDateField.java index 50e16d803b..cf61703318 100644 --- a/src/com/vaadin/ui/InlineDateField.java +++ b/src/com/vaadin/ui/InlineDateField.java @@ -7,7 +7,6 @@ package com.vaadin.ui; import java.util.Date; import com.vaadin.data.Property; -import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar; /** * <p> @@ -22,7 +21,6 @@ import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar; * @VERSION@ * @since 5.0 */ -@ClientWidget(VDateFieldCalendar.class) public class InlineDateField extends DateField { public InlineDateField() { diff --git a/src/com/vaadin/ui/Label.java b/src/com/vaadin/ui/Label.java index 2dadf4f5c5..e52090aa5f 100644 --- a/src/com/vaadin/ui/Label.java +++ b/src/com/vaadin/ui/Label.java @@ -5,19 +5,18 @@ package com.vaadin.ui; import java.lang.reflect.Method; +import java.util.Map; import com.vaadin.data.Property; import com.vaadin.data.util.ObjectProperty; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VLabel; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.Vaadin6Component; /** * Label component for showing non-editable short texts. * - * The label content can be set to the modes specified by the final members - * CONTENT_* + * The label content can be set to the modes specified by {@link ContentMode} * * <p> * The contents of the label may contain simple formatting: @@ -39,67 +38,165 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(value = VLabel.class, loadStyle = LoadStyle.EAGER) +// TODO generics for interface Property public class Label extends AbstractComponent implements Property, Property.Viewer, Property.ValueChangeListener, - Property.ValueChangeNotifier, Comparable<Object> { + Property.ValueChangeNotifier, Comparable<Object>, Vaadin6Component { /** - * Content mode, where the label contains only plain text. The getValue() - * result is coded to XML when painting. + * Content modes defining how the client should interpret a Label's value. + * + * @sine 7.0 */ - public static final int CONTENT_TEXT = 0; + public enum ContentMode { + /** + * Content mode, where the label contains only plain text. The + * getValue() result is coded to XML when painting. + */ + TEXT(null) { + @Override + public void paintText(String text, PaintTarget target) + throws PaintException { + target.addText(text); + } + }, + + /** + * Content mode, where the label contains preformatted text. + */ + PREFORMATTED("pre") { + @Override + public void paintText(String text, PaintTarget target) + throws PaintException { + target.startTag("pre"); + target.addText(text); + target.endTag("pre"); + } + }, + + /** + * Content mode, where the label contains XHTML. Contents is then + * enclosed in DIV elements having namespace of + * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd". + */ + XHTML("xhtml") { + @Override + public void paintText(String text, PaintTarget target) + throws PaintException { + target.startTag("data"); + target.addXMLSection("div", text, + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); + target.endTag("data"); + } + }, + + /** + * Content mode, where the label contains well-formed or well-balanced + * XML. Each of the root elements must have their default namespace + * specified. + */ + XML("xml") { + @Override + public void paintText(String text, PaintTarget target) + throws PaintException { + target.addXMLSection("data", text, null); + } + }, + + /** + * Content mode, where the label contains RAW output. Output is not + * required to comply to with XML. In Web Adapter output is inserted + * inside the resulting HTML document as-is. This is useful for some + * specific purposes where possibly broken HTML content needs to be + * shown, but in most cases XHTML mode should be preferred. + */ + RAW("raw") { + @Override + public void paintText(String text, PaintTarget target) + throws PaintException { + target.startTag("data"); + target.addAttribute("escape", false); + target.addText(text); + target.endTag("data"); + } + }; + + private final String uidlName; + + /** + * The default content mode is text + */ + public static ContentMode DEFAULT = TEXT; + + private ContentMode(String uidlName) { + this.uidlName = uidlName; + } + + /** + * Gets the name representing this content mode in UIDL messages + * + * @return the UIDL name of this content mode + */ + public String getUidlName() { + return uidlName; + } + + /** + * Adds the text value to a {@link PaintTarget} according to this + * content mode + * + * @param text + * the text to add + * @param target + * the paint target to add the value to + * @throws PaintException + * if the paint operation failed + */ + public abstract void paintText(String text, PaintTarget target) + throws PaintException; + } /** - * Content mode, where the label contains preformatted text. + * @deprecated From 7.0, use {@link ContentMode#TEXT} instead */ - public static final int CONTENT_PREFORMATTED = 1; + @Deprecated + public static final ContentMode CONTENT_TEXT = ContentMode.TEXT; /** - * Formatted content mode, where the contents is XML restricted to the UIDL - * 1.0 formatting markups. - * - * @deprecated Use CONTENT_XML instead. + * @deprecated From 7.0, use {@link ContentMode#PREFORMATTED} instead */ @Deprecated - public static final int CONTENT_UIDL = 2; + public static final ContentMode CONTENT_PREFORMATTED = ContentMode.PREFORMATTED; /** - * Content mode, where the label contains XHTML. Contents is then enclosed - * in DIV elements having namespace of - * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd". + * @deprecated From 7.0, use {@link ContentMode#XHTML} instead */ - public static final int CONTENT_XHTML = 3; + @Deprecated + public static final ContentMode CONTENT_XHTML = ContentMode.XHTML; /** - * Content mode, where the label contains well-formed or well-balanced XML. - * Each of the root elements must have their default namespace specified. + * @deprecated From 7.0, use {@link ContentMode#XML} instead */ - public static final int CONTENT_XML = 4; + @Deprecated + public static final ContentMode CONTENT_XML = ContentMode.XML; /** - * Content mode, where the label contains RAW output. Output is not required - * to comply to with XML. In Web Adapter output is inserted inside the - * resulting HTML document as-is. This is useful for some specific purposes - * where possibly broken HTML content needs to be shown, but in most cases - * XHTML mode should be preferred. + * @deprecated From 7.0, use {@link ContentMode#RAW} instead */ - public static final int CONTENT_RAW = 5; + @Deprecated + public static final ContentMode CONTENT_RAW = ContentMode.RAW; /** - * The default content mode is plain text. + * @deprecated From 7.0, use {@link ContentMode#DEFAULT} instead */ - public static final int CONTENT_DEFAULT = CONTENT_TEXT; - - /** Array of content mode names that are rendered in UIDL as mode attribute. */ - private static final String[] CONTENT_MODE_NAME = { "text", "pre", "uidl", - "xhtml", "xml", "raw" }; + @Deprecated + public static final ContentMode CONTENT_DEFAULT = ContentMode.DEFAULT; private static final String DATASOURCE_MUST_BE_SET = "Datasource must be set"; private Property dataSource; - private int contentMode = CONTENT_DEFAULT; + private ContentMode contentMode = ContentMode.DEFAULT; /** * Creates an empty Label. @@ -114,7 +211,7 @@ public class Label extends AbstractComponent implements Property, * @param content */ public Label(String content) { - this(content, CONTENT_DEFAULT); + this(content, ContentMode.DEFAULT); } /** @@ -124,7 +221,7 @@ public class Label extends AbstractComponent implements Property, * @param contentSource */ public Label(Property contentSource) { - this(contentSource, CONTENT_DEFAULT); + this(contentSource, ContentMode.DEFAULT); } /** @@ -133,7 +230,7 @@ public class Label extends AbstractComponent implements Property, * @param content * @param contentMode */ - public Label(String content, int contentMode) { + public Label(String content, ContentMode contentMode) { this(new ObjectProperty<String>(content, String.class), contentMode); } @@ -144,43 +241,15 @@ public class Label extends AbstractComponent implements Property, * @param contentSource * @param contentMode */ - public Label(Property contentSource, int contentMode) { + public Label(Property contentSource, ContentMode contentMode) { setPropertyDataSource(contentSource); - if (contentMode != CONTENT_DEFAULT) { + if (contentMode != ContentMode.DEFAULT) { setContentMode(contentMode); } setWidth(100, UNITS_PERCENTAGE); } /** - * Set the component to read-only. Readonly is not used in label. - * - * @param readOnly - * True to enable read-only mode, False to disable it. - */ - @Override - public void setReadOnly(boolean readOnly) { - if (dataSource == null) { - throw new IllegalStateException(DATASOURCE_MUST_BE_SET); - } - dataSource.setReadOnly(readOnly); - } - - /** - * Is the component read-only ? Readonly is not used in label - this returns - * allways false. - * - * @return <code>true</code> if the component is in read only mode. - */ - @Override - public boolean isReadOnly() { - if (dataSource == null) { - throw new IllegalStateException(DATASOURCE_MUST_BE_SET); - } - return dataSource.isReadOnly(); - } - - /** * Paints the content of this component. * * @param target @@ -188,32 +257,12 @@ public class Label extends AbstractComponent implements Property, * @throws PaintException * if the Paint Operation fails. */ - @Override public void paintContent(PaintTarget target) throws PaintException { - if (contentMode != CONTENT_TEXT) { - target.addAttribute("mode", CONTENT_MODE_NAME[contentMode]); - } - if (contentMode == CONTENT_TEXT) { - target.addText(toString()); - } else if (contentMode == CONTENT_UIDL) { - target.addUIDL(toString()); - } else if (contentMode == CONTENT_XHTML) { - target.startTag("data"); - target.addXMLSection("div", toString(), - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); - target.endTag("data"); - } else if (contentMode == CONTENT_PREFORMATTED) { - target.startTag("pre"); - target.addText(toString()); - target.endTag("pre"); - } else if (contentMode == CONTENT_XML) { - target.addXMLSection("data", toString(), null); - } else if (contentMode == CONTENT_RAW) { - target.startTag("data"); - target.addAttribute("escape", false); - target.addText(toString()); - target.endTag("data"); + String uidlName = contentMode.getUidlName(); + if (uidlName != null) { + target.addAttribute("mode", uidlName); } + contentMode.paintText(getStringValue(), target); } @@ -246,13 +295,33 @@ public class Label extends AbstractComponent implements Property, /** * @see java.lang.Object#toString() + * @deprecated use the data source value or {@link #getStringValue()} + * instead */ + @Deprecated @Override public String toString() { + throw new UnsupportedOperationException( + "Use Property.getValue() instead of Label.toString()"); + } + + /** + * Returns the value of the <code>Property</code> in human readable textual + * format. + * + * This method exists to help migration from previous Vaadin versions by + * providing a simple replacement for {@link #toString()}. However, it is + * normally better to use the value of the label directly. + * + * @return String representation of the value stored in the Property + * @since 7.0 + */ + public String getStringValue() { if (dataSource == null) { throw new IllegalStateException(DATASOURCE_MUST_BE_SET); } - return dataSource.toString(); + Object value = dataSource.getValue(); + return (null != value) ? value.toString() : null; } /** @@ -307,67 +376,27 @@ public class Label extends AbstractComponent implements Property, /** * Gets the content mode of the Label. * - * <p> - * Possible content modes include: - * <ul> - * <li><b>CONTENT_TEXT</b> Content mode, where the label contains only plain - * text. The getValue() result is coded to XML when painting.</li> - * <li><b>CONTENT_PREFORMATTED</b> Content mode, where the label contains - * preformatted text.</li> - * <li><b>CONTENT_UIDL</b> Formatted content mode, where the contents is XML - * restricted to the UIDL 1.0 formatting markups.</li> - * <li><b>CONTENT_XHTML</b> Content mode, where the label contains XHTML. - * Contents is then enclosed in DIV elements having namespace of - * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".</li> - * <li><b>CONTENT_XML</b> Content mode, where the label contains well-formed - * or well-balanced XML. Each of the root elements must have their default - * namespace specified.</li> - * <li><b>CONTENT_RAW</b> Content mode, where the label contains RAW output. - * Output is not required to comply to with XML. In Web Adapter output is - * inserted inside the resulting HTML document as-is. This is useful for - * some specific purposes where possibly broken HTML content needs to be - * shown, but in most cases XHTML mode should be preferred.</li> - * </ul> - * </p> - * * @return the Content mode of the label. + * + * @see ContentMode */ - public int getContentMode() { + public ContentMode getContentMode() { return contentMode; } /** * Sets the content mode of the Label. * - * <p> - * Possible content modes include: - * <ul> - * <li><b>CONTENT_TEXT</b> Content mode, where the label contains only plain - * text. The getValue() result is coded to XML when painting.</li> - * <li><b>CONTENT_PREFORMATTED</b> Content mode, where the label contains - * preformatted text.</li> - * <li><b>CONTENT_UIDL</b> Formatted content mode, where the contents is XML - * restricted to the UIDL 1.0 formatting markups.</li> - * <li><b>CONTENT_XHTML</b> Content mode, where the label contains XHTML. - * Contents is then enclosed in DIV elements having namespace of - * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd".</li> - * <li><b>CONTENT_XML</b> Content mode, where the label contains well-formed - * or well-balanced XML. Each of the root elements must have their default - * namespace specified.</li> - * <li><b>CONTENT_RAW</b> Content mode, where the label contains RAW output. - * Output is not required to comply to with XML. In Web Adapter output is - * inserted inside the resulting HTML document as-is. This is useful for - * some specific purposes where possibly broken HTML content needs to be - * shown, but in most cases XHTML mode should be preferred.</li> - * </ul> - * </p> - * * @param contentMode * the New content mode of the label. + * + * @see ContentMode */ - public void setContentMode(int contentMode) { - if (contentMode != this.contentMode && contentMode >= CONTENT_TEXT - && contentMode <= CONTENT_RAW) { + public void setContentMode(ContentMode contentMode) { + if (contentMode == null) { + throw new IllegalArgumentException("Content mode can not be null"); + } + if (contentMode != this.contentMode) { this.contentMode = contentMode; requestRepaint(); } @@ -397,7 +426,7 @@ public class Label extends AbstractComponent implements Property, * @VERSION@ * @since 3.0 */ - public class ValueChangeEvent extends Component.Event implements + public static class ValueChangeEvent extends Component.Event implements Property.ValueChangeEvent { /** @@ -487,19 +516,19 @@ public class Label extends AbstractComponent implements Property, String thisValue; String otherValue; - if (contentMode == CONTENT_XML || contentMode == CONTENT_UIDL - || contentMode == CONTENT_XHTML) { - thisValue = stripTags(toString()); + if (contentMode == ContentMode.XML || contentMode == ContentMode.XHTML) { + thisValue = stripTags(getStringValue()); } else { - thisValue = toString(); + thisValue = getStringValue(); } if (other instanceof Label - && (((Label) other).getContentMode() == CONTENT_XML - || ((Label) other).getContentMode() == CONTENT_UIDL || ((Label) other) - .getContentMode() == CONTENT_XHTML)) { - otherValue = stripTags(other.toString()); + && (((Label) other).getContentMode() == ContentMode.XML || ((Label) other) + .getContentMode() == ContentMode.XHTML)) { + otherValue = stripTags(((Label) other).getStringValue()); } else { + // TODO not a good idea - and might assume that Field.toString() + // returns a string representation of the value otherValue = other.toString(); } @@ -537,4 +566,8 @@ public class Label extends AbstractComponent implements Property, return res.toString(); } + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented + } + } diff --git a/src/com/vaadin/ui/Layout.java b/src/com/vaadin/ui/Layout.java index a7cd0abdb4..67bfaa75ff 100644 --- a/src/com/vaadin/ui/Layout.java +++ b/src/com/vaadin/ui/Layout.java @@ -178,15 +178,6 @@ public interface Layout extends ComponentContainer, Serializable { * * @return true if spacing between child components within this layout * is enabled, false otherwise - * @deprecated Use {@link #isSpacing()} instead. - */ - @Deprecated - public boolean isSpacingEnabled(); - - /** - * - * @return true if spacing between child components within this layout - * is enabled, false otherwise */ public boolean isSpacing(); } diff --git a/src/com/vaadin/ui/Link.java b/src/com/vaadin/ui/Link.java index ebea47118a..ed5ffbba3a 100644 --- a/src/com/vaadin/ui/Link.java +++ b/src/com/vaadin/ui/Link.java @@ -4,10 +4,12 @@ package com.vaadin.ui; +import java.util.Map; + import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VLink; +import com.vaadin.terminal.Vaadin6Component; /** * Link is used to create external or internal URL links. @@ -18,17 +20,16 @@ import com.vaadin.terminal.gwt.client.ui.VLink; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VLink.class) -public class Link extends AbstractComponent { +public class Link extends AbstractComponent implements Vaadin6Component { /* Target window border type constant: No window border */ - public static final int TARGET_BORDER_NONE = Window.BORDER_NONE; + public static final int TARGET_BORDER_NONE = Root.BORDER_NONE; /* Target window border type constant: Minimal window border */ - public static final int TARGET_BORDER_MINIMAL = Window.BORDER_MINIMAL; + public static final int TARGET_BORDER_MINIMAL = Root.BORDER_MINIMAL; /* Target window border type constant: Default window border */ - public static final int TARGET_BORDER_DEFAULT = Window.BORDER_DEFAULT; + public static final int TARGET_BORDER_DEFAULT = Root.BORDER_DEFAULT; private Resource resource = null; @@ -94,7 +95,6 @@ public class Link extends AbstractComponent { * @throws PaintException * if the paint operation failed. */ - @Override public void paintContent(PaintTarget target) throws PaintException { if (resource != null) { @@ -232,4 +232,8 @@ public class Link extends AbstractComponent { this.resource = resource; requestRepaint(); } + + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented + } } diff --git a/src/com/vaadin/ui/ListSelect.java b/src/com/vaadin/ui/ListSelect.java index 5c879f00f5..35ccb34b3c 100644 --- a/src/com/vaadin/ui/ListSelect.java +++ b/src/com/vaadin/ui/ListSelect.java @@ -9,14 +9,12 @@ import java.util.Collection; import com.vaadin.data.Container; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VListSelect; /** * This is a simple list select without, for instance, support for new items, * lazyloading, and other advanced features. */ @SuppressWarnings("serial") -@ClientWidget(VListSelect.class) public class ListSelect extends AbstractSelect { private int columns = 0; diff --git a/src/com/vaadin/ui/LoginForm.java b/src/com/vaadin/ui/LoginForm.java index 80e002435e..1d5203bc6b 100644 --- a/src/com/vaadin/ui/LoginForm.java +++ b/src/com/vaadin/ui/LoginForm.java @@ -4,10 +4,10 @@ package com.vaadin.ui; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; -import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -15,8 +15,9 @@ import java.util.Map; import com.vaadin.Application; import com.vaadin.terminal.ApplicationResource; import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.ParameterHandler; -import com.vaadin.terminal.URIHandler; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.terminal.gwt.client.ApplicationConnection; /** @@ -73,11 +74,20 @@ public class LoginForm extends CustomComponent { } }; - private ParameterHandler paramHandler = new ParameterHandler() { - - public void handleParameters(Map<String, String[]> parameters) { - if (parameters.containsKey("username")) { - getWindow().addURIHandler(uriHandler); + private final RequestHandler requestHandler = new RequestHandler() { + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + String requestPathInfo = request.getRequestPathInfo(); + if ("/loginHandler".equals(requestPathInfo)) { + response.setCacheTime(-1); + response.setContentType("text/html; charset=utf-8"); + response.getWriter() + .write("<html><body>Login form handled." + + "<script type='text/javascript'>top.vaadin.forceSync();" + + "</script></body></html>"); + + Map<String, String[]> parameters = request.getParameterMap(); HashMap<String, String> params = new HashMap<String, String>(); // expecting single params @@ -89,33 +99,12 @@ public class LoginForm extends CustomComponent { } LoginEvent event = new LoginEvent(params); fireEvent(event); + return true; } + return false; } }; - private URIHandler uriHandler = new URIHandler() { - private final String responce = "<html><body>Login form handeled." - + "<script type='text/javascript'>top.vaadin.forceSync();" - + "</script></body></html>"; - - public DownloadStream handleURI(URL context, String relativeUri) { - if (relativeUri != null && relativeUri.contains("loginHandler")) { - if (window != null) { - window.removeURIHandler(this); - } - DownloadStream downloadStream = new DownloadStream( - new ByteArrayInputStream(responce.getBytes()), - "text/html", "loginSuccesfull"); - downloadStream.setCacheTime(-1); - return downloadStream; - } else { - return null; - } - } - }; - - private Window window; - public LoginForm() { iframe.setType(Embedded.TYPE_BROWSER); iframe.setSizeFull(); @@ -132,8 +121,7 @@ public class LoginForm extends CustomComponent { * @return byte array containing login page html */ protected byte[] getLoginHTML() { - String appUri = getApplication().getURL().toString() - + getWindow().getName() + "/"; + String appUri = getApplication().getURL().toString(); try { return ("<!DOCTYPE html PUBLIC \"-//W3C//DTD " @@ -170,11 +158,11 @@ public class LoginForm extends CustomComponent { + "<div>" + usernameCaption + "</div><div >" - + "<input class='v-textfield' style='display:block;' type='text' name='username'></div>" + + "<input class='v-textfield v-connector' style='display:block;' type='text' name='username'></div>" + "<div>" + passwordCaption + "</div>" - + "<div><input class='v-textfield' style='display:block;' type='password' name='password'></div>" + + "<div><input class='v-textfield v-connector' style='display:block;' type='password' name='password'></div>" + "<div><div onclick=\"document.forms[0].submit();\" tabindex=\"0\" class=\"v-button\" role=\"button\" ><span class=\"v-button-wrap\"><span class=\"v-button-caption\">" + loginButtonCaption + "</span></span></div></div></form></div>" + "</body></html>") @@ -188,21 +176,15 @@ public class LoginForm extends CustomComponent { public void attach() { super.attach(); getApplication().addResource(loginPage); - getWindow().addParameterHandler(paramHandler); + getApplication().addRequestHandler(requestHandler); iframe.setSource(loginPage); } @Override public void detach() { getApplication().removeResource(loginPage); - getWindow().removeParameterHandler(paramHandler); - // store window temporary to properly remove uri handler once - // response is handled. (May happen if login handler removes login - // form - window = getWindow(); - if (window.getParent() != null) { - window = window.getParent(); - } + getApplication().removeRequestHandler(requestHandler); + super.detach(); } @@ -281,7 +263,7 @@ public class LoginForm extends CustomComponent { } @Override - public void setWidth(float width, int unit) { + public void setWidth(float width, Unit unit) { super.setWidth(width, unit); if (iframe != null) { if (width < 0) { @@ -293,7 +275,7 @@ public class LoginForm extends CustomComponent { } @Override - public void setHeight(float height, int unit) { + public void setHeight(float height, Unit unit) { super.setHeight(height, unit); if (iframe != null) { if (height < 0) { diff --git a/src/com/vaadin/ui/MenuBar.java b/src/com/vaadin/ui/MenuBar.java index 3469f77ebb..f94bd7ea64 100644 --- a/src/com/vaadin/ui/MenuBar.java +++ b/src/com/vaadin/ui/MenuBar.java @@ -13,8 +13,8 @@ import java.util.Stack; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VMenuBar; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.menubar.VMenuBar; /** * <p> @@ -24,8 +24,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * </p> */ @SuppressWarnings("serial") -@ClientWidget(value = VMenuBar.class, loadStyle = LoadStyle.LAZY) -public class MenuBar extends AbstractComponent { +public class MenuBar extends AbstractComponent implements Vaadin6Component { // Items of the top-level menu private final List<MenuItem> menuItems; @@ -33,20 +32,6 @@ public class MenuBar extends AbstractComponent { // Number of items in this menu private int numberOfItems = 0; - /** - * @deprecated - * @see #setCollapse(boolean) - */ - @Deprecated - private boolean collapseItems; - - /** - * @deprecated - * @see #setSubmenuIcon(Resource) - */ - @Deprecated - private Resource submenuIcon; - private MenuItem moreItem; private boolean openRootOnHover; @@ -54,12 +39,7 @@ public class MenuBar extends AbstractComponent { private boolean htmlContentAllowed; /** Paint (serialise) the component for the client. */ - @Override public void paintContent(PaintTarget target) throws PaintException { - - // Superclass writes any common attributes in the paint target. - super.paintContent(target); - target.addAttribute(VMenuBar.OPEN_ROOT_MENU_ON_HOWER, openRootOnHover); if (isHtmlContentAllowed()) { @@ -68,10 +48,6 @@ public class MenuBar extends AbstractComponent { target.startTag("options"); - if (submenuIcon != null) { - target.addAttribute("submenuIcon", submenuIcon); - } - if (getWidth() > -1) { target.startTag("moreItem"); target.addAttribute("text", moreItem.getText()); @@ -103,7 +79,8 @@ public class MenuBar extends AbstractComponent { target.addAttribute("id", item.getId()); if (item.getStyleName() != null) { - target.addAttribute("style", item.getStyleName()); + target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_STYLE, + item.getStyleName()); } if (item.isSeparator()) { @@ -118,16 +95,17 @@ public class MenuBar extends AbstractComponent { Resource icon = item.getIcon(); if (icon != null) { - target.addAttribute("icon", icon); + target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_ICON, icon); } if (!item.isEnabled()) { - target.addAttribute("disabled", true); + target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_DISABLED, true); } String description = item.getDescription(); if (description != null && description.length() > 0) { - target.addAttribute("description", description); + target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_DESCRIPTION, + description); } if (item.isCheckable()) { // if the "checked" attribute is present (either true or false), @@ -147,7 +125,6 @@ public class MenuBar extends AbstractComponent { } /** Deserialize changes received from client. */ - @Override public void changeVariables(Object source, Map<String, Object> variables) { Stack<MenuItem> items = new Stack<MenuItem>(); boolean found = false; @@ -193,7 +170,6 @@ public class MenuBar extends AbstractComponent { */ public MenuBar() { menuItems = new ArrayList<MenuItem>(); - setCollapse(true); setMoreMenuItem(null); } @@ -311,54 +287,6 @@ public class MenuBar extends AbstractComponent { } /** - * Set the icon to be used if a sub-menu has children. Defaults to null; - * - * @param icon - * @deprecated (since 6.2, will be removed in 7.0) Icon is set in theme, no - * need to worry about the visual representation here. - */ - @Deprecated - public void setSubmenuIcon(Resource icon) { - submenuIcon = icon; - requestRepaint(); - } - - /** - * @deprecated - * @see #setSubmenuIcon(Resource) - */ - @Deprecated - public Resource getSubmenuIcon() { - return submenuIcon; - } - - /** - * Enable or disable collapsing top-level items. Top-level items will - * collapse together if there is not enough room for them. Items that don't - * fit will be placed under the "More" menu item. - * - * Collapsing is enabled by default. - * - * @param collapse - * @deprecated (since 6.2, will be removed in 7.0) Collapsing is always - * enabled if the MenuBar has a specified width. - */ - @Deprecated - public void setCollapse(boolean collapse) { - collapseItems = collapse; - requestRepaint(); - } - - /** - * @see #setCollapse(boolean) - * @deprecated - */ - @Deprecated - public boolean getCollapse() { - return collapseItems; - } - - /** * Set the item that is used when collapsing the top level menu. All * "overflowing" items will be added below this. The item command will be * ignored. If set to null, the default item with a downwards arrow is used. @@ -798,8 +726,7 @@ public class MenuBar extends AbstractComponent { /** * Sets the items's description. See {@link #getDescription()} for more * information on what the description is. This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent}. + * {@link RepaintRequestEvent}. * * @param description * the new description string for the component. diff --git a/src/com/vaadin/ui/NativeButton.java b/src/com/vaadin/ui/NativeButton.java index 369b40b93a..6eb4379261 100644 --- a/src/com/vaadin/ui/NativeButton.java +++ b/src/com/vaadin/ui/NativeButton.java @@ -3,11 +3,7 @@ */ package com.vaadin.ui; -import com.vaadin.data.Property; -import com.vaadin.terminal.gwt.client.ui.VNativeButton; - @SuppressWarnings("serial") -@ClientWidget(VNativeButton.class) public class NativeButton extends Button { public NativeButton() { @@ -22,34 +18,4 @@ public class NativeButton extends Button { super(caption, listener); } - public NativeButton(String caption, Object target, String methodName) { - super(caption, target, methodName); - } - - /** - * Creates a new switch button with initial value. - * - * @param state - * the Initial state of the switch-button. - * @param initialState - * @deprecated use the {@link CheckBox} component instead - */ - @Deprecated - public NativeButton(String caption, boolean initialState) { - super(caption, initialState); - } - - /** - * Creates a new switch button that is connected to a boolean property. - * - * @param state - * the Initial state of the switch-button. - * @param dataSource - * @deprecated use the {@link CheckBox} component instead - */ - @Deprecated - public NativeButton(String caption, Property dataSource) { - super(caption, dataSource); - } - -}
\ No newline at end of file +} diff --git a/src/com/vaadin/ui/NativeSelect.java b/src/com/vaadin/ui/NativeSelect.java index e701d212b4..1f85f57c97 100644 --- a/src/com/vaadin/ui/NativeSelect.java +++ b/src/com/vaadin/ui/NativeSelect.java @@ -9,7 +9,6 @@ import java.util.Collection; import com.vaadin.data.Container; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VNativeSelect; /** * This is a simple drop-down select without, for instance, support for @@ -18,7 +17,6 @@ import com.vaadin.terminal.gwt.client.ui.VNativeSelect; * better choice. */ @SuppressWarnings("serial") -@ClientWidget(VNativeSelect.class) public class NativeSelect extends AbstractSelect { // width in characters, mimics TextField diff --git a/src/com/vaadin/ui/Notification.java b/src/com/vaadin/ui/Notification.java new file mode 100644 index 0000000000..bb1f874635 --- /dev/null +++ b/src/com/vaadin/ui/Notification.java @@ -0,0 +1,321 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.ui; + +import java.io.Serializable; + +import com.vaadin.terminal.Resource; + +/** + * A notification message, used to display temporary messages to the user - for + * example "Document saved", or "Save failed". + * <p> + * The notification message can consist of several parts: caption, description + * and icon. It is usually used with only caption - one should be wary of + * filling the notification with too much information. + * </p> + * <p> + * The notification message tries to be as unobtrusive as possible, while still + * drawing needed attention. There are several basic types of messages that can + * be used in different situations: + * <ul> + * <li>TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses the + * mouse or types something. It can be used to show fairly unimportant messages, + * such as feedback that an operation succeeded ("Document Saved") - the kind of + * messages the user ignores once the application is familiar.</li> + * <li>TYPE_WARNING_MESSAGE is shown for a short while after the user uses the + * mouse or types something. It's default style is also more noticeable than the + * humanized message. It can be used for messages that do not contain a lot of + * important information, but should be noticed by the user. Despite the name, + * it does not have to be a warning, but can be used instead of the humanized + * message whenever you want to make the message a little more noticeable.</li> + * <li>TYPE_ERROR_MESSAGE requires to user to click it before disappearing, and + * can be used for critical messages.</li> + * <li>TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner of + * the window, and can be used for "convenience notifications" that do not have + * to be noticed immediately, and should not interfere with the current task - + * for instance to show "You have a new message in your inbox" while the user is + * working in some other area of the application.</li> + * </ul> + * </p> + * <p> + * In addition to the basic pre-configured types, a Notification can also be + * configured to show up in a custom position, for a specified time (or until + * clicked), and with a custom stylename. An icon can also be added. + * </p> + * + */ +public class Notification implements Serializable { + public static final int TYPE_HUMANIZED_MESSAGE = 1; + public static final int TYPE_WARNING_MESSAGE = 2; + public static final int TYPE_ERROR_MESSAGE = 3; + public static final int TYPE_TRAY_NOTIFICATION = 4; + + public static final int POSITION_CENTERED = 1; + public static final int POSITION_CENTERED_TOP = 2; + public static final int POSITION_CENTERED_BOTTOM = 3; + public static final int POSITION_TOP_LEFT = 4; + public static final int POSITION_TOP_RIGHT = 5; + public static final int POSITION_BOTTOM_LEFT = 6; + public static final int POSITION_BOTTOM_RIGHT = 7; + + public static final int DELAY_FOREVER = -1; + public static final int DELAY_NONE = 0; + + private String caption; + private String description; + private Resource icon; + private int position = POSITION_CENTERED; + private int delayMsec = 0; + private String styleName; + private boolean htmlContentAllowed; + + /** + * Creates a "humanized" notification message. + * + * Care should be taken to to avoid XSS vulnerabilities as the caption is by + * default rendered as html. + * + * @param caption + * The message to show + */ + public Notification(String caption) { + this(caption, null, TYPE_HUMANIZED_MESSAGE); + } + + /** + * Creates a notification message of the specified type. + * + * Care should be taken to to avoid XSS vulnerabilities as the caption is by + * default rendered as html. + * + * @param caption + * The message to show + * @param type + * The type of message + */ + public Notification(String caption, int type) { + this(caption, null, type); + } + + /** + * Creates a "humanized" notification message with a bigger caption and + * smaller description. + * + * Care should be taken to to avoid XSS vulnerabilities as the caption and + * description are by default rendered as html. + * + * @param caption + * The message caption + * @param description + * The message description + */ + public Notification(String caption, String description) { + this(caption, description, TYPE_HUMANIZED_MESSAGE); + } + + /** + * Creates a notification message of the specified type, with a bigger + * caption and smaller description. + * + * Care should be taken to to avoid XSS vulnerabilities as the caption and + * description are by default rendered as html. + * + * @param caption + * The message caption + * @param description + * The message description + * @param type + * The type of message + */ + public Notification(String caption, String description, int type) { + this(caption, description, type, true); + } + + /** + * Creates a notification message of the specified type, with a bigger + * caption and smaller description. + * + * Care should be taken to to avoid XSS vulnerabilities if html is allowed. + * + * @param caption + * The message caption + * @param description + * The message description + * @param type + * The type of message + * @param htmlContentAllowed + * Whether html in the caption and description should be + * displayed as html or as plain text + */ + public Notification(String caption, String description, int type, + boolean htmlContentAllowed) { + this.caption = caption; + this.description = description; + this.htmlContentAllowed = htmlContentAllowed; + setType(type); + } + + private void setType(int type) { + switch (type) { + case TYPE_WARNING_MESSAGE: + delayMsec = 1500; + styleName = "warning"; + break; + case TYPE_ERROR_MESSAGE: + delayMsec = -1; + styleName = "error"; + break; + case TYPE_TRAY_NOTIFICATION: + delayMsec = 3000; + position = POSITION_BOTTOM_RIGHT; + styleName = "tray"; + + case TYPE_HUMANIZED_MESSAGE: + default: + break; + } + + } + + /** + * Gets the caption part of the notification message. + * + * @return The message caption + */ + public String getCaption() { + return caption; + } + + /** + * Sets the caption part of the notification message + * + * @param caption + * The message caption + */ + public void setCaption(String caption) { + this.caption = caption; + } + + /** + * Gets the description part of the notification message. + * + * @return The message description. + */ + public String getDescription() { + return description; + } + + /** + * Sets the description part of the notification message. + * + * @param description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the position of the notification message. + * + * @return The position + */ + public int getPosition() { + return position; + } + + /** + * Sets the position of the notification message. + * + * @param position + * The desired notification position + */ + public void setPosition(int position) { + this.position = position; + } + + /** + * Gets the icon part of the notification message. + * + * @return The message icon + */ + public Resource getIcon() { + return icon; + } + + /** + * Sets the icon part of the notification message. + * + * @param icon + * The desired message icon + */ + public void setIcon(Resource icon) { + this.icon = icon; + } + + /** + * Gets the delay before the notification disappears. + * + * @return the delay in msec, -1 indicates the message has to be clicked. + */ + public int getDelayMsec() { + return delayMsec; + } + + /** + * Sets the delay before the notification disappears. + * + * @param delayMsec + * the desired delay in msec, -1 to require the user to click the + * message + */ + public void setDelayMsec(int delayMsec) { + this.delayMsec = delayMsec; + } + + /** + * Sets the style name for the notification message. + * + * @param styleName + * The desired style name. + */ + public void setStyleName(String styleName) { + this.styleName = styleName; + } + + /** + * Gets the style name for the notification message. + * + * @return + */ + public String getStyleName() { + return styleName; + } + + /** + * Sets whether html is allowed in the caption and description. If set to + * true, the texts are passed to the browser as html and the developer is + * responsible for ensuring no harmful html is used. If set to false, the + * texts are passed to the browser as plain text. + * + * @param htmlContentAllowed + * true if the texts are used as html, false if used as plain + * text + */ + public void setHtmlContentAllowed(boolean htmlContentAllowed) { + this.htmlContentAllowed = htmlContentAllowed; + } + + /** + * Checks whether caption and description are interpreted as html or plain + * text. + * + * @return true if the texts are used as html, false if used as plain text + * @see #setHtmlContentAllowed(boolean) + */ + public boolean isHtmlContentAllowed() { + return htmlContentAllowed; + } +}
\ No newline at end of file diff --git a/src/com/vaadin/ui/OptionGroup.java b/src/com/vaadin/ui/OptionGroup.java index 884e58824a..a4aaf7ec99 100644 --- a/src/com/vaadin/ui/OptionGroup.java +++ b/src/com/vaadin/ui/OptionGroup.java @@ -17,13 +17,12 @@ import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VOptionGroup; +import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroup; /** * Configures select to be used as an option group. */ @SuppressWarnings("serial") -@ClientWidget(VOptionGroup.class) public class OptionGroup extends AbstractSelect implements FieldEvents.BlurNotifier, FieldEvents.FocusNotifier { @@ -60,7 +59,7 @@ public class OptionGroup extends AbstractSelect implements throws PaintException { super.paintItem(target, itemId); if (!isItemEnabled(itemId)) { - target.addAttribute("disabled", true); + target.addAttribute(VOptionGroup.ATTRIBUTE_OPTION_DISABLED, true); } } diff --git a/src/com/vaadin/ui/OrderedLayout.java b/src/com/vaadin/ui/OrderedLayout.java deleted file mode 100644 index 474fc89867..0000000000 --- a/src/com/vaadin/ui/OrderedLayout.java +++ /dev/null @@ -1,128 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VOrderedLayout; -import com.vaadin.ui.ClientWidget.LoadStyle; - -/** - * Ordered layout. - * - * <code>OrderedLayout</code> is a component container, which shows the - * subcomponents in the order of their addition in specified orientation. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - * @deprecated Replaced by VerticalLayout/HorizontalLayout. For type checking - * please not that VerticalLayout/HorizontalLayout do not extend - * OrderedLayout but AbstractOrderedLayout (which also OrderedLayout - * extends). - */ -@SuppressWarnings("serial") -@Deprecated -@ClientWidget(value = VOrderedLayout.class, loadStyle = LoadStyle.EAGER) -public class OrderedLayout extends AbstractOrderedLayout { - /* Predefined orientations */ - - /** - * Components are to be laid out vertically. - */ - public static final int ORIENTATION_VERTICAL = 0; - - /** - * Components are to be laid out horizontally. - */ - public static final int ORIENTATION_HORIZONTAL = 1; - - /** - * Orientation of the layout. - */ - private int orientation; - - /** - * Creates a new ordered layout. The order of the layout is - * <code>ORIENTATION_VERTICAL</code>. - * - * @deprecated Use VerticalLayout instead. - */ - @Deprecated - public OrderedLayout() { - this(ORIENTATION_VERTICAL); - } - - /** - * Create a new ordered layout. The orientation of the layout is given as - * parameters. - * - * @param orientation - * the Orientation of the layout. - * - * @deprecated Use VerticalLayout/HorizontalLayout instead. - */ - @Deprecated - public OrderedLayout(int orientation) { - this.orientation = orientation; - if (orientation == ORIENTATION_VERTICAL) { - setWidth(100, UNITS_PERCENTAGE); - } - } - - /** - * Gets the orientation of the container. - * - * @return the Value of property orientation. - */ - public int getOrientation() { - return orientation; - } - - /** - * Sets the orientation of this OrderedLayout. This method should only be - * used before initial paint. - * - * @param orientation - * the New value of property orientation. - * @deprecated Use VerticalLayout/HorizontalLayout or define orientation in - * constructor instead - */ - @Deprecated - public void setOrientation(int orientation) { - setOrientation(orientation, true); - } - - /** - * Internal method to change orientation of layout. This method should only - * be used before initial paint. - * - * @param orientation - */ - protected void setOrientation(int orientation, boolean needsRepaint) { - // Checks the validity of the argument - if (orientation < ORIENTATION_VERTICAL - || orientation > ORIENTATION_HORIZONTAL) { - throw new IllegalArgumentException(); - } - - this.orientation = orientation; - if (needsRepaint) { - requestRepaint(); - } - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - // Adds the orientation attributes (the default is vertical) - if (orientation == ORIENTATION_HORIZONTAL) { - target.addAttribute("orientation", "horizontal"); - } - - } - -} diff --git a/src/com/vaadin/ui/Panel.java b/src/com/vaadin/ui/Panel.java index a69413c28b..b2916f78c7 100644 --- a/src/com/vaadin/ui/Panel.java +++ b/src/com/vaadin/ui/Panel.java @@ -15,11 +15,12 @@ import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Scrollable; +import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VPanel; +import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; +import com.vaadin.terminal.gwt.client.ui.panel.PanelServerRpc; +import com.vaadin.terminal.gwt.client.ui.panel.PanelState; import com.vaadin.ui.Component.Focusable; -import com.vaadin.ui.themes.Reindeer; -import com.vaadin.ui.themes.Runo; /** * Panel - a simple single component container. @@ -30,24 +31,10 @@ import com.vaadin.ui.themes.Runo; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VPanel.class) public class Panel extends AbstractComponentContainer implements Scrollable, ComponentContainer.ComponentAttachListener, - ComponentContainer.ComponentDetachListener, Action.Notifier, Focusable { - - private static final String CLICK_EVENT = VPanel.CLICK_EVENT_IDENTIFIER; - - /** - * Removes extra decorations from the Panel. - * - * @deprecated this style is no longer part of the core framework and this - * component, even though most built-in themes implement this - * style. Use the constant specified in the theme class file - * that you're using, if it provides one, e.g. - * {@link Reindeer#PANEL_LIGHT} or {@link Runo#PANEL_LIGHT} . - */ - @Deprecated - public static final String STYLE_LIGHT = "light"; + ComponentContainer.ComponentDetachListener, Action.Notifier, Focusable, + Vaadin6Component { /** * Content of the panel. @@ -55,32 +42,16 @@ public class Panel extends AbstractComponentContainer implements Scrollable, private ComponentContainer content; /** - * Scroll X position. - */ - private int scrollOffsetX = 0; - - /** - * Scroll Y position. - */ - private int scrollOffsetY = 0; - - /** - * Scrolling mode. - */ - private boolean scrollable = false; - - /** * Keeps track of the Actions added to this component, and manages the * painting and handling as well. */ protected ActionManager actionManager; - /** - * By default the Panel is not in the normal document focus flow and can - * only be focused by using the focus()-method. Change this to 0 if you want - * to have the Panel in the normal focus flow. - */ - private int tabIndex = -1; + private PanelServerRpc rpc = new PanelServerRpc() { + public void click(MouseEventDetails mouseDetails) { + fireEvent(new ClickEvent(Panel.this, mouseDetails)); + } + }; /** * Creates a new empty panel. A VerticalLayout is used as content. @@ -97,8 +68,10 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * the content for the panel. */ public Panel(ComponentContainer content) { + registerRpc(rpc); setContent(content); - setWidth(100, UNITS_PERCENTAGE); + setWidth(100, Unit.PERCENTAGE); + getState().setTabIndex(-1); } /** @@ -139,45 +112,6 @@ public class Panel extends AbstractComponentContainer implements Scrollable, } /** - * Gets the current layout of the panel. - * - * @return the Current layout of the panel. - * @deprecated A Panel can now contain a ComponentContainer which is not - * necessarily a Layout. Use {@link #getContent()} instead. - */ - @Deprecated - public Layout getLayout() { - if (content instanceof Layout) { - return (Layout) content; - } else if (content == null) { - return null; - } - - throw new IllegalStateException( - "Panel does not contain a Layout. Use getContent() instead of getLayout()."); - } - - /** - * Sets the layout of the panel. - * - * If given layout is null, a VerticalLayout with margins set is used as a - * default. - * - * Components from old layout are not moved to new layout by default - * (changed in 5.2.2). Use function in Layout interface manually. - * - * @param newLayout - * the New layout of the panel. - * @deprecated A Panel can now contain a ComponentContainer which is not - * necessarily a Layout. Use - * {@link #setContent(ComponentContainer)} instead. - */ - @Deprecated - public void setLayout(Layout newLayout) { - setContent(newLayout); - } - - /** * Returns the content of the Panel. * * @return @@ -249,20 +183,10 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * (non-Javadoc) * * @see - * com.vaadin.ui.AbstractComponent#paintContent(com.vaadin.terminal.PaintTarget - * ) + * com.vaadin.terminal.Vaadin6Component#paintContent(com.vaadin.terminal + * .PaintTarget) */ - @Override public void paintContent(PaintTarget target) throws PaintException { - content.paint(target); - - target.addVariable(this, "tabindex", getTabIndex()); - - if (isScrollable()) { - target.addVariable(this, "scrollLeft", getScrollLeft()); - target.addVariable(this, "scrollTop", getScrollTop()); - } - if (actionManager != null) { actionManager.paintActions(null, target); } @@ -323,14 +247,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * @see com.vaadin.terminal.VariableOwner#changeVariables(Object, Map) */ @SuppressWarnings("unchecked") - @Override public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - - if (variables.containsKey(CLICK_EVENT)) { - fireClick((Map<String, Object>) variables.get(CLICK_EVENT)); - } - // Get new size final Integer newWidth = (Integer) variables.get("width"); final Integer newHeight = (Integer) variables.get("height"); @@ -346,11 +263,11 @@ public class Panel extends AbstractComponentContainer implements Scrollable, final Integer newScrollY = (Integer) variables.get("scrollTop"); if (newScrollX != null && newScrollX.intValue() != getScrollLeft()) { // set internally, not to fire request repaint - scrollOffsetX = newScrollX.intValue(); + getState().setScrollLeft(newScrollX.intValue()); } if (newScrollY != null && newScrollY.intValue() != getScrollTop()) { // set internally, not to fire request repaint - scrollOffsetY = newScrollY.intValue(); + getState().setScrollTop(newScrollY.intValue()); } // Actions @@ -368,15 +285,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * @see com.vaadin.terminal.Scrollable#setScrollable(boolean) */ public int getScrollLeft() { - return scrollOffsetX; - } - - /** - * @deprecated use {@link #getScrollLeft()} instead - */ - @Deprecated - public int getScrollOffsetX() { - return getScrollLeft(); + return getState().getScrollLeft(); } /* @@ -385,110 +294,35 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * @see com.vaadin.terminal.Scrollable#setScrollable(boolean) */ public int getScrollTop() { - return scrollOffsetY; - } - - /** - * @deprecated use {@link #getScrollTop()} instead - */ - @Deprecated - public int getScrollOffsetY() { - return getScrollTop(); + return getState().getScrollTop(); } /* * (non-Javadoc) * - * @see com.vaadin.terminal.Scrollable#setScrollable(boolean) - */ - public boolean isScrollable() { - return scrollable; - } - - /** - * Sets the panel as programmatically scrollable. - * - * <p> - * Panel is by default not scrollable programmatically with - * {@link #setScrollLeft(int)} and {@link #setScrollTop(int)}, so if you use - * those methods, you need to enable scrolling with this method. Components - * that extend Panel may have a different default for the programmatic - * scrollability. - * </p> - * - * @see com.vaadin.terminal.Scrollable#setScrollable(boolean) - */ - public void setScrollable(boolean isScrollingEnabled) { - if (scrollable != isScrollingEnabled) { - scrollable = isScrollingEnabled; - requestRepaint(); - } - } - - /** - * Sets the horizontal scroll position. - * - * <p> - * Setting the horizontal scroll position with this method requires that - * programmatic scrolling of the component has been enabled. For Panel it is - * disabled by default, so you have to call {@link #setScrollable(boolean)}. - * Components extending Panel may have a different default for programmatic - * scrollability. - * </p> - * * @see com.vaadin.terminal.Scrollable#setScrollLeft(int) - * @see #setScrollable(boolean) */ - public void setScrollLeft(int pixelsScrolled) { - if (pixelsScrolled < 0) { + public void setScrollLeft(int scrollLeft) { + if (scrollLeft < 0) { throw new IllegalArgumentException( "Scroll offset must be at least 0"); } - if (scrollOffsetX != pixelsScrolled) { - scrollOffsetX = pixelsScrolled; - requestRepaint(); - } - } - - /** - * @deprecated use setScrollLeft() method instead - */ - @Deprecated - public void setScrollOffsetX(int pixels) { - setScrollLeft(pixels); + getState().setScrollLeft(scrollLeft); + requestRepaint(); } - /** - * Sets the vertical scroll position. - * - * <p> - * Setting the vertical scroll position with this method requires that - * programmatic scrolling of the component has been enabled. For Panel it is - * disabled by default, so you have to call {@link #setScrollable(boolean)}. - * Components extending Panel may have a different default for programmatic - * scrollability. - * </p> + /* + * (non-Javadoc) * * @see com.vaadin.terminal.Scrollable#setScrollTop(int) - * @see #setScrollable(boolean) */ - public void setScrollTop(int pixelsScrolledDown) { - if (pixelsScrolledDown < 0) { + public void setScrollTop(int scrollTop) { + if (scrollTop < 0) { throw new IllegalArgumentException( "Scroll offset must be at least 0"); } - if (scrollOffsetY != pixelsScrolledDown) { - scrollOffsetY = pixelsScrolledDown; - requestRepaint(); - } - } - - /** - * @deprecated use setScrollTop() method instead - */ - @Deprecated - public void setScrollOffsetY(int pixels) { - setScrollTop(pixels); + getState().setScrollTop(scrollTop); + requestRepaint(); } /* Documented in superclass */ @@ -526,6 +360,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable, */ @Override public void attach() { + getRoot().componentAttached(this); // can't call parent here as this is Panels hierarchy is a hack requestRepaint(); if (content != null) { @@ -544,6 +379,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable, if (content != null) { content.detach(); } + getRoot().componentDetached(this); } /** @@ -559,6 +395,7 @@ public class Panel extends AbstractComponentContainer implements Scrollable, /* * ACTIONS */ + @Override protected ActionManager getActionManager() { if (actionManager == null) { actionManager = new ActionManager(this); @@ -609,8 +446,8 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * The listener to add */ public void addListener(ClickListener listener) { - addListener(CLICK_EVENT, ClickEvent.class, listener, - ClickListener.clickMethod); + addListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, ClickEvent.class, + listener, ClickListener.clickMethod); } /** @@ -621,33 +458,22 @@ public class Panel extends AbstractComponentContainer implements Scrollable, * The listener to remove */ public void removeListener(ClickListener listener) { - removeListener(CLICK_EVENT, ClickEvent.class, listener); - } - - /** - * Fire a click event to all click listeners. - * - * @param object - * The raw "value" of the variable change from the client side. - */ - private void fireClick(Map<String, Object> parameters) { - MouseEventDetails mouseDetails = MouseEventDetails - .deSerialize((String) parameters.get("mouseDetails")); - fireEvent(new ClickEvent(this, mouseDetails)); + removeListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, + ClickEvent.class, listener); } /** * {@inheritDoc} */ public int getTabIndex() { - return tabIndex; + return getState().getTabIndex(); } /** * {@inheritDoc} */ public void setTabIndex(int tabIndex) { - this.tabIndex = tabIndex; + getState().setTabIndex(tabIndex); requestRepaint(); } @@ -660,4 +486,19 @@ public class Panel extends AbstractComponentContainer implements Scrollable, super.focus(); } + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.ComponentContainer#getComponentCount() + */ + public int getComponentCount() { + // This is so wrong... (#2924) + return content.getComponentCount(); + } + + @Override + public PanelState getState() { + return (PanelState) super.getState(); + } + } diff --git a/src/com/vaadin/ui/PasswordField.java b/src/com/vaadin/ui/PasswordField.java index 99874147d5..c1fccebbfe 100644 --- a/src/com/vaadin/ui/PasswordField.java +++ b/src/com/vaadin/ui/PasswordField.java @@ -4,13 +4,11 @@ package com.vaadin.ui; import com.vaadin.data.Property; -import com.vaadin.terminal.gwt.client.ui.VPasswordField; /** * A field that is used to enter secret text information like passwords. The * entered text is not displayed on the screen. */ -@ClientWidget(VPasswordField.class) public class PasswordField extends AbstractTextField { /** diff --git a/src/com/vaadin/ui/PopupView.java b/src/com/vaadin/ui/PopupView.java index fcad727510..911d926053 100644 --- a/src/com/vaadin/ui/PopupView.java +++ b/src/com/vaadin/ui/PopupView.java @@ -8,9 +8,10 @@ import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; +import com.vaadin.terminal.LegacyPaint; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VPopupView; +import com.vaadin.terminal.Vaadin6Component; /** * @@ -22,8 +23,8 @@ import com.vaadin.terminal.gwt.client.ui.VPopupView; * @author Vaadin Ltd. */ @SuppressWarnings("serial") -@ClientWidget(VPopupView.class) -public class PopupView extends AbstractComponentContainer { +public class PopupView extends AbstractComponentContainer implements + Vaadin6Component { private Content content; private boolean hideOnMouseOut; @@ -306,11 +307,7 @@ public class PopupView extends AbstractComponentContainer { * * @see com.vaadin.ui.AbstractComponent#paintContent(com.vaadin.terminal.PaintTarget) */ - @Override public void paintContent(PaintTarget target) throws PaintException { - // Superclass writes any common attributes in the paint target. - super.paintContent(target); - String html = content.getMinimizedValueAsHTML(); if (html == null) { html = ""; @@ -321,7 +318,7 @@ public class PopupView extends AbstractComponentContainer { // Only paint component to client if we know that the popup is showing if (isPopupVisible()) { target.startTag("popupComponent"); - visibleComponent.paint(target); + LegacyPaint.paint(visibleComponent, target); target.endTag("popupComponent"); } @@ -334,7 +331,6 @@ public class PopupView extends AbstractComponentContainer { * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, * java.util.Map) */ - @Override public void changeVariables(Object source, Map<String, Object> variables) { if (variables.containsKey("popupVisibility")) { setPopupVisible(((Boolean) variables.get("popupVisibility")) diff --git a/src/com/vaadin/ui/ProgressIndicator.java b/src/com/vaadin/ui/ProgressIndicator.java index 405ff2b52f..4d585cfdd7 100644 --- a/src/com/vaadin/ui/ProgressIndicator.java +++ b/src/com/vaadin/ui/ProgressIndicator.java @@ -4,11 +4,13 @@ package com.vaadin.ui; +import java.util.Map; + import com.vaadin.data.Property; import com.vaadin.data.util.ObjectProperty; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VProgressIndicator; +import com.vaadin.terminal.Vaadin6Component; /** * <code>ProgressIndicator</code> is component that shows user state of a @@ -25,9 +27,8 @@ import com.vaadin.terminal.gwt.client.ui.VProgressIndicator; * @since 4 */ @SuppressWarnings("serial") -@ClientWidget(VProgressIndicator.class) -public class ProgressIndicator extends AbstractField implements Property, - Property.Viewer, Property.ValueChangeListener { +public class ProgressIndicator extends AbstractField<Number> implements + Property.Viewer, Property.ValueChangeListener, Vaadin6Component { /** * Content mode, where the label contains only plain text. The getValue() @@ -110,7 +111,6 @@ public class ProgressIndicator extends AbstractField implements Property, * @throws PaintException * if the Paint Operation fails. */ - @Override public void paintContent(PaintTarget target) throws PaintException { target.addAttribute("indeterminate", indeterminate); target.addAttribute("pollinginterval", pollingInterval); @@ -125,11 +125,12 @@ public class ProgressIndicator extends AbstractField implements Property, * @see com.vaadin.ui.AbstractField#getValue() */ @Override - public Object getValue() { + public Number getValue() { if (dataSource == null) { throw new IllegalStateException("Datasource must be set"); } - return dataSource.getValue(); + // TODO conversions to eliminate cast + return (Number) dataSource.getValue(); } /** @@ -138,7 +139,7 @@ public class ProgressIndicator extends AbstractField implements Property, * * @param newValue * the New value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object) + * @see com.vaadin.ui.AbstractField#setValue() */ @Override public void setValue(Object newValue) { @@ -149,21 +150,10 @@ public class ProgressIndicator extends AbstractField implements Property, } /** - * @see com.vaadin.ui.AbstractField#toString() - */ - @Override - public String toString() { - if (dataSource == null) { - throw new IllegalStateException("Datasource must be set"); - } - return dataSource.toString(); - } - - /** * @see com.vaadin.ui.AbstractField#getType() */ @Override - public Class<?> getType() { + public Class<? extends Number> getType() { if (dataSource == null) { throw new IllegalStateException("Datasource must be set"); } @@ -257,4 +247,9 @@ public class ProgressIndicator extends AbstractField implements Property, return pollingInterval; } + public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Remove once Vaadin6Component is no longer implemented + + } + } diff --git a/src/com/vaadin/ui/RichTextArea.java b/src/com/vaadin/ui/RichTextArea.java index f4d88edc78..16d4761b40 100644 --- a/src/com/vaadin/ui/RichTextArea.java +++ b/src/com/vaadin/ui/RichTextArea.java @@ -10,8 +10,7 @@ import java.util.Map; import com.vaadin.data.Property; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea; -import com.vaadin.ui.ClientWidget.LoadStyle; +import com.vaadin.terminal.Vaadin6Component; /** * A simple RichTextArea to edit HTML format text. @@ -20,8 +19,8 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * {@link RichTextArea} may produce unexpected results as formatting is counted * into length of field. */ -@ClientWidget(value = VRichTextArea.class, loadStyle = LoadStyle.LAZY) -public class RichTextArea extends AbstractField { +public class RichTextArea extends AbstractField<String> implements + Vaadin6Component { /** * Value formatter used to format the string contents. @@ -104,7 +103,6 @@ public class RichTextArea extends AbstractField { setCaption(caption); } - @Override public void paintContent(PaintTarget target) throws PaintException { if (selectAll) { target.addAttribute("selectAll", true); @@ -122,13 +120,13 @@ public class RichTextArea extends AbstractField { } target.addVariable(this, "text", value); - super.paintContent(target); } @Override public void setReadOnly(boolean readOnly) { super.setReadOnly(readOnly); // IE6 cannot support multi-classname selectors properly + // TODO Can be optimized now that support for I6 is dropped if (readOnly) { addStyleName("v-richtextarea-readonly"); } else { @@ -175,8 +173,8 @@ public class RichTextArea extends AbstractField { } @Override - public Object getValue() { - Object v = super.getValue(); + public String getValue() { + String v = super.getValue(); if (format == null || v == null) { return v; } @@ -187,11 +185,7 @@ public class RichTextArea extends AbstractField { } } - @Override public void changeVariables(Object source, Map<String, Object> variables) { - - super.changeVariables(source, variables); - // Sets the text if (variables.containsKey("text") && !isReadOnly()) { @@ -221,7 +215,7 @@ public class RichTextArea extends AbstractField { } @Override - public Class getType() { + public Class<String> getType() { return String.class; } @@ -342,7 +336,7 @@ public class RichTextArea extends AbstractField { @Override protected boolean isEmpty() { - return super.isEmpty() || toString().length() == 0; + return super.isEmpty() || getValue().length() == 0; } } diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java new file mode 100644 index 0000000000..405ae8da93 --- /dev/null +++ b/src/com/vaadin/ui/Root.java @@ -0,0 +1,1590 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.ui; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.vaadin.Application; +import com.vaadin.annotations.EagerInit; +import com.vaadin.event.Action; +import com.vaadin.event.Action.Handler; +import com.vaadin.event.ActionManager; +import com.vaadin.event.MouseEvents.ClickEvent; +import com.vaadin.event.MouseEvents.ClickListener; +import com.vaadin.terminal.PaintException; +import com.vaadin.terminal.PaintTarget; +import com.vaadin.terminal.Resource; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedRequest.BrowserDetails; +import com.vaadin.terminal.gwt.client.ComponentState; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.notification.VNotification; +import com.vaadin.terminal.gwt.client.ui.root.RootServerRpc; +import com.vaadin.terminal.gwt.client.ui.root.RootState; +import com.vaadin.terminal.gwt.client.ui.root.VRoot; +import com.vaadin.tools.ReflectTools; +import com.vaadin.ui.Window.CloseListener; + +/** + * The topmost component in any component hierarchy. There is one root for every + * Vaadin instance in a browser window. A root may either represent an entire + * browser window (or tab) or some part of a html page where a Vaadin + * application is embedded. + * <p> + * The root is the server side entry point for various client side features that + * are not represented as components added to a layout, e.g notifications, sub + * windows, and executing javascript in the browser. + * </p> + * <p> + * When a new application instance is needed, typically because the user opens + * the application in a browser window, + * {@link Application#gerRoot(WrappedRequest)} is invoked to get a root. That + * method does by default create a root according to the + * {@value Application#ROOT_PARAMETER} parameter from web.xml. + * </p> + * <p> + * After a root has been created by the application, it is initialized using + * {@link #init(WrappedRequest)}. This method is intended to be overridden by + * the developer to add components to the user interface and initialize + * non-component functionality. The component hierarchy is initialized by + * passing a {@link ComponentContainer} with the main layout of the view to + * {@link #setContent(ComponentContainer)}. + * </p> + * <p> + * If a {@link EagerInit} annotation is present on a class extending + * <code>Root</code>, the framework will use a faster initialization method + * which will not ensure that {@link BrowserDetails} are present in the + * {@link WrappedRequest} passed to the init method. + * </p> + * + * @see #init(WrappedRequest) + * @see Application#getRoot(WrappedRequest) + * + * @since 7.0 + */ +public abstract class Root extends AbstractComponentContainer implements + Action.Container, Action.Notifier, Vaadin6Component { + + /** + * Listener that gets notified when the size of the browser window + * containing the root has changed. + * + * @see Root#addListener(BrowserWindowResizeListener) + */ + public interface BrowserWindowResizeListener extends Serializable { + /** + * Invoked when the browser window containing a Root has been resized. + * + * @param event + * a browser window resize event + */ + public void browserWindowResized(BrowserWindowResizeEvent event); + } + + /** + * Event that is fired when a browser window containing a root is resized. + */ + public class BrowserWindowResizeEvent extends Component.Event { + + private final int width; + private final int height; + + /** + * Creates a new event + * + * @param source + * the root for which the browser window has been resized + * @param width + * the new width of the browser window + * @param height + * the new height of the browser window + */ + public BrowserWindowResizeEvent(Root source, int width, int height) { + super(source); + this.width = width; + this.height = height; + } + + @Override + public Root getSource() { + return (Root) super.getSource(); + } + + /** + * Gets the new browser window height + * + * @return an integer with the new pixel height of the browser window + */ + public int getHeight() { + return height; + } + + /** + * Gets the new browser window width + * + * @return an integer with the new pixel width of the browser window + */ + public int getWidth() { + return width; + } + } + + private static final Method BROWSWER_RESIZE_METHOD = ReflectTools + .findMethod(BrowserWindowResizeListener.class, + "browserWindowResized", BrowserWindowResizeEvent.class); + + /** + * Listener that listens changes in URI fragment. + */ + public interface FragmentChangedListener extends Serializable { + public void fragmentChanged(FragmentChangedEvent event); + } + + /** + * Event fired when uri fragment changes. + */ + public class FragmentChangedEvent extends Component.Event { + + /** + * The new uri fragment + */ + private final String fragment; + + /** + * Creates a new instance of UriFragmentReader change event. + * + * @param source + * the Source of the event. + */ + public FragmentChangedEvent(Root source, String fragment) { + super(source); + this.fragment = fragment; + } + + /** + * Gets the root in which the fragment has changed. + * + * @return the root in which the fragment has changed + */ + public Root getRoot() { + return (Root) getComponent(); + } + + /** + * Get the new fragment + * + * @return the new fragment + */ + public String getFragment() { + return fragment; + } + } + + /** + * Helper class to emulate the main window from Vaadin 6 using roots. This + * class should be used in the same way as Window used as a browser level + * window in Vaadin 6 with {@link com.vaadin.Application.LegacyApplication} + */ + @Deprecated + @EagerInit + public static class LegacyWindow extends Root { + private String name; + + /** + * Create a new legacy window + */ + public LegacyWindow() { + super(); + } + + /** + * Creates a new legacy window with the given caption + * + * @param caption + * the caption of the window + */ + public LegacyWindow(String caption) { + super(caption); + } + + /** + * Creates a legacy window with the given caption and content layout + * + * @param caption + * @param content + */ + public LegacyWindow(String caption, ComponentContainer content) { + super(caption, content); + } + + @Override + protected void init(WrappedRequest request) { + // Just empty + } + + /** + * Gets the unique name of the window. The name of the window is used to + * uniquely identify it. + * <p> + * The name also determines the URL that can be used for direct access + * to a window. All windows can be accessed through + * {@code http://host:port/app/win} where {@code http://host:port/app} + * is the application URL (as returned by {@link Application#getURL()} + * and {@code win} is the window name. + * </p> + * <p> + * Note! Portlets do not support direct window access through URLs. + * </p> + * + * @return the Name of the Window. + */ + public String getName() { + return name; + } + + /** + * Sets the unique name of the window. The name of the window is used to + * uniquely identify it inside the application. + * <p> + * The name also determines the URL that can be used for direct access + * to a window. All windows can be accessed through + * {@code http://host:port/app/win} where {@code http://host:port/app} + * is the application URL (as returned by {@link Application#getURL()} + * and {@code win} is the window name. + * </p> + * <p> + * This method can only be called before the window is added to an + * application. + * <p> + * Note! Portlets do not support direct window access through URLs. + * </p> + * + * @param name + * the new name for the window or null if the application + * should automatically assign a name to it + * @throws IllegalStateException + * if the window is attached to an application + */ + public void setName(String name) { + this.name = name; + // The name can not be changed in application + if (getApplication() != null) { + throw new IllegalStateException( + "Window name can not be changed while " + + "the window is in application"); + } + + } + + /** + * Gets the full URL of the window. The returned URL is window specific + * and can be used to directly refer to the window. + * <p> + * Note! This method can not be used for portlets. + * </p> + * + * @return the URL of the window or null if the window is not attached + * to an application + */ + public URL getURL() { + Application application = getApplication(); + if (application == null) { + return null; + } + + try { + return new URL(application.getURL(), getName() + "/"); + } catch (MalformedURLException e) { + throw new RuntimeException( + "Internal problem getting window URL, please report"); + } + } + } + + private static final Method FRAGMENT_CHANGED_METHOD; + + static { + try { + FRAGMENT_CHANGED_METHOD = FragmentChangedListener.class + .getDeclaredMethod("fragmentChanged", + new Class[] { FragmentChangedEvent.class }); + } catch (final java.lang.NoSuchMethodException e) { + // This should never happen + throw new java.lang.RuntimeException( + "Internal error finding methods in FragmentChangedListener"); + } + } + + /** + * A border style used for opening resources in a window without a border. + */ + public static final int BORDER_NONE = 0; + + /** + * A border style used for opening resources in a window with a minimal + * border. + */ + public static final int BORDER_MINIMAL = 1; + + /** + * A border style that indicates that the default border style should be + * used when opening resources. + */ + public static final int BORDER_DEFAULT = 2; + + /** + * The application to which this root belongs + */ + private Application application; + + /** + * A list of notifications that are waiting to be sent to the client. + * Cleared (set to null) when the notifications have been sent. + */ + private List<Notification> notifications; + + /** + * A list of javascript commands that are waiting to be sent to the client. + * Cleared (set to null) when the commands have been sent. + */ + private List<String> jsExecQueue = null; + + /** + * List of windows in this root. + */ + private final LinkedHashSet<Window> windows = new LinkedHashSet<Window>(); + + /** + * Resources to be opened automatically on next repaint. The list is + * automatically cleared when it has been sent to the client. + */ + private final LinkedList<OpenResource> openList = new LinkedList<OpenResource>(); + + /** + * The component that should be scrolled into view after the next repaint. + * Null if nothing should be scrolled into view. + */ + private Component scrollIntoView; + + /** + * The id of this root, used to find the server side instance of the root + * form which a request originates. A negative value indicates that the root + * id has not yet been assigned by the Application. + * + * @see Application#nextRootId + */ + private int rootId = -1; + + /** + * Keeps track of the Actions added to this component, and manages the + * painting and handling as well. + */ + protected ActionManager actionManager; + + /** + * Thread local for keeping track of the current root. + */ + private static final ThreadLocal<Root> currentRoot = new ThreadLocal<Root>(); + + private int browserWindowWidth = -1; + private int browserWindowHeight = -1; + + /** Identifies the click event */ + private static final String CLICK_EVENT_ID = VRoot.CLICK_EVENT_ID; + + private DirtyConnectorTracker dirtyConnectorTracker = new DirtyConnectorTracker( + this); + + private RootServerRpc rpc = new RootServerRpc() { + public void click(MouseEventDetails mouseDetails) { + fireEvent(new ClickEvent(Root.this, mouseDetails)); + } + }; + + /** + * Creates a new empty root without a caption. This root will have a + * {@link VerticalLayout} with margins enabled as its content. + */ + public Root() { + this((ComponentContainer) null); + } + + /** + * Creates a new root with the given component container as its content. + * + * @param content + * the content container to use as this roots content. + * + * @see #setContent(ComponentContainer) + */ + public Root(ComponentContainer content) { + registerRpc(rpc); + setSizeFull(); + setContent(content); + } + + /** + * Creates a new empty root with the given caption. This root will have a + * {@link VerticalLayout} with margins enabled as its content. + * + * @param caption + * the caption of the root, used as the page title if there's + * nothing but the application on the web page + * + * @see #setCaption(String) + */ + public Root(String caption) { + this((ComponentContainer) null); + setCaption(caption); + } + + /** + * Creates a new root with the given caption and content. + * + * @param caption + * the caption of the root, used as the page title if there's + * nothing but the application on the web page + * @param content + * the content container to use as this roots content. + * + * @see #setContent(ComponentContainer) + * @see #setCaption(String) + */ + public Root(String caption, ComponentContainer content) { + this(content); + setCaption(caption); + } + + @Override + public RootState getState() { + return (RootState) super.getState(); + } + + @Override + protected ComponentState createState() { + // This is a workaround for a problem with creating the correct state + // object during build + return new RootState(); + } + + /** + * Overridden to return a value instead of referring to the parent. + * + * @return this root + * + * @see com.vaadin.ui.AbstractComponent#getRoot() + */ + @Override + public Root getRoot() { + return this; + } + + public void replaceComponent(Component oldComponent, Component newComponent) { + throw new UnsupportedOperationException(); + } + + @Override + public Application getApplication() { + return application; + } + + public void paintContent(PaintTarget target) throws PaintException { + // Open requested resource + synchronized (openList) { + if (!openList.isEmpty()) { + for (final Iterator<OpenResource> i = openList.iterator(); i + .hasNext();) { + (i.next()).paintContent(target); + } + openList.clear(); + } + } + + // Paint notifications + if (notifications != null) { + target.startTag("notifications"); + for (final Iterator<Notification> it = notifications.iterator(); it + .hasNext();) { + final Notification n = it.next(); + target.startTag("notification"); + if (n.getCaption() != null) { + target.addAttribute( + VNotification.ATTRIBUTE_NOTIFICATION_CAPTION, + n.getCaption()); + } + if (n.getDescription() != null) { + target.addAttribute( + VNotification.ATTRIBUTE_NOTIFICATION_MESSAGE, + n.getDescription()); + } + if (n.getIcon() != null) { + target.addAttribute( + VNotification.ATTRIBUTE_NOTIFICATION_ICON, + n.getIcon()); + } + if (!n.isHtmlContentAllowed()) { + target.addAttribute( + VRoot.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true); + } + target.addAttribute( + VNotification.ATTRIBUTE_NOTIFICATION_POSITION, + n.getPosition()); + target.addAttribute(VNotification.ATTRIBUTE_NOTIFICATION_DELAY, + n.getDelayMsec()); + if (n.getStyleName() != null) { + target.addAttribute( + VNotification.ATTRIBUTE_NOTIFICATION_STYLE, + n.getStyleName()); + } + target.endTag("notification"); + } + target.endTag("notifications"); + notifications = null; + } + + // Add executable javascripts if needed + if (jsExecQueue != null) { + for (String script : jsExecQueue) { + target.startTag("execJS"); + target.addAttribute("script", script); + target.endTag("execJS"); + } + jsExecQueue = null; + } + + if (scrollIntoView != null) { + target.addAttribute("scrollTo", scrollIntoView); + scrollIntoView = null; + } + + if (pendingFocus != null) { + // ensure focused component is still attached to this main window + if (pendingFocus.getRoot() == this + || (pendingFocus.getRoot() != null && pendingFocus + .getRoot().getParent() == this)) { + target.addAttribute("focused", pendingFocus); + } + pendingFocus = null; + } + + if (actionManager != null) { + actionManager.paintActions(null, target); + } + + if (fragment != null) { + target.addAttribute(VRoot.FRAGMENT_VARIABLE, fragment); + } + + if (isResizeLazy()) { + target.addAttribute(VRoot.RESIZE_LAZY, true); + } + } + + /** + * Fire a click event to all click listeners. + * + * @param object + * The raw "value" of the variable change from the client side. + */ + private void fireClick(Map<String, Object> parameters) { + MouseEventDetails mouseDetails = MouseEventDetails + .deSerialize((String) parameters.get("mouseDetails")); + fireEvent(new ClickEvent(this, mouseDetails)); + } + + @SuppressWarnings("unchecked") + public void changeVariables(Object source, Map<String, Object> variables) { + if (variables.containsKey(CLICK_EVENT_ID)) { + fireClick((Map<String, Object>) variables.get(CLICK_EVENT_ID)); + } + + // Actions + if (actionManager != null) { + actionManager.handleActions(variables, this); + } + + if (variables.containsKey(VRoot.FRAGMENT_VARIABLE)) { + String fragment = (String) variables.get(VRoot.FRAGMENT_VARIABLE); + setFragment(fragment, true); + } + + boolean sendResizeEvent = false; + if (variables.containsKey("height")) { + browserWindowHeight = ((Integer) variables.get("height")) + .intValue(); + sendResizeEvent = true; + } + if (variables.containsKey("width")) { + browserWindowWidth = ((Integer) variables.get("width")).intValue(); + sendResizeEvent = true; + } + if (sendResizeEvent) { + fireEvent(new BrowserWindowResizeEvent(this, browserWindowWidth, + browserWindowHeight)); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.ComponentContainer#getComponentIterator() + */ + public Iterator<Component> getComponentIterator() { + return Collections.singleton((Component) getContent()).iterator(); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.ComponentContainer#getComponentCount() + */ + public int getComponentCount() { + return getContent() == null ? 0 : 1; + } + + /** + * Sets the application to which this root is assigned. It is not legal to + * change the application once it has been set nor to set a + * <code>null</code> application. + * <p> + * This method is mainly intended for internal use by the framework. + * </p> + * + * @param application + * the application to set + * + * @throws IllegalStateException + * if the application has already been set + * + * @see #getApplication() + */ + public void setApplication(Application application) { + if ((application == null) == (this.application == null)) { + throw new IllegalStateException("Application has already been set"); + } else { + this.application = application; + } + + if (application != null) { + attach(); + } else { + detach(); + } + } + + /** + * Sets the id of this root within its application. The root id is used to + * route requests to the right root. + * <p> + * This method is mainly intended for internal use by the framework. + * </p> + * + * @param rootId + * the id of this root + * + * @throws IllegalStateException + * if the root id has already been set + * + * @see #getRootId() + */ + public void setRootId(int rootId) { + if (this.rootId != -1) { + throw new IllegalStateException("Root id has already been defined"); + } + this.rootId = rootId; + } + + /** + * Gets the id of the root, used to identify this root within its + * application when processing requests. The root id should be present in + * every request to the server that originates from this root. + * {@link Application#getRootForRequest(WrappedRequest)} uses this id to + * find the route to which the request belongs. + * + * @return + */ + public int getRootId() { + return rootId; + } + + /** + * Adds a window as a subwindow inside this root. To open a new browser + * window or tab, you should instead use {@link open(Resource)} with an url + * pointing to this application and ensure + * {@link Application#getRoot(WrappedRequest)} returns an appropriate root + * for the request. + * + * @param window + * @throws IllegalArgumentException + * if the window is already added to an application + * @throws NullPointerException + * if the given <code>Window</code> is <code>null</code>. + */ + public void addWindow(Window window) throws IllegalArgumentException, + NullPointerException { + + if (window == null) { + throw new NullPointerException("Argument must not be null"); + } + + if (window.getApplication() != null) { + throw new IllegalArgumentException( + "Window is already attached to an application."); + } + + attachWindow(window); + } + + /** + * Helper method to attach a window. + * + * @param w + * the window to add + */ + private void attachWindow(Window w) { + windows.add(w); + w.setParent(this); + requestRepaint(); + } + + /** + * Remove the given subwindow from this root. + * + * Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly + * removing a window by calling this method. + * + * Since Vaadin 6.5, returns a boolean indicating if the window was removed + * or not. + * + * @param window + * Window to be removed. + * @return true if the subwindow was removed, false otherwise + */ + public boolean removeWindow(Window window) { + if (!windows.remove(window)) { + // Window window is not a subwindow of this root. + return false; + } + window.setParent(null); + window.fireClose(); + requestRepaint(); + + return true; + } + + /** + * Gets all the windows added to this root. + * + * @return an unmodifiable collection of windows + */ + public Collection<Window> getWindows() { + return Collections.unmodifiableCollection(windows); + } + + @Override + public void focus() { + super.focus(); + } + + /** + * Component that should be focused after the next repaint. Null if no focus + * change should take place. + */ + private Focusable pendingFocus; + + /** + * The current URI fragment. + */ + private String fragment; + + private boolean resizeLazy = false; + + /** + * This method is used by Component.Focusable objects to request focus to + * themselves. Focus renders must be handled at window level (instead of + * Component.Focusable) due we want the last focused component to be focused + * in client too. Not the one that is rendered last (the case we'd get if + * implemented in Focusable only). + * + * To focus component from Vaadin application, use Focusable.focus(). See + * {@link Focusable}. + * + * @param focusable + * to be focused on next paint + */ + public void setFocusedComponent(Focusable focusable) { + pendingFocus = focusable; + requestRepaint(); + } + + /** + * Shows a notification message on the middle of the root. The message + * automatically disappears ("humanized message"). + * + * Care should be taken to to avoid XSS vulnerabilities as the caption is + * rendered as html. + * + * @see #showNotification(Notification) + * @see Notification + * + * @param caption + * The message + */ + public void showNotification(String caption) { + addNotification(new Notification(caption)); + } + + /** + * Shows a notification message the root. The position and behavior of the + * message depends on the type, which is one of the basic types defined in + * {@link Notification}, for instance Notification.TYPE_WARNING_MESSAGE. + * + * Care should be taken to to avoid XSS vulnerabilities as the caption is + * rendered as html. + * + * @see #showNotification(Notification) + * @see Notification + * + * @param caption + * The message + * @param type + * The message type + */ + public void showNotification(String caption, int type) { + addNotification(new Notification(caption, type)); + } + + /** + * Shows a notification consisting of a bigger caption and a smaller + * description on the middle of the root. The message automatically + * disappears ("humanized message"). + * + * Care should be taken to to avoid XSS vulnerabilities as the caption and + * description are rendered as html. + * + * @see #showNotification(Notification) + * @see Notification + * + * @param caption + * The caption of the message + * @param description + * The message description + * + */ + public void showNotification(String caption, String description) { + addNotification(new Notification(caption, description)); + } + + /** + * Shows a notification consisting of a bigger caption and a smaller + * description. The position and behavior of the message depends on the + * type, which is one of the basic types defined in {@link Notification}, + * for instance Notification.TYPE_WARNING_MESSAGE. + * + * Care should be taken to to avoid XSS vulnerabilities as the caption and + * description are rendered as html. + * + * @see #showNotification(Notification) + * @see Notification + * + * @param caption + * The caption of the message + * @param description + * The message description + * @param type + * The message type + */ + public void showNotification(String caption, String description, int type) { + addNotification(new Notification(caption, description, type)); + } + + /** + * Shows a notification consisting of a bigger caption and a smaller + * description. The position and behavior of the message depends on the + * type, which is one of the basic types defined in {@link Notification}, + * for instance Notification.TYPE_WARNING_MESSAGE. + * + * Care should be taken to avoid XSS vulnerabilities if html content is + * allowed. + * + * @see #showNotification(Notification) + * @see Notification + * + * @param caption + * The message caption + * @param description + * The message description + * @param type + * The type of message + * @param htmlContentAllowed + * Whether html in the caption and description should be + * displayed as html or as plain text + */ + public void showNotification(String caption, String description, int type, + boolean htmlContentAllowed) { + addNotification(new Notification(caption, description, type, + htmlContentAllowed)); + } + + /** + * Shows a notification message. + * + * @see Notification + * @see #showNotification(String) + * @see #showNotification(String, int) + * @see #showNotification(String, String) + * @see #showNotification(String, String, int) + * + * @param notification + * The notification message to show + */ + public void showNotification(Notification notification) { + addNotification(notification); + } + + /** + * Internal helper method to actually add a notification. + * + * @param notification + * the notification to add + */ + private void addNotification(Notification notification) { + if (notifications == null) { + notifications = new LinkedList<Notification>(); + } + notifications.add(notification); + requestRepaint(); + } + + /** + * Executes JavaScript in this root. + * + * <p> + * This method allows one to inject javascript from the server to client. A + * client implementation is not required to implement this functionality, + * but currently all web-based clients do implement this. + * </p> + * + * <p> + * Executing javascript this way often leads to cross-browser compatibility + * issues and regressions that are hard to resolve. Use of this method + * should be avoided and instead it is recommended to create new widgets + * with GWT. For more info on creating own, reusable client-side widgets in + * Java, read the corresponding chapter in Book of Vaadin. + * </p> + * + * @param script + * JavaScript snippet that will be executed. + */ + public void executeJavaScript(String script) { + if (jsExecQueue == null) { + jsExecQueue = new ArrayList<String>(); + } + + jsExecQueue.add(script); + + requestRepaint(); + } + + /** + * Scrolls any component between the component and root to a suitable + * position so the component is visible to the user. The given component + * must belong to this root. + * + * @param component + * the component to be scrolled into view + * @throws IllegalArgumentException + * if {@code component} does not belong to this root + */ + public void scrollIntoView(Component component) + throws IllegalArgumentException { + if (component.getRoot() != this) { + throw new IllegalArgumentException( + "The component where to scroll must belong to this root."); + } + scrollIntoView = component; + requestRepaint(); + } + + /** + * Gets the content of this root. The content is a component container that + * serves as the outermost item of the visual contents of this root. + * + * @return a component container to use as content + * + * @see #setContent(ComponentContainer) + * @see #createDefaultLayout() + */ + public ComponentContainer getContent() { + return (ComponentContainer) getState().getContent(); + } + + /** + * Helper method to create the default content layout that is used if no + * content has not been explicitly defined. + * + * @return a newly created layout + */ + private static VerticalLayout createDefaultLayout() { + VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + return layout; + } + + /** + * Sets the content of this root. The content is a component container that + * serves as the outermost item of the visual contents of this root. If no + * content has been set, a {@link VerticalLayout} with margins enabled will + * be used by default - see {@link #createDefaultLayout()}. The content can + * also be set in a constructor. + * + * @return a component container to use as content + * + * @see #Root(ComponentContainer) + * @see #createDefaultLayout() + */ + public void setContent(ComponentContainer content) { + if (content == null) { + content = createDefaultLayout(); + } + + if (getState().getContent() != null) { + super.removeComponent((Component) getState().getContent()); + } + getState().setContent(content); + if (content != null) { + super.addComponent(content); + } + } + + /** + * Adds a component to this root. The component is not added directly to the + * root, but instead to the content container ({@link #getContent()}). + * + * @param component + * the component to add to this root + * + * @see #getContent() + */ + @Override + public void addComponent(Component component) { + getContent().addComponent(component); + } + + /** + * This implementation removes the component from the content container ( + * {@link #getContent()}) instead of from the actual root. + */ + @Override + public void removeComponent(Component component) { + getContent().removeComponent(component); + } + + /** + * This implementation removes the components from the content container ( + * {@link #getContent()}) instead of from the actual root. + */ + @Override + public void removeAllComponents() { + getContent().removeAllComponents(); + } + + /** + * Internal initialization method, should not be overridden. This method is + * not declared as final because that would break compatibility with e.g. + * CDI. + * + * @param request + * the initialization request + */ + public void doInit(WrappedRequest request) { + BrowserDetails browserDetails = request.getBrowserDetails(); + if (browserDetails != null) { + fragment = browserDetails.getUriFragment(); + } + + // Call the init overridden by the application developer + init(request); + } + + /** + * Initializes this root. This method is intended to be overridden by + * subclasses to build the view and configure non-component functionality. + * Performing the initialization in a constructor is not suggested as the + * state of the root is not properly set up when the constructor is invoked. + * <p> + * The {@link WrappedRequest} can be used to get information about the + * request that caused this root to be created. By default, the + * {@link BrowserDetails} will be available in the request. If the browser + * details are not required, loading the application in the browser can take + * some shortcuts giving a faster initial rendering. This can be indicated + * by adding the {@link EagerInit} annotation to the Root class. + * </p> + * + * @param request + * the wrapped request that caused this root to be created + */ + protected abstract void init(WrappedRequest request); + + /** + * Sets the thread local for the current root. This method is used by the + * framework to set the current application whenever a new request is + * processed and it is cleared when the request has been processed. + * <p> + * The application developer can also use this method to define the current + * root outside the normal request handling, e.g. when initiating custom + * background threads. + * </p> + * + * @param root + * the root to register as the current root + * + * @see #getCurrentRoot() + * @see ThreadLocal + */ + public static void setCurrentRoot(Root root) { + currentRoot.set(root); + } + + /** + * Gets the currently used root. The current root is automatically defined + * when processing requests to the server. In other cases, (e.g. from + * background threads), the current root is not automatically defined. + * + * @return the current root instance if available, otherwise + * <code>null</code> + * + * @see #setCurrentRoot(Root) + */ + public static Root getCurrentRoot() { + return currentRoot.get(); + } + + /** + * Opens the given resource in this root. The contents of this Root is + * replaced by the {@code Resource}. + * + * @param resource + * the resource to show in this root + */ + public void open(Resource resource) { + synchronized (openList) { + if (!openList.contains(resource)) { + openList.add(new OpenResource(resource, null, -1, -1, + BORDER_DEFAULT)); + } + } + requestRepaint(); + } + + /* ********************************************************************* */ + + /** + * Opens the given resource in a window with the given name. + * <p> + * The supplied {@code windowName} is used as the target name in a + * window.open call in the client. This means that special values such as + * "_blank", "_self", "_top", "_parent" have special meaning. An empty or + * <code>null</code> window name is also a special case. + * </p> + * <p> + * "", null and "_self" as {@code windowName} all causes the resource to be + * opened in the current window, replacing any old contents. For + * downloadable content you should avoid "_self" as "_self" causes the + * client to skip rendering of any other changes as it considers them + * irrelevant (the page will be replaced by the resource). This can speed up + * the opening of a resource, but it might also put the client side into an + * inconsistent state if the window content is not completely replaced e.g., + * if the resource is downloaded instead of displayed in the browser. + * </p> + * <p> + * "_blank" as {@code windowName} causes the resource to always be opened in + * a new window or tab (depends on the browser and browser settings). + * </p> + * <p> + * "_top" and "_parent" as {@code windowName} works as specified by the HTML + * standard. + * </p> + * <p> + * Any other {@code windowName} will open the resource in a window with that + * name, either by opening a new window/tab in the browser or by replacing + * the contents of an existing window with that name. + * </p> + * + * @param resource + * the resource. + * @param windowName + * the name of the window. + */ + public void open(Resource resource, String windowName) { + synchronized (openList) { + if (!openList.contains(resource)) { + openList.add(new OpenResource(resource, windowName, -1, -1, + BORDER_DEFAULT)); + } + } + requestRepaint(); + } + + /** + * Opens the given resource in a window with the given size, border and + * name. For more information on the meaning of {@code windowName}, see + * {@link #open(Resource, String)}. + * + * @param resource + * the resource. + * @param windowName + * the name of the window. + * @param width + * the width of the window in pixels + * @param height + * the height of the window in pixels + * @param border + * the border style of the window. See {@link #BORDER_NONE + * Window.BORDER_* constants} + */ + public void open(Resource resource, String windowName, int width, + int height, int border) { + synchronized (openList) { + if (!openList.contains(resource)) { + openList.add(new OpenResource(resource, windowName, width, + height, border)); + } + } + requestRepaint(); + } + + /** + * Private class for storing properties related to opening resources. + */ + private class OpenResource implements Serializable { + + /** + * The resource to open + */ + private final Resource resource; + + /** + * The name of the target window + */ + private final String name; + + /** + * The width of the target window + */ + private final int width; + + /** + * The height of the target window + */ + private final int height; + + /** + * The border style of the target window + */ + private final int border; + + /** + * Creates a new open resource. + * + * @param resource + * The resource to open + * @param name + * The name of the target window + * @param width + * The width of the target window + * @param height + * The height of the target window + * @param border + * The border style of the target window + */ + private OpenResource(Resource resource, String name, int width, + int height, int border) { + this.resource = resource; + this.name = name; + this.width = width; + this.height = height; + this.border = border; + } + + /** + * Paints the open request. Should be painted inside the window. + * + * @param target + * the paint target + * @throws PaintException + * if the paint operation fails + */ + private void paintContent(PaintTarget target) throws PaintException { + target.startTag("open"); + target.addAttribute("src", resource); + if (name != null && name.length() > 0) { + target.addAttribute("name", name); + } + if (width >= 0) { + target.addAttribute("width", width); + } + if (height >= 0) { + target.addAttribute("height", height); + } + switch (border) { + case BORDER_MINIMAL: + target.addAttribute("border", "minimal"); + break; + case BORDER_NONE: + target.addAttribute("border", "none"); + break; + } + + target.endTag("open"); + } + } + + public void setScrollTop(int scrollTop) { + throw new RuntimeException("Not yet implemented"); + } + + @Override + protected ActionManager getActionManager() { + if (actionManager == null) { + actionManager = new ActionManager(this); + } + return actionManager; + } + + public <T extends Action & com.vaadin.event.Action.Listener> void addAction( + T action) { + getActionManager().addAction(action); + } + + public <T extends Action & com.vaadin.event.Action.Listener> void removeAction( + T action) { + if (actionManager != null) { + actionManager.removeAction(action); + } + } + + public void addActionHandler(Handler actionHandler) { + getActionManager().addActionHandler(actionHandler); + } + + public void removeActionHandler(Handler actionHandler) { + if (actionManager != null) { + actionManager.removeActionHandler(actionHandler); + } + } + + /** + * Should resize operations be lazy, i.e. should there be a delay before + * layout sizes are recalculated. Speeds up resize operations in slow UIs + * with the penalty of slightly decreased usability. + * <p> + * Default value: <code>false</code> + * + * @param resizeLazy + * true to use a delay before recalculating sizes, false to + * calculate immediately. + */ + public void setResizeLazy(boolean resizeLazy) { + this.resizeLazy = resizeLazy; + requestRepaint(); + } + + /** + * Checks whether lazy resize is enabled. + * + * @return <code>true</code> if lazy resize is enabled, <code>false</code> + * if lazy resize is not enabled + */ + public boolean isResizeLazy() { + return resizeLazy; + } + + /** + * Add a click listener to the Root. The listener is called whenever the + * user clicks inside the Root. Also when the click targets a component + * inside the Root, provided the targeted component does not prevent the + * click event from propagating. + * + * Use {@link #removeListener(ClickListener)} to remove the listener. + * + * @param listener + * The listener to add + */ + public void addListener(ClickListener listener) { + addListener(CLICK_EVENT_ID, ClickEvent.class, listener, + ClickListener.clickMethod); + } + + /** + * Remove a click listener from the Root. The listener should earlier have + * been added using {@link #addListener(ClickListener)}. + * + * @param listener + * The listener to remove + */ + public void removeListener(ClickListener listener) { + removeListener(CLICK_EVENT_ID, ClickEvent.class, listener); + } + + public void addListener(FragmentChangedListener listener) { + addListener(FragmentChangedEvent.class, listener, + FRAGMENT_CHANGED_METHOD); + } + + public void removeListener(FragmentChangedListener listener) { + removeListener(FragmentChangedEvent.class, listener, + FRAGMENT_CHANGED_METHOD); + } + + /** + * Sets URI fragment. Optionally fires a {@link FragmentChangedEvent} + * + * @param newFragment + * id of the new fragment + * @param fireEvent + * true to fire event + * @see FragmentChangedEvent + * @see FragmentChangedListener + */ + public void setFragment(String newFragment, boolean fireEvents) { + if (newFragment == null) { + throw new NullPointerException("The fragment may not be null"); + } + if (!newFragment.equals(fragment)) { + fragment = newFragment; + if (fireEvents) { + fireEvent(new FragmentChangedEvent(this, newFragment)); + } + requestRepaint(); + } + } + + /** + * Sets URI fragment. This method fires a {@link FragmentChangedEvent} + * + * @param newFragment + * id of the new fragment + * @see FragmentChangedEvent + * @see FragmentChangedListener + */ + public void setFragment(String newFragment) { + setFragment(newFragment, true); + } + + /** + * Gets currently set URI fragment. + * <p> + * To listen changes in fragment, hook a {@link FragmentChangedListener}. + * + * @return the current fragment in browser uri or null if not known + */ + public String getFragment() { + return fragment; + } + + /** + * Adds a new {@link BrowserWindowResizeListener} to this root. The listener + * will be notified whenever the browser window within which this root + * resides is resized. + * + * @param resizeListener + * the listener to add + * + * @see BrowserWindowResizeListener#browserWindowResized(BrowserWindowResizeEvent) + * @see #setResizeLazy(boolean) + */ + public void addListener(BrowserWindowResizeListener resizeListener) { + addListener(BrowserWindowResizeEvent.class, resizeListener, + BROWSWER_RESIZE_METHOD); + } + + /** + * Removes a {@link BrowserWindowResizeListener} from this root. The + * listener will no longer be notified when the browser window is resized. + * + * @param resizeListener + * the listener to remove + */ + public void removeListener(BrowserWindowResizeListener resizeListener) { + removeListener(BrowserWindowResizeEvent.class, resizeListener, + BROWSWER_RESIZE_METHOD); + } + + /** + * Gets the last known height of the browser window in which this root + * resides. + * + * @return the browser window height in pixels + */ + public int getBrowserWindowHeight() { + return browserWindowHeight; + } + + /** + * Gets the last known width of the browser window in which this root + * resides. + * + * @return the browser window width in pixels + */ + public int getBrowserWindowWidth() { + return browserWindowWidth; + } + + /** + * Notifies the child components and windows that the root is attached to + * the application. + */ + @Override + public void attach() { + super.attach(); + for (Window w : windows) { + w.attach(); + } + } + + /** + * Notifies the child components and windows that the root is detached from + * the application. + */ + @Override + public void detach() { + super.detach(); + for (Window w : windows) { + w.detach(); + } + } + + @Override + public boolean isConnectorEnabled() { + // TODO How can a Root be invisible? What does it mean? + return isVisible() && isEnabled(); + } + + public DirtyConnectorTracker getDirtyConnectorTracker() { + return dirtyConnectorTracker; + } + + public void componentAttached(Component component) { + getDirtyConnectorTracker().componentAttached(component); + } + + public void componentDetached(Component component) { + getDirtyConnectorTracker().componentDetached(component); + } + +} diff --git a/src/com/vaadin/ui/Select.java b/src/com/vaadin/ui/Select.java index 0ea331dc40..5398f11391 100644 --- a/src/com/vaadin/ui/Select.java +++ b/src/com/vaadin/ui/Select.java @@ -23,7 +23,6 @@ import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VFilterSelect; /** * <p> @@ -44,7 +43,6 @@ import com.vaadin.terminal.gwt.client.ui.VFilterSelect; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VFilterSelect.class) public class Select extends AbstractSelect implements AbstractSelect.Filtering, FieldEvents.BlurNotifier, FieldEvents.FocusNotifier { @@ -147,11 +145,6 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering, target.addAttribute("modified", true); } - // Adds the required attribute - if (!isReadOnly() && isRequired()) { - target.addAttribute("required", true); - } - if (isNewItemsAllowed()) { target.addAttribute("allownewitem", true); } @@ -271,11 +264,6 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering, currentPage = -1; // current page is always set by client optionRequest = true; - - // Hide the error indicator if needed - if (shouldHideErrors()) { - target.addAttribute("hideErrors", true); - } } /** @@ -754,11 +742,15 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering, * @deprecated use {@link ListSelect}, {@link OptionGroup} or * {@link TwinColSelect} instead * @see com.vaadin.ui.AbstractSelect#setMultiSelect(boolean) + * @throws UnsupportedOperationException + * if trying to activate multiselect mode */ @Deprecated @Override public void setMultiSelect(boolean multiSelect) { - super.setMultiSelect(multiSelect); + if (multiSelect) { + throw new UnsupportedOperationException("Multiselect not supported"); + } } /** diff --git a/src/com/vaadin/ui/Slider.java b/src/com/vaadin/ui/Slider.java index 1d67a6b12c..dc5dc0be98 100644 --- a/src/com/vaadin/ui/Slider.java +++ b/src/com/vaadin/ui/Slider.java @@ -8,7 +8,7 @@ import java.util.Map; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VSlider; +import com.vaadin.terminal.Vaadin6Component; /** * A component for selecting a numerical value within a range. @@ -46,22 +46,12 @@ import com.vaadin.terminal.gwt.client.ui.VSlider; * * @author Vaadin Ltd. */ -@ClientWidget(VSlider.class) -public class Slider extends AbstractField { +public class Slider extends AbstractField<Double> implements Vaadin6Component { public static final int ORIENTATION_HORIZONTAL = 0; public static final int ORIENTATION_VERTICAL = 1; - /** - * Style constant representing a scrollbar styled slider. Use this with - * {@link #addStyleName(String)}. Default styling usually represents a - * common slider found e.g. in Adobe Photoshop. The client side - * implementation dictates how different styles will look. - */ - @Deprecated - public static final String STYLE_SCROLLBAR = "scrollbar"; - /** Minimum value of slider */ private double min = 0; @@ -80,35 +70,6 @@ public class Slider extends AbstractField { private int orientation = ORIENTATION_HORIZONTAL; /** - * Slider size in pixels. In horizontal mode, if set to -1, allow 100% width - * of container. In vertical mode, if set to -1, default height is - * determined by the client-side implementation. - * - * @deprecated - */ - @Deprecated - private int size = -1; - - /** - * Handle (draggable control element) size in percents relative to base - * size. Must be a value between 1-99. Other values are converted to nearest - * bound. A negative value sets the width to auto (client-side - * implementation calculates). - * - * @deprecated The size is dictated by the current theme. - */ - @Deprecated - private int handleSize = -1; - - /** - * Show arrows that can be pressed to slide the handle in some increments - * (client-side implementation decides the increment, usually somewhere - * between 5-10% of slide range). - */ - @Deprecated - private final boolean arrows = false; - - /** * Default slider constructor. Sets all values to defaults and the slide * handle at minimum value. * @@ -198,17 +159,8 @@ public class Slider extends AbstractField { */ public void setMax(double max) { this.max = max; - try { - if ((new Double(getValue().toString())).doubleValue() > max) { - super.setValue(new Double(max)); - } - } catch (final ClassCastException e) { - // FIXME: Handle exception - /* - * Where does ClassCastException come from? Can't see any casts - * above - */ - super.setValue(new Double(max)); + if (getValue() > max) { + setValue(max); } requestRepaint(); } @@ -231,17 +183,8 @@ public class Slider extends AbstractField { */ public void setMin(double min) { this.min = min; - try { - if ((new Double(getValue().toString())).doubleValue() < min) { - super.setValue(new Double(min)); - } - } catch (final ClassCastException e) { - // FIXME: Handle exception - /* - * Where does ClassCastException come from? Can't see any casts - * above - */ - super.setValue(new Double(min)); + if (getValue() < min) { + setValue(min); } requestRepaint(); } @@ -303,8 +246,8 @@ public class Slider extends AbstractField { * If the given value is not inside the range of the slider. * @see #setMin(double) {@link #setMax(double)} */ - public void setValue(Double value, boolean repaintIsNotNeeded) - throws ValueOutOfBoundsException { + @Override + protected void setValue(Double value, boolean repaintIsNotNeeded) { final double v = value.doubleValue(); double newValue; if (resolution > 0) { @@ -320,102 +263,22 @@ public class Slider extends AbstractField { throw new ValueOutOfBoundsException(value); } } - super.setValue(new Double(newValue), repaintIsNotNeeded); - } - - /** - * Sets the value of the slider. - * - * @param value - * The new value of the slider. - * @throws ValueOutOfBoundsException - * If the given value is not inside the range of the slider. - * @see #setMin(double) {@link #setMax(double)} - */ - public void setValue(Double value) throws ValueOutOfBoundsException { - setValue(value, false); - } - - /** - * Sets the value of the slider. - * - * @param value - * The new value of the slider. - * @throws ValueOutOfBoundsException - * If the given value is not inside the range of the slider. - * @see #setMin(double) {@link #setMax(double)} - */ - public void setValue(double value) throws ValueOutOfBoundsException { - setValue(new Double(value), false); - } - - /** - * Get the current slider size. - * - * @return size in pixels or -1 for auto sizing. - * @deprecated use standard getWidth/getHeight instead - */ - @Deprecated - public int getSize() { - return size; + super.setValue(newValue, repaintIsNotNeeded); } - /** - * Set the size for this slider. - * - * @param size - * in pixels, or -1 auto sizing. - * @deprecated use standard setWidth/setHeight instead - */ - @Deprecated - public void setSize(int size) { - this.size = size; - switch (orientation) { - case ORIENTATION_HORIZONTAL: - setWidth(size, UNITS_PIXELS); - break; - default: - setHeight(size, UNITS_PIXELS); - break; + @Override + public void setValue(Object newFieldValue) + throws com.vaadin.data.Property.ReadOnlyException { + if (newFieldValue != null && newFieldValue instanceof Number + && !(newFieldValue instanceof Double)) { + // Support setting all types of Numbers + newFieldValue = ((Number) newFieldValue).doubleValue(); } - requestRepaint(); - } - /** - * Get the handle size of this slider. - * - * @return handle size in percentages. - * @deprecated The size is dictated by the current theme. - */ - @Deprecated - public int getHandleSize() { - return handleSize; + super.setValue(newFieldValue); } - /** - * Set the handle size of this slider. - * - * @param handleSize - * in percentages relative to slider base size. - * @deprecated The size is dictated by the current theme. - */ - @Deprecated - public void setHandleSize(int handleSize) { - if (handleSize < 0) { - this.handleSize = -1; - } else if (handleSize > 99) { - this.handleSize = 99; - } else if (handleSize < 1) { - this.handleSize = 1; - } else { - this.handleSize = handleSize; - } - requestRepaint(); - } - - @Override public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); target.addAttribute("min", min); if (max > min) { @@ -426,30 +289,15 @@ public class Slider extends AbstractField { target.addAttribute("resolution", resolution); if (resolution > 0) { - target.addVariable(this, "value", - ((Double) getValue()).doubleValue()); + target.addVariable(this, "value", getValue().doubleValue()); } else { - target.addVariable(this, "value", ((Double) getValue()).intValue()); + target.addVariable(this, "value", getValue().intValue()); } if (orientation == ORIENTATION_VERTICAL) { target.addAttribute("vertical", true); } - if (arrows) { - target.addAttribute("arrows", true); - } - - if (size > -1) { - target.addAttribute("size", size); - } - - if (min != max && min < max) { - target.addAttribute("hsize", handleSize); - } else { - target.addAttribute("hsize", 100); - } - } /** @@ -459,9 +307,7 @@ public class Slider extends AbstractField { * @param source * @param variables */ - @Override public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); if (variables.containsKey("value")) { final Object value = variables.get("value"); final Double newValue = new Double(value.toString()); @@ -491,7 +337,7 @@ public class Slider extends AbstractField { * @author Vaadin Ltd. * */ - public class ValueOutOfBoundsException extends Exception { + public class ValueOutOfBoundsException extends RuntimeException { private final Double value; @@ -517,7 +363,7 @@ public class Slider extends AbstractField { } @Override - public Class getType() { + public Class<Double> getType() { return Double.class; } diff --git a/src/com/vaadin/ui/SplitPanel.java b/src/com/vaadin/ui/SplitPanel.java deleted file mode 100644 index bae1bf7ce0..0000000000 --- a/src/com/vaadin/ui/SplitPanel.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal; -import com.vaadin.ui.ClientWidget.LoadStyle; - -/** - * SplitPanel. - * - * <code>SplitPanel</code> is a component container, that can contain two - * components (possibly containers) which are split by divider element. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - * @deprecated in 6.5. Use {@link HorizontalSplitPanel} or - * {@link VerticalSplitPanel} instead. - */ -@Deprecated -@ClientWidget(value = VSplitPanelHorizontal.class, loadStyle = LoadStyle.EAGER) -public class SplitPanel extends AbstractSplitPanel { - - /* Predefined orientations */ - - /** - * Components are to be laid out vertically. - */ - public static final int ORIENTATION_VERTICAL = 0; - - /** - * Components are to be laid out horizontally. - */ - public static final int ORIENTATION_HORIZONTAL = 1; - - /** - * Orientation of the layout. - */ - private int orientation; - - /** - * Creates a new split panel. The orientation of the panels is - * <code>ORIENTATION_VERTICAL</code>. - */ - public SplitPanel() { - super(); - orientation = ORIENTATION_VERTICAL; - setSizeFull(); - } - - /** - * Create a new split panels. The orientation of the panel is given as - * parameters. - * - * @param orientation - * the Orientation of the layout. - */ - public SplitPanel(int orientation) { - this(); - setOrientation(orientation); - } - - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - if (orientation == ORIENTATION_VERTICAL) { - target.addAttribute("vertical", true); - } - - } - - /** - * Gets the orientation of the split panel. - * - * @return the Value of property orientation. - * - */ - public int getOrientation() { - return orientation; - } - - /** - * Sets the orientation of the split panel. - * - * @param orientation - * the New value of property orientation. - */ - public void setOrientation(int orientation) { - - // Checks the validity of the argument - if (orientation < ORIENTATION_VERTICAL - || orientation > ORIENTATION_HORIZONTAL) { - throw new IllegalArgumentException(); - } - - this.orientation = orientation; - requestRepaint(); - } - -} diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java index 09d1002b48..23dee15359 100644 --- a/src/com/vaadin/ui/TabSheet.java +++ b/src/com/vaadin/ui/TabSheet.java @@ -7,10 +7,8 @@ package com.vaadin.ui; import java.io.Serializable; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; @@ -22,11 +20,13 @@ import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.FieldEvents.FocusNotifier; import com.vaadin.terminal.ErrorMessage; import com.vaadin.terminal.KeyMapper; +import com.vaadin.terminal.LegacyPaint; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VTabsheet; -import com.vaadin.terminal.gwt.server.CommunicationManager; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.ui.tabsheet.TabsheetBaseConnector; +import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheet; import com.vaadin.ui.Component.Focusable; import com.vaadin.ui.themes.Reindeer; import com.vaadin.ui.themes.Runo; @@ -60,10 +60,8 @@ import com.vaadin.ui.themes.Runo; * @VERSION@ * @since 3.0 */ -@SuppressWarnings("serial") -@ClientWidget(VTabsheet.class) public class TabSheet extends AbstractComponentContainer implements Focusable, - FocusNotifier, BlurNotifier { + FocusNotifier, BlurNotifier, Vaadin6Component { /** * List of component tabs (tab contents). In addition to being on this list, @@ -86,7 +84,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, * Mapper between server-side component instances (tab contents) and keys * given to the client that identify tabs. */ - private final KeyMapper keyMapper = new KeyMapper(); + private final KeyMapper<Component> keyMapper = new KeyMapper<Component>(); /** * When true, the tab selection area is not displayed to the user. @@ -94,11 +92,6 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, private boolean tabsHidden; /** - * Tabs that have been shown to the user (have been painted as selected). - */ - private HashSet<Component> paintedTabs = new HashSet<Component>(); - - /** * Handler to be called when a tab is closed. */ private CloseHandler closeHandler; @@ -159,7 +152,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, tabs.remove(c); if (c.equals(selected)) { if (components.isEmpty()) { - selected = null; + setSelected(null); } else { // select the first enabled and visible tab, if any updateSelection(); @@ -286,7 +279,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, tabs.put(c, tab); if (selected == null) { - selected = c; + setSelected(c); fireSelectedTabChange(); } super.addComponent(c); @@ -366,7 +359,6 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, * @throws PaintException * if the paint operation failed. */ - @Override public void paintContent(PaintTarget target) throws PaintException { if (areTabsHidden()) { @@ -379,18 +371,15 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, target.startTag("tabs"); - Collection<Component> orphaned = new HashSet<Component>(paintedTabs); - for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) { final Component component = i.next(); - orphaned.remove(component); - Tab tab = tabs.get(component); target.startTag("tab"); if (!tab.isEnabled() && tab.isVisible()) { - target.addAttribute("disabled", true); + target.addAttribute( + TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED, true); } if (!tab.isVisible()) { @@ -401,23 +390,29 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, target.addAttribute("closable", true); } + // tab icon, caption and description, but used via + // VCaption.updateCaption(uidl) final Resource icon = tab.getIcon(); if (icon != null) { - target.addAttribute("icon", icon); + target.addAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON, + icon); } final String caption = tab.getCaption(); if (caption != null && caption.length() > 0) { - target.addAttribute("caption", caption); + target.addAttribute( + TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION, caption); + } + ErrorMessage tabError = tab.getComponentError(); + if (tabError != null) { + target.addAttribute( + TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE, + tabError.getFormattedHtmlMessage()); } - final String description = tab.getDescription(); if (description != null) { - target.addAttribute("description", description); - } - - final ErrorMessage componentError = tab.getComponentError(); - if (componentError != null) { - componentError.paint(target); + target.addAttribute( + TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION, + description); } final String styleName = tab.getStyleName(); @@ -428,17 +423,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, target.addAttribute("key", keyMapper.key(component)); if (component.equals(selected)) { target.addAttribute("selected", true); - if (!paintedTabs.contains(component)) { - // Ensure the component is painted if it hasn't already been - // painted in this tabsheet - component.requestRepaint(); - paintedTabs.add(component); - } - component.paint(target); - } else if (paintedTabs.contains(component)) { - component.paint(target); - } else { - component.requestRepaintRequests(); + LegacyPaint.paint(component, target); } target.endTag("tab"); } @@ -449,10 +434,6 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, target.addVariable(this, "selected", keyMapper.key(selected)); } - // clean possibly orphaned entries in paintedTabs - for (Component component2 : orphaned) { - paintedTabs.remove(component2); - } } /** @@ -589,7 +570,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, */ public void setSelectedTab(Component c) { if (c != null && components.contains(c) && !c.equals(selected)) { - selected = c; + setSelected(c); updateSelection(); fireSelectedTabChange(); requestRepaint(); @@ -597,6 +578,31 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, } /** + * Sets the selected tab in the TabSheet. Ensures that the selected tab is + * repainted if needed. + * + * @param c + * The new selection or null for no selection + */ + private void setSelected(Component c) { + selected = c; + // Repaint of the selected component is needed as only the selected + // component is communicated to the client. Otherwise this will be a + // "cached" update even though the client knows nothing about the + // connector + if (selected instanceof ComponentContainer) { + ((ComponentContainer) selected).requestRepaintAll(); + } else if (selected instanceof Table) { + // Workaround until there's a generic way of telling a component + // that there is no client side state to rely on. See #8642 + ((Table) selected).refreshRowCache(); + } else if (selected != null) { + selected.requestRepaint(); + } + + } + + /** * Sets the selected tab. The tab is identified by the corresponding * {@link Tab Tab} instance. Does nothing if the tabsheet doesn't contain * the given tab. @@ -653,14 +659,14 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, // The current selection is not valid so we need to change // it if (tab.isEnabled() && tab.isVisible()) { - selected = component; + setSelected(component); break; } else { /* * The current selection is not valid but this tab cannot be * selected either. */ - selected = null; + setSelected(null); } } } @@ -677,15 +683,13 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, } // inherits javadoc - @Override public void changeVariables(Object source, Map<String, Object> variables) { if (variables.containsKey("selected")) { - setSelectedTab((Component) keyMapper.get((String) variables - .get("selected"))); + setSelectedTab(keyMapper.get((String) variables.get("selected"))); } if (variables.containsKey("close")) { - final Component tab = (Component) keyMapper.get((String) variables - .get("close")); + final Component tab = keyMapper + .get((String) variables.get("close")); if (tab != null) { closeHandler.onTabClose(this, tab); } @@ -719,7 +723,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, if (selected == oldComponent) { // keep selection w/o selectedTabChange event - selected = newComponent; + setSelected(newComponent); } Tab newTab = tabs.get(newComponent); @@ -897,16 +901,6 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, fireEvent(new SelectedTabChangeEvent(this)); } - @Override - public void removeListener(RepaintRequestListener listener) { - super.removeListener(listener); - if (listener instanceof CommunicationManager) { - // clean the paintedTabs here instead of detach to avoid subtree - // caching issues when detached-attached without render - paintedTabs.clear(); - } - } - /** * Tab meta-data for a component in a {@link TabSheet}. * @@ -1033,12 +1027,11 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, public void setComponentError(ErrorMessage componentError); /** - * Gets the curent error message shown for the tab. + * Gets the current error message shown for the tab. * - * @see AbstractComponent#setComponentError(ErrorMessage) + * TODO currently not sent to the client * - * @param error - * message or null if none + * @see AbstractComponent#setComponentError(ErrorMessage) */ public ErrorMessage getComponentError(); @@ -1068,9 +1061,8 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, * </pre> * * <p> - * This method will trigger a - * {@link com.vaadin.terminal.Paintable.RepaintRequestEvent - * RepaintRequestEvent} on the TabSheet to which the Tab belongs. + * This method will trigger a {@link RepaintRequestEvent} on the + * TabSheet to which the Tab belongs. * </p> * * @param styleName @@ -1303,4 +1295,9 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); } + + @Override + public boolean isComponentVisible(Component childComponent) { + return childComponent == getSelectedTab(); + } } diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java index e605ec4f6b..2fffedd9d6 100644 --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@ -8,6 +8,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -20,18 +21,19 @@ import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; +import com.vaadin.Application; import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.util.ContainerOrderedWrapper; import com.vaadin.data.util.IndexedContainer; +import com.vaadin.data.util.converter.Converter; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.event.DataBoundTransferable; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.event.ItemClickEvent.ItemClickNotifier; -import com.vaadin.event.ItemClickEvent.ItemClickSource; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DragSource; @@ -40,12 +42,13 @@ import com.vaadin.event.dd.DropTarget; import com.vaadin.event.dd.acceptcriteria.ClientCriterion; import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion; import com.vaadin.terminal.KeyMapper; +import com.vaadin.terminal.LegacyPaint; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VScrollTable; import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers; +import com.vaadin.terminal.gwt.client.ui.table.VScrollTable; /** * <p> @@ -70,11 +73,10 @@ import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers; * @VERSION@ * @since 3.0 */ -@SuppressWarnings({ "serial", "deprecation" }) -@ClientWidget(VScrollTable.class) +@SuppressWarnings({ "deprecation" }) public class Table extends AbstractSelect implements Action.Container, - Container.Ordered, Container.Sortable, ItemClickSource, - ItemClickNotifier, DragSource, DropTarget { + Container.Ordered, Container.Sortable, ItemClickNotifier, DragSource, + DropTarget, HasComponents { private static final Logger logger = Logger .getLogger(Table.class.getName()); @@ -113,91 +115,215 @@ public class Table extends AbstractSelect implements Action.Container, protected static final int CELL_FIRSTCOL = 5; + public enum Align { + /** + * Left column alignment. <b>This is the default behaviour. </b> + */ + LEFT("b"), + + /** + * Center column alignment. + */ + CENTER("c"), + + /** + * Right column alignment. + */ + RIGHT("e"); + + private String alignment; + + private Align(String alignment) { + this.alignment = alignment; + } + + @Override + public String toString() { + return alignment; + } + + public Align convertStringToAlign(String string) { + if (string == null) { + return null; + } + if (string.equals("b")) { + return Align.LEFT; + } else if (string.equals("c")) { + return Align.CENTER; + } else if (string.equals("e")) { + return Align.RIGHT; + } else { + return null; + } + } + } + /** - * Left column alignment. <b>This is the default behaviour. </b> + * @deprecated from 7.0, use {@link Align#LEFT} instead */ - public static final String ALIGN_LEFT = "b"; + @Deprecated + public static final Align ALIGN_LEFT = Align.LEFT; /** - * Center column alignment. + * @deprecated from 7.0, use {@link Align#CENTER} instead */ - public static final String ALIGN_CENTER = "c"; + @Deprecated + public static final Align ALIGN_CENTER = Align.CENTER; /** - * Right column alignment. + * @deprecated from 7.0, use {@link Align#RIGHT} instead */ - public static final String ALIGN_RIGHT = "e"; + @Deprecated + public static final Align ALIGN_RIGHT = Align.RIGHT; + + public enum ColumnHeaderMode { + /** + * Column headers are hidden. + */ + HIDDEN, + /** + * Property ID:s are used as column headers. + */ + ID, + /** + * Column headers are explicitly specified with + * {@link #setColumnHeaders(String[])}. + */ + EXPLICIT, + /** + * Column headers are explicitly specified with + * {@link #setColumnHeaders(String[])}. If a header is not specified for + * a given property, its property id is used instead. + * <p> + * <b>This is the default behavior. </b> + */ + EXPLICIT_DEFAULTS_ID + } /** - * Column header mode: Column headers are hidden. + * @deprecated from 7.0, use {@link ColumnHeaderMode#HIDDEN} instead */ - public static final int COLUMN_HEADER_MODE_HIDDEN = -1; + @Deprecated + public static final ColumnHeaderMode COLUMN_HEADER_MODE_HIDDEN = ColumnHeaderMode.HIDDEN; /** - * Column header mode: Property ID:s are used as column headers. + * @deprecated from 7.0, use {@link ColumnHeaderMode#ID} instead */ - public static final int COLUMN_HEADER_MODE_ID = 0; + @Deprecated + public static final ColumnHeaderMode COLUMN_HEADER_MODE_ID = ColumnHeaderMode.ID; /** - * Column header mode: Column headers are explicitly specified with - * {@link #setColumnHeaders(String[])}. + * @deprecated from 7.0, use {@link ColumnHeaderMode#EXPLICIT} instead */ - public static final int COLUMN_HEADER_MODE_EXPLICIT = 1; + @Deprecated + public static final ColumnHeaderMode COLUMN_HEADER_MODE_EXPLICIT = ColumnHeaderMode.EXPLICIT; /** - * Column header mode: Column headers are explicitly specified with - * {@link #setColumnHeaders(String[])}. If a header is not specified for a - * given property, its property id is used instead. - * <p> - * <b>This is the default behavior. </b> + * @deprecated from 7.0, use {@link ColumnHeaderMode#EXPLICIT_DEFAULTS_ID} + * instead */ - public static final int COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = 2; + @Deprecated + public static final ColumnHeaderMode COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = ColumnHeaderMode.EXPLICIT_DEFAULTS_ID; + + public enum RowHeaderMode { + /** + * Row caption mode: The row headers are hidden. <b>This is the default + * mode. </b> + */ + HIDDEN(null), + /** + * Row caption mode: Items Id-objects toString is used as row caption. + */ + ID(ItemCaptionMode.ID), + /** + * Row caption mode: Item-objects toString is used as row caption. + */ + ITEM(ItemCaptionMode.ITEM), + /** + * Row caption mode: Index of the item is used as item caption. The + * index mode can only be used with the containers implementing the + * {@link com.vaadin.data.Container.Indexed} interface. + */ + INDEX(ItemCaptionMode.INDEX), + /** + * Row caption mode: Item captions are explicitly specified, but if the + * caption is missing, the item id objects <code>toString()</code> is + * used instead. + */ + EXPLICIT_DEFAULTS_ID(ItemCaptionMode.EXPLICIT_DEFAULTS_ID), + /** + * Row caption mode: Item captions are explicitly specified. + */ + EXPLICIT(ItemCaptionMode.EXPLICIT), + /** + * Row caption mode: Only icons are shown, the captions are hidden. + */ + ICON_ONLY(ItemCaptionMode.ICON_ONLY), + /** + * Row caption mode: Item captions are read from property specified with + * {@link #setItemCaptionPropertyId(Object)}. + */ + PROPERTY(ItemCaptionMode.PROPERTY); + + ItemCaptionMode mode; + + private RowHeaderMode(ItemCaptionMode mode) { + this.mode = mode; + } + + public ItemCaptionMode getItemCaptionMode() { + return mode; + } + } /** - * Row caption mode: The row headers are hidden. <b>This is the default - * mode. </b> + * @deprecated from 7.0, use {@link RowHeaderMode#HIDDEN} instead */ - public static final int ROW_HEADER_MODE_HIDDEN = -1; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_HIDDEN = RowHeaderMode.HIDDEN; /** - * Row caption mode: Items Id-objects toString is used as row caption. + * @deprecated from 7.0, use {@link RowHeaderMode#ID} instead */ - public static final int ROW_HEADER_MODE_ID = AbstractSelect.ITEM_CAPTION_MODE_ID; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_ID = RowHeaderMode.ID; /** - * Row caption mode: Item-objects toString is used as row caption. + * @deprecated from 7.0, use {@link RowHeaderMode#ITEM} instead */ - public static final int ROW_HEADER_MODE_ITEM = AbstractSelect.ITEM_CAPTION_MODE_ITEM; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_ITEM = RowHeaderMode.ITEM; /** - * Row caption mode: Index of the item is used as item caption. The index - * mode can only be used with the containers implementing Container.Indexed - * interface. + * @deprecated from 7.0, use {@link RowHeaderMode#INDEX} instead */ - public static final int ROW_HEADER_MODE_INDEX = AbstractSelect.ITEM_CAPTION_MODE_INDEX; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_INDEX = RowHeaderMode.INDEX; /** - * Row caption mode: Item captions are explicitly specified. + * @deprecated from 7.0, use {@link RowHeaderMode#EXPLICIT_DEFAULTS_ID} + * instead */ - public static final int ROW_HEADER_MODE_EXPLICIT = AbstractSelect.ITEM_CAPTION_MODE_EXPLICIT; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = RowHeaderMode.EXPLICIT_DEFAULTS_ID; /** - * Row caption mode: Item captions are read from property specified with - * {@link #setItemCaptionPropertyId(Object)}. + * @deprecated from 7.0, use {@link RowHeaderMode#EXPLICIT} instead */ - public static final int ROW_HEADER_MODE_PROPERTY = AbstractSelect.ITEM_CAPTION_MODE_PROPERTY; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_EXPLICIT = RowHeaderMode.EXPLICIT; /** - * Row caption mode: Only icons are shown, the captions are hidden. + * @deprecated from 7.0, use {@link RowHeaderMode#ICON_ONLY} instead */ - public static final int ROW_HEADER_MODE_ICON_ONLY = AbstractSelect.ITEM_CAPTION_MODE_ICON_ONLY; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_ICON_ONLY = RowHeaderMode.ICON_ONLY; /** - * Row caption mode: Item captions are explicitly specified, but if the - * caption is missing, the item id objects <code>toString()</code> is used - * instead. + * @deprecated from 7.0, use {@link RowHeaderMode#PROPERTY} instead */ - public static final int ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = AbstractSelect.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID; + @Deprecated + public static final RowHeaderMode ROW_HEADER_MODE_PROPERTY = RowHeaderMode.PROPERTY; /** * The default rate that table caches rows for smooth scrolling. @@ -222,7 +348,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Keymapper for column ids. */ - private final KeyMapper columnIdMap = new KeyMapper(); + private final KeyMapper<Object> columnIdMap = new KeyMapper<Object>(); /** * Holds visible column propertyIds - in order. @@ -252,7 +378,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Holds alignments for visible columns (by propertyId). */ - private HashMap<Object, String> columnAlignments = new HashMap<Object, String>(); + private HashMap<Object, Align> columnAlignments = new HashMap<Object, Align>(); /** * Holds column widths in pixels (Integer) or expand ratios (Float) for @@ -288,17 +414,17 @@ public class Table extends AbstractSelect implements Action.Container, /** * Holds value of property columnHeaderMode. */ - private int columnHeaderMode = COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID; + private ColumnHeaderMode columnHeaderMode = ColumnHeaderMode.EXPLICIT_DEFAULTS_ID; /** - * Should the Table footer be visible? + * Holds value of property rowHeaderMode. */ - private boolean columnFootersVisible = false; + private RowHeaderMode rowHeaderMode = RowHeaderMode.EXPLICIT_DEFAULTS_ID; /** - * True iff the row captions are hidden. + * Should the Table footer be visible? */ - private boolean rowCaptionsAreHidden = true; + private boolean columnFootersVisible = false; /** * Page contents buffer used in buffered mode. @@ -309,7 +435,7 @@ public class Table extends AbstractSelect implements Action.Container, * Set of properties listened - the list is kept to release the listeners * later. */ - private HashSet<Property> listenedProperties = null; + private HashSet<Property<?>> listenedProperties = null; /** * Set of visible components - the is used for needsRepaint calculation. @@ -324,7 +450,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Action mapper. */ - private KeyMapper actionMapper = null; + private KeyMapper<Action> actionMapper = null; /** * Table cell editor factory. @@ -404,10 +530,12 @@ public class Table extends AbstractSelect implements Action.Container, private RowGenerator rowGenerator = null; - private final Map<Field, Property> associatedProperties = new HashMap<Field, Property>(); + private final Map<Field<?>, Property<?>> associatedProperties = new HashMap<Field<?>, Property<?>>(); private boolean painted = false; + private HashMap<Object, Converter<String, Object>> propertyValueConverters = new HashMap<Object, Converter<String, Object>>(); + /* Table constructors */ /** @@ -508,7 +636,7 @@ public class Table extends AbstractSelect implements Action.Container, final Object col = i.next(); if (!newVC.contains(col)) { setColumnHeader(col, null); - setColumnAlignment(col, null); + setColumnAlignment(col, (Align) null); setColumnIcon(col, null); } } @@ -652,21 +780,21 @@ public class Table extends AbstractSelect implements Action.Container, * {@link #getVisibleColumns()}. The possible values for the alignments * include: * <ul> - * <li>{@link #ALIGN_LEFT}: Left alignment</li> - * <li>{@link #ALIGN_CENTER}: Centered</li> - * <li>{@link #ALIGN_RIGHT}: Right alignment</li> + * <li>{@link Align#LEFT}: Left alignment</li> + * <li>{@link Align#CENTER}: Centered</li> + * <li>{@link Align#RIGHT}: Right alignment</li> * </ul> - * The alignments default to {@link #ALIGN_LEFT}: any null values are + * The alignments default to {@link Align#LEFT}: any null values are * rendered as align lefts. * </p> * * @return the Column alignments array. */ - public String[] getColumnAlignments() { + public Align[] getColumnAlignments() { if (columnAlignments == null) { return null; } - final String[] alignments = new String[visibleColumns.size()]; + final Align[] alignments = new Align[visibleColumns.size()]; int i = 0; for (final Iterator<Object> it = visibleColumns.iterator(); it .hasNext(); i++) { @@ -680,39 +808,29 @@ public class Table extends AbstractSelect implements Action.Container, * Sets the column alignments. * * <p> - * The items in the array must match the properties identified by - * {@link #getVisibleColumns()}. The possible values for the alignments - * include: + * The amount of items in the array must match the amount of properties + * identified by {@link #getVisibleColumns()}. The possible values for the + * alignments include: * <ul> - * <li>{@link #ALIGN_LEFT}: Left alignment</li> - * <li>{@link #ALIGN_CENTER}: Centered</li> - * <li>{@link #ALIGN_RIGHT}: Right alignment</li> + * <li>{@link Align#LEFT}: Left alignment</li> + * <li>{@link Align#CENTER}: Centered</li> + * <li>{@link Align#RIGHT}: Right alignment</li> * </ul> - * The alignments default to {@link #ALIGN_LEFT} + * The alignments default to {@link Align#LEFT} * </p> * * @param columnAlignments * the Column alignments array. */ - public void setColumnAlignments(String[] columnAlignments) { + public void setColumnAlignments(Align... columnAlignments) { if (columnAlignments.length != visibleColumns.size()) { throw new IllegalArgumentException( "The length of the alignments array must match the number of visible columns"); } - // Checks all alignments - for (int i = 0; i < columnAlignments.length; i++) { - final String a = columnAlignments[i]; - if (a != null && !a.equals(ALIGN_LEFT) && !a.equals(ALIGN_CENTER) - && !a.equals(ALIGN_RIGHT)) { - throw new IllegalArgumentException("Column " + i - + " aligment '" + a + "' is invalid"); - } - } - // Resets the alignments - final HashMap<Object, String> newCA = new HashMap<Object, String>(); + final HashMap<Object, Align> newCA = new HashMap<Object, Align>(); int i = 0; for (final Iterator<Object> it = visibleColumns.iterator(); it .hasNext() && i < columnAlignments.length; i++) { @@ -1032,13 +1150,13 @@ public class Table extends AbstractSelect implements Action.Container, * @return the header for the specified column if it has one. */ public String getColumnHeader(Object propertyId) { - if (getColumnHeaderMode() == COLUMN_HEADER_MODE_HIDDEN) { + if (getColumnHeaderMode() == ColumnHeaderMode.HIDDEN) { return null; } String header = columnHeaders.get(propertyId); - if ((header == null && getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) - || getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) { + if ((header == null && getColumnHeaderMode() == ColumnHeaderMode.EXPLICIT_DEFAULTS_ID) + || getColumnHeaderMode() == ColumnHeaderMode.ID) { header = propertyId.toString(); } @@ -1071,9 +1189,9 @@ public class Table extends AbstractSelect implements Action.Container, * the propertyID identifying the column. * @return the specified column's alignment if it as one; null otherwise. */ - public String getColumnAlignment(Object propertyId) { - final String a = columnAlignments.get(propertyId); - return a == null ? ALIGN_LEFT : a; + public Align getColumnAlignment(Object propertyId) { + final Align a = columnAlignments.get(propertyId); + return a == null ? Align.LEFT : a; } /** @@ -1081,8 +1199,8 @@ public class Table extends AbstractSelect implements Action.Container, * * <p> * Throws IllegalArgumentException if the alignment is not one of the - * following: {@link #ALIGN_LEFT}, {@link #ALIGN_CENTER} or - * {@link #ALIGN_RIGHT} + * following: {@link Align#LEFT}, {@link Align#CENTER} or + * {@link Align#RIGHT} * </p> * * @param propertyId @@ -1090,17 +1208,8 @@ public class Table extends AbstractSelect implements Action.Container, * @param alignment * the desired alignment. */ - public void setColumnAlignment(Object propertyId, String alignment) { - - // Checks for valid alignments - if (alignment != null && !alignment.equals(ALIGN_LEFT) - && !alignment.equals(ALIGN_CENTER) - && !alignment.equals(ALIGN_RIGHT)) { - throw new IllegalArgumentException("Column alignment '" + alignment - + "' is not supported."); - } - - if (alignment == null || alignment.equals(ALIGN_LEFT)) { + public void setColumnAlignment(Object propertyId, Align alignment) { + if (alignment == null || alignment == Align.LEFT) { columnAlignments.remove(propertyId); } else { columnAlignments.put(propertyId, alignment); @@ -1400,7 +1509,7 @@ public class Table extends AbstractSelect implements Action.Container, * * @return the Value of property columnHeaderMode. */ - public int getColumnHeaderMode() { + public ColumnHeaderMode getColumnHeaderMode() { return columnHeaderMode; } @@ -1410,10 +1519,12 @@ public class Table extends AbstractSelect implements Action.Container, * @param columnHeaderMode * the New value of property columnHeaderMode. */ - public void setColumnHeaderMode(int columnHeaderMode) { - if (columnHeaderMode != this.columnHeaderMode - && columnHeaderMode >= COLUMN_HEADER_MODE_HIDDEN - && columnHeaderMode <= COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) { + public void setColumnHeaderMode(ColumnHeaderMode columnHeaderMode) { + if (columnHeaderMode == null) { + throw new IllegalArgumentException( + "Column header mode can not be null"); + } + if (columnHeaderMode != this.columnHeaderMode) { this.columnHeaderMode = columnHeaderMode; requestRepaint(); } @@ -1725,13 +1836,13 @@ public class Table extends AbstractSelect implements Action.Container, final Object[] colids = getVisibleColumns(); final int cols = colids.length; - HashSet<Property> oldListenedProperties = listenedProperties; + HashSet<Property<?>> oldListenedProperties = listenedProperties; HashSet<Component> oldVisibleComponents = visibleComponents; if (replaceListeners) { // initialize the listener collections, this should only be done if // the entire cache is refreshed (through refreshRenderedCells) - listenedProperties = new HashSet<Property>(); + listenedProperties = new HashSet<Property<?>>(); visibleComponents = new HashSet<Component>(); } @@ -1753,7 +1864,7 @@ public class Table extends AbstractSelect implements Action.Container, } } - final int headmode = getRowHeaderMode(); + final RowHeaderMode headmode = getRowHeaderMode(); final boolean[] iscomponent = new boolean[cols]; for (int i = 0; i < cols; i++) { iscomponent[i] = columnGenerators.containsKey(colids[i]) @@ -1774,7 +1885,7 @@ public class Table extends AbstractSelect implements Action.Container, cells[CELL_KEY][i] = itemIdMapper.key(id); if (headmode != ROW_HEADER_MODE_HIDDEN) { switch (headmode) { - case ROW_HEADER_MODE_INDEX: + case INDEX: cells[CELL_HEADER][i] = String.valueOf(i + firstIndex + 1); break; default: @@ -1791,7 +1902,7 @@ public class Table extends AbstractSelect implements Action.Container, if (isColumnCollapsed(colids[j])) { continue; } - Property p = null; + Property<?> p = null; Object value = ""; boolean isGeneratedRow = generatedRow != null; boolean isGeneratedColumn = columnGenerators @@ -1911,8 +2022,8 @@ public class Table extends AbstractSelect implements Action.Container, visibleComponents.add(component); } - private void listenProperty(Property p, - HashSet<Property> oldListenedProperties) { + private void listenProperty(Property<?> p, + HashSet<Property<?>> oldListenedProperties) { if (p instanceof Property.ValueChangeNotifier) { if (oldListenedProperties == null || !oldListenedProperties.contains(p)) { @@ -1952,7 +2063,7 @@ public class Table extends AbstractSelect implements Action.Container, visibleComponents.remove(cellVal); unregisterComponent((Component) cellVal); } else { - Property p = getContainerProperty( + Property<?> p = getContainerProperty( pageBuffer[CELL_ITEMID][i + ix], colids[c]); if (p instanceof ValueChangeNotifier && listenedProperties.contains(p)) { @@ -1977,7 +2088,7 @@ public class Table extends AbstractSelect implements Action.Container, * set of components that where attached in last render */ private void unregisterPropertiesAndComponents( - HashSet<Property> oldListenedProperties, + HashSet<Property<?>> oldListenedProperties, HashSet<Component> oldVisibleComponents) { if (oldVisibleComponents != null) { for (final Iterator<Component> i = oldVisibleComponents.iterator(); i @@ -1990,8 +2101,8 @@ public class Table extends AbstractSelect implements Action.Container, } if (oldListenedProperties != null) { - for (final Iterator<Property> i = oldListenedProperties.iterator(); i - .hasNext();) { + for (final Iterator<Property<?>> i = oldListenedProperties + .iterator(); i.hasNext();) { Property.ValueChangeNotifier o = (ValueChangeNotifier) i.next(); if (!listenedProperties.contains(o)) { o.removeListener(this); @@ -2024,8 +2135,8 @@ public class Table extends AbstractSelect implements Action.Container, * fields in memory. */ if (component instanceof Field) { - Field field = (Field) component; - Property associatedProperty = associatedProperties + Field<?> field = (Field<?>) component; + Property<?> associatedProperty = associatedProperties .remove(component); if (associatedProperty != null && field.getPropertyDataSource() == associatedProperty) { @@ -2073,17 +2184,17 @@ public class Table extends AbstractSelect implements Action.Container, * @param mode * the One of the modes listed above. */ - public void setRowHeaderMode(int mode) { - if (ROW_HEADER_MODE_HIDDEN == mode) { - rowCaptionsAreHidden = true; - } else { - rowCaptionsAreHidden = false; - setItemCaptionMode(mode); + public void setRowHeaderMode(RowHeaderMode mode) { + if (mode != null) { + rowHeaderMode = mode; + if (mode != RowHeaderMode.HIDDEN) { + setItemCaptionMode(mode.getItemCaptionMode()); + } + // Assures the visual refresh. No need to reset the page buffer + // before + // as the content has not changed, only the alignments. + refreshRenderedCells(); } - - // Assures the visual refresh. No need to reset the page buffer before - // as the content has not changed, only the alignments. - refreshRenderedCells(); } /** @@ -2092,9 +2203,8 @@ public class Table extends AbstractSelect implements Action.Container, * @return the Row header mode. * @see #setRowHeaderMode(int) */ - public int getRowHeaderMode() { - return rowCaptionsAreHidden ? ROW_HEADER_MODE_HIDDEN - : getItemCaptionMode(); + public RowHeaderMode getRowHeaderMode() { + return rowHeaderMode; } /** @@ -2491,7 +2601,7 @@ public class Table extends AbstractSelect implements Action.Container, (String) variables.get("action"), ","); if (st.countTokens() == 2) { final Object itemId = itemIdMapper.get(st.nextToken()); - final Action action = (Action) actionMapper.get(st.nextToken()); + final Action action = actionMapper.get(st.nextToken()); if (action != null && (itemId == null || containsId(itemId)) && actionHandlers != null) { @@ -2931,7 +3041,7 @@ public class Table extends AbstractSelect implements Action.Container, } private boolean areColumnHeadersEnabled() { - return getColumnHeaderMode() != COLUMN_HEADER_MODE_HIDDEN; + return getColumnHeaderMode() != ColumnHeaderMode.HIDDEN; } private void paintVisibleColumns(PaintTarget target) throws PaintException { @@ -2962,8 +3072,9 @@ public class Table extends AbstractSelect implements Action.Container, target.addAttribute("sortable", true); } } - if (!ALIGN_LEFT.equals(getColumnAlignment(colId))) { - target.addAttribute("align", getColumnAlignment(colId)); + if (!Align.LEFT.equals(getColumnAlignment(colId))) { + target.addAttribute("align", getColumnAlignment(colId) + .toString()); } paintColumnWidth(target, colId); target.endTag("column"); @@ -3253,7 +3364,7 @@ public class Table extends AbstractSelect implements Action.Container, target.addText(""); paintCellTooltips(target, itemId, columnId); } else { - c.paint(target); + LegacyPaint.paint(c, target); } } else { target.addText((String) cells[CELL_FIRSTCOL + currentColumn][indexInRowbuffer]); @@ -3409,8 +3520,8 @@ public class Table extends AbstractSelect implements Action.Container, protected Object getPropertyValue(Object rowId, Object colId, Property property) { if (isEditable() && fieldFactory != null) { - final Field f = fieldFactory.createField(getContainerDataSource(), - rowId, colId, this); + final Field<?> f = fieldFactory.createField( + getContainerDataSource(), rowId, colId, this); if (f != null) { // Remember that we have made this association so we can remove // it when the component is removed @@ -3464,11 +3575,27 @@ public class Table extends AbstractSelect implements Action.Container, * @since 3.1 */ protected String formatPropertyValue(Object rowId, Object colId, - Property property) { + Property<?> property) { if (property == null) { return ""; } - return property.toString(); + Converter<String, Object> converter = null; + + if (hasConverter(colId)) { + converter = getConverter(colId); + } else { + Application app = Application.getCurrentApplication(); + if (app != null) { + converter = (Converter<String, Object>) app + .getConverterFactory().createConverter(String.class, + property.getType()); + } + } + Object value = property.getValue(); + if (converter != null) { + return converter.convertToPresentation(value, getLocale()); + } + return (null != value) ? value.toString() : ""; } /* Action container */ @@ -3484,7 +3611,7 @@ public class Table extends AbstractSelect implements Action.Container, if (actionHandlers == null) { actionHandlers = new LinkedList<Handler>(); - actionMapper = new KeyMapper(); + actionMapper = new KeyMapper<Action>(); } if (!actionHandlers.contains(actionHandler)) { @@ -3711,7 +3838,7 @@ public class Table extends AbstractSelect implements Action.Container, */ public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue, String columnHeader, Resource columnIcon, - String columnAlignment) throws UnsupportedOperationException { + Align columnAlignment) throws UnsupportedOperationException { if (!this.addContainerProperty(propertyId, type, defaultValue)) { return false; } @@ -4029,44 +4156,6 @@ public class Table extends AbstractSelect implements Action.Container, } /** - * Gets the FieldFactory that is used to create editor for table cells. - * - * The FieldFactory is only used if the Table is editable. - * - * @return FieldFactory used to create the Field instances. - * @see #isEditable - * @deprecated use {@link #getTableFieldFactory()} instead - */ - @Deprecated - public FieldFactory getFieldFactory() { - if (fieldFactory instanceof FieldFactory) { - return (FieldFactory) fieldFactory; - - } - return null; - } - - /** - * Sets the FieldFactory that is used to create editor for table cells. - * - * The FieldFactory is only used if the Table is editable. By default the - * BaseFieldFactory is used. - * - * @param fieldFactory - * the field factory to set. - * @see #isEditable - * @see BaseFieldFactory - * @deprecated use {@link #setTableFieldFactory(TableFieldFactory)} instead - */ - @Deprecated - public void setFieldFactory(FieldFactory fieldFactory) { - this.fieldFactory = fieldFactory; - - // Assure visual refresh - refreshRowCache(); - } - - /** * Is table editable. * * If table is editable a editor of type Field is created for each table @@ -4377,27 +4466,8 @@ public class Table extends AbstractSelect implements Action.Container, } } - // Virtually identical to AbstractCompoenentContainer.setEnabled(); public void requestRepaintAll() { - requestRepaint(); - if (visibleComponents != null) { - for (Iterator<Component> childIterator = visibleComponents - .iterator(); childIterator.hasNext();) { - Component c = childIterator.next(); - if (c instanceof Form) { - // Form has children in layout, but is not - // ComponentContainer - c.requestRepaint(); - ((Form) c).getLayout().requestRepaintAll(); - } else if (c instanceof Table) { - ((Table) c).requestRepaintAll(); - } else if (c instanceof ComponentContainer) { - ((ComponentContainer) c).requestRepaintAll(); - } else { - c.requestRepaint(); - } - } - } + AbstractComponentContainer.requestRepaintAll(this); } /** @@ -5147,13 +5217,86 @@ public class Table extends AbstractSelect implements Action.Container, return rowGenerator; } + /** + * Sets a converter for a property id. + * <p> + * The converter is used to format the the data for the given property id + * before displaying it in the table. + * </p> + * + * @param propertyId + * The propertyId to format using the converter + * @param converter + * The converter to use for the property id + */ + public void setConverter(Object propertyId, Converter<String, ?> converter) { + if (!getContainerPropertyIds().contains(propertyId)) { + throw new IllegalArgumentException("PropertyId " + propertyId + + " must be in the container"); + } + // FIXME: This check should be here but primitive types like Boolean + // formatter for boolean property must be handled + + // if (!converter.getSourceType().isAssignableFrom(getType(propertyId))) + // { + // throw new IllegalArgumentException("Property type (" + // + getType(propertyId) + // + ") must match converter source type (" + // + converter.getSourceType() + ")"); + // } + propertyValueConverters.put(propertyId, + (Converter<String, Object>) converter); + refreshRowCache(); + } + + /** + * Checks if there is a converter set explicitly for the given property id. + * + * @param propertyId + * The propertyId to check + * @return true if a converter has been set for the property id, false + * otherwise + */ + protected boolean hasConverter(Object propertyId) { + return propertyValueConverters.containsKey(propertyId); + } + + /** + * Returns the converter used to format the given propertyId. + * + * @param propertyId + * The propertyId to check + * @return The converter used to format the propertyId or null if no + * converter has been set + */ + public Converter<String, Object> getConverter(Object propertyId) { + return propertyValueConverters.get(propertyId); + } + @Override public void setVisible(boolean visible) { - if (!isVisible() && visible) { + if (visible) { // We need to ensure that the rows are sent to the client when the // Table is made visible if it has been rendered as invisible. setRowCacheInvalidated(true); } super.setVisible(visible); } + + public Iterator<Component> iterator() { + return getComponentIterator(); + } + + public Iterator<Component> getComponentIterator() { + if (visibleComponents == null) { + Collection<Component> empty = Collections.emptyList(); + return empty.iterator(); + } + + return visibleComponents.iterator(); + } + + public boolean isComponentVisible(Component childComponent) { + return true; + } } diff --git a/src/com/vaadin/ui/TableFieldFactory.java b/src/com/vaadin/ui/TableFieldFactory.java index 9b0495d589..6c9a641aa8 100644 --- a/src/com/vaadin/ui/TableFieldFactory.java +++ b/src/com/vaadin/ui/TableFieldFactory.java @@ -39,7 +39,7 @@ public interface TableFieldFactory extends Serializable { * @return A field suitable for editing the specified data or null if the * property should not be editable. */ - Field createField(Container container, Object itemId, Object propertyId, + Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext); } diff --git a/src/com/vaadin/ui/TextArea.java b/src/com/vaadin/ui/TextArea.java index e1e5aeabd4..adb980818e 100644 --- a/src/com/vaadin/ui/TextArea.java +++ b/src/com/vaadin/ui/TextArea.java @@ -7,12 +7,10 @@ package com.vaadin.ui; import com.vaadin.data.Property; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VTextArea; /** * A text field that supports multi line editing. */ -@ClientWidget(VTextArea.class) public class TextArea extends AbstractTextField { private static final int DEFAULT_ROWS = 5; diff --git a/src/com/vaadin/ui/TextField.java b/src/com/vaadin/ui/TextField.java index 0d719efd12..567e9c1c10 100644 --- a/src/com/vaadin/ui/TextField.java +++ b/src/com/vaadin/ui/TextField.java @@ -5,10 +5,6 @@ package com.vaadin.ui; import com.vaadin.data.Property; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VTextField; -import com.vaadin.ui.ClientWidget.LoadStyle; /** * <p> @@ -31,30 +27,9 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(value = VTextField.class, loadStyle = LoadStyle.EAGER) public class TextField extends AbstractTextField { /** - * Tells if input is used to enter sensitive information that is not echoed - * to display. Typically passwords. - */ - @Deprecated - private boolean secret = false; - - /** - * Number of visible rows in a multiline TextField. Value 0 implies a - * single-line text-editor. - */ - @Deprecated - private int rows = 0; - - /** - * Tells if word-wrapping should be used in multiline mode. - */ - @Deprecated - private boolean wordwrap = true; - - /** * Constructs an empty <code>TextField</code> with no caption. */ public TextField() { @@ -106,7 +81,7 @@ public class TextField extends AbstractTextField { * * @param caption * the caption <code>String</code> for the editor. - * @param text + * @param value * the initial text content of the editor. */ public TextField(String caption, String value) { @@ -114,180 +89,4 @@ public class TextField extends AbstractTextField { setCaption(caption); } - /** - * Gets the secret property. If a field is used to enter secret information - * the information is not echoed to display. - * - * @return <code>true</code> if the field is used to enter secret - * information, <code>false</code> otherwise. - * - * @deprecated Starting from 6.5 use {@link PasswordField} instead for - * secret text input. - */ - @Deprecated - public boolean isSecret() { - return secret; - } - - /** - * Sets the secret property on and off. If a field is used to enter secret - * information the information is not echoed to display. - * - * @param secret - * the value specifying if the field is used to enter secret - * information. - * @deprecated Starting from 6.5 use {@link PasswordField} instead for - * secret text input. - */ - @Deprecated - public void setSecret(boolean secret) { - if (this.secret != secret) { - this.secret = secret; - requestRepaint(); - } - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (isSecret()) { - target.addAttribute("secret", true); - } - - final int rows = getRows(); - if (rows != 0) { - target.addAttribute("rows", rows); - target.addAttribute("multiline", true); - - if (!isWordwrap()) { - // Wordwrap is only painted if turned off to minimize - // communications - target.addAttribute("wordwrap", false); - } - } - - super.paintContent(target); - - } - - /** - * Gets the number of rows in the editor. If the number of rows is set to 0, - * the actual number of displayed rows is determined implicitly by the - * adapter. - * - * @return number of explicitly set rows. - * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text - * input. - * - */ - @Deprecated - public int getRows() { - return rows; - } - - /** - * Sets the number of rows in the editor. - * - * @param rows - * the number of rows for this editor. - * - * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text - * input. - */ - @Deprecated - public void setRows(int rows) { - if (rows < 0) { - rows = 0; - } - if (this.rows != rows) { - this.rows = rows; - requestRepaint(); - } - } - - /** - * Tests if the editor is in word-wrap mode. - * - * @return <code>true</code> if the component is in the word-wrap mode, - * <code>false</code> if not. - * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text - * input. - */ - @Deprecated - public boolean isWordwrap() { - return wordwrap; - } - - /** - * Sets the editor's word-wrap mode on or off. - * - * @param wordwrap - * the boolean value specifying if the editor should be in - * word-wrap mode after the call or not. - * - * @deprecated Starting from 6.5 use {@link TextArea} for a multi-line text - * input. - */ - @Deprecated - public void setWordwrap(boolean wordwrap) { - if (this.wordwrap != wordwrap) { - this.wordwrap = wordwrap; - requestRepaint(); - } - } - - /** - * Sets the height of the {@link TextField} instance. - * - * <p> - * Setting height for {@link TextField} also has a side-effect that puts - * {@link TextField} into multiline mode (aka "textarea"). Multiline mode - * can also be achieved by calling {@link #setRows(int)}. The height value - * overrides the number of rows set by {@link #setRows(int)}. - * <p> - * If you want to set height of single line {@link TextField}, call - * {@link #setRows(int)} with value 0 after setting the height. Setting rows - * to 0 resets the side-effect. - * <p> - * Starting from 6.5 you should use {@link TextArea} instead of - * {@link TextField} for multiline text input. - * - * - * @see com.vaadin.ui.AbstractComponent#setHeight(float, int) - */ - @Override - public void setHeight(float height, int unit) { - super.setHeight(height, unit); - if (height > 1 && getClass() == TextField.class) { - /* - * In html based terminals we most commonly want to make component - * to be textarea if height is defined. Setting row field above 0 - * will render component as textarea. - */ - - setRows(2); - } - } - - /** - * Sets the height of the {@link TextField} instance. - * - * <p> - * Setting height for {@link TextField} also has a side-effect that puts - * {@link TextField} into multiline mode (aka "textarea"). Multiline mode - * can also be achieved by calling {@link #setRows(int)}. The height value - * overrides the number of rows set by {@link #setRows(int)}. - * <p> - * If you want to set height of single line {@link TextField}, call - * {@link #setRows(int)} with value 0 after setting the height. Setting rows - * to 0 resets the side-effect. - * - * @see com.vaadin.ui.AbstractComponent#setHeight(java.lang.String) - */ - @Override - public void setHeight(String height) { - // will call setHeight(float, int) the actually does the magic. Method - // is overridden just to document side-effects. - super.setHeight(height); - } - } diff --git a/src/com/vaadin/ui/Tree.java b/src/com/vaadin/ui/Tree.java index 554afda97c..db738fee58 100644 --- a/src/com/vaadin/ui/Tree.java +++ b/src/com/vaadin/ui/Tree.java @@ -28,7 +28,6 @@ import com.vaadin.event.DataBoundTransferable; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.event.ItemClickEvent.ItemClickNotifier; -import com.vaadin.event.ItemClickEvent.ItemClickSource; import com.vaadin.event.Transferable; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DragSource; @@ -44,10 +43,11 @@ import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.ui.VTree; import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers; import com.vaadin.terminal.gwt.client.ui.dd.VTargetInSubtree; import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation; +import com.vaadin.terminal.gwt.client.ui.tree.TreeConnector; +import com.vaadin.terminal.gwt.client.ui.tree.VTree; import com.vaadin.tools.ReflectTools; /** @@ -60,10 +60,8 @@ import com.vaadin.tools.ReflectTools; * @since 3.0 */ @SuppressWarnings({ "serial", "deprecation" }) -@ClientWidget(VTree.class) public class Tree extends AbstractSelect implements Container.Hierarchical, - Action.Container, ItemClickSource, ItemClickNotifier, DragSource, - DropTarget { + Action.Container, ItemClickNotifier, DragSource, DropTarget { /* Private members */ @@ -80,7 +78,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, /** * Action mapper. */ - private KeyMapper actionMapper = null; + private KeyMapper<Action> actionMapper = null; /** * Is the tree selectable on the client side. @@ -447,7 +445,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, (String) variables.get("action"), ","); if (st.countTokens() == 2) { final Object itemId = itemIdMapper.get(st.nextToken()); - final Action action = (Action) actionMapper.get(st.nextToken()); + final Action action = actionMapper.get(st.nextToken()); if (action != null && (itemId == null || containsId(itemId)) && actionHandlers != null) { for (Handler ah : actionHandlers) { @@ -609,7 +607,8 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, if (itemStyleGenerator != null) { String stylename = itemStyleGenerator.getStyle(itemId); if (stylename != null) { - target.addAttribute("style", stylename); + target.addAttribute(TreeConnector.ATTRIBUTE_NODE_STYLE, + stylename); } } @@ -622,10 +621,12 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, } // Adds the attributes - target.addAttribute("caption", getItemCaption(itemId)); + target.addAttribute(TreeConnector.ATTRIBUTE_NODE_CAPTION, + getItemCaption(itemId)); final Resource icon = getItemIcon(itemId); if (icon != null) { - target.addAttribute("icon", getItemIcon(itemId)); + target.addAttribute(TreeConnector.ATTRIBUTE_NODE_ICON, + getItemIcon(itemId)); } final String key = itemIdMapper.key(itemId); target.addAttribute("key", key); @@ -682,10 +683,12 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, final Action a = i.next(); target.startTag("action"); if (a.getCaption() != null) { - target.addAttribute("caption", a.getCaption()); + target.addAttribute(TreeConnector.ATTRIBUTE_ACTION_CAPTION, + a.getCaption()); } if (a.getIcon() != null) { - target.addAttribute("icon", a.getIcon()); + target.addAttribute(TreeConnector.ATTRIBUTE_ACTION_ICON, + a.getIcon()); } target.addAttribute("key", actionMapper.key(a)); target.endTag("action"); @@ -1021,7 +1024,7 @@ public class Tree extends AbstractSelect implements Container.Hierarchical, if (actionHandlers == null) { actionHandlers = new LinkedList<Action.Handler>(); - actionMapper = new KeyMapper(); + actionMapper = new KeyMapper<Action>(); } if (!actionHandlers.contains(actionHandler)) { diff --git a/src/com/vaadin/ui/TreeTable.java b/src/com/vaadin/ui/TreeTable.java index 43bc7a80fe..9607add2c9 100644 --- a/src/com/vaadin/ui/TreeTable.java +++ b/src/com/vaadin/ui/TreeTable.java @@ -13,22 +13,21 @@ import java.util.List; import java.util.Map; import java.util.logging.Logger; -import com.google.gwt.user.client.ui.Tree; +import com.vaadin.data.Collapsible; import com.vaadin.data.Container; import com.vaadin.data.Container.Hierarchical; import com.vaadin.data.Container.ItemSetChangeEvent; import com.vaadin.data.util.ContainerHierarchicalWrapper; import com.vaadin.data.util.HierarchicalContainer; +import com.vaadin.data.util.HierarchicalContainerOrderedWrapper; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VTreeTable; +import com.vaadin.terminal.gwt.client.ui.treetable.TreeTableConnector; import com.vaadin.ui.Tree.CollapseEvent; import com.vaadin.ui.Tree.CollapseListener; import com.vaadin.ui.Tree.ExpandEvent; import com.vaadin.ui.Tree.ExpandListener; -import com.vaadin.ui.treetable.Collapsible; -import com.vaadin.ui.treetable.HierarchicalContainerOrderedWrapper; /** * TreeTable extends the {@link Table} component so that it can also visualize a @@ -48,7 +47,6 @@ import com.vaadin.ui.treetable.HierarchicalContainerOrderedWrapper; * share UI state in the container. */ @SuppressWarnings({ "serial" }) -@ClientWidget(VTreeTable.class) public class TreeTable extends Table implements Hierarchical { private static final Logger logger = Logger.getLogger(TreeTable.class @@ -454,7 +452,8 @@ public class TreeTable extends Table implements Hierarchical { Object object = visibleColumns2[i]; if (hierarchyColumnId.equals(object)) { target.addAttribute( - VTreeTable.ATTRIBUTE_HIERARCHY_COLUMN_INDEX, i); + TreeTableConnector.ATTRIBUTE_HIERARCHY_COLUMN_INDEX, + i); break; } } @@ -552,7 +551,9 @@ public class TreeTable extends Table implements Hierarchical { public void setContainerDataSource(Container newDataSource) { cStrategy = null; - containerSupportsPartialUpdates = (newDataSource instanceof ItemSetChangeNotifier); + // FIXME: This disables partial updates until TreeTable is fixed so it + // does not change component hierarchy during paint + containerSupportsPartialUpdates = (newDataSource instanceof ItemSetChangeNotifier) && false; if (!(newDataSource instanceof Hierarchical)) { newDataSource = new ContainerHierarchicalWrapper(newDataSource); diff --git a/src/com/vaadin/ui/TwinColSelect.java b/src/com/vaadin/ui/TwinColSelect.java index 1c1fe07a5c..5539236f77 100644 --- a/src/com/vaadin/ui/TwinColSelect.java +++ b/src/com/vaadin/ui/TwinColSelect.java @@ -9,14 +9,13 @@ import java.util.Collection; import com.vaadin.data.Container; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VTwinColSelect; +import com.vaadin.terminal.gwt.client.ui.twincolselect.VTwinColSelect; /** * Multiselect component with two lists: left side for available items and right * side for selected items. */ @SuppressWarnings("serial") -@ClientWidget(VTwinColSelect.class) public class TwinColSelect extends AbstractSelect { private int columns = 0; diff --git a/src/com/vaadin/ui/Upload.java b/src/com/vaadin/ui/Upload.java index 9d684291a5..4dff71e45b 100644 --- a/src/com/vaadin/ui/Upload.java +++ b/src/com/vaadin/ui/Upload.java @@ -15,10 +15,9 @@ import java.util.Map; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.StreamVariable.StreamingProgressEvent; -import com.vaadin.terminal.gwt.client.ui.VUpload; +import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.gwt.server.NoInputStreamException; import com.vaadin.terminal.gwt.server.NoOutputStreamException; -import com.vaadin.ui.ClientWidget.LoadStyle; /** * Component for uploading files from client to server. @@ -61,8 +60,8 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(value = VUpload.class, loadStyle = LoadStyle.LAZY) -public class Upload extends AbstractComponent implements Component.Focusable { +public class Upload extends AbstractComponent implements Component.Focusable, + Vaadin6Component { /** * Should the field be focused on next repaint? @@ -123,7 +122,6 @@ public class Upload extends AbstractComponent implements Component.Focusable { * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, * java.util.Map) */ - @Override public void changeVariables(Object source, Map<String, Object> variables) { if (variables.containsKey("pollForStart")) { int id = (Integer) variables.get("pollForStart"); @@ -143,7 +141,6 @@ public class Upload extends AbstractComponent implements Component.Focusable { * @throws PaintException * if the paint operation failed. */ - @Override public void paintContent(PaintTarget target) throws PaintException { if (notStarted) { target.addAttribute("notStarted", true); diff --git a/src/com/vaadin/ui/UriFragmentUtility.java b/src/com/vaadin/ui/UriFragmentUtility.java deleted file mode 100644 index 5eaffbde6f..0000000000 --- a/src/com/vaadin/ui/UriFragmentUtility.java +++ /dev/null @@ -1,153 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Map; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.VUriFragmentUtility; -import com.vaadin.ui.ClientWidget.LoadStyle; - -/** - * Experimental web browser dependent component for URI fragment (part after - * hash mark "#") reading and writing. - * - * Component can be used to workaround common ajax web applications pitfalls: - * bookmarking a program state and back button. - * - */ -@SuppressWarnings("serial") -@ClientWidget(value = VUriFragmentUtility.class, loadStyle = LoadStyle.EAGER) -public class UriFragmentUtility extends AbstractComponent { - - /** - * Listener that listens changes in URI fragment. - */ - public interface FragmentChangedListener extends Serializable { - - public void fragmentChanged(FragmentChangedEvent source); - - } - - /** - * Event fired when uri fragment changes. - */ - public class FragmentChangedEvent extends Component.Event { - - /** - * Creates a new instance of UriFragmentReader change event. - * - * @param source - * the Source of the event. - */ - public FragmentChangedEvent(Component source) { - super(source); - } - - /** - * Gets the UriFragmentReader where the event occurred. - * - * @return the Source of the event. - */ - public UriFragmentUtility getUriFragmentUtility() { - return (UriFragmentUtility) getSource(); - } - } - - private static final Method FRAGMENT_CHANGED_METHOD; - - static { - try { - FRAGMENT_CHANGED_METHOD = FragmentChangedListener.class - .getDeclaredMethod("fragmentChanged", - new Class[] { FragmentChangedEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in FragmentChangedListener"); - } - } - - public void addListener(FragmentChangedListener listener) { - addListener(FragmentChangedEvent.class, listener, - FRAGMENT_CHANGED_METHOD); - } - - public void removeListener(FragmentChangedListener listener) { - removeListener(FragmentChangedEvent.class, listener, - FRAGMENT_CHANGED_METHOD); - } - - private String fragment; - - public UriFragmentUtility() { - // immediate by default - setImmediate(true); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - target.addVariable(this, "fragment", fragment); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - fragment = (String) variables.get("fragment"); - fireEvent(new FragmentChangedEvent(this)); - } - - /** - * Gets currently set URI fragment. - * <p> - * To listen changes in fragment, hook a {@link FragmentChangedListener}. - * <p> - * Note that initial URI fragment that user used to enter the application - * will be read after application init. It fires FragmentChangedEvent only - * if it is not the same as on server side. - * - * @return the current fragment in browser uri or null if not known - */ - public String getFragment() { - return fragment; - } - - /** - * Sets URI fragment. Optionally fires a {@link FragmentChangedEvent} - * - * @param newFragment - * id of the new fragment - * @param fireEvent - * true to fire event - * @see FragmentChangedEvent - * @see FragmentChangedListener - */ - public void setFragment(String newFragment, boolean fireEvent) { - if ((newFragment == null && fragment != null) - || (newFragment != null && !newFragment.equals(fragment))) { - fragment = newFragment; - if (fireEvent) { - fireEvent(new FragmentChangedEvent(this)); - } - requestRepaint(); - } - } - - /** - * Sets URI fragment. This method fires a {@link FragmentChangedEvent} - * - * @param newFragment - * id of the new fragment - * @see FragmentChangedEvent - * @see FragmentChangedListener - */ - public void setFragment(String newFragment) { - setFragment(newFragment, true); - } - -} diff --git a/src/com/vaadin/ui/VerticalLayout.java b/src/com/vaadin/ui/VerticalLayout.java index c40aeaea30..a04d052d98 100644 --- a/src/com/vaadin/ui/VerticalLayout.java +++ b/src/com/vaadin/ui/VerticalLayout.java @@ -3,9 +3,6 @@ */ package com.vaadin.ui; -import com.vaadin.terminal.gwt.client.ui.VVerticalLayout; -import com.vaadin.ui.ClientWidget.LoadStyle; - /** * Vertical layout * @@ -19,7 +16,6 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * @since 5.3 */ @SuppressWarnings("serial") -@ClientWidget(value = VVerticalLayout.class, loadStyle = LoadStyle.EAGER) public class VerticalLayout extends AbstractOrderedLayout { public VerticalLayout() { diff --git a/src/com/vaadin/ui/VerticalSplitPanel.java b/src/com/vaadin/ui/VerticalSplitPanel.java index 699bd9287c..0630240e9c 100644 --- a/src/com/vaadin/ui/VerticalSplitPanel.java +++ b/src/com/vaadin/ui/VerticalSplitPanel.java @@ -3,9 +3,6 @@ */ package com.vaadin.ui; -import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical; -import com.vaadin.ui.ClientWidget.LoadStyle; - /** * A vertical split panel contains two components and lays them vertically. The * first component is above the second component. @@ -23,7 +20,6 @@ import com.vaadin.ui.ClientWidget.LoadStyle; * </pre> * */ -@ClientWidget(value = VSplitPanelVertical.class, loadStyle = LoadStyle.EAGER) public class VerticalSplitPanel extends AbstractSplitPanel { public VerticalSplitPanel() { diff --git a/src/com/vaadin/ui/Video.java b/src/com/vaadin/ui/Video.java index ed6588f96a..28fbfb0547 100644 --- a/src/com/vaadin/ui/Video.java +++ b/src/com/vaadin/ui/Video.java @@ -7,7 +7,7 @@ package com.vaadin.ui; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.VVideo; +import com.vaadin.terminal.gwt.client.ui.video.VideoConnector; /** * The Video component translates into an HTML5 <video> element and as @@ -30,7 +30,6 @@ import com.vaadin.terminal.gwt.client.ui.VVideo; * @author Vaadin Ltd * @since 6.7.0 */ -@ClientWidget(VVideo.class) public class Video extends AbstractMedia { private Resource poster; @@ -80,7 +79,7 @@ public class Video extends AbstractMedia { public void paintContent(PaintTarget target) throws PaintException { super.paintContent(target); if (getPoster() != null) { - target.addAttribute(VVideo.ATTR_POSTER, getPoster()); + target.addAttribute(VideoConnector.ATTR_POSTER, getPoster()); } } } diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java index 5f6c29f182..3c17baf414 100644 --- a/src/com/vaadin/ui/Window.java +++ b/src/com/vaadin/ui/Window.java @@ -6,15 +6,7 @@ package com.vaadin.ui; import java.io.Serializable; import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.Map; -import java.util.Set; import com.vaadin.Application; import com.vaadin.event.FieldEvents.BlurEvent; @@ -23,20 +15,17 @@ import com.vaadin.event.FieldEvents.BlurNotifier; import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.FieldEvents.FocusNotifier; +import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.ShortcutAction; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutAction.ModifierKey; import com.vaadin.event.ShortcutListener; -import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.ParameterHandler; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.URIHandler; -import com.vaadin.terminal.gwt.client.ui.VView; -import com.vaadin.terminal.gwt.client.ui.VWindow; +import com.vaadin.terminal.Vaadin6Component; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.ui.window.WindowServerRpc; +import com.vaadin.terminal.gwt.client.ui.window.WindowState; /** * A component that represents an application (browser native) window or a sub @@ -84,144 +73,15 @@ import com.vaadin.terminal.gwt.client.ui.VWindow; * @since 3.0 */ @SuppressWarnings("serial") -@ClientWidget(VWindow.class) -public class Window extends Panel implements URIHandler, ParameterHandler, - FocusNotifier, BlurNotifier { +public class Window extends Panel implements FocusNotifier, BlurNotifier, + Vaadin6Component { - /** - * <b>Application window only</b>. A border style used for opening resources - * in a window without a border. - */ - public static final int BORDER_NONE = 0; - - /** - * <b>Application window only</b>. A border style used for opening resources - * in a window with a minimal border. - */ - public static final int BORDER_MINIMAL = 1; - - /** - * <b>Application window only</b>. A border style that indicates that the - * default border style should be used when opening resources. - */ - public static final int BORDER_DEFAULT = 2; - - /** - * <b>Application window only</b>. The user terminal for this window. - */ - private Terminal terminal = null; - - /** - * <b>Application window only</b>. The application this window is attached - * to or null. - */ - private Application application = null; - - /** - * <b>Application window only</b>. List of URI handlers for this window. - */ - private LinkedList<URIHandler> uriHandlerList = null; - - /** - * <b>Application window only</b>. List of parameter handlers for this - * window. - */ - private LinkedList<ParameterHandler> parameterHandlerList = null; - - /** - * <b>Application window only</b>. List of sub windows in this window. A sub - * window cannot have other sub windows. - */ - private final LinkedHashSet<Window> subwindows = new LinkedHashSet<Window>(); - - /** - * <b>Application window only</b>. Explicitly specified theme of this window - * or null if the application theme should be used. - */ - private String theme = null; - - /** - * <b>Application window only</b>. Resources to be opened automatically on - * next repaint. The list is automatically cleared when it has been sent to - * the client. - */ - private final LinkedList<OpenResource> openList = new LinkedList<OpenResource>(); + private WindowServerRpc rpc = new WindowServerRpc() { - /** - * <b>Application window only</b>. Unique name of the window used to - * identify it. - */ - private String name = null; - - /** - * <b>Application window only.</b> Border mode of the Window. - */ - private int border = BORDER_DEFAULT; - - /** - * <b>Sub window only</b>. Top offset in pixels for the sub window (relative - * to the parent application window) or -1 if unspecified. - */ - private int positionY = -1; - - /** - * <b>Sub window only</b>. Left offset in pixels for the sub window - * (relative to the parent application window) or -1 if unspecified. - */ - private int positionX = -1; - - /** - * <b>Application window only</b>. A list of notifications that are waiting - * to be sent to the client. Cleared (set to null) when the notifications - * have been sent. - */ - private LinkedList<Notification> notifications; - - /** - * <b>Sub window only</b>. Modality flag for sub window. - */ - private boolean modal = false; - - /** - * <b>Sub window only</b>. Controls if the end user can resize the window. - */ - private boolean resizable = true; - - /** - * <b>Sub window only</b>. Controls if the end user can move the window by - * dragging. - */ - private boolean draggable = true; - - /** - * <b>Sub window only</b>. Flag which is true if the window is centered on - * the screen. - */ - private boolean centerRequested = false; - - /** - * Should resize recalculate layouts lazily (as opposed to immediately) - */ - private boolean resizeLazy = false; - - /** - * Component that should be focused after the next repaint. Null if no focus - * change should take place. - */ - private Focusable pendingFocus; - - /** - * <b>Application window only</b>. A list of javascript commands that are - * waiting to be sent to the client. Cleared (set to null) when the commands - * have been sent. - */ - private ArrayList<String> jsExecQueue = null; - - /** - * The component that should be scrolled into view after the next repaint. - * Null if nothing should be scrolled into view. - */ - private Component scrollIntoView; + public void click(MouseEventDetails mouseDetails) { + fireEvent(new ClickEvent(Window.this, mouseDetails)); + } + }; /** * Creates a new unnamed window with a default layout. @@ -250,7 +110,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, */ public Window(String caption, ComponentContainer content) { super(caption, content); - setScrollable(true); + registerRpc(rpc); setSizeUndefined(); } @@ -269,288 +129,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler, super.addComponent(c); } - /** - * <b>Application window only</b>. Gets the user terminal. - * - * @return the user terminal - */ - public Terminal getTerminal() { - return terminal; - } - /* ********************************************************************* */ - /** - * Gets the parent window of the component. - * <p> - * This is always the window itself. - * </p> - * <p> - * <b>This method is not meant to be overridden. Due to CDI requirements we - * cannot declare it as final even though it should be final.</b> - * </p> - * - * @see Component#getWindow() - * @return the window itself - */ - @Override - public Window getWindow() { - return this; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractComponent#getApplication() - */ - @Override - public Application getApplication() { - if (getParent() == null) { - return application; - } - return getParent().getApplication(); - } - - /** - * Gets the parent component of the window. - * - * <p> - * The parent of an application window is always null. The parent of a sub - * window is the application window the sub window is attached to. - * </p> - * <p> - * <b>This method is not meant to be overridden. Due to CDI requirements we - * cannot declare it as final even though it should be final.</b> - * </p> - * - * - * @return the parent window - * @see Component#getParent() - */ - @Override - public Window getParent() { - return (Window) super.getParent(); - } - - /* ********************************************************************* */ - - /** - * <b>Application window only</b>. Adds a new URI handler to this window. If - * this is a sub window the URI handler is attached to the parent - * application window. - * - * @param handler - * the URI handler to add. - */ - public void addURIHandler(URIHandler handler) { - if (getParent() != null) { - // this is subwindow, attach to main level instead - // TODO hold internal list also and remove on detach - Window mainWindow = getParent(); - mainWindow.addURIHandler(handler); - } else { - if (uriHandlerList == null) { - uriHandlerList = new LinkedList<URIHandler>(); - } - synchronized (uriHandlerList) { - if (!uriHandlerList.contains(handler)) { - uriHandlerList.addLast(handler); - } - } - } - } - - /** - * <b>Application window only</b>. Removes the URI handler from this window. - * If this is a sub window the URI handler is removed from the parent - * application window. - * - * @param handler - * the URI handler to remove. - */ - public void removeURIHandler(URIHandler handler) { - if (getParent() != null) { - // this is subwindow - Window mainWindow = getParent(); - mainWindow.removeURIHandler(handler); - } else { - if (handler == null || uriHandlerList == null) { - return; - } - synchronized (uriHandlerList) { - uriHandlerList.remove(handler); - if (uriHandlerList.isEmpty()) { - uriHandlerList = null; - } - } - } - } - - /** - * <b>Application window only</b>. Handles an URI by passing the URI to all - * URI handlers defined using {@link #addURIHandler(URIHandler)}. All URI - * handlers are called for each URI but no more than one handler may return - * a {@link DownloadStream}. If more than one stream is returned a - * {@code RuntimeException} is thrown. - * - * @param context - * The URL of the application - * @param relativeUri - * The URI relative to {@code context} - * @return A {@code DownloadStream} that one of the URI handlers returned, - * null if no {@code DownloadStream} was returned. - */ - public DownloadStream handleURI(URL context, String relativeUri) { - - DownloadStream result = null; - if (uriHandlerList != null) { - Object[] handlers; - synchronized (uriHandlerList) { - handlers = uriHandlerList.toArray(); - } - for (int i = 0; i < handlers.length; i++) { - final DownloadStream ds = ((URIHandler) handlers[i]).handleURI( - context, relativeUri); - if (ds != null) { - if (result != null) { - throw new RuntimeException("handleURI for " + context - + " uri: '" + relativeUri - + "' returns ambigious result."); - } - result = ds; - } - } - } - return result; - } - - /* ********************************************************************* */ - - /** - * <b>Application window only</b>. Adds a new parameter handler to this - * window. If this is a sub window the parameter handler is attached to the - * parent application window. - * - * @param handler - * the parameter handler to add. - */ - public void addParameterHandler(ParameterHandler handler) { - if (getParent() != null) { - // this is subwindow - // TODO hold internal list also and remove on detach - Window mainWindow = getParent(); - mainWindow.addParameterHandler(handler); - } else { - if (parameterHandlerList == null) { - parameterHandlerList = new LinkedList<ParameterHandler>(); - } - synchronized (parameterHandlerList) { - if (!parameterHandlerList.contains(handler)) { - parameterHandlerList.addLast(handler); - } - } - } - - } - - /** - * <b>Application window only</b>. Removes the parameter handler from this - * window. If this is a sub window the parameter handler is removed from the - * parent application window. - * - * @param handler - * the parameter handler to remove. - */ - public void removeParameterHandler(ParameterHandler handler) { - if (getParent() != null) { - // this is subwindow - Window mainWindow = getParent(); - mainWindow.removeParameterHandler(handler); - } else { - if (handler == null || parameterHandlerList == null) { - return; - } - synchronized (parameterHandlerList) { - parameterHandlerList.remove(handler); - if (parameterHandlerList.isEmpty()) { - parameterHandlerList = null; - } - } - } - } - - /** - * <b>Application window only</b>. Handles parameters by passing the - * parameters to all {@code ParameterHandler}s defined using - * {@link #addParameterHandler(ParameterHandler)}. All - * {@code ParameterHandler}s are called for each set of parameters. - * - * @param parameters - * a map containing the parameter names and values - * @see ParameterHandler#handleParameters(Map) - */ - public void handleParameters(Map<String, String[]> parameters) { - if (parameterHandlerList != null) { - Object[] handlers; - synchronized (parameterHandlerList) { - handlers = parameterHandlerList.toArray(); - } - for (int i = 0; i < handlers.length; i++) { - ((ParameterHandler) handlers[i]).handleParameters(parameters); - } - } - } - - /* ********************************************************************* */ - - /** - * <b>Application window only</b>. Gets the theme for this window. - * <p> - * If the theme for this window is not explicitly set, the application theme - * name is returned. If the window is not attached to an application, the - * terminal default theme name is returned. If the theme name cannot be - * determined, null is returned - * </p> - * <p> - * Subwindows do not support themes and return the theme used by the parent - * window - * </p> - * - * @return the name of the theme used for the window - */ - public String getTheme() { - if (getParent() != null) { - return (getParent()).getTheme(); - } - if (theme != null) { - return theme; - } - if ((application != null) && (application.getTheme() != null)) { - return application.getTheme(); - } - if (terminal != null) { - return terminal.getDefaultTheme(); - } - return null; - } - - /** - * <b>Application window only</b>. Sets the name of the theme to use for - * this window. Changing the theme will cause the page to be reloaded. - * - * @param theme - * the name of the new theme for this window or null to use the - * application theme. - */ - public void setTheme(String theme) { - if (getParent() != null) { - throw new UnsupportedOperationException( - "Setting theme for sub-windows is not supported."); - } - this.theme = theme; - requestRepaint(); - } - /* * (non-Javadoc) * @@ -559,505 +139,13 @@ public class Window extends Panel implements URIHandler, ParameterHandler, @Override public synchronized void paintContent(PaintTarget target) throws PaintException { - - // Sets the window name - final String name = getName(); - target.addAttribute("name", name == null ? "" : name); - - // Sets the window theme - final String theme = getTheme(); - target.addAttribute("theme", theme == null ? "" : theme); - - if (modal) { - target.addAttribute("modal", true); - } - - if (resizable) { - target.addAttribute("resizable", true); - } - if (resizeLazy) { - target.addAttribute(VView.RESIZE_LAZY, resizeLazy); - } - - if (!draggable) { - // Inverted to prevent an extra attribute for almost all sub windows - target.addAttribute("fixedposition", true); - } - if (bringToFront != null) { target.addAttribute("bringToFront", bringToFront.intValue()); bringToFront = null; } - if (centerRequested) { - target.addAttribute("center", true); - centerRequested = false; - } - - if (scrollIntoView != null) { - target.addAttribute("scrollTo", scrollIntoView); - scrollIntoView = null; - } - - // Marks the main window - if (getApplication() != null - && this == getApplication().getMainWindow()) { - target.addAttribute("main", true); - } - - if (getContent() != null) { - if (getContent().getHeightUnits() == Sizeable.UNITS_PERCENTAGE) { - target.addAttribute("layoutRelativeHeight", true); - } - if (getContent().getWidthUnits() == Sizeable.UNITS_PERCENTAGE) { - target.addAttribute("layoutRelativeWidth", true); - } - } - - // Open requested resource - synchronized (openList) { - if (!openList.isEmpty()) { - for (final Iterator<OpenResource> i = openList.iterator(); i - .hasNext();) { - (i.next()).paintContent(target); - } - openList.clear(); - } - } - // Contents of the window panel is painted super.paintContent(target); - - // Add executable javascripts if needed - if (jsExecQueue != null) { - for (String script : jsExecQueue) { - target.startTag("execJS"); - target.addAttribute("script", script); - target.endTag("execJS"); - } - jsExecQueue = null; - } - - // Window position - target.addVariable(this, "positionx", getPositionX()); - target.addVariable(this, "positiony", getPositionY()); - - // Window closing - target.addVariable(this, "close", false); - - if (getParent() == null) { - // Paint subwindows - for (final Iterator<Window> i = subwindows.iterator(); i.hasNext();) { - final Window w = i.next(); - w.paint(target); - } - } else { - // mark subwindows - target.addAttribute("sub", true); - } - - // Paint notifications - if (notifications != null) { - target.startTag("notifications"); - for (final Iterator<Notification> it = notifications.iterator(); it - .hasNext();) { - final Notification n = it.next(); - target.startTag("notification"); - if (n.getCaption() != null) { - target.addAttribute("caption", n.getCaption()); - } - if (n.getMessage() != null) { - target.addAttribute("message", n.getMessage()); - } - if (n.getIcon() != null) { - target.addAttribute("icon", n.getIcon()); - } - if (!n.isHtmlContentAllowed()) { - target.addAttribute( - VView.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true); - } - target.addAttribute("position", n.getPosition()); - target.addAttribute("delay", n.getDelayMsec()); - if (n.getStyleName() != null) { - target.addAttribute("style", n.getStyleName()); - } - target.endTag("notification"); - } - target.endTag("notifications"); - notifications = null; - } - - if (pendingFocus != null) { - // ensure focused component is still attached to this main window - if (pendingFocus.getWindow() == this - || (pendingFocus.getWindow() != null && pendingFocus - .getWindow().getParent() == this)) { - target.addAttribute("focused", pendingFocus); - } - pendingFocus = null; - } - - } - - /* ********************************************************************* */ - - /** - * Scrolls any component between the component and window to a suitable - * position so the component is visible to the user. The given component - * must be inside this window. - * - * @param component - * the component to be scrolled into view - * @throws IllegalArgumentException - * if {@code component} is not inside this window - */ - public void scrollIntoView(Component component) - throws IllegalArgumentException { - if (component.getWindow() != this) { - throw new IllegalArgumentException( - "The component where to scroll must be inside this window."); - } - scrollIntoView = component; - requestRepaint(); - } - - /** - * Opens the given resource in this window. The contents of this Window is - * replaced by the {@code Resource}. - * - * @param resource - * the resource to show in this window - */ - public void open(Resource resource) { - synchronized (openList) { - if (!openList.contains(resource)) { - openList.add(new OpenResource(resource, null, -1, -1, - BORDER_DEFAULT)); - } - } - requestRepaint(); - } - - /* ********************************************************************* */ - - /** - * Opens the given resource in a window with the given name. - * <p> - * The supplied {@code windowName} is used as the target name in a - * window.open call in the client. This means that special values such as - * "_blank", "_self", "_top", "_parent" have special meaning. An empty or - * <code>null</code> window name is also a special case. - * </p> - * <p> - * "", null and "_self" as {@code windowName} all causes the resource to be - * opened in the current window, replacing any old contents. For - * downloadable content you should avoid "_self" as "_self" causes the - * client to skip rendering of any other changes as it considers them - * irrelevant (the page will be replaced by the resource). This can speed up - * the opening of a resource, but it might also put the client side into an - * inconsistent state if the window content is not completely replaced e.g., - * if the resource is downloaded instead of displayed in the browser. - * </p> - * <p> - * "_blank" as {@code windowName} causes the resource to always be opened in - * a new window or tab (depends on the browser and browser settings). - * </p> - * <p> - * "_top" and "_parent" as {@code windowName} works as specified by the HTML - * standard. - * </p> - * <p> - * Any other {@code windowName} will open the resource in a window with that - * name, either by opening a new window/tab in the browser or by replacing - * the contents of an existing window with that name. - * </p> - * - * @param resource - * the resource. - * @param windowName - * the name of the window. - */ - public void open(Resource resource, String windowName) { - synchronized (openList) { - if (!openList.contains(resource)) { - openList.add(new OpenResource(resource, windowName, -1, -1, - BORDER_DEFAULT)); - } - } - requestRepaint(); - } - - /** - * Opens the given resource in a window with the given size, border and - * name. For more information on the meaning of {@code windowName}, see - * {@link #open(Resource, String)}. - * - * @param resource - * the resource. - * @param windowName - * the name of the window. - * @param width - * the width of the window in pixels - * @param height - * the height of the window in pixels - * @param border - * the border style of the window. See {@link #BORDER_NONE - * Window.BORDER_* constants} - */ - public void open(Resource resource, String windowName, int width, - int height, int border) { - synchronized (openList) { - if (!openList.contains(resource)) { - openList.add(new OpenResource(resource, windowName, width, - height, border)); - } - } - requestRepaint(); - } - - /* ********************************************************************* */ - - /** - * Gets the full URL of the window. The returned URL is window specific and - * can be used to directly refer to the window. - * <p> - * Note! This method can not be used for portlets. - * </p> - * - * @return the URL of the window or null if the window is not attached to an - * application - */ - public URL getURL() { - - if (application == null) { - return null; - } - - try { - return new URL(application.getURL(), getName() + "/"); - } catch (final MalformedURLException e) { - throw new RuntimeException( - "Internal problem getting window URL, please report"); - } - } - - /** - * <b>Application window only</b>. Gets the unique name of the window. The - * name of the window is used to uniquely identify it. - * <p> - * The name also determines the URL that can be used for direct access to a - * window. All windows can be accessed through - * {@code http://host:port/app/win} where {@code http://host:port/app} is - * the application URL (as returned by {@link Application#getURL()} and - * {@code win} is the window name. - * </p> - * <p> - * Note! Portlets do not support direct window access through URLs. - * </p> - * - * @return the Name of the Window. - */ - public String getName() { - return name; - } - - /** - * Returns the border style of the window. - * - * @see #setBorder(int) - * @return the border style for the window - */ - public int getBorder() { - return border; - } - - /** - * Sets the border style for this window. Valid values are - * {@link Window#BORDER_NONE}, {@link Window#BORDER_MINIMAL}, - * {@link Window#BORDER_DEFAULT}. - * <p> - * <b>Note!</b> Setting this seems to currently have no effect whatsoever on - * the window. - * </p> - * - * @param border - * the border style to set - */ - public void setBorder(int border) { - this.border = border; - } - - /** - * Sets the application this window is attached to. - * - * <p> - * This method is called by the framework and should not be called directly - * from application code. {@link com.vaadin.Application#addWindow(Window)} - * should be used to add the window to an application and - * {@link com.vaadin.Application#removeWindow(Window)} to remove the window - * from the application. - * </p> - * <p> - * This method invokes {@link Component#attach()} and - * {@link Component#detach()} methods when necessary. - * <p> - * - * @param application - * the application the window is attached to - */ - public void setApplication(Application application) { - - // If the application is not changed, dont do nothing - if (application == this.application) { - return; - } - - // Sends detach event if the window is connected to application - if (this.application != null) { - detach(); - } - - // Connects to new parent - this.application = application; - - // Sends the attach event if connected to a window - if (application != null) { - attach(); - } - } - - /** - * <b>Application window only</b>. Sets the unique name of the window. The - * name of the window is used to uniquely identify it inside the - * application. - * <p> - * The name also determines the URL that can be used for direct access to a - * window. All windows can be accessed through - * {@code http://host:port/app/win} where {@code http://host:port/app} is - * the application URL (as returned by {@link Application#getURL()} and - * {@code win} is the window name. - * </p> - * <p> - * This method can only be called before the window is added to an - * application. - * </p> - * <p> - * Note! Portlets do not support direct window access through URLs. - * </p> - * - * @param name - * the new name for the window or null if the application should - * automatically assign a name to it - * @throws IllegalStateException - * if the window is attached to an application - */ - public void setName(String name) throws IllegalStateException { - - // The name can not be changed in application - if (getApplication() != null) { - throw new IllegalStateException( - "Window name can not be changed while " - + "the window is in application"); - } - - this.name = name; - } - - /** - * Sets the user terminal. Used by the terminal adapter, should never be - * called from application code. - * - * @param type - * the terminal to set. - */ - public void setTerminal(Terminal type) { - terminal = type; - } - - /** - * Private class for storing properties related to opening resources. - */ - private class OpenResource implements Serializable { - - /** - * The resource to open - */ - private final Resource resource; - - /** - * The name of the target window - */ - private final String name; - - /** - * The width of the target window - */ - private final int width; - - /** - * The height of the target window - */ - private final int height; - - /** - * The border style of the target window - */ - private final int border; - - /** - * Creates a new open resource. - * - * @param resource - * The resource to open - * @param name - * The name of the target window - * @param width - * The width of the target window - * @param height - * The height of the target window - * @param border - * The border style of the target window - */ - private OpenResource(Resource resource, String name, int width, - int height, int border) { - this.resource = resource; - this.name = name; - this.width = width; - this.height = height; - this.border = border; - } - - /** - * Paints the open request. Should be painted inside the window. - * - * @param target - * the paint target - * @throws PaintException - * if the paint operation fails - */ - private void paintContent(PaintTarget target) throws PaintException { - target.startTag("open"); - target.addAttribute("src", resource); - if (name != null && name.length() > 0) { - target.addAttribute("name", name); - } - if (width >= 0) { - target.addAttribute("width", width); - } - if (height >= 0) { - target.addAttribute("height", height); - } - switch (border) { - case Window.BORDER_MINIMAL: - target.addAttribute("border", "minimal"); - break; - case Window.BORDER_NONE: - target.addAttribute("border", "none"); - break; - } - - target.endTag("open"); - } } /* @@ -1068,6 +156,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, @Override public void changeVariables(Object source, Map<String, Object> variables) { + // TODO Are these for top level windows or sub windows? boolean sizeHasChanged = false; // size is handled in super class, but resize events only in windows -> // so detect if size change occurs before super.changeVariables() @@ -1137,17 +226,15 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * {@link CloseListener}. * </p> */ - protected void close() { - Window parent = getParent(); - if (parent == null) { - fireClose(); - } else { + public void close() { + Root root = getRoot(); + // Don't do anything if not attached to a root + if (root != null) { // focus is restored to the parent window - parent.focus(); - - // subwindow is removed from parent - parent.removeWindow(this); + root.focus(); + // subwindow is removed from the root + root.removeWindow(this); } } @@ -1160,7 +247,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @since 4.0.0 */ public int getPositionX() { - return positionX; + return getState().getPositionX(); } /** @@ -1188,8 +275,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @since 6.3.4 */ private void setPositionX(int positionX, boolean repaintRequired) { - this.positionX = positionX; - centerRequested = false; + getState().setPositionX(positionX); + getState().setCentered(false); if (repaintRequired) { requestRepaint(); } @@ -1205,7 +292,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @since 4.0.0 */ public int getPositionY() { - return positionY; + return getState().getPositionY(); } /** @@ -1235,8 +322,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @since 6.3.4 */ private void setPositionY(int positionY, boolean repaintRequired) { - this.positionY = positionY; - centerRequested = false; + getState().setPositionY(positionY); + getState().setCentered(false); if (repaintRequired) { requestRepaint(); } @@ -1413,136 +500,53 @@ public class Window extends Panel implements URIHandler, ParameterHandler, fireEvent(new ResizeEvent(this)); } - private void attachWindow(Window w) { - subwindows.add(w); - w.setParent(this); - requestRepaint(); - } - - /** - * Adds a window inside another window. - * - * <p> - * Adding windows inside another window creates "subwindows". These windows - * should not be added to application directly and are not accessible - * directly with any url. Addding windows implicitly sets their parents. - * </p> - * - * <p> - * Only one level of subwindows are supported. Thus you can add windows - * inside such windows whose parent is <code>null</code>. - * </p> - * - * @param window - * @throws IllegalArgumentException - * if a window is added inside non-application level window. - * @throws NullPointerException - * if the given <code>Window</code> is <code>null</code>. - */ - public void addWindow(Window window) throws IllegalArgumentException, - NullPointerException { - - if (window == null) { - throw new NullPointerException("Argument must not be null"); - } - - if (window.getApplication() != null) { - throw new IllegalArgumentException( - "Window was already added to application" - + " - it can not be added to another window also."); - } else if (getParent() != null) { - throw new IllegalArgumentException( - "You can only add windows inside application-level windows."); - } else if (window.subwindows.size() > 0) { - throw new IllegalArgumentException( - "Only one level of subwindows are supported."); - } - - attachWindow(window); - } - /** - * Remove the given subwindow from this window. - * - * Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly - * removing a window by calling this method. - * - * Since Vaadin 6.5, returns a boolean indicating if the window was removed - * or not. - * - * @param window - * Window to be removed. - * @return true if the subwindow was removed, false otherwise - */ - public boolean removeWindow(Window window) { - if (!subwindows.remove(window)) { - // Window window is not a subwindow of this window. - return false; - } - window.setParent(null); - window.fireClose(); - requestRepaint(); - - return true; - } - - private Integer bringToFront = null; - - /* - * This sequesnce is used to keep the right order of windows if multiple - * windows are brought to front in a single changeset. Incremented and saved - * by childwindows. If sequence is not used, the order is quite random - * (depends on the order getting to dirty list. e.g. which window got + * Used to keep the right order of windows if multiple windows are brought + * to front in a single changeset. If this is not used, the order is quite + * random (depends on the order getting to dirty list. e.g. which window got * variable changes). */ - private int bringToFrontSequence = 0; + private Integer bringToFront = null; /** - * If there are currently several sub windows visible, calling this method - * makes this window topmost. + * If there are currently several windows visible, calling this method makes + * this window topmost. * <p> - * This method can only be called if this window is a sub window and - * connected a top level window. Else an illegal state exception is thrown. - * Also if there are modal windows and this window is not modal, and illegal - * state exception is thrown. + * This method can only be called if this window connected a root. Else an + * illegal state exception is thrown. Also if there are modal windows and + * this window is not modal, and illegal state exception is thrown. * <p> - * <strong> Note, this API works on sub windows only. Browsers can't reorder - * OS windows.</strong> */ public void bringToFront() { - Window parent = getParent(); - if (parent == null) { + Root root = getRoot(); + if (root == null) { throw new IllegalStateException( "Window must be attached to parent before calling bringToFront method."); } - for (Window w : parent.getChildWindows()) { - if (w.isModal() && !isModal()) { + int maxBringToFront = -1; + for (Window w : root.getWindows()) { + if (!isModal() && w.isModal()) { throw new IllegalStateException( - "There are modal windows currently visible, non-modal window cannot be brought to front."); + "The root contains modal windows, non-modal window cannot be brought to front."); + } + if (w.bringToFront != null) { + maxBringToFront = Math.max(maxBringToFront, + w.bringToFront.intValue()); } } - bringToFront = getParent().bringToFrontSequence++; + bringToFront = Integer.valueOf(maxBringToFront + 1); requestRepaint(); } /** - * Get the set of all child windows. - * - * @return Set of child windows. - */ - public Set<Window> getChildWindows() { - return Collections.unmodifiableSet(subwindows); - } - - /** * Sets sub-window modal, so that widgets behind it cannot be accessed. * <b>Note:</b> affects sub-windows only. * - * @param modality + * @param modal * true if modality is to be turned on */ - public void setModal(boolean modality) { - modal = modality; + public void setModal(boolean modal) { + getState().setModal(modal); center(); requestRepaint(); } @@ -1551,7 +555,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @return true if this window is modal. */ public boolean isModal() { - return modal; + return getState().isModal(); } /** @@ -1560,8 +564,8 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @param resizable * true if resizability is to be turned on */ - public void setResizable(boolean resizeability) { - resizable = resizeability; + public void setResizable(boolean resizable) { + getState().setResizable(resizable); requestRepaint(); } @@ -1570,7 +574,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * @return true if window is resizable by the end-user, otherwise false. */ public boolean isResizable() { - return resizable; + return getState().isResizable(); } /** @@ -1579,7 +583,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * sizes are recalculated immediately. */ public boolean isResizeLazy() { - return resizeLazy; + return getState().isResizeLazy(); } /** @@ -1595,7 +599,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * calculate immediately. */ public void setResizeLazy(boolean resizeLazy) { - this.resizeLazy = resizeLazy; + getState().setResizeLazy(resizeLazy); requestRepaint(); } @@ -1604,534 +608,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * sub-windows only. */ public void center() { - centerRequested = true; - requestRepaint(); - } - - /** - * Shows a notification message on the middle of the window. The message - * automatically disappears ("humanized message"). - * - * Care should be taken to to avoid XSS vulnerabilities as the caption is - * rendered as html. - * - * @see #showNotification(com.vaadin.ui.Window.Notification) - * @see Notification - * - * @param caption - * The message - */ - public void showNotification(String caption) { - addNotification(new Notification(caption)); - } - - /** - * Shows a notification message the window. The position and behavior of the - * message depends on the type, which is one of the basic types defined in - * {@link Notification}, for instance Notification.TYPE_WARNING_MESSAGE. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption is - * rendered as html. - * - * @see #showNotification(com.vaadin.ui.Window.Notification) - * @see Notification - * - * @param caption - * The message - * @param type - * The message type - */ - public void showNotification(String caption, int type) { - addNotification(new Notification(caption, type)); - } - - /** - * Shows a notification consisting of a bigger caption and a smaller - * description on the middle of the window. The message automatically - * disappears ("humanized message"). - * - * Care should be taken to to avoid XSS vulnerabilities as the caption and - * description are rendered as html. - * - * @see #showNotification(com.vaadin.ui.Window.Notification) - * @see Notification - * - * @param caption - * The caption of the message - * @param description - * The message description - * - */ - public void showNotification(String caption, String description) { - addNotification(new Notification(caption, description)); - } - - /** - * Shows a notification consisting of a bigger caption and a smaller - * description. The position and behavior of the message depends on the - * type, which is one of the basic types defined in {@link Notification}, - * for instance Notification.TYPE_WARNING_MESSAGE. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption and - * description are rendered as html. - * - * @see #showNotification(com.vaadin.ui.Window.Notification) - * @see Notification - * - * @param caption - * The caption of the message - * @param description - * The message description - * @param type - * The message type - */ - public void showNotification(String caption, String description, int type) { - addNotification(new Notification(caption, description, type)); - } - - /** - * Shows a notification consisting of a bigger caption and a smaller - * description. The position and behavior of the message depends on the - * type, which is one of the basic types defined in {@link Notification}, - * for instance Notification.TYPE_WARNING_MESSAGE. - * - * Care should be taken to avoid XSS vulnerabilities if html content is - * allowed. - * - * @see #showNotification(com.vaadin.ui.Window.Notification) - * @see Notification - * - * @param caption - * The message caption - * @param description - * The message description - * @param type - * The type of message - * @param htmlContentAllowed - * Whether html in the caption and description should be - * displayed as html or as plain text - */ - public void showNotification(String caption, String description, int type, - boolean htmlContentAllowed) { - addNotification(new Notification(caption, description, type, - htmlContentAllowed)); - } - - /** - * Shows a notification message. - * - * @see Notification - * @see #showNotification(String) - * @see #showNotification(String, int) - * @see #showNotification(String, String) - * @see #showNotification(String, String, int) - * - * @param notification - * The notification message to show - */ - public void showNotification(Notification notification) { - addNotification(notification); - } - - private void addNotification(Notification notification) { - if (notifications == null) { - notifications = new LinkedList<Notification>(); - } - notifications.add(notification); - requestRepaint(); - } - - /** - * This method is used by Component.Focusable objects to request focus to - * themselves. Focus renders must be handled at window level (instead of - * Component.Focusable) due we want the last focused component to be focused - * in client too. Not the one that is rendered last (the case we'd get if - * implemented in Focusable only). - * - * To focus component from Vaadin application, use Focusable.focus(). See - * {@link Focusable}. - * - * @param focusable - * to be focused on next paint - */ - void setFocusedComponent(Focusable focusable) { - if (getParent() != null) { - // focus is handled by main windows - (getParent()).setFocusedComponent(focusable); - } else { - pendingFocus = focusable; - requestRepaint(); - } - } - - /** - * A notification message, used to display temporary messages to the user - - * for example "Document saved", or "Save failed". - * <p> - * The notification message can consist of several parts: caption, - * description and icon. It is usually used with only caption - one should - * be wary of filling the notification with too much information. - * </p> - * <p> - * The notification message tries to be as unobtrusive as possible, while - * still drawing needed attention. There are several basic types of messages - * that can be used in different situations: - * <ul> - * <li>TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses - * the mouse or types something. It can be used to show fairly unimportant - * messages, such as feedback that an operation succeeded ("Document Saved") - * - the kind of messages the user ignores once the application is familiar. - * </li> - * <li>TYPE_WARNING_MESSAGE is shown for a short while after the user uses - * the mouse or types something. It's default style is also more noticeable - * than the humanized message. It can be used for messages that do not - * contain a lot of important information, but should be noticed by the - * user. Despite the name, it does not have to be a warning, but can be used - * instead of the humanized message whenever you want to make the message a - * little more noticeable.</li> - * <li>TYPE_ERROR_MESSAGE requires to user to click it before disappearing, - * and can be used for critical messages.</li> - * <li>TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner - * of the window, and can be used for "convenience notifications" that do - * not have to be noticed immediately, and should not interfere with the - * current task - for instance to show "You have a new message in your - * inbox" while the user is working in some other area of the application.</li> - * </ul> - * </p> - * <p> - * In addition to the basic pre-configured types, a Notification can also be - * configured to show up in a custom position, for a specified time (or - * until clicked), and with a custom stylename. An icon can also be added. - * </p> - * - */ - public static class Notification implements Serializable { - public static final int TYPE_HUMANIZED_MESSAGE = 1; - public static final int TYPE_WARNING_MESSAGE = 2; - public static final int TYPE_ERROR_MESSAGE = 3; - public static final int TYPE_TRAY_NOTIFICATION = 4; - - public static final int POSITION_CENTERED = 1; - public static final int POSITION_CENTERED_TOP = 2; - public static final int POSITION_CENTERED_BOTTOM = 3; - public static final int POSITION_TOP_LEFT = 4; - public static final int POSITION_TOP_RIGHT = 5; - public static final int POSITION_BOTTOM_LEFT = 6; - public static final int POSITION_BOTTOM_RIGHT = 7; - - public static final int DELAY_FOREVER = -1; - public static final int DELAY_NONE = 0; - - private String caption; - private String description; - private Resource icon; - private int position = POSITION_CENTERED; - private int delayMsec = 0; - private String styleName; - private boolean htmlContentAllowed; - - /** - * Creates a "humanized" notification message. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption - * is by default rendered as html. - * - * @param caption - * The message to show - */ - public Notification(String caption) { - this(caption, null, TYPE_HUMANIZED_MESSAGE); - } - - /** - * Creates a notification message of the specified type. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption - * is by default rendered as html. - * - * @param caption - * The message to show - * @param type - * The type of message - */ - public Notification(String caption, int type) { - this(caption, null, type); - } - - /** - * Creates a "humanized" notification message with a bigger caption and - * smaller description. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption - * and description are by default rendered as html. - * - * @param caption - * The message caption - * @param description - * The message description - */ - public Notification(String caption, String description) { - this(caption, description, TYPE_HUMANIZED_MESSAGE); - } - - /** - * Creates a notification message of the specified type, with a bigger - * caption and smaller description. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption - * and description are by default rendered as html. - * - * @param caption - * The message caption - * @param description - * The message description - * @param type - * The type of message - */ - public Notification(String caption, String description, int type) { - this(caption, description, type, true); - } - - /** - * Creates a notification message of the specified type, with a bigger - * caption and smaller description. - * - * Care should be taken to to avoid XSS vulnerabilities if html is - * allowed. - * - * @param caption - * The message caption - * @param description - * The message description - * @param type - * The type of message - * @param htmlContentAllowed - * Whether html in the caption and description should be - * displayed as html or as plain text - */ - public Notification(String caption, String description, int type, - boolean htmlContentAllowed) { - this.caption = caption; - this.description = description; - this.htmlContentAllowed = htmlContentAllowed; - setType(type); - } - - private void setType(int type) { - switch (type) { - case TYPE_WARNING_MESSAGE: - delayMsec = 1500; - styleName = "warning"; - break; - case TYPE_ERROR_MESSAGE: - delayMsec = -1; - styleName = "error"; - break; - case TYPE_TRAY_NOTIFICATION: - delayMsec = 3000; - position = POSITION_BOTTOM_RIGHT; - styleName = "tray"; - - case TYPE_HUMANIZED_MESSAGE: - default: - break; - } - - } - - /** - * Gets the caption part of the notification message. - * - * @return The message caption - */ - public String getCaption() { - return caption; - } - - /** - * Sets the caption part of the notification message - * - * @param caption - * The message caption - */ - public void setCaption(String caption) { - this.caption = caption; - } - - /** - * @deprecated Use {@link #getDescription()} instead. - * @return - */ - @Deprecated - public String getMessage() { - return description; - } - - /** - * @deprecated Use {@link #setDescription(String)} instead. - * @param description - */ - @Deprecated - public void setMessage(String description) { - this.description = description; - } - - /** - * Gets the description part of the notification message. - * - * @return The message description. - */ - public String getDescription() { - return description; - } - - /** - * Sets the description part of the notification message. - * - * @param description - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * Gets the position of the notification message. - * - * @return The position - */ - public int getPosition() { - return position; - } - - /** - * Sets the position of the notification message. - * - * @param position - * The desired notification position - */ - public void setPosition(int position) { - this.position = position; - } - - /** - * Gets the icon part of the notification message. - * - * @return The message icon - */ - public Resource getIcon() { - return icon; - } - - /** - * Sets the icon part of the notification message. - * - * @param icon - * The desired message icon - */ - public void setIcon(Resource icon) { - this.icon = icon; - } - - /** - * Gets the delay before the notification disappears. - * - * @return the delay in msec, -1 indicates the message has to be - * clicked. - */ - public int getDelayMsec() { - return delayMsec; - } - - /** - * Sets the delay before the notification disappears. - * - * @param delayMsec - * the desired delay in msec, -1 to require the user to click - * the message - */ - public void setDelayMsec(int delayMsec) { - this.delayMsec = delayMsec; - } - - /** - * Sets the style name for the notification message. - * - * @param styleName - * The desired style name. - */ - public void setStyleName(String styleName) { - this.styleName = styleName; - } - - /** - * Gets the style name for the notification message. - * - * @return - */ - public String getStyleName() { - return styleName; - } - - /** - * Sets whether html is allowed in the caption and description. If set - * to true, the texts are passed to the browser as html and the - * developer is responsible for ensuring no harmful html is used. If set - * to false, the texts are passed to the browser as plain text. - * - * @param htmlContentAllowed - * true if the texts are used as html, false if used as plain - * text - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - this.htmlContentAllowed = htmlContentAllowed; - } - - /** - * Checks whether caption and description are interpreted as html or - * plain text. - * - * @return true if the texts are used as html, false if used as plain - * text - * @see #setHtmlContentAllowed(boolean) - */ - public boolean isHtmlContentAllowed() { - return htmlContentAllowed; - } - } - - /** - * Executes JavaScript in this window. - * - * <p> - * This method allows one to inject javascript from the server to client. A - * client implementation is not required to implement this functionality, - * but currently all web-based clients do implement this. - * </p> - * - * <p> - * Executing javascript this way often leads to cross-browser compatibility - * issues and regressions that are hard to resolve. Use of this method - * should be avoided and instead it is recommended to create new widgets - * with GWT. For more info on creating own, reusable client-side widgets in - * Java, read the corresponding chapter in Book of Vaadin. - * </p> - * - * @param script - * JavaScript snippet that will be executed. - */ - public void executeJavaScript(String script) { - - if (getParent() != null) { - throw new UnsupportedOperationException( - "Only application level windows can execute javascript."); - } - - if (jsExecQueue == null) { - jsExecQueue = new ArrayList<String>(); - } - - jsExecQueue.add(script); - + getState().setCentered(true); requestRepaint(); } @@ -2183,7 +660,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * true if the sub window can be dragged by the user */ public boolean isDraggable() { - return draggable; + return getState().isDraggable(); } /** @@ -2196,7 +673,7 @@ public class Window extends Panel implements URIHandler, ParameterHandler, * true if the sub window can be dragged by the user */ public void setDraggable(boolean draggable) { - this.draggable = draggable; + getState().setDraggable(draggable); requestRepaint(); } @@ -2344,40 +821,18 @@ public class Window extends Panel implements URIHandler, ParameterHandler, */ @Override public void focus() { - if (getParent() != null) { - /* - * When focusing a sub-window it basically means it should be - * brought to the front. Instead of just moving the keyboard focus - * we focus the window and bring it top-most. - */ - bringToFront(); - } else { - super.focus(); - } - } - - /** - * Notifies the child components and subwindows that the window is attached - * to the application. - */ - @Override - public void attach() { - super.attach(); - for (Window w : subwindows) { - w.attach(); - } + /* + * When focusing a sub-window it basically means it should be brought to + * the front. Instead of just moving the keyboard focus we focus the + * window and bring it top-most. + */ + super.focus(); + bringToFront(); } - /** - * Notifies the child components and subwindows that the window is detached - * from the application. - */ @Override - public void detach() { - super.detach(); - for (Window w : subwindows) { - w.detach(); - } + public WindowState getState() { + return (WindowState) super.getState(); } } diff --git a/src/com/vaadin/ui/themes/BaseTheme.java b/src/com/vaadin/ui/themes/BaseTheme.java index c652a8a675..6f448746bf 100644 --- a/src/com/vaadin/ui/themes/BaseTheme.java +++ b/src/com/vaadin/ui/themes/BaseTheme.java @@ -50,4 +50,10 @@ public class BaseTheme { */ public static final String TREE_CONNECTORS = "connectors"; + /** + * Clips the component so it will be constrained to its given size and not + * overflow. + */ + public static final String CLIP = "v-clip"; + }
\ No newline at end of file diff --git a/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html b/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html index d97a9dce4a..85258d7036 100644 --- a/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html +++ b/tests/integration-testscripts/GateIn-3/integration-test-GateIn-3.1.0-portlet2.html @@ -118,7 +118,7 @@ </tr> <tr> <td>mouseClickAndWait</td> - <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div/div[5]/div/div/a</td> + <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div[5]/div/a</td> <td>10,10</td> </tr> <tr> @@ -138,7 +138,7 @@ </tr> <tr> <td>mouseClickAndWait</td> - <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div/div[5]/div/div/a</td> + <td>//div[@id='UIPage']/div/div/div[2]/div/div/div/div/div/div/div[2]/div[5]/div/a</td> <td>15,8</td> </tr> <tr> diff --git a/tests/integration-testscripts/common/integration_test.tpl b/tests/integration-testscripts/common/integration_test.tpl index 4275d3fab0..ed97710282 100644 --- a/tests/integration-testscripts/common/integration_test.tpl +++ b/tests/integration-testscripts/common/integration_test.tpl @@ -18,7 +18,7 @@ </tr> <tr> <td>pause</td> - <td>500</td> + <td>1000</td> <td></td> </tr> <tr> diff --git a/tests/integration_tests.xml b/tests/integration_tests.xml index 1270807630..7f72758a37 100644 --- a/tests/integration_tests.xml +++ b/tests/integration_tests.xml @@ -1,6 +1,10 @@ <?xml version="1.0"?> -<project name="Vaadin Integration Tests" basedir="." default="integration-test-all"> +<project xmlns:antcontrib="antlib:net.sf.antcontrib" + name="Vaadin Integration Tests" basedir="." default="integration-test-all"> + + <!-- Import common targets --> + <import file="../build/common.xml" /> <!-- Target deploying demo.war --> <fail unless="test.integration.server" message="test.integration.server must be set for integration tests to run" /> @@ -28,13 +32,6 @@ <property name="user" value="${test.integration.user}" /> <property name="passphrase" value="" /> - <!-- add ant contrib --> - <taskdef resource="net/sf/antcontrib/antcontrib.properties"> - <classpath> - <pathelement location="../build/lib/ant-contrib-1.0b3.jar" /> - </classpath> - </taskdef> - <!-- Upload war to deploy to ssh host --> <target name="integration-test-upload-demo"> <scp file="${demo.war}" todir="${user}@${test.integration.server}:integration-tests/servers/demo.war" keyfile="${sshkey.file}" passphrase="${passphrase}" /> @@ -100,14 +97,6 @@ <param name="target-server" value="tomcat7" /> </antcall> </target> - - <target name="integration-test-tomcat4"> - <antcall target="run-generic-integration-test"> - <param name="startDelay" value="10" /> - <param name="target-server" value="tomcat4" /> - </antcall> - </target> - <target name="integration-test-tomcat5"> <antcall target="run-generic-integration-test"> <param name="startDelay" value="10" /> @@ -142,17 +131,11 @@ <target name="integration-test-jetty8"> <antcall target="run-generic-integration-test"> + <param name="startDelay" value="300" /> <param name="target-server" value="jetty8" /> </antcall> </target> - <target name="integration-test-jboss3"> - <antcall target="run-generic-integration-test"> - <param name="startDelay" value="10" /> - <param name="target-server" value="jboss3" /> - </antcall> - </target> - <target name="integration-test-jboss4"> <antcall target="run-generic-integration-test"> <param name="startDelay" value="10" /> @@ -302,10 +285,9 @@ </target> <!-- Upload demo, clean error screenshots and test deployment on all servers --> - <target name="integration-test-all"> - + <target name="integration-test-all" depends="common.init-deps"> <parallel> - <trycatch property="tried"> + <antcontrib:trycatch property="tried"> <try> <!-- Still running GAE test from the old server which requires its own lock --> <echo message="Getting lock" /> @@ -326,8 +308,7 @@ <catch> <echo message="Uploading of demo.war failed. ${tried}" /> </catch> - </trycatch> - + </antcontrib:trycatch> <antcall target="integration-test-liferay6" /> <antcall target="integration-test-liferay6ee" /> <antcall target="integration-test-exo3" /> @@ -339,7 +320,6 @@ <antcall target="integration-test-gatein3" /> <antcall target="integration-test-glassfish2" /> <antcall target="integration-test-glassfish3" /> - <antcall target="integration-test-jboss3" /> <antcall target="integration-test-jboss4" /> <antcall target="integration-test-jboss5" /> <antcall target="integration-test-jboss6" /> @@ -348,7 +328,6 @@ <antcall target="integration-test-jetty6" /> <antcall target="integration-test-jetty7" /> <antcall target="integration-test-jetty8" /> - <antcall target="integration-test-tomcat4" /> <antcall target="integration-test-tomcat5" /> <antcall target="integration-test-tomcat6" /> <antcall target="integration-test-tomcat7" /> @@ -361,31 +340,30 @@ <target name="do-run-generic-test"> <property name="target-host" value="${target-server}.devnet.vaadin.com" /> <property name="target-port" value="8080" /> - - <if> + <antcontrib:if> <isset property="startDelay" /> <then> - <math result="sleepTime" datatype="int"> + <antcontrib:math result="sleepTime" datatype="int"> <op op="rint"> <op op="*"> <num value="${startDelay}" /> <op op="random" /> </op> </op> - </math> - <echo>Delaying startup of ${target-server} with ${sleepTime} seconds</echo> + </antcontrib:math> + <echo>Delaying startup of ${target-server} with ${sleepTime} seconds</echo> <sleep seconds="${sleepTime}" /> </then> - </if> - - <scp todir="${user}@${target-host}:." keyfile="${sshkey.file}" trust="yes" passphrase="${passphrase}"> + </antcontrib:if> + + <scp todir="${user}@${target-host}:." keyfile="${sshkey.file}" trust="yes" passphrase="${passphrase}" > <fileset dir="integration_base_files"> <include name="*" /> </fileset> </scp> <!-- trycatch probably not needed any more as it just fails with the original message and doesn't do anything in the finally block --> - <trycatch property="error_message"> + <antcontrib:trycatch property="error_message"> <try> <!-- timeout in one hour (remote end should timeout in 55 minutes) --> <sshexec host="${target-host}" outputproperty="lock-output" timeout="3600000" username="${user}" keyfile="${sshkey.file}" trust="yes" command="chmod +x *.sh; ant -f deploy.xml get-lock" /> @@ -418,16 +396,16 @@ </antcall> <!-- Run theme tests in all browsers if there's a property with the test files --> - <if> + <antcontrib:if> <isset property="testfiles-theme" /> - <then> + <antcontrib:then> <antcall target="integration-test-theme"> <param name="server-name" value="${target-server}" /> <param name="deployment.url" value="http://${target-host}:${target-port}" /> </antcall> - </then> - </if> - + </antcontrib:then> + </antcontrib:if> + <!-- timeout in five minutes --> <sshexec host="${target-host}" outputproperty="stop-output" timeout="600000" username="${user}" keyfile="${sshkey.file}" trust="yes" command="ant -f deploy.xml shutdown-and-cleanup" failonerror="false" /> <antcall target="echo-prefix"> @@ -438,28 +416,28 @@ <catch> <fail message="${error_message}" /> </catch> - </trycatch> + </antcontrib:trycatch> </target> <target name="echo-prefix"> - <propertyregex property="message-prefixed" input="${prefix}${message}" regexp="\n" replace="\0${prefix}" global="true" defaultValue="${prefix}${message}" /> + <antcontrib:propertyregex property="message-prefixed" input="${prefix}${message}" regexp="\n" replace="\0${prefix}" global="true" defaultValue="${prefix}${message}" /> <echo message="${message-prefixed}" /> </target> <target name="run-generic-integration-test"> <concat>##teamcity[testStarted name='${target-server}' flowId='${target-server}']</concat> - <trycatch property="tried"> + <antcontrib:trycatch property="tried"> <try> <antcall target="do-run-generic-test" /> </try> <catch> - <antcallback target="teamcity-escape" return="tried-escaped"> + <antcontrib:antcallback target="teamcity-escape" return="tried-escaped"> <param name="returnTo" value="tried-escaped" /> <param name="message" value="${tried}" /> - </antcallback> + </antcontrib:antcallback> <concat>##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}']</concat> </catch> - </trycatch> + </antcontrib:trycatch> <concat>##teamcity[testFinished name='${target-server}' flowId='${target-server}']"</concat> </target> @@ -468,16 +446,16 @@ <!-- Should also perform other escaping (\u0085, \u2028 and \u2029) - see http://confluence.jetbrains.net/display/TCD65/Build+Script+Interaction+with+TeamCity --> <!-- Immutable properties -> needs to create a new one every time --> - <propertyregex property="details-escaped1" input="${message}" regexp="['|\[\]]" replace="|\0" global="true" defaultValue="${message}" /> - <propertyregex property="details-escaped2" input="${details-escaped1}" regexp="\n" replace="|n" global="true" defaultValue="${details-escaped1}" /> - <propertyregex property="details-escaped3" input="${details-escaped2}" regexp="\r" replace="|r" global="true" defaultValue="${details-escaped2}" /> + <antcontrib:propertyregex property="details-escaped1" input="${message}" regexp="['|\[\]]" replace="|\0" global="true" defaultValue="${message}" /> + <antcontrib:propertyregex property="details-escaped2" input="${details-escaped1}" regexp="\n" replace="|n" global="true" defaultValue="${details-escaped1}" /> + <antcontrib:propertyregex property="details-escaped3" input="${details-escaped2}" regexp="\r" replace="|r" global="true" defaultValue="${details-escaped2}" /> <property name="${returnTo}" value="${details-escaped3}" /> </target> <target name="run-integration-test"> <concat>##teamcity[testStarted name='${target-server}' flowId='${target-server}']</concat> - <trycatch property="tried"> + <antcontrib:trycatch property="tried"> <try> <antcall target="integration-test-${target-server}" /> </try> @@ -488,7 +466,7 @@ </antcallback> <concat>##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}']"</concat> </catch> - </trycatch> + </antcontrib:trycatch> <concat>##teamcity[testFinished name='${target-server}' flowId='${target-server}']"</concat> </target> @@ -504,4 +482,4 @@ <target name="integration-test-clean"> <sshexec host="${test.integration.server}" username="${user}" keyfile="${sshkey.file}" command="ant -f ${ant.hub} clean" /> </target> -</project>
\ No newline at end of file +</project> diff --git a/tests/ivy.xml b/tests/ivy.xml new file mode 100644 index 0000000000..6c7171166b --- /dev/null +++ b/tests/ivy.xml @@ -0,0 +1,16 @@ +<ivy-module version="2.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation= "http://ant.apache.org/ivy/schemas/ivy.xsd"> + + <info organisation="com.vaadin" module="tests"/> + <configurations> + <conf name="jetty" visibility="private" /> + <conf name="emma" visibility="private" /> + <conf name="server" visibility="private" /> + </configurations> + <publications /> + <dependencies> + <dependency org="org.mortbay.jetty" name="jetty" rev="6.1.7" conf="server,jetty->default(*)" /> + <dependency org="emma" name="emma" rev="2.0.5312-patched" conf="server,emma -> default(*)"/> + </dependencies> +</ivy-module>
\ No newline at end of file diff --git a/tests/server-side/com/vaadin/data/util/BeanItemTest.java b/tests/server-side/com/vaadin/data/util/BeanItemTest.java index 044a410803..51e11260f5 100644 --- a/tests/server-side/com/vaadin/data/util/BeanItemTest.java +++ b/tests/server-side/com/vaadin/data/util/BeanItemTest.java @@ -12,11 +12,6 @@ import java.util.Map; import junit.framework.Assert; import junit.framework.TestCase; -import com.vaadin.data.util.BeanItem; -import com.vaadin.data.util.MethodProperty; -import com.vaadin.data.util.MethodPropertyDescriptor; -import com.vaadin.data.util.VaadinPropertyDescriptor; - /** * Test BeanItem specific features. * @@ -322,7 +317,7 @@ public class BeanItemTest extends TestCase { MyClass.class.getDeclaredMethod("getName"), MyClass.class.getDeclaredMethod("setName", String.class)); - BeanItem<MyClass> item = new BeanItem(new MyClass("bean1")); + BeanItem<MyClass> item = new BeanItem<MyClass>(new MyClass("bean1")); Assert.assertEquals(6, item.getItemPropertyIds().size()); Assert.assertEquals(null, item.getItemProperty("myname")); diff --git a/tests/server-side/com/vaadin/data/util/NestedMethodPropertyTest.java b/tests/server-side/com/vaadin/data/util/NestedMethodPropertyTest.java index b110ea1c6b..640ede8743 100644 --- a/tests/server-side/com/vaadin/data/util/NestedMethodPropertyTest.java +++ b/tests/server-side/com/vaadin/data/util/NestedMethodPropertyTest.java @@ -10,8 +10,6 @@ import java.io.Serializable; import junit.framework.Assert; import junit.framework.TestCase; -import com.vaadin.data.util.NestedMethodProperty; - public class NestedMethodPropertyTest extends TestCase { public static class Address implements Serializable { @@ -126,34 +124,34 @@ public class NestedMethodPropertyTest extends TestCase { } public void testSingleLevelNestedSimpleProperty() { - NestedMethodProperty nameProperty = new NestedMethodProperty(vaadin, - "name"); + NestedMethodProperty<String> nameProperty = new NestedMethodProperty<String>( + vaadin, "name"); Assert.assertEquals(String.class, nameProperty.getType()); Assert.assertEquals("Vaadin", nameProperty.getValue()); } public void testSingleLevelNestedObjectProperty() { - NestedMethodProperty managerProperty = new NestedMethodProperty(vaadin, - "manager"); + NestedMethodProperty<Person> managerProperty = new NestedMethodProperty<Person>( + vaadin, "manager"); Assert.assertEquals(Person.class, managerProperty.getType()); Assert.assertEquals(joonas, managerProperty.getValue()); } public void testMultiLevelNestedProperty() { - NestedMethodProperty managerNameProperty = new NestedMethodProperty( + NestedMethodProperty<String> managerNameProperty = new NestedMethodProperty<String>( vaadin, "manager.name"); - NestedMethodProperty addressProperty = new NestedMethodProperty(vaadin, - "manager.address"); - NestedMethodProperty streetProperty = new NestedMethodProperty(vaadin, - "manager.address.street"); - NestedMethodProperty postalCodePrimitiveProperty = new NestedMethodProperty( + NestedMethodProperty<Address> addressProperty = new NestedMethodProperty<Address>( + vaadin, "manager.address"); + NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>( + vaadin, "manager.address.street"); + NestedMethodProperty<Integer> postalCodePrimitiveProperty = new NestedMethodProperty<Integer>( vaadin, "manager.address.postalCodePrimitive"); - NestedMethodProperty postalCodeObjectProperty = new NestedMethodProperty( + NestedMethodProperty<Integer> postalCodeObjectProperty = new NestedMethodProperty<Integer>( vaadin, "manager.address.postalCodeObject"); - NestedMethodProperty booleanProperty = new NestedMethodProperty(vaadin, - "manager.address.boolean"); + NestedMethodProperty<Boolean> booleanProperty = new NestedMethodProperty<Boolean>( + vaadin, "manager.address.boolean"); Assert.assertEquals(String.class, managerNameProperty.getType()); Assert.assertEquals("Joonas", managerNameProperty.getValue()); @@ -166,25 +164,27 @@ public class NestedMethodPropertyTest extends TestCase { Assert.assertEquals(Integer.class, postalCodePrimitiveProperty.getType()); - Assert.assertEquals(20540, postalCodePrimitiveProperty.getValue()); + Assert.assertEquals(Integer.valueOf(20540), + postalCodePrimitiveProperty.getValue()); Assert.assertEquals(Integer.class, postalCodeObjectProperty.getType()); - Assert.assertEquals(20540, postalCodeObjectProperty.getValue()); + Assert.assertEquals(Integer.valueOf(20540), + postalCodeObjectProperty.getValue()); Assert.assertEquals(Boolean.class, booleanProperty.getType()); - Assert.assertEquals(true, booleanProperty.getValue()); + Assert.assertEquals(Boolean.TRUE, booleanProperty.getValue()); } public void testEmptyPropertyName() { try { - new NestedMethodProperty(vaadin, ""); + new NestedMethodProperty<Object>(vaadin, ""); fail(); } catch (IllegalArgumentException e) { // should get exception } try { - new NestedMethodProperty(vaadin, " "); + new NestedMethodProperty<Object>(vaadin, " "); fail(); } catch (IllegalArgumentException e) { // should get exception @@ -193,25 +193,25 @@ public class NestedMethodPropertyTest extends TestCase { public void testInvalidPropertyName() { try { - new NestedMethodProperty(vaadin, "."); + new NestedMethodProperty<Object>(vaadin, "."); fail(); } catch (IllegalArgumentException e) { // should get exception } try { - new NestedMethodProperty(vaadin, ".manager"); + new NestedMethodProperty<Object>(vaadin, ".manager"); fail(); } catch (IllegalArgumentException e) { // should get exception } try { - new NestedMethodProperty(vaadin, "manager."); + new NestedMethodProperty<Object>(vaadin, "manager."); fail(); } catch (IllegalArgumentException e) { // should get exception } try { - new NestedMethodProperty(vaadin, "manager..name"); + new NestedMethodProperty<Object>(vaadin, "manager..name"); fail(); } catch (IllegalArgumentException e) { // should get exception @@ -220,21 +220,21 @@ public class NestedMethodPropertyTest extends TestCase { public void testInvalidNestedPropertyName() { try { - new NestedMethodProperty(vaadin, "member"); + new NestedMethodProperty<Object>(vaadin, "member"); fail(); } catch (IllegalArgumentException e) { // should get exception } try { - new NestedMethodProperty(vaadin, "manager.pet"); + new NestedMethodProperty<Object>(vaadin, "manager.pet"); fail(); } catch (IllegalArgumentException e) { // should get exception } try { - new NestedMethodProperty(vaadin, "manager.address.city"); + new NestedMethodProperty<Object>(vaadin, "manager.address.city"); fail(); } catch (IllegalArgumentException e) { // should get exception @@ -242,10 +242,10 @@ public class NestedMethodPropertyTest extends TestCase { } public void testNullNestedProperty() { - NestedMethodProperty managerNameProperty = new NestedMethodProperty( + NestedMethodProperty<String> managerNameProperty = new NestedMethodProperty<String>( vaadin, "manager.name"); - NestedMethodProperty streetProperty = new NestedMethodProperty(vaadin, - "manager.address.street"); + NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>( + vaadin, "manager.address.street"); joonas.setAddress(null); try { @@ -274,15 +274,15 @@ public class NestedMethodPropertyTest extends TestCase { } public void testMultiLevelNestedPropertySetValue() { - NestedMethodProperty managerNameProperty = new NestedMethodProperty( + NestedMethodProperty<String> managerNameProperty = new NestedMethodProperty<String>( vaadin, "manager.name"); - NestedMethodProperty addressProperty = new NestedMethodProperty(vaadin, - "manager.address"); - NestedMethodProperty streetProperty = new NestedMethodProperty(vaadin, - "manager.address.street"); - NestedMethodProperty postalCodePrimitiveProperty = new NestedMethodProperty( + NestedMethodProperty<Address> addressProperty = new NestedMethodProperty<Address>( + vaadin, "manager.address"); + NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>( + vaadin, "manager.address.street"); + NestedMethodProperty<Integer> postalCodePrimitiveProperty = new NestedMethodProperty<Integer>( vaadin, "manager.address.postalCodePrimitive"); - NestedMethodProperty postalCodeObjectProperty = new NestedMethodProperty( + NestedMethodProperty<Integer> postalCodeObjectProperty = new NestedMethodProperty<Integer>( vaadin, "manager.address.postalCodeObject"); managerNameProperty.setValue("Joonas L"); @@ -303,21 +303,22 @@ public class NestedMethodPropertyTest extends TestCase { } public void testSerialization() throws IOException, ClassNotFoundException { - NestedMethodProperty streetProperty = new NestedMethodProperty(vaadin, - "manager.address.street"); + NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>( + vaadin, "manager.address.street"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); new ObjectOutputStream(baos).writeObject(streetProperty); - NestedMethodProperty property2 = (NestedMethodProperty) new ObjectInputStream( + @SuppressWarnings("unchecked") + NestedMethodProperty<String> property2 = (NestedMethodProperty<String>) new ObjectInputStream( new ByteArrayInputStream(baos.toByteArray())).readObject(); Assert.assertEquals("Ruukinkatu 2-4", property2.getValue()); } public void testIsReadOnly() { - NestedMethodProperty streetProperty = new NestedMethodProperty(vaadin, - "manager.address.street"); - NestedMethodProperty booleanProperty = new NestedMethodProperty(vaadin, - "manager.address.boolean"); + NestedMethodProperty<String> streetProperty = new NestedMethodProperty<String>( + vaadin, "manager.address.street"); + NestedMethodProperty<Boolean> booleanProperty = new NestedMethodProperty<Boolean>( + vaadin, "manager.address.boolean"); Assert.assertFalse(streetProperty.isReadOnly()); Assert.assertTrue(booleanProperty.isReadOnly()); diff --git a/tests/server-side/com/vaadin/data/util/ObjectPropertyTest.java b/tests/server-side/com/vaadin/data/util/ObjectPropertyTest.java index 11676099e6..99ca58ba42 100644 --- a/tests/server-side/com/vaadin/data/util/ObjectPropertyTest.java +++ b/tests/server-side/com/vaadin/data/util/ObjectPropertyTest.java @@ -4,8 +4,6 @@ import junit.framework.TestCase; import org.junit.Assert; -import com.vaadin.data.util.ObjectProperty; - public class ObjectPropertyTest extends TestCase { public static class TestSuperClass { @@ -70,7 +68,7 @@ public class ObjectPropertyTest extends TestCase { ObjectProperty<TestSuperClass> prop = new ObjectProperty<TestSuperClass>( super1, TestSuperClass.class); Assert.assertEquals("super1", prop.getValue().getName()); - prop.setValue("super2"); + prop.setValue(new TestSuperClass("super2")); Assert.assertEquals("super1", super1.getName()); Assert.assertEquals("super2", prop.getValue().getName()); } @@ -79,7 +77,7 @@ public class ObjectPropertyTest extends TestCase { ObjectProperty<TestSubClass> prop = new ObjectProperty<TestSubClass>( sub1, TestSubClass.class); Assert.assertEquals("Subclass: sub1", prop.getValue().getName()); - prop.setValue("sub2"); + prop.setValue(new TestSubClass("sub2")); Assert.assertEquals("Subclass: sub1", sub1.getName()); Assert.assertEquals("Subclass: sub2", prop.getValue().getName()); } @@ -92,7 +90,7 @@ public class ObjectPropertyTest extends TestCase { // create correct subclass based on the runtime type of the instance // given to ObjectProperty constructor, which is a subclass of the type // parameter - prop.setValue("sub2"); + prop.setValue(new TestSubClass("sub2")); Assert.assertEquals("Subclass: sub2", prop.getValue().getName()); } diff --git a/tests/server-side/com/vaadin/data/util/PropertyDescriptorTest.java b/tests/server-side/com/vaadin/data/util/PropertyDescriptorTest.java index c3621fa99b..14e70d76d4 100644 --- a/tests/server-side/com/vaadin/data/util/PropertyDescriptorTest.java +++ b/tests/server-side/com/vaadin/data/util/PropertyDescriptorTest.java @@ -11,9 +11,6 @@ import junit.framework.Assert; import junit.framework.TestCase; import com.vaadin.data.Property; -import com.vaadin.data.util.MethodPropertyDescriptor; -import com.vaadin.data.util.NestedPropertyDescriptor; -import com.vaadin.data.util.VaadinPropertyDescriptor; import com.vaadin.data.util.NestedMethodPropertyTest.Person; public class PropertyDescriptorTest extends TestCase { @@ -33,11 +30,12 @@ public class PropertyDescriptorTest extends TestCase { ByteArrayOutputStream baos = new ByteArrayOutputStream(); new ObjectOutputStream(baos).writeObject(descriptor); + @SuppressWarnings("unchecked") VaadinPropertyDescriptor<Person> descriptor2 = (VaadinPropertyDescriptor<Person>) new ObjectInputStream( new ByteArrayInputStream(baos.toByteArray())).readObject(); - Property property = descriptor2 - .createProperty(new Person("John", null)); + Property<?> property = descriptor2.createProperty(new Person("John", + null)); Assert.assertEquals("John", property.getValue()); } @@ -47,10 +45,11 @@ public class PropertyDescriptorTest extends TestCase { ByteArrayOutputStream baos = new ByteArrayOutputStream(); new ObjectOutputStream(baos).writeObject(pd); + @SuppressWarnings("unchecked") VaadinPropertyDescriptor<Person> pd2 = (VaadinPropertyDescriptor<Person>) new ObjectInputStream( new ByteArrayInputStream(baos.toByteArray())).readObject(); - Property property = pd2.createProperty(new Person("John", null)); + Property<?> property = pd2.createProperty(new Person("John", null)); Assert.assertEquals("John", property.getValue()); } } diff --git a/tests/server-side/com/vaadin/data/util/PropertySetItemTest.java b/tests/server-side/com/vaadin/data/util/PropertySetItemTest.java index 4516e8d109..a3169332ec 100644 --- a/tests/server-side/com/vaadin/data/util/PropertySetItemTest.java +++ b/tests/server-side/com/vaadin/data/util/PropertySetItemTest.java @@ -9,8 +9,6 @@ import org.easymock.EasyMock; import com.vaadin.data.Item.PropertySetChangeEvent; import com.vaadin.data.Item.PropertySetChangeListener; -import com.vaadin.data.util.ObjectProperty; -import com.vaadin.data.util.PropertysetItem; public class PropertySetItemTest extends TestCase { @@ -395,13 +393,13 @@ public class PropertySetItemTest extends TestCase { item.addItemProperty(ID1, prop1); - Assert.assertEquals(String.valueOf(prop1), item.toString()); + Assert.assertEquals(String.valueOf(prop1.getValue()), item.toString()); item.addItemProperty(ID2, prop2); Assert.assertEquals( - String.valueOf(prop1) + " " + String.valueOf(prop2), - item.toString()); + String.valueOf(prop1.getValue()) + " " + + String.valueOf(prop2.getValue()), item.toString()); } } diff --git a/tests/server-side/com/vaadin/data/util/TestContainerSorting.java b/tests/server-side/com/vaadin/data/util/TestContainerSorting.java index d9a8e6e51c..9e69b94fbb 100644 --- a/tests/server-side/com/vaadin/data/util/TestContainerSorting.java +++ b/tests/server-side/com/vaadin/data/util/TestContainerSorting.java @@ -8,8 +8,7 @@ import junit.framework.TestCase; import com.vaadin.data.Container; import com.vaadin.data.Item; -import com.vaadin.data.util.HierarchicalContainer; -import com.vaadin.data.util.IndexedContainer; +import com.vaadin.tests.util.TestUtil; public class TestContainerSorting extends TestCase { @@ -93,12 +92,12 @@ public class TestContainerSorting extends TestCase { "Might and Magic", "Natural languages", "PHP", "Programming languages", "Python", "Red Alert", "Swedish", "Toyota", "Volvo" }); - assertArrays( + TestUtil.assertArrays( hc.rootItemIds().toArray(), new Integer[] { nameToId.get("Cars"), nameToId.get("Games"), nameToId.get("Natural languages"), nameToId.get("Programming languages") }); - assertArrays( + TestUtil.assertArrays( hc.getChildren(nameToId.get("Games")).toArray(), new Integer[] { nameToId.get("Call of Duty"), nameToId.get("Fallout"), @@ -168,21 +167,7 @@ public class TestContainerSorting extends TestCase { actual[index++] = o; } - assertArrays(actual, idOrder); - - } - - private void assertArrays(Object[] actualObjects, Object[] expectedObjects) { - assertEquals( - "Actual contains a different number of values than was expected", - expectedObjects.length, actualObjects.length); - - for (int i = 0; i < actualObjects.length; i++) { - Object actual = actualObjects[i]; - Object expected = expectedObjects[i]; - - assertEquals("Item[" + i + "] does not match", expected, actual); - } + TestUtil.assertArrays(actual, idOrder); } diff --git a/tests/server-side/com/vaadin/data/util/filter/AbstractFilterTest.java b/tests/server-side/com/vaadin/data/util/filter/AbstractFilterTest.java index beaa1c4e8f..efc31f0bd4 100644 --- a/tests/server-side/com/vaadin/data/util/filter/AbstractFilterTest.java +++ b/tests/server-side/com/vaadin/data/util/filter/AbstractFilterTest.java @@ -22,18 +22,17 @@ public abstract class AbstractFilterTest<FILTERTYPE extends Filter> extends } } - protected static class NullProperty implements Property { + protected static class NullProperty implements Property<String> { - public Object getValue() { + public String getValue() { return null; } - public void setValue(Object newValue) throws ReadOnlyException, - ConversionException { + public void setValue(Object newValue) throws ReadOnlyException { throw new ReadOnlyException(); } - public Class<?> getType() { + public Class<String> getType() { return String.class; } diff --git a/tests/server-side/com/vaadin/data/util/filter/AndOrFilterTest.java b/tests/server-side/com/vaadin/data/util/filter/AndOrFilterTest.java index bdd852bd41..fdd5b8a645 100644 --- a/tests/server-side/com/vaadin/data/util/filter/AndOrFilterTest.java +++ b/tests/server-side/com/vaadin/data/util/filter/AndOrFilterTest.java @@ -5,10 +5,8 @@ import junit.framework.Assert; import com.vaadin.data.Container.Filter; import com.vaadin.data.Item; import com.vaadin.data.util.BeanItem; -import com.vaadin.data.util.filter.And; -import com.vaadin.data.util.filter.Or; -public class AndOrFilterTest extends AbstractFilterTest { +public class AndOrFilterTest extends AbstractFilterTest<AbstractJunctionFilter> { protected Item item1 = new BeanItem<Integer>(1); protected Item item2 = new BeanItem<Integer>(2); diff --git a/tests/server-side/com/vaadin/data/util/filter/CompareFilterTest.java b/tests/server-side/com/vaadin/data/util/filter/CompareFilterTest.java index 4cd683bfde..99e8429a51 100644 --- a/tests/server-side/com/vaadin/data/util/filter/CompareFilterTest.java +++ b/tests/server-side/com/vaadin/data/util/filter/CompareFilterTest.java @@ -14,7 +14,7 @@ import com.vaadin.data.util.filter.Compare.GreaterOrEqual; import com.vaadin.data.util.filter.Compare.Less; import com.vaadin.data.util.filter.Compare.LessOrEqual; -public class CompareFilterTest extends AbstractFilterTest { +public class CompareFilterTest extends AbstractFilterTest<Compare> { protected Item itemNull; protected Item itemEmpty; diff --git a/tests/server-side/com/vaadin/data/util/filter/IsNullFilterTest.java b/tests/server-side/com/vaadin/data/util/filter/IsNullFilterTest.java index 24d5152cf7..6f90273de1 100644 --- a/tests/server-side/com/vaadin/data/util/filter/IsNullFilterTest.java +++ b/tests/server-side/com/vaadin/data/util/filter/IsNullFilterTest.java @@ -6,10 +6,8 @@ import com.vaadin.data.Container.Filter; import com.vaadin.data.Item; import com.vaadin.data.util.ObjectProperty; import com.vaadin.data.util.PropertysetItem; -import com.vaadin.data.util.filter.And; -import com.vaadin.data.util.filter.IsNull; -public class IsNullFilterTest extends AbstractFilterTest { +public class IsNullFilterTest extends AbstractFilterTest<IsNull> { public void testIsNull() { Item item1 = new PropertysetItem(); diff --git a/tests/server-side/com/vaadin/data/util/filter/NotFilterTest.java b/tests/server-side/com/vaadin/data/util/filter/NotFilterTest.java index be6417ccdf..c3b666e6f7 100644 --- a/tests/server-side/com/vaadin/data/util/filter/NotFilterTest.java +++ b/tests/server-side/com/vaadin/data/util/filter/NotFilterTest.java @@ -5,10 +5,8 @@ import junit.framework.Assert; import com.vaadin.data.Container.Filter; import com.vaadin.data.Item; import com.vaadin.data.util.BeanItem; -import com.vaadin.data.util.filter.And; -import com.vaadin.data.util.filter.Not; -public class NotFilterTest extends AbstractFilterTest { +public class NotFilterTest extends AbstractFilterTest<Not> { protected Item item1 = new BeanItem<Integer>(1); protected Item item2 = new BeanItem<Integer>(2); diff --git a/tests/server-side/com/vaadin/data/util/filter/SimpleStringFilterTest.java b/tests/server-side/com/vaadin/data/util/filter/SimpleStringFilterTest.java index c36a764a54..bc63d57752 100644 --- a/tests/server-side/com/vaadin/data/util/filter/SimpleStringFilterTest.java +++ b/tests/server-side/com/vaadin/data/util/filter/SimpleStringFilterTest.java @@ -2,9 +2,8 @@ package com.vaadin.data.util.filter; import junit.framework.Assert; -import com.vaadin.data.util.filter.SimpleStringFilter; - -public class SimpleStringFilterTest extends AbstractFilterTest { +public class SimpleStringFilterTest extends + AbstractFilterTest<SimpleStringFilter> { protected static TestItem<String, String> createTestItem() { return new TestItem<String, String>("abcde", "TeSt"); diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/DataGenerator.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/DataGenerator.java index 6fa807b007..489f780d61 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/DataGenerator.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/DataGenerator.java @@ -12,11 +12,12 @@ import com.vaadin.data.util.sqlcontainer.AllTests.DB; import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; public class DataGenerator { - - @Test - public void testDummy(){ - // Added dummy test so JUnit will not complain about "No runnable methods". - } + + @Test + public void testDummy() { + // Added dummy test so JUnit will not complain about + // "No runnable methods". + } public static void addPeopleToDatabase(JDBCConnectionPool connectionPool) throws SQLException { diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/FreeformQueryUtil.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/FreeformQueryUtil.java index 2579a38aa1..b0e2a232ca 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/FreeformQueryUtil.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/FreeformQueryUtil.java @@ -11,11 +11,12 @@ import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; public class FreeformQueryUtil { - @Test - public void testDummy(){ - // Added dummy test so JUnit will not complain about "No runnable methods". - } - + @Test + public void testDummy() { + // Added dummy test so JUnit will not complain about + // "No runnable methods". + } + public static StatementHelper getQueryWithFilters(List<Filter> filters, int offset, int limit) { StatementHelper sh = new StatementHelper(); @@ -30,8 +31,7 @@ public class FreeformQueryUtil { query.append(") AS rownum, * FROM \"PEOPLE\""); if (!filters.isEmpty()) { - query.append(QueryBuilder.getWhereStringForFilters( - filters, sh)); + query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); } query.append(") AS a WHERE a.rownum BETWEEN ").append(offset) .append(" AND ").append(Integer.toString(offset + limit)); @@ -46,8 +46,7 @@ public class FreeformQueryUtil { query.append("SELECT * FROM (SELECT x.*, ROWNUM AS " + "\"rownum\" FROM (SELECT * FROM \"PEOPLE\""); if (!filters.isEmpty()) { - query.append(QueryBuilder.getWhereStringForFilters( - filters, sh)); + query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); } query.append(") x) WHERE \"rownum\" BETWEEN ? AND ?"); sh.addParameterValue(offset); @@ -57,8 +56,7 @@ public class FreeformQueryUtil { } else { StringBuilder query = new StringBuilder("SELECT * FROM people"); if (!filters.isEmpty()) { - query.append(QueryBuilder.getWhereStringForFilters( - filters, sh)); + query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); } if (limit != 0 || offset != 0) { query.append(" LIMIT ? OFFSET ?"); diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java index 56c9921a0b..c273bbf590 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/SQLContainerTest.java @@ -1344,7 +1344,7 @@ public class SQLContainerTest { Statement statement = conn.createStatement(); statement .executeUpdate("DELETE FROM people WHERE \"ID\"=" - + item.getItemProperty("ID")); + + item.getItemProperty("ID").getValue()); statement.close(); return true; } diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/UtilTest.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/UtilTest.java index d6a6a72300..31bdf2b81b 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/UtilTest.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/UtilTest.java @@ -21,7 +21,7 @@ public class UtilTest { @Test public void escapeSQL_severalQuotes_returnsEscapedString() { Assert.assertEquals("asdf''ghjk''qwerty", - SQLUtil.escapeSQL("asdf'ghjk'qwerty")); + SQLUtil.escapeSQL("asdf'ghjk'qwerty")); } @Test @@ -32,12 +32,13 @@ public class UtilTest { @Test public void escapeSQL_multipleDoubleQuotes_returnsEscapedString() { Assert.assertEquals("asdf\\\"foo\\\"bar", - SQLUtil.escapeSQL("asdf\"foo\"bar")); + SQLUtil.escapeSQL("asdf\"foo\"bar")); } @Test public void escapeSQL_backslashes_returnsEscapedString() { - Assert.assertEquals("foo\\\\nbar\\\\r", SQLUtil.escapeSQL("foo\\nbar\\r")); + Assert.assertEquals("foo\\\\nbar\\\\r", + SQLUtil.escapeSQL("foo\\nbar\\r")); } @Test diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/connection/MockInitialContextFactory.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/connection/MockInitialContextFactory.java index 19019eed0b..3ee260245a 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/connection/MockInitialContextFactory.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/connection/MockInitialContextFactory.java @@ -11,11 +11,12 @@ import org.junit.Test; */ public class MockInitialContextFactory implements InitialContextFactory { private static Context mockCtx = null; - + @Test - public void testDummy(){ - // Added dummy test so JUnit will not complain about "No runnable methods". - } + public void testDummy() { + // Added dummy test so JUnit will not complain about + // "No runnable methods". + } public static void setMockContext(Context ctx) { mockCtx = ctx; diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/filters/BetweenTest.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/filters/BetweenTest.java index 5faa859b67..da4cfe4522 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/filters/BetweenTest.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/filters/BetweenTest.java @@ -12,7 +12,7 @@ import com.vaadin.data.util.filter.Between; public class BetweenTest { private Item itemWithPropertyValue(Object propertyId, Object value) { - Property property = EasyMock.createMock(Property.class); + Property<?> property = EasyMock.createMock(Property.class); property.getValue(); EasyMock.expectLastCall().andReturn(value).anyTimes(); EasyMock.replay(property); diff --git a/tests/server-side/com/vaadin/terminal/gwt/server/TestAbstractApplicationServletStaticFilesLocation.java b/tests/server-side/com/vaadin/terminal/gwt/server/TestAbstractApplicationServletStaticFilesLocation.java index fcd9970717..7e45ea50d7 100644 --- a/tests/server-side/com/vaadin/terminal/gwt/server/TestAbstractApplicationServletStaticFilesLocation.java +++ b/tests/server-side/com/vaadin/terminal/gwt/server/TestAbstractApplicationServletStaticFilesLocation.java @@ -17,9 +17,6 @@ import javax.servlet.http.HttpServletRequest; import junit.framework.TestCase; -import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; -import com.vaadin.terminal.gwt.server.ApplicationServlet; - public class TestAbstractApplicationServletStaticFilesLocation extends TestCase { ApplicationServlet servlet; @@ -147,9 +144,6 @@ public class TestAbstractApplicationServletStaticFilesLocation extends TestCase .andReturn(realContextPath).anyTimes(); expect(request.getAttribute("javax.servlet.include.servlet_path")) .andReturn(realServletPath).anyTimes(); - expect( - request.getAttribute(AbstractApplicationServlet.REQUEST_VAADIN_STATIC_FILE_PATH)) - .andReturn(null).anyTimes(); return request; } @@ -163,9 +157,6 @@ public class TestAbstractApplicationServletStaticFilesLocation extends TestCase .andReturn(null).anyTimes(); expect(request.getAttribute("javax.servlet.include.servlet_path")) .andReturn(null).anyTimes(); - expect( - request.getAttribute(ApplicationServlet.REQUEST_VAADIN_STATIC_FILE_PATH)) - .andReturn(null).anyTimes(); return request; } diff --git a/tests/server-side/com/vaadin/tests/VaadinClasses.java b/tests/server-side/com/vaadin/tests/VaadinClasses.java index e02c4f0b6e..b74af660e4 100644 --- a/tests/server-side/com/vaadin/tests/VaadinClasses.java +++ b/tests/server-side/com/vaadin/tests/VaadinClasses.java @@ -22,10 +22,11 @@ import com.vaadin.ui.Component; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.DragAndDropWrapper; +import com.vaadin.ui.Field; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.LoginForm; import com.vaadin.ui.PopupView; -import com.vaadin.ui.SplitPanel; +import com.vaadin.ui.Root; import com.vaadin.ui.VerticalSplitPanel; import com.vaadin.ui.Window; @@ -61,6 +62,15 @@ public class VaadinClasses { } } + public static List<Class<? extends Field>> getFields() { + try { + return findClasses(Field.class, "com.vaadin.ui"); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + public static List<Class<? extends Object>> getAllServerSideClasses() { try { return findClassesNoTests(Object.class, "com.vaadin", new String[] { @@ -87,13 +97,13 @@ public class VaadinClasses { classes.remove(DragAndDropWrapper.class); classes.remove(CustomComponent.class); classes.remove(LoginForm.class); + classes.remove(Root.class); return classes; } public static List<Class<? extends ComponentContainer>> getComponentContainersSupportingUnlimitedNumberOfComponents() { List<Class<? extends ComponentContainer>> classes = getComponentContainersSupportingAddRemoveComponent(); - classes.remove(SplitPanel.class); classes.remove(VerticalSplitPanel.class); classes.remove(HorizontalSplitPanel.class); classes.remove(Window.class); diff --git a/tests/server-side/com/vaadin/tests/data/bean/Address.java b/tests/server-side/com/vaadin/tests/data/bean/Address.java new file mode 100644 index 0000000000..15cdf34ae5 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/data/bean/Address.java @@ -0,0 +1,63 @@ +package com.vaadin.tests.data.bean; + +import java.io.Serializable; + +@SuppressWarnings("serial") +public class Address implements Serializable { + + private String streetAddress = ""; + private Integer postalCode = null; + private String city = ""; + private Country country = null; + + public Address() { + + } + + public Address(String streetAddress, int postalCode, String city, + Country country) { + setStreetAddress(streetAddress); + setPostalCode(postalCode); + setCity(city); + setCountry(country); + } + + @Override + public String toString() { + return "Address [streetAddress=" + streetAddress + ", postalCode=" + + postalCode + ", city=" + city + ", country=" + country + "]"; + } + + public String getStreetAddress() { + return streetAddress; + } + + public void setStreetAddress(String streetAddress) { + this.streetAddress = streetAddress; + } + + public Integer getPostalCode() { + return postalCode; + } + + public void setPostalCode(Integer postalCode) { + this.postalCode = postalCode; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public Country getCountry() { + return country; + } + + public void setCountry(Country country) { + this.country = country; + } + +} diff --git a/tests/server-side/com/vaadin/tests/data/bean/BeanToValidate.java b/tests/server-side/com/vaadin/tests/data/bean/BeanToValidate.java new file mode 100644 index 0000000000..416563baba --- /dev/null +++ b/tests/server-side/com/vaadin/tests/data/bean/BeanToValidate.java @@ -0,0 +1,56 @@ +package com.vaadin.tests.data.bean; + +import javax.validation.constraints.Digits; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +public class BeanToValidate { + @NotNull + @Size(min = 3, max = 16) + private String firstname; + + @NotNull(message = "Last name must not be empty") + private String lastname; + + @Min(value = 18, message = "Must be 18 or above") + @Max(150) + private int age; + + @Digits(integer = 3, fraction = 2) + private String decimals; + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + +} diff --git a/tests/server-side/com/vaadin/tests/data/bean/Country.java b/tests/server-side/com/vaadin/tests/data/bean/Country.java new file mode 100644 index 0000000000..afdf8dcfa1 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/data/bean/Country.java @@ -0,0 +1,18 @@ +package com.vaadin.tests.data.bean; + +public enum Country { + + FINLAND("Finland"), SWEDEN("Sweden"), USA("USA"), RUSSIA("Russia"), NETHERLANDS( + "Netherlands"), SOUTH_AFRICA("South Africa"); + + private String name; + + private Country(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/tests/server-side/com/vaadin/tests/data/bean/Person.java b/tests/server-side/com/vaadin/tests/data/bean/Person.java new file mode 100644 index 0000000000..2cb3a29368 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/data/bean/Person.java @@ -0,0 +1,133 @@ +package com.vaadin.tests.data.bean; + +import java.math.BigDecimal; +import java.util.Date; + +public class Person { + private String firstName; + private String lastName; + private String email; + private int age; + private Sex sex; + private Address address; + private boolean deceased; + private Date birthDate; + + private Integer salary; // null if unknown + private Double salaryDouble; // null if unknown + + private BigDecimal rent; + + public Person() { + + } + + @Override + public String toString() { + return "Person [firstName=" + firstName + ", lastName=" + lastName + + ", email=" + email + ", age=" + age + ", sex=" + sex + + ", address=" + address + ", deceased=" + deceased + + ", salary=" + salary + ", salaryDouble=" + salaryDouble + + ", rent=" + rent + "]"; + } + + public Person(String firstName, String lastName, String email, int age, + Sex sex, Address address) { + super(); + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.age = age; + this.sex = sex; + this.address = address; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public Sex getSex() { + return sex; + } + + public void setSex(Sex sex) { + this.sex = sex; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public boolean getDeceased() { + return deceased; + } + + public void setDeceased(boolean deceased) { + this.deceased = deceased; + } + + public Integer getSalary() { + return salary; + } + + public void setSalary(Integer salary) { + this.salary = salary; + } + + public BigDecimal getRent() { + return rent; + } + + public void setRent(BigDecimal rent) { + this.rent = rent; + } + + public Double getSalaryDouble() { + return salaryDouble; + } + + public void setSalaryDouble(Double salaryDouble) { + this.salaryDouble = salaryDouble; + } + + public Date getBirthDate() { + return birthDate; + } + + public void setBirthDate(Date birthDate) { + this.birthDate = birthDate; + } + +} diff --git a/tests/server-side/com/vaadin/tests/data/bean/PersonWithBeanValidationAnnotations.java b/tests/server-side/com/vaadin/tests/data/bean/PersonWithBeanValidationAnnotations.java new file mode 100644 index 0000000000..93b2273263 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/data/bean/PersonWithBeanValidationAnnotations.java @@ -0,0 +1,156 @@ +package com.vaadin.tests.data.bean; + +import java.math.BigDecimal; +import java.util.Date; + +import javax.validation.constraints.Digits; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Past; +import javax.validation.constraints.Size; + +public class PersonWithBeanValidationAnnotations { + @NotNull + @Size(min = 5, max = 20) + private String firstName; + @NotNull + private String lastName; + + private String email; + + @Min(0) + @Max(100) + private int age; + + @NotNull + private Sex sex; + + private Address address; + private boolean deceased; + + @NotNull + @Past + private Date birthDate; + + @Min(0) + private Integer salary; // null if unknown + + @Digits(integer = 6, fraction = 2) + private Double salaryDouble; // null if unknown + + private BigDecimal rent; + + public PersonWithBeanValidationAnnotations() { + + } + + @Override + public String toString() { + return "Person [firstName=" + firstName + ", lastName=" + lastName + + ", email=" + email + ", age=" + age + ", sex=" + sex + + ", address=" + address + ", deceased=" + deceased + + ", salary=" + salary + ", salaryDouble=" + salaryDouble + + ", rent=" + rent + "]"; + } + + public PersonWithBeanValidationAnnotations(String firstName, + String lastName, String email, int age, Sex sex, Address address) { + super(); + this.firstName = firstName; + this.lastName = lastName; + this.email = email; + this.age = age; + this.sex = sex; + this.address = address; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public Sex getSex() { + return sex; + } + + public void setSex(Sex sex) { + this.sex = sex; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public boolean getDeceased() { + return deceased; + } + + public void setDeceased(boolean deceased) { + this.deceased = deceased; + } + + public Integer getSalary() { + return salary; + } + + public void setSalary(Integer salary) { + this.salary = salary; + } + + public BigDecimal getRent() { + return rent; + } + + public void setRent(BigDecimal rent) { + this.rent = rent; + } + + public Double getSalaryDouble() { + return salaryDouble; + } + + public void setSalaryDouble(Double salaryDouble) { + this.salaryDouble = salaryDouble; + } + + public Date getBirthDate() { + return birthDate; + } + + public void setBirthDate(Date birthDate) { + this.birthDate = birthDate; + } + +} diff --git a/tests/server-side/com/vaadin/tests/data/bean/Sex.java b/tests/server-side/com/vaadin/tests/data/bean/Sex.java new file mode 100644 index 0000000000..a4e3f20a11 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/data/bean/Sex.java @@ -0,0 +1,20 @@ +package com.vaadin.tests.data.bean; + +public enum Sex { + MALE("Male"), FEMALE("Female"), UNKNOWN("Unknown"); + + private String stringRepresentation; + + private Sex(String stringRepresentation) { + this.stringRepresentation = stringRepresentation; + } + + public String getStringRepresentation() { + return stringRepresentation; + } + + @Override + public String toString() { + return getStringRepresentation(); + } +} diff --git a/tests/server-side/com/vaadin/tests/server/TestAbstractBeanContainerListeners.java b/tests/server-side/com/vaadin/tests/server/TestAbstractBeanContainerListeners.java index d6598a3b62..0d8433d1c6 100644 --- a/tests/server-side/com/vaadin/tests/server/TestAbstractBeanContainerListeners.java +++ b/tests/server-side/com/vaadin/tests/server/TestAbstractBeanContainerListeners.java @@ -5,7 +5,8 @@ import com.vaadin.data.Container.PropertySetChangeListener; import com.vaadin.data.util.BeanItemContainer; import com.vaadin.tests.server.component.AbstractListenerMethodsTest; -public class TestAbstractBeanContainerListeners extends AbstractListenerMethodsTest { +public class TestAbstractBeanContainerListeners extends + AbstractListenerMethodsTest { public void testPropertySetChangeListenerAddGetRemove() throws Exception { testListenerAddGetRemove(BeanItemContainer.class, PropertySetChangeEvent.class, PropertySetChangeListener.class, diff --git a/tests/server-side/com/vaadin/tests/server/TestAbstractInMemoryContainerListeners.java b/tests/server-side/com/vaadin/tests/server/TestAbstractInMemoryContainerListeners.java index 4be4e35554..a8e2a4aa2a 100644 --- a/tests/server-side/com/vaadin/tests/server/TestAbstractInMemoryContainerListeners.java +++ b/tests/server-side/com/vaadin/tests/server/TestAbstractInMemoryContainerListeners.java @@ -5,7 +5,8 @@ import com.vaadin.data.Container.ItemSetChangeListener; import com.vaadin.data.util.IndexedContainer; import com.vaadin.tests.server.component.AbstractListenerMethodsTest; -public class TestAbstractInMemoryContainerListeners extends AbstractListenerMethodsTest { +public class TestAbstractInMemoryContainerListeners extends + AbstractListenerMethodsTest { public void testItemSetChangeListenerAddGetRemove() throws Exception { testListenerAddGetRemove(IndexedContainer.class, ItemSetChangeEvent.class, ItemSetChangeListener.class); diff --git a/tests/server-side/com/vaadin/tests/server/TestClassesSerializable.java b/tests/server-side/com/vaadin/tests/server/TestClassesSerializable.java index c047565fcc..44a6a3b66d 100644 --- a/tests/server-side/com/vaadin/tests/server/TestClassesSerializable.java +++ b/tests/server-side/com/vaadin/tests/server/TestClassesSerializable.java @@ -47,7 +47,6 @@ public class TestClassesSerializable extends TestCase { // class level filtering, also affecting nested classes and // interfaces "com\\.vaadin\\.terminal\\.gwt\\.server\\.AbstractCommunicationManager.*", // - "com\\.vaadin\\.terminal\\.gwt\\.server\\.ApplicationRunnerServlet.*", // "com\\.vaadin\\.terminal\\.gwt\\.server\\.CommunicationManager.*", // "com\\.vaadin\\.terminal\\.gwt\\.server\\.PortletCommunicationManager.*", // }; @@ -98,9 +97,19 @@ public class TestClassesSerializable extends TestCase { if (!nonSerializableClasses.isEmpty()) { String nonSerializableString = ""; Iterator<Class<?>> it = nonSerializableClasses.iterator(); - nonSerializableString = it.next().getName(); while (it.hasNext()) { - nonSerializableString += ", " + it.next().getName(); + Class c = it.next(); + nonSerializableString += ", " + c.getName(); + if (c.isAnonymousClass()) { + nonSerializableString += "(super: "; + nonSerializableString += c.getSuperclass().getName(); + nonSerializableString += ", interfaces: "; + for (Class i : c.getInterfaces()) { + nonSerializableString += i.getName(); + nonSerializableString += ","; + } + nonSerializableString += ")"; + } } fail("Serializable not implemented by the following classes and interfaces: " + nonSerializableString); diff --git a/tests/server-side/com/vaadin/tests/server/TestKeyMapper.java b/tests/server-side/com/vaadin/tests/server/TestKeyMapper.java index ca33cf3314..4f5f0b1431 100644 --- a/tests/server-side/com/vaadin/tests/server/TestKeyMapper.java +++ b/tests/server-side/com/vaadin/tests/server/TestKeyMapper.java @@ -1,7 +1,7 @@ package com.vaadin.tests.server; import java.lang.reflect.Field; -import java.util.Hashtable; +import java.util.HashMap; import junit.framework.TestCase; @@ -10,7 +10,7 @@ import com.vaadin.terminal.KeyMapper; public class TestKeyMapper extends TestCase { public void testAdd() { - KeyMapper mapper = new KeyMapper(); + KeyMapper<Object> mapper = new KeyMapper<Object>(); Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); @@ -41,7 +41,7 @@ public class TestKeyMapper extends TestCase { } public void testRemoveAll() { - KeyMapper mapper = new KeyMapper(); + KeyMapper<Object> mapper = new KeyMapper<Object>(); Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); @@ -58,7 +58,7 @@ public class TestKeyMapper extends TestCase { } public void testRemove() { - KeyMapper mapper = new KeyMapper(); + KeyMapper<Object> mapper = new KeyMapper<Object>(); Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); @@ -82,15 +82,15 @@ public class TestKeyMapper extends TestCase { } - private void assertSize(KeyMapper mapper, int i) { + private void assertSize(KeyMapper<?> mapper, int i) { try { Field f1 = KeyMapper.class.getDeclaredField("objectKeyMap"); Field f2 = KeyMapper.class.getDeclaredField("keyObjectMap"); f1.setAccessible(true); f2.setAccessible(true); - Hashtable<?, ?> h1 = (Hashtable<?, ?>) f1.get(mapper); - Hashtable<?, ?> h2 = (Hashtable<?, ?>) f2.get(mapper); + HashMap<?, ?> h1 = (HashMap<?, ?>) f1.get(mapper); + HashMap<?, ?> h2 = (HashMap<?, ?>) f2.get(mapper); assertEquals(i, h1.size()); assertEquals(i, h2.size()); diff --git a/tests/server-side/com/vaadin/tests/server/TestPropertyFormatter.java b/tests/server-side/com/vaadin/tests/server/TestPropertyFormatter.java index 91e36b5caa..48c60c83c4 100644 --- a/tests/server-side/com/vaadin/tests/server/TestPropertyFormatter.java +++ b/tests/server-side/com/vaadin/tests/server/TestPropertyFormatter.java @@ -27,6 +27,7 @@ public class TestPropertyFormatter extends TestCase { return getExpectedClass().newInstance(); } }; + @SuppressWarnings("rawtypes") private Class expectedClass; @@ -34,36 +35,41 @@ public class TestPropertyFormatter extends TestCase { private Class getExpectedClass() { return expectedClass; } - + /** * The object passed to format should be same as property's type. - * @throws IllegalAccessException - * @throws InstantiationException + * + * @throws IllegalAccessException + * @throws InstantiationException */ @Test @SuppressWarnings({ "rawtypes" }) - public void testCorrectTypeForFormat() throws InstantiationException, IllegalAccessException { - Class[] testedTypes = new Class[] {Integer.class, Boolean.class, Double.class, String.class, Date.class}; - Object[] testValues = new Object[] {new Integer(3), Boolean.FALSE, new Double(3.3), "bar", new Date()}; - + public void testCorrectTypeForFormat() throws InstantiationException, + IllegalAccessException { + Class[] testedTypes = new Class[] { Integer.class, Boolean.class, + Double.class, String.class, Date.class }; + Object[] testValues = new Object[] { new Integer(3), Boolean.FALSE, + new Double(3.3), "bar", new Date() }; + int i = 0; for (Class class1 : testedTypes) { expectedClass = class1; - + TestFormatter formatter = new TestFormatter(); - + // Should just return null, without formatting Object value = formatter.getValue(); - + // test with property which value is null - formatter.setPropertyDataSource(new ObjectProperty(null, expectedClass)); + formatter.setPropertyDataSource(new ObjectProperty(null, + expectedClass)); formatter.getValue(); // calls format - + // test with a value - formatter.setPropertyDataSource(new ObjectProperty(testValues[i++], expectedClass)); + formatter.setPropertyDataSource(new ObjectProperty(testValues[i++], + expectedClass)); formatter.getValue(); // calls format } - } } diff --git a/tests/server-side/com/vaadin/tests/server/TestSerialization.java b/tests/server-side/com/vaadin/tests/server/TestSerialization.java index 03a9d3e262..84ff5ad6fa 100644 --- a/tests/server-side/com/vaadin/tests/server/TestSerialization.java +++ b/tests/server-side/com/vaadin/tests/server/TestSerialization.java @@ -10,6 +10,7 @@ import java.io.Serializable; import junit.framework.TestCase; import com.vaadin.data.Item; +import com.vaadin.data.Property; import com.vaadin.data.util.IndexedContainer; import com.vaadin.data.util.MethodProperty; import com.vaadin.data.validator.RegexpValidator; @@ -19,9 +20,9 @@ public class TestSerialization extends TestCase { public void testValidators() throws Exception { RegexpValidator validator = new RegexpValidator(".*", "Error"); - validator.isValid("aaa"); + validator.validate("aaa"); RegexpValidator validator2 = (RegexpValidator) serializeAndDeserialize(validator); - validator2.isValid("aaa"); + validator2.validate("aaa"); } public void testForm() throws Exception { @@ -78,15 +79,25 @@ public class TestSerialization extends TestCase { data)); Serializable s2 = (Serializable) in.readObject(); + // using special toString(Object) method to avoid calling + // Property.toString(), which will be temporarily disabled if (s.equals(s2)) { - System.out.println(s + " equals " + s2); + System.out.println(toString(s) + " equals " + toString(s2)); } else { - System.out.println(s + " does NOT equal " + s2); + System.out.println(toString(s) + " does NOT equal " + toString(s2)); } return s2; } + private static String toString(Object o) { + if (o instanceof Property) { + return String.valueOf(((Property<?>) o).getValue()); + } else { + return String.valueOf(o); + } + } + public static class Data implements Serializable { private String dummyGetter; private String dummyGetterAndSetter; diff --git a/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java b/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java index 224c9f5964..8cc26a5c7f 100644 --- a/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java +++ b/tests/server-side/com/vaadin/tests/server/TransactionListenersConcurrency.java @@ -20,6 +20,7 @@ import junit.framework.TestCase; import org.easymock.EasyMock; import com.vaadin.Application; +import com.vaadin.Application.ApplicationStartEvent; import com.vaadin.service.ApplicationContext.TransactionListener; import com.vaadin.terminal.gwt.server.AbstractWebApplicationContext; import com.vaadin.terminal.gwt.server.WebApplicationContext; @@ -70,8 +71,9 @@ public class TransactionListenersConcurrency extends TestCase { // called later on. try { - app.start(new URL("http://localhost/"), - new Properties(), context); + app.start(new ApplicationStartEvent(new URL( + "http://localhost/"), new Properties(), + context, true)); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/tests/server-side/com/vaadin/tests/server/component/AbstractListenerMethodsTest.java b/tests/server-side/com/vaadin/tests/server/component/AbstractListenerMethodsTest.java index 355f5167d7..e189ffc77d 100644 --- a/tests/server-side/com/vaadin/tests/server/component/AbstractListenerMethodsTest.java +++ b/tests/server-side/com/vaadin/tests/server/component/AbstractListenerMethodsTest.java @@ -48,11 +48,14 @@ public abstract class AbstractListenerMethodsTest extends TestCase { System.out.println("package " + packageName + ";"); System.out.println("import " - + AbstractListenerMethodsTest.class.getName() + ";"); + + AbstractListenerMethodsTest.class.getName() + + ";"); System.out.println("import " + c.getName() + ";"); - System.out.println("public class " + c.getSimpleName() + System.out.println("public class " + + c.getSimpleName() + "Listeners extends " - + AbstractListenerMethodsTest.class.getSimpleName() + " {"); + + AbstractListenerMethodsTest.class + .getSimpleName() + " {"); } String listenerClassName = m.getParameterTypes()[0] diff --git a/tests/server-side/com/vaadin/tests/server/component/absolutelayout/ComponentPosition.java b/tests/server-side/com/vaadin/tests/server/component/absolutelayout/ComponentPosition.java index ee8ef6bfbc..4458872c79 100644 --- a/tests/server-side/com/vaadin/tests/server/component/absolutelayout/ComponentPosition.java +++ b/tests/server-side/com/vaadin/tests/server/component/absolutelayout/ComponentPosition.java @@ -3,6 +3,7 @@ package com.vaadin.tests.server.component.absolutelayout; import junit.framework.TestCase; import com.vaadin.terminal.Sizeable; +import com.vaadin.terminal.Sizeable.Unit; import com.vaadin.ui.AbsoluteLayout; import com.vaadin.ui.Button; @@ -12,7 +13,7 @@ public class ComponentPosition extends TestCase { private static final String PARTIAL_CSS = "top:7.0px;left:7.0em;"; private static final Float CSS_VALUE = Float.valueOf(7); - private static final int UNIT_UNSET = Sizeable.UNITS_PIXELS; + private static final Unit UNIT_UNSET = Sizeable.Unit.PIXELS; /** * Add component w/o giving positions, assert that everything is unset @@ -51,11 +52,11 @@ public class ComponentPosition extends TestCase { assertEquals(CSS_VALUE, layout.getPosition(b).getLeftValue()); assertEquals(CSS_VALUE, layout.getPosition(b).getRightValue()); - assertEquals(Sizeable.UNITS_PIXELS, layout.getPosition(b).getTopUnits()); - assertEquals(Sizeable.UNITS_PICAS, layout.getPosition(b) + assertEquals(Sizeable.Unit.PIXELS, layout.getPosition(b).getTopUnits()); + assertEquals(Sizeable.Unit.PICAS, layout.getPosition(b) .getBottomUnits()); - assertEquals(Sizeable.UNITS_EM, layout.getPosition(b).getLeftUnits()); - assertEquals(Sizeable.UNITS_PERCENTAGE, layout.getPosition(b) + assertEquals(Sizeable.Unit.EM, layout.getPosition(b).getLeftUnits()); + assertEquals(Sizeable.Unit.PERCENTAGE, layout.getPosition(b) .getRightUnits()); assertEquals(7, layout.getPosition(b).getZIndex()); @@ -77,9 +78,9 @@ public class ComponentPosition extends TestCase { assertEquals(CSS_VALUE, layout.getPosition(b).getLeftValue()); assertNull(layout.getPosition(b).getRightValue()); - assertEquals(Sizeable.UNITS_PIXELS, layout.getPosition(b).getTopUnits()); + assertEquals(Sizeable.Unit.PIXELS, layout.getPosition(b).getTopUnits()); assertEquals(UNIT_UNSET, layout.getPosition(b).getBottomUnits()); - assertEquals(Sizeable.UNITS_EM, layout.getPosition(b).getLeftUnits()); + assertEquals(Sizeable.Unit.EM, layout.getPosition(b).getLeftUnits()); assertEquals(UNIT_UNSET, layout.getPosition(b).getRightUnits()); assertEquals(-1, layout.getPosition(b).getZIndex()); @@ -104,9 +105,9 @@ public class ComponentPosition extends TestCase { assertEquals(CSS_VALUE, layout.getPosition(b).getLeftValue()); assertNull(layout.getPosition(b).getRightValue()); - assertEquals(Sizeable.UNITS_PIXELS, layout.getPosition(b).getTopUnits()); + assertEquals(Sizeable.Unit.PIXELS, layout.getPosition(b).getTopUnits()); assertEquals(UNIT_UNSET, layout.getPosition(b).getBottomUnits()); - assertEquals(Sizeable.UNITS_EM, layout.getPosition(b).getLeftUnits()); + assertEquals(Sizeable.Unit.EM, layout.getPosition(b).getLeftUnits()); assertEquals(UNIT_UNSET, layout.getPosition(b).getRightUnits()); assertEquals(-1, layout.getPosition(b).getZIndex()); @@ -131,21 +132,20 @@ public class ComponentPosition extends TestCase { layout.getPosition(b).setBottomValue(SIZE); layout.getPosition(b).setLeftValue(SIZE); - layout.getPosition(b).setTopUnits(Sizeable.UNITS_CM); - layout.getPosition(b).setRightUnits(Sizeable.UNITS_EX); - layout.getPosition(b).setBottomUnits(Sizeable.UNITS_INCH); - layout.getPosition(b).setLeftUnits(Sizeable.UNITS_MM); + layout.getPosition(b).setTopUnits(Sizeable.Unit.CM); + layout.getPosition(b).setRightUnits(Sizeable.Unit.EX); + layout.getPosition(b).setBottomUnits(Sizeable.Unit.INCH); + layout.getPosition(b).setLeftUnits(Sizeable.Unit.MM); assertEquals(SIZE, layout.getPosition(b).getTopValue()); assertEquals(SIZE, layout.getPosition(b).getRightValue()); assertEquals(SIZE, layout.getPosition(b).getBottomValue()); assertEquals(SIZE, layout.getPosition(b).getLeftValue()); - assertEquals(Sizeable.UNITS_CM, layout.getPosition(b).getTopUnits()); - assertEquals(Sizeable.UNITS_EX, layout.getPosition(b).getRightUnits()); - assertEquals(Sizeable.UNITS_INCH, layout.getPosition(b) - .getBottomUnits()); - assertEquals(Sizeable.UNITS_MM, layout.getPosition(b).getLeftUnits()); + assertEquals(Sizeable.Unit.CM, layout.getPosition(b).getTopUnits()); + assertEquals(Sizeable.Unit.EX, layout.getPosition(b).getRightUnits()); + assertEquals(Sizeable.Unit.INCH, layout.getPosition(b).getBottomUnits()); + assertEquals(Sizeable.Unit.MM, layout.getPosition(b).getLeftUnits()); } @@ -159,21 +159,20 @@ public class ComponentPosition extends TestCase { Button b = new Button(); layout.addComponent(b); - layout.getPosition(b).setTop(SIZE, Sizeable.UNITS_CM); - layout.getPosition(b).setRight(SIZE, Sizeable.UNITS_EX); - layout.getPosition(b).setBottom(SIZE, Sizeable.UNITS_INCH); - layout.getPosition(b).setLeft(SIZE, Sizeable.UNITS_MM); + layout.getPosition(b).setTop(SIZE, Sizeable.Unit.CM); + layout.getPosition(b).setRight(SIZE, Sizeable.Unit.EX); + layout.getPosition(b).setBottom(SIZE, Sizeable.Unit.INCH); + layout.getPosition(b).setLeft(SIZE, Sizeable.Unit.MM); assertEquals(SIZE, layout.getPosition(b).getTopValue()); assertEquals(SIZE, layout.getPosition(b).getRightValue()); assertEquals(SIZE, layout.getPosition(b).getBottomValue()); assertEquals(SIZE, layout.getPosition(b).getLeftValue()); - assertEquals(Sizeable.UNITS_CM, layout.getPosition(b).getTopUnits()); - assertEquals(Sizeable.UNITS_EX, layout.getPosition(b).getRightUnits()); - assertEquals(Sizeable.UNITS_INCH, layout.getPosition(b) - .getBottomUnits()); - assertEquals(Sizeable.UNITS_MM, layout.getPosition(b).getLeftUnits()); + assertEquals(Sizeable.Unit.CM, layout.getPosition(b).getTopUnits()); + assertEquals(Sizeable.Unit.EX, layout.getPosition(b).getRightUnits()); + assertEquals(Sizeable.Unit.INCH, layout.getPosition(b).getBottomUnits()); + assertEquals(Sizeable.Unit.MM, layout.getPosition(b).getLeftUnits()); } diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java b/tests/server-side/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java index 6a8267f296..f9f170eb2a 100644 --- a/tests/server-side/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java +++ b/tests/server-side/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java @@ -8,7 +8,8 @@ import com.vaadin.ui.ComponentContainer.ComponentDetachListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.VerticalLayout; -public class TestAbstractComponentContainerListeners extends AbstractListenerMethodsTest { +public class TestAbstractComponentContainerListeners extends + AbstractListenerMethodsTest { public void testComponentDetachListenerAddGetRemove() throws Exception { testListenerAddGetRemove(HorizontalLayout.class, ComponentDetachEvent.class, ComponentDetachListener.class); diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java b/tests/server-side/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java new file mode 100644 index 0000000000..050ab282a6 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java @@ -0,0 +1,162 @@ +package com.vaadin.tests.server.component.abstractfield; + +import java.util.Locale; + +import junit.framework.TestCase; + +import com.vaadin.data.util.MethodProperty; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.StringToIntegerConverter; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.TextField; + +public class AbstractFieldValueConversions extends TestCase { + + Person paulaBean = new Person("Paula", "Brilliant", "paula@brilliant.com", + 34, Sex.FEMALE, new Address("Paula street 1", 12345, "P-town", + Country.FINLAND)); + + public void testWithoutConversion() { + TextField tf = new TextField(); + tf.setPropertyDataSource(new MethodProperty<String>(paulaBean, + "firstName")); + assertEquals("Paula", tf.getValue()); + assertEquals("Paula", tf.getPropertyDataSource().getValue()); + tf.setValue("abc"); + assertEquals("abc", tf.getValue()); + assertEquals("abc", tf.getPropertyDataSource().getValue()); + assertEquals("abc", paulaBean.getFirstName()); + } + + public void testStringIdentityConversion() { + TextField tf = new TextField(); + tf.setConverter(new Converter<String, String>() { + + public String convertToModel(String value, Locale locale) { + return value; + } + + public String convertToPresentation(String value, Locale locale) { + return value; + } + + public Class<String> getModelType() { + return String.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + }); + tf.setPropertyDataSource(new MethodProperty<String>(paulaBean, + "firstName")); + assertEquals("Paula", tf.getValue()); + assertEquals("Paula", tf.getPropertyDataSource().getValue()); + tf.setValue("abc"); + assertEquals("abc", tf.getValue()); + assertEquals("abc", tf.getPropertyDataSource().getValue()); + assertEquals("abc", paulaBean.getFirstName()); + } + + public void testFailingConversion() { + TextField tf = new TextField(); + tf.setConverter(new Converter<String, Integer>() { + + public Integer convertToModel(String value, Locale locale) { + throw new ConversionException("Failed"); + } + + public String convertToPresentation(Integer value, Locale locale) { + throw new ConversionException("Failed"); + } + + public Class<Integer> getModelType() { + // TODO Auto-generated method stub + return null; + } + + public Class<String> getPresentationType() { + // TODO Auto-generated method stub + return null; + } + }); + try { + tf.setValue(1); + fail("setValue(Integer) should throw an exception"); + } catch (Converter.ConversionException e) { + // OK, expected + } + } + + public void testIntegerStringConversion() { + TextField tf = new TextField(); + + tf.setConverter(new StringToIntegerConverter()); + tf.setPropertyDataSource(new MethodProperty<Integer>(paulaBean, "age")); + assertEquals(34, tf.getPropertyDataSource().getValue()); + assertEquals("34", tf.getValue()); + tf.setValue("12"); + assertEquals(12, tf.getPropertyDataSource().getValue()); + assertEquals("12", tf.getValue()); + tf.getPropertyDataSource().setValue(42); + assertEquals(42, tf.getPropertyDataSource().getValue()); + assertEquals("42", tf.getValue()); + } + + public void testBooleanNullConversion() { + CheckBox cb = new CheckBox(); + cb.setConverter(new Converter<Boolean, Boolean>() { + + public Boolean convertToModel(Boolean value, Locale locale) { + // value from a CheckBox should never be null as long as it is + // not set to null (handled by conversion below). + assertNotNull(value); + return value; + } + + public Boolean convertToPresentation(Boolean value, Locale locale) { + // Datamodel -> field + if (value == null) { + return false; + } + + return value; + } + + public Class<Boolean> getModelType() { + return Boolean.class; + } + + public Class<Boolean> getPresentationType() { + return Boolean.class; + } + + }); + MethodProperty<Boolean> property = new MethodProperty<Boolean>( + paulaBean, "deceased"); + cb.setPropertyDataSource(property); + assertEquals(Boolean.FALSE, property.getValue()); + assertEquals(Boolean.FALSE, cb.getValue()); + Boolean newDmValue = cb.getConverter().convertToPresentation( + cb.getValue(), new Locale("fi", "FI")); + assertEquals(Boolean.FALSE, newDmValue); + + // FIXME: Should be able to set to false here to cause datamodel to be + // set to false but the change will not be propagated to the Property + // (field value is already false) + + cb.setValue(true); + assertEquals(Boolean.TRUE, cb.getValue()); + assertEquals(Boolean.TRUE, property.getValue()); + + cb.setValue(false); + assertEquals(Boolean.FALSE, cb.getValue()); + assertEquals(Boolean.FALSE, property.getValue()); + + } + +} diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java b/tests/server-side/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java new file mode 100644 index 0000000000..e39b5d6629 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java @@ -0,0 +1,48 @@ +package com.vaadin.tests.server.component.abstractfield; + +import java.math.BigDecimal; +import java.util.Locale; + +import junit.framework.TestCase; + +import com.vaadin.Application; +import com.vaadin.data.util.MethodProperty; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.ui.TextField; + +public class DefaultConverterFactory extends TestCase { + + Person paulaBean = new Person("Paula", "Brilliant", "paula@brilliant.com", + 34, Sex.FEMALE, new Address("Paula street 1", 12345, "P-town", + Country.FINLAND)); + { + paulaBean.setSalary(49000); + BigDecimal rent = new BigDecimal(57223); + rent = rent.scaleByPowerOfTen(-2); + paulaBean.setRent(rent); + } + + public void testDefaultNumberConversion() { + Application app = new Application(); + Application.setCurrentApplication(app); + TextField tf = new TextField(); + tf.setLocale(new Locale("en", "US")); + tf.setPropertyDataSource(new MethodProperty<Integer>(paulaBean, + "salary")); + assertEquals("49,000", tf.getValue()); + + tf.setLocale(new Locale("fi", "FI")); + // FIXME: The following line should not be necessary and should be + // removed + tf.setPropertyDataSource(new MethodProperty<Integer>(paulaBean, + "salary")); + String value = tf.getValue(); + // Java uses a non-breaking space (ascii 160) instead of space when + // formatting + String expected = "49" + (char) 160 + "000"; + assertEquals(expected, value); + } +} diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java b/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java index 32b80e0bcd..851fece4d1 100644 --- a/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java +++ b/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java @@ -2,11 +2,14 @@ package com.vaadin.tests.server.component.abstractfield; import static org.junit.Assert.assertEquals; +import org.junit.Test; + import com.vaadin.data.Property; import com.vaadin.data.util.AbstractProperty; +import com.vaadin.data.util.converter.Converter.ConversionException; +import com.vaadin.terminal.WrappedRequest; import com.vaadin.ui.AbstractField; - -import org.junit.Test; +import com.vaadin.ui.Root; public class RemoveListenersOnDetach { @@ -14,6 +17,15 @@ public class RemoveListenersOnDetach { int numReadOnlyChanges = 0; AbstractField field = new AbstractField() { + private Root root = new Root() { + + @Override + protected void init(WrappedRequest request) { + + } + + }; + @Override public Class<?> getType() { return null; @@ -31,6 +43,11 @@ public class RemoveListenersOnDetach { super.readOnlyStatusChange(event); numReadOnlyChanges++; } + + @Override + public com.vaadin.ui.Root getRoot() { + return root; + }; }; Property property = new AbstractProperty() { diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractfield/TestAbstractFieldListeners.java b/tests/server-side/com/vaadin/tests/server/component/abstractfield/TestAbstractFieldListeners.java index 7ee70bde13..9937bf92d5 100644 --- a/tests/server-side/com/vaadin/tests/server/component/abstractfield/TestAbstractFieldListeners.java +++ b/tests/server-side/com/vaadin/tests/server/component/abstractfield/TestAbstractFieldListeners.java @@ -5,16 +5,17 @@ import com.vaadin.data.Property.ReadOnlyStatusChangeListener; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.server.component.AbstractListenerMethodsTest; -import com.vaadin.ui.Button; +import com.vaadin.ui.CheckBox; public class TestAbstractFieldListeners extends AbstractListenerMethodsTest { public void testReadOnlyStatusChangeListenerAddGetRemove() throws Exception { - testListenerAddGetRemove(Button.class, ReadOnlyStatusChangeEvent.class, + testListenerAddGetRemove(CheckBox.class, + ReadOnlyStatusChangeEvent.class, ReadOnlyStatusChangeListener.class); } public void testValueChangeListenerAddGetRemove() throws Exception { - testListenerAddGetRemove(Button.class, ValueChangeEvent.class, + testListenerAddGetRemove(CheckBox.class, ValueChangeEvent.class, ValueChangeListener.class); } } diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/TestAbstractOrderedLayoutListeners.java b/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/TestAbstractOrderedLayoutListeners.java index 02143a2796..a0b34aca78 100644 --- a/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/TestAbstractOrderedLayoutListeners.java +++ b/tests/server-side/com/vaadin/tests/server/component/abstractorderedlayout/TestAbstractOrderedLayoutListeners.java @@ -5,7 +5,8 @@ import com.vaadin.event.LayoutEvents.LayoutClickListener; import com.vaadin.tests.server.component.AbstractListenerMethodsTest; import com.vaadin.ui.VerticalLayout; -public class TestAbstractOrderedLayoutListeners extends AbstractListenerMethodsTest { +public class TestAbstractOrderedLayoutListeners extends + AbstractListenerMethodsTest { public void testLayoutClickListenerAddGetRemove() throws Exception { testListenerAddGetRemove(VerticalLayout.class, LayoutClickEvent.class, LayoutClickListener.class); diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractsplitpanel/TestAbstractSplitPanelListeners.java b/tests/server-side/com/vaadin/tests/server/component/abstractsplitpanel/TestAbstractSplitPanelListeners.java index 5e9556c182..2b6cdaa6cc 100644 --- a/tests/server-side/com/vaadin/tests/server/component/abstractsplitpanel/TestAbstractSplitPanelListeners.java +++ b/tests/server-side/com/vaadin/tests/server/component/abstractsplitpanel/TestAbstractSplitPanelListeners.java @@ -5,7 +5,8 @@ import com.vaadin.ui.AbstractSplitPanel.SplitterClickEvent; import com.vaadin.ui.AbstractSplitPanel.SplitterClickListener; import com.vaadin.ui.HorizontalSplitPanel; -public class TestAbstractSplitPanelListeners extends AbstractListenerMethodsTest { +public class TestAbstractSplitPanelListeners extends + AbstractListenerMethodsTest { public void testSplitterClickListenerAddGetRemove() throws Exception { testListenerAddGetRemove(HorizontalSplitPanel.class, SplitterClickEvent.class, SplitterClickListener.class); diff --git a/tests/server-side/com/vaadin/tests/server/component/datefield/ResolutionTest.java b/tests/server-side/com/vaadin/tests/server/component/datefield/ResolutionTest.java new file mode 100644 index 0000000000..00b5c60dad --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/datefield/ResolutionTest.java @@ -0,0 +1,61 @@ +package com.vaadin.tests.server.component.datefield; + +import java.util.ArrayList; + +import junit.framework.TestCase; + +import com.vaadin.tests.util.TestUtil; +import com.vaadin.ui.DateField.Resolution; + +public class ResolutionTest extends TestCase { + + public void testResolutionHigherOrEqualToYear() { + Iterable<Resolution> higherOrEqual = Resolution + .getResolutionsHigherOrEqualTo(Resolution.YEAR); + ArrayList<Resolution> expected = new ArrayList<Resolution>(); + expected.add(Resolution.YEAR); + TestUtil.assertIterableEquals(expected, higherOrEqual); + } + + public void testResolutionHigherOrEqualToDay() { + Iterable<Resolution> higherOrEqual = Resolution + .getResolutionsHigherOrEqualTo(Resolution.DAY); + ArrayList<Resolution> expected = new ArrayList<Resolution>(); + expected.add(Resolution.DAY); + expected.add(Resolution.MONTH); + expected.add(Resolution.YEAR); + TestUtil.assertIterableEquals(expected, higherOrEqual); + + } + + public void testResolutionLowerThanDay() { + Iterable<Resolution> higherOrEqual = Resolution + .getResolutionsLowerThan(Resolution.DAY); + ArrayList<Resolution> expected = new ArrayList<Resolution>(); + expected.add(Resolution.HOUR); + expected.add(Resolution.MINUTE); + expected.add(Resolution.SECOND); + TestUtil.assertIterableEquals(expected, higherOrEqual); + + } + + public void testResolutionLowerThanSecond() { + Iterable<Resolution> higherOrEqual = Resolution + .getResolutionsLowerThan(Resolution.SECOND); + ArrayList<Resolution> expected = new ArrayList<Resolution>(); + TestUtil.assertIterableEquals(expected, higherOrEqual); + } + + public void testResolutionLowerThanYear() { + Iterable<Resolution> higherOrEqual = Resolution + .getResolutionsLowerThan(Resolution.YEAR); + ArrayList<Resolution> expected = new ArrayList<Resolution>(); + expected.add(Resolution.MONTH); + expected.add(Resolution.DAY); + expected.add(Resolution.HOUR); + expected.add(Resolution.MINUTE); + expected.add(Resolution.SECOND); + TestUtil.assertIterableEquals(expected, higherOrEqual); + + } +} diff --git a/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java b/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java new file mode 100644 index 0000000000..aa9753ebcc --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java @@ -0,0 +1,118 @@ +package com.vaadin.tests.server.component.root; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import junit.framework.TestCase; + +import org.easymock.EasyMock; + +import com.vaadin.Application; +import com.vaadin.Application.ApplicationStartEvent; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.ui.Root; + +public class CustomRootClassLoader extends TestCase { + + /** + * Stub root + */ + public static class MyRoot extends Root { + @Override + protected void init(WrappedRequest request) { + // Nothing to see here + } + } + + /** + * Dummy ClassLoader that just saves the name of the requested class before + * delegating to the default implementation. + */ + public class LoggingClassLoader extends ClassLoader { + + private List<String> requestedClasses = new ArrayList<String>(); + + @Override + protected synchronized Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException { + requestedClasses.add(name); + return super.loadClass(name, resolve); + } + } + + /** + * Tests that a Root class can be loaded even if no classloader has been + * provided. + * + * @throws Exception + * if thrown + */ + public void testWithNullClassLoader() throws Exception { + Application application = createStubApplication(); + application.start(new ApplicationStartEvent(null, new Properties(), + null, false)); + + Root root = application.getRootForRequest(createRequestMock(null)); + assertTrue(root instanceof MyRoot); + } + + private static WrappedRequest createRequestMock(ClassLoader classloader) { + // Mock a DeploymentConfiguration to give the passed classloader + DeploymentConfiguration configurationMock = EasyMock + .createMock(DeploymentConfiguration.class); + EasyMock.expect(configurationMock.getClassLoader()).andReturn( + classloader); + + // Mock a WrappedRequest to give the mocked deployment configuration + WrappedRequest requestMock = EasyMock.createMock(WrappedRequest.class); + EasyMock.expect(requestMock.getDeploymentConfiguration()).andReturn( + configurationMock); + + EasyMock.replay(configurationMock, requestMock); + return requestMock; + } + + /** + * Tests that the ClassLoader passed in the ApplicationStartEvent is used to + * load Root classes. + * + * @throws Exception + * if thrown + */ + public void testWithClassLoader() throws Exception { + LoggingClassLoader loggingClassLoader = new LoggingClassLoader(); + + Application application = createStubApplication(); + application.start(new ApplicationStartEvent(null, new Properties(), + null, false)); + + Root root = application + .getRootForRequest(createRequestMock(loggingClassLoader)); + assertTrue(root instanceof MyRoot); + assertEquals(1, loggingClassLoader.requestedClasses.size()); + assertEquals(MyRoot.class.getName(), + loggingClassLoader.requestedClasses.get(0)); + + } + + private Application createStubApplication() { + return new Application() { + @Override + protected String getRootClassName(WrappedRequest request) { + // Always use the same root class + return MyRoot.class.getName(); + } + + @Override + public Root getRootForRequest(WrappedRequest request) + throws RootRequiresMoreInformationException { + // Always create a new root for testing (can't directly use + // getRoot as it's protected) + return getRoot(request); + } + }; + } +} diff --git a/tests/server-side/com/vaadin/tests/server/component/slider/SliderTest.java b/tests/server-side/com/vaadin/tests/server/component/slider/SliderTest.java new file mode 100644 index 0000000000..b969bf5e53 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/slider/SliderTest.java @@ -0,0 +1,25 @@ +package com.vaadin.tests.server.component.slider; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.vaadin.ui.Slider; +import com.vaadin.ui.Slider.ValueOutOfBoundsException; + +public class SliderTest extends TestCase { + + public void testOutOfBounds() { + Slider s = new Slider(0, 10); + s.setValue(0); + Assert.assertEquals(0.0, s.getValue()); + s.setValue(10); + Assert.assertEquals(10.0, s.getValue()); + try { + s.setValue(20); + fail("Should throw out of bounds exception"); + } catch (ValueOutOfBoundsException e) { + // TODO: handle exception + } + + } +} diff --git a/tests/server-side/com/vaadin/tests/server/component/table/TableColumnAlignments.java b/tests/server-side/com/vaadin/tests/server/component/table/TableColumnAlignments.java index 04f436f5c4..299f9c79d4 100644 --- a/tests/server-side/com/vaadin/tests/server/component/table/TableColumnAlignments.java +++ b/tests/server-side/com/vaadin/tests/server/component/table/TableColumnAlignments.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertArrayEquals; import org.junit.Test; import com.vaadin.ui.Table; +import com.vaadin.ui.Table.Align; public class TableColumnAlignments { @@ -15,7 +16,7 @@ public class TableColumnAlignments { properties, 10); Object[] expected = new Object[properties]; for (int i = 0; i < properties; i++) { - expected[i] = Table.ALIGN_LEFT; + expected[i] = Align.LEFT; } org.junit.Assert.assertArrayEquals("getColumnAlignments", expected, t.getColumnAlignments()); @@ -27,9 +28,8 @@ public class TableColumnAlignments { int properties = 5; Table t = TableGenerator .createTableWithDefaultContainer(properties, 10); - String[] explicitAlignments = new String[] { Table.ALIGN_CENTER, - Table.ALIGN_LEFT, Table.ALIGN_RIGHT, Table.ALIGN_RIGHT, - Table.ALIGN_LEFT }; + Align[] explicitAlignments = new Align[] { Align.CENTER, Align.LEFT, + Align.RIGHT, Align.RIGHT, Align.LEFT }; t.setColumnAlignments(explicitAlignments); @@ -40,28 +40,10 @@ public class TableColumnAlignments { @Test public void invalidColumnAlignmentStrings() { Table t = TableGenerator.createTableWithDefaultContainer(3, 7); - String[] defaultAlignments = new String[] { Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT }; + Align[] defaultAlignments = new Align[] { Align.LEFT, Align.LEFT, + Align.LEFT }; try { - t.setColumnAlignments(new String[] { "a", "b", "c" }); - junit.framework.Assert - .fail("No exception thrown for invalid array length"); - } catch (IllegalArgumentException e) { - // Ok, expected - } - - assertArrayEquals("Invalid change affected alignments", - defaultAlignments, t.getColumnAlignments()); - - } - - @Test - public void invalidColumnAlignmentString() { - Table t = TableGenerator.createTableWithDefaultContainer(3, 7); - String[] defaultAlignments = new String[] { Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT }; - try { - t.setColumnAlignment("Property 1", "a"); + t.setColumnAlignments(new Align[] { Align.RIGHT, Align.RIGHT }); junit.framework.Assert .fail("No exception thrown for invalid array length"); } catch (IllegalArgumentException e) { @@ -76,10 +58,10 @@ public class TableColumnAlignments { @Test public void columnAlignmentForPropertyNotInContainer() { Table t = TableGenerator.createTableWithDefaultContainer(3, 7); - String[] defaultAlignments = new String[] { Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT }; + Align[] defaultAlignments = new Align[] { Align.LEFT, Align.LEFT, + Align.LEFT }; try { - t.setColumnAlignment("Property 1200", Table.ALIGN_LEFT); + t.setColumnAlignment("Property 1200", Align.LEFT); // FIXME: Uncomment as there should be an exception (#6475) // junit.framework.Assert // .fail("No exception thrown for property not in container"); @@ -100,12 +82,11 @@ public class TableColumnAlignments { @Test public void invalidColumnAlignmentsLength() { Table t = TableGenerator.createTableWithDefaultContainer(7, 7); - String[] defaultAlignments = new String[] { Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT, Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT, Table.ALIGN_LEFT }; + Align[] defaultAlignments = new Align[] { Align.LEFT, Align.LEFT, + Align.LEFT, Align.LEFT, Align.LEFT, Align.LEFT, Align.LEFT }; try { - t.setColumnAlignments(new String[] { Table.ALIGN_LEFT }); + t.setColumnAlignments(new Align[] { Align.LEFT }); junit.framework.Assert .fail("No exception thrown for invalid array length"); } catch (IllegalArgumentException e) { @@ -115,7 +96,7 @@ public class TableColumnAlignments { defaultAlignments, t.getColumnAlignments()); try { - t.setColumnAlignments(new String[] {}); + t.setColumnAlignments(new Align[] {}); junit.framework.Assert .fail("No exception thrown for invalid array length"); } catch (IllegalArgumentException e) { @@ -125,10 +106,9 @@ public class TableColumnAlignments { defaultAlignments, t.getColumnAlignments()); try { - t.setColumnAlignments(new String[] { Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT, Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT, Table.ALIGN_LEFT, - Table.ALIGN_LEFT }); + t.setColumnAlignments(new Align[] { Align.LEFT, Align.LEFT, + Align.LEFT, Align.LEFT, Align.LEFT, Align.LEFT, Align.LEFT, + Align.LEFT }); junit.framework.Assert .fail("No exception thrown for invalid array length"); } catch (IllegalArgumentException e) { @@ -144,13 +124,11 @@ public class TableColumnAlignments { int properties = 5; Table t = TableGenerator .createTableWithDefaultContainer(properties, 10); - String[] explicitAlignments = new String[] { Table.ALIGN_CENTER, - Table.ALIGN_LEFT, Table.ALIGN_RIGHT, Table.ALIGN_RIGHT, - Table.ALIGN_LEFT }; + Align[] explicitAlignments = new Align[] { Align.CENTER, Align.LEFT, + Align.RIGHT, Align.RIGHT, Align.LEFT }; - String[] currentAlignments = new String[] { Table.ALIGN_LEFT, - Table.ALIGN_LEFT, Table.ALIGN_LEFT, Table.ALIGN_LEFT, - Table.ALIGN_LEFT }; + Align[] currentAlignments = new Align[] { Align.LEFT, Align.LEFT, + Align.LEFT, Align.LEFT, Align.LEFT }; for (int i = 0; i < properties; i++) { t.setColumnAlignment("Property " + i, explicitAlignments[i]); diff --git a/tests/server-side/com/vaadin/tests/server/component/table/TableListeners.java b/tests/server-side/com/vaadin/tests/server/component/table/TableListeners.java index 6d9c7ed0eb..6cc522f8c7 100644 --- a/tests/server-side/com/vaadin/tests/server/component/table/TableListeners.java +++ b/tests/server-side/com/vaadin/tests/server/component/table/TableListeners.java @@ -20,7 +20,8 @@ public class TableListeners extends AbstractListenerMethodsTest { } public void testItemClickListenerAddGetRemove() throws Exception { - testListenerAddGetRemove(Table.class, ItemClickEvent.class, ItemClickListener.class); + testListenerAddGetRemove(Table.class, ItemClickEvent.class, + ItemClickListener.class); } public void testFooterClickListenerAddGetRemove() throws Exception { diff --git a/tests/server-side/com/vaadin/tests/server/component/tabsheet/TestTabSheet.java b/tests/server-side/com/vaadin/tests/server/component/tabsheet/TestTabSheet.java index 69de33f3af..40d0ffd17d 100644 --- a/tests/server-side/com/vaadin/tests/server/component/tabsheet/TestTabSheet.java +++ b/tests/server-side/com/vaadin/tests/server/component/tabsheet/TestTabSheet.java @@ -5,13 +5,13 @@ import static org.junit.Assert.assertNotNull; import java.util.Iterator; +import org.junit.Test; + import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.Tab; -import org.junit.Test; - public class TestTabSheet { @Test diff --git a/tests/server-side/com/vaadin/tests/server/component/textfield/TextFieldWithPropertyFormatter.java b/tests/server-side/com/vaadin/tests/server/component/textfield/TextFieldWithPropertyFormatter.java index 5a494b8ccd..0749dc299e 100644 --- a/tests/server-side/com/vaadin/tests/server/component/textfield/TextFieldWithPropertyFormatter.java +++ b/tests/server-side/com/vaadin/tests/server/component/textfield/TextFieldWithPropertyFormatter.java @@ -2,17 +2,17 @@ package com.vaadin.tests.server.component.textfield; import java.util.Collections; +import junit.framework.TestCase; + import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.util.ObjectProperty; import com.vaadin.data.util.PropertyFormatter; -import com.vaadin.terminal.Paintable; -import com.vaadin.terminal.Paintable.RepaintRequestEvent; +import com.vaadin.ui.Component.RepaintRequestEvent; +import com.vaadin.ui.Component.RepaintRequestListener; import com.vaadin.ui.TextField; -import junit.framework.TestCase; - public class TextFieldWithPropertyFormatter extends TestCase { private static final String INPUT_VALUE = "foo"; @@ -20,7 +20,7 @@ public class TextFieldWithPropertyFormatter extends TestCase { private static final String FORMATTED_VALUE = "FOOBAR"; private static final String ORIGINAL_VALUE = "Original"; private TextField field; - private PropertyFormatter formatter; + private PropertyFormatter<String> formatter; private ObjectProperty<String> property; private ValueChangeListener listener; private int listenerCalled; @@ -32,16 +32,16 @@ public class TextFieldWithPropertyFormatter extends TestCase { field = new TextField(); - formatter = new PropertyFormatter() { + formatter = new PropertyFormatter<String>() { @Override - public Object parse(String formattedValue) throws Exception { + public String parse(String formattedValue) throws Exception { assertEquals(INPUT_VALUE, formattedValue); return PARSED_VALUE; } @Override - public String format(Object value) { + public String format(String value) { return FORMATTED_VALUE; } }; @@ -59,9 +59,9 @@ public class TextFieldWithPropertyFormatter extends TestCase { assertEquals(FORMATTED_VALUE, event.getProperty().getValue()); } }; - + field.addListener(listener); - field.addListener(new Paintable.RepaintRequestListener() { + field.addListener(new RepaintRequestListener() { public void repaintRequested(RepaintRequestEvent event) { repainted++; } @@ -81,7 +81,9 @@ public class TextFieldWithPropertyFormatter extends TestCase { private void checkEndState() { assertEquals(1, listenerCalled); - assertEquals(1, repainted); + // setModified triggers repaint, this is done 2 times. A + // ValueChangeEvent triggers the third + assertEquals(3, repainted); assertEquals(FORMATTED_VALUE, field.getValue()); assertEquals(FORMATTED_VALUE, formatter.getValue()); assertEquals(PARSED_VALUE, property.getValue()); diff --git a/tests/server-side/com/vaadin/tests/server/component/urifragmentutility/UriFragmentUtilityListeners.java b/tests/server-side/com/vaadin/tests/server/component/urifragmentutility/UriFragmentUtilityListeners.java deleted file mode 100644 index 70fb68b9ec..0000000000 --- a/tests/server-side/com/vaadin/tests/server/component/urifragmentutility/UriFragmentUtilityListeners.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.vaadin.tests.server.component.urifragmentutility; - -import com.vaadin.tests.server.component.AbstractListenerMethodsTest; -import com.vaadin.ui.UriFragmentUtility; -import com.vaadin.ui.UriFragmentUtility.FragmentChangedEvent; -import com.vaadin.ui.UriFragmentUtility.FragmentChangedListener; - -public class UriFragmentUtilityListeners extends AbstractListenerMethodsTest { - public void testFragmentChangedListenerAddGetRemove() throws Exception { - testListenerAddGetRemove(UriFragmentUtility.class, - FragmentChangedEvent.class, FragmentChangedListener.class); - } -} diff --git a/tests/server-side/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java b/tests/server-side/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java index 50de91e2af..f8901803c3 100644 --- a/tests/server-side/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java +++ b/tests/server-side/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java @@ -1,22 +1,23 @@ package com.vaadin.tests.server.component.window; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Test; import com.vaadin.Application; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; public class AddRemoveSubWindow { - public class TestApp extends Application { + public class TestApp extends Application.LegacyApplication { @Override public void init() { - Window w = new Window("Main window"); + LegacyWindow w = new LegacyWindow("Main window"); setMainWindow(w); } } @@ -26,7 +27,7 @@ public class AddRemoveSubWindow { TestApp app = new TestApp(); app.init(); Window subWindow = new Window("Sub window"); - Window mainWindow = app.getMainWindow(); + Root mainWindow = app.getMainWindow(); mainWindow.addWindow(subWindow); // Added to main window so the parent of the sub window should be the @@ -44,7 +45,7 @@ public class AddRemoveSubWindow { // Try to add the same sub window to another window try { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); w.addWindow(subWindow); assertTrue("Window.addWindow did not throw the expected exception", false); @@ -60,23 +61,18 @@ public class AddRemoveSubWindow { TestApp app = new TestApp(); app.init(); Window subWindow = new Window("Sub window"); - Window mainWindow = app.getMainWindow(); + Root mainWindow = app.getMainWindow(); mainWindow.addWindow(subWindow); // Added to main window so the parent of the sub window should be the // main window assertEquals(subWindow.getParent(), mainWindow); - // Remove from the wrong window, should result in an exception - boolean removed = subWindow.removeWindow(subWindow); - assertFalse("Window was removed even though it should not have been", - removed); - // Parent should still be set assertEquals(subWindow.getParent(), mainWindow); // Remove from the main window and assert it has been removed - removed = mainWindow.removeWindow(subWindow); + boolean removed = mainWindow.removeWindow(subWindow); assertTrue("Window was not removed correctly", removed); assertNull(subWindow.getParent()); } diff --git a/tests/server-side/com/vaadin/tests/server/component/window/AttachDetachWindow.java b/tests/server-side/com/vaadin/tests/server/component/window/AttachDetachWindow.java index 5fabe40bb7..7423ba8669 100644 --- a/tests/server-side/com/vaadin/tests/server/component/window/AttachDetachWindow.java +++ b/tests/server-side/com/vaadin/tests/server/component/window/AttachDetachWindow.java @@ -3,61 +3,36 @@ package com.vaadin.tests.server.component.window; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import org.junit.Test; + import com.vaadin.Application; -import com.vaadin.ui.Component; +import com.vaadin.terminal.WrappedRequest; import com.vaadin.ui.Label; +import com.vaadin.ui.Root; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; -import org.junit.Test; - public class AttachDetachWindow { - private Application testApp = new Application() { - @Override - public void init() { - } - }; + private Application testApp = new Application(); + + private interface TestContainer { + public boolean attachCalled(); + + public boolean detachCalled(); - private class TestWindow extends Window { + public TestContent getTestContent(); + + public Application getApplication(); + } + + private class TestWindow extends Window implements TestContainer { boolean windowAttachCalled = false; - boolean contentAttachCalled = false; - boolean childAttachCalled = false; boolean windowDetachCalled = false; - boolean contentDetachCalled = false; - boolean childDetachCalled = false; + private TestContent testContent = new TestContent();; TestWindow() { - setContent(new VerticalLayout() { - @Override - public void attach() { - super.attach(); - contentAttachCalled = true; - } - - @Override - public void detach() { - super.detach(); - contentDetachCalled = true; - } - }); - addComponent(new Label() { - @Override - public void attach() { - super.attach(); - childAttachCalled = true; - } - - @Override - public void detach() { - super.detach(); - childDetachCalled = true; - } - }); - } - - Component getChild() { - return getComponentIterator().next(); + setContent(testContent); } @Override @@ -71,9 +46,97 @@ public class AttachDetachWindow { super.detach(); windowDetachCalled = true; } + + public boolean attachCalled() { + return windowAttachCalled; + } + + public boolean detachCalled() { + return windowDetachCalled; + } + + public TestContent getTestContent() { + return testContent; + } + } + + private class TestContent extends VerticalLayout { + boolean contentDetachCalled = false; + boolean childDetachCalled = false; + boolean contentAttachCalled = false; + boolean childAttachCalled = false; + + private Label child = new Label() { + @Override + public void attach() { + super.attach(); + childAttachCalled = true; + } + + @Override + public void detach() { + super.detach(); + childDetachCalled = true; + } + }; + + public TestContent() { + addComponent(child); + } + + @Override + public void attach() { + super.attach(); + contentAttachCalled = true; + } + + @Override + public void detach() { + super.detach(); + contentDetachCalled = true; + } + } + + private class TestRoot extends Root implements TestContainer { + boolean rootAttachCalled = false; + boolean rootDetachCalled = false; + private TestContent testContent = new TestContent();; + + public TestRoot() { + setContent(testContent); + } + + @Override + protected void init(WrappedRequest request) { + // Do nothing + } + + public boolean attachCalled() { + return rootAttachCalled; + } + + public boolean detachCalled() { + return rootDetachCalled; + } + + public TestContent getTestContent() { + return testContent; + } + + @Override + public void attach() { + super.attach(); + rootAttachCalled = true; + } + + @Override + public void detach() { + super.detach(); + rootDetachCalled = true; + } } - TestWindow main = new TestWindow(); + TestRoot main = new TestRoot(); TestWindow sub = new TestWindow(); @Test @@ -86,7 +149,7 @@ public class AttachDetachWindow { assertUnattached(sub); // attaching main should recurse to sub - testApp.setMainWindow(main); + main.setApplication(testApp); assertAttached(main); assertAttached(sub); } @@ -96,7 +159,7 @@ public class AttachDetachWindow { assertUnattached(main); assertUnattached(sub); - testApp.setMainWindow(main); + main.setApplication(testApp); assertAttached(main); assertUnattached(sub); @@ -108,7 +171,7 @@ public class AttachDetachWindow { @Test public void removeSubWindowBeforeDetachingMainWindow() { - testApp.addWindow(main); + main.setApplication(testApp); main.addWindow(sub); // sub should be detached when removing from attached main @@ -117,18 +180,18 @@ public class AttachDetachWindow { assertDetached(sub); // main detach should recurse to sub - testApp.removeWindow(main); + main.setApplication(null); assertDetached(main); assertDetached(sub); } @Test public void removeSubWindowAfterDetachingMainWindow() { - testApp.addWindow(main); + main.setApplication(testApp); main.addWindow(sub); // main detach should recurse to sub - testApp.removeWindow(main); + main.setApplication(null); assertDetached(main); assertDetached(sub); @@ -141,27 +204,31 @@ public class AttachDetachWindow { * Asserts that win and its children are attached to testApp and their * attach() methods have been called. */ - private void assertAttached(TestWindow win) { - assertTrue("window attach not called", win.windowAttachCalled); - assertTrue("window content attach not called", win.contentAttachCalled); - assertTrue("window child attach not called", win.childAttachCalled); + private void assertAttached(TestContainer win) { + TestContent testContent = win.getTestContent(); + + assertTrue("window attach not called", win.attachCalled()); + assertTrue("window content attach not called", + testContent.contentAttachCalled); + assertTrue("window child attach not called", + testContent.childAttachCalled); assertSame("window not attached", win.getApplication(), testApp); - assertSame("window content not attached", win.getContent() - .getApplication(), testApp); - assertSame("window children not attached", win.getChild() - .getApplication(), testApp); + assertSame("window content not attached", testContent.getApplication(), + testApp); + assertSame("window children not attached", + testContent.child.getApplication(), testApp); } /** * Asserts that win and its children are not attached. */ - private void assertUnattached(TestWindow win) { + private void assertUnattached(TestContainer win) { assertSame("window not detached", win.getApplication(), null); - assertSame("window content not detached", win.getContent() - .getApplication(), null); - assertSame("window children not detached", win.getChild() + assertSame("window content not detached", win.getTestContent() .getApplication(), null); + assertSame("window children not detached", + win.getTestContent().child.getApplication(), null); } /** @@ -170,10 +237,12 @@ public class AttachDetachWindow { * * @param win */ - private void assertDetached(TestWindow win) { + private void assertDetached(TestContainer win) { assertUnattached(win); - assertTrue("window detach not called", win.windowDetachCalled); - assertTrue("window content detach not called", win.contentDetachCalled); - assertTrue("window child detach not called", win.childDetachCalled); + assertTrue("window detach not called", win.detachCalled()); + assertTrue("window content detach not called", + win.getTestContent().contentDetachCalled); + assertTrue("window child detach not called", + win.getTestContent().childDetachCalled); } } diff --git a/tests/server-side/com/vaadin/tests/server/components/AbstractTestFieldValueChange.java b/tests/server-side/com/vaadin/tests/server/components/AbstractTestFieldValueChange.java index fcea309e84..3512f555c9 100644 --- a/tests/server-side/com/vaadin/tests/server/components/AbstractTestFieldValueChange.java +++ b/tests/server-side/com/vaadin/tests/server/components/AbstractTestFieldValueChange.java @@ -22,12 +22,12 @@ import com.vaadin.ui.AbstractField; * override {@link #setValue(AbstractField)} to set the field value via * <code>changeVariables()</code>. */ -public abstract class AbstractTestFieldValueChange extends TestCase { +public abstract class AbstractTestFieldValueChange<T> extends TestCase { - private AbstractField field; + private AbstractField<T> field; private ValueChangeListener listener; - protected void setUp(AbstractField field) throws Exception { + protected void setUp(AbstractField<T> field) throws Exception { this.field = field; listener = EasyMock.createStrictMock(ValueChangeListener.class); @@ -155,14 +155,14 @@ public abstract class AbstractTestFieldValueChange extends TestCase { EasyMock.verify(listener); } - protected AbstractField getField() { + protected AbstractField<T> getField() { return field; } /** * Override in subclasses to set value with changeVariables(). */ - protected void setValue(AbstractField field) { + protected void setValue(AbstractField<T> field) { field.setValue("newValue"); } diff --git a/tests/server-side/com/vaadin/tests/server/components/TestComboBoxValueChange.java b/tests/server-side/com/vaadin/tests/server/components/TestComboBoxValueChange.java index 3fbe1406f2..308889fa33 100644 --- a/tests/server-side/com/vaadin/tests/server/components/TestComboBoxValueChange.java +++ b/tests/server-side/com/vaadin/tests/server/components/TestComboBoxValueChange.java @@ -12,7 +12,8 @@ import com.vaadin.ui.ComboBox; * * See <a href="http://dev.vaadin.com/ticket/4394">Ticket 4394</a>. */ -public class TestComboBoxValueChange extends AbstractTestFieldValueChange { +public class TestComboBoxValueChange extends + AbstractTestFieldValueChange<Object> { @Override protected void setUp() throws Exception { ComboBox combo = new ComboBox(); @@ -21,10 +22,10 @@ public class TestComboBoxValueChange extends AbstractTestFieldValueChange { } @Override - protected void setValue(AbstractField field) { + protected void setValue(AbstractField<Object> field) { Map<String, Object> variables = new HashMap<String, Object>(); variables.put("selected", new String[] { "myvalue" }); - field.changeVariables(field, variables); + ((ComboBox) field).changeVariables(field, variables); } } diff --git a/tests/server-side/com/vaadin/tests/server/components/TestTextFieldValueChange.java b/tests/server-side/com/vaadin/tests/server/components/TestTextFieldValueChange.java index 2c911d5f3f..f5db67be97 100644 --- a/tests/server-side/com/vaadin/tests/server/components/TestTextFieldValueChange.java +++ b/tests/server-side/com/vaadin/tests/server/components/TestTextFieldValueChange.java @@ -18,7 +18,8 @@ import com.vaadin.ui.TextField; * * See <a href="http://dev.vaadin.com/ticket/4394">Ticket 4394</a>. */ -public class TestTextFieldValueChange extends AbstractTestFieldValueChange { +public class TestTextFieldValueChange extends + AbstractTestFieldValueChange<String> { @Override protected void setUp() throws Exception { @@ -36,10 +37,10 @@ public class TestTextFieldValueChange extends AbstractTestFieldValueChange { } @Override - protected void setValue(AbstractField field) { + protected void setValue(AbstractField<String> field) { Map<String, Object> variables = new HashMap<String, Object>(); variables.put("text", "newValue"); - field.changeVariables(field, variables); + ((TextField) field).changeVariables(field, variables); } /** @@ -54,8 +55,7 @@ public class TestTextFieldValueChange extends AbstractTestFieldValueChange { getField().setPropertyDataSource(property); // defaults, buffering off - getField().setWriteThrough(true); - getField().setReadThrough(true); + getField().setBuffered(false); // Expectations and start test getListener().valueChange(EasyMock.isA(ValueChangeEvent.class)); @@ -142,8 +142,7 @@ public class TestTextFieldValueChange extends AbstractTestFieldValueChange { initialValue); // set buffering - getField().setWriteThrough(false); - getField().setReadThrough(false); + getField().setBuffered(true); // Value change should only happen once, when setting the property, // further changes via property should not cause value change listener diff --git a/tests/server-side/com/vaadin/tests/server/components/TestWindow.java b/tests/server-side/com/vaadin/tests/server/components/TestWindow.java index 89d018c8a5..7713f69f68 100644 --- a/tests/server-side/com/vaadin/tests/server/components/TestWindow.java +++ b/tests/server-side/com/vaadin/tests/server/components/TestWindow.java @@ -7,6 +7,7 @@ import junit.framework.TestCase; import org.easymock.EasyMock; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; import com.vaadin.ui.Window.CloseEvent; import com.vaadin.ui.Window.CloseListener; @@ -20,6 +21,7 @@ public class TestWindow extends TestCase { @Override protected void setUp() throws Exception { window = new Window(); + new LegacyWindow().addWindow(window); } public void testCloseListener() { diff --git a/tests/server-side/com/vaadin/tests/server/validation/RangeValidatorTest.java b/tests/server-side/com/vaadin/tests/server/validation/RangeValidatorTest.java new file mode 100644 index 0000000000..e3320b8699 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/validation/RangeValidatorTest.java @@ -0,0 +1,52 @@ +package com.vaadin.tests.server.validation; + +import junit.framework.TestCase; + +import com.vaadin.data.validator.IntegerRangeValidator; + +public class RangeValidatorTest extends TestCase { + + // This test uses IntegerRangeValidator for simplicity. + // IntegerRangeValidator contains no code so we really are testing + // RangeValidator + public void testMinValueNonInclusive() { + IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10); + iv.setMinValueIncluded(false); + assertFalse(iv.isValid(0)); + assertTrue(iv.isValid(10)); + assertFalse(iv.isValid(11)); + assertFalse(iv.isValid(-1)); + } + + public void testMinMaxValuesInclusive() { + IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10); + assertTrue(iv.isValid(0)); + assertTrue(iv.isValid(1)); + assertTrue(iv.isValid(10)); + assertFalse(iv.isValid(11)); + assertFalse(iv.isValid(-1)); + } + + public void testMaxValueNonInclusive() { + IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10); + iv.setMaxValueIncluded(false); + assertTrue(iv.isValid(0)); + assertTrue(iv.isValid(9)); + assertFalse(iv.isValid(10)); + assertFalse(iv.isValid(11)); + assertFalse(iv.isValid(-1)); + } + + public void testMinMaxValuesNonInclusive() { + IntegerRangeValidator iv = new IntegerRangeValidator("Failed", 0, 10); + iv.setMinValueIncluded(false); + iv.setMaxValueIncluded(false); + + assertFalse(iv.isValid(0)); + assertTrue(iv.isValid(1)); + assertTrue(iv.isValid(9)); + assertFalse(iv.isValid(10)); + assertFalse(iv.isValid(11)); + assertFalse(iv.isValid(-1)); + } +} diff --git a/tests/server-side/com/vaadin/tests/server/validation/TestBeanValidation.java b/tests/server-side/com/vaadin/tests/server/validation/TestBeanValidation.java new file mode 100644 index 0000000000..8f6928fc35 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/validation/TestBeanValidation.java @@ -0,0 +1,57 @@ +package com.vaadin.tests.server.validation; + +import org.junit.Test; + +import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.validator.BeanValidator; +import com.vaadin.tests.data.bean.BeanToValidate; + +public class TestBeanValidation { + @Test(expected = InvalidValueException.class) + public void testBeanValidationNull() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, + "firstname"); + validator.validate(null); + } + + @Test(expected = InvalidValueException.class) + public void testBeanValidationStringTooShort() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, + "firstname"); + validator.validate("aa"); + } + + @Test + public void testBeanValidationStringOk() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, + "firstname"); + validator.validate("aaa"); + } + + @Test(expected = InvalidValueException.class) + public void testBeanValidationIntegerTooSmall() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, "age"); + validator.validate(17); + } + + @Test + public void testBeanValidationIntegerOk() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, "age"); + validator.validate(18); + } + + @Test(expected = InvalidValueException.class) + public void testBeanValidationTooManyDigits() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, + "decimals"); + validator.validate("1234.567"); + } + + @Test + public void testBeanValidationDigitsOk() { + BeanValidator validator = new BeanValidator(BeanToValidate.class, + "decimals"); + validator.validate("123.45"); + } + +} diff --git a/tests/server-side/com/vaadin/tests/server/validation/TestReadOnlyValidation.java b/tests/server-side/com/vaadin/tests/server/validation/TestReadOnlyValidation.java index c4052c2db8..e37b97e02c 100644 --- a/tests/server-side/com/vaadin/tests/server/validation/TestReadOnlyValidation.java +++ b/tests/server-side/com/vaadin/tests/server/validation/TestReadOnlyValidation.java @@ -11,7 +11,7 @@ public class TestReadOnlyValidation { public void testIntegerValidation() { TextField field = new TextField(); field.addValidator(new IntegerValidator("Enter a Valid Number")); - field.setValue(Integer.valueOf(10)); + field.setValue(String.valueOf(10)); field.validate(); } } diff --git a/tests/server-side/com/vaadin/tests/util/GraphVizClassHierarchyCreator.java b/tests/server-side/com/vaadin/tests/util/GraphVizClassHierarchyCreator.java new file mode 100644 index 0000000000..9e791500b0 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/util/GraphVizClassHierarchyCreator.java @@ -0,0 +1,149 @@ +package com.vaadin.tests.util; + +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.vaadin.tests.VaadinClasses; + +public class GraphVizClassHierarchyCreator { + + public static void main(String[] args) { + String gv = getGraphVizHierarchy((List) VaadinClasses.getComponents(), + "com.vaadin"); + System.out.println(gv); + } + + private static String getGraphVizHierarchy(List<Class> classes, + String packageToInclude) { + boolean includeInterfaces = false; + + StringBuilder header = new StringBuilder(); + header.append("digraph finite_state_machine {\n" + + " rankdir=BT;\n" + " dpi=\"150\";\n" + + " ratio=\"0.25\";\n"); + + StringBuilder sb = new StringBuilder(); + + Set<Class> classesAndParents = new HashSet<Class>(); + for (Class<?> cls : classes) { + addClassAndParents(classesAndParents, cls, packageToInclude); + } + + Set<Class> interfaces = new HashSet<Class>(); + for (Object cls : classesAndParents.toArray()) { + for (Class<?> c : ((Class) cls).getInterfaces()) { + addClassAndParentInterfaces(classesAndParents, c, + packageToInclude); + } + } + + for (Class<?> c : classesAndParents) { + appendClass(sb, c, c.getSuperclass(), packageToInclude, + includeInterfaces); + for (Class ci : c.getInterfaces()) { + appendClass(sb, c, ci, packageToInclude, includeInterfaces); + } + } + + header.append(" node [shape = ellipse, style=\"dotted\"] "); + for (Class c : classesAndParents) { + if (!c.isInterface() && Modifier.isAbstract(c.getModifiers())) { + header.append(c.getSimpleName() + " "); + } + } + if (includeInterfaces) { + System.out.print(" node [shape = ellipse, style=\"solid\"] "); + for (Class c : classesAndParents) { + if (c.isInterface()) { + header.append(c.getSimpleName() + " "); + } + } + header.append(";\n"); + } + header.append(";\n"); + header.append(" node [shape = rectangle, style=\"solid\"];\n"); + return header.toString() + sb.toString() + "}"; + } + + private static void addClassAndParents(Set<Class> classesAndParents, + Class<?> cls, String packageToInclude) { + + if (cls == null) { + return; + } + + if (classesAndParents.contains(cls)) { + return; + } + + if (!cls.getPackage().getName().startsWith(packageToInclude)) { + return; + } + + classesAndParents.add(cls); + addClassAndParents(classesAndParents, cls.getSuperclass(), + packageToInclude); + + } + + private static void addClassAndParentInterfaces( + Set<Class> classesAndParents, Class<?> cls, String packageToInclude) { + + if (cls == null) { + return; + } + + if (classesAndParents.contains(cls)) { + return; + } + + if (!cls.getPackage().getName().startsWith(packageToInclude)) { + return; + } + + classesAndParents.add(cls); + for (Class iClass : cls.getInterfaces()) { + addClassAndParentInterfaces(classesAndParents, iClass, + packageToInclude); + } + + } + + private static void appendClass(StringBuilder sb, Class<?> c, + Class<?> superClass, String packageToInclude, + boolean includeInterfaces) { + if (superClass == null) { + return; + } + if (!c.getPackage().getName().startsWith(packageToInclude)) { + return; + } + if (!superClass.getPackage().getName().startsWith(packageToInclude)) { + return; + } + if (!includeInterfaces && (c.isInterface() || superClass.isInterface())) { + return; + } + + sb.append(c.getSimpleName()).append(" -> ") + .append(superClass.getSimpleName()).append("\n"); + + } + + private static void addInterfaces(Set<Class> interfaces, Class<?> cls) { + if (interfaces.contains(cls)) { + return; + } + + if (cls.isInterface()) { + interfaces.add(cls); + } + + for (Class c : cls.getInterfaces()) { + addInterfaces(interfaces, c); + } + } + +} diff --git a/tests/server-side/com/vaadin/tests/util/TestUtil.java b/tests/server-side/com/vaadin/tests/util/TestUtil.java new file mode 100644 index 0000000000..e84f9dd8b9 --- /dev/null +++ b/tests/server-side/com/vaadin/tests/util/TestUtil.java @@ -0,0 +1,43 @@ +package com.vaadin.tests.util; + +import java.util.Iterator; + +import junit.framework.Assert; + +public class TestUtil { + public static void assertArrays(Object[] actualObjects, + Object[] expectedObjects) { + Assert.assertEquals( + "Actual contains a different number of values than was expected", + expectedObjects.length, actualObjects.length); + + for (int i = 0; i < actualObjects.length; i++) { + Object actual = actualObjects[i]; + Object expected = expectedObjects[i]; + + Assert.assertEquals("Item[" + i + "] does not match", expected, + actual); + } + + } + + public static void assertIterableEquals(Iterable<?> iterable1, + Iterable<?> iterable2) { + Iterator<?> i1 = iterable1.iterator(); + Iterator<?> i2 = iterable2.iterator(); + + while (i1.hasNext()) { + Object o1 = i1.next(); + if (!i2.hasNext()) { + Assert.fail("The second iterable contains fewer items than the first. The object " + + o1 + " has no match in the second iterable."); + } + Object o2 = i2.next(); + Assert.assertEquals(o1, o2); + } + if (i2.hasNext()) { + Assert.fail("The second iterable contains more items than the first. The object " + + i2.next() + " has no match in the first iterable."); + } + } +} diff --git a/tests/test.xml b/tests/test.xml index fbb0a3a019..28459c37e9 100644 --- a/tests/test.xml +++ b/tests/test.xml @@ -1,11 +1,17 @@ <?xml version="1.0"?> - -<project name="Run Vaadin Testbench Tests" basedir="." default="run-and-clean-up"> +<project xmlns:antcontrib="antlib:net.sf.antcontrib" + xmlns:ivy="antlib:org.apache.ivy.ant" + name="Run Vaadin Testbench Tests" basedir="." default="run-and-clean-up"> + + <property name="project.root" value=".."/> + <!-- Import common targets --> + <import file="../build/common.xml" /> + <!-- ================================================================== --> <!-- Configuration --> <!-- ================================================================== --> <!-- Browsers to use for testing --> - <property name="browsers-windows" value="winxp-ie6,winxp-ie7,winxp-ie8,win7-ie9,winxp-firefox36,winxp-firefox11,winxp-safari4,winxp-safari5,winxp-googlechrome13,winxp-googlechrome18,winxp-opera1060,winxp-opera11" /> + <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox11,winxp-safari5,winxp-googlechrome18,winxp-opera11" /> <property name="browsers-linux" value="linux-firefox3,linux-opera10,linux-googlechrome8" /> <property name="browsers-mac" value="osx-firefox3,osx-opera10,osx-googlechrome8,osx-safari4,osx-safari5" /> @@ -27,21 +33,19 @@ <property name="com.vaadin.testbench.debug" value="false"/> <!-- Temporary output directory, created and removed by this script --> - <!-- <property name="test-output-dir" value="../build/test-output" /> --> - <fail unless="test-output-dir" message="The 'test-output-dir' property must be defined." /> - + <fail unless="test-output-dir" message="The 'test-output-dir' property must be defined." /> + <property name="class-dir" value="${test-output-dir}/classes" /> - <taskdef resource="net/sf/antcontrib/antlib.xml"> - <classpath> - <pathelement location="../build/lib/ant-contrib-1.0b3.jar" /> - </classpath> - </taskdef> - - <!-- classpath must include test bench jar and its dependencies --> - <path id="classpath"> - <fileset dir="${com.vaadin.testbench.lib.dir}" includes="**/*.jar" /> - <fileset dir="../build/lib" includes="emma*.jar" /> - </path> + + <target name="initialize" depends="common.init-deps"> + <ivy:resolve conf="emma"/> + <ivy:cachepath pathid="emma.lib" conf="emma" /> + <!-- classpath must include test bench jar and its dependencies --> + <path id="classpath"> + <fileset dir="${com.vaadin.testbench.lib.dir}" includes="**/*.jar" /> + <path refid="emma.lib" /> + </path> + </target> <!-- fileset containing all TestBench tests to run --> <fileset dir=".." id="html-test-files"> @@ -51,7 +55,7 @@ </fileset> <!-- This target converts HTML tests files to java junit tests. One test file for each browser is created. --> - <target name="create-tests" depends="remove-temp-testclasses" if="server.start.succeeded"> + <target name="create-tests" depends="initialize, remove-temp-testclasses"> <pathconvert pathsep=" " property="testfiles" refid="html-test-files" /> <java classname="com.vaadin.testbench.util.TestConverter" classpathref="classpath" fork="true"> @@ -68,51 +72,13 @@ <!-- This target complies the generated java junit tests. --> <target name="compile-tests" depends="create-tests"> <mkdir dir="${class-dir}" /> - <javac srcdir="${test-output-dir}" destdir="${class-dir}" debug="on" fork="yes" failonerror="false" encoding="UTF8"> + <javac includeantruntime="false" srcdir="${test-output-dir}" destdir="${class-dir}" debug="on" fork="yes" failonerror="false" encoding="UTF8"> <classpath> <path refid="classpath" /> </classpath> </javac> </target> - - <!-- ================================================================== --> - <!-- Vaadin Server Management --> - <!-- ================================================================== --> - - <target name="server-start"> - <fail unless="output-dir" message="The 'output-dir' (usually build/result/vaadin-xxx) should be given to test script." /> - <fail unless="package.name" message="The 'package.name' property must be defined." /> - <fail unless="package.filename" message="The 'package.filename' property must be defined." /> - <fail unless="testing.testarea" message="The 'testing.testarea' property must be defined." /> - - <echo>Package name: ${package.name}</echo> - <echo>Package filename: ${package.filename}</echo> - <echo>Testing area: ${testing.testarea}</echo> - - <exec executable="python" searchpath="true" dir=".." resultproperty="server.start.result"> - <arg value="build/testing/vaadin-server.py" /> - <arg value="start" /> - <arg value="${package.name}" /> - <arg value="${package.filename}" /> - <arg value="${output-dir}" /> - <arg value="${testing.testarea}" /> - </exec> - - <condition property="server.start.succeeded"> - <equals arg1="${server.start.result}" arg2="0" /> - </condition> - </target> - - <target name="server-stop"> - <sleep seconds="5" /> - <exec executable="python" dir=".." searchpath="true" resultproperty="server.stop.result"> - <arg value="build/testing/vaadin-server.py" /> - <arg value="stop" /> - </exec> - <move file="${testing.testarea}/${package.name}/war.ec" todir="../build/result" failonerror="false" /> - </target> - <!-- ================================================================== --> <!-- Running Tests --> <!-- ================================================================== --> @@ -123,22 +89,22 @@ <fail unless="com.vaadin.testbench.deployment.url" message="The 'com.vaadin.testbench.deployment.url' property must be defined." /> </target> - <target name="run-tests" depends="compile-tests" if="server.start.succeeded"> + <target name="run-tests" depends="compile-tests"> <fileset dir="${test-output-dir}" id="tests-fileset"> <include name="**/**.java" /> </fileset> - - - <for threadCount="30" parallel="true" keepgoing="true" param="target"> + + <antcontrib:for threadCount="30" parallel="true" keepgoing="true" param="target"> <path> <fileset refid="tests-fileset" /> </path> <sequential> <antcall target="execute-tests"> <param name="target" value="@{target}" /> + <reference refid="classpath" /> </antcall> </sequential> - </for> + </antcontrib:for> </target> <!-- This target runs the generated and compiled junit tests --> @@ -198,11 +164,19 @@ <!-- ================================================================== --> <!-- The default target. --> - <target name="run-and-clean-up" depends="check-parameters,remove-error-screens,run-tests" if="server.start.succeeded"> - </target> + <target name="run-and-clean-up" depends="check-parameters,remove-error-screens,run-tests" /> <!-- Also starts the server. --> - <target name="test-package" depends="server-start, run-and-clean-up, server-stop"> - </target> - -</project>
\ No newline at end of file + <target name="test-package"> + <parallel> + <daemons> + <ant antfile="vaadin-server.xml" inheritall="true" inheritrefs="true" target="deploy-and-start" /> + </daemons> + <sequential> + <ant antfile="vaadin-server.xml" target="wait-for-startup" /> + <antcall inheritall="true" inheritrefs="true" target="run-and-clean-up" /> + <move file="${testing.testarea}/${package.name}/war.ec" todir="../build/result" failonerror="false" /> + </sequential> + </parallel> + </target> +</project> diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java b/tests/testbench/com/vaadin/launcher/ApplicationRunnerServlet.java index a9eaa1bb82..33d63b0413 100644 --- a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java +++ b/tests/testbench/com/vaadin/launcher/ApplicationRunnerServlet.java @@ -1,11 +1,15 @@ /* @VaadinApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.server; +package com.vaadin.launcher; +import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -15,10 +19,32 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.vaadin.Application; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; +import com.vaadin.terminal.gwt.server.WrappedHttpServletRequest; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Root; @SuppressWarnings("serial") public class ApplicationRunnerServlet extends AbstractApplicationServlet { + /** + * Internal implementation of an application with a dynamically selected + * Root implementation; + */ + private static class RootRunnerApplication extends Application { + private final Class<?> runnableClass; + + private RootRunnerApplication(Class<?> runnableClass) { + this.runnableClass = runnableClass; + } + + @Override + protected String getRootClassName(WrappedRequest request) { + return runnableClass.getCanonicalName(); + } + } + private static final Logger logger = Logger .getLogger(ApplicationRunnerServlet.class.getName()); @@ -26,7 +52,8 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { * The name of the application class currently used. Only valid within one * request. */ - private String[] defaultPackages; + private LinkedHashSet<String> defaultPackages = new LinkedHashSet<String>(); + private final ThreadLocal<HttpServletRequest> request = new ThreadLocal<HttpServletRequest>(); @Override @@ -35,7 +62,27 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { String initParameter = servletConfig .getInitParameter("defaultPackages"); if (initParameter != null) { - defaultPackages = initParameter.split(","); + Collections.addAll(defaultPackages, initParameter.split(",")); + } + String str = TestBase.class.getName().replace('.', '/') + ".class"; + URL url = getClassLoader().getResource(str); + if ("file".equals(url.getProtocol())) { + File comVaadinTests = new File(url.getPath()).getParentFile() + .getParentFile(); + addDirectories(comVaadinTests, defaultPackages, "com.vaadin.tests"); + + } + } + + private void addDirectories(File parent, LinkedHashSet<String> packages, + String parentPackage) { + packages.add(parentPackage); + + for (File f : parent.listFiles()) { + if (f.isDirectory()) { + String newPackage = parentPackage + "." + f.getName(); + addDirectories(f, packages, newPackage); + } } } @@ -43,8 +90,11 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.request.set(request); - super.service(request, response); - this.request.set(null); + try { + super.service(request, response); + } finally { + this.request.set(null); + } } @Override @@ -65,8 +115,15 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { // Creates a new application instance try { - final Application application = getApplicationClass().newInstance(); - return application; + final Class<?> classToRun = getClassToRun(); + if (Root.class.isAssignableFrom(classToRun)) { + return new RootRunnerApplication(classToRun); + } else if (Application.class.isAssignableFrom(classToRun)) { + return (Application) classToRun.newInstance(); + } else { + throw new ServletException(classToRun.getCanonicalName() + + " is neither an Application nor a Root"); + } } catch (final IllegalAccessException e) { throw new ServletException(e); } catch (final InstantiationException e) { @@ -150,40 +207,45 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { return uris; } - @SuppressWarnings("unchecked") @Override protected Class<? extends Application> getApplicationClass() throws ClassNotFoundException { + Class<?> classToRun = getClassToRun(); + if (Root.class.isAssignableFrom(classToRun)) { + return RootRunnerApplication.class; + } else if (Application.class.isAssignableFrom(classToRun)) { + return classToRun.asSubclass(Application.class); + } else { + throw new ClassCastException(classToRun.getCanonicalName() + + " is not an Application nor a Root"); + } + } + + private Class<?> getClassToRun() throws ClassNotFoundException { // TODO use getClassLoader() ? - Class<? extends Application> appClass = null; + Class<?> appClass = null; String baseName = getApplicationRunnerApplicationClassName(request .get()); try { - appClass = (Class<? extends Application>) getClass() - .getClassLoader().loadClass(baseName); + appClass = getClass().getClassLoader().loadClass(baseName); return appClass; } catch (Exception e) { // - if (defaultPackages != null) { - for (int i = 0; i < defaultPackages.length; i++) { - try { - appClass = (Class<? extends Application>) getClass() - .getClassLoader().loadClass( - defaultPackages[i] + "." + baseName); - } catch (ClassNotFoundException ee) { - // Ignore as this is expected for many packages - } catch (Exception e2) { - // TODO: handle exception - logger.log( - Level.FINE, - "Failed to find application class in the default package.", - e2); - } - if (appClass != null) { - return appClass; - } + for (String pkg : defaultPackages) { + try { + appClass = getClass().getClassLoader().loadClass( + pkg + "." + baseName); + } catch (ClassNotFoundException ee) { + // Ignore as this is expected for many packages + } catch (Exception e2) { + // TODO: handle exception + logger.log(Level.FINE, "Failed to find application class " + + pkg + "." + baseName, e2); + } + if (appClass != null) { + return appClass; } } @@ -215,4 +277,16 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { return staticFilesPath; } + @Override + protected WrappedHttpServletRequest createWrappedRequest( + HttpServletRequest request) { + return new WrappedHttpServletRequest(request, + getDeploymentConfiguration()) { + @Override + public String getRequestPathInfo() { + return ApplicationRunnerServlet.this.getRequestPathInfo(this); + } + }; + } + } diff --git a/tests/testbench/com/vaadin/tests/Components.java b/tests/testbench/com/vaadin/tests/Components.java index 3366f6db43..fa82948e2b 100644 --- a/tests/testbench/com/vaadin/tests/Components.java +++ b/tests/testbench/com/vaadin/tests/Components.java @@ -24,18 +24,19 @@ import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.Embedded; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; import com.vaadin.ui.Tree.ItemStyleGenerator; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Components extends Application { +public class Components extends Application.LegacyApplication { private static final Object CAPTION = "c"; private Map<Class<? extends AbstractComponentTest>, String> tests = new HashMap<Class<? extends AbstractComponentTest>, String>(); private Tree naviTree; private HorizontalSplitPanel sp; - private Window mainWindow; + private LegacyWindow mainWindow; private final Embedded applicationEmbedder = new Embedded(); private String baseUrl; private List<Class<? extends Component>> componentsWithoutTests = new ArrayList<Class<? extends Component>>(); @@ -85,7 +86,7 @@ public class Components extends Application { @Override public void init() { - mainWindow = new Window(); + mainWindow = new LegacyWindow(); setTheme("tests-components"); mainWindow.getContent().setSizeFull(); setMainWindow(mainWindow); @@ -95,7 +96,7 @@ public class Components extends Application { naviLayout .addComponent(new Label( "Click to open a test case.<br/>Right click to open test in a new window<br/><br/>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); naviLayout.addComponent(createMenu()); naviLayout.addComponent(createMissingTestsList()); @@ -106,7 +107,7 @@ public class Components extends Application { embeddingLayout .addComponent(new Label( "<b>Do not use the embedded version for creating automated tests. Open the test in a new window before recording.</b><br/>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); applicationEmbedder.setSizeFull(); embeddingLayout.addComponent(applicationEmbedder); embeddingLayout.setExpandRatio(applicationEmbedder, 1); @@ -129,7 +130,7 @@ public class Components extends Application { + component.getSimpleName() + "</font><br/>"; } return new Label("<b>Components without a test:</B><br/>" - + missingTests, Label.CONTENT_XHTML); + + missingTests, ContentMode.XHTML); } private Component createMenu() { diff --git a/tests/testbench/com/vaadin/tests/CustomLayoutDemo.java b/tests/testbench/com/vaadin/tests/CustomLayoutDemo.java index 2b45ef7458..62340b7c9e 100644 --- a/tests/testbench/com/vaadin/tests/CustomLayoutDemo.java +++ b/tests/testbench/com/vaadin/tests/CustomLayoutDemo.java @@ -5,16 +5,18 @@ package com.vaadin.tests; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component.Event; import com.vaadin.ui.Component.Listener; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Field; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; import com.vaadin.ui.PasswordField; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree; -import com.vaadin.ui.Window; /** * This example demonstrates custom layout. All components created here are @@ -29,8 +31,8 @@ import com.vaadin.ui.Window; * @since 4.0.0 * */ -public class CustomLayoutDemo extends com.vaadin.Application implements - Listener { +public class CustomLayoutDemo extends com.vaadin.Application.LegacyApplication + implements Listener { private CustomLayout mainLayout = null; @@ -40,7 +42,13 @@ public class CustomLayoutDemo extends com.vaadin.Application implements private final PasswordField loginPwd = new PasswordField("Password"); - private final Button loginButton = new Button("Login", this, "loginClicked"); + private final Button loginButton = new Button("Login", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + loginClicked(); + } + }); private final Tree menu = new Tree(); @@ -49,7 +57,7 @@ public class CustomLayoutDemo extends com.vaadin.Application implements */ @Override public void init() { - final Window mainWindow = new Window("CustomLayout demo"); + final LegacyWindow mainWindow = new LegacyWindow("CustomLayout demo"); setMainWindow(mainWindow); // set the application to use example -theme @@ -89,7 +97,7 @@ public class CustomLayoutDemo extends com.vaadin.Application implements // Add heading label and custom layout panel to main window mainWindow.addComponent(new Label("<h3>Custom layout demo</h3>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); mainWindow.addComponent(customLayoutPanel); } @@ -105,7 +113,7 @@ public class CustomLayoutDemo extends com.vaadin.Application implements username.setValue("Anonymous"); } mainLayout.replaceComponent(loginButton, new Label("Welcome user <em>" - + username.getValue() + "</em>", Label.CONTENT_XHTML)); + + username.getValue() + "</em>", ContentMode.XHTML)); } /** diff --git a/tests/testbench/com/vaadin/tests/LayoutDemo.java b/tests/testbench/com/vaadin/tests/LayoutDemo.java index 989a4822ad..d88285468e 100644 --- a/tests/testbench/com/vaadin/tests/LayoutDemo.java +++ b/tests/testbench/com/vaadin/tests/LayoutDemo.java @@ -10,11 +10,12 @@ import com.vaadin.ui.Embedded; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * This example demonstrates layouts. Layouts are populated with sample Vaadin @@ -24,14 +25,14 @@ import com.vaadin.ui.Window; * @since 4.0.0 * */ -public class LayoutDemo extends com.vaadin.Application { +public class LayoutDemo extends com.vaadin.Application.LegacyApplication { /** * Initialize Application. Demo components are added to main window. */ @Override public void init() { - final Window mainWindow = new Window("Layout demo"); + final LegacyWindow mainWindow = new LegacyWindow("Layout demo"); setMainWindow(mainWindow); // @@ -85,25 +86,23 @@ public class LayoutDemo extends com.vaadin.Application { // mainWindow.addComponent(new Label( "<h3>Horizontal ordered layout</h3>Added four components.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); mainWindow.addComponent(layoutA); mainWindow.addComponent(new Label( "<br /><h3>Vertical ordered layout</h3>Added four components.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); mainWindow.addComponent(layoutB); mainWindow.addComponent(new Label( "<br /><h3>Grid Layout (4 x 4)</h3>Added 16 components.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); mainWindow.addComponent(layoutG); - mainWindow - .addComponent(new Label("<br /><h3>Grid Layout (4 x 4)</h3>" - + "Added four panels and four embedded components " - + "diagonally with absolute coordinates.", - Label.CONTENT_XHTML)); + mainWindow.addComponent(new Label("<br /><h3>Grid Layout (4 x 4)</h3>" + + "Added four panels and four embedded components " + + "diagonally with absolute coordinates.", ContentMode.XHTML)); mainWindow.addComponent(layoutG2); mainWindow.addComponent(new Label( "<br /><h3>TabSheet</h3>Added above layouts as tabs.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); mainWindow.addComponent(tabsheet); } @@ -124,7 +123,7 @@ public class LayoutDemo extends com.vaadin.Application { + "extremities and may have a caption to clarify the nature of the contained components' purpose." + " Panel contains an layout where the actual contained components are added, " + "this layout may be switched on the fly.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); panel.setWidth("222px"); return panel; } diff --git a/tests/testbench/com/vaadin/tests/ListenerOrder.java b/tests/testbench/com/vaadin/tests/ListenerOrder.java index c1d6245222..797561eb00 100644 --- a/tests/testbench/com/vaadin/tests/ListenerOrder.java +++ b/tests/testbench/com/vaadin/tests/ListenerOrder.java @@ -13,12 +13,12 @@ import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; -import com.vaadin.ui.Window; -public class ListenerOrder extends com.vaadin.Application implements - Button.ClickListener, PropertySetChangeListener, ItemSetChangeListener, - ValueChangeListener { +public class ListenerOrder extends com.vaadin.Application.LegacyApplication + implements Button.ClickListener, PropertySetChangeListener, + ItemSetChangeListener, ValueChangeListener { Button b1; @@ -32,7 +32,7 @@ public class ListenerOrder extends com.vaadin.Application implements } public void createNewView() { - final Window main = new Window("Test window"); + final LegacyWindow main = new LegacyWindow("Test window"); setMainWindow(main); main.removeAllComponents(); @@ -49,12 +49,12 @@ public class ListenerOrder extends com.vaadin.Application implements addListeners(b1, 1); b1.addListener(mutualListener); b1.addListener(mutualListener); - b1.addListener((Button.ClickListener) this); + b1.addListener(this); b1.addListener(mutualListener); Button.ClickListener b1Listener = addListeners(b1, 3); b1.addListener(mutualListener); - b1.addListener((Button.ClickListener) this); - b1.addListener((ValueChangeListener) this); + b1.addListener(this); + // b1.addListener((ValueChangeListener) this); b1.addListener(mutualListener); b1.removeListener(b1Listener); // remove non-existing listener diff --git a/tests/testbench/com/vaadin/tests/ModalWindow.java b/tests/testbench/com/vaadin/tests/ModalWindow.java index 84adaf1a39..c848803642 100644 --- a/tests/testbench/com/vaadin/tests/ModalWindow.java +++ b/tests/testbench/com/vaadin/tests/ModalWindow.java @@ -8,6 +8,7 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.Window; @@ -21,8 +22,8 @@ import com.vaadin.ui.Window; * @see com.vaadin.ui.Window * @see com.vaadin.ui.Label */ -public class ModalWindow extends com.vaadin.Application implements - ClickListener { +public class ModalWindow extends com.vaadin.Application.LegacyApplication + implements ClickListener { private Window test; private Button reopen; @@ -31,7 +32,7 @@ public class ModalWindow extends com.vaadin.Application implements public void init() { // Create main window - final Window main = new Window("ModalWindow demo"); + final LegacyWindow main = new LegacyWindow("ModalWindow demo"); setMainWindow(main); main.addComponent(new Label("ModalWindow demo")); diff --git a/tests/testbench/com/vaadin/tests/NativeWindowing.java b/tests/testbench/com/vaadin/tests/NativeWindowing.java index f148c6a835..1a22b5a4d2 100644 --- a/tests/testbench/com/vaadin/tests/NativeWindowing.java +++ b/tests/testbench/com/vaadin/tests/NativeWindowing.java @@ -11,11 +11,13 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; -public class NativeWindowing extends Application { +public class NativeWindowing extends Application.LegacyApplication { - Window main = new Window("Windowing test"); + LegacyWindow main = new LegacyWindow("Windowing test"); @Override public void init() { @@ -68,7 +70,7 @@ public class NativeWindowing extends Application { + "<p>Lorem ipsum dolor sit amet.</p>" + "<p>Lorem ipsum dolor sit amet.</p>" + "<p>Lorem ipsum dolor sit amet.</p>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); } })); @@ -95,16 +97,16 @@ public class NativeWindowing extends Application { } @Override - public Window getWindow(String name) { + public LegacyWindow getWindow(String name) { - final Window w = super.getWindow(name); + final LegacyWindow w = super.getWindow(name); if (w != null) { return w; } if (name != null && name.startsWith("mainwin-")) { final String postfix = name.substring("mainwin-".length()); - final Window ww = new Window("Window: " + postfix); + final LegacyWindow ww = new LegacyWindow("Window: " + postfix); ww.setName(name); ww.addComponent(new Label( "This is a application-level window opened with name: " diff --git a/tests/testbench/com/vaadin/tests/Parameters.java b/tests/testbench/com/vaadin/tests/Parameters.java index 8b8bec8834..8d940101c3 100644 --- a/tests/testbench/com/vaadin/tests/Parameters.java +++ b/tests/testbench/com/vaadin/tests/Parameters.java @@ -4,21 +4,23 @@ package com.vaadin.tests; +import java.io.IOException; import java.net.URL; import java.util.Iterator; import java.util.Map; -import com.vaadin.terminal.DownloadStream; +import com.vaadin.Application; import com.vaadin.terminal.ExternalResource; -import com.vaadin.terminal.ParameterHandler; -import com.vaadin.terminal.URIHandler; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * This is a demonstration of how URL parameters can be recieved and handled. @@ -27,8 +29,8 @@ import com.vaadin.ui.Window; * * @since 3.1.1 */ -public class Parameters extends com.vaadin.Application implements URIHandler, - ParameterHandler { +public class Parameters extends com.vaadin.Application.LegacyApplication + implements RequestHandler { private final Label context = new Label(); @@ -38,12 +40,11 @@ public class Parameters extends com.vaadin.Application implements URIHandler, @Override public void init() { - final Window main = new Window("Parameters demo"); + final LegacyWindow main = new LegacyWindow("Parameters demo"); setMainWindow(main); // This class acts both as URI handler and parameter handler - main.addURIHandler(this); - main.addParameterHandler(this); + addRequestHandler(this); final VerticalLayout layout = new VerticalLayout(); final Label info = new Label("To test URI and Parameter Handlers, " @@ -92,24 +93,14 @@ public class Parameters extends com.vaadin.Application implements URIHandler, main.setContent(layout); } - /** - * Update URI - * - * @see com.vaadin.terminal.URIHandler#handleURI(URL, String) - */ - @Override - public DownloadStream handleURI(URL context, String relativeUri) { - this.context.setValue(context.toString()); - relative.setValue(relativeUri); - return null; - } + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + context.setValue("Context not available"); + relative.setValue(request.getRequestPathInfo()); - /** - * Handles GET parameters, in this demo GET parameteres are used to - * communicate with EmbeddedToolkit.jsp - */ - public void handleParameters(Map<String, String[]> parameters) { params.removeAllItems(); + Map<String, String[]> parameters = request.getParameterMap(); for (final Iterator<String> i = parameters.keySet().iterator(); i .hasNext();) { final String name = i.next(); @@ -123,5 +114,7 @@ public class Parameters extends com.vaadin.Application implements URIHandler, } params.addItem(new Object[] { name, v }, name); } + + return false; } } diff --git a/tests/testbench/com/vaadin/tests/PerformanceTestBasicComponentRendering.java b/tests/testbench/com/vaadin/tests/PerformanceTestBasicComponentRendering.java index 00f98657b8..a0bd894ebe 100644 --- a/tests/testbench/com/vaadin/tests/PerformanceTestBasicComponentRendering.java +++ b/tests/testbench/com/vaadin/tests/PerformanceTestBasicComponentRendering.java @@ -13,6 +13,7 @@ import com.vaadin.ui.ComboBox; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.DateField; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; @@ -102,7 +103,7 @@ public class PerformanceTestBasicComponentRendering extends CustomComponent { } private void addInfo() { - main.addComponent(new Label(DESCRIPTION, Label.CONTENT_XHTML)); + main.addComponent(new Label(DESCRIPTION, ContentMode.XHTML)); } } diff --git a/tests/testbench/com/vaadin/tests/PerformanceTestLabelsAndOrderedLayouts.java b/tests/testbench/com/vaadin/tests/PerformanceTestLabelsAndOrderedLayouts.java index 9e4aac05d4..93df046fa0 100644 --- a/tests/testbench/com/vaadin/tests/PerformanceTestLabelsAndOrderedLayouts.java +++ b/tests/testbench/com/vaadin/tests/PerformanceTestLabelsAndOrderedLayouts.java @@ -12,6 +12,7 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.VerticalLayout; public class PerformanceTestLabelsAndOrderedLayouts extends CustomComponent { @@ -73,7 +74,7 @@ public class PerformanceTestLabelsAndOrderedLayouts extends CustomComponent { } private void addInfo() { - main.addComponent(new Label(DESCRIPTION, Label.CONTENT_XHTML)); + main.addComponent(new Label(DESCRIPTION, ContentMode.XHTML)); } } diff --git a/tests/testbench/com/vaadin/tests/PerformanceTestSubTreeCaching.java b/tests/testbench/com/vaadin/tests/PerformanceTestSubTreeCaching.java index 4d36da40b5..40433fae84 100644 --- a/tests/testbench/com/vaadin/tests/PerformanceTestSubTreeCaching.java +++ b/tests/testbench/com/vaadin/tests/PerformanceTestSubTreeCaching.java @@ -7,8 +7,10 @@ package com.vaadin.tests; import java.util.Date; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; @@ -36,10 +38,18 @@ public class PerformanceTestSubTreeCaching extends CustomComponent { setCompositionRoot(main); addInfo(); - Button b = new Button("start test", this, "startTest"); + Button b = new Button("start test", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + startTest(); + } + }); b.setDescription("Push this button to start test. A test label will be rendered above existing components."); main.addComponent(b); - b = new Button("end test", this, "endTest"); + b = new Button("end test", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + endTest(); + } + }); b.setDescription("Push this button as soon as test componenet is rendered."); main.addComponent(b); @@ -77,7 +87,7 @@ public class PerformanceTestSubTreeCaching extends CustomComponent { } private void addInfo() { - main.addComponent(new Label(DESCRIPTION, Label.CONTENT_XHTML)); + main.addComponent(new Label(DESCRIPTION, ContentMode.XHTML)); } } diff --git a/tests/testbench/com/vaadin/tests/RandomLayoutStress.java b/tests/testbench/com/vaadin/tests/RandomLayoutStress.java index d6f896527b..0390ea8157 100644 --- a/tests/testbench/com/vaadin/tests/RandomLayoutStress.java +++ b/tests/testbench/com/vaadin/tests/RandomLayoutStress.java @@ -17,11 +17,11 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * This example demonstrates layouts. Layouts are populated with sample Vaadin @@ -30,7 +30,8 @@ import com.vaadin.ui.Window; * @author Vaadin Ltd. * */ -public class RandomLayoutStress extends com.vaadin.Application { +public class RandomLayoutStress extends + com.vaadin.Application.LegacyApplication { private final Random seededRandom = new Random(1); @@ -48,7 +49,7 @@ public class RandomLayoutStress extends com.vaadin.Application { */ @Override public void init() { - final Window mainWindow = new Window("Layout demo"); + final LegacyWindow mainWindow = new LegacyWindow("Layout demo"); setMainWindow(mainWindow); // Create horizontal ordered layout diff --git a/tests/testbench/com/vaadin/tests/ScrollbarStressTest.java b/tests/testbench/com/vaadin/tests/ScrollbarStressTest.java index a66274a635..bd40a7fb7b 100644 --- a/tests/testbench/com/vaadin/tests/ScrollbarStressTest.java +++ b/tests/testbench/com/vaadin/tests/ScrollbarStressTest.java @@ -10,15 +10,16 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.OptionGroup; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; import com.vaadin.ui.Window; -public class ScrollbarStressTest extends Application { +public class ScrollbarStressTest extends Application.LegacyApplication { - final Window main = new Window("Scrollbar Stress Test"); + final LegacyWindow main = new LegacyWindow("Scrollbar Stress Test"); final Panel panel = new Panel("Panel"); final VerticalSplitPanel splitPanel = new VerticalSplitPanel(); diff --git a/tests/testbench/com/vaadin/tests/TestBench.java b/tests/testbench/com/vaadin/tests/TestBench.java index b15e3994b5..c3bb24cbef 100644 --- a/tests/testbench/com/vaadin/tests/TestBench.java +++ b/tests/testbench/com/vaadin/tests/TestBench.java @@ -23,11 +23,11 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.FragmentChangedEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; -import com.vaadin.ui.UriFragmentUtility; -import com.vaadin.ui.UriFragmentUtility.FragmentChangedEvent; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * TestBench finds out testable classes within given java packages and adds them @@ -39,8 +39,8 @@ import com.vaadin.ui.Window; * @author Vaadin Ltd. * */ -public class TestBench extends com.vaadin.Application implements - Property.ValueChangeListener { +public class TestBench extends com.vaadin.Application.LegacyApplication + implements Property.ValueChangeListener { // Add here packages which are used for finding testable classes String[] testablePackages = { "com.vaadin.tests", @@ -48,7 +48,7 @@ public class TestBench extends com.vaadin.Application implements HierarchicalContainer testables = new HierarchicalContainer(); - Window mainWindow = new Window("TestBench window"); + LegacyWindow mainWindow = new LegacyWindow("TestBench window"); // Main layout consists of tree menu and body layout HorizontalSplitPanel mainLayout = new HorizontalSplitPanel(); @@ -119,12 +119,9 @@ public class TestBench extends com.vaadin.Application implements VerticalLayout lo = new VerticalLayout(); lo.addComponent(menu); - UriFragmentUtility uri = new UriFragmentUtility(); - lo.addComponent(uri); - - uri.addListener(new UriFragmentUtility.FragmentChangedListener() { + mainWindow.addListener(new Root.FragmentChangedListener() { public void fragmentChanged(FragmentChangedEvent source) { - String fragment = source.getUriFragmentUtility().getFragment(); + String fragment = source.getFragment(); if (fragment != null && !"".equals(fragment)) { // try to find a proper test class @@ -213,7 +210,8 @@ public class TestBench extends com.vaadin.Application implements private Component createTestable(Class<?> c) { try { - final Application app = (Application) c.newInstance(); + final Application.LegacyApplication app = (Application.LegacyApplication) c + .newInstance(); app.init(); Layout lo = (Layout) app.getMainWindow().getContent(); lo.setParent(null); diff --git a/tests/testbench/com/vaadin/tests/TestCaptionWrapper.java b/tests/testbench/com/vaadin/tests/TestCaptionWrapper.java index b0ccca2480..89822a9574 100644 --- a/tests/testbench/com/vaadin/tests/TestCaptionWrapper.java +++ b/tests/testbench/com/vaadin/tests/TestCaptionWrapper.java @@ -17,6 +17,7 @@ import com.vaadin.ui.DateField; import com.vaadin.ui.Embedded; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.NativeSelect; @@ -161,7 +162,7 @@ public class TestCaptionWrapper extends CustomComponent implements Listener { // Custom components layout.addComponent(new Label("<B>Below are few custom components</B>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); final TestForUpload tfu = new TestForUpload(); layout.addComponent(tfu); diff --git a/tests/testbench/com/vaadin/tests/TestComponentAddAndRecursion.java b/tests/testbench/com/vaadin/tests/TestComponentAddAndRecursion.java index 62a67cb747..48eff0336e 100644 --- a/tests/testbench/com/vaadin/tests/TestComponentAddAndRecursion.java +++ b/tests/testbench/com/vaadin/tests/TestComponentAddAndRecursion.java @@ -8,9 +8,10 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * @author marc @@ -91,12 +92,13 @@ public class TestComponentAddAndRecursion extends CustomComponent { public void buttonClick(ClickEvent event) { try { p3.addComponent(p2); - getWindow().showNotification("ERROR", + Root.getCurrentRoot().showNotification("ERROR", "This should have failed", - Window.Notification.TYPE_ERROR_MESSAGE); + Notification.TYPE_ERROR_MESSAGE); } catch (Exception e) { - getWindow().showNotification("OK", "threw, as expected", - Window.Notification.TYPE_ERROR_MESSAGE); + Root.getCurrentRoot().showNotification("OK", + "threw, as expected", + Notification.TYPE_ERROR_MESSAGE); } } @@ -109,12 +111,13 @@ public class TestComponentAddAndRecursion extends CustomComponent { p.addComponent(p2); try { p3.addComponent(p); - getWindow().showNotification("ERROR", + Root.getCurrentRoot().showNotification("ERROR", "This should have failed", - Window.Notification.TYPE_ERROR_MESSAGE); + Notification.TYPE_ERROR_MESSAGE); } catch (Exception e) { - getWindow().showNotification("OK", "threw, as expected", - Window.Notification.TYPE_ERROR_MESSAGE); + Root.getCurrentRoot().showNotification("OK", + "threw, as expected", + Notification.TYPE_ERROR_MESSAGE); } } diff --git a/tests/testbench/com/vaadin/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java b/tests/testbench/com/vaadin/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java index 74ca67987d..c4b96e59b4 100644 --- a/tests/testbench/com/vaadin/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java +++ b/tests/testbench/com/vaadin/tests/TestForApplicationLayoutThatUsesWholeBrosersSpace.java @@ -7,15 +7,15 @@ package com.vaadin.tests; import com.vaadin.Application; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; public class TestForApplicationLayoutThatUsesWholeBrosersSpace extends - Application { + Application.LegacyApplication { - Window main = new Window("Windowing test"); + LegacyWindow main = new LegacyWindow("Windowing test"); VerticalLayout rootLayout; diff --git a/tests/testbench/com/vaadin/tests/TestForChildComponentRendering.java b/tests/testbench/com/vaadin/tests/TestForChildComponentRendering.java index 0dd0fdb1bb..e90231eefd 100644 --- a/tests/testbench/com/vaadin/tests/TestForChildComponentRendering.java +++ b/tests/testbench/com/vaadin/tests/TestForChildComponentRendering.java @@ -9,6 +9,7 @@ import java.util.Iterator; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; @@ -51,14 +52,26 @@ public class TestForChildComponentRendering extends CustomComponent { se.addItem("valinta1"); se.addItem("Valinta 2"); - Button b = new Button("refresh view", this, "createNewView"); + Button b = new Button("refresh view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + createNewView(); + } + }); main.addComponent(b); - b = new Button("reorder view", this, "randomReorder"); + b = new Button("reorder view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + randomReorder(); + } + }); main.addComponent(b); - b = new Button("remove randomly one component", this, - "removeRandomComponent"); + b = new Button("remove randomly one component", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + removeRandomComponent(); + } + }); main.addComponent(b); } diff --git a/tests/testbench/com/vaadin/tests/TestForContainerFilterable.java b/tests/testbench/com/vaadin/tests/TestForContainerFilterable.java index 395f677723..92b7ae4f62 100644 --- a/tests/testbench/com/vaadin/tests/TestForContainerFilterable.java +++ b/tests/testbench/com/vaadin/tests/TestForContainerFilterable.java @@ -62,12 +62,12 @@ public class TestForContainerFilterable extends CustomComponent { filterButton.addListener(new Button.ClickListener() { public void buttonClick(ClickEvent event) { ic.removeAllContainerFilters(); - if (fooFilter.toString().length() > 0) { - ic.addContainerFilter("foo", fooFilter.toString(), false, + if (fooFilter.getValue().length() > 0) { + ic.addContainerFilter("foo", fooFilter.getValue(), false, false); } - if (barFilter.toString().length() > 0) { - ic.addContainerFilter("bar", barFilter.toString(), true, + if (barFilter.getValue().length() > 0) { + ic.addContainerFilter("bar", barFilter.getValue(), true, true); } count.setValue("Rows in table: " + ic.size()); diff --git a/tests/testbench/com/vaadin/tests/TestForGridLayoutChildComponentRendering.java b/tests/testbench/com/vaadin/tests/TestForGridLayoutChildComponentRendering.java index c1cb7d6bb8..6adcf49ec6 100644 --- a/tests/testbench/com/vaadin/tests/TestForGridLayoutChildComponentRendering.java +++ b/tests/testbench/com/vaadin/tests/TestForGridLayoutChildComponentRendering.java @@ -9,6 +9,7 @@ import java.util.Iterator; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.GridLayout; @@ -52,14 +53,26 @@ public class TestForGridLayoutChildComponentRendering extends CustomComponent { main.addComponent(se, 0, 1, 1, 1); - Button b = new Button("refresh view", this, "createNewView"); + Button b = new Button("refresh view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + createNewView(); + } + }); main.addComponent(b); - b = new Button("reorder view", this, "randomReorder"); + b = new Button("reorder view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + randomReorder(); + } + }); main.addComponent(b); - b = new Button("remove randomly one component", this, - "removeRandomComponent"); + b = new Button("remove randomly one component", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + removeRandomComponent(); + } + }); main.addComponent(b); } diff --git a/tests/testbench/com/vaadin/tests/TestForNativeWindowing.java b/tests/testbench/com/vaadin/tests/TestForNativeWindowing.java index b417d57a56..91ade9b403 100644 --- a/tests/testbench/com/vaadin/tests/TestForNativeWindowing.java +++ b/tests/testbench/com/vaadin/tests/TestForNativeWindowing.java @@ -11,11 +11,13 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; -public class TestForNativeWindowing extends Application { +public class TestForNativeWindowing extends Application.LegacyApplication { - Window main = new Window("Windowing test"); + LegacyWindow main = new LegacyWindow("Windowing test"); @Override public void init() { @@ -68,7 +70,7 @@ public class TestForNativeWindowing extends Application { + "<p>Lorem ipsum dolor sit amet.</p>" + "<p>Lorem ipsum dolor sit amet.</p>" + "<p>Lorem ipsum dolor sit amet.</p>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); } })); @@ -95,16 +97,16 @@ public class TestForNativeWindowing extends Application { } @Override - public Window getWindow(String name) { + public LegacyWindow getWindow(String name) { - final Window w = super.getWindow(name); + final LegacyWindow w = super.getWindow(name); if (w != null) { return w; } if (name != null && name.startsWith("mainwin-")) { final String postfix = name.substring("mainwin-".length()); - final Window ww = new Window("Window: " + postfix); + final LegacyWindow ww = new LegacyWindow("Window: " + postfix); ww.setName(name); ww.addComponent(new Label( "This is a application-level window opened with name: " diff --git a/tests/testbench/com/vaadin/tests/TestForPreconfiguredComponents.java b/tests/testbench/com/vaadin/tests/TestForPreconfiguredComponents.java index 7ca9fd0cfc..74fdb0c35f 100644 --- a/tests/testbench/com/vaadin/tests/TestForPreconfiguredComponents.java +++ b/tests/testbench/com/vaadin/tests/TestForPreconfiguredComponents.java @@ -90,7 +90,11 @@ public class TestForPreconfiguredComponents extends CustomComponent implements test.setCaption("OptionGroup + multiselect manually (configured from select)"); main.addComponent(test); - final Button b = new Button("refresh view", this, "createNewView"); + final Button b = new Button("refresh view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + createNewView(); + } + }); main.addComponent(b); } @@ -160,6 +164,7 @@ public class TestForPreconfiguredComponents extends CustomComponent implements t.addListener(new Listener() { public void componentEvent(Event event) { status.addComponent(new Label(event.getClass().getName())); + // TODO should not use Field.toString() status.addComponent(new Label("selected: " + event.getSource().toString())); } diff --git a/tests/testbench/com/vaadin/tests/TestForRichTextEditor.java b/tests/testbench/com/vaadin/tests/TestForRichTextEditor.java index 15caf21b3c..302d28af35 100644 --- a/tests/testbench/com/vaadin/tests/TestForRichTextEditor.java +++ b/tests/testbench/com/vaadin/tests/TestForRichTextEditor.java @@ -4,13 +4,14 @@ package com.vaadin.tests; +import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.RichTextArea; import com.vaadin.ui.VerticalLayout; @@ -45,13 +46,14 @@ public class TestForRichTextEditor extends CustomComponent implements main.addComponent(new Button("commit content to label below")); - l = new Label("", Label.CONTENT_XHTML); + l = new Label("", ContentMode.XHTML); main.addComponent(l); CheckBox b = new CheckBox("enabled"); b.setImmediate(true); - b.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + b.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { rte.setEnabled(!rte.isEnabled()); } }); diff --git a/tests/testbench/com/vaadin/tests/TestForStyledUpload.java b/tests/testbench/com/vaadin/tests/TestForStyledUpload.java index 88b71185ae..3b1100bb66 100644 --- a/tests/testbench/com/vaadin/tests/TestForStyledUpload.java +++ b/tests/testbench/com/vaadin/tests/TestForStyledUpload.java @@ -19,10 +19,12 @@ import com.vaadin.terminal.StreamResource; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.Panel; import com.vaadin.ui.ProgressIndicator; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Upload; import com.vaadin.ui.Upload.FailedEvent; import com.vaadin.ui.Upload.FailedListener; @@ -33,10 +35,9 @@ import com.vaadin.ui.Upload.StartedListener; import com.vaadin.ui.Upload.SucceededEvent; import com.vaadin.ui.Upload.SucceededListener; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class TestForStyledUpload extends Application implements - Upload.FinishedListener, FailedListener, SucceededListener, +public class TestForStyledUpload extends Application.LegacyApplication + implements Upload.FinishedListener, FailedListener, SucceededListener, StartedListener { Layout main = new VerticalLayout(); @@ -80,9 +81,19 @@ public class TestForStyledUpload extends Application implements }); - final Button b = new Button("Update status", this, "readState"); + final Button b = new Button("Update status", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + readState(); + } + }); - final Button c = new Button("Update status with gc", this, "gc"); + final Button c = new Button("Update status with gc", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + gc(); + } + }); main.addComponent(up); l = new Label("Idle"); @@ -153,11 +164,11 @@ public class TestForStyledUpload extends Application implements "Upload finished, but output buffer is null!!")); } else { status.addComponent(new Label( - "<b>Name:</b> " + event.getFilename(), Label.CONTENT_XHTML)); + "<b>Name:</b> " + event.getFilename(), ContentMode.XHTML)); status.addComponent(new Label("<b>Mimetype:</b> " - + event.getMIMEType(), Label.CONTENT_XHTML)); + + event.getMIMEType(), ContentMode.XHTML)); status.addComponent(new Label("<b>Size:</b> " + event.getLength() - + " bytes.", Label.CONTENT_XHTML)); + + " bytes.", ContentMode.XHTML)); status.addComponent(new Link("Download " + buffer.getFileName(), new StreamResource(buffer, buffer.getFileName(), this))); @@ -276,8 +287,8 @@ public class TestForStyledUpload extends Application implements @Override public void init() { - Window w = new Window(); - w.setTheme("runo"); + LegacyWindow w = new LegacyWindow(); + setTheme("runo"); w.addComponent(main); setMainWindow(w); diff --git a/tests/testbench/com/vaadin/tests/TestForTablesInitialColumnWidthLogicRendering.java b/tests/testbench/com/vaadin/tests/TestForTablesInitialColumnWidthLogicRendering.java index 5b301fbc5d..48c056ff58 100644 --- a/tests/testbench/com/vaadin/tests/TestForTablesInitialColumnWidthLogicRendering.java +++ b/tests/testbench/com/vaadin/tests/TestForTablesInitialColumnWidthLogicRendering.java @@ -102,7 +102,11 @@ public class TestForTablesInitialColumnWidthLogicRendering extends t.setWidth("200px"); main.addComponent(t); - final Button b = new Button("refresh view", this, "createNewView"); + final Button b = new Button("refresh view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + createNewView(); + } + }); main.addComponent(b); } diff --git a/tests/testbench/com/vaadin/tests/TestForTrees.java b/tests/testbench/com/vaadin/tests/TestForTrees.java index 0499ceb8ec..37030a25c2 100644 --- a/tests/testbench/com/vaadin/tests/TestForTrees.java +++ b/tests/testbench/com/vaadin/tests/TestForTrees.java @@ -86,7 +86,11 @@ public class TestForTrees extends CustomComponent implements Handler { main.addComponent(ol); contextTree = t; - final Button b = new Button("refresh view", this, "createNewView"); + final Button b = new Button("refresh view", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + createNewView(); + } + }); main.addComponent(b); } @@ -142,6 +146,7 @@ public class TestForTrees extends CustomComponent implements Handler { t.addListener(new Listener() { public void componentEvent(Event event) { status.addComponent(new Label(event.getClass().getName())); + // TODO should not use Field.toString() status.addComponent(new Label("selected: " + event.getSource().toString())); } diff --git a/tests/testbench/com/vaadin/tests/TestForUpload.java b/tests/testbench/com/vaadin/tests/TestForUpload.java index 399669357d..fdda4dfd2a 100644 --- a/tests/testbench/com/vaadin/tests/TestForUpload.java +++ b/tests/testbench/com/vaadin/tests/TestForUpload.java @@ -24,6 +24,7 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.Panel; @@ -136,12 +137,11 @@ public class TestForUpload extends CustomComponent implements "Upload finished, but output buffer is null")); } else { status.addComponent(new Label("<b>Name:</b> " - + event.getFilename(), Label.CONTENT_XHTML)); + + event.getFilename(), ContentMode.XHTML)); status.addComponent(new Label("<b>Mimetype:</b> " - + event.getMIMEType(), Label.CONTENT_XHTML)); + + event.getMIMEType(), ContentMode.XHTML)); status.addComponent(new Label("<b>Size:</b> " - + event.getLength() + " bytes.", - Label.CONTENT_XHTML)); + + event.getLength() + " bytes.", ContentMode.XHTML)); status.addComponent(new Link("Download " + buffer.getFileName(), new StreamResource(buffer, @@ -164,9 +164,18 @@ public class TestForUpload extends CustomComponent implements }); - final Button b = new Button("Reed state from upload", this, "readState"); + final Button b = new Button("Reed state from upload", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + readState(); + } + }); - final Button c = new Button("Force GC", this, "gc"); + final Button c = new Button("Force GC", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + gc(); + } + }); main.addComponent(b); main.addComponent(c); @@ -413,7 +422,7 @@ public class TestForUpload extends CustomComponent implements } private void beSluggish() { - if (beSluggish.booleanValue()) { + if (beSluggish.getValue()) { try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -424,7 +433,7 @@ public class TestForUpload extends CustomComponent implements } private void throwExecption() { - if (throwExecption.booleanValue()) { + if (throwExecption.getValue()) { throwExecption.setValue(false); throw new RuntimeException("Test execption in receiver."); } diff --git a/tests/testbench/com/vaadin/tests/TestForWindowOpen.java b/tests/testbench/com/vaadin/tests/TestForWindowOpen.java index b523813c0b..c9dbf8dabe 100644 --- a/tests/testbench/com/vaadin/tests/TestForWindowOpen.java +++ b/tests/testbench/com/vaadin/tests/TestForWindowOpen.java @@ -8,6 +8,7 @@ import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.Root; import com.vaadin.ui.VerticalLayout; public class TestForWindowOpen extends CustomComponent { @@ -23,7 +24,7 @@ public class TestForWindowOpen extends CustomComponent { public void buttonClick(ClickEvent event) { final ExternalResource r = new ExternalResource( "http://www.google.com"); - getApplication().getMainWindow().open(r); + Root.getCurrentRoot().open(r); } @@ -35,7 +36,7 @@ public class TestForWindowOpen extends CustomComponent { public void buttonClick(ClickEvent event) { final ExternalResource r = new ExternalResource( "http://www.google.com"); - getApplication().getMainWindow().open(r, "mytarget"); + Root.getCurrentRoot().open(r, "mytarget"); } @@ -47,8 +48,7 @@ public class TestForWindowOpen extends CustomComponent { public void buttonClick(ClickEvent event) { final ExternalResource r = new ExternalResource( "http://www.google.com"); - getApplication().getMainWindow() - .open(r, "secondtarget"); + Root.getCurrentRoot().open(r, "secondtarget"); } diff --git a/tests/testbench/com/vaadin/tests/TestForWindowing.java b/tests/testbench/com/vaadin/tests/TestForWindowing.java index bf6d794c13..f97ea33d61 100644 --- a/tests/testbench/com/vaadin/tests/TestForWindowing.java +++ b/tests/testbench/com/vaadin/tests/TestForWindowing.java @@ -14,6 +14,7 @@ import com.vaadin.ui.CheckBox; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; import com.vaadin.ui.OptionGroup; +import com.vaadin.ui.Root; import com.vaadin.ui.Select; import com.vaadin.ui.Slider; import com.vaadin.ui.VerticalLayout; @@ -84,7 +85,7 @@ public class TestForWindowing extends CustomComponent { w.addComponent(s); - getApplication().getMainWindow().addWindow(w); + Root.getCurrentRoot().addWindow(w); } diff --git a/tests/testbench/com/vaadin/tests/TestIFrames.java b/tests/testbench/com/vaadin/tests/TestIFrames.java index 5bbe58ee62..a8a9d1c2ca 100644 --- a/tests/testbench/com/vaadin/tests/TestIFrames.java +++ b/tests/testbench/com/vaadin/tests/TestIFrames.java @@ -6,6 +6,7 @@ package com.vaadin.tests; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.VerticalLayout; public class TestIFrames extends CustomComponent { @@ -31,7 +32,7 @@ public class TestIFrames extends CustomComponent { final int height = 250; final String iFrame = "<iframe height=\"" + height + "\" width=\"" + width + "\" src=\"" + URL + "\" />"; - return new Label(iFrame, Label.CONTENT_XHTML); + return new Label(iFrame, ContentMode.XHTML); } } diff --git a/tests/testbench/com/vaadin/tests/TestSetVisibleAndCaching.java b/tests/testbench/com/vaadin/tests/TestSetVisibleAndCaching.java index 2da22f7f5d..a46253598f 100644 --- a/tests/testbench/com/vaadin/tests/TestSetVisibleAndCaching.java +++ b/tests/testbench/com/vaadin/tests/TestSetVisibleAndCaching.java @@ -9,9 +9,10 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class TestSetVisibleAndCaching extends com.vaadin.Application { +public class TestSetVisibleAndCaching extends + com.vaadin.Application.LegacyApplication { Panel panelA = new Panel("Panel A"); Panel panelB = new Panel("Panel B"); @@ -23,7 +24,8 @@ public class TestSetVisibleAndCaching extends com.vaadin.Application { @Override public void init() { - final Window mainWindow = new Window("TestSetVisibleAndCaching"); + final LegacyWindow mainWindow = new LegacyWindow( + "TestSetVisibleAndCaching"); setMainWindow(mainWindow); panelA.addComponent(new Label( diff --git a/tests/testbench/com/vaadin/tests/TestSizeableIncomponents.java b/tests/testbench/com/vaadin/tests/TestSizeableIncomponents.java index a140b56285..a9005e7fd3 100644 --- a/tests/testbench/com/vaadin/tests/TestSizeableIncomponents.java +++ b/tests/testbench/com/vaadin/tests/TestSizeableIncomponents.java @@ -25,11 +25,11 @@ import com.vaadin.ui.Embedded; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class TestSizeableIncomponents extends Application { +public class TestSizeableIncomponents extends Application.LegacyApplication { private IndexedContainer cont; private ComboBox select; @@ -42,9 +42,9 @@ public class TestSizeableIncomponents extends Application { initComponentList(); - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); - w.setTheme("tests-components"); + setTheme("tests-components"); final VerticalLayout main = new VerticalLayout(); w.setContent(main); diff --git a/tests/testbench/com/vaadin/tests/TestSplitPanel.java b/tests/testbench/com/vaadin/tests/TestSplitPanel.java index 9e03cd4f89..87c8309faf 100644 --- a/tests/testbench/com/vaadin/tests/TestSplitPanel.java +++ b/tests/testbench/com/vaadin/tests/TestSplitPanel.java @@ -5,16 +5,16 @@ package com.vaadin.tests; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; -public class TestSplitPanel extends com.vaadin.Application { +public class TestSplitPanel extends com.vaadin.Application.LegacyApplication { VerticalSplitPanel verticalSplit = new VerticalSplitPanel(); @Override public void init() { - final Window mainWindow = new Window("Feature Browser"); + final LegacyWindow mainWindow = new LegacyWindow("Feature Browser"); setMainWindow(mainWindow); verticalSplit.setFirstComponent(new Label("vertical first")); diff --git a/tests/testbench/com/vaadin/tests/TreeFilesystem.java b/tests/testbench/com/vaadin/tests/TreeFilesystem.java index 761fd688d3..28fb289af4 100644 --- a/tests/testbench/com/vaadin/tests/TreeFilesystem.java +++ b/tests/testbench/com/vaadin/tests/TreeFilesystem.java @@ -9,10 +9,11 @@ import java.io.File; import com.vaadin.data.Item; import com.vaadin.tests.util.SampleDirectory; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; import com.vaadin.ui.Tree.ExpandEvent; -import com.vaadin.ui.Window; /** * Browsable file explorer using Vaadin Tree component. Demonstrates: how to add @@ -23,8 +24,8 @@ import com.vaadin.ui.Window; * @since 4.0.0 * */ -public class TreeFilesystem extends com.vaadin.Application implements - Tree.ExpandListener { +public class TreeFilesystem extends com.vaadin.Application.LegacyApplication + implements Tree.ExpandListener { // Filesystem explorer panel and it's components private final Panel explorerPanel = new Panel("Filesystem explorer"); @@ -33,11 +34,11 @@ public class TreeFilesystem extends com.vaadin.Application implements @Override public void init() { - final Window main = new Window("Tree filesystem demo"); + final LegacyWindow main = new LegacyWindow("Tree filesystem demo"); setMainWindow(main); // Main window contains heading and panel - main.addComponent(new Label("<h2>Tree demo</h2>", Label.CONTENT_XHTML)); + main.addComponent(new Label("<h2>Tree demo</h2>", ContentMode.XHTML)); // configure file structure panel main.addComponent(explorerPanel); @@ -48,7 +49,7 @@ public class TreeFilesystem extends com.vaadin.Application implements tree.addListener(this); // Get sample directory - final File sampleDir = SampleDirectory.getDirectory(this); + final File sampleDir = SampleDirectory.getDirectory(this, main); // populate tree's root node with example directory if (sampleDir != null) { populateNode(sampleDir.getAbsolutePath(), null); diff --git a/tests/testbench/com/vaadin/tests/TreeFilesystemContainer.java b/tests/testbench/com/vaadin/tests/TreeFilesystemContainer.java index 60d0f24b4e..1b32a35a38 100644 --- a/tests/testbench/com/vaadin/tests/TreeFilesystemContainer.java +++ b/tests/testbench/com/vaadin/tests/TreeFilesystemContainer.java @@ -14,9 +14,9 @@ import com.vaadin.ui.Component.Listener; import com.vaadin.ui.Field; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * Browsable file explorer using Vaadin Tree component. Demonstrates: how to use @@ -28,8 +28,8 @@ import com.vaadin.ui.Window; * @since 4.0.0 * */ -public class TreeFilesystemContainer extends com.vaadin.Application implements - Listener { +public class TreeFilesystemContainer extends + com.vaadin.Application.LegacyApplication implements Listener { // Filesystem explorer panel and it's components private final Panel explorerPanel = new Panel("Filesystem explorer"); @@ -43,7 +43,7 @@ public class TreeFilesystemContainer extends com.vaadin.Application implements @Override public void init() { - final Window w = new Window("Tree FilesystemContainer demo"); + final LegacyWindow w = new LegacyWindow("Tree FilesystemContainer demo"); setMainWindow(w); final VerticalLayout main = new VerticalLayout(); w.setContent(main); @@ -65,7 +65,7 @@ public class TreeFilesystemContainer extends com.vaadin.Application implements propertyPanel.setEnabled(false); // Get sample directory - final File sampleDir = SampleDirectory.getDirectory(this); + final File sampleDir = SampleDirectory.getDirectory(this, w); // Populate tree with FilesystemContainer final FilesystemContainer fsc = new FilesystemContainer(sampleDir, true); filesystem.setContainerDataSource(fsc); diff --git a/tests/testbench/com/vaadin/tests/UpgradingSample.java b/tests/testbench/com/vaadin/tests/UpgradingSample.java index 2b3a85624f..0db63ca789 100644 --- a/tests/testbench/com/vaadin/tests/UpgradingSample.java +++ b/tests/testbench/com/vaadin/tests/UpgradingSample.java @@ -14,14 +14,15 @@ package com.vaadin.tests; import com.vaadin.Application; import com.vaadin.data.Property; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * <p> @@ -34,7 +35,7 @@ import com.vaadin.ui.Window; * @since 3.1.1 * @author Vaadin Ltd. */ -public class UpgradingSample extends Application implements +public class UpgradingSample extends Application.LegacyApplication implements Property.ValueChangeListener { /* Menu for navigating inside the application. */ @@ -56,7 +57,7 @@ public class UpgradingSample extends Application implements public void init() { // Create the main window of the application - final Window main = new Window("Login example", layout); + final LegacyWindow main = new LegacyWindow("Login example", layout); setMainWindow(main); // Add menu and loginbox to the application @@ -113,14 +114,23 @@ public class UpgradingSample extends Application implements // The components this loginbox is composed of private final TextField loginName = new TextField("Name"); - private final Button loginButton = new Button("Enter", this, "login"); + private final Button loginButton = new Button("Enter", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + login(); + } + }); private final Panel loginPanel = new Panel("Login"); private final Panel statusPanel = new Panel(); private final Button logoutButton = new Button("Logout", - UpgradingSample.this, "close"); + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + close(); + } + }); private final Label statusLabel = new Label(); @@ -145,7 +155,7 @@ public class UpgradingSample extends Application implements // Login into application public void login() { - final String name = (String) loginName.getValue(); + final String name = loginName.getValue(); if (name != null && name.length() > 0) { setUser(name); } diff --git a/tests/testbench/com/vaadin/tests/UsingObjectsInSelect.java b/tests/testbench/com/vaadin/tests/UsingObjectsInSelect.java index 405f23ef91..780b7d94e1 100644 --- a/tests/testbench/com/vaadin/tests/UsingObjectsInSelect.java +++ b/tests/testbench/com/vaadin/tests/UsingObjectsInSelect.java @@ -10,16 +10,17 @@ import java.util.Random; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; -import com.vaadin.ui.Window; -public class UsingObjectsInSelect extends com.vaadin.Application implements - ValueChangeListener { +public class UsingObjectsInSelect extends + com.vaadin.Application.LegacyApplication implements ValueChangeListener { private final Select select = new Select(); private final Label selectedTask = new Label("Selected task", - Label.CONTENT_XHTML); + ContentMode.XHTML); public LinkedList<?> exampleTasks = new LinkedList<Object>(); @@ -27,7 +28,7 @@ public class UsingObjectsInSelect extends com.vaadin.Application implements @Override public void init() { - final Window main = new Window("Select demo"); + final LegacyWindow main = new LegacyWindow("Select demo"); setMainWindow(main); final Panel panel = new Panel("Select demo"); diff --git a/tests/testbench/com/vaadin/tests/appengine/GAESyncTest.java b/tests/testbench/com/vaadin/tests/appengine/GAESyncTest.java index 2b6656f11a..7d5e298286 100644 --- a/tests/testbench/com/vaadin/tests/appengine/GAESyncTest.java +++ b/tests/testbench/com/vaadin/tests/appengine/GAESyncTest.java @@ -11,11 +11,11 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Embedded; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; -public class GAESyncTest extends Application { +public class GAESyncTest extends Application.LegacyApplication { /** * @@ -45,7 +45,7 @@ public class GAESyncTest extends Application { } - private class IntrWindow extends Window { + private class IntrWindow extends LegacyWindow { private int n = 0; private static final long serialVersionUID = -6521351715072191625l; TextField tf; @@ -90,8 +90,8 @@ public class GAESyncTest extends Application { Button b = new Button("Add", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - if (getWindow() == getApplication().getMainWindow()) { - getWindow().showNotification("main"); + if (getRoot() == getMainWindow()) { + getRoot().showNotification("main"); try { Thread.sleep((5000)); } catch (InterruptedException e) { @@ -139,8 +139,8 @@ public class GAESyncTest extends Application { } @Override - public Window getWindow(String name) { - Window w = super.getWindow(name); + public LegacyWindow getWindow(String name) { + LegacyWindow w = super.getWindow(name); if (w == null) { w = new IntrWindow(this); addWindow(w); diff --git a/tests/testbench/com/vaadin/tests/application/ApplicationCloseTest.java b/tests/testbench/com/vaadin/tests/application/ApplicationCloseTest.java index 3d767eb016..2706134c27 100644 --- a/tests/testbench/com/vaadin/tests/application/ApplicationCloseTest.java +++ b/tests/testbench/com/vaadin/tests/application/ApplicationCloseTest.java @@ -6,6 +6,7 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; public class ApplicationCloseTest extends TestBase { @@ -14,7 +15,7 @@ public class ApplicationCloseTest extends TestBase { @Override protected void setup() { Label applications = new Label("Applications in session: <br/>", - Label.CONTENT_XHTML); + ContentMode.XHTML); for (Application a : ((WebApplicationContext) getContext()) .getApplications()) { applications.setValue(applications.getValue() + "App: " + a @@ -50,7 +51,7 @@ public class ApplicationCloseTest extends TestBase { / 1000 / 1000 + "MiB memory for this application.<br/>Total memory usage reported as " - + totalUsageString + "<br/>", Label.CONTENT_XHTML); + + totalUsageString + "<br/>", ContentMode.XHTML); addComponent(thisApp); addComponent(memoryUsage); diff --git a/tests/testbench/com/vaadin/tests/application/ErrorInUnloadEvent.java b/tests/testbench/com/vaadin/tests/application/ErrorInUnloadEvent.java index f212e74ca3..fcc4e26b55 100644 --- a/tests/testbench/com/vaadin/tests/application/ErrorInUnloadEvent.java +++ b/tests/testbench/com/vaadin/tests/application/ErrorInUnloadEvent.java @@ -9,13 +9,14 @@ import com.vaadin.ui.Component; import com.vaadin.ui.FormLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.PasswordField; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class ErrorInUnloadEvent extends AbstractTestCase { - private Window mainWindow; + private LegacyWindow mainWindow; @Override public void init() { @@ -28,7 +29,8 @@ public class ErrorInUnloadEvent extends AbstractTestCase { private void showLoginWindow() { if (mainWindow == null) { - mainWindow = new Window(); + mainWindow = new LegacyWindow(); + setMainWindow(mainWindow); } else { mainWindow.removeAllComponents(); } @@ -37,9 +39,8 @@ public class ErrorInUnloadEvent extends AbstractTestCase { FormLayout formLayout = new FormLayout(); final TextField userField = new TextField("Username"); userField.setDebugId("user"); - final TextField passwordField = new TextField("Password"); + final PasswordField passwordField = new PasswordField("Password"); passwordField.setDebugId("pwd"); - passwordField.setSecret(true); Button login = new Button("login"); login.setDebugId("loginButton"); login.setClickShortcut(KeyCode.ENTER); @@ -50,20 +51,19 @@ public class ErrorInUnloadEvent extends AbstractTestCase { login.addListener(new ClickListener() { public void buttonClick(final ClickEvent event) { - String username = (String) userField.getValue(); - String password = (String) passwordField.getValue(); + String username = userField.getValue(); + String password = passwordField.getValue(); setUser(username); showMainWindow(); } }); - - setMainWindow(mainWindow); } private void showMainWindow() { if (mainWindow == null) { - mainWindow = new Window(); + mainWindow = new LegacyWindow(); + setMainWindow(mainWindow); } else { mainWindow.removeAllComponents(); } diff --git a/tests/testbench/com/vaadin/tests/application/PaintableIdsShouldBeUnique.html b/tests/testbench/com/vaadin/tests/application/PaintableIdsShouldBeUnique.html deleted file mode 100644 index 64b3197fb8..0000000000 --- a/tests/testbench/com/vaadin/tests/application/PaintableIdsShouldBeUnique.html +++ /dev/null @@ -1,122 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8068/" /> -<title>PaintableIdsShouldBeUnique</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">PaintableIdsShouldBeUnique</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.application.PaintableIdsShouldBeUnique?restartApplication</td> - <td></td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_SMyLabel</td> - <td>30,11</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_SMyLabel</td> - <td>A label with a debug id.</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> - <td>A label without a debug id.</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_SMyButton/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_SMyButton/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_SMyButton/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_SMyLabel</td> - <td>Button clicked 3 times.</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> - <td>Button clicked 3 times.</td> -</tr> -<tr> - <td>clickAndWait</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_0SMyLabel</td> - <td>A label with a debug id.</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> - <td>A label without a debug id.</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_0SMyButton/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_0SMyLabel</td> - <td>Button clicked 1 times.</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> - <td>Button clicked 1 times.</td> -</tr> -<tr> - <td>clickAndWait</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_1SMyLabel</td> - <td>A label with a debug id.</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> - <td>A label without a debug id.</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_1SMyButton/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::PID_1SMyLabel</td> - <td>Button clicked 1 times.</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestsapplicationPaintableIdsShouldBeUnique::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> - <td>Button clicked 1 times.</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/tests/testbench/com/vaadin/tests/application/PaintableIdsShouldBeUnique.java b/tests/testbench/com/vaadin/tests/application/PaintableIdsShouldBeUnique.java deleted file mode 100644 index 95760c11a8..0000000000 --- a/tests/testbench/com/vaadin/tests/application/PaintableIdsShouldBeUnique.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.vaadin.tests.application; - -import com.vaadin.terminal.ExternalResource; -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Label; -import com.vaadin.ui.Window; - -public class PaintableIdsShouldBeUnique extends TestBase { - - @Override - protected void setup() { - setMainWindow(new MyWindow()); - } - - @Override - protected String getDescription() { - return "Two Paintables attached to different windows with the same debug id should have unique paintable ids"; - } - - @Override - protected Integer getTicketNumber() { - return 5109; - } - - @Override - public Window getWindow(String name) { - Window win = super.getWindow(name); - if (win == null) { - win = new MyWindow(); - addWindow(win); - win.open(new ExternalResource(win.getURL())); - } - return win; - } - - private class MyWindow extends Window { - int counter = 0; - Label labelWithDebugId = new Label("A label with a debug id."); - Label labelWithoutDebugId = new Label("A label without a debug id."); - Button button = new Button("Click me."); - Button newwin = new Button("New window"); - - MyWindow() { - labelWithDebugId.setDebugId("MyLabel"); - - button.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - counter++; - labelWithDebugId.setValue("Button clicked " + counter - + " times."); - labelWithoutDebugId.setValue("Button clicked " + counter - + " times."); - } - }); - button.setDebugId("MyButton"); - - newwin.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - Window win = new MyWindow(); - PaintableIdsShouldBeUnique.this.addWindow(win); - open(new ExternalResource(win.getURL())); - } - }); - - addComponent(labelWithDebugId); - addComponent(labelWithoutDebugId); - addComponent(button); - addComponent(newwin); - }; - } - -} diff --git a/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.html b/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.html new file mode 100644 index 0000000000..d48ab220b5 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.html @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.application.RefreshStatePreserve?restartApplication</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationRefreshStatePreserve::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>Root id: 0</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.application.RefreshStatePreserve</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationRefreshStatePreserve::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>Root id: 0</td> +</tr> +<tr> + <td>runScript</td> + <td>history.back()</td> + <td></td> +</tr> +<tr> + <td>pause</td> + <td></td> + <td>1000</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationRefreshStatePreserve::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>Root id: 0</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java b/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java new file mode 100644 index 0000000000..36a793bd6d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java @@ -0,0 +1,39 @@ +package com.vaadin.tests.application; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestApplication; +import com.vaadin.ui.Label; +import com.vaadin.ui.Root; + +public class RefreshStatePreserve extends AbstractTestApplication { + public static class RefreshStateRoot extends Root { + @Override + public void init(WrappedRequest request) { + getContent().addComponent( + new Label("window.name: " + + request.getBrowserDetails().getWindowName())); + getContent().addComponent(new Label("Root id: " + getRootId())); + } + } + + @Override + public void init() { + super.init(); + setRootPreserved(true); + } + + @Override + protected String getRootClassName(WrappedRequest request) { + return RefreshStateRoot.class.getName(); + } + + @Override + protected String getTestDescription() { + return "Refreshing the browser window should preserve the state"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(8068); + } +} diff --git a/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.html b/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.html new file mode 100644 index 0000000000..35657c73fc --- /dev/null +++ b/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.html @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.application.ThreadLocalInstances?restartApplication</td> + <td></td> +</tr> +<tr> + <td>waitForElementHeight</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::/VVerticalLayout[0]/ChildComponentContainer[1]/VEmbedded[0]/domChild[0]</td> + <td>11</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_15</td> + <td>1. null app in class init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_14</td> + <td>2. null root in class init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_13</td> + <td>3. null app in app constructor</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_12</td> + <td>4. null root in app constructor</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_11</td> + <td>5. this app in app init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_10</td> + <td>6. null root in app init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_9</td> + <td>7. this app in root init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_8</td> + <td>8. this root in root init</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_7</td> + <td>9. this app in root paint</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_6</td> + <td>10. this root in root paint</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_5</td> + <td>11. null app in background thread</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_4</td> + <td>12. null root in background thread</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_3</td> + <td>13. this app in resource handler</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_2</td> + <td>14. null root in resource handler</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_1</td> + <td>15. this app in button listener</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_0</td> + <td>16. this root in button listener</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java b/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java new file mode 100644 index 0000000000..68a0bb3805 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/application/ThreadLocalInstances.java @@ -0,0 +1,114 @@ +package com.vaadin.tests.application; + +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.ApplicationResource; +import com.vaadin.terminal.DownloadStream; +import com.vaadin.terminal.PaintException; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestApplication; +import com.vaadin.tests.integration.FlagSeResource; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Embedded; +import com.vaadin.ui.Root; + +public class ThreadLocalInstances extends AbstractTestApplication { + private static final Application staticInitApplication = Application + .getCurrentApplication(); + private static final Root staticInitRoot = Root.getCurrentRoot(); + + private final Root mainWindow = new Root() { + boolean paintReported = false; + + @Override + protected void init(WrappedRequest request) { + reportCurrentStatus("root init"); + } + + @Override + public void paintContent(com.vaadin.terminal.PaintTarget target) + throws PaintException { + if (!paintReported) { + reportCurrentStatus("root paint"); + Thread thread = new Thread() { + @Override + public void run() { + synchronized (ThreadLocalInstances.this) { + reportCurrentStatus("background thread"); + } + } + }; + thread.start(); + paintReported = true; + } + super.paintContent(target); + } + }; + + private final ApplicationResource resource = new FlagSeResource(this) { + @Override + public DownloadStream getStream() { + reportCurrentStatus("resource handler"); + return super.getStream(); + } + }; + + private final Log log = new Log(16); + + public ThreadLocalInstances() { + mainWindow.addComponent(log); + mainWindow.addComponent(new Embedded("Icon", resource)); + mainWindow.addComponent(new Button("Sync", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + reportCurrentStatus("button listener"); + } + })); + + reportStatus("class init", staticInitApplication, staticInitRoot); + reportCurrentStatus("app constructor"); + } + + @Override + public void init() { + reportCurrentStatus("app init"); + } + + @Override + protected Root getRoot(WrappedRequest request) + throws RootRequiresMoreInformationException { + return mainWindow; + } + + @Override + protected String getTestDescription() { + return "Tests the precence of Application.getCurrentApplication() and Root.getCurrentRoot() from different contexts"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(7895); + } + + private void reportCurrentStatus(String phase) { + reportStatus(phase, Application.getCurrentApplication(), + Root.getCurrentRoot()); + } + + private void reportStatus(String phase, Application application, Root root) { + log.log(getState(application, this) + " app in " + phase); + log.log(getState(root, mainWindow) + " root in " + phase); + } + + private static String getState(Object value, Object reference) { + if (value == null) { + return "null"; + } else if (value == reference) { + return "this"; + } else { + return value.toString(); + } + } + +} diff --git a/tests/testbench/com/vaadin/tests/applicationcontext/ChangeSessionId.java b/tests/testbench/com/vaadin/tests/applicationcontext/ChangeSessionId.java index c0141a72d5..17ac74e5a3 100644 --- a/tests/testbench/com/vaadin/tests/applicationcontext/ChangeSessionId.java +++ b/tests/testbench/com/vaadin/tests/applicationcontext/ChangeSessionId.java @@ -6,7 +6,7 @@ import com.vaadin.tests.util.Log; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; public class ChangeSessionId extends AbstractTestCase { @@ -16,7 +16,7 @@ public class ChangeSessionId extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window("Sestest Application"); + LegacyWindow mainWindow = new LegacyWindow("Sestest Application"); mainWindow.addComponent(log); mainWindow.addComponent(loginButton); mainWindow.addComponent(new Button("Show session id", diff --git a/tests/testbench/com/vaadin/tests/components/formlayout/FormLayoutReplaceComponent.html b/tests/testbench/com/vaadin/tests/browserfeatures/FullHeightScrollbar.html index ecac497a1b..37fee35746 100644 --- a/tests/testbench/com/vaadin/tests/components/formlayout/FormLayoutReplaceComponent.html +++ b/tests/testbench/com/vaadin/tests/browserfeatures/FullHeightScrollbar.html @@ -3,7 +3,7 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head profile="http://selenium-ide.openqa.org/profiles/test-case"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> +<link rel="selenium.base" href="http://192.168.2.41:8888/" /> <title>New Test</title> </head> <body> @@ -13,28 +13,33 @@ </thead><tbody> <tr> <td>open</td> - <td>/run/com.vaadin.tests.components.formlayout.FormLayoutReplaceComponent?restartApplication</td> + <td>/statictestfiles/browserfeatures/fullHeightScrollbar.html</td> <td></td> </tr> <tr> + <td>screenCapture</td> + <td></td> + <td>1-withScrolling</td> +</tr> +<tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsformlayoutFormLayoutReplaceComponent::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td> - <td>6,6</td> + <td>disableScrolling</td> + <td>34,7</td> </tr> <tr> <td>screenCapture</td> <td></td> - <td>textarea-visible</td> + <td>2-withoutScrolling</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsformlayoutFormLayoutReplaceComponent::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td> - <td>5,8</td> + <td>triggerReflow</td> + <td>34,7</td> </tr> <tr> <td>screenCapture</td> <td></td> - <td>textarea-hidden</td> + <td>3-afterReflow</td> </tr> </tbody></table> diff --git a/tests/testbench/com/vaadin/tests/components/AbstractComponentContainerTest.java b/tests/testbench/com/vaadin/tests/components/AbstractComponentContainerTest.java index 2a98988487..6e9e4e8930 100644 --- a/tests/testbench/com/vaadin/tests/components/AbstractComponentContainerTest.java +++ b/tests/testbench/com/vaadin/tests/components/AbstractComponentContainerTest.java @@ -1,5 +1,6 @@ package com.vaadin.tests.components; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -284,6 +285,11 @@ public abstract class AbstractComponentContainerTest<T extends AbstractComponent addCommands.put("PopupDateField", addPopupDateFieldCommand); addCommands.put("VerticalSplitPanel", addVerticalSplitPanelCommand); addCommands.put("HorizontalSplitPanel", addHorizontalSplitPanelCommand); + + HashSet<String> noVerticalSize = new HashSet<String>(); + noVerticalSize.add("TextField"); + noVerticalSize.add("Button"); + // addCommands.put("AbsoluteLayout", addAbsoluteLayoutCommand); // addCommands.put("HorizontalLayout", addHorizontalLayoutCommand); // addCommands.put("VerticalLayout", addVerticalLayoutCommand); @@ -303,6 +309,10 @@ public abstract class AbstractComponentContainerTest<T extends AbstractComponent createCategory(componentCategory, subCategory); for (ComponentSize size : sizes) { + if (size.getHeight() != null + && noVerticalSize.contains(componentCategory)) { + continue; + } createClickAction(size.toString(), componentCategory, addCommands.get(componentCategory), size); } diff --git a/tests/testbench/com/vaadin/tests/components/AbstractComponentTest.java b/tests/testbench/com/vaadin/tests/components/AbstractComponentTest.java index fe61df8913..60ce941565 100644 --- a/tests/testbench/com/vaadin/tests/components/AbstractComponentTest.java +++ b/tests/testbench/com/vaadin/tests/components/AbstractComponentTest.java @@ -8,6 +8,12 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import com.vaadin.event.FieldEvents.BlurEvent; +import com.vaadin.event.FieldEvents.BlurListener; +import com.vaadin.event.FieldEvents.BlurNotifier; +import com.vaadin.event.FieldEvents.FocusEvent; +import com.vaadin.event.FieldEvents.FocusListener; +import com.vaadin.event.FieldEvents.FocusNotifier; import com.vaadin.terminal.Resource; import com.vaadin.terminal.ThemeResource; import com.vaadin.tests.util.Log; @@ -15,9 +21,11 @@ import com.vaadin.tests.util.LoremIpsum; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; +import com.vaadin.ui.themes.BaseTheme; public abstract class AbstractComponentTest<T extends AbstractComponent> - extends AbstractComponentTestCase<T> { + extends AbstractComponentTestCase<T> implements FocusListener, + BlurListener { protected static final String TEXT_SHORT = "Short"; protected static final String TEXT_MEDIUM = "This is a semi-long text that might wrap."; @@ -150,11 +158,23 @@ public abstract class AbstractComponentTest<T extends AbstractComponent> } protected void setLogVisible(boolean visible) { - log.setVisible(visible); + // This is only to be screenshot-compatible with Vaadin 6, where + // invisible components cause spacing + if (visible) { + log.setHeight(null); + log.setWidth(null); + log.setCaption((String) log.getData()); + } else { + log.setHeight("0px"); + log.setWidth("0px"); + log.setCaption(null); + } } private void createLog() { log = new Log(5).setNumberLogRows(true); + log.setData(log.getCaption()); + log.setStyleName(BaseTheme.CLIP); getLayout().addComponent(log, 1); } @@ -221,6 +241,39 @@ public abstract class AbstractComponentTest<T extends AbstractComponent> } + protected Command<T, Boolean> focusListenerCommand = new Command<T, Boolean>() { + + public void execute(T c, Boolean value, Object data) { + if (value) { + ((FocusNotifier) c).addListener(AbstractComponentTest.this); + } else { + ((FocusNotifier) c).removeListener(AbstractComponentTest.this); + } + } + }; + protected Command<T, Boolean> blurListenerCommand = new Command<T, Boolean>() { + + public void execute(T c, Boolean value, Object data) { + if (value) { + ((BlurNotifier) c).addListener(AbstractComponentTest.this); + } else { + ((BlurNotifier) c).removeListener(AbstractComponentTest.this); + } + } + }; + + protected void createFocusListener(String category) { + createBooleanAction("Focus listener", category, false, + focusListenerCommand); + + } + + protected void createBlurListener(String category) { + createBooleanAction("Blur listener", category, false, + blurListenerCommand); + + } + private void createStyleNameSelect(String category) { LinkedHashMap<String, String> options = new LinkedHashMap<String, String>(); options.put("-", null); @@ -668,4 +721,13 @@ public abstract class AbstractComponentTest<T extends AbstractComponent> } } + + public void focus(FocusEvent event) { + log(event.getClass().getSimpleName()); + } + + public void blur(BlurEvent event) { + log(event.getClass().getSimpleName()); + } + } diff --git a/tests/testbench/com/vaadin/tests/components/AbstractComponentTestCase.java b/tests/testbench/com/vaadin/tests/components/AbstractComponentTestCase.java index 1b04198da0..57a32aafc4 100644 --- a/tests/testbench/com/vaadin/tests/components/AbstractComponentTestCase.java +++ b/tests/testbench/com/vaadin/tests/components/AbstractComponentTestCase.java @@ -126,7 +126,7 @@ public abstract class AbstractComponentTestCase<T extends AbstractComponent> public void execute(T c, Boolean enabled, Object data) { if (c instanceof Field) { - ((Field) c).setRequired(enabled); + ((Field<?>) c).setRequired(enabled); } else { throw new IllegalArgumentException(c.getClass().getName() + " is not a field and cannot be set to required"); @@ -136,7 +136,7 @@ public abstract class AbstractComponentTestCase<T extends AbstractComponent> protected Command<T, String> requiredErrorMessageCommand = new Command<T, String>() { public void execute(T c, String value, Object data) { - ((Field) c).setRequiredError(value); + ((Field<?>) c).setRequiredError(value); } }; diff --git a/tests/testbench/com/vaadin/tests/components/AbstractTestApplication.java b/tests/testbench/com/vaadin/tests/components/AbstractTestApplication.java new file mode 100644 index 0000000000..8de1e68b4b --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/AbstractTestApplication.java @@ -0,0 +1,23 @@ +package com.vaadin.tests.components; + +import com.vaadin.Application; +import com.vaadin.service.ApplicationContext; +import com.vaadin.terminal.gwt.server.AbstractWebApplicationContext; +import com.vaadin.terminal.gwt.server.WebBrowser; + +public abstract class AbstractTestApplication extends Application { + protected abstract String getTestDescription(); + + protected abstract Integer getTicketNumber(); + + protected WebBrowser getBrowser() { + ApplicationContext context = getContext(); + if (context instanceof AbstractWebApplicationContext) { + WebBrowser webBrowser = ((AbstractWebApplicationContext) context) + .getBrowser(); + return webBrowser; + } + + return null; + } +} diff --git a/tests/testbench/com/vaadin/tests/components/AbstractTestCase.java b/tests/testbench/com/vaadin/tests/components/AbstractTestCase.java index e2b3ad0fe1..11d960e143 100644 --- a/tests/testbench/com/vaadin/tests/components/AbstractTestCase.java +++ b/tests/testbench/com/vaadin/tests/components/AbstractTestCase.java @@ -5,7 +5,7 @@ import com.vaadin.service.ApplicationContext; import com.vaadin.terminal.gwt.server.AbstractWebApplicationContext; import com.vaadin.terminal.gwt.server.WebBrowser; -public abstract class AbstractTestCase extends Application { +public abstract class AbstractTestCase extends Application.LegacyApplication { protected abstract String getDescription(); diff --git a/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java b/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java new file mode 100644 index 0000000000..eb27d18ca0 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/AbstractTestRoot.java @@ -0,0 +1,70 @@ +package com.vaadin.tests.components; + +import com.vaadin.Application; +import com.vaadin.service.ApplicationContext; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.gwt.server.AbstractWebApplicationContext; +import com.vaadin.terminal.gwt.server.WebBrowser; +import com.vaadin.ui.Component; +import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root; +import com.vaadin.ui.VerticalLayout; + +public abstract class AbstractTestRoot extends Root { + + @Override + public void init(WrappedRequest request) { + setCaption(getClass().getName()); + + Label label = new Label(getTestDescription(), ContentMode.XHTML); + label.setWidth("100%"); + + layout = new VerticalLayout(); + + getContent().addComponent(label); + getContent().addComponent(layout); + ((VerticalLayout) getContent()).setExpandRatio(layout, 1); + + setup(request); + } + + private VerticalLayout layout; + + protected VerticalLayout getLayout() { + return layout; + } + + protected abstract void setup(WrappedRequest request); + + @Override + public void addComponent(Component c) { + getLayout().addComponent(c); + } + + @Override + public void removeComponent(Component c) { + getLayout().removeComponent(c); + } + + @Override + public void replaceComponent(Component oldComponent, Component newComponent) { + getLayout().replaceComponent(oldComponent, newComponent); + } + + protected abstract String getTestDescription(); + + protected abstract Integer getTicketNumber(); + + protected WebBrowser getBrowser() { + ApplicationContext context = Application.getCurrentApplication() + .getContext(); + if (context instanceof AbstractWebApplicationContext) { + AbstractWebApplicationContext webContext = (AbstractWebApplicationContext) context; + return webContext.getBrowser(); + } + + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/ComponentTestCase.java b/tests/testbench/com/vaadin/tests/components/ComponentTestCase.java index 1e15f7a47b..a2c186df7e 100644 --- a/tests/testbench/com/vaadin/tests/components/ComponentTestCase.java +++ b/tests/testbench/com/vaadin/tests/components/ComponentTestCase.java @@ -7,6 +7,7 @@ import java.util.List; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; @@ -111,9 +112,10 @@ public abstract class ComponentTestCase<T extends AbstractComponent> extends boolean initialState, final Command<T, Boolean> command) { CheckBox checkBox = new CheckBox(caption); - checkBox.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - boolean enabled = (Boolean) event.getButton().getValue(); + checkBox.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean enabled = (Boolean) event.getProperty().getValue(); doCommand(command, enabled); } }); @@ -132,10 +134,13 @@ public abstract class ComponentTestCase<T extends AbstractComponent> extends final Command<T, Boolean> command) { Button button = new Button(caption); + button.setData(Boolean.FALSE); button.addListener(new Button.ClickListener() { public void buttonClick(ClickEvent event) { - boolean enabled = (Boolean) event.getButton().getValue(); - doCommand(command, enabled); + Button b = event.getButton(); + boolean state = (Boolean) b.getData(); + b.setData(!state); + doCommand(command, state); } }); diff --git a/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html new file mode 100644 index 0000000000..029da64754 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.html @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>DisableEnableCascade</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">DisableEnableCascade</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.DisableEnableCascade?restartApplication</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>panel-disabled</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>tabsheet-disabled</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>all-enabled</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>tabsheet-button-disabled</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[2]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsDisableEnableCascade::/VVerticalLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>all-enabled2</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java new file mode 100644 index 0000000000..aa83ff7a42 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/DisableEnableCascade.java @@ -0,0 +1,90 @@ +package com.vaadin.tests.components; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TabSheet; + +public class DisableEnableCascade extends TestBase { + + private Panel outerPanel; + private TabSheet innerTabsheet; + private Button button; + private Button enableDisablePanelButton; + private Button enableDisableTabSheetButton; + private Button enableDisableButtonButton; + + @Override + protected void setup() { + + outerPanel = new Panel("Outer panel, enabled"); + innerTabsheet = new TabSheet(); + innerTabsheet.setCaption("Inner Tabsheet, enabled"); + + button = new Button("Button, enabled"); + + outerPanel.setContent(innerTabsheet); + innerTabsheet.addTab(button, "Tab containing button"); + + addComponent(outerPanel); + + enableDisablePanelButton = new Button("Disable panel", + new ClickListener() { + + public void buttonClick(ClickEvent event) { + enableDisable(outerPanel, enableDisablePanelButton); + + } + }); + + enableDisableTabSheetButton = new Button("Disable TabSheet", + new ClickListener() { + + public void buttonClick(ClickEvent event) { + enableDisable(innerTabsheet, + enableDisableTabSheetButton); + + } + }); + + enableDisableButtonButton = new Button("Disable Button", + new ClickListener() { + + public void buttonClick(ClickEvent event) { + enableDisable(button, enableDisableButtonButton); + + } + }); + + addComponent(enableDisablePanelButton); + addComponent(enableDisableTabSheetButton); + addComponent(enableDisableButtonButton); + } + + protected void enableDisable(Component target, Button button) { + if (target.isEnabled()) { + target.setEnabled(false); + button.setCaption(button.getCaption().replace("Disable", "Enable")); + target.setCaption(target.getCaption() + .replace("enabled", "disabled")); + } else { + target.setEnabled(true); + button.setCaption(button.getCaption().replace("Enable", "Disable")); + target.setCaption(target.getCaption() + .replace("disabled", "enabled")); + } + } + + @Override + protected String getDescription() { + return "Tests the disable state is cascaded correctly to children. Disabling a parent should disabled its children aswell. The buttons only toggle the state of the target component."; + } + + @Override + protected Integer getTicketNumber() { + return 8507; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/LayoutAttachListenerInfo.java b/tests/testbench/com/vaadin/tests/components/LayoutAttachListenerInfo.java index 7ed44768fd..dc07c35f62 100644 --- a/tests/testbench/com/vaadin/tests/components/LayoutAttachListenerInfo.java +++ b/tests/testbench/com/vaadin/tests/components/LayoutAttachListenerInfo.java @@ -11,10 +11,9 @@ import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.ComponentContainer.ComponentAttachEvent; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; import com.vaadin.ui.OptionGroup; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window.Notification; - public class LayoutAttachListenerInfo extends TestBase { @@ -85,9 +84,9 @@ public class LayoutAttachListenerInfo extends TestBase { })); } - private void testOrderedLayout(){ + private void testOrderedLayout() { content.removeAllComponents(); - + final VerticalLayout v = new VerticalLayout(); v.setWidth("300px"); v.setHeight("300px"); diff --git a/tests/testbench/com/vaadin/tests/components/TestBase.java b/tests/testbench/com/vaadin/tests/components/TestBase.java index c7380d3d7c..4825e09404 100644 --- a/tests/testbench/com/vaadin/tests/components/TestBase.java +++ b/tests/testbench/com/vaadin/tests/components/TestBase.java @@ -2,18 +2,19 @@ package com.vaadin.tests.components; import com.vaadin.ui.Component; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public abstract class TestBase extends AbstractTestCase { @Override public final void init() { - window = new Window(getClass().getName()); + window = new LegacyWindow(getClass().getName()); setMainWindow(window); window.getContent().setSizeFull(); - Label label = new Label(getDescription(), Label.CONTENT_XHTML); + Label label = new Label(getDescription(), ContentMode.XHTML); label.setWidth("100%"); window.getContent().addComponent(label); @@ -24,7 +25,7 @@ public abstract class TestBase extends AbstractTestCase { setup(); } - private Window window; + private LegacyWindow window; private VerticalLayout layout; public TestBase() { diff --git a/tests/testbench/com/vaadin/tests/components/TouchScrollables.java b/tests/testbench/com/vaadin/tests/components/TouchScrollables.java index 88335a1996..636bddead8 100644 --- a/tests/testbench/com/vaadin/tests/components/TouchScrollables.java +++ b/tests/testbench/com/vaadin/tests/components/TouchScrollables.java @@ -75,7 +75,6 @@ public class TouchScrollables extends TestBase { cssLayout.setCaption("Panel"); final Panel p = new Panel(); - p.setScrollable(true); p.setHeight("400px"); p.setCaption("Panel"); Label l50 = null; @@ -90,7 +89,7 @@ public class TouchScrollables extends TestBase { final Label l = l50; button = new Button("Scroll to label 50", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - getLayout().getWindow().scrollIntoView(l); + getLayout().getRoot().scrollIntoView(l); } }); cssLayout.addComponent(button); @@ -106,7 +105,7 @@ public class TouchScrollables extends TestBase { TestUtils .injectCSS( - getLayout().getWindow(), + getLayout().getRoot(), "body * {-webkit-user-select: none;} .v-table-row-drag-middle .v-table-cell-content {" + " background-color: inherit ; border-bottom: 1px solid cyan;" + "}" @@ -139,7 +138,7 @@ public class TouchScrollables extends TestBase { } public void handleAction(Action action, Object sender, Object target) { - getLayout().getWindow().showNotification(action.getCaption()); + getLayout().getRoot().showNotification(action.getCaption()); } }); diff --git a/tests/testbench/com/vaadin/tests/components/abstractcomponent/EnableState.java b/tests/testbench/com/vaadin/tests/components/abstractcomponent/EnableState.java index a5498660be..9261962b0d 100644 --- a/tests/testbench/com/vaadin/tests/components/abstractcomponent/EnableState.java +++ b/tests/testbench/com/vaadin/tests/components/abstractcomponent/EnableState.java @@ -1,25 +1,27 @@ package com.vaadin.tests.components.abstractcomponent; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; public class EnableState extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window("Helloworld Application"); + LegacyWindow mainWindow = new LegacyWindow("Helloworld Application"); final Panel panel = new Panel("Test"); final Button button = new Button("ablebutton"); panel.addComponent(button); CheckBox enable = new CheckBox("Toggle button enabled", true); - enable.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - boolean enabled = (Boolean) event.getButton().getValue(); + enable.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean enabled = (Boolean) event.getProperty().getValue(); button.setEnabled(enabled); // button.requestRepaint(); } @@ -27,17 +29,19 @@ public class EnableState extends AbstractTestCase { enable.setImmediate(true); CheckBox caption = new CheckBox("Toggle button caption", true); - caption.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + caption.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { button.setCaption(button.getCaption() + "+"); } }); caption.setImmediate(true); CheckBox visible = new CheckBox("Toggle panel visibility", true); - visible.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - boolean visible = (Boolean) event.getButton().getValue(); + visible.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean visible = (Boolean) event.getProperty().getValue(); panel.setVisible(visible); } @@ -45,9 +49,10 @@ public class EnableState extends AbstractTestCase { visible.setImmediate(true); CheckBox panelEnable = new CheckBox("Toggle panel enabled", true); - panelEnable.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - boolean enabled = (Boolean) event.getButton().getValue(); + panelEnable.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean enabled = (Boolean) event.getProperty().getValue(); panel.setEnabled(enabled); } }); diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractComponentDataBindingTest.java b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractComponentDataBindingTest.java new file mode 100644 index 0000000000..93ba858e37 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractComponentDataBindingTest.java @@ -0,0 +1,117 @@ +package com.vaadin.tests.components.abstractfield; + +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import com.vaadin.data.Container; +import com.vaadin.data.Item; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.AbstractField; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Component; + +public abstract class AbstractComponentDataBindingTest extends TestBase + implements ValueChangeListener { + private static final Object CAPTION = "CAPTION"; + private Log log = new Log(5); + private ComboBox localeSelect; + + @Override + protected void setup() { + addComponent(log); + localeSelect = createLocaleSelect(); + addComponent(localeSelect); + + // Causes fields to be created + localeSelect.setValue(Locale.US); + } + + private ComboBox createLocaleSelect() { + ComboBox cb = new ComboBox("Locale"); + cb.addContainerProperty(CAPTION, String.class, ""); + cb.setItemCaptionPropertyId(CAPTION); + cb.setNullSelectionAllowed(false); + for (Locale l : Locale.getAvailableLocales()) { + Item i = cb.addItem(l); + i.getItemProperty(CAPTION).setValue( + l.getDisplayName(Locale.ENGLISH)); + } + ((Container.Sortable) cb.getContainerDataSource()).sort( + new Object[] { CAPTION }, new boolean[] { true }); + cb.setImmediate(true); + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + updateLocale((Locale) localeSelect.getValue()); + } + }); + return cb; + } + + protected void updateLocale(Locale locale) { + setLocale(locale); + for (Component c : fields) { + removeComponent(c); + } + fields.clear(); + createFields(); + } + + protected abstract void createFields(); + + private Set<Component> fields = new HashSet<Component>(); + + @Override + protected void addComponent(Component c) { + super.addComponent(c); + if (c instanceof AbstractField) { + configureField((AbstractField<?>) c); + if (c != localeSelect) { + fields.add(c); + } + } + } + + protected void configureField(AbstractField<?> field) { + field.setImmediate(true); + field.addListener(this); + } + + @Override + protected String getDescription() { + return ""; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + + public void valueChange(ValueChangeEvent event) { + AbstractField field = (AbstractField) event.getProperty(); + // if (field == localeSelect) { + // return; + // } + + Object newValue = field.getValue(); + if (newValue != null) { + newValue = newValue + " (" + newValue.getClass().getName() + ")"; + } + + String message = "Value of " + field.getCaption() + " changed to " + + newValue + "."; + if (field.getPropertyDataSource() != null) { + Object dataSourceValue = field.getPropertyDataSource().getValue(); + message += "Data model value is " + dataSourceValue; + message += " (" + field.getPropertyDataSource().getType().getName() + + ")"; + } + log.log(message); + + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldCommitWithInvalidValues.java b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldCommitWithInvalidValues.java index a08f8999a6..5d0e0fe488 100644 --- a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldCommitWithInvalidValues.java +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldCommitWithInvalidValues.java @@ -6,8 +6,8 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Notification; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window.Notification; public class AbstractFieldCommitWithInvalidValues extends TestBase { diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java index 40cc2948ee..716f80e23f 100644 --- a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java @@ -13,26 +13,29 @@ import com.vaadin.data.Property; import com.vaadin.data.Property.ReadOnlyStatusChangeEvent; import com.vaadin.data.Property.ReadOnlyStatusChangeListener; import com.vaadin.data.Property.ValueChangeListener; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.BlurNotifier; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.FieldEvents.FocusNotifier; import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.AbstractField; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; -public abstract class AbstractFieldTest<T extends AbstractField> extends +public abstract class AbstractFieldTest<T extends AbstractField<?>> extends AbstractComponentTest<T> implements ValueChangeListener, - ReadOnlyStatusChangeListener, FocusListener, BlurListener { + ReadOnlyStatusChangeListener { @Override protected void createActions() { super.createActions(); createBooleanAction("Required", CATEGORY_STATE, false, requiredCommand); createRequiredErrorSelect(CATEGORY_DECORATIONS); + if (FocusNotifier.class.isAssignableFrom(getTestClass())) { + createFocusListener(CATEGORY_LISTENERS); + } + + if (BlurNotifier.class.isAssignableFrom(getTestClass())) { + createBlurListener(CATEGORY_LISTENERS); + } createValueChangeListener(CATEGORY_LISTENERS); createReadOnlyStatusChangeListener(CATEGORY_LISTENERS); @@ -82,14 +85,6 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends createSelectAction("Required error message", category, options, "-", requiredErrorMessageCommand); - if (FocusNotifier.class.isAssignableFrom(getTestClass())) { - createFocusListener(CATEGORY_LISTENERS); - } - - if (BlurNotifier.class.isAssignableFrom(getTestClass())) { - createBlurListener(CATEGORY_LISTENERS); - } - } private void createValueChangeListener(String category) { @@ -104,18 +99,6 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends false, readonlyStatusChangeListenerCommand); } - private void createFocusListener(String category) { - createBooleanAction("Focus listener", category, false, - focusListenerCommand); - - } - - private void createBlurListener(String category) { - createBooleanAction("Blur listener", category, false, - blurListenerCommand); - - } - protected Command<T, Boolean> valueChangeListenerCommand = new Command<T, Boolean>() { public void execute(T c, Boolean value, Object data) { @@ -136,26 +119,7 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends } } }; - protected Command<T, Boolean> focusListenerCommand = new Command<T, Boolean>() { - - public void execute(T c, Boolean value, Object data) { - if (value) { - ((FocusNotifier) c).addListener(AbstractFieldTest.this); - } else { - ((FocusNotifier) c).removeListener(AbstractFieldTest.this); - } - } - }; - protected Command<T, Boolean> blurListenerCommand = new Command<T, Boolean>() { - public void execute(T c, Boolean value, Object data) { - if (value) { - ((BlurNotifier) c).addListener(AbstractFieldTest.this); - } else { - ((BlurNotifier) c).removeListener(AbstractFieldTest.this); - } - } - }; protected Command<T, Object> setValueCommand = new Command<T, Object>() { public void execute(T c, Object value, Object data) { @@ -208,14 +172,6 @@ public abstract class AbstractFieldTest<T extends AbstractField> extends log(event.getClass().getSimpleName()); } - public void focus(FocusEvent event) { - log(event.getClass().getSimpleName()); - } - - public void blur(BlurEvent event) { - log(event.getClass().getSimpleName()); - } - protected void createSetTextValueAction(String category) { String subCategory = "Set text value"; createCategory(subCategory, category); diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/DateFieldBackedByString.java b/tests/testbench/com/vaadin/tests/components/abstractfield/DateFieldBackedByString.java new file mode 100644 index 0000000000..d4b2f89522 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/DateFieldBackedByString.java @@ -0,0 +1,17 @@ +package com.vaadin.tests.components.abstractfield; + +import com.vaadin.ui.DateField; + +public class DateFieldBackedByString extends AbstractComponentDataBindingTest { + + private String s = null; + + @Override + protected void createFields() { + DateField df = new DateField("Date field"); + addComponent(df); + df.setPropertyDataSource(new com.vaadin.data.util.ObjectProperty<String>( + s, String.class)); + + } +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/DateFieldBasedOnLong.java b/tests/testbench/com/vaadin/tests/components/abstractfield/DateFieldBasedOnLong.java new file mode 100644 index 0000000000..deea0fbe0a --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/DateFieldBasedOnLong.java @@ -0,0 +1,34 @@ +package com.vaadin.tests.components.abstractfield; + +import java.util.Date; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.PopupDateField; + +public class DateFieldBasedOnLong extends AbstractComponentDataBindingTest { + + private Long l = null; + private ObjectProperty<Long> property; + + @Override + protected void createFields() { + PopupDateField pdf = new PopupDateField("DateField"); + addComponent(pdf); + property = new ObjectProperty<Long>(l, Long.class); + pdf.setPropertyDataSource(property); + + property.setValue(new Date(2011 - 1900, 4, 6).getTime()); + + addComponent(new Button("Set property value to 10000L", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + property.setValue(10000L); + + } + })); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/DoubleInTextField.java b/tests/testbench/com/vaadin/tests/components/abstractfield/DoubleInTextField.java new file mode 100644 index 0000000000..4fd81081ea --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/DoubleInTextField.java @@ -0,0 +1,31 @@ +package com.vaadin.tests.components.abstractfield; + +import com.vaadin.data.util.MethodProperty; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.ui.TextField; + +public class DoubleInTextField extends AbstractComponentDataBindingTest { + + @Override + protected void createFields() { + Person person = new Person("John", "Doe", "john@doe.com", 78, Sex.MALE, + new Address("Dovestreet 12", 12233, "Johnston", + Country.SOUTH_AFRICA)); + + TextField salary = new TextField("Vaadin 7 - TextField with Double"); + addComponent(salary); + salary.setPropertyDataSource(new MethodProperty<Double>(person, + "salaryDouble")); + + TextField salary6 = new TextField("Vaadin 6 - TextField with Double"); + addComponent(salary6); + salary6.setPropertyDataSource(new MethodProperty<Double>(person, + "salaryDouble")); + salary6.setConverter(new Vaadin6ImplicitDoubleConverter()); + + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/IntegerDoubleFieldsWithDataSource.java b/tests/testbench/com/vaadin/tests/components/abstractfield/IntegerDoubleFieldsWithDataSource.java new file mode 100644 index 0000000000..c13aadd895 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/IntegerDoubleFieldsWithDataSource.java @@ -0,0 +1,64 @@ +package com.vaadin.tests.components.abstractfield; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.data.validator.DoubleValidator; +import com.vaadin.data.validator.IntegerValidator; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.TextField; + +public class IntegerDoubleFieldsWithDataSource extends TestBase { + + private Log log = new Log(5); + + @Override + protected void setup() { + addComponent(log); + + TextField tf = createIntegerTextField(); + tf.addValidator(new IntegerValidator("Must be an Integer")); + addComponent(tf); + + tf = createIntegerTextField(); + tf.setCaption("Enter a double"); + tf.setPropertyDataSource(new ObjectProperty<Double>(2.1)); + tf.addValidator(new DoubleValidator("Must be a Double")); + addComponent(tf); + } + + private TextField createIntegerTextField() { + final TextField tf = new TextField("Enter an integer"); + tf.setPropertyDataSource(new ObjectProperty<Integer>(new Integer(2))); + tf.setImmediate(true); + tf.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + try { + log.log("Value for " + tf.getCaption() + " changed to " + + tf.getValue()); + log.log("Converted value is " + tf.getConvertedValue()); + } catch (Exception e) { + // TODO: handle exception + e.printStackTrace(); + } + } + }); + + return tf; + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/IntegerFieldWithoutDataSource.java b/tests/testbench/com/vaadin/tests/components/abstractfield/IntegerFieldWithoutDataSource.java new file mode 100644 index 0000000000..b25dc9d953 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/IntegerFieldWithoutDataSource.java @@ -0,0 +1,59 @@ +package com.vaadin.tests.components.abstractfield; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.TextField; + +public class IntegerFieldWithoutDataSource extends TestBase { + + private Log log = new Log(5); + + @Override + protected void setup() { + addComponent(log); + + TextField tf = createIntegerTextField(); + tf.setCaption(tf.getCaption() + "(invalid allowed)"); + addComponent(tf); + tf = createIntegerTextField(); + tf.setInvalidAllowed(false); + tf.setCaption(tf.getCaption() + "(invalid not allowed)"); + addComponent(tf); + } + + private TextField createIntegerTextField() { + final TextField tf = new TextField("Enter an integer"); + tf.setConverter(Integer.class); + tf.setImmediate(true); + tf.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + try { + log.log("Value for " + tf.getCaption() + " changed to " + + tf.getValue()); + log.log("Converted value is " + tf.getConvertedValue()); + } catch (Exception e) { + // TODO: handle exception + e.printStackTrace(); + } + } + }); + + return tf; + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/ShortcutAddAndRemove.html b/tests/testbench/com/vaadin/tests/components/abstractfield/ShortcutAddAndRemove.html index cad194d37a..a7b8e24ae7 100644 --- a/tests/testbench/com/vaadin/tests/components/abstractfield/ShortcutAddAndRemove.html +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/ShortcutAddAndRemove.html @@ -18,7 +18,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/domChild[0]</td> <td>316,58</td> </tr> <!--Enter on background - should cause event--> @@ -159,7 +159,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>625,2</td> </tr> <tr> @@ -185,15 +185,10 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/VVerticalLayout[0]</td> <td>631,52</td> </tr> <tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> - <td>597,57</td> -</tr> -<tr> <td>pressSpecialKey</td> <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::</td> <td>enter</td> @@ -203,7 +198,6 @@ <td>vaadin=runcomvaadintestscomponentsabstractfieldShortcutAddAndRemove::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> <td>4. Log button was clicked</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/TextFieldConversions.java b/tests/testbench/com/vaadin/tests/components/abstractfield/TextFieldConversions.java new file mode 100644 index 0000000000..8ce214918d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/TextFieldConversions.java @@ -0,0 +1,51 @@ +package com.vaadin.tests.components.abstractfield; + +import java.util.Date; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.terminal.UserError; +import com.vaadin.ui.AbstractComponent.ComponentErrorEvent; +import com.vaadin.ui.AbstractComponent.ComponentErrorHandler; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.TextField; + +public class TextFieldConversions extends AbstractComponentDataBindingTest { + + private TextField tf; + + private Object o; + + private ComboBox dataType; + + @Override + protected void createFields() { + dataType = new ComboBox("Data type"); + dataType.setImmediate(true); + dataType.addItem(Long.class); + dataType.addItem(Integer.class); + dataType.addItem(Double.class); + dataType.addItem(Date.class); + dataType.addItem(String.class); + + dataType.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + tf.setPropertyDataSource(new ObjectProperty<Object>(o, + (Class<Object>) dataType.getValue())); + } + }); + addComponent(dataType); + + tf = new TextField("TextField"); + addComponent(tf); + tf.setErrorHandler(new ComponentErrorHandler() { + + public boolean handleComponentError(ComponentErrorEvent event) { + tf.setComponentError(new UserError("Invalid value")); + return true; + } + }); + } +} diff --git a/tests/testbench/com/vaadin/tests/components/abstractfield/Vaadin6ImplicitDoubleConverter.java b/tests/testbench/com/vaadin/tests/components/abstractfield/Vaadin6ImplicitDoubleConverter.java new file mode 100644 index 0000000000..0228a59f06 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/Vaadin6ImplicitDoubleConverter.java @@ -0,0 +1,35 @@ +package com.vaadin.tests.components.abstractfield; + +import java.util.Locale; + +import com.vaadin.data.util.converter.Converter; + +public class Vaadin6ImplicitDoubleConverter implements + Converter<String, Double> { + + public Double convertToModel(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (null == value) { + return null; + } + return new Double(value.toString()); + } + + public String convertToPresentation(Double value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + return value.toString(); + + } + + public Class<Double> getModelType() { + return Double.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonDisableOnClick.html b/tests/testbench/com/vaadin/tests/components/button/ButtonDisableOnClick.html index 850d553b5b..d39f72ef1f 100644 --- a/tests/testbench/com/vaadin/tests/components/button/ButtonDisableOnClick.html +++ b/tests/testbench/com/vaadin/tests/components/button/ButtonDisableOnClick.html @@ -16,7 +16,7 @@ <td>/run/com.vaadin.tests.components.button.Buttons2?restartApplication</td> <td></td> </tr> -<!--value change listener--> +<!--click listener--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::PID_Smenu#item0</td> @@ -29,7 +29,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::Root/VOverlay[1]/VMenuBar[0]#item4</td> + <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::Root/VOverlay[1]/VMenuBar[0]#item2</td> <td>35,8</td> </tr> <!--disable on click--> @@ -45,7 +45,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::Root/VOverlay[1]/VMenuBar[0]#item1</td> + <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::Root/VOverlay[1]/VMenuBar[0]#item0</td> <td>22,4</td> </tr> <tr> @@ -133,7 +133,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::Root/VOverlay[1]/VMenuBar[0]#item1</td> + <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::Root/VOverlay[1]/VMenuBar[0]#item0</td> <td>36,3</td> </tr> <tr> @@ -151,7 +151,6 @@ <td>vaadin=runcomvaadintestscomponentsbuttonButtons2::PID_StestComponent</td> <td>v-disabled</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonMouseDetails.java b/tests/testbench/com/vaadin/tests/components/button/ButtonMouseDetails.java index 40caf620a8..deab87f8a2 100644 --- a/tests/testbench/com/vaadin/tests/components/button/ButtonMouseDetails.java +++ b/tests/testbench/com/vaadin/tests/components/button/ButtonMouseDetails.java @@ -3,12 +3,12 @@ package com.vaadin.tests.components.button; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.CheckBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; public class ButtonMouseDetails extends TestBase { - private Label out = new Label("", Label.CONTENT_PREFORMATTED); + private Label out = new Label("", ContentMode.PREFORMATTED); private int clickCounter = 1; @@ -46,10 +46,6 @@ public class ButtonMouseDetails extends TestBase { button.setImmediate(true); addComponent(button); - CheckBox cb = new CheckBox("CHECK ME!", clickListener); - cb.setImmediate(true); - addComponent(cb); - addComponent(out); } diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonUndefinedWidth.html b/tests/testbench/com/vaadin/tests/components/button/ButtonUndefinedWidth.html index 28fe12f5a2..0aaa01f05b 100644 --- a/tests/testbench/com/vaadin/tests/components/button/ButtonUndefinedWidth.html +++ b/tests/testbench/com/vaadin/tests/components/button/ButtonUndefinedWidth.html @@ -63,7 +63,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsbuttonButtonUndefinedWidth::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentsbuttonButtonUndefinedWidth::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[2]</td> <td>636,149</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/button/Buttons.java b/tests/testbench/com/vaadin/tests/components/button/Buttons.java index afbc90d197..573c95c2b8 100644 --- a/tests/testbench/com/vaadin/tests/components/button/Buttons.java +++ b/tests/testbench/com/vaadin/tests/components/button/Buttons.java @@ -46,13 +46,7 @@ public class Buttons extends ComponentTestCase<Button> { l.setWidth("100%"); l.setHeight("65px"); - boolean ie6 = (getBrowser().isIE() && getBrowser() - .getBrowserMajorVersion() == 6); - if (!ie6 || !nat) { - // Skip this NativeButton for IE6 as it can't decide how to - // render it - addTestComponent(l); - } + addTestComponent(l); } } diff --git a/tests/testbench/com/vaadin/tests/components/button/Buttons2.java b/tests/testbench/com/vaadin/tests/components/button/Buttons2.java index b65a9fc0cd..e04d50bddb 100644 --- a/tests/testbench/com/vaadin/tests/components/button/Buttons2.java +++ b/tests/testbench/com/vaadin/tests/components/button/Buttons2.java @@ -2,22 +2,14 @@ package com.vaadin.tests.components.button; import java.util.LinkedHashMap; -import com.vaadin.tests.components.abstractfield.AbstractFieldTest; +import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.themes.Reindeer; -public class Buttons2<T extends Button> extends AbstractFieldTest<T> implements - ClickListener { - - private Command<T, Boolean> switchModeCommand = new Command<T, Boolean>() { - - @SuppressWarnings("deprecation") - public void execute(T c, Boolean value, Object data) { - c.setSwitchMode(value); - } - }; +public class Buttons2<T extends Button> extends AbstractComponentTest<T> + implements ClickListener { private Command<T, Boolean> disableOnClickCommand = new Command<T, Boolean>() { @@ -38,6 +30,7 @@ public class Buttons2<T extends Button> extends AbstractFieldTest<T> implements } }; + @SuppressWarnings("unchecked") @Override protected Class<T> getTestClass() { return (Class<T>) Button.class; @@ -47,8 +40,9 @@ public class Buttons2<T extends Button> extends AbstractFieldTest<T> implements protected void createActions() { super.createActions(); - createBooleanAction("Switch mode", CATEGORY_FEATURES, false, - switchModeCommand); + createFocusListener(CATEGORY_LISTENERS); + createBlurListener(CATEGORY_LISTENERS); + createBooleanAction("Disable on click", CATEGORY_FEATURES, false, disableOnClickCommand); addClickListener(CATEGORY_LISTENERS); diff --git a/tests/testbench/com/vaadin/tests/components/button/ButtonsInHorizontalLayout.java b/tests/testbench/com/vaadin/tests/components/button/ButtonsInHorizontalLayout.java index 46d92c3a03..bdabed3032 100644 --- a/tests/testbench/com/vaadin/tests/components/button/ButtonsInHorizontalLayout.java +++ b/tests/testbench/com/vaadin/tests/components/button/ButtonsInHorizontalLayout.java @@ -3,8 +3,8 @@ package com.vaadin.tests.components.button; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; import com.vaadin.ui.themes.BaseTheme; public class ButtonsInHorizontalLayout extends AbstractTestCase { @@ -18,7 +18,7 @@ public class ButtonsInHorizontalLayout extends AbstractTestCase { content.addComponent(createButtonLayout(null)); content.addComponent(createButtonLayout(BaseTheme.BUTTON_LINK)); - setMainWindow(new Window("", content)); + setMainWindow(new LegacyWindow("", content)); } private HorizontalLayout createButtonLayout(String style) { diff --git a/tests/testbench/com/vaadin/tests/components/button/ShortCutListenerModification.java b/tests/testbench/com/vaadin/tests/components/button/ShortCutListenerModification.java index 3d4dfeda04..295c04fc0c 100644 --- a/tests/testbench/com/vaadin/tests/components/button/ShortCutListenerModification.java +++ b/tests/testbench/com/vaadin/tests/components/button/ShortCutListenerModification.java @@ -6,8 +6,9 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.Notification; import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; @SuppressWarnings("serial") public class ShortCutListenerModification extends TestBase implements @@ -60,8 +61,12 @@ public class ShortCutListenerModification extends TestBase implements } public void buttonClick(ClickEvent event) { - Window window2 = event.getButton().getWindow(); - window2.getParent().removeWindow(window2); + Component c = event.getButton(); + while (!(c instanceof Window)) { + c = c.getParent(); + } + ((Window) c).close(); + Button prev = (Button) event.getButton().getData(); if (prev != null) { prev.focus(); diff --git a/tests/testbench/com/vaadin/tests/components/caption/IconsInCaption.java b/tests/testbench/com/vaadin/tests/components/caption/IconsInCaption.java index 926088ff48..428ebdb66b 100644 --- a/tests/testbench/com/vaadin/tests/components/caption/IconsInCaption.java +++ b/tests/testbench/com/vaadin/tests/components/caption/IconsInCaption.java @@ -10,6 +10,7 @@ import com.vaadin.ui.ComboBox; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.Embedded; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.VerticalLayout; public class IconsInCaption extends TestBase { @@ -103,7 +104,7 @@ public class IconsInCaption extends TestBase { ComponentContainer container = containerClass.newInstance(); for (String size : sizes) { Label title = new Label("<h3>" + size + "x" + size + "</h3>", - Label.CONTENT_XHTML); + ContentMode.XHTML); container.addComponent(title); for (String icon : icons) { ThemeResource res = new ThemeResource("../runo/icons/" + size diff --git a/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxNullValue.java b/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxNullValue.java index a961b48426..2c981432c8 100644 --- a/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxNullValue.java +++ b/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxNullValue.java @@ -1,6 +1,7 @@ package com.vaadin.tests.components.checkbox; import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.terminal.AbstractErrorMessage; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; @@ -34,12 +35,14 @@ public class CheckBoxNullValue extends TestBase { try { checkbox.validate(); } catch (InvalidValueException e) { - checkbox.setComponentError(e); + checkbox.setComponentError(AbstractErrorMessage + .getErrorMessageForException(e)); } try { requiredCheckbox.validate(); } catch (InvalidValueException e) { - requiredCheckbox.setComponentError(e); + requiredCheckbox.setComponentError(AbstractErrorMessage + .getErrorMessageForException(e)); } valueLabel.setValue("Checkbox: " + checkbox.getValue() + "; Required checkbox: " + requiredCheckbox.getValue()); diff --git a/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxes2.java b/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxes2.java index 2af1e41867..4f9cd10ecc 100644 --- a/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxes2.java +++ b/tests/testbench/com/vaadin/tests/components/checkbox/CheckBoxes2.java @@ -8,46 +8,15 @@ import com.vaadin.ui.CheckBox; public class CheckBoxes2 extends AbstractFieldTest<CheckBox> implements ClickListener { - // cannot extend Buttons2 because of Switch mode problems - @Override protected Class<CheckBox> getTestClass() { return CheckBox.class; } - private Command<CheckBox, Boolean> switchModeCommand = new Command<CheckBox, Boolean>() { - - @SuppressWarnings("deprecation") - public void execute(CheckBox c, Boolean value, Object data) { - c.setSwitchMode(value); - } - }; - - private Command<CheckBox, Boolean> clickListenerCommand = new Command<CheckBox, Boolean>() { - - public void execute(CheckBox c, Boolean value, Object data) { - if (value) { - c.addListener((ClickListener) CheckBoxes2.this); - } else { - c.removeListener((ClickListener) CheckBoxes2.this); - } - - } - }; - @Override protected void createActions() { super.createActions(); - createBooleanAction("Switch mode", CATEGORY_FEATURES, true, - switchModeCommand); - addClickListener(CATEGORY_LISTENERS); - } - - private void addClickListener(String category) { - createBooleanAction("Click listener", category, false, - clickListenerCommand); - } public void buttonClick(ClickEvent event) { diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java index 8160fb576e..70aad31364 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java @@ -18,13 +18,13 @@ public class ComboBoxInPopup extends TestBase { Button close = new Button("Close window", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - w.getParent().removeWindow(w); + w.close(); } }); close.setClickShortcut(KeyCode.ESCAPE, null); w.addComponent(close); - getLayout().getWindow().addWindow(w); + getLayout().getRoot().addWindow(w); } diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html index a46f48fcfc..fd2aceb7f2 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html @@ -89,7 +89,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td> <td>409,27</td> </tr> <tr> @@ -109,7 +109,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[4]</td> <td>535,43</td> </tr> <tr> @@ -154,7 +154,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[6]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[6]/domChild[0]</td> <td>510,1</td> </tr> </tbody></table> diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxReapperingOldValue.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxReapperingOldValue.java index 0e295231c5..c78ff7675f 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxReapperingOldValue.java +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxReapperingOldValue.java @@ -8,19 +8,19 @@ import com.vaadin.data.util.IndexedContainer; import com.vaadin.ui.AbstractSelect; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; @SuppressWarnings("serial") -public class ComboBoxReapperingOldValue extends Application implements - ValueChangeListener { +public class ComboBoxReapperingOldValue extends Application.LegacyApplication + implements ValueChangeListener { ComboBox cbox1 = new ComboBox(); ComboBox cbox2 = new ComboBox(); @Override public void init() { - Window mainWindow = new Window("ComboBoxCacheTest"); + LegacyWindow mainWindow = new LegacyWindow("ComboBoxCacheTest"); setMainWindow(mainWindow); VerticalLayout layout = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSuggestionOnDetach.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSuggestionOnDetach.java index 134e13e49c..09354fdacf 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSuggestionOnDetach.java +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSuggestionOnDetach.java @@ -17,7 +17,7 @@ public class ComboBoxSuggestionOnDetach extends TestBase { "Option 2", "Option 3")); comboBox.addListener(new FieldEvents.FocusListener() { public void focus(FocusEvent event) { - popup.getParent().removeWindow(popup); + popup.close(); } }); popup.addComponent(comboBox); diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxTextFieldEventOrder.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxTextFieldEventOrder.java index d92a1872b8..6f6e550ab4 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxTextFieldEventOrder.java +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxTextFieldEventOrder.java @@ -1,4 +1,5 @@ package com.vaadin.tests.components.combobox; + import java.util.Arrays; import com.vaadin.data.Property.ValueChangeEvent; diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboFocusBlurEvents.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboFocusBlurEvents.java index 6681342ea6..027cf5fd24 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/ComboFocusBlurEvents.java +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboFocusBlurEvents.java @@ -10,6 +10,7 @@ import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.TextField; public class ComboFocusBlurEvents extends TestBase { @@ -18,18 +19,18 @@ public class ComboFocusBlurEvents extends TestBase { @Override protected void setup() { - + List<String> list = new ArrayList<String>(); for (int i = 0; i < 100; i++) { list.add("Item " + i); } - + ComboBox cb = new ComboBox("Combobox", list); cb.setImmediate(true); cb.setInputPrompt("Enter text"); cb.setDescription("Some Combobox"); addComponent(cb); - + final ObjectProperty<String> log = new ObjectProperty<String>(""); cb.addListener(new FieldEvents.FocusListener() { @@ -47,7 +48,7 @@ public class ComboFocusBlurEvents extends TestBase { counter++; } }); - + TextField field = new TextField("Some textfield"); field.setImmediate(true); addComponent(field); @@ -55,7 +56,7 @@ public class ComboFocusBlurEvents extends TestBase { Label output = new Label(log); output.setCaption("Events:"); - output.setContentMode(Label.CONTENT_XHTML); + output.setContentMode(ContentMode.XHTML); addComponent(output); } diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/ClipContent.java b/tests/testbench/com/vaadin/tests/components/customcomponent/ClipContent.java index 8bc464f176..7ba26e54a9 100644 --- a/tests/testbench/com/vaadin/tests/components/customcomponent/ClipContent.java +++ b/tests/testbench/com/vaadin/tests/components/customcomponent/ClipContent.java @@ -5,6 +5,7 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.TextField; public class ClipContent extends TestBase { @@ -14,7 +15,7 @@ public class ClipContent extends TestBase { Label text = new Label( "1_long_line_that_should_be_clipped<br/>2_long_line_that_should_be_clipped<br/>3_long_line_that_should_be_clipped<br/>4_long_line_that_should_be_clipped<br/>", - Label.CONTENT_XHTML); + ContentMode.XHTML); final CustomComponent cc = new CustomComponent(text); cc.setWidth("20px"); @@ -24,7 +25,7 @@ public class ClipContent extends TestBase { w.setValue("20px"); w.addListener(new TextField.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - cc.setWidth((String) w.getValue()); + cc.setWidth(w.getValue()); } }); addComponent(w); @@ -32,7 +33,7 @@ public class ClipContent extends TestBase { h.setValue("20px"); h.addListener(new TextField.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - cc.setHeight((String) h.getValue()); + cc.setHeight(h.getValue()); } }); addComponent(h); diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html new file mode 100644 index 0000000000..b2806afe5c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.html @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head profile="http://selenium-ide.openqa.org/profiles/test-case"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="selenium.base" href="" /><title>com.vaadin.tests.components.accordion.AccordionInactiveTabSize</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">com.vaadin.tests.components.accordion.AccordionInactiveTabSize</td></tr></thead><tbody><tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.customcomponent.CustomLayoutUsingTemplate?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomcomponentCustomLayoutUsingTemplate::/VVerticalLayout[0]/VVerticalLayout[0]/VCustomLayout[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>with-text-field</td> +</tr> +</tbody></table></body></html>
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.java b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.java new file mode 100644 index 0000000000..2dc3063b0c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTemplate.java @@ -0,0 +1,60 @@ +package com.vaadin.tests.components.customcomponent; + +import java.io.IOException; +import java.io.InputStream; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.TextField; + +public class CustomLayoutUsingTemplate extends TestBase implements + ClickListener { + + CustomLayout layout; + + @Override + protected void setup() { + String thisPackage = CustomLayoutUsingTemplate.class.getName().replace( + '.', '/'); + thisPackage = thisPackage.replaceAll( + CustomLayoutUsingTemplate.class.getSimpleName() + "$", ""); + String template = thisPackage + "template.htm"; + InputStream is = getClass().getClassLoader().getResourceAsStream( + template); + try { + layout = new CustomLayout(is); + layout.addComponent(new Button( + "Click to add a TextField to second location", this), + "location1"); + addComponent(layout); + } catch (IOException e) { + addComponent(new Label(e.getMessage())); + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + @Override + protected String getDescription() { + return "Test for using a CustomLayout with a template read from an input stream and passed through the state"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + + public void buttonClick(ClickEvent event) { + layout.addComponent(new TextField("A text field!"), "location2"); + } +} diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html new file mode 100644 index 0000000000..954afb2adb --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.html @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head profile="http://selenium-ide.openqa.org/profiles/test-case"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="selenium.base" href="" /><title>com.vaadin.tests.components.accordion.AccordionInactiveTabSize</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">com.vaadin.tests.components.accordion.AccordionInactiveTabSize</td></tr></thead><tbody><tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.customcomponent.CustomLayoutUsingTheme?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomcomponentCustomLayoutUsingTheme::/VVerticalLayout[0]/VVerticalLayout[0]/VCustomLayout[0]/VVerticalLayout[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>label</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomcomponentCustomLayoutUsingTheme::/VVerticalLayout[0]/VVerticalLayout[0]/VCustomLayout[0]/VVerticalLayout[0]/VButton[1]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>button</td> +</tr> +</tbody></table></body></html>
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java new file mode 100644 index 0000000000..6ea1d0a0c5 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customcomponent/CustomLayoutUsingTheme.java @@ -0,0 +1,60 @@ +package com.vaadin.tests.components.customcomponent; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.LoremIpsum; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.NativeButton; +import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; + +public class CustomLayoutUsingTheme extends TestBase implements ClickListener { + + private CustomLayout layout; + + @Override + protected void setup() { + setTheme("tests-tickets"); + layout = new CustomLayout("Ticket1775"); + addComponent(layout); + layout.addComponent(new TextField("Username"), "loginUser"); + layout.addComponent(new TextField("Password"), "loginPassword"); + layout.addComponent(new Button("Login"), "loginButton"); + layout.setWidth(null); + + VerticalLayout menu = new VerticalLayout(); + menu.addComponent(new Button("Set body to label", new ClickListener() { + + public void buttonClick(ClickEvent event) { + layout.addComponent(new Label(LoremIpsum.get(200)), "body"); + } + })); + menu.addComponent(new Button("Set body to huge NativeButton", + new ClickListener() { + + public void buttonClick(ClickEvent event) { + layout.addComponent(new NativeButton( + "This is it, the body!"), "body"); + } + })); + layout.addComponent(menu, "menu"); + } + + @Override + protected String getDescription() { + return "Test for using a CustomLayout with a template read from an input stream and passed through the state"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + + public void buttonClick(ClickEvent event) { + layout.addComponent(new TextField("A text field!"), "location2"); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/customcomponent/template.htm b/tests/testbench/com/vaadin/tests/components/customcomponent/template.htm new file mode 100644 index 0000000000..fa023050da --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customcomponent/template.htm @@ -0,0 +1,4 @@ +<b>Contents</b> +<div location="location1">This is where the first component goes</div> +<div style="width: 500px; border: 1 px solid blue; margin: 10px;" location="location2">This is where the second component goes</div> +<b>End of template</b>
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/customfield/AbstractNestedFormExample.java b/tests/testbench/com/vaadin/tests/components/customfield/AbstractNestedFormExample.java new file mode 100644 index 0000000000..c15ca1916a --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/AbstractNestedFormExample.java @@ -0,0 +1,75 @@ +package com.vaadin.tests.components.customfield; + +import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Person; +import com.vaadin.ui.Table; + +/** + * Demonstrate the use of a form as a custom field within another form. + */ +public abstract class AbstractNestedFormExample extends TestBase { + private NestedPersonForm personForm; + private boolean embeddedAddress; + + public void setup(boolean embeddedAddress) { + this.embeddedAddress = embeddedAddress; + + addComponent(getPersonTable()); + } + + /** + * Creates a table with two person objects + */ + public Table getPersonTable() { + Table table = new Table(); + table.setPageLength(5); + table.setSelectable(true); + table.setImmediate(true); + table.setNullSelectionAllowed(true); + table.addContainerProperty("Name", String.class, null); + table.addListener(getTableValueChangeListener()); + Person person = new Person("Teppo", "Testaaja", + "teppo.testaaja@example.com", "", "Ruukinkatu 2–4", 20540, + "Turku"); + Person person2 = new Person("Taina", "Testaaja", + "taina.testaaja@example.com", "", "Ruukinkatu 2–4", 20540, + "Turku"); + Item item = table.addItem(person); + item.getItemProperty("Name").setValue( + person.getFirstName() + " " + person.getLastName()); + item = table.addItem(person2); + item.getItemProperty("Name").setValue( + person2.getFirstName() + " " + person2.getLastName()); + return table; + } + + /** + * Creates value change listener for the table + */ + private Property.ValueChangeListener getTableValueChangeListener() { + return new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + if (personForm != null) { + removeComponent(personForm); + } + if (event.getProperty().getValue() != null) { + personForm = new NestedPersonForm((Person) event + .getProperty().getValue(), embeddedAddress); + personForm.setWidth("350px"); + addComponent(personForm); + } + } + + }; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/customfield/AddressField.java b/tests/testbench/com/vaadin/tests/components/customfield/AddressField.java new file mode 100644 index 0000000000..a3ee89b3ee --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/AddressField.java @@ -0,0 +1,97 @@ +package com.vaadin.tests.components.customfield; + +import java.util.Arrays; +import java.util.List; + +import com.vaadin.data.Buffered; +import com.vaadin.data.Validator.InvalidValueException; +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.util.Address; +import com.vaadin.ui.Component; +import com.vaadin.ui.CustomField; +import com.vaadin.ui.Form; + +/** + * Nested form for the Address object of the Person object + */ +public class AddressField extends CustomField<Address> { + private Form addressForm; + private final Form parentForm; + + public AddressField() { + this(null); + } + + public AddressField(Form parentForm) { + this.parentForm = parentForm; + } + + @Override + protected Component initContent() { + if (parentForm != null) { + addressForm = new EmbeddedForm(parentForm); + } else { + addressForm = new Form(); + } + addressForm.setCaption("Address"); + addressForm.setWriteThrough(false); + + // make sure field changes are sent early + addressForm.setImmediate(true); + + return addressForm; + } + + @Override + protected Form getContent() { + return (Form) super.getContent(); + } + + @Override + public void setInternalValue(Address address) throws ReadOnlyException { + // create the address if not given + if (null == address) { + address = new Address(); + } + + super.setInternalValue(address); + + // set item data source and visible properties in a single operation to + // avoid creating fields multiple times + List<String> visibleProperties = Arrays.asList("streetAddress", + "postalCode", "city"); + getContent().setItemDataSource(new BeanItem<Address>(address), + visibleProperties); + } + + /** + * commit changes of the address form + */ + @Override + public void commit() throws Buffered.SourceException, InvalidValueException { + addressForm.commit(); + super.commit(); + } + + /** + * discard changes of the address form + */ + @Override + public void discard() throws Buffered.SourceException { + // Do not discard the top-level value + // super.discard(); + addressForm.discard(); + } + + @Override + public boolean isReadOnly() { + // In this application, the address is modified implicitly by + // addressForm.commit(), not by setting the Address object for a Person. + return false; + } + + @Override + public Class<Address> getType() { + return Address.class; + } +}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/customfield/AddressFormExample.java b/tests/testbench/com/vaadin/tests/components/customfield/AddressFormExample.java new file mode 100644 index 0000000000..55e61e3980 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/AddressFormExample.java @@ -0,0 +1,45 @@ +package com.vaadin.tests.components.customfield; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Address; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; + +/** + * Demonstrate a custom field which is a form, and contains another custom field + * for the selection of a city. + */ +public class AddressFormExample extends TestBase { + + @Override + protected void setup() { + Address address = new Address("Ruukinkatu 2-4", 20540, "Turku"); + final AddressField field = new AddressField(); + field.setValue(address); + + addComponent(field); + + Button commitButton = new Button("Save", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + field.commit(); + Address address = field.getValue(); + field.getRoot().showNotification( + "Address saved: " + address.getStreetAddress() + ", " + + address.getPostalCode() + ", " + + address.getCity()); + } + }); + addComponent(commitButton); + } + + @Override + protected String getDescription() { + return "Custom field for editing an Address"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/customfield/BooleanField.java b/tests/testbench/com/vaadin/tests/components/customfield/BooleanField.java new file mode 100644 index 0000000000..dc60d7e517 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/BooleanField.java @@ -0,0 +1,45 @@ +package com.vaadin.tests.components.customfield; + +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.CustomField; +import com.vaadin.ui.Label; +import com.vaadin.ui.VerticalLayout; + +/** + * An example of a custom field for editing a boolean value. The field is + * composed of multiple components, and could also edit a more complex data + * structures. Here, the commit etc. logic is not overridden. + */ +public class BooleanField extends CustomField { + + @Override + protected Component initContent() { + VerticalLayout layout = new VerticalLayout(); + + layout.addComponent(new Label("Please click the button")); + + final Button button = new Button("Click me"); + button.addListener(new ClickListener() { + public void buttonClick(ClickEvent event) { + Object value = getValue(); + boolean newValue = true; + if ((value instanceof Boolean) && ((Boolean) value)) { + newValue = false; + } + setValue(newValue); + button.setCaption(newValue ? "On" : "Off"); + } + }); + layout.addComponent(button); + + return layout; + } + + @Override + public Class<?> getType() { + return Boolean.class; + } +}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/customfield/BooleanFieldExample.html b/tests/testbench/com/vaadin/tests/components/customfield/BooleanFieldExample.html new file mode 100644 index 0000000000..6b1b3e8a2d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/BooleanFieldExample.html @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>BooleanFieldExample</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">BooleanFieldExample</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.customfield.BooleanFieldExample?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldBooleanFieldExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>on</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldBooleanFieldExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>off</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/customfield/BooleanFieldExample.java b/tests/testbench/com/vaadin/tests/components/customfield/BooleanFieldExample.java new file mode 100644 index 0000000000..2f9720a1c1 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/BooleanFieldExample.java @@ -0,0 +1,89 @@ +package com.vaadin.tests.components.customfield; + +import com.vaadin.data.Item; +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.DefaultFieldFactory; +import com.vaadin.ui.Field; +import com.vaadin.ui.Form; +import com.vaadin.ui.VerticalLayout; + +public class BooleanFieldExample extends TestBase { + + /** + * Data model class with two boolean fields. + */ + public static class TwoBooleans { + private boolean normal; + private boolean custom; + + public void setNormal(boolean normal) { + this.normal = normal; + } + + public boolean isNormal() { + return normal; + } + + public void setCustom(boolean custom) { + this.custom = custom; + } + + public boolean isCustom() { + return custom; + } + } + + @Override + protected void setup() { + final VerticalLayout layout = new VerticalLayout(); + layout.setMargin(true); + + final Form form = new Form(); + form.setFormFieldFactory(new DefaultFieldFactory() { + @Override + public Field createField(Item item, Object propertyId, + Component uiContext) { + if ("custom".equals(propertyId)) { + return new BooleanField(); + } + return super.createField(item, propertyId, uiContext); + } + }); + final TwoBooleans data = new TwoBooleans(); + form.setItemDataSource(new BeanItem<TwoBooleans>(data)); + + layout.addComponent(form); + + Button submit = new Button("Submit", new ClickListener() { + public void buttonClick(ClickEvent event) { + form.commit(); + layout.getRoot() + .showNotification( + "The custom boolean field value is " + + data.isCustom() + + ".<br>" + + "The checkbox (default boolean field) value is " + + data.isNormal() + "."); + } + }); + layout.addComponent(submit); + + addComponent(layout); + } + + @Override + protected String getDescription() { + return "A customized field (a two-state button) for editing a boolean value."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedForm.java b/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedForm.java new file mode 100644 index 0000000000..d305afde1d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedForm.java @@ -0,0 +1,67 @@ +package com.vaadin.tests.components.customfield; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Field; +import com.vaadin.ui.Form; +import com.vaadin.ui.Layout; + +/** + * Form that displays its fields in the layout of another form. + * + * The fields are still logically part of this form even though they are in the + * layout of the parent form. The embedded form itself is automatically hidden. + * + * TODO Known issue: any field factory creating an {@link EmbeddedForm} + * (directly or indirectly) should re-use the field once it has been created to + * avoid the creation of duplicate fields when e.g. setting the visible item + * properties. + */ +public class EmbeddedForm extends Form { + private Form parentForm; + private Map<Object, Field> fields = new HashMap<Object, Field>(); + + /** + * Create a form that places its fields in another {@link Form}. + * + * @param parentForm + * form to which to embed the fields, not null + */ + public EmbeddedForm(Form parentForm) { + this.parentForm = parentForm; + setVisible(false); + } + + @Override + protected void attachField(Object propertyId, Field field) { + if (propertyId == null || field == null) { + return; + } + + Layout layout = parentForm.getLayout(); + + Field oldField = fields.get(propertyId); + if (oldField != null) { + layout.removeComponent(oldField); + } + + fields.put(propertyId, field); + + if (layout instanceof CustomLayout) { + ((CustomLayout) layout).addComponent(field, propertyId.toString()); + } else { + layout.addComponent(field); + } + } + + @Override + public boolean removeItemProperty(Object id) { + // remove the field from the parent layout if already added there + parentForm.getLayout().removeComponent(fields.get(id)); + fields.remove(id); + + return super.removeItemProperty(id); + } +}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedFormExample.html b/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedFormExample.html new file mode 100644 index 0000000000..2af441bc83 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedFormExample.html @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="http://localhost:8888/" /> +<title>EmbeddedFormExample</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">EmbeddedFormExample</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.customfield.EmbeddedFormExample?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>66,10</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[4]</td> + <td>Turkuaa</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[4]</td> + <td>Turku</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[4]</td> + <td>Helsinki</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[4]</td> + <td>Helsinki</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>52,15</td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[4]</td> + <td>Turku</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>56,10</td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldEmbeddedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[4]</td> + <td>Helsinki</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedFormExample.java b/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedFormExample.java new file mode 100644 index 0000000000..aeb1984937 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/EmbeddedFormExample.java @@ -0,0 +1,17 @@ +package com.vaadin.tests.components.customfield; + +public class EmbeddedFormExample extends AbstractNestedFormExample { + + @Override + protected void setup() { + super.setup(true); + } + + @Override + protected String getDescription() { + return "An address form embedded in a person form.\n" + + "The address fields are placed in the layout of the parent (person) form.\n" + + "Note that in many cases the same result can be achieved with a property that maps subfields to the top level."; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/customfield/NestedFormExample.html b/tests/testbench/com/vaadin/tests/components/customfield/NestedFormExample.html new file mode 100644 index 0000000000..f9f5783c05 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/NestedFormExample.html @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>NestedFormExample</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">NestedFormExample</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.customfield.NestedFormExample?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>33,9</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[2]</td> + <td>Turkuaa</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[2]</td> + <td>Turku</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[2]</td> + <td>Helsinki</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[2]</td> + <td>Helsinki</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>56,14</td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[2]</td> + <td>Turku</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>30,9</td> +</tr> +<tr> + <td>verifyValue</td> + <td>vaadin=runcomvaadintestscomponentscustomfieldNestedFormExample::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCustomComponent[0]/VForm[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[2]</td> + <td>Helsinki</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/customfield/NestedFormExample.java b/tests/testbench/com/vaadin/tests/components/customfield/NestedFormExample.java new file mode 100644 index 0000000000..91fb43f4e2 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/NestedFormExample.java @@ -0,0 +1,15 @@ +package com.vaadin.tests.components.customfield; + +public class NestedFormExample extends AbstractNestedFormExample { + + @Override + protected void setup() { + super.setup(false); + } + + @Override + protected String getDescription() { + return "An address form nested in a person form."; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/customfield/NestedPersonForm.java b/tests/testbench/com/vaadin/tests/components/customfield/NestedPersonForm.java new file mode 100644 index 0000000000..e0a3b08bc7 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/customfield/NestedPersonForm.java @@ -0,0 +1,94 @@ +package com.vaadin.tests.components.customfield; + +import java.util.Arrays; + +import com.vaadin.data.Item; +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.util.Person; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Component; +import com.vaadin.ui.DefaultFieldFactory; +import com.vaadin.ui.Field; +import com.vaadin.ui.Form; +import com.vaadin.ui.HorizontalLayout; + +/** + * Example of nested forms + */ +public class NestedPersonForm extends Form { + private BeanItem<Person> beanItem; + private final boolean embeddedAddress; + + /** + * Creates a person form which contains nested form for the persons address + */ + public NestedPersonForm(Person person, boolean embeddedAddress) { + this.embeddedAddress = embeddedAddress; + + beanItem = new BeanItem<Person>(person); + setCaption("Update person details"); + setWriteThrough(false); + setFormFieldFactory(new PersonFieldFactory()); + // set the data source and the visible fields + // Note that if the nested form is the first or last field in the parent + // form, styles from the parent (padding, ...) may leak to its contents. + setItemDataSource(beanItem, Arrays.asList("firstName", "lastName", + "address", "email", "phoneNumber")); + getFooter().addComponent(getButtonsLayout()); + getFooter().setMargin(false, false, true, true); + } + + /** + * Get apply and discard button in the layout + */ + private Component getButtonsLayout() { + HorizontalLayout buttons = new HorizontalLayout(); + buttons.setSpacing(true); + Button discardChanges = new Button("Discard changes", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + NestedPersonForm.this.discard(); + } + }); + buttons.addComponent(discardChanges); + buttons.setComponentAlignment(discardChanges, Alignment.MIDDLE_LEFT); + + Button apply = new Button("Apply", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + try { + NestedPersonForm.this.commit(); + } catch (Exception e) { + // Ignored, we'll let the Form handle the errors + } + } + }); + buttons.addComponent(apply); + return buttons; + } + + /** + * Field factory for person form + */ + private class PersonFieldFactory extends DefaultFieldFactory { + // reuse the address field - required by EmbeddedForm + private AddressField addressField; + + @Override + public Field createField(Item item, Object propertyId, + Component uiContext) { + Field f = super.createField(item, propertyId, uiContext); + if ("address".equals(propertyId)) { + // create a custom field for the Address object + if (addressField == null) { + Form form = (embeddedAddress && uiContext instanceof Form) ? (Form) uiContext + : null; + addressField = new AddressField(form); + } + f = addressField; + } + return f; + } + } +} diff --git a/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.html b/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.html index 29ad93c6c6..8420888098 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.html @@ -45,12 +45,12 @@ <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentsdatefieldCommitInvalid::PID_SLog_row_2</td> - <td>4. Commit failed : Not an integer</td> + <td>4. Commit failed : Could not convert value to Integer</td> </tr> <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentsdatefieldCommitInvalid::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VForm[0]/domChild[0]/domChild[2]/domChild[0]</td> - <td>Not an integer</td> + <td>Could not convert value to Integer</td> </tr> <tr> <td>assertText</td> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.java b/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.java index 36ee068af4..1395b4d735 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/CommitInvalid.java @@ -6,7 +6,6 @@ import java.util.Locale; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.util.ObjectProperty; -import com.vaadin.data.validator.IntegerValidator; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; import com.vaadin.ui.Button; @@ -64,7 +63,6 @@ public class CommitInvalid extends TestBase { */ integerProperty = new ObjectProperty<Integer>(42); integerField = new TextField("Another Field", integerProperty); - integerField.addValidator(new IntegerValidator("Not an integer")); integerField.setDebugId("_IF"); form.addField("text", integerField); diff --git a/tests/testbench/com/vaadin/tests/components/datefield/CustomDateFormats.html b/tests/testbench/com/vaadin/tests/components/datefield/CustomDateFormats.html index 61ff29d1c5..1acdded4cb 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/CustomDateFormats.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/CustomDateFormats.html @@ -161,12 +161,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[11]</td> <td>10 maalis 1999</td> </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[14]</td> <td>26 syyskuu 1980</td> </tr> <tr> @@ -211,7 +211,7 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[43]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[35]</td> <td>10. tammikuuta 2011</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.html b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.html index 751c7ba9bd..f387695b5f 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.html @@ -98,7 +98,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldEmptyValid::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldEmptyValid::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[2]</td> <td>208,5</td> </tr> <tr> @@ -128,7 +128,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldEmptyValid::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldEmptyValid::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[2]</td> <td>186,10</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.java index 440f004531..37fb09ab29 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldEmptyValid.java @@ -14,6 +14,7 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.DateField; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.PopupDateField; @SuppressWarnings("serial") @@ -36,7 +37,7 @@ public class DateFieldEmptyValid extends TestBase { @Override protected void setup() { - addComponent(new Label("<br/><br/>", Label.CONTENT_XHTML)); + addComponent(new Label("<br/><br/>", ContentMode.XHTML)); log = new Log(8); addComponent(log); df = new MyDateField(); diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldInSubWindow.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldInSubWindow.java index 18bc719850..298359068e 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldInSubWindow.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldInSubWindow.java @@ -13,6 +13,7 @@ import com.vaadin.ui.DefaultFieldFactory; import com.vaadin.ui.Field; import com.vaadin.ui.Form; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; @@ -59,9 +60,9 @@ public class DateFieldInSubWindow extends AbstractTestCase { public static final String COMMON_FIELD_WIDTH = "12em"; @Override - public Field createField(Item item, Object propertyId, + public Field<?> createField(Item item, Object propertyId, Component uiContext) { - Field f = super.createField(item, propertyId, uiContext); + Field<?> f = super.createField(item, propertyId, uiContext); if ("myDate".equals(propertyId)) { ((DateField) f).setResolution(DateField.RESOLUTION_MIN); @@ -106,7 +107,7 @@ public class DateFieldInSubWindow extends AbstractTestCase { Button b = new Button("Close", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - (getParent()).removeWindow(TestCaseWindow.this); + TestCaseWindow.this.close(); } }); buttons.addComponent(b); @@ -118,7 +119,7 @@ public class DateFieldInSubWindow extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window(); + LegacyWindow mainWindow = new LegacyWindow(); setMainWindow(mainWindow); Button open = new Button("Open window", new Button.ClickListener() { public void buttonClick(ClickEvent event) { diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldPopupOffScreen.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldPopupOffScreen.java index 3521e8b95e..b87c458c01 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldPopupOffScreen.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldPopupOffScreen.java @@ -6,8 +6,9 @@ import java.util.Locale; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Alignment; import com.vaadin.ui.DateField; +import com.vaadin.ui.DateField.Resolution; import com.vaadin.ui.GridLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; public class DateFieldPopupOffScreen extends AbstractTestCase { @@ -23,7 +24,7 @@ public class DateFieldPopupOffScreen extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window(getClass().getName()); + LegacyWindow mainWindow = new LegacyWindow(getClass().getName()); GridLayout mainLayout = new GridLayout(3, 3); mainLayout.setSizeFull(); @@ -57,7 +58,7 @@ public class DateFieldPopupOffScreen extends AbstractTestCase { private DateField createDateField() { DateField df = new DateField(); df.setLocale(new Locale("fi")); - df.setResolution(DateField.RESOLUTION_SEC); + df.setResolution(Resolution.SECOND); df.setDescription("This is a long, multiline tooltip.<br/>It should always be on screen so it can be read."); df.setValue(new Date(1000000L)); return df; diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.html b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.html new file mode 100644 index 0000000000..444f8e3bac --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.html @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="http://localhost:8888/" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.datefield.DateFieldRangeValidation?restartApplication</td> + <td></td> +</tr> +<!--select 15.12.2011--> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#popupButton</td> + <td>11,17</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::Root/VOverlay[0]/VCalendarPanel[0]#day15</td> + <td>7,5</td> +</tr> +<!--should not be error--> +<tr> + <td>assertElementNotPresent</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[4]/domChild[1]</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VCheckBox[0]/domChild[0]</td> + <td>26,6</td> +</tr> +<!--should be error--> +<tr> + <td>assertElementPresent</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[4]/domChild[1]</td> + <td></td> +</tr> +<!--select 3.12.2011--> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#popupButton</td> + <td>13,17</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::Root/VOverlay[0]/VCalendarPanel[0]#day3</td> + <td>13,13</td> +</tr> +<!--should be error--> +<tr> + <td>assertElementPresent</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[4]/domChild[1]</td> + <td></td> +</tr> +<!--change to 4.12.2011 by writing--> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#field</td> + <td>52,6</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VPopupCalendar[0]#field</td> + <td>12/4/11</td> +</tr> +<!--should not be error--> +<tr> + <td>assertElementNotPresent</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[4]/domChild[1]</td> + <td></td> +</tr> +<!--no longer include start date--> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VCheckBox[0]/domChild[0]</td> + <td>6,8</td> +</tr> +<!--should be error--> +<tr> + <td>assertElementPresent</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRangeValidation::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[4]/domChild[1]</td> + <td></td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.java new file mode 100644 index 0000000000..bf93d8c8b9 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldRangeValidation.java @@ -0,0 +1,144 @@ +package com.vaadin.tests.components.datefield; + +import java.util.Date; +import java.util.Locale; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.BeanItem; +import com.vaadin.data.validator.RangeValidator; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.DateField.Resolution; +import com.vaadin.ui.PopupDateField; + +public class DateFieldRangeValidation extends TestBase { + + public class Range { + private Date from, to; + private boolean fromInclusive = true; + private boolean toInclusive = true; + + public boolean isFromInclusive() { + return fromInclusive; + } + + public void setFromInclusive(boolean fromInclusive) { + this.fromInclusive = fromInclusive; + } + + public boolean isToInclusive() { + return toInclusive; + } + + public void setToInclusive(boolean toInclusive) { + this.toInclusive = toInclusive; + } + + public Date getFrom() { + return from; + } + + public void setFrom(Date from) { + this.from = from; + } + + public Date getTo() { + return to; + } + + public void setTo(Date to) { + this.to = to; + } + + } + + private Range range = new Range(); + private ValueChangeListener refreshField = new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + actualDateField.requestRepaint(); + } + }; + + private PopupDateField actualDateField; + + @Override + protected void setup() { + BeanItem<Range> bi = new BeanItem<Range>(range); + range.setFrom(new Date(2011 - 1900, 12 - 1, 4)); + range.setTo(new Date(2011 - 1900, 12 - 1, 15)); + + PopupDateField fromField = createDateField(); + fromField.setPropertyDataSource(bi.getItemProperty("from")); + CheckBox fromInclusive = new CheckBox("From inclusive", + bi.getItemProperty("fromInclusive")); + CheckBox toInclusive = new CheckBox("To inclusive", + bi.getItemProperty("toInclusive")); + fromInclusive.setImmediate(true); + fromInclusive.addListener(refreshField); + toInclusive.setImmediate(true); + toInclusive.addListener(refreshField); + + PopupDateField toField = createDateField(); + toField.setPropertyDataSource(bi.getItemProperty("to")); + + actualDateField = createDateField(); + actualDateField.setValue(new Date(2011 - 1900, 12 - 1, 1)); + actualDateField.addValidator(new RangeValidator<Date>("", Date.class, + null, null) { + @Override + public boolean isMinValueIncluded() { + return range.isFromInclusive(); + } + + @Override + public boolean isMaxValueIncluded() { + return range.isToInclusive(); + } + + @Override + public Date getMaxValue() { + return range.getTo(); + } + + @Override + public Date getMinValue() { + return range.getFrom(); + } + + @Override + public String getErrorMessage() { + return "Date must be in range " + getMinValue() + " - " + + getMaxValue(); + } + }); + addComponent(fromField); + addComponent(fromInclusive); + addComponent(toField); + addComponent(toInclusive); + addComponent(actualDateField); + } + + private PopupDateField createDateField() { + PopupDateField df = new PopupDateField(); + df.setLocale(new Locale("en", "US")); + df.setResolution(Resolution.DAY); + df.setWriteThrough(true); + df.setReadThrough(true); + df.setImmediate(true); + return df; + } + + @Override + protected String getDescription() { + return "Tests the DateField range validator. The first field sets the minimum date, the second the maximum. Checkboxes control if the selected date is ok or not."; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTest.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTest.java index 7d1bdfc2c8..e8c8b69f9f 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTest.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTest.java @@ -9,9 +9,11 @@ import java.util.Locale; import com.vaadin.tests.components.abstractfield.AbstractFieldTest; import com.vaadin.ui.DateField; +import com.vaadin.ui.DateField.Resolution; public class DateFieldTest<T extends DateField> extends AbstractFieldTest<T> { + @SuppressWarnings("unchecked") @Override protected Class<T> getTestClass() { return (Class<T>) DateField.class; @@ -93,22 +95,21 @@ public class DateFieldTest<T extends DateField> extends AbstractFieldTest<T> { } private void createResolutionSelectAction(String category) { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Year", DateField.RESOLUTION_YEAR); - options.put("Month", DateField.RESOLUTION_MONTH); - options.put("Day", DateField.RESOLUTION_DAY); - options.put("Hour", DateField.RESOLUTION_HOUR); - options.put("Min", DateField.RESOLUTION_MIN); - options.put("Sec", DateField.RESOLUTION_SEC); - options.put("Msec", DateField.RESOLUTION_MSEC); + LinkedHashMap<String, Resolution> options = new LinkedHashMap<String, Resolution>(); + options.put("Year", DateField.Resolution.YEAR); + options.put("Month", DateField.Resolution.MONTH); + options.put("Day", DateField.Resolution.DAY); + options.put("Hour", DateField.Resolution.HOUR); + options.put("Min", DateField.Resolution.MINUTE); + options.put("Sec", DateField.Resolution.SECOND); createSelectAction("Resolution", category, options, "Year", resolutionCommand); } - private Command<T, Integer> resolutionCommand = new Command<T, Integer>() { + private Command<T, Resolution> resolutionCommand = new Command<T, Resolution>() { - public void execute(T c, Integer value, Object data) { + public void execute(T c, Resolution value, Object data) { c.setResolution(value); } diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html index 2a67b16170..be325ef2eb 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html @@ -39,12 +39,12 @@ <tr> <td>assertValue</td> <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldTimezone::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VPopupCalendar[0]#field</td> - <td>1/1/10 02:00:00.000 AM</td> + <td>1/1/10 02:00:00 AM</td> </tr> <tr> <td>type</td> <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldTimezone::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VPopupCalendar[0]#field</td> - <td>1/1/10 01:00:00.000 AM</td> + <td>1/1/10 01:00:00 AM</td> </tr> <tr> <td>assertText</td> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.java index 6562e5412e..340b647931 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.java @@ -14,6 +14,7 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; import com.vaadin.ui.ComboBox; import com.vaadin.ui.DateField; +import com.vaadin.ui.DateField.Resolution; public class DateFieldTimezone extends TestBase { @@ -25,6 +26,8 @@ public class DateFieldTimezone extends TestBase { @Override protected void setup() { + dateField.setResolution(Resolution.SECOND); + ArrayList<String> timeZoneCodes = new ArrayList<String>(); timeZoneCodes.add(nullValue); timeZoneCodes.addAll(Arrays.asList(TimeZone.getAvailableIDs())); @@ -73,7 +76,7 @@ public class DateFieldTimezone extends TestBase { dateField.setLocale(EN); dateField.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - Date date = (Date) dateField.getValue(); + Date date = dateField.getValue(); DateFormat format = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.LONG, EN); format.setTimeZone(UTC); diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldUnparsableDate.java b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldUnparsableDate.java index 4f83575b39..9b4a3c3383 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldUnparsableDate.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldUnparsableDate.java @@ -3,6 +3,7 @@ package com.vaadin.tests.components.datefield; import java.util.Date; import com.vaadin.data.Property; +import com.vaadin.data.util.converter.Converter; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.DateField; @@ -16,14 +17,14 @@ public class DateFieldUnparsableDate extends TestBase { addListener(new Property.ValueChangeListener() { public void valueChange( com.vaadin.data.Property.ValueChangeEvent event) { - oldDate = (Date) getValue(); + oldDate = getValue(); } }); } @Override protected Date handleUnparsableDateString(String dateString) - throws ConversionException { + throws Converter.ConversionException { return oldDate; } } @@ -35,7 +36,7 @@ public class DateFieldUnparsableDate extends TestBase { @Override protected Date handleUnparsableDateString(String dateString) - throws ConversionException { + throws Converter.ConversionException { return null; } } @@ -47,8 +48,9 @@ public class DateFieldUnparsableDate extends TestBase { @Override protected Date handleUnparsableDateString(String dateString) - throws ConversionException { - throw new ConversionException("You should not enter invalid dates!"); + throws Converter.ConversionException { + throw new Converter.ConversionException( + "You should not enter invalid dates!"); } } @@ -59,11 +61,12 @@ public class DateFieldUnparsableDate extends TestBase { @Override protected Date handleUnparsableDateString(String dateString) - throws ConversionException { + throws Converter.ConversionException { if (dateString != null && dateString.equals("today")) { return new Date(); } - throw new ConversionException("You should not enter invalid dates!"); + throw new Converter.ConversionException( + "You should not enter invalid dates!"); } } diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java b/tests/testbench/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java index bcdc8260b0..060c7fcc0a 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/DefaultHandleUnparsableDateField.java @@ -17,7 +17,8 @@ public class DefaultHandleUnparsableDateField extends TestBase { date.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { if (date.isValid()) { - getMainWindow().showNotification(date.toString()); + getMainWindow() + .showNotification(date.getValue().toString()); } } diff --git a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldResolutionMsec.html b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldResolutionMsec.html index 3cdf70d5ab..4bf57177bd 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldResolutionMsec.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFieldResolutionMsec.html @@ -53,7 +53,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item6</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item5</td> <td>29,2</td> </tr> <tr> @@ -83,12 +83,7 @@ </tr> <tr> <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>000</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[8]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#ampm</td> <td>PM</td> </tr> <tr> @@ -108,7 +103,7 @@ </tr> <tr> <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[8]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#ampm</td> <td>label=AM</td> </tr> <tr> @@ -148,43 +143,38 @@ </tr> <tr> <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#h</td> <td>03</td> </tr> <tr> <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#m</td> <td>04</td> </tr> <tr> <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[4]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#s</td> <td>05</td> </tr> <tr> <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>006</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[8]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#ampm</td> <td>AM</td> </tr> <tr> <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>label=002</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#s</td> + <td>label=02</td> </tr> <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_SLog/ChildComponentContainer[0]/VLabel[0]</td> - <td>6. ValueChangeEvent, new value: Jan 2, 2000 03:04:05.002</td> + <td>6. ValueChangeEvent, new value: Jan 2, 2000 03:04:02.006</td> </tr> <tr> <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>002</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/VCalendarPanel[0]#s</td> + <td>02</td> </tr> </tbody></table> </body> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java index 56f3641043..de08477dd3 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/InlineDateFields.java @@ -8,6 +8,7 @@ import java.util.Locale; import com.vaadin.tests.components.ComponentTestCase; import com.vaadin.ui.Component; import com.vaadin.ui.DateField; +import com.vaadin.ui.DateField.Resolution; import com.vaadin.ui.InlineDateField; @SuppressWarnings("serial") @@ -47,7 +48,7 @@ public class InlineDateFields extends ComponentTestCase<InlineDateField> { pd.setWidth(width); pd.setValue(new Date(12312312313L)); pd.setLocale(locale); - pd.setResolution(DateField.RESOLUTION_YEAR); + pd.setResolution(DateField.Resolution.YEAR); return pd; } @@ -66,18 +67,17 @@ public class InlineDateFields extends ComponentTestCase<InlineDateField> { } private Component createResolutionSelectAction() { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Year", DateField.RESOLUTION_YEAR); - options.put("Month", DateField.RESOLUTION_MONTH); - options.put("Day", DateField.RESOLUTION_DAY); - options.put("Hour", DateField.RESOLUTION_HOUR); - options.put("Min", DateField.RESOLUTION_MIN); - options.put("Sec", DateField.RESOLUTION_SEC); - options.put("Msec", DateField.RESOLUTION_MSEC); + LinkedHashMap<String, Resolution> options = new LinkedHashMap<String, Resolution>(); + options.put("Year", DateField.Resolution.YEAR); + options.put("Month", DateField.Resolution.MONTH); + options.put("Day", DateField.Resolution.DAY); + options.put("Hour", DateField.Resolution.HOUR); + options.put("Min", DateField.Resolution.MINUTE); + options.put("Sec", DateField.Resolution.SECOND); return createSelectAction("Resolution", options, "Year", - new Command<InlineDateField, Integer>() { + new Command<InlineDateField, Resolution>() { - public void execute(InlineDateField c, Integer value, + public void execute(InlineDateField c, Resolution value, Object data) { c.setResolution(value); diff --git a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldDisabledReadonly.html b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldDisabledReadonly.html index fcd2ddf573..009ca0aaf9 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldDisabledReadonly.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldDisabledReadonly.html @@ -39,7 +39,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[4]</td> <td>759,5</td> </tr> <tr> @@ -59,7 +59,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[2]/domChild[0]</td> <td>566,9</td> </tr> <tr> @@ -84,7 +84,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[4]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[4]</td> <td>699,43</td> </tr> <tr> @@ -109,7 +109,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[3]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[3]</td> <td>630,30</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldMonth.html b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldMonth.html index 440de7c952..9111388f5a 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldMonth.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldMonth.html @@ -23,7 +23,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VPopupCalendar[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VPopupCalendar[0]/domChild[1]</td> <td>10,14</td> </tr> <tr> @@ -33,12 +33,12 @@ </tr> <tr> <td>enterCharacter</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VPopupCalendar[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VPopupCalendar[0]/domChild[0]</td> <td>1 1 2010</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VPopupCalendar[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldCustomDateFormats::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VPopupCalendar[0]/domChild[1]</td> <td>14,13</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldPopup.html b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldPopup.html index 993d053b63..1ec418e523 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldPopup.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldPopup.html @@ -43,7 +43,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldPopup::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldPopup::/VVerticalLayout[0]</td> <td>85,81</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldResolutions.html b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldResolutions.html index 6dae483332..8ecf9a4731 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldResolutions.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFieldResolutions.html @@ -272,67 +272,6 @@ <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::PID_SLocale-en_US-undefined-wide#field</td> <td>10,12</td> </tr> -<!--Resolution: msec--> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::PID_Sselectaction-Resolution/domChild[0]</td> - <td>label=Msec</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>enabled-msec</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::PID_SLocale-en_US-undefined-wide#popupButton</td> - <td>10,12</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#header</td> - <td>May 1970</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#day23</td> - <td>23</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#h</td> - <td>02</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#m</td> - <td>05</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#s</td> - <td>12</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#ms</td> - <td>313</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::Root/VOverlay[0]/VCalendarPanel[0]#ampm</td> - <td>PM</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>msec-popup-us</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::PID_SLocale-en_US-undefined-wide#field</td> - <td>10,12</td> -</tr> <!--Check resolution year functionality--> <tr> <td>select</td> @@ -401,7 +340,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td> <td>202,40</td> </tr> <tr> @@ -451,7 +390,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td> <td>129,26</td> </tr> <!--Check resolution month functionality--> @@ -542,7 +481,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]/domChild[0]</td> <td>174,3</td> </tr> <tr> @@ -552,7 +491,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td> <td>129,26</td> </tr> <!--Check resolution day functionality--> @@ -568,7 +507,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[2]</td> <td>478,1</td> </tr> <tr> @@ -618,7 +557,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]/domChild[0]</td> <td>193,12</td> </tr> <tr> @@ -858,7 +797,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]/domChild[0]</td> <td>185,8</td> </tr> <tr> @@ -888,7 +827,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td> <td>364,32</td> </tr> <!--Also check finnish locale--> @@ -924,7 +863,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[7]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[7]/domChild[0]</td> <td>286,10</td> </tr> <tr> @@ -1080,7 +1019,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[7]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFields::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[7]</td> <td>291,3</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFields.java b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFields.java index 7e8b19b2a1..ad961ee7a6 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFields.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/PopupDateFields.java @@ -8,6 +8,7 @@ import java.util.Locale; import com.vaadin.tests.components.ComponentTestCase; import com.vaadin.ui.Component; import com.vaadin.ui.DateField; +import com.vaadin.ui.DateField.Resolution; import com.vaadin.ui.PopupDateField; @SuppressWarnings("serial") @@ -47,7 +48,7 @@ public class PopupDateFields extends ComponentTestCase<PopupDateField> { pd.setWidth(width); pd.setValue(new Date(12312312313L)); pd.setLocale(locale); - pd.setResolution(DateField.RESOLUTION_YEAR); + pd.setResolution(DateField.Resolution.YEAR); return pd; } @@ -66,18 +67,17 @@ public class PopupDateFields extends ComponentTestCase<PopupDateField> { } private Component createResolutionSelectAction() { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Year", DateField.RESOLUTION_YEAR); - options.put("Month", DateField.RESOLUTION_MONTH); - options.put("Day", DateField.RESOLUTION_DAY); - options.put("Hour", DateField.RESOLUTION_HOUR); - options.put("Min", DateField.RESOLUTION_MIN); - options.put("Sec", DateField.RESOLUTION_SEC); - options.put("Msec", DateField.RESOLUTION_MSEC); + LinkedHashMap<String, Resolution> options = new LinkedHashMap<String, Resolution>(); + options.put("Year", DateField.Resolution.YEAR); + options.put("Month", DateField.Resolution.MONTH); + options.put("Day", DateField.Resolution.DAY); + options.put("Hour", DateField.Resolution.HOUR); + options.put("Min", DateField.Resolution.MINUTE); + options.put("Sec", DateField.Resolution.SECOND); return createSelectAction("Resolution", options, "Year", - new Command<PopupDateField, Integer>() { + new Command<PopupDateField, Resolution>() { - public void execute(PopupDateField c, Integer value, + public void execute(PopupDateField c, Resolution value, Object data) { c.setResolution(value); diff --git a/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java b/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java index 7176dae48b..a89459d37a 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/RequiredInvalidDateField.java @@ -12,6 +12,7 @@ import com.vaadin.ui.DateField; public class RequiredInvalidDateField extends TestBase { + @SuppressWarnings("deprecation") @Override protected void setup() { // StringLengthValidator textValidator = new StringLengthValidator( @@ -34,20 +35,26 @@ public class RequiredInvalidDateField extends TestBase { Date date = new Date(2011 - 1900, 9 - 1, 1); - Validator dateValidator = new AbstractValidator( + Validator dateValidator = new AbstractValidator<Date>( "Day of month must be an even number") { - public boolean isValid(Object value) { - if (!(value instanceof Date)) { - return false; + @Override + protected boolean isValidValue(Date value) { + if (value == null) { + return true; } - Date date = (Date) value; - return (date.getDate() % 2 == 0); + + return (value.getDate() % 2 == 0); + } + + @Override + public Class getType() { + return Date.class; } }; // not required - Property dateProperty1 = new ObjectProperty<Date>(date); + Property<Date> dateProperty1 = new ObjectProperty<Date>(date); DateField dateField1 = new DateField("Not required", dateProperty1); dateField1.setLocale(new Locale("fi", "FI")); dateField1.setResolution(DateField.RESOLUTION_DAY); @@ -57,7 +64,7 @@ public class RequiredInvalidDateField extends TestBase { addComponent(dateField1); // required - Property dateProperty2 = new ObjectProperty<Date>(date); + Property<Date> dateProperty2 = new ObjectProperty<Date>(date); DateField dateField2 = new DateField("Required", dateProperty2); dateField2.setLocale(new Locale("fi", "FI")); dateField2.setResolution(DateField.RESOLUTION_DAY); diff --git a/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullInlineDateField.html b/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullInlineDateField.html index 40d50f0328..7f4cd92be2 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullInlineDateField.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullInlineDateField.html @@ -16,16 +16,7 @@ <td>/run/com.vaadin.tests.components.datefield.InlineDateFieldTest?restartApplication</td> <td></td> </tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_Smenu#item0</td> - <td>42,20</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_Smenu#item0</td> - <td>42,20</td> -</tr> +<!--locale -> en_us--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_Smenu#item0</td> @@ -46,6 +37,7 @@ <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item2</td> <td>34,4</td> </tr> +<!--resolution seconds--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_Smenu#item0</td> @@ -63,19 +55,10 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item6</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item5</td> <td>27,5</td> </tr> -<tr> - <td>scroll</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>7539</td> -</tr> -<tr> - <td>pause</td> - <td>300</td> - <td></td> -</tr> +<!--set value to null--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_Smenu#item0</td> @@ -96,16 +79,7 @@ <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item0</td> <td>12,8</td> </tr> -<tr> - <td>scroll</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>3542</td> -</tr> -<tr> - <td>pause</td> - <td>300</td> - <td></td> -</tr> +<!--add a value change listener--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_Smenu#item0</td> @@ -139,19 +113,14 @@ <tr> <td>select</td> <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[6]</td> - <td>index=0</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_StestComponent/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]/domChild[8]</td> <td>index=1</td> </tr> +<!--As we start from current date - might be 0-4 value changes and the day may be any day--> <tr> - <td>verifyTextPresent</td> - <td>12:00:00.000</td> - <td></td> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldInlineDateFieldTest::PID_SLog_row_0</td> + <td>*. ValueChangeEvent, new value: * DATE(D), DATE(YYYY) 12:00:00.000</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullPopupDateField.html b/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullPopupDateField.html index b7f63591f9..9fabd8b1e7 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullPopupDateField.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/TestSettingTimeOnInitiallyNullPopupDateField.html @@ -78,7 +78,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item6</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[2]/VMenuBar[0]#item5</td> <td>30,12</td> </tr> <tr> @@ -88,22 +88,17 @@ </tr> <tr> <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#m</td> - <td>index=0</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#s</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#h</td> <td>index=0</td> </tr> <tr> <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#ms</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#m</td> <td>index=0</td> </tr> <tr> <td>select</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#h</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::Root/VOverlay[0]/VCalendarPanel[0]#s</td> <td>index=0</td> </tr> <tr> @@ -112,11 +107,10 @@ <td>index=1</td> </tr> <tr> - <td>verifyTextPresent</td> - <td>12:00:00.000</td> - <td></td> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldPopupDateFieldTest::PID_SLog_row_0</td> + <td>*. ValueChangeEvent, new value: * DATE(D), DATE(YYYY) 12:00:00.000</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.html b/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.html index ce74f8941e..07b8b1b237 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.html @@ -28,7 +28,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsdatefieldValueThroughProperty::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsdatefieldValueThroughProperty::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>246,18</td> </tr> <tr> @@ -41,7 +41,6 @@ <td>vaadin=runcomvaadintestscomponentsdatefieldValueThroughProperty::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VPopupCalendar[0]#field</td> <td>12/14/10</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.java b/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.java index 1f9735b543..12c9608d28 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.java +++ b/tests/testbench/com/vaadin/tests/components/datefield/ValueThroughProperty.java @@ -12,10 +12,11 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.DateField; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.PopupDateField; public class ValueThroughProperty extends TestBase { - private final Property dateProperty = new ObjectProperty<Date>(null, + private final Property<Date> dateProperty = new ObjectProperty<Date>(null, Date.class); @Override @@ -25,7 +26,7 @@ public class ValueThroughProperty extends TestBase { + "Then try to set DateField's value using the first button. It sets the value " + "correctly (as we can see from the Label) but the client-side is not updated.<br/>" + "Using second button updates value correctly on the client-side too.", - Label.CONTENT_XML)); + ContentMode.XML)); final PopupDateField df = new PopupDateField(dateProperty); df.setLocale(new Locale("en", "US")); diff --git a/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html b/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html index 3afb322a22..2dcd1b5071 100644 --- a/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html +++ b/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html @@ -17,38 +17,23 @@ <td></td> </tr> <tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]</td> <td>41,22</td> </tr> <tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>click-41-22</td> -</tr> -<!-- Should really be 41,22 but due to v-view border-top it is not always... <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]/HTML[0]/domChild[0]</td> <td>41, 22</td> -</tr>--> +</tr> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]</td> <td>0,0</td> </tr> <tr> - <td>waitForVaadin</td> - <td></td> + <td>waitForElementNotPresent</td> + <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]/HTML[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -57,19 +42,9 @@ <td>0,0</td> </tr> <tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<!-- Should really be 0,0 but due to v-view border-top it is not always... <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentsembeddedEmbeddedClickListenerRelativeCoordinates::Root/VNotification[0]/HTML[0]/domChild[0]</td> <td>0, 0</td> -</tr>--> -<tr> - <td>screenCapture</td> - <td></td> - <td>click-0-0</td> </tr> </tbody></table> </body> diff --git a/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedPdf.java b/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedPdf.java index 320df648b1..d507cebebc 100644 --- a/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedPdf.java +++ b/tests/testbench/com/vaadin/tests/components/embedded/EmbeddedPdf.java @@ -34,7 +34,7 @@ public class EmbeddedPdf extends TestBase { } })); - player.getWindow().addWindow(new Window("Testwindow")); + player.getRoot().addWindow(new Window("Testwindow")); } } diff --git a/tests/testbench/com/vaadin/tests/components/form/FormCaptionClickFocusing.html b/tests/testbench/com/vaadin/tests/components/form/FormCaptionClickFocusing.html index ab0aa25c44..14dbc6d4c8 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormCaptionClickFocusing.html +++ b/tests/testbench/com/vaadin/tests/components/form/FormCaptionClickFocusing.html @@ -28,7 +28,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsformFormCaptionClickFocusing::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsformFormCaptionClickFocusing::/VVerticalLayout[0]/domChild[1]</td> <td>161,159</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/form/FormClearDatasourceRepaint.java b/tests/testbench/com/vaadin/tests/components/form/FormClearDatasourceRepaint.java index 39305d5638..5255b97ffa 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormClearDatasourceRepaint.java +++ b/tests/testbench/com/vaadin/tests/components/form/FormClearDatasourceRepaint.java @@ -37,7 +37,6 @@ public class FormClearDatasourceRepaint extends TestBase { @Override protected void setup() { - final Form form = new Form(); form.setItemDataSource(new BeanItem<MySecondBean>(new MySecondBean())); addComponent(form); @@ -50,10 +49,10 @@ public class FormClearDatasourceRepaint extends TestBase { addComponent(new Button("Change data source", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + public void buttonClick(ClickEvent event) { form.setItemDataSource(new BeanItem<MyBean>( new MyBean())); - } + } })); } diff --git a/tests/testbench/com/vaadin/tests/components/form/FormCommitWithInvalidValues.java b/tests/testbench/com/vaadin/tests/components/form/FormCommitWithInvalidValues.java index 0a3054b0e4..6bc7cb5cca 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormCommitWithInvalidValues.java +++ b/tests/testbench/com/vaadin/tests/components/form/FormCommitWithInvalidValues.java @@ -6,8 +6,8 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Form; +import com.vaadin.ui.Notification; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window.Notification; public class FormCommitWithInvalidValues extends TestBase { diff --git a/tests/testbench/com/vaadin/tests/components/form/FormDescription.java b/tests/testbench/com/vaadin/tests/components/form/FormDescription.java index d05d179ac8..63369413f6 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormDescription.java +++ b/tests/testbench/com/vaadin/tests/components/form/FormDescription.java @@ -10,11 +10,11 @@ public class FormDescription extends TestBase { @Override protected void setup() { - final Form form = new Form(); - form.setDescription("Some description"); + final Form form = new Form(); + form.setDescription("Some description"); form.addField("AAAA", new TextField()); - addComponent(form); - + addComponent(form); + addComponent(new Button("Toggle description", new Button.ClickListener() { public void buttonClick(ClickEvent event) { @@ -25,7 +25,6 @@ public class FormDescription extends TestBase { } } })); - } diff --git a/tests/testbench/com/vaadin/tests/components/form/FormTest.java b/tests/testbench/com/vaadin/tests/components/form/FormTest.java index e3e873c1bb..451a1b7fa3 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormTest.java +++ b/tests/testbench/com/vaadin/tests/components/form/FormTest.java @@ -118,26 +118,40 @@ public class FormTest extends AbstractFieldTest<Form> { private void createDataSourceSelect(String category) { LinkedHashMap<String, Item> options = new LinkedHashMap<String, Item>(); - options.put("Person", new BeanItem<Person>(new Person("First", "Last", - "foo@vaadin.com", "02-111 2222", "Ruukinkatu 2-4", 20540, - "Turku"))); - options.put("Product", new BeanItem<Product>(new Product( - "Computer Monitor", 399.99f, - "A monitor that can display both color and black and white."))); + + options.put("Person", createPersonItem()); + options.put("Product", createProductItem()); + createSelectAction("Form data source", category, options, "Person", formItemDataSourceCommand); } + private BeanItem<Product> createProductItem() { + return new BeanItem<Product>(new Product("Computer Monitor", 399.99f, + "A monitor that can display both color and black and white.")); + } + + private BeanItem<Person> createPersonItem() { + Person person = new Person("First", "Last", "foo@vaadin.com", + "02-111 2222", "Ruukinkatu 2-4", 20540, "Turku"); + + BeanItem<Person> personItem = new BeanItem<Person>(person); + // add nested properties from address + personItem.expandProperty("address"); + + return personItem; + } + private void createFormFactorySelect(String category) { LinkedHashMap<String, FormFieldFactory> options = new LinkedHashMap<String, FormFieldFactory>(); options.put("Default", DefaultFieldFactory.get()); options.put("Custom FieldFactory", new FormFieldFactory() { - public Field createField(Item item, Object propertyId, + public Field<?> createField(Item item, Object propertyId, Component uiContext) { Class<?> type = item.getItemProperty(propertyId).getType(); - Field c = null; + Field<?> c = null; if (Number.class.isAssignableFrom(type)) { TextField tf = new TextField(); tf.setCaption(DefaultFieldFactory diff --git a/tests/testbench/com/vaadin/tests/components/form/FormWithEnterShortCut.java b/tests/testbench/com/vaadin/tests/components/form/FormWithEnterShortCut.java index a3baab921f..689ba7ea83 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormWithEnterShortCut.java +++ b/tests/testbench/com/vaadin/tests/components/form/FormWithEnterShortCut.java @@ -5,7 +5,6 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Field; import com.vaadin.ui.Form; import com.vaadin.ui.TextField; @@ -16,7 +15,7 @@ public class FormWithEnterShortCut extends TestBase { protected void setup() { final Form form = new Form(); - final Field tf = new TextField("Search"); + final TextField tf = new TextField("Search"); form.addField("searchfield", tf); Button button = new Button("Go"); diff --git a/tests/testbench/com/vaadin/tests/components/form/FormWithPropertyFormatterConnected.java b/tests/testbench/com/vaadin/tests/components/form/FormWithPropertyFormatterConnected.java index eba570c490..b803f8667f 100644 --- a/tests/testbench/com/vaadin/tests/components/form/FormWithPropertyFormatterConnected.java +++ b/tests/testbench/com/vaadin/tests/components/form/FormWithPropertyFormatterConnected.java @@ -28,8 +28,8 @@ public class FormWithPropertyFormatterConnected extends TestBase { @Override public Object parse(String formattedValue) throws Exception { - String str = formattedValue - .replaceAll("[^0-9.]", ""); + String str = formattedValue.replaceAll("[^0-9.]", + ""); if (formattedValue.toLowerCase().contains("months")) { return Double.parseDouble(str) / 12; } @@ -40,7 +40,7 @@ public class FormWithPropertyFormatterConnected extends TestBase { public String format(Object value) { Double dValue = (Double) value; if (dValue < 1) { - return ((int)(dValue * 12)) + " months"; + return ((int) (dValue * 12)) + " months"; } return dValue + " years"; } @@ -51,7 +51,7 @@ public class FormWithPropertyFormatterConnected extends TestBase { } }); form2.setItemDataSource(createItem()); - + addComponent(form2); addComponent(new Button("B")); } diff --git a/tests/testbench/com/vaadin/tests/components/form/UndefinedWideFormWithRelativeWideFooter.java b/tests/testbench/com/vaadin/tests/components/form/UndefinedWideFormWithRelativeWideFooter.java index cb616d4548..21430d8936 100644 --- a/tests/testbench/com/vaadin/tests/components/form/UndefinedWideFormWithRelativeWideFooter.java +++ b/tests/testbench/com/vaadin/tests/components/form/UndefinedWideFormWithRelativeWideFooter.java @@ -5,16 +5,17 @@ import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Form; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; @SuppressWarnings("serial") -public class UndefinedWideFormWithRelativeWideFooter extends Application { +public class UndefinedWideFormWithRelativeWideFooter extends + Application.LegacyApplication { @Override public void init() { - Window w = new Window("Test"); + LegacyWindow w = new LegacyWindow("Test"); setMainWindow(w); final Form f = new Form(); diff --git a/tests/testbench/com/vaadin/tests/components/formlayout/FormLayoutReplaceComponent.java b/tests/testbench/com/vaadin/tests/components/formlayout/FormLayoutReplaceComponent.java deleted file mode 100644 index 9427318a10..0000000000 --- a/tests/testbench/com/vaadin/tests/components/formlayout/FormLayoutReplaceComponent.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.vaadin.tests.components.formlayout; -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.CheckBox; -import com.vaadin.ui.FormLayout; -import com.vaadin.ui.TextField; - -public class FormLayoutReplaceComponent extends TestBase { - - @Override - protected void setup() { - addComponent(new FL()); - - } - - public class FL extends FormLayout implements ClickListener { - - private TextField messages; - private CheckBox control; - - @SuppressWarnings("deprecation") - public FL() { - setCaption("Test"); - control = new CheckBox("Messages On/Off"); - control.addListener(this); - control.setImmediate(true); - addComponent(control); - - // The bug is in replaceComponent, triggered when VTextField is - // replaced by VTextArea so cannot replace this with TextArea. - messages = new TextField("Messages"); - messages.setRows(10); - messages.setColumns(40); - messages.setVisible(false); - messages.setEnabled(false); - addComponent(messages); - } - - public final void buttonClick(Button.ClickEvent e) { - if (e.getButton() == control) { - messages.setVisible(control.booleanValue()); - } - } - } - - @Override - protected String getDescription() { - return "Check or uncheck the CheckBox to show/hide the messages field inside the FormLayout."; - } - - @Override - protected Integer getTicketNumber() { - return 6308; - } - -}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/formlayout/TableInFormLayoutCausesScrolling.java b/tests/testbench/com/vaadin/tests/components/formlayout/TableInFormLayoutCausesScrolling.java index c8eb1483b4..bbe88b1770 100644 --- a/tests/testbench/com/vaadin/tests/components/formlayout/TableInFormLayoutCausesScrolling.java +++ b/tests/testbench/com/vaadin/tests/components/formlayout/TableInFormLayoutCausesScrolling.java @@ -2,16 +2,16 @@ package com.vaadin.tests.components.formlayout; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.FormLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; public class TableInFormLayoutCausesScrolling extends AbstractTestCase { @Override public void init() { // Window Initialization. - final Window window = new Window("Main Window"); + final LegacyWindow window = new LegacyWindow("Main Window"); setMainWindow(window); // FormLayout creation diff --git a/tests/testbench/com/vaadin/tests/components/label/LabelModes.java b/tests/testbench/com/vaadin/tests/components/label/LabelModes.java index 4b58794a87..00553ddf96 100644 --- a/tests/testbench/com/vaadin/tests/components/label/LabelModes.java +++ b/tests/testbench/com/vaadin/tests/components/label/LabelModes.java @@ -2,6 +2,7 @@ package com.vaadin.tests.components.label; import com.vaadin.tests.components.ComponentTestCase; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; public class LabelModes extends ComponentTestCase<Label> { @@ -23,17 +24,17 @@ public class LabelModes extends ComponentTestCase<Label> { addTestComponent(l); l = createLabel("This label contains\nnewlines and spaces\nand is in\npreformatted mode"); - l.setContentMode(Label.CONTENT_PREFORMATTED); + l.setContentMode(ContentMode.PREFORMATTED); l.setWidth(null); addTestComponent(l); l = createLabel("This label contains\nnewlines and spaces\nand is in\nhtml mode"); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); l.setWidth(null); addTestComponent(l); l = createLabel("This label contains\nnewlines and spaces\nand is in\nraw mode"); - l.setContentMode(Label.CONTENT_RAW); + l.setContentMode(ContentMode.RAW); l.setWidth(null); addTestComponent(l); diff --git a/tests/testbench/com/vaadin/tests/components/label/LabelTest.java b/tests/testbench/com/vaadin/tests/components/label/LabelTest.java index 5c71046404..130aaeca78 100644 --- a/tests/testbench/com/vaadin/tests/components/label/LabelTest.java +++ b/tests/testbench/com/vaadin/tests/components/label/LabelTest.java @@ -7,6 +7,7 @@ import java.util.List; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; public class LabelTest extends AbstractComponentTest<Label> implements ValueChangeListener { @@ -29,8 +30,8 @@ public class LabelTest extends AbstractComponentTest<Label> implements } }; - private Command<Label, Integer> contentModeCommand = new Command<Label, Integer>() { - public void execute(Label c, Integer value, Object data) { + private Command<Label, ContentMode> contentModeCommand = new Command<Label, ContentMode>() { + public void execute(Label c, ContentMode value, Object data) { c.setContentMode(value); } }; @@ -68,13 +69,14 @@ public class LabelTest extends AbstractComponentTest<Label> implements @SuppressWarnings("deprecation") private void createContentModeSelect(String category) { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Text", Label.CONTENT_TEXT); - options.put("Preformatted", Label.CONTENT_PREFORMATTED); - options.put("Raw", Label.CONTENT_RAW); - options.put("UIDL", Label.CONTENT_UIDL); - options.put("XHTML", Label.CONTENT_XHTML); - options.put("XML", Label.CONTENT_XML); + LinkedHashMap<String, ContentMode> options = new LinkedHashMap<String, ContentMode>(); + options.put("Text", ContentMode.TEXT); + options.put("Preformatted", ContentMode.PREFORMATTED); + options.put("Raw", ContentMode.RAW); + options.put("UIDL", ContentMode.XML); // Deprecated UIDL mode still used + // to avoid breaking old tests + options.put("XHTML", ContentMode.XHTML); + options.put("XML", ContentMode.XML); createSelectAction("Content mode", category, options, "Text", contentModeCommand); diff --git a/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-chameleon.html b/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-chameleon.html index 8d2744c5b7..4a724795b3 100644 --- a/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-chameleon.html +++ b/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-chameleon.html @@ -23,7 +23,7 @@ </tr> <tr> <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[1]</td> <td>0,0</td> </tr> <tr> @@ -33,7 +33,7 @@ </tr> <tr> <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[3]</td> <td>0,0</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-runo.html b/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-runo.html index fcd0169928..9877493b3b 100644 --- a/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-runo.html +++ b/tests/testbench/com/vaadin/tests/components/label/LabelTooltip-runo.html @@ -23,7 +23,7 @@ </tr> <tr> <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[1]</td> <td>0,0</td> </tr> <tr> @@ -33,7 +33,7 @@ </tr> <tr> <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[3]</td> <td>0,0</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/label/LabelTooltip.html b/tests/testbench/com/vaadin/tests/components/label/LabelTooltip.html index 0fbd3353c9..05da9195ef 100644 --- a/tests/testbench/com/vaadin/tests/components/label/LabelTooltip.html +++ b/tests/testbench/com/vaadin/tests/components/label/LabelTooltip.html @@ -23,7 +23,7 @@ </tr> <tr> <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[1]</td> <td>0,0</td> </tr> <tr> @@ -33,7 +33,7 @@ </tr> <tr> <td>showTooltip</td> - <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentslabelLabelTooltip::/VVerticalLayout[0]/VVerticalLayout[0]/VGridLayout[0]/VLabel[3]</td> <td>0,0</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/label/Labels.java b/tests/testbench/com/vaadin/tests/components/label/Labels.java index ad648e7404..bbd64375ef 100644 --- a/tests/testbench/com/vaadin/tests/components/label/Labels.java +++ b/tests/testbench/com/vaadin/tests/components/label/Labels.java @@ -3,6 +3,7 @@ package com.vaadin.tests.components.label; import com.vaadin.tests.components.ComponentTestCase; import com.vaadin.tests.util.LoremIpsum; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; public class Labels extends ComponentTestCase<Label> { @@ -37,13 +38,13 @@ public class Labels extends ComponentTestCase<Label> { l = createLabel( "<div style='border: 1px solid red'><h1>Hello\n\n\n</h1><p/><h2>I am a rich Label</h3></div>", "This is an XHTML label with rich content"); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); addTestComponent(l); l = createLabel( "<div style='border: 1px solid blue'><h1>Hello</h1><p/><h2>I am a rich Label</h3></div>", "This is an XHTML label with fixed 200px width and rich content"); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); l.setWidth("200px"); addTestComponent(l); diff --git a/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html new file mode 100644 index 0000000000..080200092d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.html @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head profile="http://selenium-ide.openqa.org/profiles/test-case"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="selenium.base" href="" /><title>com.vaadin.tests.components.accordion.AccordionInactiveTabSize</title></head><body><table cellpadding="1" cellspacing="1" border="1"><thead><tr><td rowspan="1" colspan="3">com.vaadin.tests.components.accordion.AccordionInactiveTabSize</td></tr></thead><tbody><tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.label.MarginsInLabels?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> +</tbody></table></body></html>
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.java b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.java new file mode 100644 index 0000000000..699f94bb7e --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/label/MarginsInLabels.java @@ -0,0 +1,50 @@ +package com.vaadin.tests.components.label; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.AbstractLayout; +import com.vaadin.ui.Accordion; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.VerticalLayout; + +public class MarginsInLabels extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + AbstractLayout layout = new VerticalLayout(); + layout.addComponent(new Label("<h1>Vertical layout</h1>", + ContentMode.XHTML)); + layout.addComponent(new Label("Next row")); + addComponent(layout); + + layout = new GridLayout(1, 2); + layout.setWidth("100%"); + layout.addComponent(new Label("<h1>Grid layout</h1>", ContentMode.XHTML)); + layout.addComponent(new Label("Next row")); + addComponent(layout); + + TabSheet tabSheet = new TabSheet(); + tabSheet.addTab(new Label("<h1>Tabsheet</h1>", ContentMode.XHTML), + "Label"); + addComponent(tabSheet); + + Accordion accordion = new Accordion(); + accordion.addTab(new Label("<h1>Accordion</h1>", ContentMode.XHTML), + "Label"); + addComponent(accordion); + } + + @Override + protected String getTestDescription() { + return "Margins inside labels should not be allowed to collapse out of the label as it causes problems with layotus measuring the label."; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(8671); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java b/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java index 341caecc9f..1295cadf95 100644 --- a/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java +++ b/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java @@ -1,37 +1,22 @@ package com.vaadin.tests.components.loginform; import com.vaadin.Application; +import com.vaadin.terminal.WrappedRequest; import com.vaadin.ui.LoginForm; import com.vaadin.ui.LoginForm.LoginEvent; import com.vaadin.ui.LoginForm.LoginListener; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.LegacyWindow; @SuppressWarnings("serial") public class LoginFormWithMultipleWindows extends Application { - /** - * ======================================================================= - * Comment out this to make the LoginForm work as expected - * ======================================================================= - */ @Override - public Window getWindow(String name) { - Window w = super.getWindow(name); - if (w == null) { - w = new LoginFormWindow(); - w.setName(name); - addWindow(w); - } - return w; - - } - - @Override - public void init() { - setMainWindow(new LoginFormWindow()); + protected Root getRoot(WrappedRequest request) { + return new LoginFormWindow(); } - public class LoginFormWindow extends Window { + public class LoginFormWindow extends LegacyWindow { public LoginFormWindow() { super(); diff --git a/tests/testbench/com/vaadin/tests/components/menubar/MenuBarInSplitPanel.java b/tests/testbench/com/vaadin/tests/components/menubar/MenuBarInSplitPanel.java index 4a41f8d8dc..2a6f952c0a 100644 --- a/tests/testbench/com/vaadin/tests/components/menubar/MenuBarInSplitPanel.java +++ b/tests/testbench/com/vaadin/tests/components/menubar/MenuBarInSplitPanel.java @@ -4,9 +4,9 @@ import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class MenuBarInSplitPanel extends AbstractTestCase { @@ -22,7 +22,7 @@ public class MenuBarInSplitPanel extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window("MenuBar in SplitPanel", + LegacyWindow mainWindow = new LegacyWindow("MenuBar in SplitPanel", new HorizontalSplitPanel()); VerticalLayout left = new VerticalLayout(); mainWindow.addComponent(left); diff --git a/tests/testbench/com/vaadin/tests/components/menubar/MenuBarRunsOutOfBrowser.java b/tests/testbench/com/vaadin/tests/components/menubar/MenuBarRunsOutOfBrowser.java index b05dbbd074..33e6c0b4a9 100644 --- a/tests/testbench/com/vaadin/tests/components/menubar/MenuBarRunsOutOfBrowser.java +++ b/tests/testbench/com/vaadin/tests/components/menubar/MenuBarRunsOutOfBrowser.java @@ -4,15 +4,15 @@ import com.vaadin.terminal.ThemeResource; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Alignment; import com.vaadin.ui.MenuBar; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class MenuBarRunsOutOfBrowser extends AbstractTestCase { @Override public void init() { setTheme("runo"); - Window main = new Window("Test"); + LegacyWindow main = new LegacyWindow("Test"); main.setSizeFull(); setMainWindow(main); main.getContent().setSizeFull(); diff --git a/tests/testbench/com/vaadin/tests/components/menubar/MenuBarToolTips.html b/tests/testbench/com/vaadin/tests/components/menubar/MenuBarToolTips.html index 28bcc3a221..f7c57baf1f 100644 --- a/tests/testbench/com/vaadin/tests/components/menubar/MenuBarToolTips.html +++ b/tests/testbench/com/vaadin/tests/components/menubar/MenuBarToolTips.html @@ -63,7 +63,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsmenubarMenuBarToolTips::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsmenubarMenuBarToolTips::/VVerticalLayout[0]/domChild[1]</td> <td>830,200</td> </tr> <tr> @@ -88,7 +88,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsmenubarMenuBarToolTips::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsmenubarMenuBarToolTips::/VVerticalLayout[0]/domChild[1]</td> <td>625,184</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonDisableOnClick.html b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonDisableOnClick.html index 75eab71892..5f80004c7c 100644 --- a/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonDisableOnClick.html +++ b/tests/testbench/com/vaadin/tests/components/nativebutton/NativeButtonDisableOnClick.html @@ -16,7 +16,7 @@ <td>/run/com.vaadin.tests.components.nativebutton.NativeButtonTest?restartApplication</td> <td></td> </tr> -<!--value change listener--> +<!-- click listener--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::PID_Smenu#item0</td> @@ -29,7 +29,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::Root/VOverlay[1]/VMenuBar[0]#item4</td> + <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::Root/VOverlay[1]/VMenuBar[0]#item2</td> <td>35,8</td> </tr> <!--disable on click--> @@ -45,7 +45,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::Root/VOverlay[1]/VMenuBar[0]#item1</td> + <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::Root/VOverlay[1]/VMenuBar[0]#item0</td> <td>22,4</td> </tr> <tr> @@ -133,7 +133,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::Root/VOverlay[1]/VMenuBar[0]#item1</td> + <td>vaadin=runcomvaadintestscomponentsnativebuttonNativeButtonTest::Root/VOverlay[1]/VMenuBar[0]#item0</td> <td>36,3</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/notification/Notifications.java b/tests/testbench/com/vaadin/tests/components/notification/Notifications.java index 0e054eba3b..27aef918d1 100644 --- a/tests/testbench/com/vaadin/tests/components/notification/Notifications.java +++ b/tests/testbench/com/vaadin/tests/components/notification/Notifications.java @@ -5,19 +5,20 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.NativeSelect; -import com.vaadin.ui.TextField; -import com.vaadin.ui.Window.Notification; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root; +import com.vaadin.ui.TextArea; public class Notifications extends TestBase implements ClickListener { private static final String CAPTION = "CAPTION"; - private TextField tf; + private TextArea tf; private NativeSelect type; @SuppressWarnings("deprecation") @Override protected void setup() { - tf = new TextField("Text", "Hello world"); + tf = new TextArea("Text", "Hello world"); tf.setRows(10); addComponent(tf); type = new NativeSelect(); @@ -50,9 +51,9 @@ public class Notifications extends TestBase implements ClickListener { } public void buttonClick(ClickEvent event) { - Notification n = new Notification((String) tf.getValue(), + Notification n = new Notification(tf.getValue(), (Integer) type.getValue()); - event.getButton().getWindow().showNotification(n); + Root.getCurrentRoot().showNotification(n); } } diff --git a/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.html b/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.html index b4d76edae9..455952fb71 100644 --- a/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.html +++ b/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.html @@ -18,7 +18,7 @@ </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -28,17 +28,17 @@ </tr> <tr> <td>closeNotification</td> - <td>//body/div[4]</td> + <td>//body/div[2]</td> <td>0,0</td> </tr> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VCheckBox[0]/domChild[0]</td> - <td>60,0</td> + <td>63,3</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -46,51 +46,6 @@ <td></td> <td>view-plain</td> </tr> -<tr> - <td>closeNotification</td> - <td>//body/div[4]</td> - <td>0,0</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VCheckBox[0]/domChild[0]</td> - <td>51,7</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>window-plain</td> -</tr> -<tr> - <td>closeNotification</td> - <td>//body/div[4]</td> - <td>0,0</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VCheckBox[0]/domChild[0]</td> - <td>80,2</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsHtmlAllowed::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>window-html</td> -</tr> -<tr> - <td>closeNotification</td> - <td>//body/div[4]</td> - <td>0,0</td> -</tr> </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.java b/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.java index 60db11f1df..152688d109 100644 --- a/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.java +++ b/tests/testbench/com/vaadin/tests/components/notification/NotificationsHtmlAllowed.java @@ -5,18 +5,16 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; public class NotificationsHtmlAllowed extends TestBase implements ClickListener { private TextArea messageField; private CheckBox htmlAllowedBox; private TextField captionField; - private Window subwindow; - private CheckBox showInSubwindow; @Override protected void setup() { @@ -32,16 +30,8 @@ public class NotificationsHtmlAllowed extends TestBase implements ClickListener htmlAllowedBox = new CheckBox("Html content allowed", true); addComponent(htmlAllowedBox); - showInSubwindow = new CheckBox("Show in subwindow", false); - addComponent(showInSubwindow); - Button showNotification = new Button("Show notification", this); addComponent(showNotification); - - subwindow = new Window("Sub window"); - subwindow.setPositionX(400); - subwindow.setPositionY(0); - getMainWindow().addWindow(subwindow); } @Override @@ -56,13 +46,7 @@ public class NotificationsHtmlAllowed extends TestBase implements ClickListener public void buttonClick(ClickEvent event) { Notification n = makeNotification(); - Window window; - if (showInSubwindow.booleanValue()) { - window = subwindow; - } else { - window = event.getButton().getWindow(); - } - window.showNotification(n); + Root.getCurrentRoot().showNotification(n); } @@ -70,7 +54,7 @@ public class NotificationsHtmlAllowed extends TestBase implements ClickListener Notification n = new Notification((String) captionField.getValue(), (String) messageField.getValue(), Notification.TYPE_HUMANIZED_MESSAGE, - htmlAllowedBox.booleanValue()); + (Boolean) htmlAllowedBox.getValue()); return n; } } diff --git a/tests/testbench/com/vaadin/tests/components/optiongroup/OptionGroupMultipleValueChange.java b/tests/testbench/com/vaadin/tests/components/optiongroup/OptionGroupMultipleValueChange.java index 29a81720c7..9a4bb15272 100644 --- a/tests/testbench/com/vaadin/tests/components/optiongroup/OptionGroupMultipleValueChange.java +++ b/tests/testbench/com/vaadin/tests/components/optiongroup/OptionGroupMultipleValueChange.java @@ -4,6 +4,7 @@ import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.OptionGroup; public class OptionGroupMultipleValueChange extends TestBase { @@ -26,7 +27,7 @@ public class OptionGroupMultipleValueChange extends TestBase { og.setImmediate(true); addComponent(og); - final Label events = new Label("", Label.CONTENT_PREFORMATTED); + final Label events = new Label("", ContentMode.PREFORMATTED); events.setWidth(null); addComponent(events); diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutClickListenerTest.html b/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutClickListenerTest.html index 6b850fb52a..ea0a039dbe 100644 --- a/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutClickListenerTest.html +++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/LayoutClickListenerTest.html @@ -53,7 +53,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsorderedlayoutLayoutClickListenerTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsorderedlayoutLayoutClickListenerTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/domChild[1]</td> <td></td> </tr> <tr> @@ -78,7 +78,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsorderedlayoutLayoutClickListenerTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentsorderedlayoutLayoutClickListenerTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/domChild[0]</td> <td></td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java index a9f53bf996..172e808070 100644 --- a/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java +++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java @@ -7,7 +7,8 @@ import java.util.List; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; -import com.vaadin.tests.components.TestBase; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; import com.vaadin.tests.util.TestUtils; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Alignment; @@ -19,7 +20,7 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.VerticalLayout; -public class OrderedLayoutCases extends TestBase { +public class OrderedLayoutCases extends AbstractTestRoot { private static final String[] dimensionValues = { "-1px", "5px", "350px", "800px", "100%", "50%" }; @@ -108,14 +109,14 @@ public class OrderedLayoutCases extends TestBase { private HorizontalLayout sizeBar; @Override - protected void setup() { + protected void setup(WrappedRequest request) { TestUtils .injectCSS( - getMainWindow(), + getRoot(), ".sampleChild, .theLayout {border: 1px solid black;}" - + ".theLayout > div > div:first-child {background: aqua;}" - + ".theLayout > div > div:first-child + div {background: yellow;}" - + ".theLayout > div > div:first-child + div + div {background: lightgrey;}"); + + ".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++) { @@ -312,7 +313,7 @@ public class OrderedLayoutCases extends TestBase { addComponent(currentLayout); getLayout().setSpacing(true); - getLayout().getParent().setSizeFull(); + getContent().setSizeFull(); getLayout().setSizeFull(); getLayout().setExpandRatio(currentLayout, 1); } @@ -368,7 +369,7 @@ public class OrderedLayoutCases extends TestBase { } @Override - protected String getDescription() { + protected String getTestDescription() { return "Tester application for exploring how Horizontal/VerticalLayout reacts to various settings "; } diff --git a/tests/testbench/com/vaadin/tests/components/orderedlayout/VerticalLayoutWidthCalculation.java b/tests/testbench/com/vaadin/tests/components/orderedlayout/VerticalLayoutWidthCalculation.java index f59b940353..f20f26153f 100644 --- a/tests/testbench/com/vaadin/tests/components/orderedlayout/VerticalLayoutWidthCalculation.java +++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/VerticalLayoutWidthCalculation.java @@ -4,6 +4,7 @@ import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; @@ -11,7 +12,8 @@ import com.vaadin.ui.Window; public class VerticalLayoutWidthCalculation extends AbstractTestCase { @Override public void init() { - final Window mainWindow = new Window("Vaadintest Application"); + final LegacyWindow mainWindow = new LegacyWindow( + "Vaadintest Application"); mainWindow.addWindow(createSubWindow()); setMainWindow(mainWindow); diff --git a/tests/testbench/com/vaadin/tests/components/panel/BasicPanelTest.java b/tests/testbench/com/vaadin/tests/components/panel/BasicPanelTest.java new file mode 100644 index 0000000000..671b2c3fca --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/panel/BasicPanelTest.java @@ -0,0 +1,87 @@ +package com.vaadin.tests.components.panel; + +import java.util.Map; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.themes.Reindeer; + +public class BasicPanelTest extends TestBase { + private final Label scrollPosition = new Label(); + private final Panel panel = new Panel("Panel caption") { + @Override + public void changeVariables(Object source, Map<String, Object> variables) { + super.changeVariables(source, variables); + updateLabelText(); + } + }; + + @Override + protected void setup() { + getLayout().setWidth("600px"); + getLayout().setHeight("100%"); + + HorizontalLayout actions = new HorizontalLayout(); + actions.setSpacing(true); + + actions.addComponent(scrollPosition); + actions.addComponent(new Button("Sync")); + + final CheckBox heightSelection = new CheckBox("Undefined height"); + heightSelection.setImmediate(true); + heightSelection.addListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + if (heightSelection.getValue() == Boolean.TRUE) { + panel.setHeight(null); + } else { + panel.setHeight("100%"); + } + } + }); + actions.addComponent(heightSelection); + + panel.setWidth("200px"); + panel.setHeight("100%"); + panel.setStyleName(Reindeer.PANEL_LIGHT); + + panel.getContent().setCaption("Content caption"); + + TextArea textArea = new TextArea("TextArea caption"); + textArea.setWidth("300px"); + textArea.setHeight("500px"); + panel.addComponent(textArea); + + getLayout().addComponent(actions); + getLayout().addComponent(panel); + getLayout().setExpandRatio(panel, 1); + + panel.setScrollTop(50); + panel.setScrollLeft(50); + panel.setImmediate(true); + + updateLabelText(); + } + + private void updateLabelText() { + scrollPosition.setValue("Scrolled to " + panel.getScrollTop()); + } + + @Override + protected String getDescription() { + return "Simple test for basic panel functionality"; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/panel/PanelShouldNotScroll.java b/tests/testbench/com/vaadin/tests/components/panel/PanelShouldNotScroll.java index 7c537fe710..62b3007aba 100644 --- a/tests/testbench/com/vaadin/tests/components/panel/PanelShouldNotScroll.java +++ b/tests/testbench/com/vaadin/tests/components/panel/PanelShouldNotScroll.java @@ -7,6 +7,7 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalLayout; @@ -17,7 +18,6 @@ public class PanelShouldNotScroll extends TestBase { @Override protected void setup() { final Panel p = new Panel(new CssLayout()); - p.setScrollable(true); p.setSizeFull(); p.setHeight("600px"); p.addComponent(foo()); @@ -39,7 +39,7 @@ public class PanelShouldNotScroll extends TestBase { panel.addComponent(new Label( "fooooooooo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>" + "foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>foo<br/>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); return panel; } diff --git a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewNullValues.java b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewNullValues.java index ff71f2f381..481c134ee6 100644 --- a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewNullValues.java +++ b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewNullValues.java @@ -4,9 +4,9 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Notification; import com.vaadin.ui.PopupView; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window.Notification; public class PopupViewNullValues extends TestBase { diff --git a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewOffScreen.java b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewOffScreen.java index 7067281fa2..cd2b77806c 100644 --- a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewOffScreen.java +++ b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewOffScreen.java @@ -11,9 +11,11 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; import com.vaadin.ui.PopupView; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.BaseTheme; public class PopupViewOffScreen extends TestBase { @@ -61,6 +63,7 @@ public class PopupViewOffScreen extends TestBase { vl.setSpacing(false); vl.setMargin(false); vl.setSizeFull(); + vl.addStyleName(BaseTheme.CLIP); Panel p = new Panel(vl); p.setWidth("400px"); @@ -69,7 +72,7 @@ public class PopupViewOffScreen extends TestBase { Label l = new Label( "<div style='width: 100%; height: 100%; background: " + bg + "'>" + LoremIpsum.get(2000) + "</div>", - Label.CONTENT_XHTML); + ContentMode.XHTML); l.setSizeFull(); p.addComponent(l); PopupView pv = new PopupView("Click here to popup", p); diff --git a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewWithRTE.java b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewWithRTE.java index 1123f217b7..5ed0a375fe 100644 --- a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewWithRTE.java +++ b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewWithRTE.java @@ -28,7 +28,7 @@ public class PopupViewWithRTE extends TestBase { VerticalLayout vl = new VerticalLayout(); public String getMinimizedValueAsHTML() { - Object value = rte.getValue(); + String value = rte.getValue(); if (value == null || "".equals(value)) { value = "Initial <b>content</b> for <h3>rte</h3>."; rte.setValue(value); diff --git a/tests/testbench/com/vaadin/tests/components/richtextarea/RichTextAreaWithKeyboardShortcuts.java b/tests/testbench/com/vaadin/tests/components/richtextarea/RichTextAreaWithKeyboardShortcuts.java index 2e26d3e2c4..95691ef9d7 100644 --- a/tests/testbench/com/vaadin/tests/components/richtextarea/RichTextAreaWithKeyboardShortcuts.java +++ b/tests/testbench/com/vaadin/tests/components/richtextarea/RichTextAreaWithKeyboardShortcuts.java @@ -23,14 +23,14 @@ public class RichTextAreaWithKeyboardShortcuts extends TestBase { msg += " From : " + sender.getClass().getSimpleName() + " '" + ((Component) sender).getCaption() + "'"; - AbstractField f = (AbstractField) target; + AbstractField<String> f = (AbstractField<String>) target; msg += " Target:" + target.getClass().getSimpleName() + " '" + f.getCaption() + "'"; String string = f.getValue().toString(); msg += " Value: " + string; - f.getWindow().showNotification(msg); + f.getRoot().showNotification(msg); } @@ -42,7 +42,7 @@ public class RichTextAreaWithKeyboardShortcuts extends TestBase { @Override protected void setup() { - getLayout().getWindow().addActionHandler(actionHandler); + getLayout().getRoot().addActionHandler(actionHandler); getLayout().addComponent(createRichTextArea("InMainLayout")); Panel panel = new Panel("RTA Panel"); @@ -55,7 +55,7 @@ public class RichTextAreaWithKeyboardShortcuts extends TestBase { w.addComponent(createRichTextArea("InSubWindow")); w.getContent().setSizeUndefined(); - getLayout().getWindow().addWindow(w); + getLayout().getRoot().addWindow(w); } diff --git a/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.html b/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.html new file mode 100644 index 0000000000..5448a24816 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.html @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.LazyInitRoots/normalPath?restartApplication#normalFragment</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootLazyInitRoots::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>NormalRoot<br />pathInfo: /normalPath<br />parameters: [restartApplication]<br />uri fragment: normalFragment</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.LazyInitRoots/lazyCreatePath?lazyCreate#lazyCreateFragment</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootLazyInitRoots::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>LazyCreateRoot<br />pathInfo: /lazyCreatePath<br />parameters: [lazyCreate]<br />uri fragment: lazyCreateFragment</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.LazyInitRoots/eagerPath/?eagerInit#eagerFragment</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootLazyInitRoots::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>EagerInitRoot<br />pathInfo: /eagerPath/<br />parameters: [eagerInit]<br />uri fragment: null</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java b/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java new file mode 100644 index 0000000000..97f6701fdb --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java @@ -0,0 +1,89 @@ +package com.vaadin.tests.components.root; + +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.annotations.EagerInit; +import com.vaadin.terminal.ExternalResource; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedRequest.BrowserDetails; +import com.vaadin.tests.components.AbstractTestApplication; +import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Link; +import com.vaadin.ui.Root; + +public class LazyInitRoots extends AbstractTestApplication { + + @EagerInit + private static class EagerInitRoot extends Root { + @Override + public void init(WrappedRequest request) { + addComponent(getRequestInfo("EagerInitRoot", request)); + } + } + + @Override + public Root getRoot(WrappedRequest request) + throws RootRequiresMoreInformationException { + if (request.getParameter("lazyCreate") != null) { + // Root created on second request + BrowserDetails browserDetails = request.getBrowserDetails(); + if (browserDetails == null + || browserDetails.getUriFragment() == null) { + throw new RootRequiresMoreInformationException(); + } else { + Root root = new Root() { + @Override + protected void init(WrappedRequest request) { + addComponent(getRequestInfo("LazyCreateRoot", request)); + } + }; + return root; + } + } else if (request.getParameter("eagerInit") != null) { + // Root inited on first request + return new EagerInitRoot(); + } else { + // The standard root + Root root = new Root() { + @Override + protected void init(WrappedRequest request) { + addComponent(getRequestInfo("NormalRoot", request)); + + Link lazyCreateLink = new Link("Open lazyCreate root", + new ExternalResource(getURL() + + "?lazyCreate#lazyCreate")); + lazyCreateLink.setTargetName("_blank"); + addComponent(lazyCreateLink); + + Link lazyInitLink = new Link("Open eagerInit root", + new ExternalResource(getURL() + + "?eagerInit#eagerInit")); + lazyInitLink.setTargetName("_blank"); + addComponent(lazyInitLink); + } + }; + + return root; + } + } + + public static Label getRequestInfo(String name, WrappedRequest request) { + String info = name; + info += "<br />pathInfo: " + request.getRequestPathInfo(); + info += "<br />parameters: " + request.getParameterMap().keySet(); + info += "<br />uri fragment: " + + request.getBrowserDetails().getUriFragment(); + return new Label(info, ContentMode.XHTML); + } + + @Override + protected String getTestDescription() { + return "BrowserDetails should be available in Application.getRoot if RootRequiresMoreInformation has been thrown and in Root.init if the root has the @RootInitRequiresBrowserDetals annotation"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(7883); // + #7882 + #7884 + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/root/RootInitException.java b/tests/testbench/com/vaadin/tests/components/root/RootInitException.java new file mode 100644 index 0000000000..b4cfa2a28d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/RootInitException.java @@ -0,0 +1,23 @@ +package com.vaadin.tests.components.root; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; + +public class RootInitException extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + throw new RuntimeException("Catch me if you can"); + } + + @Override + protected String getTestDescription() { + return "Throwing an exception in application code during a browser details request should show a sensible message in the client"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(8243); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/root/RootInitTest.java b/tests/testbench/com/vaadin/tests/components/root/RootInitTest.java new file mode 100644 index 0000000000..16fecc62d2 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/RootInitTest.java @@ -0,0 +1,27 @@ +/* +@ITMillApache2LicenseForJavaFiles@ + */ + +package com.vaadin.tests.components.root; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Label; + +public class RootInitTest extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + addComponent(new Label("Hello root")); + } + + @Override + public String getTestDescription() { + return "Testing basic root creation"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(3067); + } +} diff --git a/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.html b/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.html new file mode 100644 index 0000000000..c9b83fdc4e --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.html @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.RootsInMultipleTabs?restartApplication</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootRootsInMultipleTabs::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>This is root number 1</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.RootsInMultipleTabs</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootRootsInMultipleTabs::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>This is root number 2</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.RootsInMultipleTabs?restartApplication</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootRootsInMultipleTabs::/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>This is root number 1</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java b/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java new file mode 100644 index 0000000000..c3b20c5e7c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java @@ -0,0 +1,36 @@ +package com.vaadin.tests.components.root; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestApplication; +import com.vaadin.ui.Label; +import com.vaadin.ui.Root; + +public class RootsInMultipleTabs extends AbstractTestApplication { + private int numberOfRootsOpened; + + public static class TabRoot extends Root { + @Override + protected void init(WrappedRequest request) { + RootsInMultipleTabs application = (RootsInMultipleTabs) getApplication(); + String message = "This is root number " + + ++application.numberOfRootsOpened; + + addComponent(new Label(message)); + } + } + + @Override + protected String getRootClassName(WrappedRequest request) { + return TabRoot.class.getName(); + } + + @Override + protected String getTestDescription() { + return "Opening the same application again (e.g. in a new tab) should create a new Root."; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(7894); + } +} diff --git a/tests/testbench/com/vaadin/tests/components/root/TestRootTheme.html b/tests/testbench/com/vaadin/tests/components/root/TestRootTheme.html new file mode 100644 index 0000000000..7d0f638325 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/TestRootTheme.html @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.TestRootTheme?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>themeLoaded</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/root/TestRootTheme.java b/tests/testbench/com/vaadin/tests/components/root/TestRootTheme.java new file mode 100644 index 0000000000..77c0bdb150 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/TestRootTheme.java @@ -0,0 +1,28 @@ +package com.vaadin.tests.components.root; + +import com.vaadin.annotations.Theme; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Label; + +@Theme("tests-tickets") +public class TestRootTheme extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + Label label = new Label("A red label"); + label.setStyleName("red"); + addComponent(label); + } + + @Override + public String getTestDescription() { + return "Root with @RootTheme(\"tests-tickets\")"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(7885); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/root/TestRootWidgetset.java b/tests/testbench/com/vaadin/tests/components/root/TestRootWidgetset.java new file mode 100644 index 0000000000..c9c001deb6 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/TestRootWidgetset.java @@ -0,0 +1,25 @@ +package com.vaadin.tests.components.root; + +import com.vaadin.annotations.Widgetset; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; + +@Widgetset("invalid") +public class TestRootWidgetset extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + // Nothing here + } + + @Override + public String getTestDescription() { + return "This root should never load, as the widgetset can not be loaded"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(7885); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/root/UriFragmentTest.html b/tests/testbench/com/vaadin/tests/components/root/UriFragmentTest.html new file mode 100644 index 0000000000..d4704fea65 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/UriFragmentTest.html @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.root.UriFragmentTest?restartApplication#urifragment</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Current URI fragment: urifragment</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentsrootUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Current URI fragment: test</td> +</tr> +<tr> + <td>runScript</td> + <td>history.back()</td> + <td></td> +</tr> +<tr> + <td>pause</td> + <td></td> + <td>1000</td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Current URI fragment: urifragment</td> +</tr> +<tr> + <td>runScript</td> + <td>history.forward()</td> + <td></td> +</tr> +<tr> + <td>pause</td> + <td></td> + <td>1000</td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentsrootUriFragmentTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Current URI fragment: test</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/root/UriFragmentTest.java b/tests/testbench/com/vaadin/tests/components/root/UriFragmentTest.java new file mode 100644 index 0000000000..6078161996 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/root/UriFragmentTest.java @@ -0,0 +1,49 @@ +package com.vaadin.tests.components.root; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; + +public class UriFragmentTest extends AbstractTestRoot { + + private final Label fragmentLabel = new Label(); + + @Override + protected void setup(WrappedRequest request) { + addComponent(fragmentLabel); + updateLabel(); + addListener(new FragmentChangedListener() { + public void fragmentChanged(FragmentChangedEvent event) { + updateLabel(); + } + }); + addComponent(new Button("Navigate to #test", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + setFragment("test"); + } + })); + } + + private void updateLabel() { + String fragment = getFragment(); + if (fragment == null) { + fragmentLabel.setValue("No URI fragment set"); + } else { + fragmentLabel.setValue("Current URI fragment: " + fragment); + } + } + + @Override + public String getTestDescription() { + return "URI fragment status should be known when the page is loaded and retained while navigating to different fragments or using the back and forward buttons."; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(8048); + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/select/MultiSelect.java b/tests/testbench/com/vaadin/tests/components/select/MultiSelect.java deleted file mode 100644 index d823d1fd10..0000000000 --- a/tests/testbench/com/vaadin/tests/components/select/MultiSelect.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.vaadin.tests.components.select; - -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Select; - -public class MultiSelect extends TestBase { - - @SuppressWarnings("deprecation") - @Override - protected void setup() { - Select selectComponent = new Select(); - selectComponent.setMultiSelect(true); - - String[] selection = { "One", "Hund", "Three" }; - for (String word : selection) { - selectComponent.addItem(word); - } - - addComponent(selectComponent); - } - - @Override - protected String getDescription() { - return "The select is in multi select mode and should be rendered as such"; - } - - @Override - protected Integer getTicketNumber() { - return 4553; - } - -} diff --git a/tests/testbench/com/vaadin/tests/components/select/SelectDisplaysOldValue.html b/tests/testbench/com/vaadin/tests/components/select/SelectDisplaysOldValue.html index 4594130bda..122e90e140 100644 --- a/tests/testbench/com/vaadin/tests/components/select/SelectDisplaysOldValue.html +++ b/tests/testbench/com/vaadin/tests/components/select/SelectDisplaysOldValue.html @@ -131,7 +131,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentsselectSelectDisplaysOldValue::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentsselectSelectDisplaysOldValue::/VVerticalLayout[0]/domChild[1]</td> <td>58,163</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/select/TwinColSelectTest.java b/tests/testbench/com/vaadin/tests/components/select/TwinColSelectTest.java index fef9c4172d..031a7e9d3d 100644 --- a/tests/testbench/com/vaadin/tests/components/select/TwinColSelectTest.java +++ b/tests/testbench/com/vaadin/tests/components/select/TwinColSelectTest.java @@ -32,7 +32,6 @@ public class TwinColSelectTest extends AbstractSelectTestCase<TwinColSelect> { } }; - @Override protected Class<TwinColSelect> getTestClass() { return TwinColSelect.class; diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/AbstractSplitPanelTest.java b/tests/testbench/com/vaadin/tests/components/splitpanel/AbstractSplitPanelTest.java index d633618ef4..1f7b6b7cbe 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/AbstractSplitPanelTest.java +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/AbstractSplitPanelTest.java @@ -1,13 +1,15 @@ package com.vaadin.tests.components.splitpanel; import com.vaadin.terminal.Sizeable; -import com.vaadin.tests.components.AbstractLayoutTest; +import com.vaadin.terminal.Sizeable.Unit; +import com.vaadin.tests.components.AbstractComponentContainerTest; import com.vaadin.ui.AbstractSplitPanel; import com.vaadin.ui.AbstractSplitPanel.SplitterClickEvent; import com.vaadin.ui.AbstractSplitPanel.SplitterClickListener; public abstract class AbstractSplitPanelTest<T extends AbstractSplitPanel> - extends AbstractLayoutTest<T> implements SplitterClickListener { + extends AbstractComponentContainerTest<T> implements + SplitterClickListener { private Command<T, Boolean> splitterClickListenerCommand = new Command<T, Boolean>() { @@ -55,7 +57,7 @@ public abstract class AbstractSplitPanelTest<T extends AbstractSplitPanel> private boolean reverse = false; private int position; - private int unit; + private Unit unit; private String posString; public SplitPosition(String pos) { @@ -67,10 +69,10 @@ public abstract class AbstractSplitPanelTest<T extends AbstractSplitPanel> if (pos.endsWith("px")) { position = Integer.parseInt(pos.substring(0, pos.length() - 2)); - unit = Sizeable.UNITS_PIXELS; + unit = Sizeable.Unit.PIXELS; } else if (pos.endsWith("%")) { position = Integer.parseInt(pos.substring(0, pos.length() - 1)); - unit = Sizeable.UNITS_PERCENTAGE; + unit = Sizeable.Unit.PERCENTAGE; } else { throw new RuntimeException("Could not parse " + pos); } diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelBasicStates.html b/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelBasicStates.html index 8e829b2d7a..82229773d0 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelBasicStates.html +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelBasicStates.html @@ -86,7 +86,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::Root/VOverlay[2]/VMenuBar[0]#item2</td> + <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::Root/VOverlay[2]/VMenuBar[0]#item3</td> <td>38,9</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelSplitterClick.html b/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelSplitterClick.html index 3d3fcc5939..e8be62015f 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelSplitterClick.html +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/HorizontalSplitPanelSplitterClick.html @@ -46,7 +46,7 @@ <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::PID_SLog_row_0</td> - <td>1. SplitterClickEvent: left at -1,-1</td> + <td>1. SplitterClickEvent: left at 0,0</td> </tr> <tr> <td>screenCapture</td> @@ -61,7 +61,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::Root/VOverlay[0]/VMenuBar[0]#item6</td> + <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::Root/VOverlay[0]/VMenuBar[0]#item5</td> <td>73,7</td> </tr> <tr> @@ -78,19 +78,18 @@ <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::PID_StestComponent/domChild[0]/domChild[2]/domChild[0]</td> - <td>0,0</td> + <td>10,15</td> </tr> <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentssplitpanelHorizontalSplitPanels::PID_SLog_row_0</td> - <td>3. SplitterClickEvent: left at -1,-1</td> + <td>3. SplitterClickEvent: left at 10,15</td> </tr> <tr> <td>screenCapture</td> <td></td> <td>reverseSplitterClicked</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelExtraScrollbars.java b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelExtraScrollbars.java index a7cb1a857a..d4716433b7 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelExtraScrollbars.java +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelExtraScrollbars.java @@ -8,7 +8,7 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.NativeButton; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; public class SplitPanelExtraScrollbars extends AbstractTestCase implements ClickListener { @@ -32,7 +32,7 @@ public class SplitPanelExtraScrollbars extends AbstractTestCase implements sp.setSecondComponent(hl); hl.addComponent(b); - Window w = new Window("Test", sp); + LegacyWindow w = new LegacyWindow("Test", sp); setMainWindow(w); } diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelReversePosition.java b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelReversePosition.java index 107635e989..ef17a3c668 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelReversePosition.java +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelReversePosition.java @@ -8,7 +8,7 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; -import com.vaadin.ui.TextField; +import com.vaadin.ui.TextArea; import com.vaadin.ui.VerticalSplitPanel; public class SplitPanelReversePosition extends TestBase { @@ -31,9 +31,9 @@ public class SplitPanelReversePosition extends TestBase { } }); - TextField field = new TextField(""); - field.setSizeFull(); - hsplit.addComponent(field); + TextArea area = new TextArea(""); + area.setSizeFull(); + hsplit.addComponent(area); final VerticalSplitPanel vsplit = new VerticalSplitPanel(); vsplit.setSizeFull(); @@ -48,13 +48,13 @@ public class SplitPanelReversePosition extends TestBase { addComponent(hsplit); - field = new TextField(""); - field.setSizeFull(); - vsplit.addComponent(field); + area = new TextArea(""); + area.setSizeFull(); + vsplit.addComponent(area); - field = new TextField(""); - field.setSizeFull(); - vsplit.addComponent(field); + area = new TextArea(""); + area.setSizeFull(); + vsplit.addComponent(area); HorizontalLayout buttons = new HorizontalLayout(); buttons.setSpacing(true); diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelSplitterWidth.java b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelSplitterWidth.java index 49a5915999..5fad68fef5 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelSplitterWidth.java +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelSplitterWidth.java @@ -4,9 +4,9 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.HorizontalSplitPanel; +import com.vaadin.ui.Notification; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window.Notification; public class SplitPanelSplitterWidth extends TestBase { diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWidthOnResize.java b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWidthOnResize.java index 4e6a7730e7..e80ad29426 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWidthOnResize.java +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWidthOnResize.java @@ -5,9 +5,9 @@ import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.NativeButton; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class SplitPanelWidthOnResize extends AbstractTestCase { @@ -15,7 +15,7 @@ public class SplitPanelWidthOnResize extends AbstractTestCase { public void init() { VerticalLayout layout = new VerticalLayout(); layout.setSizeFull(); - Window w = new Window("", layout); + LegacyWindow w = new LegacyWindow("", layout); setMainWindow(w); HorizontalSplitPanel splitPanel = new HorizontalSplitPanel(); Button button = new NativeButton("A huge button"); diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanels.java b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanels.java deleted file mode 100644 index e0a4c19836..0000000000 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanels.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.vaadin.tests.components.splitpanel; - -import java.util.LinkedHashMap; - -import com.vaadin.ui.SplitPanel; - -@SuppressWarnings("deprecation") -public class SplitPanels extends AbstractSplitPanelTest<SplitPanel> { - - private Command<SplitPanel, Integer> orientationCommand = new Command<SplitPanel, Integer>() { - - public void execute(SplitPanel c, Integer value, Object data) { - c.setOrientation(value); - } - }; - - @Override - protected Class<SplitPanel> getTestClass() { - return SplitPanel.class; - } - - @Override - protected void createActions() { - super.createActions(); - createOrientationSelect(CATEGORY_FEATURES); - - } - - private void createOrientationSelect(String category) { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Horizontal", SplitPanel.ORIENTATION_HORIZONTAL); - options.put("Vertical", SplitPanel.ORIENTATION_VERTICAL); - createSelectAction("Orientation", category, options, "Horizontal", - orientationCommand); - - } -} diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelBasicStates.html b/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelBasicStates.html index 6e651adcda..cf67caccb7 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelBasicStates.html +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelBasicStates.html @@ -86,7 +86,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::Root/VOverlay[2]/VMenuBar[0]#item2</td> + <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::Root/VOverlay[2]/VMenuBar[0]#item3</td> <td>38,9</td> </tr> <tr> @@ -208,7 +208,6 @@ <td></td> <td>enabled</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelSplitterClick.html b/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelSplitterClick.html index ed5f191a65..d8a101b0a5 100644 --- a/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelSplitterClick.html +++ b/tests/testbench/com/vaadin/tests/components/splitpanel/VerticalSplitPanelSplitterClick.html @@ -46,7 +46,7 @@ <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::PID_SLog_row_0</td> - <td>1. SplitterClickEvent: left at -1,-1</td> + <td>1. SplitterClickEvent: left at 0,0</td> </tr> <tr> <td>screenCapture</td> @@ -61,7 +61,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::Root/VOverlay[0]/VMenuBar[0]#item6</td> + <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::Root/VOverlay[0]/VMenuBar[0]#item5</td> <td>73,7</td> </tr> <tr> @@ -78,19 +78,18 @@ <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::PID_StestComponent/domChild[0]/domChild[2]/domChild[0]</td> - <td>0,0</td> + <td>12,13</td> </tr> <tr> <td>assertText</td> <td>vaadin=runcomvaadintestscomponentssplitpanelVerticalSplitPanels::PID_SLog_row_0</td> - <td>3. SplitterClickEvent: left at -1,-1</td> + <td>3. SplitterClickEvent: left at 12,13</td> </tr> <tr> <td>screenCapture</td> <td></td> <td>reverseSplitterClicked</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/table/ColumnHeaderAlignments.java b/tests/testbench/com/vaadin/tests/components/table/ColumnHeaderAlignments.java index 0c625f1c5d..fdcb458a6a 100644 --- a/tests/testbench/com/vaadin/tests/components/table/ColumnHeaderAlignments.java +++ b/tests/testbench/com/vaadin/tests/components/table/ColumnHeaderAlignments.java @@ -4,8 +4,6 @@ import com.vaadin.data.Item; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Select; @@ -37,14 +35,14 @@ public class ColumnHeaderAlignments extends TestBase { } }); addComponent(theme); - CheckBox footers = new CheckBox("Show footers", new ClickListener() { - public void buttonClick(ClickEvent event) { - fooTable.setFooterVisible((Boolean) event.getButton() - .getValue()); - barTable.setFooterVisible((Boolean) event.getButton() - .getValue()); - bazTable.setFooterVisible((Boolean) event.getButton() - .getValue()); + CheckBox footers = new CheckBox("Show footers"); + footers.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean visible = (Boolean) event.getProperty().getValue(); + fooTable.setFooterVisible(visible); + barTable.setFooterVisible(visible); + bazTable.setFooterVisible(visible); } }); footers.setImmediate(true); diff --git a/tests/testbench/com/vaadin/tests/components/table/DoublesInTable.java b/tests/testbench/com/vaadin/tests/components/table/DoublesInTable.java new file mode 100644 index 0000000000..c048c770fa --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/table/DoublesInTable.java @@ -0,0 +1,277 @@ +package com.vaadin.tests.components.table; + +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.util.Date; +import java.util.Locale; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.StringToNumberConverter; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Table; + +public class DoublesInTable extends TestBase { + BeanItemContainer<Person> personBeanItemContainer = new BeanItemContainer<Person>( + Person.class); + + private Table table; + + private Log log = new Log(5); + + private ComboBox localeSelect; + + private CheckBox useCustomConverters; + + private CheckBox editMode; + + @Override + protected void setup() { + editMode = new CheckBox("Edit mode"); + editMode.setImmediate(true); + editMode.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + table.setEditable(editMode.getValue()); + + } + }); + + useCustomConverters = new CheckBox("Use custom converters"); + useCustomConverters.setImmediate(true); + useCustomConverters.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + recreateTable(); + } + }); + + localeSelect = createLocaleSelect(); + personBeanItemContainer = createContainer(100); + addComponent(log); + addComponent(localeSelect); + addComponent(useCustomConverters); + addComponent(editMode); + recreateTable(); + + } + + private ComboBox createLocaleSelect() { + ComboBox cb = new ComboBox(); + cb.setNullSelectionAllowed(false); + for (Locale l : Locale.getAvailableLocales()) { + cb.addItem(l); + } + cb.setImmediate(true); + cb.setValue(Locale.US); + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + recreateTable(); + } + }); + return cb; + } + + protected void recreateTable() { + Table newTable = createTable(useCustomConverters.getValue(), + (Locale) localeSelect.getValue()); + newTable.setEditable(editMode.getValue()); + if (table == null) { + addComponent(newTable); + } else { + replaceComponent(table, newTable); + } + table = newTable; + } + + private static BeanItemContainer<Person> createContainer(int nr) { + BeanItemContainer<Person> bic = new BeanItemContainer<Person>( + Person.class); + for (int i = 1; i <= nr; i++) { + Person p = new Person(); + p.setFirstName("First " + i); + p.setLastName("Last " + i); + p.setAge(i); + p.setDeceased((i % 5 - 2) == 0); + p.setEmail("person" + i + "@mail.com"); + p.setRent(new BigDecimal(i * 1250.25)); + p.setSalary(3000 + i); + p.setSex((i % 4) == 0 ? Sex.MALE : Sex.FEMALE); + p.setBirthDate(new Date(2011 - 1900 - p.getAge(), 11 - 1, 24)); + if (i % 42 == 0) { + p.setSex(Sex.UNKNOWN); + } + String city = "City " + (i / 10); + Country country = Country.FINLAND; + Address address = new Address("Street " + i, 12345 + i * 2, city, + country); + p.setAddress(address); + bic.addBean(p); + } + + return bic; + } + + protected Table createTable(boolean useCustomConverters, Locale locale) { + Table t = new Table("Persons"); + t.setLocale(locale); + t.setContainerDataSource(personBeanItemContainer); + t.setSortDisabled(false); + if (useCustomConverters) { + addConverters(t); + } + t.setSelectable(true); + t.setImmediate(true); + t.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + log.log("Value is now: " + event.getProperty().getValue()); + + } + }); + return t; + } + + private void addConverters(Table t) { + t.setConverter("sex", new Converter<String, Sex>() { + + public Sex convertToModel(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + // not used in this test - Table only converts to presentation + return null; + } + + public String convertToPresentation(Sex value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + value = Sex.UNKNOWN; + } + return value.getStringRepresentation(); + } + + public Class<Sex> getModelType() { + return Sex.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + }); + t.setConverter("deceased", new Converter<String, Boolean>() { + + public Boolean convertToModel(String value, Locale locale) { + // not used in this test - Table only converts from source to + // target + return null; + } + + public String convertToPresentation(Boolean value, Locale locale) { + if (value == null || value) { + return "YES, DEAD!"; + } else { + return "-"; + } + } + + public Class<Boolean> getModelType() { + return Boolean.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + }); + t.setConverter("age", new Converter<String, Integer>() { + + public Integer convertToModel(String value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + // not used in this test - Table only converts from source to + // target + return null; + } + + public String convertToPresentation(Integer value, Locale locale) + throws com.vaadin.data.util.converter.Converter.ConversionException { + if (value == null) { + return null; + } + if (value < 3) { + return value + " (baby)"; + } else if (value < 7) { + return value + " (kid)"; + } else if (value < 18) { + return value + " (young)"; + } else { + return value + ""; + } + } + + public Class<Integer> getModelType() { + return Integer.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + }); + t.setConverter("address", new Converter<String, Address>() { + + public Address convertToModel(String value, Locale locale) + throws ConversionException { + // not used in this test - Table only converts to presentation + return null; + } + + public String convertToPresentation(Address value, Locale locale) + throws ConversionException { + return value.getStreetAddress() + ", " + value.getCity() + " (" + + value.getCountry() + ")"; + } + + public Class<Address> getModelType() { + return Address.class; + } + + public Class<String> getPresentationType() { + return String.class; + } + + }); + + t.setConverter("rent", new StringToNumberConverter() { + @Override + protected NumberFormat getFormat(Locale locale) { + return NumberFormat.getCurrencyInstance(locale); + // DecimalFormat df = new DecimalFormat(); + // df.setDecimalSeparatorAlwaysShown(true); + // df.setGroupingUsed(true); + // df.setMinimumFractionDigits(2); + // df.setMaximumFractionDigits(2); + // return df; + } + }); + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/table/EditableModeChange.java b/tests/testbench/com/vaadin/tests/components/table/EditableModeChange.java index 5f64dec443..acb866a1da 100644 --- a/tests/testbench/com/vaadin/tests/components/table/EditableModeChange.java +++ b/tests/testbench/com/vaadin/tests/components/table/EditableModeChange.java @@ -74,7 +74,7 @@ public class EditableModeChange extends TestBase { private class ItemFieldFactory extends DefaultFieldFactory { @Override - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { if (selectionEvent != null) { if ((selectionEvent.getItemId().equals(itemId)) diff --git a/tests/testbench/com/vaadin/tests/components/table/EditableTableLeak.java b/tests/testbench/com/vaadin/tests/components/table/EditableTableLeak.java index 6561ff0076..08938c079a 100644 --- a/tests/testbench/com/vaadin/tests/components/table/EditableTableLeak.java +++ b/tests/testbench/com/vaadin/tests/components/table/EditableTableLeak.java @@ -7,6 +7,8 @@ import java.io.Serializable; import java.util.HashMap; import com.vaadin.data.Container; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.TestUtils; import com.vaadin.ui.Button; @@ -17,13 +19,14 @@ import com.vaadin.ui.Component; import com.vaadin.ui.DefaultFieldFactory; import com.vaadin.ui.Field; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Table; public class EditableTableLeak extends TestBase { private final Table table = new Table("ISO-3166 Country Codes and flags"); private final CheckBox useFieldFactory = new CheckBox( "Use a caching TableFieldFactory"); - private final Label sizeLabel = new Label("", Label.CONTENT_XHTML); + private final Label sizeLabel = new Label("", ContentMode.XHTML); private long size = 0; @@ -57,10 +60,10 @@ public class EditableTableLeak extends TestBase { } private static class CachingFieldFactory extends DefaultFieldFactory { - private final HashMap<Object, HashMap<Object, Field>> cache = new HashMap<Object, HashMap<Object, Field>>(); + private final HashMap<Object, HashMap<Object, Field<?>>> cache = new HashMap<Object, HashMap<Object, Field<?>>>(); @Override - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { if (cache.containsKey(itemId)) { if (cache.get(itemId) != null @@ -68,10 +71,10 @@ public class EditableTableLeak extends TestBase { return cache.get(itemId).get(propertyId); } } - Field f = super.createField(container, itemId, propertyId, + Field<?> f = super.createField(container, itemId, propertyId, uiContext); if (!cache.containsKey(itemId)) { - cache.put(itemId, new HashMap<Object, Field>()); + cache.put(itemId, new HashMap<Object, Field<?>>()); } cache.get(itemId).put(propertyId, f); return f; @@ -83,10 +86,10 @@ public class EditableTableLeak extends TestBase { protected void setup() { addComponent(useFieldFactory); useFieldFactory.setImmediate(true); - useFieldFactory.addListener(new Button.ClickListener() { + useFieldFactory.addListener(new ValueChangeListener() { - public void buttonClick(ClickEvent event) { - if ((Boolean) useFieldFactory.getValue()) { + public void valueChange(ValueChangeEvent event) { + if (useFieldFactory.getValue()) { table.setTableFieldFactory(new CachingFieldFactory()); } else { table.setTableFieldFactory(DefaultFieldFactory.get()); diff --git a/tests/testbench/com/vaadin/tests/components/table/Footer.java b/tests/testbench/com/vaadin/tests/components/table/Footer.java index d6a9853fff..c962ce8468 100644 --- a/tests/testbench/com/vaadin/tests/components/table/Footer.java +++ b/tests/testbench/com/vaadin/tests/components/table/Footer.java @@ -51,7 +51,7 @@ public class Footer extends TestBase { visible.setImmediate(true); visible.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - table.setFooterVisible(visible.booleanValue()); + table.setFooterVisible((Boolean) visible.getValue()); } }); diff --git a/tests/testbench/com/vaadin/tests/components/table/FooterClick.java b/tests/testbench/com/vaadin/tests/components/table/FooterClick.java index b92d6ef362..2ae663986b 100644 --- a/tests/testbench/com/vaadin/tests/components/table/FooterClick.java +++ b/tests/testbench/com/vaadin/tests/components/table/FooterClick.java @@ -2,11 +2,11 @@ package com.vaadin.tests.components.table; import com.vaadin.data.Container; import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.util.IndexedContainer; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Table; import com.vaadin.ui.Table.FooterClickEvent; @@ -43,7 +43,7 @@ public class FooterClick extends TestBase { // Add a footer click listener table.addListener(new Table.FooterClickListener() { public void footerClick(FooterClickEvent event) { - columnField.setValue(event.getPropertyId()); + columnField.setValue(String.valueOf(event.getPropertyId())); log.log("Clicked on footer: " + event.getPropertyId()); } }); @@ -51,10 +51,10 @@ public class FooterClick extends TestBase { CheckBox immediateCheckbox = new CheckBox("Immediate"); immediateCheckbox.setImmediate(true); immediateCheckbox.setValue(table.isImmediate()); - immediateCheckbox.addListener(new ClickListener() { + immediateCheckbox.addListener(new Property.ValueChangeListener() { - public void buttonClick(ClickEvent event) { - table.setImmediate(event.getButton().booleanValue()); + public void valueChange(ValueChangeEvent event) { + table.setImmediate((Boolean) event.getProperty().getValue()); } }); @@ -62,13 +62,14 @@ public class FooterClick extends TestBase { "Column reordering allowed"); columnReorderingCheckbox.setImmediate(true); columnReorderingCheckbox.setValue(table.isColumnReorderingAllowed()); - columnReorderingCheckbox.addListener(new ClickListener() { - - public void buttonClick(ClickEvent event) { - table.setColumnReorderingAllowed(event.getButton() - .booleanValue()); - } - }); + columnReorderingCheckbox + .addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + table.setColumnReorderingAllowed((Boolean) event + .getProperty().getValue()); + } + }); addComponent(immediateCheckbox); addComponent(columnReorderingCheckbox); diff --git a/tests/testbench/com/vaadin/tests/components/table/HeaderClick.java b/tests/testbench/com/vaadin/tests/components/table/HeaderClick.java index 3cb11781b1..970618374e 100644 --- a/tests/testbench/com/vaadin/tests/components/table/HeaderClick.java +++ b/tests/testbench/com/vaadin/tests/components/table/HeaderClick.java @@ -2,10 +2,10 @@ package com.vaadin.tests.components.table; import com.vaadin.data.Container; import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.util.IndexedContainer; import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Table; import com.vaadin.ui.Table.HeaderClickEvent; @@ -29,27 +29,27 @@ public class HeaderClick extends TestBase { // Add a header click listener table.addListener(new Table.HeaderClickListener() { public void headerClick(HeaderClickEvent event) { - columnField.setValue(event.getPropertyId()); + columnField.setValue(String.valueOf(event.getPropertyId())); } }); CheckBox immediateCheckbox = new CheckBox("Immediate"); immediateCheckbox.setImmediate(true); immediateCheckbox.setValue(table.isImmediate()); - immediateCheckbox.addListener(new ClickListener() { + immediateCheckbox.addListener(new Property.ValueChangeListener() { - public void buttonClick(ClickEvent event) { - table.setImmediate(event.getButton().booleanValue()); + public void valueChange(ValueChangeEvent event) { + table.setImmediate((Boolean) event.getProperty().getValue()); } }); CheckBox sortEnabledCheckbox = new CheckBox("Sortable"); sortEnabledCheckbox.setImmediate(true); sortEnabledCheckbox.setValue(!table.isSortDisabled()); - sortEnabledCheckbox.addListener(new ClickListener() { + sortEnabledCheckbox.addListener(new Property.ValueChangeListener() { - public void buttonClick(ClickEvent event) { - table.setSortDisabled(!event.getButton().booleanValue()); + public void valueChange(ValueChangeEvent event) { + table.setSortDisabled(!(Boolean) event.getProperty().getValue()); } }); @@ -57,13 +57,14 @@ public class HeaderClick extends TestBase { "Column reordering allowed"); columnReorderingCheckbox.setImmediate(true); columnReorderingCheckbox.setValue(table.isColumnReorderingAllowed()); - columnReorderingCheckbox.addListener(new ClickListener() { - - public void buttonClick(ClickEvent event) { - table.setColumnReorderingAllowed(event.getButton() - .booleanValue()); - } - }); + columnReorderingCheckbox + .addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + table.setColumnReorderingAllowed((Boolean) event + .getProperty().getValue()); + } + }); addComponent(immediateCheckbox); addComponent(sortEnabledCheckbox); diff --git a/tests/testbench/com/vaadin/tests/components/table/HeaderUpdateWhenNoRows.java b/tests/testbench/com/vaadin/tests/components/table/HeaderUpdateWhenNoRows.java index bf1f9ca883..f1e4e09d57 100644 --- a/tests/testbench/com/vaadin/tests/components/table/HeaderUpdateWhenNoRows.java +++ b/tests/testbench/com/vaadin/tests/components/table/HeaderUpdateWhenNoRows.java @@ -1,7 +1,8 @@ package com.vaadin.tests.components.table; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Table; @@ -16,16 +17,17 @@ public class HeaderUpdateWhenNoRows extends TestBase { table.setHeight("100px"); table.setImmediate(true); - CheckBox showHeaders = new CheckBox("Show headers", - new CheckBox.ClickListener() { - public void buttonClick(ClickEvent event) { - if (event.getButton().booleanValue()) { - table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID); - } else { - table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); - } - } - }); + final CheckBox showHeaders = new CheckBox("Show headers"); + showHeaders.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + if (showHeaders.getValue()) { + table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID); + } else { + table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); + } + } + }); showHeaders.setImmediate(true); showHeaders.setValue(true); diff --git a/tests/testbench/com/vaadin/tests/components/table/HugeRowCount.java b/tests/testbench/com/vaadin/tests/components/table/HugeRowCount.java index 5cd9f964a3..3478750622 100644 --- a/tests/testbench/com/vaadin/tests/components/table/HugeRowCount.java +++ b/tests/testbench/com/vaadin/tests/components/table/HugeRowCount.java @@ -20,7 +20,7 @@ public class HugeRowCount extends TestBase { container.setSize(100000); final TextField tf = new TextField("Rows"); - tf.setValue(100000); + tf.setValue(String.valueOf(100000)); tf.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { container.setSize(Integer.parseInt(tf.getValue().toString())); diff --git a/tests/testbench/com/vaadin/tests/components/table/ItemClickEvents.html b/tests/testbench/com/vaadin/tests/components/table/ItemClickEvents.html index 2c40672c0d..1d7b2b6bf9 100644 --- a/tests/testbench/com/vaadin/tests/components/table/ItemClickEvents.html +++ b/tests/testbench/com/vaadin/tests/components/table/ItemClickEvents.html @@ -130,12 +130,12 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableItemClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[5]</td> + <td>vaadin=runcomvaadintestscomponentstableItemClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[5]</td> <td>195,142</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableItemClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[5]</td> + <td>vaadin=runcomvaadintestscomponentstableItemClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[5]</td> <td>582,1</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/table/LabelEmbeddedClickThroughForTable.java b/tests/testbench/com/vaadin/tests/components/table/LabelEmbeddedClickThroughForTable.java index a54c3ce447..1cfb1ee5e5 100644 --- a/tests/testbench/com/vaadin/tests/components/table/LabelEmbeddedClickThroughForTable.java +++ b/tests/testbench/com/vaadin/tests/components/table/LabelEmbeddedClickThroughForTable.java @@ -8,6 +8,7 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Component; import com.vaadin.ui.Embedded; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Table; public class LabelEmbeddedClickThroughForTable extends TestBase { @@ -36,7 +37,7 @@ public class LabelEmbeddedClickThroughForTable extends TestBase { item.getItemProperty("Column 1").setValue("String A"); item.getItemProperty("Column 2").setValue(new Label("Label A")); item.getItemProperty("Column 3").setValue( - new Label("<b>Label A</b>", Label.CONTENT_XHTML)); + new Label("<b>Label A</b>", ContentMode.XHTML)); item.getItemProperty("Column 4").setValue( new Embedded("An embedded image", new ThemeResource( "../runo/icons/32/ok.png"))); @@ -48,7 +49,7 @@ public class LabelEmbeddedClickThroughForTable extends TestBase { .setValue( new Label( "<a style=\"color: blue\" href=\"javascript:false\">Label A</a>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); item.getItemProperty("Column 4").setValue( new Embedded("", new ThemeResource( "../runo/icons/32/cancel.png"))); diff --git a/tests/testbench/com/vaadin/tests/components/table/LongMultiselect.java b/tests/testbench/com/vaadin/tests/components/table/LongMultiselect.java index 4db9b69070..07925db05c 100644 --- a/tests/testbench/com/vaadin/tests/components/table/LongMultiselect.java +++ b/tests/testbench/com/vaadin/tests/components/table/LongMultiselect.java @@ -12,23 +12,22 @@ import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; public class LongMultiselect extends TestBase { - + private enum ItemProperty { - COLUMN1, - COLUMN2 + COLUMN1, COLUMN2 } - + @Override protected void setup() { - VerticalLayout layout = generateLayout(); - addComponent(layout); - layout.setSizeFull(); + VerticalLayout layout = generateLayout(); + addComponent(layout); + layout.setSizeFull(); } - private VerticalLayout generateLayout() { - VerticalLayout layout = new VerticalLayout(); + private VerticalLayout generateLayout() { + VerticalLayout layout = new VerticalLayout(); - final Table table = new Table("Ticket #8264 table"); + final Table table = new Table("Ticket #8264 table"); layout.addComponent(table); table.setWidth("200px"); table.setHeight("170px"); @@ -39,17 +38,18 @@ public class LongMultiselect extends TestBase { // Create example data table.addContainerProperty(ItemProperty.COLUMN1, String.class, null); table.addContainerProperty(ItemProperty.COLUMN2, String.class, null); - for (int i=1;i<100;i++) { - table.addItem(new String[]{"Item " + i, null}, i); + for (int i = 1; i < 100; i++) { + table.addItem(new String[] { "Item " + i, null }, i); } - //Add action button + // Add action button layout.addComponent(new Button("Do It", new Button.ClickListener() { public void buttonClick(Button.ClickEvent event) { // Set ItemProperty.COLUMN2 for all selected values of table - Collection selectedIds = (Collection)table.getValue(); + Collection selectedIds = (Collection) table.getValue(); for (final Object itemId : selectedIds) { - final Property p = table.getItem(itemId).getItemProperty(ItemProperty.COLUMN2); + final Property p = table.getItem(itemId).getItemProperty( + ItemProperty.COLUMN2); if (p.getValue() instanceof String) { p.setValue(null); } else { @@ -58,17 +58,17 @@ public class LongMultiselect extends TestBase { } } })); - + return layout; - } + } - @Override - protected String getDescription() { - return "Multiselecting 94 rows (from \"item 5\" to \"item 98\") and modifying second column of each row selected (press Do It). This should work (update the 2nd column) and not cause JS exception."; - } + @Override + protected String getDescription() { + return "Multiselecting 94 rows (from \"item 5\" to \"item 98\") and modifying second column of each row selected (press Do It). This should work (update the 2nd column) and not cause JS exception."; + } - @Override - protected Integer getTicketNumber() { - return 8264; - } + @Override + protected Integer getTicketNumber() { + return 8264; + } } diff --git a/tests/testbench/com/vaadin/tests/components/table/ModifyContainerProperty.html b/tests/testbench/com/vaadin/tests/components/table/ModifyContainerProperty.html index 93d97cd698..33318c9a95 100644 --- a/tests/testbench/com/vaadin/tests/components/table/ModifyContainerProperty.html +++ b/tests/testbench/com/vaadin/tests/components/table/ModifyContainerProperty.html @@ -22,9 +22,9 @@ <td></td> </tr> <tr> - <td>assertTextNotPresent</td> - <td>bar</td> + <td>screenCapture</td> <td></td> + <td>bar-hidden</td> </tr> <tr> <td>click</td> diff --git a/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithNotIdentityEqualIds.java b/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithNotIdentityEqualIds.java index 62fd53d769..9178b284f3 100644 --- a/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithNotIdentityEqualIds.java +++ b/tests/testbench/com/vaadin/tests/components/table/MultiSelectWithNotIdentityEqualIds.java @@ -20,8 +20,8 @@ public class MultiSelectWithNotIdentityEqualIds extends TestBase { t.setImmediate(true); t.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - t.getWindow().showNotification( - "Selected: " + event.getProperty()); + t.getRoot() + .showNotification("Selected: " + event.getProperty()); } }); diff --git a/tests/testbench/com/vaadin/tests/components/table/PropertyValueChange.java b/tests/testbench/com/vaadin/tests/components/table/PropertyValueChange.java index 5975137976..311c3cf3c1 100644 --- a/tests/testbench/com/vaadin/tests/components/table/PropertyValueChange.java +++ b/tests/testbench/com/vaadin/tests/components/table/PropertyValueChange.java @@ -39,17 +39,18 @@ public class PropertyValueChange extends TestBase { // Also use column generator in test, to ensure it is possible to build // columns that update automatically. ColumnGenerator multiplier = new ColumnGenerator() { - private int getMultipliedValue(Property p) { - int i = ((Integer) p.getValue()).intValue(); + private int getMultipliedValue(Property<Integer> p) { + int i = p.getValue().intValue(); return i * 3; } public Component generateCell(Table source, Object itemId, Object columnId) { final Label l = new Label(); - final Property integer = source.getContainerProperty(itemId, - "integer"); - l.setValue(getMultipliedValue(integer)); + @SuppressWarnings("unchecked") + final Property<Integer> integer = (Property<Integer>) source + .getContainerProperty(itemId, "integer"); + l.setValue(String.valueOf(getMultipliedValue(integer))); // we must hook value change listener to ensure updates in all use // cases (eg. edit mode) @@ -57,7 +58,7 @@ public class PropertyValueChange extends TestBase { Property.ValueChangeNotifier notifier = (Property.ValueChangeNotifier) integer; notifier.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - l.setValue(getMultipliedValue(integer)); + l.setValue(String.valueOf(getMultipliedValue(integer))); } }); } @@ -134,7 +135,7 @@ class MyFieldFactory extends DefaultFieldFactory { } @Override - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { if (propertyId.equals("text")) { // replace text fields with comboboxes diff --git a/tests/testbench/com/vaadin/tests/components/table/ScrollCausesRequestLoop.java b/tests/testbench/com/vaadin/tests/components/table/ScrollCausesRequestLoop.java index 1916dcd0d7..c140e7e412 100644 --- a/tests/testbench/com/vaadin/tests/components/table/ScrollCausesRequestLoop.java +++ b/tests/testbench/com/vaadin/tests/components/table/ScrollCausesRequestLoop.java @@ -7,14 +7,14 @@ import com.vaadin.data.util.BeanItemContainer; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Person; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; public class ScrollCausesRequestLoop extends TestBase { @Override protected void setup() { - setMainWindow(new Window("", new TestView())); + setMainWindow(new LegacyWindow("", new TestView())); } @Override diff --git a/tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java b/tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java index fe99cfaf2a..3b0234d805 100644 --- a/tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java +++ b/tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java @@ -7,15 +7,12 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class ScrollDetachSynchronization extends TestBase { @Override public void setup() { - Window mainWindow = new Window("Synctest Application"); - mainWindow.setContent(buildLayout()); - setMainWindow(mainWindow); + getMainWindow().setContent(buildLayout()); } @Override diff --git a/tests/testbench/com/vaadin/tests/components/table/SortLongTable.java b/tests/testbench/com/vaadin/tests/components/table/SortLongTable.java index cc9dec0965..15872aa849 100644 --- a/tests/testbench/com/vaadin/tests/components/table/SortLongTable.java +++ b/tests/testbench/com/vaadin/tests/components/table/SortLongTable.java @@ -1,9 +1,9 @@ package com.vaadin.tests.components.table; import com.vaadin.tests.components.AbstractTestCase; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class SortLongTable extends AbstractTestCase { @@ -11,7 +11,7 @@ public class SortLongTable extends AbstractTestCase { public void init() { final int NUMBER_OF_ROWS = 100; // Works with 10 - Window mainWindow = new Window("Table Sort Test"); + LegacyWindow mainWindow = new LegacyWindow("Table Sort Test"); mainWindow.setSizeFull(); setMainWindow(mainWindow); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableCacheBuildEfficiency.java b/tests/testbench/com/vaadin/tests/components/table/TableCacheBuildEfficiency.java index 220d5e8192..3c6445349a 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableCacheBuildEfficiency.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableCacheBuildEfficiency.java @@ -28,7 +28,7 @@ public class TableCacheBuildEfficiency extends TestBase { final Table table = new Table() { @Override - public Property getContainerProperty(Object itemId, + public Property<?> getContainerProperty(Object itemId, Object propertyId) { log("Fetched container property \"" + propertyId + "\" for item \"" + itemId + "\""); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.html b/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.html index 83a02ec44b..5b50eeba23 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.html +++ b/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.html @@ -18,82 +18,82 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>38,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>35,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>24,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>39,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>37,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>51,16</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>19,10</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>43,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>36,7</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>27,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>13,7</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>43,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>27,9</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>53,16</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>40,9</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>45,10</td> </tr> <tr> @@ -103,82 +103,82 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>39,7</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>37,6</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>33,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>17,9</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>49,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>53,9</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>21,12</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>32,13</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>45,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>22,10</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>28,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>15,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>35,5</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>26,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>55,13</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>22,7</td> </tr> <tr> @@ -188,82 +188,82 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>41,12</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>28,9</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>16,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>38,12</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>47,6</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>30,7</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>16,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>68,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>36,10</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>48,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>27,12</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>19,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>22,10</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>39,13</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>35,15</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> <td>19,15</td> </tr> <tr> @@ -273,82 +273,82 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>30,8</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>20,13</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>19,15</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[3]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>43,15</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[4]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>44,15</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[5]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>62,12</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[6]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>29,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[7]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>25,13</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[8]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>22,9</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[9]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>30,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[10]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>21,6</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[11]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>32,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[12]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>34,14</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[13]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>45,11</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[14]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>31,6</td> </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableClickValueChangeInteraction::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[15]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> <td>45,10</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.java b/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.java index 47216033e9..ff5aa89d84 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableClickValueChangeInteraction.java @@ -11,24 +11,21 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TableClickValueChangeInteraction extends TestBase { - final Window mainWindow = new Window(); - @Override public void setup() { - setMainWindow(mainWindow); + GridLayout grid = new GridLayout(4, 4); + grid.setSpacing(true); + grid.setMargin(true); - GridLayout layout = new GridLayout(4, 4); - layout.setSpacing(true); - layout.setMargin(true); - mainWindow.setContent(layout); + getLayout().removeAllComponents(); + getLayout().addComponent(grid); for (int i = 0; i < 16; ++i) { - mainWindow.addComponent(makeTable((i & 8) > 0, (i & 4) > 0, - (i & 2) > 0, (i & 1) > 0)); + grid.addComponent(makeTable((i & 8) > 0, (i & 4) > 0, (i & 2) > 0, + (i & 1) > 0)); } } @@ -72,7 +69,8 @@ public class TableClickValueChangeInteraction extends TestBase { if (listenValueChanges) { table.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - valueChangeLabel.setValue("Value " + event.getProperty()); + valueChangeLabel.setValue("Value " + + event.getProperty().getValue()); } }); } diff --git a/tests/testbench/com/vaadin/tests/components/table/TableContextMenu.java b/tests/testbench/com/vaadin/tests/components/table/TableContextMenu.java index 20e198a138..16323e5024 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableContextMenu.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableContextMenu.java @@ -16,7 +16,7 @@ public class TableContextMenu extends TestBase { table.addActionHandler(new Action.Handler() { public void handleAction(Action action, Object sender, Object target) { - getLayout().getWindow().showNotification("Done that :-)"); + getLayout().getRoot().showNotification("Done that :-)"); } public Action[] getActions(Object target, Object sender) { diff --git a/tests/testbench/com/vaadin/tests/components/table/TableExtraScrollbars.java b/tests/testbench/com/vaadin/tests/components/table/TableExtraScrollbars.java index 8fde820749..010093bf8f 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableExtraScrollbars.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableExtraScrollbars.java @@ -4,9 +4,9 @@ import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; import com.vaadin.tests.components.AbstractTestCase; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TableExtraScrollbars extends AbstractTestCase { @@ -16,7 +16,7 @@ public class TableExtraScrollbars extends AbstractTestCase { @Override public void init() { setTheme("runo"); - Window w = new Window("Table scrollbars bug example"); + LegacyWindow w = new LegacyWindow("Table scrollbars bug example"); setMainWindow(w); VerticalLayout vl = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java b/tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java index f7d85f1a3c..bce96ebced 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java @@ -2,8 +2,8 @@ package com.vaadin.tests.components.table; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.CssLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; public class TableHeaderZoom extends TestBase { @@ -19,7 +19,7 @@ public class TableHeaderZoom extends TestBase { table.addItem(new Object[] { "" + i, "foo" }, i); } - Window main = getMainWindow(); + LegacyWindow main = getMainWindow(); main.setContent(new CssLayout()); main.addComponent(table); } diff --git a/tests/testbench/com/vaadin/tests/components/table/TableHeightWhenHidingHeaders.java b/tests/testbench/com/vaadin/tests/components/table/TableHeightWhenHidingHeaders.java index d0b7631f10..27b962cddd 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableHeightWhenHidingHeaders.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableHeightWhenHidingHeaders.java @@ -1,10 +1,11 @@ package com.vaadin.tests.components.table; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.AbstractTestCase; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; /** * Setting table height and setting column header mode as hidden leaves the body @@ -17,7 +18,7 @@ public class TableHeightWhenHidingHeaders extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window(); + LegacyWindow mainWindow = new LegacyWindow(); setMainWindow(mainWindow); final Table table = new Table("Test table"); @@ -30,24 +31,25 @@ public class TableHeightWhenHidingHeaders extends AbstractTestCase { table.addItem("1").getItemProperty("Name").setValue("Item 1"); table.addItem("2").getItemProperty("Name").setValue("Item 2"); - CheckBox showHeaders = new CheckBox("Show headers", - new CheckBox.ClickListener() { - public void buttonClick(ClickEvent event) { - if (event.getButton().booleanValue()) { - // table body height is now 77px, which together - // with header makes 100px - table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID); - } else { - table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); - // header disappears, but table body height stays at - // 77px - // and below the body is an empty area (same height - // as header would - // have) + CheckBox showHeaders = new CheckBox("Show headers"); + showHeaders.addListener(new ValueChangeListener() { - } - } - }); + public void valueChange(ValueChangeEvent event) { + if ((Boolean) event.getProperty().getValue()) { + // table body height is now 77px, which together + // with header makes 100px + table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID); + } else { + table.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); + // header disappears, but table body height stays at + // 77px + // and below the body is an empty area (same height + // as header would + // have) + + } + } + }); showHeaders.setValue(true); showHeaders.setImmediate(true); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableItemDescriptionGeneratorTest.java b/tests/testbench/com/vaadin/tests/components/table/TableItemDescriptionGeneratorTest.java index 2f53b91107..1f15b224dc 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableItemDescriptionGeneratorTest.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableItemDescriptionGeneratorTest.java @@ -4,69 +4,70 @@ import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; +import com.vaadin.ui.AbstractSelect.ItemDescriptionGenerator; import com.vaadin.ui.Component; -import com.vaadin.ui.Label; import com.vaadin.ui.Table; -import com.vaadin.ui.AbstractSelect.ItemDescriptionGenerator; import com.vaadin.ui.TextField; public class TableItemDescriptionGeneratorTest extends TestBase { - private final String COLUMN1_PROPERTY_ID = "Text - Cell description"; - private final String COLUMN2_PROPERTY_ID = "Text - Row description"; - private final String COLUMN3_PROPERTY_ID = "Widget"; - - @Override - protected void setup() { - final Table table = new Table(); - table.setDebugId("table"); - table.setContainerDataSource(createContainer()); - addComponent(table); - - table.setItemDescriptionGenerator(new ItemDescriptionGenerator() { - public String generateDescription(Component source, Object itemId, - Object propertyId) { - if(propertyId == null){ - return "Row description "+ itemId; - } else if(propertyId == COLUMN1_PROPERTY_ID) { - return "Cell description " + itemId +","+propertyId; - } - return null; - } - }); - - table.addGeneratedColumn(COLUMN3_PROPERTY_ID, new Table.ColumnGenerator() { - - public Component generateCell(Table source, Object itemId, Object columnId) { - TextField lbl = new TextField(); - lbl.setDescription("Textfields own description"); - return lbl; - } - }); - } + private final String COLUMN1_PROPERTY_ID = "Text - Cell description"; + private final String COLUMN2_PROPERTY_ID = "Text - Row description"; + private final String COLUMN3_PROPERTY_ID = "Widget"; + + @Override + protected void setup() { + final Table table = new Table(); + table.setDebugId("table"); + table.setContainerDataSource(createContainer()); + addComponent(table); + + table.setItemDescriptionGenerator(new ItemDescriptionGenerator() { + public String generateDescription(Component source, Object itemId, + Object propertyId) { + if (propertyId == null) { + return "Row description " + itemId; + } else if (propertyId == COLUMN1_PROPERTY_ID) { + return "Cell description " + itemId + "," + propertyId; + } + return null; + } + }); + + table.addGeneratedColumn(COLUMN3_PROPERTY_ID, + new Table.ColumnGenerator() { - @Override - protected String getDescription() { - return "Cells and rows should have tooltips"; - } + public Component generateCell(Table source, Object itemId, + Object columnId) { + TextField lbl = new TextField(); + lbl.setDescription("Textfields own description"); + return lbl; + } + }); + } + + @Override + protected String getDescription() { + return "Cells and rows should have tooltips"; + } + + @Override + protected Integer getTicketNumber() { + return 5414; + } - @Override - protected Integer getTicketNumber() { - return 5414; - } - - private Container createContainer() { + private Container createContainer() { IndexedContainer container = new IndexedContainer(); container.addContainerProperty(COLUMN1_PROPERTY_ID, String.class, ""); container.addContainerProperty(COLUMN2_PROPERTY_ID, String.class, ""); - // container.addContainerProperty(COLUMN3_PROPERTY_ID, String.class, ""); + // container.addContainerProperty(COLUMN3_PROPERTY_ID, String.class, + // ""); for (int i = 0; i < 5; i++) { Item item = container.addItem("item " + i); item.getItemProperty(COLUMN1_PROPERTY_ID).setValue("first" + i); item.getItemProperty(COLUMN2_PROPERTY_ID).setValue("middle" + i); - // item.getItemProperty(COLUMN3_PROPERTY_ID).setValue("last" + i); + // item.getItemProperty(COLUMN3_PROPERTY_ID).setValue("last" + i); } return container; diff --git a/tests/testbench/com/vaadin/tests/components/table/TableMultiSelectSimple.java b/tests/testbench/com/vaadin/tests/components/table/TableMultiSelectSimple.java index 76415844be..c33ba30193 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableMultiSelectSimple.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableMultiSelectSimple.java @@ -29,8 +29,8 @@ public class TableMultiSelectSimple extends TestBase { t.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - TreeSet sorted = new TreeSet((Set) event.getProperty() - .getValue()); + TreeSet<?> sorted = new TreeSet<Object>((Set<?>) event + .getProperty().getValue()); log.log("Selected value: " + sorted); } }); @@ -40,7 +40,7 @@ public class TableMultiSelectSimple extends TestBase { for (int i = 0; i < 10; i++) { t.addItem(i); - t.getContainerProperty(i, "string").setValue(i); + t.getContainerProperty(i, "string").setValue(String.valueOf(i)); t.getContainerProperty(i, "button") .setValue(new Button("Click me")); } diff --git a/tests/testbench/com/vaadin/tests/components/table/TablePageLengthUpdate.java b/tests/testbench/com/vaadin/tests/components/table/TablePageLengthUpdate.java index 71dc987e56..c7f138ea8f 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TablePageLengthUpdate.java +++ b/tests/testbench/com/vaadin/tests/components/table/TablePageLengthUpdate.java @@ -1,7 +1,6 @@ package com.vaadin.tests.components.table; import com.vaadin.data.util.MethodProperty; -import com.vaadin.terminal.Sizeable; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; @@ -62,7 +61,7 @@ public class TablePageLengthUpdate extends TestBase { public String getTableHeight() { return "" + (int) table.getHeight() - + Sizeable.UNIT_SYMBOLS[table.getHeightUnits()]; + + table.getHeightUnits().getSymbol(); } public void setTableHeight(String height) { diff --git a/tests/testbench/com/vaadin/tests/components/table/TableRepaintWhenMadeVisible.html b/tests/testbench/com/vaadin/tests/components/table/TableRepaintWhenMadeVisible.html index 0563acd4a5..e523a89df3 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableRepaintWhenMadeVisible.html +++ b/tests/testbench/com/vaadin/tests/components/table/TableRepaintWhenMadeVisible.html @@ -28,7 +28,7 @@ </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentstableTableRepaintWhenMadeVisibile::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentstableTableRepaintWhenMadeVisibile::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -36,7 +36,6 @@ <td></td> <td>hidden-then-shown</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html b/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html index 1a91211040..93e5a802ee 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html +++ b/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.html @@ -28,7 +28,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstableTableScrollOnFocus::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentstableTableScrollOnFocus::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]</td> <td>391,141</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.java b/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.java index 2c7193956a..4053665898 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableScrollOnFocus.java @@ -15,7 +15,7 @@ public class TableScrollOnFocus extends TestBase { chkSelectable.setImmediate(true); chkSelectable.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - table.setSelectable(chkSelectable.booleanValue()); + table.setSelectable((Boolean) chkSelectable.getValue()); } }); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableShouldNotEatValueChanges.java b/tests/testbench/com/vaadin/tests/components/table/TableShouldNotEatValueChanges.java index 21e26b64b8..a1686dee3f 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableShouldNotEatValueChanges.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableShouldNotEatValueChanges.java @@ -3,10 +3,10 @@ package com.vaadin.tests.components.table; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Notification; import com.vaadin.ui.Table; import com.vaadin.ui.Table.TableDragMode; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window.Notification; public class TableShouldNotEatValueChanges extends TestBase { @@ -27,7 +27,7 @@ public class TableShouldNotEatValueChanges extends TestBase { ItemClickListener l = new ItemClickListener() { public void itemClick(ItemClickEvent event) { - tf.getWindow().showNotification( + tf.getRoot().showNotification( "TF Value on the server:" + tf.getValue(), Notification.TYPE_WARNING_MESSAGE); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableSingleSelect.java b/tests/testbench/com/vaadin/tests/components/table/TableSingleSelect.java index 911c59b5c5..62d0cce9df 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableSingleSelect.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableSingleSelect.java @@ -32,7 +32,7 @@ public class TableSingleSelect extends TestBase { for (int i = 0; i < 10; i++) { t.addItem(i); - t.getContainerProperty(i, "string").setValue(i); + t.getContainerProperty(i, "string").setValue(String.valueOf(i)); t.getContainerProperty(i, "button") .setValue(new Button("Click me")); } diff --git a/tests/testbench/com/vaadin/tests/components/table/TableToggleVisibility.java b/tests/testbench/com/vaadin/tests/components/table/TableToggleVisibility.java index f5f87599d9..0cc125acaa 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableToggleVisibility.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableToggleVisibility.java @@ -7,9 +7,9 @@ import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TableToggleVisibility extends AbstractTestCase { @@ -112,7 +112,8 @@ public class TableToggleVisibility extends AbstractTestCase { mainLayout.addComponent(split); mainLayout.setExpandRatio(split, 1.0f); - Window mainWindow = new Window("Visibilitybug Application", mainLayout); + LegacyWindow mainWindow = new LegacyWindow("Visibilitybug Application", + mainLayout); mainWindow.setSizeFull(); setMainWindow(mainWindow); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableUnregisterComponent.java b/tests/testbench/com/vaadin/tests/components/table/TableUnregisterComponent.java index 91f5aec1ca..6fd4a9db52 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableUnregisterComponent.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableUnregisterComponent.java @@ -49,10 +49,10 @@ public class TableUnregisterComponent extends TestBase { table.setColumnCollapsingAllowed(true); table.setTableFieldFactory(new DefaultFieldFactory() { @Override - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { if (COL_B.equals(propertyId)) { - Field field = new TextField() { + Field<String> field = new TextField() { @Override public void setPropertyDataSource(Property newDataSource) { super.setPropertyDataSource(newDataSource); diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithChildComponents.java b/tests/testbench/com/vaadin/tests/components/table/TableWithChildComponents.java new file mode 100644 index 0000000000..1d1c162cae --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/table/TableWithChildComponents.java @@ -0,0 +1,66 @@ +package com.vaadin.tests.components.table; + +import com.vaadin.data.Item; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Component; +import com.vaadin.ui.NativeButton; +import com.vaadin.ui.Table; +import com.vaadin.ui.Table.ColumnGenerator; + +public class TableWithChildComponents extends TestBase implements ClickListener { + + private static final String COL2 = "Column 2 - generated"; + private static final String COL1 = "Column 1 - components"; + private Log log = new Log(10); + + @Override + protected void setup() { + Table table = new Table(); + table.setWidth("500px"); + table.setPageLength(10); + table.addContainerProperty(COL1, Component.class, null); + table.addContainerProperty(COL2, Component.class, null); + + table.addGeneratedColumn(COL2, new ColumnGenerator() { + + public Object generateCell(Table source, Object itemId, + Object columnId) { + return new Button( + "Item id: " + itemId + " column: " + columnId, + TableWithChildComponents.this); + } + }); + + for (int i = 0; i < 100; i++) { + Item item = table.addItem("Row " + i); + item.getItemProperty(COL1).setValue( + new NativeButton("Row " + i + " native", this)); + } + + addComponent(table); + addComponent(log); + + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + + public void buttonClick(ClickEvent event) { + log.log("Click on " + event.getButton().getCaption()); + + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/table/TableWithManyColumns.java b/tests/testbench/com/vaadin/tests/components/table/TableWithManyColumns.java index 7040391721..e0ae38a8b9 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TableWithManyColumns.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableWithManyColumns.java @@ -20,7 +20,7 @@ public class TableWithManyColumns extends TestBase { for (int row = 0; row < ROWS; row++) { Item i = t.addItem(String.valueOf(row)); for (int col = 0; col < COLS; col++) { - Property p = i.getItemProperty("COLUMN_" + col); + Property<?> p = i.getItemProperty("COLUMN_" + col); p.setValue("item " + row + "/" + col); } } diff --git a/tests/testbench/com/vaadin/tests/components/table/Tables.java b/tests/testbench/com/vaadin/tests/components/table/Tables.java index 3f37a178b6..4c773c9678 100644 --- a/tests/testbench/com/vaadin/tests/components/table/Tables.java +++ b/tests/testbench/com/vaadin/tests/components/table/Tables.java @@ -13,9 +13,12 @@ import com.vaadin.tests.components.select.AbstractSelectTestCase; import com.vaadin.ui.AbstractSelect.MultiSelectMode; import com.vaadin.ui.Button; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Table; +import com.vaadin.ui.Table.Align; import com.vaadin.ui.Table.CellStyleGenerator; import com.vaadin.ui.Table.ColumnGenerator; +import com.vaadin.ui.Table.ColumnHeaderMode; import com.vaadin.ui.Table.ColumnResizeEvent; import com.vaadin.ui.Table.ColumnResizeListener; import com.vaadin.ui.Table.FooterClickEvent; @@ -24,6 +27,7 @@ import com.vaadin.ui.Table.GeneratedRow; import com.vaadin.ui.Table.HeaderClickEvent; import com.vaadin.ui.Table.HeaderClickListener; import com.vaadin.ui.Table.RowGenerator; +import com.vaadin.ui.Table.RowHeaderMode; public class Tables<T extends Table> extends AbstractSelectTestCase<T> implements ItemClickListener, HeaderClickListener, FooterClickListener, @@ -34,15 +38,16 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> private static final String CATEGORY_FOOTER = "Footer"; private static final String CATEGORY_COLUMNS = "Columns"; + @SuppressWarnings("unchecked") @Override protected Class<T> getTestClass() { - return (Class) Table.class; + return (Class<T>) Table.class; } /* COMMANDS */ - private Command<T, String> columnAlignmentCommand = new Command<T, String>() { + private Command<T, Align> columnAlignmentCommand = new Command<T, Align>() { - public void execute(T c, String alignment, Object propertyId) { + public void execute(T c, Align alignment, Object propertyId) { c.setColumnAlignment(propertyId, alignment); } @@ -106,10 +111,10 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> } }; - protected Command<T, Integer> rowHeaderModeCommand = new Command<T, Integer>() { + protected Command<T, RowHeaderMode> rowHeaderModeCommand = new Command<T, RowHeaderMode>() { - public void execute(Table c, Integer value, Object data) { - if (value == Table.ROW_HEADER_MODE_PROPERTY) { + public void execute(Table c, RowHeaderMode value, Object data) { + if (value == RowHeaderMode.PROPERTY) { c.setItemCaptionPropertyId("Property 3"); } c.setRowHeaderMode(value); @@ -133,7 +138,7 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> protected Command<T, Object> alignColumnLeftCommand = new Command<T, Object>() { public void execute(T c, Object propertyId, Object data) { - c.setColumnAlignment(propertyId, (String) data); + c.setColumnAlignment(propertyId, (Align) data); } }; @@ -172,9 +177,9 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> } }; - private Command<T, Integer> columnHeaderModeCommand = new Command<T, Integer>() { + private Command<T, ColumnHeaderMode> columnHeaderModeCommand = new Command<T, ColumnHeaderMode>() { - public void execute(T c, Integer columnHeaderMode, Object data) { + public void execute(T c, ColumnHeaderMode columnHeaderMode, Object data) { c.setColumnHeaderMode(columnHeaderMode); } @@ -239,7 +244,7 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> l.setWidth(col.width); if (col.html) { l.setValue(value); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); } else { l.setValue(value); } @@ -475,13 +480,12 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> } private void createColumnHeaderMode(String category) { - LinkedHashMap<String, Integer> columnHeaderModeOptions = new LinkedHashMap<String, Integer>(); - columnHeaderModeOptions.put("Hidden", Table.COLUMN_HEADER_MODE_HIDDEN); - columnHeaderModeOptions.put("Id", Table.COLUMN_HEADER_MODE_ID); - columnHeaderModeOptions.put("Explicit", - Table.COLUMN_HEADER_MODE_EXPLICIT); + LinkedHashMap<String, ColumnHeaderMode> columnHeaderModeOptions = new LinkedHashMap<String, ColumnHeaderMode>(); + columnHeaderModeOptions.put("Hidden", ColumnHeaderMode.HIDDEN); + columnHeaderModeOptions.put("Id", ColumnHeaderMode.ID); + columnHeaderModeOptions.put("Explicit", ColumnHeaderMode.EXPLICIT); columnHeaderModeOptions.put("Explicit defaults id", - Table.COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID); + ColumnHeaderMode.EXPLICIT_DEFAULTS_ID); createSelectAction("Column header mode", category, columnHeaderModeOptions, "Explicit defaults id", @@ -601,10 +605,10 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> createBooleanAction("Collapsed", category, false, columnCollapsed, propertyId); t.log("Collapsed"); - LinkedHashMap<String, String> options = new LinkedHashMap<String, String>(); - options.put("Left", Table.ALIGN_LEFT); - options.put("Center", Table.ALIGN_CENTER); - options.put("Right", Table.ALIGN_RIGHT); + LinkedHashMap<String, Align> options = new LinkedHashMap<String, Align>(); + options.put("Left", Align.LEFT); + options.put("Center", Align.CENTER); + options.put("Right", Align.RIGHT); createSelectAction("Alignment", category, options, "Left", columnAlignmentCommand, propertyId); @@ -650,16 +654,15 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> } private void createRowHeaderModeSelect(String category) { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Explicit", Table.ROW_HEADER_MODE_EXPLICIT); - options.put("Explicit defaults id", - Table.ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID); - options.put("Hidden", Table.ROW_HEADER_MODE_HIDDEN); - options.put("Icon only", Table.ROW_HEADER_MODE_ICON_ONLY); - options.put("Id", Table.ROW_HEADER_MODE_ID); - options.put("Index", Table.ROW_HEADER_MODE_INDEX); - options.put("Item", Table.ROW_HEADER_MODE_ITEM); - options.put("'Property 3' property", Table.ROW_HEADER_MODE_PROPERTY); + LinkedHashMap<String, RowHeaderMode> options = new LinkedHashMap<String, RowHeaderMode>(); + options.put("Explicit", RowHeaderMode.EXPLICIT); + options.put("Explicit defaults id", RowHeaderMode.EXPLICIT_DEFAULTS_ID); + options.put("Hidden", RowHeaderMode.HIDDEN); + options.put("Icon only", RowHeaderMode.ICON_ONLY); + options.put("Id", RowHeaderMode.ID); + options.put("Index", RowHeaderMode.INDEX); + options.put("Item", RowHeaderMode.ITEM); + options.put("'Property 3' property", RowHeaderMode.PROPERTY); createSelectAction("Row header mode", category, options, "Hidden", rowHeaderModeCommand); @@ -739,17 +742,17 @@ public class Tables<T extends Table> extends AbstractSelectTestCase<T> } protected void createHeaderVisibilitySelect(String category) { - LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>(); - options.put("Explicit", Table.COLUMN_HEADER_MODE_EXPLICIT); + LinkedHashMap<String, ColumnHeaderMode> options = new LinkedHashMap<String, ColumnHeaderMode>(); + options.put("Explicit", ColumnHeaderMode.EXPLICIT); options.put("Explicit defaults id", - Table.COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID); - options.put("Id", Table.COLUMN_HEADER_MODE_ID); - options.put("Hidden", Table.COLUMN_HEADER_MODE_HIDDEN); + ColumnHeaderMode.EXPLICIT_DEFAULTS_ID); + options.put("Id", ColumnHeaderMode.ID); + options.put("Hidden", ColumnHeaderMode.HIDDEN); createSelectAction("Header mode", category, options, - "Explicit defaults id", new Command<T, Integer>() { + "Explicit defaults id", new Command<T, ColumnHeaderMode>() { - public void execute(T c, Integer value, Object data) { + public void execute(T c, ColumnHeaderMode value, Object data) { c.setColumnHeaderMode(value); } diff --git a/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java b/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java index 2bc03f9814..7fb096739a 100644 --- a/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java +++ b/tests/testbench/com/vaadin/tests/components/table/TestCurrentPageFirstItem.java @@ -7,8 +7,10 @@ import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; public class TestCurrentPageFirstItem extends TestBase implements ClickListener { diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetIndexOperations.java b/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetIndexOperations.java index c106144144..5ae9e69975 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetIndexOperations.java +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetIndexOperations.java @@ -14,16 +14,17 @@ public class TabSheetIndexOperations extends TestBase { @Override protected void setup() { final TabSheet tabs = new TabSheet(); - + // Add some tabs tabs.addTab(new Label("Content 1"), "Tab 1", null); tabs.addTab(new Label("Content 2"), "Tab 2", null); tabs.addTab(new Label("Content 3"), "Tab 3", null); - + addComponent(tabs); - - Button addTab = new Button("Add tab at index 2", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + + Button addTab = new Button("Add tab at index 2", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { tabs.addTab(new Label("Content " + tabCounter), "Added Tab " + tabCounter, null, 2); tabCounter++; @@ -37,8 +38,8 @@ public class TabSheetIndexOperations extends TestBase { Tab tab = tabs.getTab(2); tab.setCaption(new StringBuffer(tab.getCaption()) .reverse().toString()); - } - }); + } + }); addComponent(setCaption); Button move = new Button("Move selected tab to index 2", @@ -49,16 +50,17 @@ public class TabSheetIndexOperations extends TestBase { } }); addComponent(move); - - Button getIndex = new Button("Get selected tab index", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + + Button getIndex = new Button("Get selected tab index", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { getMainWindow().showNotification( "Index: " + tabs.getTabPosition(tabs.getTab(tabs .getSelectedTab()))); - - } - }); + + } + }); addComponent(getIndex); } diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTabTheming.java b/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTabTheming.java index 7d9a65b868..a2c75d6e79 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTabTheming.java +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTabTheming.java @@ -1,4 +1,5 @@ package com.vaadin.tests.components.tabsheet; + import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Label; import com.vaadin.ui.TabSheet; diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTest.java b/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTest.java index 1c5c63dcd4..3077c1a97b 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTest.java +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabSheetTest.java @@ -80,6 +80,7 @@ public class TabSheetTest<T extends TabSheet> extends } }; + @SuppressWarnings("unchecked") @Override protected Class<T> getTestClass() { return (Class<T>) TabSheet.class; diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabsheetNPE.java b/tests/testbench/com/vaadin/tests/components/tabsheet/TabsheetNPE.java index 2b1669bff0..24077b972c 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabsheetNPE.java +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabsheetNPE.java @@ -5,10 +5,10 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.Tab; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TabsheetNPE extends AbstractTestCase implements ClickListener { @@ -29,7 +29,7 @@ public class TabsheetNPE extends AbstractTestCase implements ClickListener { @Override public void init() { - setMainWindow(new Window("TabSheet Demo", createMainLayout())); + setMainWindow(new LegacyWindow("TabSheet Demo", createMainLayout())); } private VerticalLayout createMainLayout() { diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/VerticalScrollbarPosition.java b/tests/testbench/com/vaadin/tests/components/tabsheet/VerticalScrollbarPosition.java index 66d19f6935..110f26d478 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/VerticalScrollbarPosition.java +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/VerticalScrollbarPosition.java @@ -3,7 +3,6 @@ package com.vaadin.tests.components.tabsheet; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TextArea; -import com.vaadin.ui.TextField; public class VerticalScrollbarPosition extends TestBase { @@ -28,9 +27,9 @@ public class VerticalScrollbarPosition extends TestBase { tf.setWidth("200px"); tabsheet.addTab( tf, - "A text field that is 200px wide, the tab bar for the tabsheet is wider", + "A text area that is 200px wide, the tab bar for the tabsheet is wider", null); - TextField tf2 = new TextField("Another tab", "b"); + TextArea tf2 = new TextArea("Another tab", "b"); tf2.setWidth("1000px"); tf2.setHeight("50px"); tabsheet.addTab(tf2); diff --git a/tests/testbench/com/vaadin/tests/components/textarea/TextAreaNullRepresentation.html b/tests/testbench/com/vaadin/tests/components/textarea/TextAreaNullRepresentation.html index eb62d30374..6b29b634db 100644 --- a/tests/testbench/com/vaadin/tests/components/textarea/TextAreaNullRepresentation.html +++ b/tests/testbench/com/vaadin/tests/components/textarea/TextAreaNullRepresentation.html @@ -61,7 +61,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextareaTextAreaTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextareaTextAreaTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>176,130</td> </tr> <tr> @@ -98,7 +98,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextareaTextAreaTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextareaTextAreaTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>176,130</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/textfield/SelectionAndCursorPosition.java b/tests/testbench/com/vaadin/tests/components/textfield/SelectionAndCursorPosition.java index d362a3050d..962a85ffcb 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/SelectionAndCursorPosition.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/SelectionAndCursorPosition.java @@ -3,6 +3,7 @@ package com.vaadin.tests.components.textfield; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.AbstractTextField; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; @@ -10,34 +11,31 @@ import com.vaadin.ui.CheckBox; import com.vaadin.ui.FormLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Panel; +import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; public class SelectionAndCursorPosition extends TestBase { - TextField tf = new TextField(); + TextField textField = createTextField(); + TextArea textArea = createTextArea(); + AbstractTextField activeComponent = textField; @Override protected void setup() { - - tf.setCaption("Text field"); - tf.setValue("So we have some text to select"); - tf.setWidth("400px"); - FormLayout fl = new FormLayout(); Panel panel = new Panel(fl); panel.setCaption("Hackers panel"); CheckBox ml = new CheckBox("Multiline"); ml.setImmediate(true); ml.addListener(new Property.ValueChangeListener() { - @SuppressWarnings("deprecation") public void valueChange(ValueChangeEvent event) { - if (tf.getHeight() < 0) { - tf.setHeight("50px"); + if (textField.getApplication() == null) { + replaceComponent(textArea, textField); + activeComponent = textField; } else { - tf.setSizeUndefined(); - tf.setRows(0); + replaceComponent(textField, textArea); + activeComponent = textArea; } - tf.setWidth("400px"); } }); fl.addComponent(ml); @@ -45,7 +43,7 @@ public class SelectionAndCursorPosition extends TestBase { Button b = new Button("Select all ( selectAll() )"); b.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { - tf.selectAll(); + activeComponent.selectAll(); } }); fl.addComponent(b); @@ -58,9 +56,10 @@ public class SelectionAndCursorPosition extends TestBase { b = new Button("select"); b.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { - int startPos = Integer.parseInt((String) start.getValue()); - int lenght = Integer.parseInt((String) length.getValue()); - tf.setSelectionRange(startPos, lenght); + int startPos = Integer.parseInt(start.getValue()); + int lenght = Integer.parseInt(length.getValue()); + + activeComponent.setSelectionRange(startPos, lenght); } }); @@ -74,8 +73,8 @@ public class SelectionAndCursorPosition extends TestBase { b = new Button("set"); b.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { - int startPos = Integer.parseInt((String) pos.getValue()); - tf.setCursorPosition(startPos); + int startPos = Integer.parseInt(pos.getValue()); + activeComponent.setCursorPosition(startPos); } }); @@ -85,11 +84,30 @@ public class SelectionAndCursorPosition extends TestBase { .setCaption("Set cursor position ( setCursorPosition(int pos) )"); fl.addComponent(setCursorPosition); - getLayout().addComponent(tf); + getLayout().addComponent(textField); getLayout().addComponent(panel); } + private static TextField createTextField() { + TextField tf = new TextField(); + tf.setCaption("Text field"); + tf.setValue("So we have some text to select"); + tf.setWidth("400px"); + + return tf; + } + + private static TextArea createTextArea() { + TextArea ta = new TextArea(); + ta.setCaption("Text area"); + ta.setValue("So we have some text to select"); + ta.setWidth("400px"); + ta.setHeight("50px"); + + return ta; + } + @Override protected String getDescription() { return "For usability reasons it is often essential that developer " diff --git a/tests/testbench/com/vaadin/tests/components/textfield/SizedTextFields.java b/tests/testbench/com/vaadin/tests/components/textfield/SizedTextFields.java index 93ab80b88a..7d993682fd 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/SizedTextFields.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/SizedTextFields.java @@ -3,6 +3,7 @@ package com.vaadin.tests.components.textfield; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; +import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; @@ -37,10 +38,10 @@ public class SizedTextFields extends TestBase { vl.setHeight("40px"); vl.setWidth("200px"); - tf = new TextField(); - tf.setRows(2); // make it text area, instead of oneliner - tf.setSizeFull(); - vl.addComponent(tf); + TextArea ta = new TextArea(); + ta.setRows(2); // make it text area, instead of oneliner + ta.setSizeFull(); + vl.addComponent(ta); vl.setCaption("Fullsize textarea in 100px height 200px width box"); cssLayout.addComponent(vl); diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEvents.java b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEvents.java index f0f0a52237..b3ea5b8186 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEvents.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEvents.java @@ -87,7 +87,7 @@ public class TextChangeEvents extends TestBase { @Override public void attach() { super.attach(); - TestUtils.injectCSS(getWindow(), ".match { background:green ;} " + TestUtils.injectCSS(getRoot(), ".match { background:green ;} " + ".nomatch {background:red;}"); } diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEventsWithNonImmediateValueChange.java b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEventsWithNonImmediateValueChange.java index df5b275a8e..ab3fd49cd6 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEventsWithNonImmediateValueChange.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeEventsWithNonImmediateValueChange.java @@ -32,7 +32,7 @@ public class TextChangeEventsWithNonImmediateValueChange extends TestBase { tf.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - l.log("Value change: '" + event.getProperty().toString() + "'"); + l.log("Value change: '" + event.getProperty().getValue() + "'"); } }); @@ -52,4 +52,4 @@ public class TextChangeEventsWithNonImmediateValueChange extends TestBase { return 6866; } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeListenerChangingNonTextProperties.java b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeListenerChangingNonTextProperties.java index e0fcb1dde8..8a3678ab62 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeListenerChangingNonTextProperties.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeListenerChangingNonTextProperties.java @@ -10,20 +10,23 @@ import com.vaadin.ui.TextField; public class TextChangeListenerChangingNonTextProperties extends TestBase { int index = 0; - String[] styles = {"red","green","blue","cyan", "magenta"}; - + String[] styles = { "red", "green", "blue", "cyan", "magenta" }; + private String getNextStyle() { - return styles[++index%styles.length]; + return styles[++index % styles.length]; } - + @Override protected void setup() { final TextField tf2 = new TextField("Updates width") { @Override public void attach() { super.attach(); - TestUtils.injectCSS(getWindow(), ".red { background:red;} " - + ".green { background:green;} .blue { background:blue;} .cyan { background:cyan;} .magenta { background:magenta;}"); + TestUtils + .injectCSS( + getRoot(), + ".red { background:red;} " + + ".green { background:green;} .blue { background:blue;} .cyan { background:cyan;} .magenta { background:magenta;}"); } }; tf2.setTextChangeEventMode(TextChangeEventMode.EAGER); @@ -32,7 +35,7 @@ public class TextChangeListenerChangingNonTextProperties extends TestBase { tf2.setStyleName(getNextStyle()); } - }) ; + }); tf2.setImmediate(true); addComponent(tf2); @@ -47,6 +50,5 @@ public class TextChangeListenerChangingNonTextProperties extends TestBase { protected Integer getTicketNumber() { return Integer.valueOf(6588); } - } diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeTimeoutAfterDetach.java b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeTimeoutAfterDetach.java index d1f856f40c..2f0c54ee39 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextChangeTimeoutAfterDetach.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextChangeTimeoutAfterDetach.java @@ -23,15 +23,15 @@ public class TextChangeTimeoutAfterDetach extends TestBase { } }); addComponent(field); - + Button detachBtn = new Button("detach field", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + public void buttonClick(ClickEvent event) { removeComponent(field); getLayout().addComponentAsFirst( new Label("Field detached!")); - } - }); + } + }); addComponent(detachBtn); } diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInLayoutInTable.java b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInLayoutInTable.java index 4fb91db973..3e1a709243 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInLayoutInTable.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInLayoutInTable.java @@ -3,18 +3,18 @@ package com.vaadin.tests.components.textfield; import com.vaadin.Application; import com.vaadin.ui.Component; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -@SuppressWarnings("serial") -public class TextFieldInLayoutInTable extends Application { +public class TextFieldInLayoutInTable extends Application.LegacyApplication { @Override public void init() { - final Window mainWindow = new Window(this.getClass().getName()); + final LegacyWindow mainWindow = new LegacyWindow(this.getClass() + .getName()); setMainWindow(mainWindow); final Table table = new Table(); diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java index 6aac7caddd..c04c9d6c13 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java @@ -1,5 +1,7 @@ package com.vaadin.tests.components.textfield; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; @@ -23,18 +25,18 @@ public class TextFieldInputPromptAndClickShortcut extends TestBase { }); button.setClickShortcut(KeyCode.ESCAPE); - final CheckBox inputPromptSelection = new CheckBox("Input prompt", - new ClickListener() { - public void buttonClick(ClickEvent event) { - if (event.getButton().getValue() == Boolean.TRUE) { - textField.setInputPrompt("Input prompt"); - } else { - textField.setInputPrompt(null); - } - log.log("Set input prompt: " - + textField.getInputPrompt()); - } - }); + final CheckBox inputPromptSelection = new CheckBox("Input prompt"); + inputPromptSelection.setImmediate(true); + inputPromptSelection.addListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + if (event.getProperty().getValue() == Boolean.TRUE) { + textField.setInputPrompt("Input prompt"); + } else { + textField.setInputPrompt(null); + } + log.log("Set input prompt: " + textField.getInputPrompt()); + } + }); inputPromptSelection.setImmediate(true); addComponent(textField); diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentation.html b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentation.html index 5506351d34..c4a887d764 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentation.html +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentation.html @@ -61,7 +61,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>176,130</td> </tr> <tr> @@ -98,7 +98,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>176,130</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentationAndSelection.html b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentationAndSelection.html index 7923f5acfd..cfd397b4f2 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentationAndSelection.html +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldNullRepresentationAndSelection.html @@ -87,7 +87,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>114,149</td> </tr> <tr> @@ -129,7 +129,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>120,102</td> </tr> <tr> @@ -154,7 +154,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[2]</td> + <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]</td> <td>163,129</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldSecret.html b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldSecret.html deleted file mode 100644 index 6a51103fe5..0000000000 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldSecret.html +++ /dev/null @@ -1,196 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.textfield.TextFieldTest?restartApplication</td> - <td></td> -</tr> -<!--Disable event log--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item1</td> - <td>19,8</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item0</td> - <td>24,1</td> -</tr> -<!--Enter "s3cr3t" in the TextField--> -<tr> - <td>enterCharacter</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_StestComponent</td> - <td>s3cr3t</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>normal</td> -</tr> -<!--Change to secret--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item0</td> - <td>38,11</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item5</td> - <td>51,10</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[1]/VMenuBar[0]#item6</td> - <td>25,12</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>secret</td> -</tr> -<!--Change to normal--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item0</td> - <td>38,11</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item5</td> - <td>51,10</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[1]/VMenuBar[0]#item6</td> - <td>25,12</td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>normal</td> -</tr> -<!--Change to secret--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item0</td> - <td>38,11</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item5</td> - <td>51,10</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[1]/VMenuBar[0]#item6</td> - <td>25,12</td> -</tr> -<!--ValueChangeListener--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item0</td> - <td>38,13</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item3</td> - <td>30,5</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[1]/VMenuBar[0]#item2</td> - <td>62,12</td> -</tr> -<!--Enable and clear event log--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item1</td> - <td>19,8</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item0</td> - <td>24,1</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item1</td> - <td>19,8</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item1</td> - <td>24,1</td> -</tr> -<!--Value -> Test--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item0</td> - <td>21,2</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item4</td> - <td>24,7</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[1]/VMenuBar[0]#item0</td> - <td>37,8</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[2]/VMenuBar[0]#item2</td> - <td>37,4</td> -</tr> -<tr> - <td>pause</td> - <td>100</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_SLog/ChildComponentContainer[0]/VLabel[0]</td> - <td>1. ValueChangeEvent, new value: 'Test'</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_StestComponent</td> - <td>Test</td> -</tr> -<!--Change to normal--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_Smenu#item0</td> - <td>38,11</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[0]/VMenuBar[0]#item5</td> - <td>51,10</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::Root/VOverlay[1]/VMenuBar[0]#item6</td> - <td>25,12</td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runcomvaadintestscomponentstextfieldTextFieldTest::PID_StestComponent</td> - <td>Test</td> -</tr> -<!----> -</tbody></table> -</body> -</html> diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldTest.java b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldTest.java index bc7a6fcf76..10793a8bad 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldTest.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldTest.java @@ -1,7 +1,5 @@ package com.vaadin.tests.components.textfield; -import java.util.LinkedHashMap; - import com.vaadin.event.FieldEvents.TextChangeListener; import com.vaadin.tests.components.abstractfield.AbstractTextFieldTest; import com.vaadin.ui.TextField; @@ -9,27 +7,6 @@ import com.vaadin.ui.TextField; public class TextFieldTest extends AbstractTextFieldTest<TextField> implements TextChangeListener { - private Command<TextField, Boolean> secretCommand = new Command<TextField, Boolean>() { - @SuppressWarnings("deprecation") - public void execute(TextField c, Boolean value, Object data) { - c.setSecret(value); - } - }; - - private Command<TextField, Boolean> wordwrapCommand = new Command<TextField, Boolean>() { - @SuppressWarnings("deprecation") - public void execute(TextField c, Boolean value, Object data) { - c.setWordwrap(value); - } - }; - - private Command<TextField, Integer> rowsCommand = new Command<TextField, Integer>() { - @SuppressWarnings("deprecation") - public void execute(TextField c, Integer value, Object data) { - c.setRows(value); - } - }; - @Override protected Class<TextField> getTestClass() { return TextField.class; @@ -38,22 +15,6 @@ public class TextFieldTest extends AbstractTextFieldTest<TextField> implements @Override protected void createActions() { super.createActions(); - createSecretAction(CATEGORY_FEATURES); - createWordwrapAction(CATEGORY_FEATURES); - createRowsAction(CATEGORY_FEATURES); - } - - private void createRowsAction(String category) { - LinkedHashMap<String, Integer> options = createIntegerOptions(20); - createSelectAction("Rows", category, options, "0", rowsCommand); - } - - private void createSecretAction(String category) { - createBooleanAction("Secret", category, false, secretCommand); - } - - private void createWordwrapAction(String category) { - createBooleanAction("Wordwrap", category, false, wordwrapCommand); } } diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithProperty.java b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithProperty.java index 7d0bd12359..b753978666 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithProperty.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithProperty.java @@ -12,23 +12,24 @@ public class TextFieldWithProperty extends TestBase { @Override protected void setup() { - + final TextField tf1 = new TextField(); - + final ObjectProperty<String> op = new ObjectProperty<String>("FOO"); - + tf1.setPropertyDataSource(op); addComponent(tf1); - Button b = new Button("Set BAR to underlaying property (should propagate to UI)"); + Button b = new Button( + "Set BAR to underlaying property (should propagate to UI)"); b.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { op.setValue("BAR"); } }); - addComponent(b ); - + addComponent(b); + } @Override diff --git a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithPropertyFormatter.java b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithPropertyFormatter.java index 1fbe6ffc55..ea4b572604 100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithPropertyFormatter.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldWithPropertyFormatter.java @@ -13,11 +13,10 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.TextField; -@SuppressWarnings("unchecked") public class TextFieldWithPropertyFormatter extends TestBase { - private PropertyFormatter formatter; - private Property property; + private PropertyFormatter<BigDecimal> formatter; + private Property<BigDecimal> property; @Override protected void setup() { @@ -26,25 +25,25 @@ public class TextFieldWithPropertyFormatter extends TestBase { * digits - rounds half up */ // Property containing BigDecimal - property = new Property() { + property = new Property<BigDecimal>() { private BigDecimal value; - public Object getValue() { + public BigDecimal getValue() { return value; } - public void setValue(Object newValue) throws ReadOnlyException, - ConversionException { + public void setValue(Object newValue) throws ReadOnlyException { if (newValue == null) { value = null; } else if (newValue instanceof BigDecimal) { value = (BigDecimal) newValue; } else { - throw new ConversionException(); + throw new IllegalArgumentException( + "Value must be of type BigDecimal"); } } - public Class<?> getType() { + public Class<BigDecimal> getType() { return BigDecimal.class; } @@ -57,7 +56,7 @@ public class TextFieldWithPropertyFormatter extends TestBase { } }; - formatter = new PropertyFormatter(property) { + formatter = new PropertyFormatter<BigDecimal>(property) { private final DecimalFormat df = new DecimalFormat("#,##0.00", new DecimalFormatSymbols(new Locale("en", "UK"))); @@ -67,7 +66,7 @@ public class TextFieldWithPropertyFormatter extends TestBase { } @Override - public String format(Object value) { + public String format(BigDecimal value) { final String retVal; if (value == null) { @@ -79,7 +78,7 @@ public class TextFieldWithPropertyFormatter extends TestBase { } @Override - public Object parse(String formattedValue) throws Exception { + public BigDecimal parse(String formattedValue) throws Exception { if (formattedValue != null && formattedValue.trim().length() != 0) { BigDecimal value = (BigDecimal) df.parse(formattedValue); diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeDragAndDropFromTable.java b/tests/testbench/com/vaadin/tests/components/tree/TreeDragAndDropFromTable.java index 1525d43ede..dca2d96628 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeDragAndDropFromTable.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeDragAndDropFromTable.java @@ -115,5 +115,4 @@ public class TreeDragAndDropFromTable extends TestBase { return 7687; } - } diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeFiltering.java b/tests/testbench/com/vaadin/tests/components/tree/TreeFiltering.java index e69e5f50f9..20d1eacb97 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeFiltering.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeFiltering.java @@ -48,8 +48,8 @@ public class TreeFiltering extends TestBase { filterType.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - cont.setIncludeParentsWhenFiltering(((CheckBox) event - .getProperty()).booleanValue()); + cont.setIncludeParentsWhenFiltering((Boolean) ((CheckBox) event + .getProperty()).getValue()); ccTree.requestRepaint(); } }); diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeFocusGaining.java b/tests/testbench/com/vaadin/tests/components/tree/TreeFocusGaining.java index e784009bce..87170214ca 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeFocusGaining.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeFocusGaining.java @@ -21,7 +21,7 @@ public class TreeFocusGaining extends TestBase { textField.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - log.log("TF value now:" + event.getProperty()); + log.log("TF value now:" + event.getProperty().getValue()); } }); @@ -31,7 +31,7 @@ public class TreeFocusGaining extends TestBase { tree.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - log.log("Tree value now:" + event.getProperty()); + log.log("Tree value now:" + event.getProperty().getValue()); } }); tree.setImmediate(true); diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationScrolls.java b/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationScrolls.java index 86d419c2b3..bad6359889 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationScrolls.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationScrolls.java @@ -5,8 +5,8 @@ package com.vaadin.tests.components.tree; import com.vaadin.data.Container; import com.vaadin.data.util.HierarchicalContainer; -import com.vaadin.data.validator.AbstractValidator; import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.AlwaysFailValidator; import com.vaadin.ui.Tree; public class TreeKeyboardNavigationScrolls extends TestBase { @@ -16,12 +16,7 @@ public class TreeKeyboardNavigationScrolls extends TestBase { Tree tree = new Tree(); tree.setContainerDataSource(generateHierarchicalContainer()); tree.setImmediate(true); - tree.addValidator(new AbstractValidator("failed") { - public boolean isValid(Object value) { - return false; - } - - }); + tree.addValidator(new AlwaysFailValidator("failed")); addComponent(tree); } diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationValidators.java b/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationValidators.java index 2a545065c4..9204f0495b 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationValidators.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeKeyboardNavigationValidators.java @@ -2,8 +2,8 @@ package com.vaadin.tests.components.tree; import com.vaadin.data.Container; import com.vaadin.data.util.HierarchicalContainer; -import com.vaadin.data.validator.AbstractValidator; import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.AlwaysFailValidator; import com.vaadin.ui.Tree; public class TreeKeyboardNavigationValidators extends TestBase { @@ -18,12 +18,7 @@ public class TreeKeyboardNavigationValidators extends TestBase { tree.setSizeFull(); tree.setContainerDataSource(generateHierarchicalContainer()); tree.setImmediate(true); - tree.addValidator(new AbstractValidator("failed") { - public boolean isValid(Object value) { - return false; - } - - }); + tree.addValidator(new AlwaysFailValidator("failed")); return tree; } diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreePerformanceTest.java b/tests/testbench/com/vaadin/tests/components/tree/TreePerformanceTest.java index de72a6efeb..9d58762f60 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreePerformanceTest.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreePerformanceTest.java @@ -2,9 +2,9 @@ package com.vaadin.tests.components.tree; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TreePerformanceTest extends AbstractTestCase { @@ -20,7 +20,7 @@ public class TreePerformanceTest extends AbstractTestCase { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); Layout layout = null; diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeScrolling.java b/tests/testbench/com/vaadin/tests/components/tree/TreeScrolling.java index c17855996e..abc9a5385d 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeScrolling.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeScrolling.java @@ -2,10 +2,10 @@ package com.vaadin.tests.components.tree; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.RichTextArea; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TreeScrolling extends AbstractTestCase { @@ -13,7 +13,7 @@ public class TreeScrolling extends AbstractTestCase { public void init() { VerticalLayout layout = new VerticalLayout(); layout.setSizeUndefined(); - Window w = new Window("", layout); + LegacyWindow w = new LegacyWindow("", layout); setMainWindow(w); TextField filler1 = new TextField(); diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeScrollingOnSelection.java b/tests/testbench/com/vaadin/tests/components/tree/TreeScrollingOnSelection.java index 42c9087fc3..a6079160ab 100644 --- a/tests/testbench/com/vaadin/tests/components/tree/TreeScrollingOnSelection.java +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeScrollingOnSelection.java @@ -36,7 +36,6 @@ public class TreeScrollingOnSelection extends TestBase { tree.setImmediate(true); Panel panel = new Panel(); - panel.setScrollable(true); panel.addComponent(tree); panel.setWidth("200px"); panel.setHeight("300px"); diff --git a/tests/testbench/com/vaadin/tests/components/treetable/DisappearingComponents.java b/tests/testbench/com/vaadin/tests/components/treetable/DisappearingComponents.java index becae955ab..329e5d291d 100644 --- a/tests/testbench/com/vaadin/tests/components/treetable/DisappearingComponents.java +++ b/tests/testbench/com/vaadin/tests/components/treetable/DisappearingComponents.java @@ -3,14 +3,14 @@ package com.vaadin.tests.components.treetable; import com.vaadin.terminal.ExternalResource; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Link; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TreeTable; -import com.vaadin.ui.Window; public class DisappearingComponents extends AbstractTestCase { @Override public void init() { - Window mainWindow = new Window("Application"); + LegacyWindow mainWindow = new LegacyWindow("Application"); final TreeTable tt = new TreeTable(); tt.setSizeUndefined(); tt.setWidth("100%"); diff --git a/tests/testbench/com/vaadin/tests/components/treetable/ProgrammaticCollapse.java b/tests/testbench/com/vaadin/tests/components/treetable/ProgrammaticCollapse.java index 6f2e507ce3..2f84c8a68d 100644 --- a/tests/testbench/com/vaadin/tests/components/treetable/ProgrammaticCollapse.java +++ b/tests/testbench/com/vaadin/tests/components/treetable/ProgrammaticCollapse.java @@ -31,7 +31,7 @@ public class ProgrammaticCollapse extends TestBase { new ClickListener() { public void buttonClick(ClickEvent event) { boolean collapsed = !table.isCollapsed(1); - table.getWindow().showNotification( + table.getRoot().showNotification( "set collapsed: " + collapsed); table.setCollapsed(1, collapsed); } @@ -40,7 +40,7 @@ public class ProgrammaticCollapse extends TestBase { new ClickListener() { public void buttonClick(ClickEvent event) { boolean collapsed = !table.isCollapsed(100); - table.getWindow().showNotification( + table.getRoot().showNotification( "set collapsed: " + collapsed); table.setCollapsed(100, collapsed); } @@ -51,7 +51,7 @@ public class ProgrammaticCollapse extends TestBase { public void buttonClick(ClickEvent event) { collapsed = !collapsed; - table.getWindow().showNotification( + table.getRoot().showNotification( "set collapsed: " + collapsed); for (int i = 0; i < 50; ++i) { table.setCollapsed(i * 2, collapsed); diff --git a/tests/testbench/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java b/tests/testbench/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java index ea04c3ad30..ae3d4bc053 100644 --- a/tests/testbench/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java +++ b/tests/testbench/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java @@ -12,6 +12,7 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.Label; +import com.vaadin.ui.Root; import com.vaadin.ui.Window; public class AttachShouldBeCalledForSubWindows extends AbstractTestCase @@ -25,7 +26,7 @@ public class AttachShouldBeCalledForSubWindows extends AbstractTestCase @Override public void init() { - Window mainWindow = new Window() { + Root.LegacyWindow mainWindow = new Root.LegacyWindow() { @Override public void attach() { log(this); diff --git a/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.html b/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.html index 36e9134566..6e3eb906b7 100644 --- a/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.html +++ b/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.html @@ -23,9 +23,10 @@ </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_Sopennative</td> + <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_Sopensub/domChild[0]/domChild[0]</td> <td></td> </tr> +<!--Close from click handler--> <tr> <td>click</td> <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> @@ -38,12 +39,13 @@ </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_Sopennative</td> + <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_Sopensub/domChild[0]/domChild[0]</td> <td></td> </tr> +<!--Click close in title bar--> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td> <td></td> </tr> <tr> @@ -51,41 +53,6 @@ <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_SLog/ChildComponentContainer[0]/VLabel[0]</td> <td>2. Window 'Sub-window' closed</td> </tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForPopUp</td> - <td>nativewindow</td> - <td>30000</td> -</tr> -<tr> - <td>selectWindow</td> - <td>name=nativewindow</td> - <td></td> -</tr> -<tr> - <td>close</td> - <td></td> - <td></td> -</tr> -<tr> - <td>selectWindow</td> - <td>title=com.vaadin.tests.components.window.CloseSubWindow</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_Spoll/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_SLog/ChildComponentContainer[0]/VLabel[0]</td> - <td>3. Browser window closed</td> -</tr> </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java b/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java index c1104836a8..bcfbc7f55a 100644 --- a/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java +++ b/tests/testbench/com/vaadin/tests/components/window/CloseSubWindow.java @@ -1,8 +1,5 @@ package com.vaadin.tests.components.window; -import java.net.URL; - -import com.vaadin.terminal.ExternalResource; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; import com.vaadin.ui.Button; @@ -14,7 +11,6 @@ import com.vaadin.ui.Window.CloseListener; public class CloseSubWindow extends TestBase { - private Window browserWindow; private Log log = new Log(5); @Override @@ -30,54 +26,6 @@ public class CloseSubWindow extends TestBase { addComponent(log); addComponent(openWindowButton); - - Button openBrowserWindowButton = new Button("Open browser window"); - openWindowButton.setDebugId("opennative"); - openBrowserWindowButton.addListener(new ClickListener() { - public void buttonClick(ClickEvent event) { - browserWindow = new Window("Window"); - Button closeButton = new Button("Close this window", - new ClickListener() { - - public void buttonClick(ClickEvent event) { - event.getButton().getWindow() - .executeJavaScript("window.close();"); - - } - }); - browserWindow.addComponent(closeButton); - - browserWindow.addListener(new CloseListener() { - public void windowClose(CloseEvent e) { - logBrowserWindowClosed(); - // there is no push, so the user needs to click a button - // to see the notification - - // Opera does not send a notification about the window - // having been closed - } - - }); - - addWindow(browserWindow); - URL windowUrl = browserWindow.getURL(); - // named for easier access by test tools - getMainWindow().open(new ExternalResource(windowUrl), - "nativewindow"); - if (getBrowser().isOpera()) { - // Immediately log a close event in Opera so this test can - // be run for all browsers. Vaadin ticket #5687. - logBrowserWindowClosed(); - } - } - }); - - addComponent(openBrowserWindowButton); - - Button pollButton = new Button("Poll server"); - pollButton.setDebugId("poll"); - addComponent(pollButton); - } private Window createClosableSubWindow(final String title) { @@ -89,7 +37,7 @@ public class CloseSubWindow extends TestBase { Button closeButton = new Button("Close"); closeButton.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { - window.getParent().removeWindow(window); + event.getButton().findAncestor(Window.class).close(); } }); window.addComponent(closeButton); @@ -97,7 +45,7 @@ public class CloseSubWindow extends TestBase { Button removeButton = new Button("Remove from parent"); removeButton.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { - window.getParent().removeWindow(window); + window.close(); } }); window.addComponent(closeButton); @@ -120,10 +68,4 @@ public class CloseSubWindow extends TestBase { protected Integer getTicketNumber() { return 3865; } - - private void logBrowserWindowClosed() { - log.log("Browser window closed"); - - } - } diff --git a/tests/testbench/com/vaadin/tests/components/window/ExecuteJavaScript.java b/tests/testbench/com/vaadin/tests/components/window/ExecuteJavaScript.java index dfa0e80368..bf979b1aa3 100644 --- a/tests/testbench/com/vaadin/tests/components/window/ExecuteJavaScript.java +++ b/tests/testbench/com/vaadin/tests/components/window/ExecuteJavaScript.java @@ -4,13 +4,13 @@ import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; public class ExecuteJavaScript extends AbstractTestCase { @Override public void init() { - final Window mainWindow = new Window("Test"); + final LegacyWindow mainWindow = new LegacyWindow("Test"); setMainWindow(mainWindow); for (final String script : new String[] { "alert('foo');", diff --git a/tests/testbench/com/vaadin/tests/components/window/ExtraWindowShown.java b/tests/testbench/com/vaadin/tests/components/window/ExtraWindowShown.java index 284a63543a..e81e02b22b 100644 --- a/tests/testbench/com/vaadin/tests/components/window/ExtraWindowShown.java +++ b/tests/testbench/com/vaadin/tests/components/window/ExtraWindowShown.java @@ -20,16 +20,14 @@ public class ExtraWindowShown extends TestBase { w.addComponent(new Button("Close", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - Window main = w.getParent(); - // main = w.getWindow(); - main.removeWindow(w); + w.close(); } })); Button iconButton = new Button("A button with icon"); iconButton .setIcon(new ThemeResource("../runo/icons/16/ok.png")); w.addComponent(iconButton); - event.getButton().getWindow().addWindow(w); + event.getButton().getRoot().addWindow(w); } }); diff --git a/tests/testbench/com/vaadin/tests/components/window/LazyWindowResize.java b/tests/testbench/com/vaadin/tests/components/window/LazyWindowResize.java index 6c051f4b1e..2e6a386667 100644 --- a/tests/testbench/com/vaadin/tests/components/window/LazyWindowResize.java +++ b/tests/testbench/com/vaadin/tests/components/window/LazyWindowResize.java @@ -1,37 +1,42 @@ package com.vaadin.tests.components.window; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.tests.util.Log; import com.vaadin.tests.util.LoremIpsum; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.BrowserWindowResizeEvent; +import com.vaadin.ui.Root.BrowserWindowResizeListener; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; import com.vaadin.ui.Window.ResizeEvent; import com.vaadin.ui.Window.ResizeListener; public class LazyWindowResize extends AbstractTestCase { - private Window mainWindow; + private LegacyWindow mainWindow; private Window subWindow; - private Button lazyMode; + private CheckBox lazyMode; private Log log = new Log(5); private CheckBox resizeListenerCheckBox; protected ResizeListener resizeListener = new ResizeListener() { public void windowResized(ResizeEvent e) { - if (e.getWindow() == mainWindow) { - log.log("Main window resized"); - } else { - log.log("Sub window resized"); - } + log.log("Sub window resized"); + } + }; + protected BrowserWindowResizeListener browserWindowResizeListener = new BrowserWindowResizeListener() { + public void browserWindowResized(BrowserWindowResizeEvent event) { + log.log("Main window resized"); } }; - private CheckBox immediateCheckBox;;; + + private CheckBox immediateCheckBox; @Override protected String getDescription() { @@ -45,7 +50,7 @@ public class LazyWindowResize extends AbstractTestCase { @Override public void init() { - mainWindow = new Window("Resize test"); + mainWindow = new LegacyWindow("Resize test"); setMainWindow(mainWindow); subWindow = new Window("Sub window"); subWindow.setHeight("50%"); @@ -56,24 +61,24 @@ public class LazyWindowResize extends AbstractTestCase { lazyMode = new CheckBox("Lazy resize"); lazyMode.setImmediate(true); - lazyMode.addListener(new ClickListener() { + lazyMode.addListener(new ValueChangeListener() { - public void buttonClick(ClickEvent event) { - setLazy(lazyMode.booleanValue()); + public void valueChange(ValueChangeEvent event) { + setLazy(lazyMode.getValue()); } }); resizeListenerCheckBox = new CheckBox("Resize listener"); resizeListenerCheckBox.setImmediate(true); - resizeListenerCheckBox.addListener(new ClickListener() { + resizeListenerCheckBox.addListener(new ValueChangeListener() { - public void buttonClick(ClickEvent event) { - if (resizeListenerCheckBox.booleanValue()) { + public void valueChange(ValueChangeEvent event) { + if (resizeListenerCheckBox.getValue()) { subWindow.addListener(resizeListener); - mainWindow.addListener(resizeListener); + mainWindow.addListener(browserWindowResizeListener); } else { subWindow.removeListener(resizeListener); - mainWindow.removeListener(resizeListener); + mainWindow.removeListener(browserWindowResizeListener); } } @@ -81,12 +86,11 @@ public class LazyWindowResize extends AbstractTestCase { }); immediateCheckBox = new CheckBox("Windows immediate"); immediateCheckBox.setImmediate(true); - immediateCheckBox.addListener(new ClickListener() { - - public void buttonClick(ClickEvent event) { - mainWindow.setImmediate(immediateCheckBox.booleanValue()); - subWindow.setImmediate(immediateCheckBox.booleanValue()); + immediateCheckBox.addListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + mainWindow.setImmediate(immediateCheckBox.getValue()); + subWindow.setImmediate(immediateCheckBox.getValue()); } }); @@ -94,7 +98,7 @@ public class LazyWindowResize extends AbstractTestCase { mainWindow.addComponent(resizeListenerCheckBox); mainWindow.addComponent(immediateCheckBox); mainWindow.addComponent(log); - mainWindow.addComponent(new Label("<br/><br/>", Label.CONTENT_XHTML)); + mainWindow.addComponent(new Label("<br/><br/>", ContentMode.XHTML)); mainWindow.addComponent(new Label(LoremIpsum.get(10000))); setLazy(false); diff --git a/tests/testbench/com/vaadin/tests/components/window/LongNotifications.java b/tests/testbench/com/vaadin/tests/components/window/LongNotifications.java index c70c14e08e..c916973713 100644 --- a/tests/testbench/com/vaadin/tests/components/window/LongNotifications.java +++ b/tests/testbench/com/vaadin/tests/components/window/LongNotifications.java @@ -3,7 +3,7 @@ package com.vaadin.tests.components.window; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Window.Notification; +import com.vaadin.ui.Notification; public class LongNotifications extends TestBase { private final String text = "This is a veeeery large notification in the main window which should definitly not exist at all, in any app. But they finally do in real world applications, no matter what you do. People have small screens and desperatly try to run web apps in their iphones."; diff --git a/tests/testbench/com/vaadin/tests/components/window/ReplacingComponentsInHandleParameters.html b/tests/testbench/com/vaadin/tests/components/window/ReplacingComponentsInHandleParameters.html deleted file mode 100644 index 1b2e91617d..0000000000 --- a/tests/testbench/com/vaadin/tests/components/window/ReplacingComponentsInHandleParameters.html +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>ReplacingComponentsInHandleParameters</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">ReplacingComponentsInHandleParameters</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.window.ReplacingComponentsInHandleParameters?restartApplication</td> - <td></td> -</tr> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.window.ReplacingComponentsInHandleParameters</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowReplacingComponentsInHandleParameters::PID_STestId/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowReplacingComponentsInHandleParameters::PID_STestId/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/tests/testbench/com/vaadin/tests/components/window/ReplacingComponentsInHandleParameters.java b/tests/testbench/com/vaadin/tests/components/window/ReplacingComponentsInHandleParameters.java deleted file mode 100644 index d6fe10601f..0000000000 --- a/tests/testbench/com/vaadin/tests/components/window/ReplacingComponentsInHandleParameters.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.vaadin.tests.components.window; - -import java.util.Map; - -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.Label; -import com.vaadin.ui.Window; - -public class ReplacingComponentsInHandleParameters extends TestBase { - - @Override - protected String getDescription() { - return "Reusing debug IDs when replacing components in handleParameters() causes out of sync"; - } - - @Override - protected Integer getTicketNumber() { - return 8090; - } - - @Override - protected void setup() { - final ClickListener clickListener = new ClickListener() { - public void buttonClick(ClickEvent event) { - event.getButton().setCaption("Clicked!"); - } - }; - final Window main = new Window() { - @Override - public void handleParameters(Map<String, String[]> parameters) { - super.handleParameters(parameters); - removeAllComponents(); - addComponent(new Label( - "Reload window (without ?restartApplication), then click the button twice.")); - - Button btn = new Button("Click me", clickListener); - btn.setDebugId("TestId"); - addComponent(btn); - } - }; - setMainWindow(main); - } -} diff --git a/tests/testbench/com/vaadin/tests/components/window/SubWindowFocusAndBlurListeners.java b/tests/testbench/com/vaadin/tests/components/window/SubWindowFocusAndBlurListeners.java index 2d9d7bd5b2..988d47e29f 100644 --- a/tests/testbench/com/vaadin/tests/components/window/SubWindowFocusAndBlurListeners.java +++ b/tests/testbench/com/vaadin/tests/components/window/SubWindowFocusAndBlurListeners.java @@ -10,6 +10,7 @@ import com.vaadin.event.ShortcutAction; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root; import com.vaadin.ui.TextField; import com.vaadin.ui.Window; @@ -35,14 +36,14 @@ public class SubWindowFocusAndBlurListeners extends TestBase { window.addComponent(new TextField()); window.addListener(new FocusListener() { public void focus(FocusEvent event) { - event.getComponent().getWindow() + event.getComponent().getRoot() .showNotification("Focused window"); } }); window.addListener(new BlurListener() { public void blur(BlurEvent event) { - event.getComponent().getWindow() + event.getComponent().getRoot() .showNotification("Blurred window"); } }); @@ -56,11 +57,11 @@ public class SubWindowFocusAndBlurListeners extends TestBase { } public void handleAction(Action action, Object sender, Object target) { - window.showNotification("Action!"); + window.getRoot().showNotification("Action!"); } }); - Window main = getLayout().getWindow(); + Root main = getLayout().getRoot(); main.addWindow(window); diff --git a/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.html b/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.html index 6461960c92..0476de6c35 100644 --- a/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.html +++ b/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.html @@ -65,10 +65,16 @@ <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCssLayout[0]/VCssLayout$FlowPane[0]/VButton[1]/domChild[0]/domChild[0]</td> <td></td> </tr> -<!--Make dialog 5 modal and centered--> +<!--Bring dialog 4 to front--> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/FocusableScrollPanel[0]/VVerticalLayout[0]/VCssLayout[0]/VCssLayout$FlowPane[0]/VButton[0]/domChild[0]</td> + <td></td> +</tr> +<!--Make dialog 5 modal and centered. Dialog 4 still stays on top--> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCssLayout[0]/VCssLayout$FlowPane[0]/VFilterSelect[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/FocusableScrollPanel[0]/VVerticalLayout[0]/VCssLayout[0]/VCssLayout$FlowPane[0]/VFilterSelect[0]/domChild[1]</td> <td>11,11</td> </tr> <tr> @@ -78,28 +84,27 @@ </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCssLayout[0]/VCssLayout$FlowPane[0]/VButton[1]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/FocusableScrollPanel[0]/VVerticalLayout[0]/VCssLayout[0]/VCssLayout$FlowPane[0]/VButton[1]/domChild[0]/domChild[0]</td> <td></td> </tr> -<!--Close window 5, which is not the topmost window (???)--> +<!--Close window 4, which is the topmost window--> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[4]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/domChild[0]/domChild[0]/domChild[1]</td> <td>11,15</td> </tr> -<!--The screenshot should really be ...-window-4-modal--> <tr> <td>screenCapture</td> <td></td> - <td>window5closed-window-5-modal</td> + <td>window4-closed-window-3-modal</td> </tr> -<!--Close Dialog 4 (topmost)--> +<!--Close Dialog 3 (topmost)--> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[1]</td> <td>6,8</td> </tr> -<!--Make Dialog 3 (topmost) non-modal--> +<!--Make Dialog 5 (topmost) non-modal--> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCssLayout[0]/VCssLayout$FlowPane[0]/VFilterSelect[0]/domChild[1]</td> @@ -107,7 +112,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item3</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item5</td> <td>97,6</td> </tr> <tr> @@ -131,10 +136,10 @@ <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCssLayout[0]/VCssLayout$FlowPane[0]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> -<!--Close dialog 3--> +<!--Close dialog 5--> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[1]</td> <td>10,5</td> </tr> <tr> @@ -142,7 +147,6 @@ <td></td> <td>window2-on-top-of-window1-others-closed</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.java b/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.java index c34f32f275..9b4fcea22b 100644 --- a/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.java +++ b/tests/testbench/com/vaadin/tests/components/window/SubWindowOrder.java @@ -10,6 +10,7 @@ import com.vaadin.ui.ComboBox; import com.vaadin.ui.CssLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root; import com.vaadin.ui.Window; public class SubWindowOrder extends TestBase { @@ -19,7 +20,7 @@ public class SubWindowOrder extends TestBase { @Override protected void setup() { - Window mainWindow = getMainWindow(); + Root mainWindow = getMainWindow(); HorizontalLayout controlpanels = new HorizontalLayout(); for (int i = 1; i <= 5; i++) { Window dialog = new Window("Dialog " + i); diff --git a/tests/testbench/com/vaadin/tests/components/window/SubWindowWithUndefinedHeight.java b/tests/testbench/com/vaadin/tests/components/window/SubWindowWithUndefinedHeight.java index dbe5eda9af..60f0c598ae 100644 --- a/tests/testbench/com/vaadin/tests/components/window/SubWindowWithUndefinedHeight.java +++ b/tests/testbench/com/vaadin/tests/components/window/SubWindowWithUndefinedHeight.java @@ -33,13 +33,12 @@ public class SubWindowWithUndefinedHeight extends TestBase { table.setCaption("tab 2"); table.setWidth("100%"); table.setHeight("100%"); - + final TabSheet tabsheet = new TabSheet(); tabsheet.addComponent(tabButton); tabsheet.addComponent(table); tabsheet.addListener(new TabSheet.SelectedTabChangeListener() { - public void selectedTabChange( - TabSheet.SelectedTabChangeEvent event) { + public void selectedTabChange(TabSheet.SelectedTabChangeEvent event) { if (tabsheet.getSelectedTab() == tabButton) { tabsheet.setSizeUndefined(); subwindow.getContent().setSizeUndefined(); diff --git a/tests/testbench/com/vaadin/tests/components/window/WindowCaptionTest.html b/tests/testbench/com/vaadin/tests/components/window/WindowCaptionTest.html index 83889aedb8..a9a6fd621e 100644 --- a/tests/testbench/com/vaadin/tests/components/window/WindowCaptionTest.html +++ b/tests/testbench/com/vaadin/tests/components/window/WindowCaptionTest.html @@ -18,7 +18,7 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowTest::PID_StestComponent/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowTest::PID_StestComponent/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>Short</td> </tr> <tr> @@ -43,7 +43,7 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowTest::PID_StestComponent/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowTest::PID_StestComponent/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>This is a semi-long text that might wrap.</td> </tr> <tr> @@ -68,7 +68,7 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowTest::PID_StestComponent/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowTest::PID_StestComponent/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td></td> </tr> diff --git a/tests/testbench/com/vaadin/tests/components/window/WindowClickEvents.html b/tests/testbench/com/vaadin/tests/components/window/WindowClickEvents.html index a7dc524d6d..f679779d4b 100644 --- a/tests/testbench/com/vaadin/tests/components/window/WindowClickEvents.html +++ b/tests/testbench/com/vaadin/tests/components/window/WindowClickEvents.html @@ -23,17 +23,17 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::/VVerticalLayout[0]/domChild[0]</td> <td>154,150</td> </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::PID_SLog_row_1</td> <td>1. Click using left on Main window layout</td> </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::PID_SLog_row_0</td> <td>2. Click using left on Main window</td> </tr> <tr> @@ -43,12 +43,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::PID_SLog_row_1</td> <td>3. Click using left on Sub window layout</td> </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>vaadin=runcomvaadintestscomponentswindowWindowClickEvents::PID_SLog_row_0</td> <td>4. Click using left on Sub window</td> </tr> <!--Clicking on the button should not produce a window click event--> diff --git a/tests/testbench/com/vaadin/tests/components/window/WindowResizeListener.java b/tests/testbench/com/vaadin/tests/components/window/WindowResizeListener.java index 62f998e20e..c6563f200f 100644 --- a/tests/testbench/com/vaadin/tests/components/window/WindowResizeListener.java +++ b/tests/testbench/com/vaadin/tests/components/window/WindowResizeListener.java @@ -1,15 +1,15 @@ package com.vaadin.tests.components.window; -import com.vaadin.terminal.Sizeable; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.BrowserWindowResizeEvent; import com.vaadin.ui.Window; -import com.vaadin.ui.Window.ResizeEvent; -import com.vaadin.ui.Window.ResizeListener; public class WindowResizeListener extends TestBase { @@ -33,19 +33,20 @@ public class WindowResizeListener extends TestBase { final Label l = new Label(); getLayout().addComponent(l); - getMainWindow().addListener(new ResizeListener() { - public void windowResized(ResizeEvent e) { - l.setValue("Current main window size: " - + getMainWindow().getWidth() + " x " - + getMainWindow().getHeight()); + getMainWindow().addListener(new Root.BrowserWindowResizeListener() { + public void browserWindowResized(BrowserWindowResizeEvent event) { + l.setValue("Current browser window size: " + + getMainWindow().getBrowserWindowWidth() + " x " + + getMainWindow().getBrowserWindowHeight()); } }); CheckBox subwindow = new CheckBox("show subwindow"); subwindow.setImmediate(true); - subwindow.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (event.getButton().booleanValue()) { + subwindow.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + if ((Boolean) event.getProperty().getValue()) { getMainWindow().addWindow(subwin); } else { getMainWindow().removeWindow(subwin); @@ -55,9 +56,10 @@ public class WindowResizeListener extends TestBase { getLayout().addComponent(subwindow); CheckBox immediate = new CheckBox("immediate"); - immediate.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - boolean booleanValue = event.getButton().booleanValue(); + immediate.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + boolean booleanValue = (Boolean) event.getProperty().getValue(); getMainWindow().setImmediate(booleanValue); subwin.setImmediate(booleanValue); } @@ -94,9 +96,7 @@ class ResizeListenerWindow extends Window { } public void updateLabel() { - sizeLabel - .setValue(getWidth() + Sizeable.UNIT_SYMBOLS[getWidthUnits()] - + " x " + getHeight() - + Sizeable.UNIT_SYMBOLS[getHeightUnits()]); + sizeLabel.setValue(getWidth() + getWidthUnits().getSymbol() + " x " + + getHeight() + getHeightUnits().getSymbol()); } } diff --git a/tests/testbench/com/vaadin/tests/components/window/WindowScrollingComponentIntoView.java b/tests/testbench/com/vaadin/tests/components/window/WindowScrollingComponentIntoView.java index 200d52a389..9f3f27cf6a 100644 --- a/tests/testbench/com/vaadin/tests/components/window/WindowScrollingComponentIntoView.java +++ b/tests/testbench/com/vaadin/tests/components/window/WindowScrollingComponentIntoView.java @@ -8,6 +8,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; @@ -29,15 +30,7 @@ public class WindowScrollingComponentIntoView extends AbstractTestCase { Table table = new Table(); table.setPageLength(50); - final Button up = new Button("up"); - up.addListener(new Button.ClickListener() { - - public void buttonClick(ClickEvent event) { - up.getWindow().setScrollTop(0); - } - }); - - setMainWindow(new Window("")); + setMainWindow(new LegacyWindow("")); getMainWindow().getContent().setSizeUndefined(); Component l2 = null; @@ -82,7 +75,6 @@ public class WindowScrollingComponentIntoView extends AbstractTestCase { Panel panel = new Panel("scrollable panel"); panel.setHeight(400, Panel.UNITS_PIXELS); - panel.setScrollable(true); panel.setScrollLeft(50); panel.setScrollTop(50); panel.getContent().setSizeUndefined(); @@ -109,13 +101,15 @@ public class WindowScrollingComponentIntoView extends AbstractTestCase { ((VerticalLayout) getMainWindow().getContent()).addComponent( new Button("Scroll win to X9", new ClickListener() { public void buttonClick(ClickEvent event) { - window.scrollIntoView(x29); + throw new RuntimeException("Currently not implemented"); + // window.scrollIntoView(x29); } }), 0); ((VerticalLayout) getMainWindow().getContent()).addComponent( new Button("Scroll win to Y9", new ClickListener() { public void buttonClick(ClickEvent event) { - window.scrollIntoView(y29); + throw new RuntimeException("Currently not implemented"); + // window.scrollIntoView(y29); } }), 0); diff --git a/tests/testbench/com/vaadin/tests/components/window/WindowScrollingUp.java b/tests/testbench/com/vaadin/tests/components/window/WindowScrollingUp.java index 44e5bf0d35..2054b751ef 100644 --- a/tests/testbench/com/vaadin/tests/components/window/WindowScrollingUp.java +++ b/tests/testbench/com/vaadin/tests/components/window/WindowScrollingUp.java @@ -3,8 +3,8 @@ package com.vaadin.tests.components.window; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; public class WindowScrollingUp extends AbstractTestCase { @@ -27,11 +27,11 @@ public class WindowScrollingUp extends AbstractTestCase { up.addListener(new Button.ClickListener() { public void buttonClick(ClickEvent event) { - up.getWindow().setScrollTop(0); + up.getRoot().setScrollTop(0); } }); - setMainWindow(new Window("")); + setMainWindow(new LegacyWindow("")); getMainWindow().addComponent(table); getMainWindow().addComponent(up); diff --git a/tests/testbench/com/vaadin/tests/containers/BeanItemContainerFilteringTest.java b/tests/testbench/com/vaadin/tests/containers/BeanItemContainerFilteringTest.java index 24ff586b7b..77a3efa6ad 100644 --- a/tests/testbench/com/vaadin/tests/containers/BeanItemContainerFilteringTest.java +++ b/tests/testbench/com/vaadin/tests/containers/BeanItemContainerFilteringTest.java @@ -1,6 +1,8 @@ package com.vaadin.tests.containers; import com.vaadin.data.Item; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.util.BeanItemContainer; import com.vaadin.terminal.Sizeable; import com.vaadin.tests.components.TestBase; @@ -84,17 +86,17 @@ public class BeanItemContainerFilteringTest extends TestBase { filterString = new TextField("Filter string:", "1"); vl.addComponent(filterString); - final CheckBox cb = new CheckBox("Filter on value", - new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - container.removeAllContainerFilters(); - if (((CheckBox) event.getSource()).booleanValue()) { - container.addContainerFilter("value", - filterString.getValue().toString(), - false, false); - } - } - }); + final CheckBox cb = new CheckBox("Filter on value"); + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + container.removeAllContainerFilters(); + if (((CheckBox) event.getProperty()).getValue()) { + container.addContainerFilter("value", filterString + .getValue().toString(), false, false); + } + } + }); cb.setImmediate(true); vl.addComponent(cb); diff --git a/tests/testbench/com/vaadin/tests/containers/HierarchicalWrapperOrdering.java b/tests/testbench/com/vaadin/tests/containers/HierarchicalWrapperOrdering.java index fb5fe8c27a..f60e0c74e7 100644 --- a/tests/testbench/com/vaadin/tests/containers/HierarchicalWrapperOrdering.java +++ b/tests/testbench/com/vaadin/tests/containers/HierarchicalWrapperOrdering.java @@ -98,7 +98,8 @@ public class HierarchicalWrapperOrdering extends TestBase { // Get first item Object itemId = indexedContainer.getIdByIndex(0); Item item = indexedContainer.getItem(itemId); - Property property = item.getItemProperty("name"); + Property<String> property = (Property<String>) item + .getItemProperty("name"); // Prepend with Z so item should get sorted later property.setValue("Z " + property.getValue()); // this does not work alone, requires extraneous diff --git a/tests/testbench/com/vaadin/tests/containers/IndexedContainerFilteringTest.java b/tests/testbench/com/vaadin/tests/containers/IndexedContainerFilteringTest.java index bfa9ed5512..2ed5de3bfa 100644 --- a/tests/testbench/com/vaadin/tests/containers/IndexedContainerFilteringTest.java +++ b/tests/testbench/com/vaadin/tests/containers/IndexedContainerFilteringTest.java @@ -1,6 +1,8 @@ package com.vaadin.tests.containers; import com.vaadin.data.Item; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.util.IndexedContainer; import com.vaadin.terminal.Sizeable; import com.vaadin.tests.components.TestBase; @@ -51,10 +53,12 @@ public class IndexedContainerFilteringTest extends TestBase { filterString = new TextField("Filter string:", "1"); vl.addComponent(filterString); - final CheckBox cb = new CheckBox("Filter", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + final CheckBox cb = new CheckBox("Filter"); + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { container.removeAllContainerFilters(); - if (((CheckBox) event.getSource()).booleanValue()) { + if (((CheckBox) event.getProperty()).getValue()) { container.addContainerFilter("column1", filterString .getValue().toString(), false, false); } diff --git a/tests/testbench/com/vaadin/tests/containers/TableWithFileSystemContainer.java b/tests/testbench/com/vaadin/tests/containers/TableWithFileSystemContainer.java index 20567e70af..459c234c24 100644 --- a/tests/testbench/com/vaadin/tests/containers/TableWithFileSystemContainer.java +++ b/tests/testbench/com/vaadin/tests/containers/TableWithFileSystemContainer.java @@ -4,8 +4,8 @@ import java.io.File; import com.vaadin.data.util.FilesystemContainer; import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; public class TableWithFileSystemContainer extends TestBase { @@ -13,7 +13,7 @@ public class TableWithFileSystemContainer extends TestBase { @Override public void setup() { - setMainWindow(new Window("")); + setMainWindow(new LegacyWindow("")); Table table = new Table("Documents", new FilesystemContainer(new File( testPath))); table.setWidth("100%"); diff --git a/tests/testbench/com/vaadin/tests/containers/TestItemSorter.java b/tests/testbench/com/vaadin/tests/containers/TestItemSorter.java index bf7ce6175a..0a1c592876 100644 --- a/tests/testbench/com/vaadin/tests/containers/TestItemSorter.java +++ b/tests/testbench/com/vaadin/tests/containers/TestItemSorter.java @@ -29,8 +29,8 @@ public class TestItemSorter extends TestBase { public int compare(Object o1, Object o2) { if (o1 instanceof CheckBox && o2 instanceof CheckBox) { - Boolean b1 = ((CheckBox) o1).booleanValue(); - return b1.compareTo(((CheckBox) o2).booleanValue()); + Boolean b1 = (Boolean) ((CheckBox) o1).getValue(); + return b1.compareTo((Boolean) ((CheckBox) o2).getValue()); } else if (o1 instanceof Button && o2 instanceof Button) { String caption1 = ((Button) o1).getCaption().toLowerCase(); String caption2 = ((Button) o2).getCaption().toLowerCase(); diff --git a/tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java b/tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java index 86aee2d5ab..674f610ed7 100644 --- a/tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java +++ b/tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java @@ -17,14 +17,13 @@ import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; import com.vaadin.data.util.sqlcontainer.query.TableQuery; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Form; import com.vaadin.ui.HorizontalSplitPanel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class CheckboxUpdateProblem extends Application implements - Property.ValueChangeListener { +public class CheckboxUpdateProblem extends Application.LegacyApplication + implements Property.ValueChangeListener { private final DatabaseHelper databaseHelper = new DatabaseHelper(); private Table testList; private final HorizontalSplitPanel horizontalSplit = new HorizontalSplitPanel(); @@ -33,7 +32,7 @@ public class CheckboxUpdateProblem extends Application implements @Override public void init() { - setMainWindow(new Window("Test window")); + setMainWindow(new LegacyWindow("Test window")); horizontalSplit.setSizeFull(); testList = new Table(); @@ -65,7 +64,7 @@ public class CheckboxUpdateProblem extends Application implements public void valueChange(ValueChangeEvent event) { - Property property = event.getProperty(); + Property<?> property = event.getProperty(); if (property == testList) { Item item = testList.getItem(testList.getValue()); @@ -85,7 +84,7 @@ public class CheckboxUpdateProblem extends Application implements setWriteThrough(false); setInvalidCommitted(false); - save = new Button("Save", (ClickListener) this); + save = new Button("Save", this); getFooter().addComponent(save); getFooter().setVisible(false); } @@ -187,4 +186,4 @@ public class CheckboxUpdateProblem extends Application implements } } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/containers/sqlcontainer/MassInsertMemoryLeakTestApp.java b/tests/testbench/com/vaadin/tests/containers/sqlcontainer/MassInsertMemoryLeakTestApp.java index 419e606bfc..2b76612c35 100644 --- a/tests/testbench/com/vaadin/tests/containers/sqlcontainer/MassInsertMemoryLeakTestApp.java +++ b/tests/testbench/com/vaadin/tests/containers/sqlcontainer/MassInsertMemoryLeakTestApp.java @@ -12,8 +12,8 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.ProgressIndicator; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; // author table in testdb (MySQL) is set out as follows // +-------------+-------------+------+-----+---------+----------------+ @@ -25,14 +25,14 @@ import com.vaadin.ui.Window; // +-------------+-------------+------+-----+---------+----------------+ @SuppressWarnings("serial") -public class MassInsertMemoryLeakTestApp extends Application { +public class MassInsertMemoryLeakTestApp extends Application.LegacyApplication { ProgressIndicator proggress = new ProgressIndicator(); Button process = new Button("Mass insert"); @Override public void init() { - setMainWindow(new Window("SQLContainer Test", buildLayout())); + setMainWindow(new LegacyWindow("SQLContainer Test", buildLayout())); process.addListener(new Button.ClickListener() { public void buttonClick(ClickEvent event) { diff --git a/tests/testbench/com/vaadin/tests/converter/ConverterThatEnforcesAFormat.java b/tests/testbench/com/vaadin/tests/converter/ConverterThatEnforcesAFormat.java new file mode 100644 index 0000000000..8b17cb3f48 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/converter/ConverterThatEnforcesAFormat.java @@ -0,0 +1,46 @@ +package com.vaadin.tests.converter; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.TextField; + +public class ConverterThatEnforcesAFormat extends TestBase { + + private Log log = new Log(5); + + @Override + protected void setup() { + final TextField tf = new TextField( + "This field should always be formatted with 3 digits"); + tf.setConverter(new StringToDoubleConverterWithThreeFractionDigits()); + tf.addListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + log.log("Value changed to " + + event.getProperty().getValue() + + "(converted value is " + + tf.getConvertedValue() + + "). Two-way conversion gives: " + + tf.getConverter().convertToPresentation( + tf.getConverter().convertToModel(tf.getValue(), + tf.getLocale()), tf.getLocale()) + ")"); + } + }); + tf.setImmediate(true); + addComponent(log); + addComponent(tf); + tf.setConvertedValue(50.0); + } + + @Override + protected String getDescription() { + return "Entering a valid double in the field should always cause the field contents to be formatted to contain 3 digits after the decimal point"; + } + + @Override + protected Integer getTicketNumber() { + return 8191; + } + +} diff --git a/tests/testbench/com/vaadin/tests/converter/StringToDoubleConverterWithThreeFractionDigits.java b/tests/testbench/com/vaadin/tests/converter/StringToDoubleConverterWithThreeFractionDigits.java new file mode 100644 index 0000000000..23c22a7026 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/converter/StringToDoubleConverterWithThreeFractionDigits.java @@ -0,0 +1,19 @@ +package com.vaadin.tests.converter; + +import java.text.NumberFormat; +import java.util.Locale; + +import com.vaadin.data.util.converter.StringToDoubleConverter; + +public class StringToDoubleConverterWithThreeFractionDigits extends + StringToDoubleConverter { + + @Override + protected NumberFormat getFormat(Locale locale) { + NumberFormat format = super.getFormat(locale); + format.setGroupingUsed(false); + format.setMaximumFractionDigits(3); + format.setMinimumFractionDigits(3); + return format; + } +} diff --git a/tests/testbench/com/vaadin/tests/dd/ActiveDragSourceClassName.java b/tests/testbench/com/vaadin/tests/dd/ActiveDragSourceClassName.java index 889c6bb47b..93e99274bb 100644 --- a/tests/testbench/com/vaadin/tests/dd/ActiveDragSourceClassName.java +++ b/tests/testbench/com/vaadin/tests/dd/ActiveDragSourceClassName.java @@ -25,25 +25,26 @@ public class ActiveDragSourceClassName extends TestBase { protected void setup() { TestUtils.injectCSS(getMainWindow(), GREENBOXES + HIDEDRAGSOURCE); - + VerticalLayout l = new VerticalLayout(); l.setWidth("400px"); l.setHeight("100px"); DragAndDropWrapper pane = new DragAndDropWrapper(cssLayout); pane.setSizeFull(); l.addComponent(pane); - + addComponent(l); - + for (int i = 0; i < 4; i++) { cssLayout.addComponent(new WrappedLabel("Block")); } - + } - + static int count; - private CssLayout cssLayout = new CssLayout() {}; + private CssLayout cssLayout = new CssLayout() { + }; class WrappedLabel extends DragAndDropWrapper { diff --git a/tests/testbench/com/vaadin/tests/dd/CustomDDImplementation.java b/tests/testbench/com/vaadin/tests/dd/CustomDDImplementation.java index c789ead113..2b38a3438e 100644 --- a/tests/testbench/com/vaadin/tests/dd/CustomDDImplementation.java +++ b/tests/testbench/com/vaadin/tests/dd/CustomDDImplementation.java @@ -9,7 +9,6 @@ import com.vaadin.event.dd.TargetDetails; import com.vaadin.event.dd.acceptcriteria.AcceptAll; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.ui.AbstractComponent; -import com.vaadin.ui.ClientWidget; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.CustomComponent; @@ -38,7 +37,6 @@ public class CustomDDImplementation extends CustomComponent { * Check the @ClientWidget * */ - @ClientWidget(VMyDropTarget.class) class MyDropTarget extends AbstractComponent implements DropTarget { public DropHandler getDropHandler() { return new DropHandler() { @@ -76,7 +74,6 @@ public class CustomDDImplementation extends CustomComponent { * operations that are controlled via server side api. * */ - @ClientWidget(VMyDragSource.class) public class MyDragSource extends AbstractComponent implements Component { } diff --git a/tests/testbench/com/vaadin/tests/dd/DDTest2.java b/tests/testbench/com/vaadin/tests/dd/DDTest2.java index 69af2d3f1d..0dda0d693c 100644 --- a/tests/testbench/com/vaadin/tests/dd/DDTest2.java +++ b/tests/testbench/com/vaadin/tests/dd/DDTest2.java @@ -24,6 +24,7 @@ import com.vaadin.ui.AbstractSelect; import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails; import com.vaadin.ui.AbstractSelect.AcceptItem; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root; import com.vaadin.ui.Table; import com.vaadin.ui.Table.TableTransferable; import com.vaadin.ui.Tree; @@ -44,7 +45,7 @@ public class DDTest2 extends TestBase { @Override protected void setup() { - Window w = getLayout().getWindow(); + Root w = getLayout().getRoot(); /* darn reindeer has no icons */ /* Make all trees (their nodes actually) draggable */ @@ -94,12 +95,13 @@ public class DDTest2 extends TestBase { if (transferable instanceof TableTransferable) { TableTransferable tr = (TableTransferable) transferable; System.out.println("From table row" + tr.getPropertyId()); - data = tr.getSourceContainer().getItem(tr.getItemId()) - .getItemProperty(tr.getPropertyId()).toString(); - + Object value = tr.getSourceContainer() + .getItem(tr.getItemId()) + .getItemProperty(tr.getPropertyId()).getValue(); + data = (null != value) ? value.toString() : null; } if (data == null) { - data = "-no Text data flawor-"; + data = "-no Text data flavor-"; } tree3.addItem(data); AbstractSelect.AbstractSelectTargetDetails dropTargetData = (AbstractSelect.AbstractSelectTargetDetails) dropEvent @@ -137,7 +139,7 @@ public class DDTest2 extends TestBase { public void drop(DragAndDropEvent event) { /* * We know transferrable is from table, so it is of type - * DataBindedTransferrable + * DataBoundTransferrable */ DataBoundTransferable tr = (DataBoundTransferable) event .getTransferable(); @@ -147,8 +149,10 @@ public class DDTest2 extends TestBase { // if the source is from table (not from tree1 itself), // transfer Name property and use it as an identifier in // tree1 - String name = sourceContainer.getItem(itemId) - .getItemProperty("Name").toString(); + Object nameValue = sourceContainer.getItem(itemId) + .getItemProperty("Name").getValue(); + String name = (null != nameValue) ? nameValue.toString() + : null; tree1.addItem(name); tree1.setChildrenAllowed(name, false); diff --git a/tests/testbench/com/vaadin/tests/dd/DDTest4.java b/tests/testbench/com/vaadin/tests/dd/DDTest4.java index b4da141ce2..654a30486a 100644 --- a/tests/testbench/com/vaadin/tests/dd/DDTest4.java +++ b/tests/testbench/com/vaadin/tests/dd/DDTest4.java @@ -16,8 +16,8 @@ import com.vaadin.tests.util.PersonContainer; import com.vaadin.tests.util.TestUtils; import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; public class DDTest4 extends TestBase { @@ -28,7 +28,7 @@ public class DDTest4 extends TestBase { @Override protected void setup() { - Window w = getLayout().getWindow(); + Root w = getLayout().getRoot(); TestUtils .injectCSS( diff --git a/tests/testbench/com/vaadin/tests/dd/DDTest5.java b/tests/testbench/com/vaadin/tests/dd/DDTest5.java index e4f3d5335d..a5d97f4473 100644 --- a/tests/testbench/com/vaadin/tests/dd/DDTest5.java +++ b/tests/testbench/com/vaadin/tests/dd/DDTest5.java @@ -15,7 +15,7 @@ import com.vaadin.ui.DragAndDropWrapper.DragStartMode; import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root; public class DDTest5 extends TestBase { @@ -47,7 +47,7 @@ public class DDTest5 extends TestBase { @Override protected void setup() { - Window w = getLayout().getWindow(); + Root w = getLayout().getRoot(); HorizontalSortableCssLayoutWithWrappers verticalSortableCssLayoutWithWrappers = new HorizontalSortableCssLayoutWithWrappers(); w.addWindow(verticalSortableCssLayoutWithWrappers); diff --git a/tests/testbench/com/vaadin/tests/dd/DDTest6.java b/tests/testbench/com/vaadin/tests/dd/DDTest6.java index 4299b321c3..c6c6689bcb 100644 --- a/tests/testbench/com/vaadin/tests/dd/DDTest6.java +++ b/tests/testbench/com/vaadin/tests/dd/DDTest6.java @@ -159,7 +159,7 @@ public class DDTest6 extends TestBase { getLayout().addComponent(sp); TestUtils .injectCSS( - getLayout().getWindow(), + getLayout().getRoot(), "" + ".v-tree .v-icon {height:16px;} " + ".v-tree-node-caption-drag-top {/*border-top: none;*/} " diff --git a/tests/testbench/com/vaadin/tests/dd/DDTest7.java b/tests/testbench/com/vaadin/tests/dd/DDTest7.java index 6027b3e499..26521f5a57 100644 --- a/tests/testbench/com/vaadin/tests/dd/DDTest7.java +++ b/tests/testbench/com/vaadin/tests/dd/DDTest7.java @@ -16,8 +16,8 @@ import com.vaadin.tests.util.PersonContainer; import com.vaadin.tests.util.TestUtils; import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; public class DDTest7 extends TestBase { @@ -29,7 +29,7 @@ public class DDTest7 extends TestBase { @Override protected void setup() { - Window w = getLayout().getWindow(); + Root w = getLayout().getRoot(); TestUtils .injectCSS( diff --git a/tests/testbench/com/vaadin/tests/dd/DragAndDropFiles.java b/tests/testbench/com/vaadin/tests/dd/DragAndDropFiles.java index ad23338bbf..4b4ec75f0e 100644 --- a/tests/testbench/com/vaadin/tests/dd/DragAndDropFiles.java +++ b/tests/testbench/com/vaadin/tests/dd/DragAndDropFiles.java @@ -67,8 +67,7 @@ public class DragAndDropFiles extends TestBase { return true; } - public void onProgress( - StreamingProgressEvent event) { + public void onProgress(StreamingProgressEvent event) { System.err.println("Progress" + event.getBytesReceived()); } diff --git a/tests/testbench/com/vaadin/tests/dd/MyDragSourceConnector.java b/tests/testbench/com/vaadin/tests/dd/MyDragSourceConnector.java new file mode 100644 index 0000000000..c94ac05ea2 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/dd/MyDragSourceConnector.java @@ -0,0 +1,30 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.tests.dd; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.tests.dd.CustomDDImplementation.MyDragSource; + +@Connect(MyDragSource.class) +public class MyDragSourceConnector extends AbstractComponentConnector implements + Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + } + + @Override + protected Widget createWidget() { + return GWT.create(VMyDragSource.class); + } + +} diff --git a/tests/testbench/com/vaadin/tests/dd/MyDropTargetConnector.java b/tests/testbench/com/vaadin/tests/dd/MyDropTargetConnector.java new file mode 100644 index 0000000000..0021cbf7ea --- /dev/null +++ b/tests/testbench/com/vaadin/tests/dd/MyDropTargetConnector.java @@ -0,0 +1,36 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.tests.dd; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.Paintable; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; +import com.vaadin.terminal.gwt.client.ui.Connect; +import com.vaadin.tests.dd.CustomDDImplementation.MyDropTarget; + +@Connect(MyDropTarget.class) +public class MyDropTargetConnector extends AbstractComponentConnector implements + Paintable { + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + if (!isRealUpdate(uidl)) { + return; + } + getWidget().client = client; + } + + @Override + public VMyDropTarget getWidget() { + return (VMyDropTarget) super.getWidget(); + } + + @Override + protected Widget createWidget() { + return GWT.create(VMyDropTarget.class); + } + +} diff --git a/tests/testbench/com/vaadin/tests/dd/TreeDragStart.java b/tests/testbench/com/vaadin/tests/dd/TreeDragStart.java index 4a719bfa7f..4ef7023aa6 100644 --- a/tests/testbench/com/vaadin/tests/dd/TreeDragStart.java +++ b/tests/testbench/com/vaadin/tests/dd/TreeDragStart.java @@ -48,7 +48,7 @@ public class TreeDragStart extends TestBase { checkBox.setValue(true); checkBox.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - if (((CheckBox) event.getProperty()).booleanValue()) { + if ((Boolean) ((CheckBox) event.getProperty()).getValue()) { tree.setDragMode(TreeDragMode.NODE); } else { tree.setDragMode(TreeDragMode.NONE); diff --git a/tests/testbench/com/vaadin/tests/dd/VMyDragSource.java b/tests/testbench/com/vaadin/tests/dd/VMyDragSource.java index 350ee064f3..7e91d2b9aa 100644 --- a/tests/testbench/com/vaadin/tests/dd/VMyDragSource.java +++ b/tests/testbench/com/vaadin/tests/dd/VMyDragSource.java @@ -10,23 +10,20 @@ import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; import com.vaadin.terminal.gwt.client.ui.dd.VTransferable; /** * Example code to implement Component that has something to drag. */ -public class VMyDragSource extends Composite implements Paintable, - MouseDownHandler, MouseMoveHandler, MouseOutHandler { +public class VMyDragSource extends Composite implements MouseDownHandler, + MouseMoveHandler, MouseOutHandler { private boolean mouseDown; private MouseDownEvent mDownEvent; - @SuppressWarnings("unused") - private ApplicationConnection client; + @SuppressWarnings("unused") public VMyDragSource() { FlowPanel fp = new FlowPanel(); initWidget(fp); @@ -41,13 +38,6 @@ public class VMyDragSource extends Composite implements Paintable, } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (client.updateComponent(this, uidl, true)) { - return; - } - this.client = client; - } - /* * Below a sophisticated drag start implementation. Drag event is started if * mouse is moved 5 pixels with left mouse key down. @@ -89,4 +79,8 @@ public class VMyDragSource extends Composite implements Paintable, mDownEvent = null; } + public Widget getWidgetForPaintable() { + return this; + } + } diff --git a/tests/testbench/com/vaadin/tests/dd/VMyDropTarget.java b/tests/testbench/com/vaadin/tests/dd/VMyDropTarget.java index 743cce3095..582c951251 100644 --- a/tests/testbench/com/vaadin/tests/dd/VMyDropTarget.java +++ b/tests/testbench/com/vaadin/tests/dd/VMyDropTarget.java @@ -2,16 +2,15 @@ package com.vaadin.tests.dd; import com.google.gwt.user.client.ui.Composite; import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.ComponentConnector; import com.vaadin.terminal.gwt.client.ui.dd.VDragEvent; import com.vaadin.terminal.gwt.client.ui.dd.VDropHandler; import com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler; public class VMyDropTarget extends Composite implements VHasDropHandler, - VDropHandler, Paintable { + VDropHandler { - private ApplicationConnection client; + ApplicationConnection client; public void dragEnter(VDragEvent drag) { } @@ -30,23 +29,18 @@ public class VMyDropTarget extends Composite implements VHasDropHandler, return false; } - public Paintable getPaintable() { - // Drophandler implemented by Paintable itself + public VDropHandler getDropHandler() { + // Drophandler implemented by widget itself return this; } - public VDropHandler getDropHandler() { - // Drophandler implemented by Paintable itself - return this; + public ComponentConnector getConnector() { + // TODO Auto-generated method stub + return null; } public ApplicationConnection getApplicationConnection() { return client; } - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - this.client = client; - - } - } diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/AbstractBeanFieldGroupTest.java b/tests/testbench/com/vaadin/tests/fieldgroup/AbstractBeanFieldGroupTest.java new file mode 100644 index 0000000000..584ce0ec36 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/AbstractBeanFieldGroupTest.java @@ -0,0 +1,96 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.fieldgroup.BeanFieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup.CommitException; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Root; + +public abstract class AbstractBeanFieldGroupTest extends TestBase { + + private Button commitButton; + protected Log log = new Log(5); + + private Button discardButton; + private Button showBeanButton; + private BeanFieldGroup fieldBinder; + + @Override + protected void setup() { + addComponent(log); + } + + protected Button getDiscardButton() { + if (discardButton == null) { + discardButton = new Button("Discard", new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + getFieldBinder().discard(); + log.log("Discarded changes"); + + } + }); + } + return discardButton; + } + + protected Button getShowBeanButton() { + if (showBeanButton == null) { + showBeanButton = new Button("Show bean values", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + log.log(getFieldBinder().getItemDataSource() + .getBean().toString()); + + } + }); + } + return showBeanButton; + } + + protected Button getCommitButton() { + if (commitButton == null) { + commitButton = new Button("Commit"); + commitButton.addListener(new ClickListener() { + + public void buttonClick(ClickEvent event) { + String msg = "Commit succesful"; + try { + getFieldBinder().commit(); + } catch (CommitException e) { + msg = "Commit failed: " + e.getMessage(); + } + Root.getCurrentRoot().showNotification(msg); + log.log(msg); + + } + }); + } + return commitButton; + } + + protected BeanFieldGroup getFieldBinder() { + return fieldBinder; + } + + protected void setFieldBinder(BeanFieldGroup beanFieldBinder) { + fieldBinder = beanFieldBinder; + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/BasicPersonForm.java b/tests/testbench/com/vaadin/tests/fieldgroup/BasicPersonForm.java new file mode 100644 index 0000000000..f95c172348 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/BasicPersonForm.java @@ -0,0 +1,192 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.fieldgroup.BeanFieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup.CommitEvent; +import com.vaadin.data.fieldgroup.FieldGroup.CommitException; +import com.vaadin.data.fieldgroup.FieldGroup.CommitHandler; +import com.vaadin.data.util.BeanItem; +import com.vaadin.data.util.converter.StringToBooleanConverter; +import com.vaadin.data.validator.EmailValidator; +import com.vaadin.data.validator.IntegerRangeValidator; +import com.vaadin.data.validator.StringLengthValidator; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Panel; +import com.vaadin.ui.Root; +import com.vaadin.ui.Table; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; + +public class BasicPersonForm extends TestBase { + + private Log log = new Log(5); + private TextField firstName; + private TextArea lastName; + private TextField email; + private TextField age; + private Table sex; + private TextField deceased; + + public class Configuration { + public boolean preCommitFails = false; + public boolean postCommitFails = false; + + public boolean isPreCommitFails() { + return preCommitFails; + } + + public void setPreCommitFails(boolean preCommitFails) { + this.preCommitFails = preCommitFails; + } + + public boolean isPostCommitFails() { + return postCommitFails; + } + + public void setPostCommitFails(boolean postCommitFails) { + this.postCommitFails = postCommitFails; + } + + } + + private Configuration configuration = new Configuration(); + + private class ConfigurationPanel extends Panel { + + public ConfigurationPanel() { + super("Configuration"); + BeanItem<Configuration> bi = new BeanItem<BasicPersonForm.Configuration>( + configuration); + FieldGroup confFieldGroup = new FieldGroup(bi); + confFieldGroup.setItemDataSource(bi); + confFieldGroup.setBuffered(false); + + for (Object propertyId : bi.getItemPropertyIds()) { + addComponent(confFieldGroup.buildAndBind(propertyId)); + } + + } + } + + @Override + protected void setup() { + addComponent(log); + Panel confPanel = new ConfigurationPanel(); + addComponent(confPanel); + + final FieldGroup fieldGroup = new BeanFieldGroup<Person>(Person.class); + fieldGroup.addCommitHandler(new CommitHandler() { + + public void preCommit(CommitEvent commitEvent) + throws CommitException { + if (configuration.preCommitFails) { + throw new CommitException( + "Error in preCommit because first name is " + + getPerson(commitEvent.getFieldBinder()) + .getFirstName()); + } + + } + + public void postCommit(CommitEvent commitEvent) + throws CommitException { + if (configuration.postCommitFails) { + throw new CommitException( + "Error in postCommit because first name is " + + getPerson(commitEvent.getFieldBinder()) + .getFirstName()); + } + } + }); + + fieldGroup.setBuffered(true); + + fieldGroup.buildAndBindMemberFields(this); + addComponent(firstName); + addComponent(lastName); + addComponent(email); + addComponent(age); + addComponent(sex); + addComponent(deceased); + + Button commitButton = new Button("Commit", new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + String msg = "Commit succesful"; + try { + fieldGroup.commit(); + } catch (CommitException e) { + msg = "Commit failed: " + e.getMessage(); + } + Root.getCurrentRoot().showNotification(msg); + log.log(msg); + + } + }); + Button discardButton = new Button("Discard", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + fieldGroup.discard(); + log.log("Discarded changes"); + + } + }); + Button showBean = new Button("Show bean values", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + log.log(getPerson(fieldGroup).toString()); + + } + }); + addComponent(commitButton); + addComponent(discardButton); + addComponent(showBean); + email.addValidator(new EmailValidator("Must be a valid address")); + lastName.addValidator(new StringLengthValidator("Must be min 5 chars", + 5, null, true)); + + age.addValidator(new IntegerRangeValidator( + "Must be between 0 and 150, {0} is not", 0, 150)); + sex.setPageLength(0); + deceased.setConverter(new StringToBooleanConverter() { + @Override + protected String getTrueString() { + return "YAY!"; + } + + @Override + protected String getFalseString() { + return "NAAAAAH"; + } + }); + Person p = new Person("John", "Doe", "john@doe.com", 64, Sex.MALE, + new Address("John street", 11223, "John's town", Country.USA)); + fieldGroup.setItemDataSource(new BeanItem<Person>(p)); + } + + public static Person getPerson(FieldGroup binder) { + return ((BeanItem<Person>) binder.getItemDataSource()).getBean(); + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/BooleanTextField.html b/tests/testbench/com/vaadin/tests/fieldgroup/BooleanTextField.html new file mode 100644 index 0000000000..3d5e1052c3 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/BooleanTextField.html @@ -0,0 +1,141 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.fieldgroup.BasicPersonForm?restartApplication</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>initial</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>90,38</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Dover</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>1. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> +</tr> +<tr> + <td>drag</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>108,9</td> +</tr> +<tr> + <td>drop</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]</td> + <td>0,587</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>-18,9</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>false</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]</td> + <td>239,14</td> +</tr> +<!--error indicator--> +<tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[7]/domChild[0]/domChild[1]</td> + <td>v-errorindicator</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>false</td> +</tr> +<!--show bean values--> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>2. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> +</tr> +<!--error message in tooltip--> +<tr> + <td>showTooltip</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>0,0</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]/FlowPanel[0]/VErrorMessage[0]/HTML[0]</td> + <td>Could not convert value to Boolean</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>66,6</td> +</tr> +<tr> + <td>type</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>YAY!</td> +</tr> +<!--no error indicator--> +<tr> + <td>assertElementNotPresent</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[0]/domChild[7]/domChild[0]/domChild[1]</td> + <td>v-errorindicator</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> +</tr> +<!--commit last name and new deceased status--> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>4. Person [firstName=John, lastName=Dover, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=true, salary=null, salaryDouble=null, rent=null]</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/CommitHandlerFailures.html b/tests/testbench/com/vaadin/tests/fieldgroup/CommitHandlerFailures.html new file mode 100644 index 0000000000..2ad104c16c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/CommitHandlerFailures.html @@ -0,0 +1,220 @@ +package com.vaadin.tests.fieldgroup; + +public class CommitHandlerFailures_html { + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://selenium-ide.openqa.org/profiles/test-case"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <link rel="selenium.base" href="" /> + <title>New Test</title> + </head> + <body> + <table cellpadding="1" cellspacing="1" border="1"> + <thead> + <tr><td rowspan="1" colspan="3">New Test</td></tr> + </thead><tbody> + <tr> + <td>open</td> + <td>/run/com.vaadin.tests.fieldgroup.BasicPersonForm?restartApplication</td> + <td></td> + </tr> + <!--assert we are starting with what we think we are starting with--> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VTextField[0]</td> + <td>John</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doe</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTextField[0]</td> + <td>john@doe.com</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64</td> + </tr> + <tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>v-selected</td> + </tr> + <tr> + <td>assertNotCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]</td> + <td>v-selected</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>NAAAAAH</td> + </tr> + <!--Make changes to fields--> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doeve</td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VTextField[0]</td> + <td>Mike</td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTextField[0]</td> + <td>me@me.com</td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>12</td> + </tr> + <tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td> + <td>31,10</td> + </tr> + <!--show bean values--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>1. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + <!--pre commit fails--> + <tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCheckBox[0]/domChild[0]</td> + <td>35,6</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>2. Commit failed: Commit failed</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>3. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + <!--post commit fails--> + <tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VCheckBox[0]/domChild[0]</td> + <td>10,7</td> + </tr> + <tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VCheckBox[0]/domChild[0]</td> + <td>9,7</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>4. Commit failed: Commit failed</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>5. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + <!--discard and ensure old values are returned as all commits have failed--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VTextField[0]</td> + <td>John</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doe</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTextField[0]</td> + <td>john@doe.com</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64</td> + </tr> + <tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>v-selected</td> + </tr> + <tr> + <td>assertNotCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]</td> + <td>v-selected</td> + </tr> + <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>NAAAAAH</td> + </tr> + <!--show bean values--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>7. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + + </tbody></table> + </body> + </html> + +} + diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/CommitWithValidationOrConversionError.html b/tests/testbench/com/vaadin/tests/fieldgroup/CommitWithValidationOrConversionError.html new file mode 100644 index 0000000000..2c88930077 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/CommitWithValidationOrConversionError.html @@ -0,0 +1,150 @@ + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://selenium-ide.openqa.org/profiles/test-case"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <link rel="selenium.base" href="" /> + <title>New Test</title> + </head> + <body> + <table cellpadding="1" cellspacing="1" border="1"> + <thead> + <tr><td rowspan="1" colspan="3">New Test</td></tr> + </thead><tbody> + <tr> + <td>open</td> + <td>/run/com.vaadin.tests.fieldgroup.BasicPersonForm?restartApplication</td> + <td></td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doev</td> + </tr> + <!--commit with invalid field must fail--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>1. Commit failed: Commit failed</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>2. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64,2</td> + </tr> + <!--commit with 2 fails--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>3. Commit failed: Commit failed</td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doever</td> + </tr> + <!--1 error fixed, still 1 conversion error--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>4. Commit failed: Commit failed</td> + </tr> + <tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>123</td> + </tr> + <!--all fields ok, commit should be ok--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>closeNotification</td> + <td>//body/div[2]</td> + <td>0,0</td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>5. Commit succesful</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>6. Person [firstName=John, lastName=Doever, email=john@doe.com, age=123, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + <!--discard should now have no effect--> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>7. Discarded changes</td> + </tr> + <tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]</td> + <td></td> + </tr> + <tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>8. Person [firstName=John, lastName=Doever, email=john@doe.com, age=123, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> + </tr> + + </tbody></table> + </body> + </html> + +} + diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FieldBinderWithBeanValidation.java b/tests/testbench/com/vaadin/tests/fieldgroup/FieldBinderWithBeanValidation.java new file mode 100644 index 0000000000..9ff553ce61 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FieldBinderWithBeanValidation.java @@ -0,0 +1,106 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.fieldgroup.BeanFieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup.CommitException; +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.PersonWithBeanValidationAnnotations; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root; +import com.vaadin.ui.Table; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; + +public class FieldBinderWithBeanValidation extends TestBase { + + private Log log = new Log(5); + private TextField firstName; + private TextArea lastName; + private TextField email; + private TextField age; + private Table sex; + private TextField deceased; + + @Override + protected void setup() { + addComponent(log); + + final BeanFieldGroup<PersonWithBeanValidationAnnotations> fieldGroup = new BeanFieldGroup<PersonWithBeanValidationAnnotations>( + PersonWithBeanValidationAnnotations.class); + + fieldGroup.buildAndBindMemberFields(this); + addComponent(firstName); + addComponent(lastName); + addComponent(email); + addComponent(age); + addComponent(sex); + addComponent(deceased); + + Button commitButton = new Button("Commit", new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + String msg = "Commit succesful"; + try { + fieldGroup.commit(); + } catch (CommitException e) { + msg = "Commit failed: " + e.getMessage(); + } + Root.getCurrentRoot().showNotification(msg); + log.log(msg); + + } + }); + Button discardButton = new Button("Discard", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + fieldGroup.discard(); + log.log("Discarded changes"); + + } + }); + Button showBean = new Button("Show bean values", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + log.log(getPerson(fieldGroup).toString()); + + } + }); + addComponent(commitButton); + addComponent(discardButton); + addComponent(showBean); + sex.setPageLength(0); + + PersonWithBeanValidationAnnotations p = new PersonWithBeanValidationAnnotations( + "John", "Doe", "john@doe.com", 64, Sex.MALE, new Address( + "John street", 11223, "John's town", Country.USA)); + fieldGroup + .setItemDataSource(new BeanItem<PersonWithBeanValidationAnnotations>( + p)); + } + + public static Person getPerson(FieldGroup binder) { + return ((BeanItem<Person>) binder.getItemDataSource()).getBean(); + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FieldGroupDiscard.html b/tests/testbench/com/vaadin/tests/fieldgroup/FieldGroupDiscard.html new file mode 100644 index 0000000000..a2ac1b748b --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FieldGroupDiscard.html @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.fieldgroup.BasicPersonForm?restartApplication</td> + <td></td> +</tr> +<!--assert we are starting with what we think we are starting with--> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VTextField[0]</td> + <td>John</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doe</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTextField[0]</td> + <td>john@doe.com</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64</td> +</tr> +<tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>v-selected</td> +</tr> +<tr> + <td>assertNotCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]</td> + <td>v-selected</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>NAAAAAH</td> +</tr> +<!--make some changes--> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VTextField[0]</td> + <td>John123</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doe123</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTextField[0]</td> + <td>john@doe.com123</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64123</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>33,8</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>72,10</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>-18,15</td> +</tr> +<tr> + <td>type</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>YAY!</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>1. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>2. Discarded changes</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[10]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::PID_SLog_row_0</td> + <td>3. Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]</td> +</tr> +<!--we should still be at the state we started from--> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VTextField[0]</td> + <td>John</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VTextArea[0]</td> + <td>Doe</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTextField[0]</td> + <td>john@doe.com</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64</td> +</tr> +<tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]</td> + <td>v-selected</td> +</tr> +<tr> + <td>assertNotCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]</td> + <td>v-selected</td> +</tr> +<tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VTextField[0]</td> + <td>NAAAAAH</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FormBuilderWithNestedProperties.java b/tests/testbench/com/vaadin/tests/fieldgroup/FormBuilderWithNestedProperties.java new file mode 100644 index 0000000000..5f25070f2e --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FormBuilderWithNestedProperties.java @@ -0,0 +1,47 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.fieldgroup.BeanFieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.data.fieldgroup.PropertyId; +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.ui.TextField; + +public class FormBuilderWithNestedProperties extends TestBase { + + private TextField firstName; + private TextField lastName; + @PropertyId("address.streetAddress") + private TextField streetAddress; + + @Override + protected void setup() { + FieldGroup fieldGroup = new BeanFieldGroup<Person>(Person.class); + fieldGroup.buildAndBindMemberFields(this); + + addComponent(firstName); + addComponent(lastName); + addComponent(streetAddress); + + fieldGroup.setItemDataSource(new BeanItem<Person>(new Person("Who", + "me?", "email", 1, Sex.MALE, new Address("street name", 202020, + "City", Country.FINLAND)))); + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FormManyToMany.java b/tests/testbench/com/vaadin/tests/fieldgroup/FormManyToMany.java new file mode 100644 index 0000000000..f4f612503c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FormManyToMany.java @@ -0,0 +1,28 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.tests.components.TestBase; + +public class FormManyToMany extends TestBase { + + @Override + protected void setup() { + // TODO implement + + // TODO note that in one direction, a setter is used and automatically + // updates the other direction (setting the Roles of a User updates + // Roles), whereas in the other direction (updating the list of Users + // for a Role), manual updates are needed at commit time to keep the + // Users consistent with Roles + } + + @Override + protected String getDescription() { + return "Forms which allow editing of a many-to-many mapping between users and roles"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FormOneToMany.java b/tests/testbench/com/vaadin/tests/fieldgroup/FormOneToMany.java new file mode 100644 index 0000000000..e269a39441 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FormOneToMany.java @@ -0,0 +1,43 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Millionaire; +import com.vaadin.ui.Form; + +public class FormOneToMany extends TestBase { + + @Override + protected void setup() { + final Form form = new Form(); + addComponent(form); + form.setItemDataSource(createMillionaireItem()); + + // TODO support adding, editing and removing secondary addresses + } + + protected BeanItem<Millionaire> createMillionaireItem() { + Millionaire person = new Millionaire("First", "Last", "foo@vaadin.com", + "02-111 2222", "Ruukinkatu 2-4", 20540, "Turku"); + + BeanItem<Millionaire> item = new BeanItem<Millionaire>(person); + // add nested properties from address + item.expandProperty("address"); + + // TODO for now, hide secondary residences + item.removeItemProperty("secondaryResidences"); + + return item; + } + + @Override + protected String getDescription() { + return "Form with an editable list of sub-objects."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FormOneToOne.java b/tests/testbench/com/vaadin/tests/fieldgroup/FormOneToOne.java new file mode 100644 index 0000000000..b16cb29a8a --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FormOneToOne.java @@ -0,0 +1,38 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Person; +import com.vaadin.ui.Form; + +public class FormOneToOne extends TestBase { + + @Override + protected void setup() { + final Form form = new Form(); + addComponent(form); + form.setItemDataSource(createPersonItem()); + } + + protected BeanItem<Person> createPersonItem() { + Person person = new Person("First", "Last", "foo@vaadin.com", + "02-111 2222", "Ruukinkatu 2-4", 20540, "Turku"); + + BeanItem<Person> item = new BeanItem<Person>(person); + // add nested properties from address + item.expandProperty("address"); + + return item; + } + + @Override + protected String getDescription() { + return "Form where some properties come from a sub-object of the bean."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/FormWithNestedProperties.java b/tests/testbench/com/vaadin/tests/fieldgroup/FormWithNestedProperties.java new file mode 100644 index 0000000000..f66d822495 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/FormWithNestedProperties.java @@ -0,0 +1,67 @@ +package com.vaadin.tests.fieldgroup; + +import com.vaadin.data.fieldgroup.BeanFieldGroup; +import com.vaadin.data.fieldgroup.PropertyId; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Country; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.tests.data.bean.Sex; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.TextField; + +public class FormWithNestedProperties extends AbstractBeanFieldGroupTest { + + private Log log = new Log(5); + + private TextField firstName = new TextField("First name"); + private TextField lastName = new TextField("Last name"); + private TextField email = new TextField("Email"); + private TextField age = new TextField("Age"); + + @PropertyId("address.streetAddress") + private TextField streetAddress = new TextField("Street address"); + private NativeSelect country; + + private CheckBox deceased = new CheckBox("Deceased"); + + @Override + protected void setup() { + super.setup(); + + setFieldBinder(new BeanFieldGroup<Person>(Person.class)); + country = getFieldBinder().buildAndBind("country", "address.country", + NativeSelect.class); + getFieldBinder().bindMemberFields(this); + addComponent(firstName); + addComponent(lastName); + addComponent(streetAddress); + addComponent(country); + addComponent(email); + addComponent(age); + addComponent(deceased); + addComponent(getCommitButton()); + addComponent(getDiscardButton()); + addComponent(getShowBeanButton()); + + getFieldBinder().setItemDataSource( + new Person("First", "Last", "Email", 52, Sex.FEMALE, + new Address("street address", 01234, "City", + Country.FINLAND))); + + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fieldgroup/IntegerRangeValidator.html b/tests/testbench/com/vaadin/tests/fieldgroup/IntegerRangeValidator.html new file mode 100644 index 0000000000..078aede82f --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fieldgroup/IntegerRangeValidator.html @@ -0,0 +1,95 @@ + <?xml version="1.0" encoding="UTF-8"?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head profile="http://selenium-ide.openqa.org/profiles/test-case"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <link rel="selenium.base" href="" /> + <title>New Test</title> + </head> + <body> + <table cellpadding="1" cellspacing="1" border="1"> + <thead> + <tr><td rowspan="1" colspan="3">New Test</td></tr> + </thead><tbody> + <tr> + <td>open</td> + <td>/run/com.vaadin.tests.fieldgroup.BasicPersonForm?restartApplication</td> + <td></td> +</tr> +<!--64123 -> age--> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64,20</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>64123</td> +</tr> +<tr> + <td>showTooltip</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td></td> +</tr> +<tr> + <td>waitForElementPresent</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]/FlowPanel[0]/VErrorMessage[0]/HTML[0]</td> + <td>Must be between 0 and 150, 64123 is not</td> +</tr> +<tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[5]/domChild[0]/domChild[1]</td> + <td>v-errorindicator</td> +</tr> +<!--10 -> age--> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>10</td> +</tr> +<tr> + <td>assertElementNotPresent</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[5]/domChild[0]/domChild[1]</td> + <td>v-errorindicator</td> +</tr> +<!---1--> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>69,11</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td>-1</td> +</tr> +<tr> + <td>assertCSSClass</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/VVerticalLayout[0]/domChild[5]/domChild[0]/domChild[1]</td> + <td>v-errorindicator</td> +</tr> +<tr> + <td>showTooltip</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VTextField[0]</td> + <td></td> +</tr> +<tr> + <td>waitForElementPresent</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsfieldgroupBasicPersonForm::Root/VTooltip[0]/FlowPanel[0]/VErrorMessage[0]/HTML[0]</td> + <td>Must be between 0 and 150, -1 is not</td> +</tr> +</tbody></table> + </body> + </html> + diff --git a/tests/testbench/com/vaadin/tests/fields/FormManyToMany.java b/tests/testbench/com/vaadin/tests/fields/FormManyToMany.java new file mode 100644 index 0000000000..43fba20f33 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fields/FormManyToMany.java @@ -0,0 +1,28 @@ +package com.vaadin.tests.fields; + +import com.vaadin.tests.components.TestBase; + +public class FormManyToMany extends TestBase { + + @Override + protected void setup() { + // TODO implement + + // TODO note that in one direction, a setter is used and automatically + // updates the other direction (setting the Roles of a User updates + // Roles), whereas in the other direction (updating the list of Users + // for a Role), manual updates are needed at commit time to keep the + // Users consistent with Roles + } + + @Override + protected String getDescription() { + return "Forms which allow editing of a many-to-many mapping between users and roles"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fields/FormOneToMany.java b/tests/testbench/com/vaadin/tests/fields/FormOneToMany.java new file mode 100644 index 0000000000..a010e935ab --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fields/FormOneToMany.java @@ -0,0 +1,43 @@ +package com.vaadin.tests.fields; + +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Millionaire; +import com.vaadin.ui.Form; + +public class FormOneToMany extends TestBase { + + @Override + protected void setup() { + final Form form = new Form(); + addComponent(form); + form.setItemDataSource(createMillionaireItem()); + + // TODO support adding, editing and removing secondary addresses + } + + protected BeanItem<Millionaire> createMillionaireItem() { + Millionaire person = new Millionaire("First", "Last", "foo@vaadin.com", + "02-111 2222", "Ruukinkatu 2-4", 20540, "Turku"); + + BeanItem<Millionaire> item = new BeanItem<Millionaire>(person); + // add nested properties from address + item.expandProperty("address"); + + // TODO for now, hide secondary residences + item.removeItemProperty("secondaryResidences"); + + return item; + } + + @Override + protected String getDescription() { + return "Form with an editable list of sub-objects."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/fields/FormOneToOne.java b/tests/testbench/com/vaadin/tests/fields/FormOneToOne.java new file mode 100644 index 0000000000..36f4dfe0ea --- /dev/null +++ b/tests/testbench/com/vaadin/tests/fields/FormOneToOne.java @@ -0,0 +1,38 @@ +package com.vaadin.tests.fields; + +import com.vaadin.data.util.BeanItem; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Person; +import com.vaadin.ui.Form; + +public class FormOneToOne extends TestBase { + + @Override + protected void setup() { + final Form form = new Form(); + addComponent(form); + form.setItemDataSource(createPersonItem()); + } + + protected BeanItem<Person> createPersonItem() { + Person person = new Person("First", "Last", "foo@vaadin.com", + "02-111 2222", "Ruukinkatu 2-4", 20540, "Turku"); + + BeanItem<Person> item = new BeanItem<Person>(person); + // add nested properties from address + item.expandProperty("address"); + + return item; + } + + @Override + protected String getDescription() { + return "Form where some properties come from a sub-object of the bean."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/integration/EmbedSizeTest.java b/tests/testbench/com/vaadin/tests/integration/EmbedSizeTest.java index 479af4aa87..eb26faacc0 100644 --- a/tests/testbench/com/vaadin/tests/integration/EmbedSizeTest.java +++ b/tests/testbench/com/vaadin/tests/integration/EmbedSizeTest.java @@ -1,12 +1,12 @@ package com.vaadin.tests.integration; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.TestBase; import com.vaadin.tests.util.Log; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.ResizeEvent; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.BrowserWindowResizeEvent; public class EmbedSizeTest extends TestBase { @@ -14,30 +14,31 @@ public class EmbedSizeTest extends TestBase { @Override protected void setup() { - Window mainWindow = getMainWindow(); + Root mainWindow = getMainWindow(); mainWindow.setSizeUndefined(); mainWindow.getContent().setSizeUndefined(); mainWindow.setImmediate(true); - CheckBox lazyCheckBox = new CheckBox("Lazy resize", - new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - boolean resizeLazy = Boolean.TRUE == event.getButton() - .getValue(); - getMainWindow().setResizeLazy(resizeLazy); - log.log("Resize lazy: " + resizeLazy); - } - }); + CheckBox lazyCheckBox = new CheckBox("Lazy resize"); + lazyCheckBox.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + CheckBox cb = (CheckBox) event.getProperty(); + Boolean resizeLazy = cb.getValue(); + getMainWindow().setResizeLazy(resizeLazy); + log.log("Resize lazy: " + resizeLazy); + } + }); lazyCheckBox.setValue(Boolean.FALSE); lazyCheckBox.setImmediate(true); addComponent(lazyCheckBox); addComponent(log); - mainWindow.addListener(new Window.ResizeListener() { - public void windowResized(ResizeEvent e) { - Window window = e.getWindow(); - log.log("Resize event: " + window.getWidth() + " x " - + window.getHeight()); + mainWindow.addListener(new Root.BrowserWindowResizeListener() { + public void browserWindowResized(BrowserWindowResizeEvent event) { + log.log("Resize event: " + event.getWidth() + " x " + + event.getHeight()); + } }); } diff --git a/tests/testbench/com/vaadin/tests/integration/IntegrationTestApplication.java b/tests/testbench/com/vaadin/tests/integration/IntegrationTestApplication.java index 6bff7aca1d..b2001bdd7e 100644 --- a/tests/testbench/com/vaadin/tests/integration/IntegrationTestApplication.java +++ b/tests/testbench/com/vaadin/tests/integration/IntegrationTestApplication.java @@ -7,14 +7,14 @@ import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.terminal.ClassResource; import com.vaadin.terminal.Resource; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class IntegrationTestApplication extends Application { +public class IntegrationTestApplication extends Application.LegacyApplication { @Override public void init() { - Window window = new Window("Vaadin Application"); + LegacyWindow window = new LegacyWindow("Vaadin Application"); setMainWindow(window); final Table table = new Table(); diff --git a/tests/testbench/com/vaadin/tests/integration/JSR286PortletApplication.java b/tests/testbench/com/vaadin/tests/integration/JSR286PortletApplication.java index 41d02d35ae..ecc7ea9647 100644 --- a/tests/testbench/com/vaadin/tests/integration/JSR286PortletApplication.java +++ b/tests/testbench/com/vaadin/tests/integration/JSR286PortletApplication.java @@ -22,17 +22,19 @@ import com.vaadin.terminal.gwt.server.PortletApplicationContext2; import com.vaadin.terminal.gwt.server.PortletApplicationContext2.PortletListener; import com.vaadin.ui.Embedded; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Link; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; /** * Adapted from old PortletDemo to support integration testing. */ -public class JSR286PortletApplication extends Application { +public class JSR286PortletApplication extends Application.LegacyApplication { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); TextField tf = new TextField("Some value"); Label userInfo = new Label(); Link portletEdit = new Link(); @@ -41,7 +43,6 @@ public class JSR286PortletApplication extends Application { @Override public void init() { - main = new Window(); setMainWindow(main); Embedded appResourceTest = new Embedded( @@ -54,7 +55,7 @@ public class JSR286PortletApplication extends Application { main.addComponent(specialNameResourceTest); userInfo.setCaption("User info"); - userInfo.setContentMode(Label.CONTENT_PREFORMATTED); + userInfo.setContentMode(ContentMode.PREFORMATTED); main.addComponent(userInfo); tf.setEnabled(false); @@ -79,12 +80,12 @@ public class JSR286PortletApplication extends Application { private class DemoPortletListener implements PortletListener { public void handleActionRequest(ActionRequest request, - ActionResponse response, Window window) { + ActionResponse response, Root window) { main.addComponent(new Label("Action received")); } public void handleRenderRequest(RenderRequest request, - RenderResponse response, Window window) { + RenderResponse response, Root window) { // Portlet up-and-running, enable stuff portletEdit.setEnabled(true); portletMax.setEnabled(true); @@ -157,12 +158,12 @@ public class JSR286PortletApplication extends Application { } public void handleEventRequest(EventRequest request, - EventResponse response, Window window) { + EventResponse response, Root window) { // events not used by this test } public void handleResourceRequest(ResourceRequest request, - ResourceResponse response, Window window) { + ResourceResponse response, Root window) { // nothing special to do here } } diff --git a/tests/testbench/com/vaadin/tests/integration/LiferayThemeDemo.java b/tests/testbench/com/vaadin/tests/integration/LiferayThemeDemo.java index 4267a7ea91..91e9a4620c 100644 --- a/tests/testbench/com/vaadin/tests/integration/LiferayThemeDemo.java +++ b/tests/testbench/com/vaadin/tests/integration/LiferayThemeDemo.java @@ -5,15 +5,17 @@ import java.util.Iterator; import java.util.Locale; import com.vaadin.Application; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.event.Action; import com.vaadin.terminal.ExternalResource; import com.vaadin.terminal.Resource; import com.vaadin.terminal.ThemeResource; +import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractSelect; import com.vaadin.ui.Accordion; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Component; @@ -24,6 +26,7 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.InlineDateField; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.ListSelect; import com.vaadin.ui.MenuBar; @@ -31,25 +34,27 @@ import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.NativeButton; import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.Notification; import com.vaadin.ui.Panel; import com.vaadin.ui.PopupView; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Slider; import com.vaadin.ui.Slider.ValueOutOfBoundsException; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; import com.vaadin.ui.TabSheet.Tab; import com.vaadin.ui.Table; +import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree; import com.vaadin.ui.TwinColSelect; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; import com.vaadin.ui.themes.LiferayTheme; @SuppressWarnings("serial") -public class LiferayThemeDemo extends Application { +public class LiferayThemeDemo extends Application.LegacyApplication { @SuppressWarnings("deprecation") private static final Date DATE = new Date(2009 - 1900, 6 - 1, 2); @@ -59,7 +64,7 @@ public class LiferayThemeDemo extends Application { private static final Resource ICON_OK = new ThemeResource( "../runo/icons/16/ok.png"); - private Window main; + private LegacyWindow main; private VerticalLayout mainLayout; private TabSheet tabs; @@ -79,7 +84,7 @@ public class LiferayThemeDemo extends Application { @Override public void init() { - main = new Window("Vaadin Liferay Theme"); + main = new LegacyWindow("Vaadin Liferay Theme"); mainLayout = (VerticalLayout) main.getContent(); mainLayout.setMargin(false); setMainWindow(main); @@ -127,7 +132,7 @@ public class LiferayThemeDemo extends Application { l.setMargin(true); l.setCaption("Labels"); - l.addComponent(new Label("Normal Label", Label.CONTENT_XHTML)); + l.addComponent(new Label("Normal Label", ContentMode.XHTML)); l.addComponent(new Label( "Lorem ipsum dolor sit amet, consectetur adipiscing elit.")); return l; @@ -139,7 +144,7 @@ public class LiferayThemeDemo extends Application { l.setMargin(true); l.setSpacing(true); - Button b = new Button("Normal Button"); + AbstractComponent b = new Button("Normal Button"); b.setDescription("This is a tooltip!"); l.addComponent(b); @@ -208,17 +213,17 @@ public class LiferayThemeDemo extends Application { l.setWidth("400px"); l.setColumnExpandRatio(0, 1); - l.addComponent(new Label("Normal TextField", Label.CONTENT_XHTML)); + l.addComponent(new Label("Normal TextField", ContentMode.XHTML)); TextField tf = new TextField(); tf.setInputPrompt("Enter text"); l.addComponent(tf); - l.addComponent(new Label("Normal TextArea", Label.CONTENT_XHTML)); + l.addComponent(new Label("Normal TextArea", ContentMode.XHTML)); - tf = new TextField(); - tf.setHeight("5em"); - tf.setInputPrompt("Enter text"); - l.addComponent(tf); + TextArea ta = new TextArea(); + ta.setHeight("5em"); + ta.setInputPrompt("Enter text"); + l.addComponent(ta); return l; } @@ -310,12 +315,14 @@ public class LiferayThemeDemo extends Application { } } - closable.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + closable.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { Iterator<Component> it = ts.getComponentIterator(); for (; it.hasNext();) { Component c = it.next(); - ts.getTab(c).setClosable(event.getButton().booleanValue()); + ts.getTab(c).setClosable( + (Boolean) event.getProperty().getValue()); } } }); @@ -332,7 +339,7 @@ public class LiferayThemeDemo extends Application { l.setColumnExpandRatio(0, 2); l.setColumnExpandRatio(1, 5); - l.addComponent(new Label("Normal Panel", Label.CONTENT_XHTML)); + l.addComponent(new Label("Normal Panel", ContentMode.XHTML)); Panel p = new Panel("Normal Panel"); p.setHeight("100px"); @@ -341,7 +348,7 @@ public class LiferayThemeDemo extends Application { l.addComponent(new Label( "Light Style (<code>LiferayTheme.PANEL_LIGHT</code>)", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); Panel p2 = new Panel("Light Style Panel"); p2.setStyleName(LiferayTheme.PANEL_LIGHT); @@ -374,7 +381,7 @@ public class LiferayThemeDemo extends Application { int sum = 0; for (int j = 0; j < 100; j++) { - t.addItem(new Object[] { j, "Bar value " + j, + t.addItem(new Object[] { "" + j, "Bar value " + j, "Last column value " + j, new TextField() }, j); sum += j; } @@ -404,7 +411,7 @@ public class LiferayThemeDemo extends Application { w2.setPositionX(350); w2.setPositionY(160); w2.addComponent(new Label("<code>Window.setResizable(false)</code>", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); tabs.addListener(new TabSheet.SelectedTabChangeListener() { public void selectedTabChange(SelectedTabChangeEvent event) { @@ -435,7 +442,7 @@ public class LiferayThemeDemo extends Application { l.addComponent(lockCheckBox, 1, 0); l.newLine(); - Label label = new Label("Normal SplitPanel", Label.CONTENT_XHTML); + Label label = new Label("Normal SplitPanel", ContentMode.XHTML); label.setWidth(null); l.addComponent(label); final HorizontalSplitPanel sp = new HorizontalSplitPanel(); @@ -448,7 +455,7 @@ public class LiferayThemeDemo extends Application { label = new Label( "Small Style<br />(<code>LiferayTheme.SPLITPANEL_SMALL</code>)", - Label.CONTENT_XHTML); + ContentMode.XHTML); label.setWidth(null); l.addComponent(label); @@ -462,12 +469,13 @@ public class LiferayThemeDemo extends Application { sp3.setSecondComponent(sp4); l.addComponent(sp3); - lockCheckBox.addListener(new ClickListener() { - public void buttonClick(ClickEvent event) { - sp.setLocked(event.getButton().booleanValue()); - sp2.setLocked(event.getButton().booleanValue()); - sp3.setLocked(event.getButton().booleanValue()); - sp4.setLocked(event.getButton().booleanValue()); + lockCheckBox.addListener(new Property.ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + sp.setLocked((Boolean) event.getProperty().getValue()); + sp2.setLocked((Boolean) event.getProperty().getValue()); + sp3.setLocked((Boolean) event.getProperty().getValue()); + sp4.setLocked((Boolean) event.getProperty().getValue()); } }); @@ -507,7 +515,7 @@ public class LiferayThemeDemo extends Application { l.setWidth("400px"); l.setColumnExpandRatio(0, 1); - l.addComponent(new Label("Horizontal Slider", Label.CONTENT_XHTML)); + l.addComponent(new Label("Horizontal Slider", ContentMode.XHTML)); Slider s = new Slider(); s.setWidth("200px"); try { @@ -518,7 +526,7 @@ public class LiferayThemeDemo extends Application { } l.addComponent(s); - l.addComponent(new Label("Vertical Slider", Label.CONTENT_XHTML)); + l.addComponent(new Label("Vertical Slider", ContentMode.XHTML)); s = new Slider(); s.setOrientation(Slider.ORIENTATION_VERTICAL); s.setHeight("200px"); @@ -580,55 +588,52 @@ public class LiferayThemeDemo extends Application { message.setValue("Jumped over the lazy dog."); message.setWidth("15em"); - l.addComponent(new Label("<h3>Type</h3>", Label.CONTENT_XHTML)); - l.addComponent(new Label("<h3>Preview</h3>", Label.CONTENT_XHTML)); + l.addComponent(new Label("<h3>Type</h3>", ContentMode.XHTML)); + l.addComponent(new Label("<h3>Preview</h3>", ContentMode.XHTML)); - l.addComponent(new Label("Humanized", Label.CONTENT_XHTML)); + l.addComponent(new Label("Humanized", ContentMode.XHTML)); Button show = new Button("Humanized Notification", new Button.ClickListener() { public void buttonClick(ClickEvent event) { event.getButton() - .getWindow() - .showNotification((String) title.getValue(), - (String) message.getValue()); + .getRoot() + .showNotification(title.getValue(), + message.getValue()); } }); l.addComponent(show); - l.addComponent(new Label("Warning", Label.CONTENT_XHTML)); + l.addComponent(new Label("Warning", ContentMode.XHTML)); show = new Button("Warning Notification", new Button.ClickListener() { public void buttonClick(ClickEvent event) { event.getButton() - .getWindow() - .showNotification((String) title.getValue(), - (String) message.getValue(), + .getRoot() + .showNotification(title.getValue(), message.getValue(), Notification.TYPE_WARNING_MESSAGE); } }); l.addComponent(show); - l.addComponent(new Label("Error", Label.CONTENT_XHTML)); + l.addComponent(new Label("Error", ContentMode.XHTML)); show = new Button("Error Notification", new Button.ClickListener() { public void buttonClick(ClickEvent event) { event.getButton() - .getWindow() - .showNotification((String) title.getValue(), - (String) message.getValue(), + .getRoot() + .showNotification(title.getValue(), message.getValue(), Notification.TYPE_ERROR_MESSAGE); } }); l.addComponent(show); - l.addComponent(new Label("Tray", Label.CONTENT_XHTML)); + l.addComponent(new Label("Tray", ContentMode.XHTML)); show = new Button("Tray Notification", new Button.ClickListener() { public void buttonClick(ClickEvent event) { event.getButton() - .getWindow() - .showNotification((String) title.getValue(), - (String) message.getValue(), + .getRoot() + .showNotification(title.getValue(), message.getValue(), Notification.TYPE_TRAY_NOTIFICATION); } diff --git a/tests/testbench/com/vaadin/tests/layouts/CaptionsInLayouts.java b/tests/testbench/com/vaadin/tests/layouts/CaptionsInLayouts.java index 7ad433e5c9..4388639893 100644 --- a/tests/testbench/com/vaadin/tests/layouts/CaptionsInLayouts.java +++ b/tests/testbench/com/vaadin/tests/layouts/CaptionsInLayouts.java @@ -37,7 +37,7 @@ public class CaptionsInLayouts extends TestBase { private HorizontalLayout horizontalLayout; private GridLayout gridLayout; private FormLayout formLayout; - private List<AbstractField> components = new ArrayList<AbstractField>(); + private List<AbstractField<?>> components = new ArrayList<AbstractField<?>>(); private CssLayout cssLayout; private HorizontalLayout layoutParent = new HorizontalLayout(); @@ -69,7 +69,7 @@ public class CaptionsInLayouts extends TestBase { } protected void prependCaptions(String prepend) { - for (AbstractField c : components) { + for (AbstractField<?> c : components) { c.setCaption(prepend + c.getCaption()); } @@ -102,14 +102,14 @@ public class CaptionsInLayouts extends TestBase { } protected void setRequired(boolean value) { - for (AbstractField c : components) { + for (AbstractField<?> c : components) { c.setRequired(value); } } protected void setIcon(boolean value) { - for (AbstractField c : components) { + for (AbstractField<?> c : components) { if (!value) { c.setIcon(null); } else { @@ -133,7 +133,7 @@ public class CaptionsInLayouts extends TestBase { } protected void setError(boolean value) { - for (AbstractField c : components) { + for (AbstractField<?> c : components) { if (value) { c.setComponentError(new UserError("error")); } else { diff --git a/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.html b/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.html index 403bb32a67..6dab84d718 100644 --- a/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.html +++ b/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.html @@ -18,7 +18,7 @@ </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsComplexGLColumnExpansionWithColSpan::/VVerticalLayout[0]/ChildComponentContainer[0]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsComplexGLColumnExpansionWithColSpan::/VVerticalLayout[0]/VGridLayout[0]/VButton[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -26,7 +26,6 @@ <td></td> <td>buttons-next-stacked-left</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java b/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java index 87b04ffcb0..f1e05b6fee 100644 --- a/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java +++ b/tests/testbench/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java @@ -4,9 +4,9 @@ import com.vaadin.terminal.Sizeable; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Button; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class ComplexGLColumnExpansionWithColSpan extends AbstractTestCase { private int cols; @@ -29,7 +29,7 @@ public class ComplexGLColumnExpansionWithColSpan extends AbstractTestCase { mainLayout.setMargin(true); mainLayout.setHeight(100, Sizeable.UNITS_PERCENTAGE); mainLayout.setWidth(100, Sizeable.UNITS_PERCENTAGE); - setMainWindow(new Window("Vaadin Test", mainLayout)); + setMainWindow(new LegacyWindow("Vaadin Test", mainLayout)); cols = 1; final GridLayout gl = new GridLayout(cols, 3); @@ -71,7 +71,7 @@ public class ComplexGLColumnExpansionWithColSpan extends AbstractTestCase { mainLayout.addComponent(restart); restart.addListener(new Button.ClickListener() { public void buttonClick(Button.ClickEvent event) { - mainLayout.getWindow().getApplication().close(); + mainLayout.getRoot().getApplication().close(); } }); diff --git a/tests/testbench/com/vaadin/tests/layouts/CssLayoutCustomCss.java b/tests/testbench/com/vaadin/tests/layouts/CssLayoutCustomCss.java new file mode 100644 index 0000000000..0e2d570101 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/layouts/CssLayoutCustomCss.java @@ -0,0 +1,89 @@ +package com.vaadin.tests.layouts; + +import java.util.HashMap; +import java.util.Map; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Component; +import com.vaadin.ui.CssLayout; +import com.vaadin.ui.NativeButton; + +public class CssLayoutCustomCss extends TestBase implements ClickListener { + + protected Map<Component, String> css = new HashMap<Component, String>(); + private CssLayout layout; + + @Override + protected void setup() { + setTheme("tests-tickets"); + layout = new CssLayout() { + @Override + protected String getCss(com.vaadin.ui.Component c) { + return css.get(c); + } + }; + layout.setSizeFull(); + addComponent(layout); + + Button red, green; + layout.addComponent(red = createButton("color:red")); + layout.addComponent(createButton("color: blue")); + layout.addComponent(green = createButton("color: green")); + + red.click(); + green.click(); + layout.addComponent(createMarginsToggle()); + } + + private Component createMarginsToggle() { + final CheckBox cb = new CheckBox("Margins"); + cb.setImmediate(true); + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + layout.setMargin(cb.getValue()); + } + }); + + return cb; + } + + private Button createButton(String string) { + NativeButton button = new NativeButton(string); + css.put(button, string); + button.addListener(this); + return button; + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + + public void buttonClick(ClickEvent event) { + Button b = event.getButton(); + if (b.getCaption().contains("not ")) { + b.setCaption(b.getCaption().substring(4)); + css.put(b, b.getCaption()); + } else { + css.remove(b); + b.setCaption("not " + b.getCaption()); + } + layout.requestRepaint(); + + } + +} diff --git a/tests/testbench/com/vaadin/tests/layouts/CssLayoutRemoveComponent.html b/tests/testbench/com/vaadin/tests/layouts/CssLayoutRemoveComponent.html index 0c4c3ad12c..0932be5d81 100644 --- a/tests/testbench/com/vaadin/tests/layouts/CssLayoutRemoveComponent.html +++ b/tests/testbench/com/vaadin/tests/layouts/CssLayoutRemoveComponent.html @@ -22,14 +22,9 @@ <td></td> </tr> <tr> - <td>verifyTextPresent</td> - <td>Caption2</td> - <td></td> -</tr> -<tr> - <td>verifyTextNotPresent</td> - <td>Caption1</td> + <td>screenCapture</td> <td></td> + <td>caption1-hidden</td> </tr> </tbody></table> diff --git a/tests/testbench/com/vaadin/tests/layouts/FormLayoutWithInvisibleComponent.java b/tests/testbench/com/vaadin/tests/layouts/FormLayoutWithInvisibleComponent.java index e29c7559b3..7fc33edfc7 100644 --- a/tests/testbench/com/vaadin/tests/layouts/FormLayoutWithInvisibleComponent.java +++ b/tests/testbench/com/vaadin/tests/layouts/FormLayoutWithInvisibleComponent.java @@ -1,15 +1,15 @@ package com.vaadin.tests.layouts; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.FormLayout; -import com.vaadin.ui.TextField; +import com.vaadin.ui.TextArea; public class FormLayoutWithInvisibleComponent extends TestBase { - private TextField messages; + private TextArea messages; @Override protected String getDescription() { @@ -24,19 +24,20 @@ public class FormLayoutWithInvisibleComponent extends TestBase { @Override protected void setup() { FormLayout formLayout = new FormLayout(); - CheckBox control = new CheckBox("Messages On/Off", - new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - messages.setVisible(event.getButton().booleanValue()); - messages.setRequired(true); - messages.setCaption("Messages visible"); - } - - }); + CheckBox control = new CheckBox("Messages On/Off"); + control.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + messages.setVisible((Boolean) event.getProperty().getValue()); + messages.setRequired(true); + messages.setCaption("Messages visible"); + } + + }); control.setImmediate(true); formLayout.addComponent(control); - messages = new TextField("Messages hidden"); + messages = new TextArea("Messages hidden"); messages.setRows(10); messages.setColumns(40); messages.setVisible(false); diff --git a/tests/testbench/com/vaadin/tests/layouts/GridLayoutCaptions.java b/tests/testbench/com/vaadin/tests/layouts/GridLayoutCaptions.java index 08df953e66..1fe33d62ca 100644 --- a/tests/testbench/com/vaadin/tests/layouts/GridLayoutCaptions.java +++ b/tests/testbench/com/vaadin/tests/layouts/GridLayoutCaptions.java @@ -3,6 +3,7 @@ package com.vaadin.tests.layouts; import com.vaadin.data.Item; import com.vaadin.data.Validator; import com.vaadin.data.util.BeanItem; +import com.vaadin.terminal.AbstractErrorMessage; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; @@ -14,9 +15,9 @@ import com.vaadin.ui.Form; import com.vaadin.ui.FormFieldFactory; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class GridLayoutCaptions extends TestBase { @@ -27,31 +28,31 @@ public class GridLayoutCaptions extends TestBase { private CssLayout wrapper2 = new CssLayout(); private FormFieldFactory fff = new FormFieldFactory() { - public Field createField(Item item, Object propertyId, + public Field<?> createField(Item item, Object propertyId, Component uiContext) { if (propertyId.equals(DataPOJO.Fields.name.name())) { - Field f = DefaultFieldFactory.get().createField(item, + Field<?> f = DefaultFieldFactory.get().createField(item, propertyId, uiContext); f.setCaption("This is a long caption for the name field"); return f; } else if (propertyId.equals(DataPOJO.Fields.hp.name())) { - Field f = DefaultFieldFactory.get().createField(item, + Field<?> f = DefaultFieldFactory.get().createField(item, propertyId, uiContext); f.setCaption("This is a long caption for the HP field, but it has a VL as a wrapper"); return f; } else if (propertyId.equals(DataPOJO.Fields.place.name())) { - Field f = DefaultFieldFactory.get().createField(item, + Field<?> f = DefaultFieldFactory.get().createField(item, propertyId, uiContext); f.setCaption("This is a long caption for the Place field, but it has a CSSLo as a wrapper"); return f; } else if (propertyId.equals(DataPOJO.Fields.price.name())) { - Field f = DefaultFieldFactory.get().createField(item, + Field<?> f = DefaultFieldFactory.get().createField(item, propertyId, uiContext); f.setCaption("With size undefined the caption behaves like this..."); f.setSizeFull(); @@ -95,7 +96,9 @@ public class GridLayoutCaptions extends TestBase { "Ipsum lipsum laarum lop... "); for (Object propIDs : getItemDataSource().getItemPropertyIds()) { - ((TextField) getField(propIDs)).setComponentError(ive); + ((TextField) getField(propIDs)) + .setComponentError(AbstractErrorMessage + .getErrorMessageForException(ive)); } @@ -174,7 +177,8 @@ public class GridLayoutCaptions extends TestBase { @Override protected void setup() { - Window mainWindow = new Window("Formlayoutcaptionboom Application"); + LegacyWindow mainWindow = new LegacyWindow( + "Formlayoutcaptionboom Application"); Label label = new Label("Hello Vaadin user"); mainWindow.addComponent(label); setMainWindow(mainWindow); diff --git a/tests/testbench/com/vaadin/tests/layouts/GridLayoutExpandRatioModification.java b/tests/testbench/com/vaadin/tests/layouts/GridLayoutExpandRatioModification.java index e9d206009a..f7f4ac2d4c 100644 --- a/tests/testbench/com/vaadin/tests/layouts/GridLayoutExpandRatioModification.java +++ b/tests/testbench/com/vaadin/tests/layouts/GridLayoutExpandRatioModification.java @@ -6,9 +6,9 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class GridLayoutExpandRatioModification extends TestBase implements ClickListener { @@ -21,7 +21,7 @@ public class GridLayoutExpandRatioModification extends TestBase implements @Override public void setup() { - Window main = new Window("The Main Window"); + LegacyWindow main = new LegacyWindow("The Main Window"); mainLayout = new GridLayout(3, 3); main.setContent(mainLayout); setMainWindow(main); diff --git a/tests/testbench/com/vaadin/tests/layouts/GridLayoutInsidePanel2.java b/tests/testbench/com/vaadin/tests/layouts/GridLayoutInsidePanel2.java index 8fb42948fc..d6ea84e44e 100644 --- a/tests/testbench/com/vaadin/tests/layouts/GridLayoutInsidePanel2.java +++ b/tests/testbench/com/vaadin/tests/layouts/GridLayoutInsidePanel2.java @@ -4,15 +4,15 @@ import com.vaadin.Application; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class GridLayoutInsidePanel2 extends Application { +public class GridLayoutInsidePanel2 extends Application.LegacyApplication { private Layout layout; @Override public void init() { - Window w = new Window("Main"); + LegacyWindow w = new LegacyWindow("Main"); setMainWindow(w); layout = (Layout) w.getContent(); GridLayout gl = new GridLayout(1, 1); diff --git a/tests/testbench/com/vaadin/tests/layouts/HiddenHorizontalLayout.java b/tests/testbench/com/vaadin/tests/layouts/HiddenHorizontalLayout.java index 8de59ccf00..a8f44a5771 100644 --- a/tests/testbench/com/vaadin/tests/layouts/HiddenHorizontalLayout.java +++ b/tests/testbench/com/vaadin/tests/layouts/HiddenHorizontalLayout.java @@ -5,6 +5,7 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.VerticalLayout; public class HiddenHorizontalLayout extends TestBase { @@ -41,7 +42,7 @@ public class HiddenHorizontalLayout extends TestBase { + "3. Click \"toggle layout visibility\"<br>" + "4. Resize browser window to full <br/>" + "5. Click \"toggle layout visibility\"<br/>", - Label.CONTENT_XHTML); + ContentMode.XHTML); vl.addComponent(l); Button b = new Button("toggle layout visibility", new Button.ClickListener() { diff --git a/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.html b/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.html index 22d81ce11f..31b3985a1c 100644 --- a/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.html +++ b/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.html @@ -17,6 +17,11 @@ <td></td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.AbsoluteLayout</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VAbsoluteLayout[0]/VAbsoluteLayout$AbsoluteWrapper[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -28,12 +33,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -53,6 +58,11 @@ <td>199,6</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.Accordion</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VAccordion[0]/VAccordion$StackItem[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -64,12 +74,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -89,6 +99,11 @@ <td>186,11</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.CssLayout</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VCssLayout[0]/VCssLayout$FlowPane[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -100,12 +115,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -125,40 +140,9 @@ <td>199,10</td> </tr> <tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VOrderedLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> - <td>Label inside the component container</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> - <td>Label outside the component container</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VOrderedLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> - <td>Label inside the component container</td> -</tr> -<!--Next component container--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[1]</td> - <td>14,5</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item4</td> - <td>199,10</td> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.FormLayout</td> </tr> <tr> <td>assertText</td> @@ -172,12 +156,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -193,10 +177,15 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item5</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item4</td> <td>199,10</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.GridLayout</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -208,12 +197,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -229,10 +218,15 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item6</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item5</td> <td>199,10</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.HorizontalLayout</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -244,12 +238,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -265,10 +259,15 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item7</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item6</td> <td>199,10</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.HorizontalSplitPanel</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VSplitPanelHorizontal[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -280,12 +279,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -301,44 +300,13 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item8</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item7</td> <td>199,10</td> </tr> <tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VOrderedLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> - <td>Label inside the component container</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> - <td>Label outside the component container</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VOrderedLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> - <td>Label inside the component container</td> -</tr> -<!--Next component container--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[1]</td> - <td>14,5</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item9</td> - <td>199,10</td> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.Panel</td> </tr> <tr> <td>assertText</td> @@ -352,12 +320,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -373,44 +341,13 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item10</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item9</td> <td>199,10</td> </tr> <tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VSplitPanelVertical[0]/VLabel[0]</td> - <td>Label inside the component container</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> - <td>Label outside the component container</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VSplitPanelVertical[0]/VLabel[0]</td> - <td>Label inside the component container</td> -</tr> -<!--Next component container--> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[1]</td> - <td>14,5</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item11</td> - <td>199,10</td> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.TabSheet</td> </tr> <tr> <td>assertText</td> @@ -424,12 +361,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -445,10 +382,15 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item12</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item10</td> <td>199,10</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.VerticalLayout</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -460,12 +402,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> @@ -481,10 +423,15 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item13</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item11</td> <td>199,10</td> </tr> <tr> + <td>assertValue</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::PID_ScomponentContainerSelect/domChild[0]</td> + <td>class com.vaadin.ui.VerticalSplitPanel</td> +</tr> +<tr> <td>assertText</td> <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VSplitPanelVertical[0]/VLabel[0]</td> <td>Label inside the component container</td> @@ -496,12 +443,12 @@ </tr> <tr> <td>assertText</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VLabel[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VLabel[0]</td> <td>Label outside the component container</td> </tr> <tr> <td>click</td> - <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td>vaadin=runcomvaadintestslayoutsMovingComponentsWhileOldParentInvisible::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> <td></td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.java b/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.java index d21ecdd575..bf5de2976f 100644 --- a/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.java +++ b/tests/testbench/com/vaadin/tests/layouts/MovingComponentsWhileOldParentInvisible.java @@ -14,6 +14,7 @@ import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Label; import com.vaadin.ui.LoginForm; import com.vaadin.ui.PopupView; +import com.vaadin.ui.Root; import com.vaadin.ui.Window; public class MovingComponentsWhileOldParentInvisible extends TestBase { @@ -43,7 +44,8 @@ public class MovingComponentsWhileOldParentInvisible extends TestBase { .getComponentContainers()) { if (cls == LoginForm.class || cls == CustomLayout.class || CustomComponent.class.isAssignableFrom(cls) - || cls == PopupView.class || cls == Window.class) { + || cls == PopupView.class || cls == Window.class + || cls == Root.class) { // Does not support addComponent continue; } diff --git a/tests/testbench/com/vaadin/tests/layouts/OrderedLayoutBasics.java b/tests/testbench/com/vaadin/tests/layouts/OrderedLayoutBasics.java index 1fe11f1a92..9f18ef7887 100644 --- a/tests/testbench/com/vaadin/tests/layouts/OrderedLayoutBasics.java +++ b/tests/testbench/com/vaadin/tests/layouts/OrderedLayoutBasics.java @@ -16,8 +16,8 @@ import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.ListSelect; import com.vaadin.ui.Panel; -import com.vaadin.ui.Select; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; @@ -116,13 +116,13 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(tf); ol.setComponentAlignment(tf, Alignment.BOTTOM_LEFT); - Select s = new Select("100% high select"); + ListSelect s = new ListSelect("100% high select"); s.setMultiSelect(true); s.setHeight("100%"); s.setWidth(""); ol.addComponent(s); - s = new Select("200 px high select"); + s = new ListSelect("200 px high select"); s.setMultiSelect(true); s.setHeight("200px"); s.setWidth(""); @@ -172,7 +172,8 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(l); ol.setComponentAlignment(l, Alignment.BOTTOM_LEFT); - Select s = new Select("100% high select, should fit into layout"); + ListSelect s = new ListSelect( + "100% high select, should fit into layout"); s.setMultiSelect(true); s.setHeight("100%"); s.setWidth(""); @@ -182,7 +183,7 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(s); - s = new Select("200 px high select, should be partly outside"); + s = new ListSelect("200 px high select, should be partly outside"); s.setMultiSelect(true); s.setHeight("200px"); s.setWidth(""); @@ -224,7 +225,8 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(l); ol.setComponentAlignment(l, Alignment.BOTTOM_LEFT); - Select s = new Select("100% high select, should fit into layout"); + ListSelect s = new ListSelect( + "100% high select, should fit into layout"); s.setMultiSelect(true); s.setHeight("100%"); s.setWidth("100%"); @@ -234,7 +236,8 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(s); - s = new Select("200 px high select, should make the layout 200px high"); + s = new ListSelect( + "200 px high select, should make the layout 200px high"); s.setMultiSelect(true); s.setHeight("200px"); s.setWidth("100%"); @@ -277,7 +280,8 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(l); ol.setComponentAlignment(l, Alignment.BOTTOM_LEFT); - Select s = new Select("100% high select, should fit into layout"); + ListSelect s = new ListSelect( + "100% high select, should fit into layout"); s.setMultiSelect(true); s.setHeight("100%"); s.setWidth("100%"); @@ -287,7 +291,8 @@ public class OrderedLayoutBasics extends TestBase { ol.addComponent(s); - s = new Select("200 px high select, should make the layout 200px high"); + s = new ListSelect( + "200 px high select, should make the layout 200px high"); s.setMultiSelect(true); s.setHeight("200px"); s.setWidth("100%"); diff --git a/tests/testbench/com/vaadin/tests/layouts/TestAbsoluteLayout.java b/tests/testbench/com/vaadin/tests/layouts/TestAbsoluteLayout.java index 9a98cd17bd..2f0f16b4a5 100644 --- a/tests/testbench/com/vaadin/tests/layouts/TestAbsoluteLayout.java +++ b/tests/testbench/com/vaadin/tests/layouts/TestAbsoluteLayout.java @@ -33,7 +33,7 @@ public class TestAbsoluteLayout extends TestBase { private static class MFieldFactory extends DefaultFieldFactory { @Override - public Field createField(Item item, Object propertyId, + public Field<?> createField(Item item, Object propertyId, Component uiContext) { if (propertyId.equals("CSSString")) { TextArea f = new TextArea(); @@ -47,10 +47,10 @@ public class TestAbsoluteLayout extends TestBase { s.addContainerProperty("caption", String.class, ""); s.setItemCaptionPropertyId("caption"); s.setNullSelectionAllowed(false); - for (int i = 0; i < Layout.UNIT_SYMBOLS.length; i++) { + for (int i = 0; i < Layout.Unit.values().length; i++) { Item unitItem = s.addItem(i); unitItem.getItemProperty("caption").setValue( - Layout.UNIT_SYMBOLS[i]); + Layout.Unit.values()[i]); } return s; } @@ -155,7 +155,8 @@ public class TestAbsoluteLayout extends TestBase { + getDebugId(); if (next instanceof Property) { - caption += " value:" + ((Property) next).getValue(); + caption += " value:" + + ((Property<?>) next).getValue(); } item.getItemProperty("caption").setValue(caption); diff --git a/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.html b/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.html index 743d59c007..317e13ac80 100644 --- a/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.html +++ b/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.html @@ -59,7 +59,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/domChild[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestslayoutsTestLayoutClickListeners::/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VGridLayout[0]/domChild[0]</td> <td>87,42</td> </tr> <tr> diff --git a/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.java b/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.java index 93c51d6b4a..619e4581fa 100644 --- a/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.java +++ b/tests/testbench/com/vaadin/tests/layouts/TestLayoutClickListeners.java @@ -13,9 +13,10 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; +import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TestLayoutClickListeners extends AbstractTestCase { @@ -23,7 +24,7 @@ public class TestLayoutClickListeners extends AbstractTestCase { @Override public void init() { - Window w = new Window("main window"); + LegacyWindow w = new LegacyWindow("main window"); setMainWindow(w); setTheme("tests-tickets"); @@ -117,7 +118,7 @@ public class TestLayoutClickListeners extends AbstractTestCase { gl.setStyleName("borders"); gl.setSpacing(true); addContent(gl, 4); - TextField largeTextarea = new TextField("Large textarea"); + TextArea largeTextarea = new TextArea("Large textarea"); largeTextarea.setWidth("100%"); largeTextarea.setHeight("99%"); gl.addComponent(largeTextarea, 0, 3, 3, 3); diff --git a/tests/testbench/com/vaadin/tests/layouts/TestLayoutPerformance.java b/tests/testbench/com/vaadin/tests/layouts/TestLayoutPerformance.java index c7cf89e8b6..a5e2048066 100644 --- a/tests/testbench/com/vaadin/tests/layouts/TestLayoutPerformance.java +++ b/tests/testbench/com/vaadin/tests/layouts/TestLayoutPerformance.java @@ -9,6 +9,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.TextField; @@ -33,12 +34,12 @@ public class TestLayoutPerformance extends TestBase { @Override protected void setup() { Label label = new Label("<h1>CssLayout performance test.</h1>", - Label.CONTENT_XHTML); + ContentMode.XHTML); getLayout().addComponent(label); label = new Label( "<em>Hint</em>. Use debug dialog to measure rendering times TODO: extend with size settings (to both layout and content).", - Label.CONTENT_XHTML); + ContentMode.XHTML); getLayout().addComponent(label); ns = new NativeSelect("Select component to test"); @@ -65,11 +66,11 @@ public class TestLayoutPerformance extends TestBase { b.addListener(new Button.ClickListener() { public void buttonClick(ClickEvent event) { - int components = Integer.parseInt((String) n.getValue()); + int components = Integer.parseInt(n.getValue()); Layout layout = getCurrentLayout(); for (int i = 0; i < components; i++) { Component component = newTestComponent(); - if (cb.booleanValue()) { + if (cb.getValue()) { component.setCaption("caption " + i); } layout.addComponent(component); diff --git a/tests/testbench/com/vaadin/tests/layouts/TreeWithBordersInLayout.java b/tests/testbench/com/vaadin/tests/layouts/TreeWithBordersInLayout.java index bce30f8fea..8d506e0884 100644 --- a/tests/testbench/com/vaadin/tests/layouts/TreeWithBordersInLayout.java +++ b/tests/testbench/com/vaadin/tests/layouts/TreeWithBordersInLayout.java @@ -2,9 +2,9 @@ package com.vaadin.tests.layouts; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class TreeWithBordersInLayout extends AbstractTestCase { @@ -14,7 +14,7 @@ public class TreeWithBordersInLayout extends AbstractTestCase { public void init() { Layout mainLayout = new VerticalLayout(); mainLayout.setSizeUndefined(); - setMainWindow(new Window("main window", mainLayout)); + setMainWindow(new LegacyWindow("main window", mainLayout)); setTheme("tests-tickets"); diff --git a/tests/testbench/com/vaadin/tests/layouts/VerticalLayoutExpandRatioModification.java b/tests/testbench/com/vaadin/tests/layouts/VerticalLayoutExpandRatioModification.java index e2c02a629b..d41b288e03 100644 --- a/tests/testbench/com/vaadin/tests/layouts/VerticalLayoutExpandRatioModification.java +++ b/tests/testbench/com/vaadin/tests/layouts/VerticalLayoutExpandRatioModification.java @@ -5,9 +5,9 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class VerticalLayoutExpandRatioModification extends TestBase implements ClickListener { @@ -20,7 +20,7 @@ public class VerticalLayoutExpandRatioModification extends TestBase implements @Override public void setup() { - Window main = new Window("The Main Window"); + LegacyWindow main = new LegacyWindow("The Main Window"); mainLayout = new VerticalLayout(); main.setContent(mainLayout); setMainWindow(main); diff --git a/tests/testbench/com/vaadin/tests/layouts/WidgetImplementationSwap.html b/tests/testbench/com/vaadin/tests/layouts/WidgetImplementationSwap.html deleted file mode 100644 index c335f5df5a..0000000000 --- a/tests/testbench/com/vaadin/tests/layouts/WidgetImplementationSwap.html +++ /dev/null @@ -1,182 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.layouts.WidgetImplementationSwap?restartApplication</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>assertElementPresent</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VAbsoluteLayout[0]/VAbsoluteLayout$AbsoluteWrapper[0]/VTextArea[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>assertElementPresent</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VVerticalLayout[0]/ChildComponentContainer[0]/VTextArea[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[5]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>assertElementPresent</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextArea[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VButton[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VButton[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>assertElementPresent</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[6]/VGridLayout[0]/AbsolutePanel[0]/ChildComponentContainer[0]/VTextArea[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> -<tr> - <td>assertElementPresent</td> - <td>vaadin=runcomvaadintestslayoutsWidgetImplementationSwap::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VCssLayout[0]/VCssLayout$FlowPane[0]/VTextArea[0]</td> - <td></td> -</tr> -<tr> - <td>waitForVaadin</td> - <td></td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/tests/testbench/com/vaadin/tests/layouts/WidgetImplementationSwap.java b/tests/testbench/com/vaadin/tests/layouts/WidgetImplementationSwap.java deleted file mode 100644 index 283e9f7a54..0000000000 --- a/tests/testbench/com/vaadin/tests/layouts/WidgetImplementationSwap.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.vaadin.tests.layouts; - -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.AbsoluteLayout; -import com.vaadin.ui.AbstractLayout; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.CssLayout; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.TextField; -import com.vaadin.ui.VerticalLayout; - -@SuppressWarnings("deprecation") -public class WidgetImplementationSwap extends TestBase { - - @Override - protected void setup() { - setTheme("tests-tickets"); - - { - final AbstractLayout layout = new AbsoluteLayout(); - layout.setCaption(layout.getClass().getSimpleName()); - layout.setStyleName("borders"); - layout.setWidth("500px"); - layout.setHeight("50px"); - addComponent(layout); - final TextField tf = new TextField(); - layout.addComponent(tf); - Button b = new Button("-> TextArea", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (tf.getRows() == 0) { - tf.setRows(3); - event.getButton().setCaption("Move"); - } else { - layout.setCaption(layout.getClass().getSimpleName() - + " done"); - event.getButton().setCaption("done"); - } - - } - }); - addComponent(b); - } - { - final AbstractLayout layout = new VerticalLayout(); - layout.setCaption(layout.getClass().getSimpleName()); - layout.setStyleName("borders"); - layout.setWidth("500px"); - layout.setHeight("50px"); - addComponent(layout); - final TextField tf = new TextField(); - layout.addComponent(tf); - Button b = new Button("-> TextArea", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (tf.getRows() == 0) { - tf.setRows(3); - event.getButton().setCaption("Move"); - } else { - layout.setCaption(layout.getClass().getSimpleName() - + " done"); - event.getButton().setCaption("done"); - } - - } - }); - addComponent(b); - } - - { - final AbstractLayout layout = new HorizontalLayout(); - layout.setCaption(layout.getClass().getSimpleName()); - layout.setStyleName("borders"); - layout.setWidth("500px"); - layout.setHeight("50px"); - addComponent(layout); - final TextField tf = new TextField(); - layout.addComponent(tf); - Button b = new Button("-> TextArea", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (tf.getRows() == 0) { - tf.setRows(3); - event.getButton().setCaption("Move"); - } else { - layout.setCaption(layout.getClass().getSimpleName() - + " done"); - event.getButton().setCaption("done"); - } - - } - }); - addComponent(b); - } - - { - final AbstractLayout layout = new GridLayout(); - layout.setCaption(layout.getClass().getSimpleName()); - layout.setStyleName("borders"); - layout.setWidth("500px"); - layout.setHeight("50px"); - addComponent(layout); - final TextField tf = new TextField(); - layout.addComponent(tf); - Button b = new Button("-> TextArea", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (tf.getRows() == 0) { - tf.setRows(3); - event.getButton().setCaption("Move"); - } else { - layout.setCaption(layout.getClass().getSimpleName() - + " done"); - event.getButton().setCaption("done"); - } - - } - }); - addComponent(b); - } - - { - final AbstractLayout layout = new CssLayout(); - layout.setCaption(layout.getClass().getSimpleName()); - layout.setStyleName("borders"); - layout.setWidth("500px"); - layout.setHeight("50px"); - addComponent(layout); - final TextField tf = new TextField(); - layout.addComponent(tf); - Button b = new Button("-> TextArea", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - if (tf.getRows() == 0) { - tf.setRows(3); - event.getButton().setCaption("Move"); - } else { - layout.setCaption(layout.getClass().getSimpleName() - + " done"); - event.getButton().setCaption("done"); - } - - } - }); - addComponent(b); - } - - } - - @Override - protected String getDescription() { - return "First click turns TextField into a TextArea (on the client); second click modifies the layout - widget should still be a TextArea."; - } - - @Override - protected Integer getTicketNumber() { - return 5457; - } - -} diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/GridLayoutTests.java b/tests/testbench/com/vaadin/tests/layouts/layouttester/GridLayoutTests.java index 0ccff34f44..467705a103 100644 --- a/tests/testbench/com/vaadin/tests/layouts/layouttester/GridLayoutTests.java +++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/GridLayoutTests.java @@ -513,17 +513,17 @@ public class GridLayoutTests extends AbstractLayoutTests { glo.replaceComponent(row2, row2 = new NativeSelect()); glo.replaceComponent(row3, row3 = getTestTabsheet()); - ((AbstractField) col1).setRequired(true); - ((AbstractField) col1).setValidationVisible(true); - ((AbstractField) col1).setRequiredError("required error"); + ((AbstractField<?>) col1).setRequired(true); + ((AbstractField<?>) col1).setValidationVisible(true); + ((AbstractField<?>) col1).setRequiredError("required error"); - ((AbstractField) row1).setRequired(true); - ((AbstractField) row1).setValidationVisible(true); - ((AbstractField) row1).setRequiredError("required error"); + ((AbstractField<?>) row1).setRequired(true); + ((AbstractField<?>) row1).setValidationVisible(true); + ((AbstractField<?>) row1).setRequiredError("required error"); - ((AbstractField) row2).setRequired(true); - ((AbstractField) row2).setValidationVisible(true); - ((AbstractField) row2).setRequiredError("required error"); + ((AbstractField<?>) row2).setRequired(true); + ((AbstractField<?>) row2).setValidationVisible(true); + ((AbstractField<?>) row2).setRequiredError("required error"); row2.setComponentError(new UserError("component error, user error")); row3.setComponentError(new UserError("component error, user error")); diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/HorizontalLayoutTests.java b/tests/testbench/com/vaadin/tests/layouts/layouttester/HorizontalLayoutTests.java index caebbc8532..920c9ec819 100644 --- a/tests/testbench/com/vaadin/tests/layouts/layouttester/HorizontalLayoutTests.java +++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/HorizontalLayoutTests.java @@ -14,6 +14,7 @@ import com.vaadin.ui.CheckBox; import com.vaadin.ui.DateField; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.Select; @@ -114,7 +115,7 @@ public class HorizontalLayoutTests extends AbstractLayoutTests { final AbstractComponent c1 = new Button("BUTTON"); final AbstractComponent c2 = new Label("<b>LABEL</b>", - Label.CONTENT_XHTML); + ContentMode.XHTML); final AbstractComponent c3 = new Table("TABLE"); c3.setHeight("100px"); c3.setWidth("100%"); @@ -489,7 +490,7 @@ public class HorizontalLayoutTests extends AbstractLayoutTests { components[3] = getTestTabsheet(); components[3].setIcon(new ThemeResource(LOCK_16_PNG)); - AbstractField[] fields = new AbstractField[5]; + AbstractField<?>[] fields = new AbstractField<?>[5]; fields[0] = new TextField(); fields[0].setRequired(true); fields[0].setValidationVisible(true); diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html index b0e2444986..4bc409b881 100644 --- a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html +++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.html @@ -316,12 +316,6 @@ <td>vaadin=runcomvaadintestslayoutslayouttesterLayoutTesterApplication::/VVerticalLayout[0]/ChildComponentContainer[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]</td> <td></td> </tr> -<!-- Only for IE6 so it has time to load images and adjust --> -<tr> - <td>pause</td> - <td>2000</td> - <td></td> -</tr> <tr> <td>screenCapture</td> <td></td> diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java index 6f73a42497..6a524cd024 100644 --- a/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java +++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java @@ -11,8 +11,8 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; import com.vaadin.ui.themes.Reindeer; @SuppressWarnings("serial") @@ -22,12 +22,12 @@ public class LayoutTesterApplication extends AbstractTestCase { private int layoutCount = 1; private Method[] layoutGetters; - private Window mainWindow; + private LegacyWindow mainWindow; private NativeSelect layoutSelector; @Override public void init() { - mainWindow = new Window("LayoutTesterApplication"); + mainWindow = new LegacyWindow("LayoutTesterApplication"); setMainWindow(mainWindow); loadLayoutGetters(); nextLaytout(); diff --git a/tests/testbench/com/vaadin/tests/layouts/layouttester/VerticalLayoutTests.java b/tests/testbench/com/vaadin/tests/layouts/layouttester/VerticalLayoutTests.java index 941dfcd877..a542a8f10c 100644 --- a/tests/testbench/com/vaadin/tests/layouts/layouttester/VerticalLayoutTests.java +++ b/tests/testbench/com/vaadin/tests/layouts/layouttester/VerticalLayoutTests.java @@ -14,6 +14,7 @@ import com.vaadin.ui.CheckBox; import com.vaadin.ui.DateField; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; import com.vaadin.ui.Link; import com.vaadin.ui.NativeSelect; @@ -46,7 +47,7 @@ public class VerticalLayoutTests extends AbstractLayoutTests { ((TextField) components[i]).setValue("FIELD " + i); vlo.addComponent(components[i]); vlo.setComponentAlignment(components[i], alignments[i]); - vlo.addComponent(new Label("<hr />", Label.CONTENT_XHTML)); + vlo.addComponent(new Label("<hr />", ContentMode.XHTML)); } baseLayout.addComponent(vlo); vlo = getTestLaytout(); @@ -55,7 +56,7 @@ public class VerticalLayoutTests extends AbstractLayoutTests { ((TextField) components[i]).setValue("FIELD " + i); vlo.addComponent(components[i]); vlo.setComponentAlignment(components[i], alignments[i]); - vlo.addComponent(new Label("<hr />", Label.CONTENT_XHTML)); + vlo.addComponent(new Label("<hr />", ContentMode.XHTML)); } baseLayout.addComponent(vlo); return baseLayout; @@ -115,7 +116,7 @@ public class VerticalLayoutTests extends AbstractLayoutTests { final AbstractComponent c1 = new Button("BUTTON"); final AbstractComponent c2 = new Label("<b>LABEL</b>", - Label.CONTENT_XHTML); + ContentMode.XHTML); final AbstractComponent c3 = new Table("TABLE"); c3.setHeight("100px"); c3.setWidth("100%"); @@ -268,7 +269,9 @@ public class VerticalLayoutTests extends AbstractLayoutTests { button4.setEnabled(false); vlo2.addComponent(c1); - vlo2.addComponent(new Label("<hr />", Label.CONTENT_XHTML)); + vlo2.addComponent(new Label( + "<div style='height: 1px'></div><hr /><div style='height: 1px'></div>", + ContentMode.XHTML)); vlo2.addComponent(c2); vlo2.setExpandRatio(c1, 0.5f); vlo2.setExpandRatio(c2, 0.5f); @@ -288,7 +291,9 @@ public class VerticalLayoutTests extends AbstractLayoutTests { public void buttonClick(ClickEvent event) { vlo2.setSizeUndefined(); - vlo2.addComponent(new Label("--- NEW LABEL ---")); + Label newLabel = new Label("--- NEW LABEL ---"); + newLabel.setSizeUndefined(); + vlo2.addComponent(newLabel); button2.setEnabled(false); button3.setEnabled(true); } @@ -453,7 +458,10 @@ public class VerticalLayoutTests extends AbstractLayoutTests { final VerticalLayout vlo2 = getTestLaytout(); vlo2.addComponent(c1); - vlo2.addComponent(new Label("<hr />", Label.CONTENT_XHTML)); + // Must add something around the hr to avoid the margins collapsing + vlo2.addComponent(new Label( + "<div style='height: 1px'></div><hr /><div style='height: 1px'></div>", + ContentMode.XHTML)); vlo2.addComponent(c2); vlo2.setExpandRatio(c1, 0.5f); vlo2.setExpandRatio(c2, 0.5f); @@ -510,7 +518,7 @@ public class VerticalLayoutTests extends AbstractLayoutTests { components[3] = getTestTabsheet(); components[3].setIcon(new ThemeResource(LOCK_16_PNG)); - AbstractField[] fields = new AbstractField[6]; + AbstractField<?>[] fields = new AbstractField<?>[6]; fields[0] = new TextField(); fields[0].setRequired(true); fields[0].setValidationVisible(true); diff --git a/tests/testbench/com/vaadin/tests/minitutorials/CustomConverterFactoryRoot.java b/tests/testbench/com/vaadin/tests/minitutorials/CustomConverterFactoryRoot.java new file mode 100644 index 0000000000..de32a817a1 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/CustomConverterFactoryRoot.java @@ -0,0 +1,33 @@ +package com.vaadin.tests.minitutorials; + +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.TextField; + +public class CustomConverterFactoryRoot extends AbstractTestRoot { + @Override + public void setup(WrappedRequest request) { + getApplication().setConverterFactory(new MyConverterFactory()); + + TextField tf = new TextField("This is my double field"); + tf.setImmediate(true); + tf.setConverter(Double.class); + addComponent(tf); + + // As we do not set the locale explicitly for the field we set the value + // after the field has been attached so it uses the application locale + // for conversion + tf.setConvertedValue(50.1); + + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Changing%20the%20default%20converters%20for%20an%20application"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/DynamicImageRoot.java b/tests/testbench/com/vaadin/tests/minitutorials/DynamicImageRoot.java new file mode 100644 index 0000000000..a0e6a54c41 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/DynamicImageRoot.java @@ -0,0 +1,79 @@ +package com.vaadin.tests.minitutorials; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.imageio.ImageIO; + +import com.vaadin.Application; +import com.vaadin.terminal.ExternalResource; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Embedded; + +public class DynamicImageRoot extends AbstractTestRoot { + + @Override + public void setup(WrappedRequest request) { + // Add the request handler that handles our dynamic image + getApplication().addRequestHandler(new DynamicImageRequestHandler()); + + // Create a URL that we can handle in DynamicImageRequestHandler + URL imageUrl; + try { + imageUrl = new URL(getApplication().getURL(), + DynamicImageRequestHandler.IMAGE_URL + "?text=Hello!"); + } catch (MalformedURLException e) { + // This should never happen + throw new RuntimeException(e); + } + + // Add an embedded using the created URL + Embedded embedded = new Embedded("A dynamically generated image", + new ExternalResource(imageUrl)); + embedded.setType(Embedded.TYPE_IMAGE); + getContent().addComponent(embedded); + + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Generating%20dynamic%20resources%20based%20on%20URI%20or%20parameters"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } +} + +class DynamicImageRequestHandler implements RequestHandler { + + public static final String IMAGE_URL = "myimage.png"; + + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + String pathInfo = request.getRequestPathInfo(); + if (("/" + IMAGE_URL).equals(pathInfo)) { + // Create an image, draw the "text" parameter to it and output it to + // the browser. + String text = request.getParameter("text"); + BufferedImage bi = new BufferedImage(100, 30, + BufferedImage.TYPE_3BYTE_BGR); + bi.getGraphics().drawChars(text.toCharArray(), 0, text.length(), + 10, 20); + response.setContentType("image/png"); + ImageIO.write(bi, "png", response.getOutputStream()); + + return true; + } + // If the URL did not match our image URL, let the other request + // handlers handle it + return false; + } +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/FormUsingExistingLayout.java b/tests/testbench/com/vaadin/tests/minitutorials/FormUsingExistingLayout.java new file mode 100644 index 0000000000..9d20867d24 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/FormUsingExistingLayout.java @@ -0,0 +1,98 @@ +package com.vaadin.tests.minitutorials; + +import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.data.fieldgroup.PropertyId; +import com.vaadin.data.util.BeanItem; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; + +public class FormUsingExistingLayout extends AbstractTestRoot { + + public static class Notice { + String firstName; + String lastName; + String message; + + public Notice(String firstName, String lastName, String message) { + this.firstName = firstName; + this.lastName = lastName; + this.message = message; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + } + + public static class MyFormLayout extends GridLayout { + private TextField firstName = new TextField("First name"); + private TextField lastName = new TextField("Last name"); + + // The name of the property is by default the name of the member field, + // but it can be redefined with the @PropertyId annotation + @PropertyId("message") + private TextArea messageField = new TextArea("Your message"); + + public MyFormLayout() { + // Set up the GridLayout + super(2, 3); + setSpacing(true); + + // Add the (currently unbound) fields + addComponent(firstName); + addComponent(lastName); + + addComponent(messageField, 0, 1, 1, 1); + messageField.setWidth("100%"); + } + + } + + @Override + protected void setup(WrappedRequest request) { + // Create the layout + MyFormLayout myFormLayout = new MyFormLayout(); + + // Create a field group and use it to bind the fields in the layout + FieldGroup fieldGroup = new FieldGroup(new BeanItem<Notice>(new Notice( + "John", "Doe", ""))); + fieldGroup.bindMemberFields(myFormLayout); + + addComponent(myFormLayout); + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Creating%20a%20form%20using%20an%20existing%20layout"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/FormatTableValue.java b/tests/testbench/com/vaadin/tests/minitutorials/FormatTableValue.java new file mode 100644 index 0000000000..aba1447d2c --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/FormatTableValue.java @@ -0,0 +1,60 @@ +package com.vaadin.tests.minitutorials; + +import java.text.NumberFormat; +import java.util.Locale; + +import com.vaadin.data.util.converter.StringToNumberConverter; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Table; + +public class FormatTableValue extends AbstractTestRoot { + + private static final String PERCENT_PROPERTY = "percent"; + private static final String CURRENCY_PROPERTY = "currency"; + private static final String DEFAULT_PROPERTY = "default"; + + @Override + protected void setup(WrappedRequest request) { + Table table = new Table(); + table.setLocale(Locale.FRANCE); + table.addContainerProperty(PERCENT_PROPERTY, Double.class, 0); + table.addContainerProperty(CURRENCY_PROPERTY, Double.class, 0); + table.addContainerProperty(DEFAULT_PROPERTY, Double.class, 0); + + Object itemId = table.addItem(); + table.getItem(itemId).getItemProperty(PERCENT_PROPERTY) + .setValue(3.1415); + table.getItem(itemId).getItemProperty(CURRENCY_PROPERTY) + .setValue(3.1415); + table.getItem(itemId).getItemProperty(DEFAULT_PROPERTY) + .setValue(3.1415); + + table.setConverter(PERCENT_PROPERTY, new StringToNumberConverter() { + @Override + protected NumberFormat getFormat(Locale locale) { + return NumberFormat.getPercentInstance(locale); + } + }); + + table.setConverter(CURRENCY_PROPERTY, new StringToNumberConverter() { + @Override + protected NumberFormat getFormat(Locale locale) { + return NumberFormat.getCurrencyInstance(locale); + } + }); + + addComponent(table); + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Formatting%20data%20in%20Table"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/IntegerTextFieldDataSource.java b/tests/testbench/com/vaadin/tests/minitutorials/IntegerTextFieldDataSource.java new file mode 100644 index 0000000000..5c0efea3ea --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/IntegerTextFieldDataSource.java @@ -0,0 +1,69 @@ +package com.vaadin.tests.minitutorials; + +import com.vaadin.data.Property; +import com.vaadin.data.util.BeanItem; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Label; +import com.vaadin.ui.Root; +import com.vaadin.ui.TextField; + +public class IntegerTextFieldDataSource extends AbstractTestRoot { + + public class MyBean { + private int value; + + public int getValue() { + return value; + } + + public void setValue(int integer) { + value = integer; + } + } + + @Override + protected void setup(WrappedRequest request) { + final MyBean myBean = new MyBean(); + BeanItem<MyBean> beanItem = new BeanItem<MyBean>(myBean); + + final Property<Integer> integerProperty = (Property<Integer>) beanItem + .getItemProperty("value"); + final TextField textField = new TextField("Text field", integerProperty); + + Button submitButton = new Button("Submit value", new ClickListener() { + public void buttonClick(ClickEvent event) { + String uiValue = textField.getValue(); + Integer propertyValue = integerProperty.getValue(); + int dataModelValue = myBean.getValue(); + + Root.getCurrentRoot().showNotification( + "UI value (String): " + uiValue + + "<br />Property value (Integer): " + + propertyValue + + "<br />Data model value (int): " + + dataModelValue); + } + }); + + addComponent(new Label("Text field type: " + textField.getType())); + addComponent(new Label("Text field type: " + integerProperty.getType())); + addComponent(textField); + addComponent(submitButton); + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Creating%20a%20TextField%20for%20Integer%20only%20input%20using%20a%20data%20source"; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/IntegerTextFieldStandalone.java b/tests/testbench/com/vaadin/tests/minitutorials/IntegerTextFieldStandalone.java new file mode 100644 index 0000000000..45bc49ba72 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/IntegerTextFieldStandalone.java @@ -0,0 +1,57 @@ +package com.vaadin.tests.minitutorials; + +import com.vaadin.data.util.converter.Converter.ConversionException; +import com.vaadin.data.util.converter.StringToIntegerConverter; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Label; +import com.vaadin.ui.Root; +import com.vaadin.ui.TextField; + +public class IntegerTextFieldStandalone extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + final TextField textField = new TextField("Text field"); + textField.setConverter(new StringToIntegerConverter()); + + Button submitButton = new Button("Submit value", new ClickListener() { + public void buttonClick(ClickEvent event) { + String uiValue = textField.getValue(); + try { + Integer convertedValue = (Integer) textField + .getConvertedValue(); + Root.getCurrentRoot().showNotification( + "UI value (String): " + uiValue + + "<br />Converted value (Integer): " + + convertedValue); + } catch (ConversionException e) { + e.printStackTrace(); + Root.getCurrentRoot().showNotification( + "Could not convert value: " + uiValue); + } + } + }); + + addComponent(new Label("Text field type: " + textField.getType())); + addComponent(new Label("Converterd text field type: " + + textField.getConverter().getModelType())); + addComponent(textField); + addComponent(submitButton); + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Creating%20a%20TextField%20for%20Integer%20only%20input%20when%20not%20using%20a%20data%20source"; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/MyConverterFactory.java b/tests/testbench/com/vaadin/tests/minitutorials/MyConverterFactory.java new file mode 100644 index 0000000000..456654e10a --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/MyConverterFactory.java @@ -0,0 +1,17 @@ +package com.vaadin.tests.minitutorials; + +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.DefaultConverterFactory; + +public class MyConverterFactory extends DefaultConverterFactory { + @Override + protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter( + Class<PRESENTATION> presentationType, Class<MODEL> modelType) { + // Handle String <-> Double + if (presentationType == String.class && modelType == Double.class) { + return (Converter<PRESENTATION, MODEL>) new MyStringToDoubleConverter(); + } + // Let default factory handle the rest + return super.findConverter(presentationType, modelType); + } +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/MyStringToDoubleConverter.java b/tests/testbench/com/vaadin/tests/minitutorials/MyStringToDoubleConverter.java new file mode 100644 index 0000000000..38268bdf68 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/MyStringToDoubleConverter.java @@ -0,0 +1,18 @@ +package com.vaadin.tests.minitutorials; + +import java.text.NumberFormat; +import java.util.Locale; + +import com.vaadin.data.util.converter.StringToDoubleConverter; + +public class MyStringToDoubleConverter extends StringToDoubleConverter { + + @Override + protected NumberFormat getFormat(Locale locale) { + NumberFormat format = super.getFormat(locale); + format.setGroupingUsed(false); + format.setMaximumFractionDigits(3); + format.setMinimumFractionDigits(3); + return format; + } +} diff --git a/tests/testbench/com/vaadin/tests/minitutorials/StringMyTypeConverter.java b/tests/testbench/com/vaadin/tests/minitutorials/StringMyTypeConverter.java new file mode 100644 index 0000000000..e28788f743 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/minitutorials/StringMyTypeConverter.java @@ -0,0 +1,108 @@ +package com.vaadin.tests.minitutorials; + +import java.util.Locale; + +import com.vaadin.data.util.converter.Converter; +import com.vaadin.data.util.converter.Converter.ConversionException; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.tests.components.AbstractTestRoot; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.TextField; + +public class StringMyTypeConverter extends AbstractTestRoot { + + @Override + protected void setup(WrappedRequest request) { + Name name = new Name("Rudolph", "Reindeer"); + + final TextField textField = new TextField("Name"); + textField.setConverter(new StringToNameConverter()); + textField.setConvertedValue(name); + + addComponent(textField); + addComponent(new Button("Submit value", new ClickListener() { + public void buttonClick(ClickEvent event) { + try { + Name name = (Name) textField.getConvertedValue(); + getRoot().showNotification( + "First name: " + name.getFirstName() + + "<br />Last name: " + name.getLastName()); + } catch (ConversionException e) { + e.printStackTrace(); + getRoot().showNotification(e.getCause().getMessage()); + } + } + })); + } + + @Override + protected String getTestDescription() { + return "Mini tutorial for https://vaadin.com/wiki/-/wiki/Main/Creating%20your%20own%20converter%20for%20String%20-%20MyType%20conversion"; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} + +class StringToNameConverter implements Converter<String, Name> { + public Name convertToModel(String text, Locale locale) + throws ConversionException { + if (text == null) { + return null; + } + String[] parts = text.split(" "); + if (parts.length != 2) { + throw new ConversionException("Can not convert text to a name: " + + text); + } + return new Name(parts[0], parts[1]); + } + + public String convertToPresentation(Name name, Locale locale) + throws ConversionException { + if (name == null) { + return null; + } else { + return name.getFirstName() + " " + name.getLastName(); + } + } + + public Class<Name> getModelType() { + return Name.class; + } + + public Class<String> getPresentationType() { + return String.class; + } +} + +class Name { + private String firstName; + private String lastName; + + public Name(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/tests/testbench/com/vaadin/tests/requesthandlers/AppResource404.html b/tests/testbench/com/vaadin/tests/requesthandlers/AppResource404.html new file mode 100644 index 0000000000..da050b3aaa --- /dev/null +++ b/tests/testbench/com/vaadin/tests/requesthandlers/AppResource404.html @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="http://localhost:8888/" /> +<title>CloseSubWindow</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">CloseSubWindow</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.requesthandlers.AppResource404?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClickAndWait</td> + <td>vaadin=runcomvaadintestsrequesthandlersAppResource404::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLink[0]/domChild[0]/domChild[0]</td> + <td>57,3</td> +</tr> +<tr> + <td>assertTextNotPresent</td> + <td>404</td> + <td></td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.requesthandlers.AppResource404</td> + <td></td> +</tr> +<tr> + <td>mouseClickAndWait</td> + <td>vaadin=runcomvaadintestsrequesthandlersAppResource404::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VLink[0]/domChild[0]/domChild[0]</td> + <td>72,9</td> +</tr> +<tr> + <td>assertTextPresent</td> + <td>RequestURI=/run/com.vaadin.tests.requesthandlers.AppResource404/APP/12341234/</td> + <td></td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.requesthandlers.AppResource404</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestsrequesthandlersAppResource404::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>mouseClickAndWait</td> + <td>vaadin=runcomvaadintestsrequesthandlersAppResource404::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VLink[0]/domChild[0]/domChild[0]</td> + <td>47,9</td> +</tr> +<tr> + <td>assertTextPresent</td> + <td>RequestURI=/run/com.vaadin.tests.requesthandlers.AppResource404/APP/1//com/vaadin/tests/integration/se.gif</td> + <td></td> +</tr> +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/requesthandlers/AppResource404.java b/tests/testbench/com/vaadin/tests/requesthandlers/AppResource404.java new file mode 100644 index 0000000000..1d98e35dd5 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/requesthandlers/AppResource404.java @@ -0,0 +1,41 @@ +package com.vaadin.tests.requesthandlers; + +import com.vaadin.terminal.ExternalResource; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.integration.FlagSeResource; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Link; + +public class AppResource404 extends TestBase { + + @Override + protected void setup() { + // Add one existing resource + final FlagSeResource resource = new FlagSeResource(this); + resource.setCacheTime(0); + addResource(resource); + + addComponent(new Link("Existing resource", resource)); + addComponent(new Link("Non-existing resource", new ExternalResource( + getURL().toString() + "APP/12341234/"))); + + addComponent(new Button("Remove existing resrouce", + new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + removeResource(resource); + } + })); + } + + @Override + protected String getDescription() { + return "Accessing the URL of a resource that has been removed or the URL following the resource URL pattern but not currently mapped to a resource should give a 404 error message"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(6702); + } + +} diff --git a/tests/testbench/com/vaadin/tests/themes/ButtonsTest.java b/tests/testbench/com/vaadin/tests/themes/ButtonsTest.java index 9425cd9bd2..cc275c18f4 100644 --- a/tests/testbench/com/vaadin/tests/themes/ButtonsTest.java +++ b/tests/testbench/com/vaadin/tests/themes/ButtonsTest.java @@ -1,5 +1,7 @@ package com.vaadin.tests.themes; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.terminal.ThemeResource; import com.vaadin.terminal.UserError; import com.vaadin.ui.Button; @@ -8,12 +10,13 @@ import com.vaadin.ui.CheckBox; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.NativeButton; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.LegacyWindow; @SuppressWarnings("serial") -public class ButtonsTest extends com.vaadin.Application { +public class ButtonsTest extends com.vaadin.Application.LegacyApplication { - final Window main = new Window("Button states & themes"); + final Root.LegacyWindow main = new LegacyWindow("Button states & themes"); CheckBox styleToggle; CheckBox iconToggle; @@ -29,8 +32,10 @@ public class ButtonsTest extends com.vaadin.Application { setMainWindow(main); setTheme("reindeer"); - themeToggle = new CheckBox("Runo theme", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + themeToggle = new CheckBox("Runo theme"); + themeToggle.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { if (getTheme() == "reindeer") { setTheme("runo"); } else { @@ -41,8 +46,10 @@ public class ButtonsTest extends com.vaadin.Application { themeToggle.setStyleName("small"); themeToggle.setImmediate(true); - styleToggle = new CheckBox("Black style", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + styleToggle = new CheckBox("Black style"); + styleToggle.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { if (!main.getContent().getStyleName().contains("black")) { main.getContent().setStyleName("black"); } else { @@ -53,8 +60,10 @@ public class ButtonsTest extends com.vaadin.Application { styleToggle.setImmediate(true); styleToggle.setStyleName("small"); - iconToggle = new CheckBox("64x icons", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + iconToggle = new CheckBox("64x icons"); + iconToggle.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { largeIcons = !largeIcons; recreateAll(); } @@ -62,13 +71,14 @@ public class ButtonsTest extends com.vaadin.Application { iconToggle.setImmediate(true); iconToggle.setStyleName("small"); - nativeToggle = new CheckBox("Native buttons", - new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - nativeButtons = !nativeButtons; - recreateAll(); - } - }); + nativeToggle = new CheckBox("Native buttons"); + nativeToggle.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + nativeButtons = !nativeButtons; + recreateAll(); + } + }); nativeToggle.setImmediate(true); nativeToggle.setStyleName("small"); @@ -155,4 +165,4 @@ public class ButtonsTest extends com.vaadin.Application { return hl; } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1225.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1225.java index 0596fd4d49..92a5e526d1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1225.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1225.java @@ -4,23 +4,24 @@ import com.vaadin.Application; import com.vaadin.tests.TestForTablesInitialColumnWidthLogicRendering; import com.vaadin.ui.Alignment; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; /** * With IE7 extra scrollbars appear in content area all though content fits * properly. Scrollbars will disappear if "shaking" content a bit, like * selecting tests in area. */ -public class Ticket1225 extends Application { +public class Ticket1225 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window( + final LegacyWindow mainWin = new LegacyWindow( "Test app to break layout fuction in IE7"); setMainWindow(mainWin); @@ -45,7 +46,7 @@ public class Ticket1225 extends Application { Label red = new Label( "<div style='background:red;width:100%;height:100%;'>??</div>", - Label.CONTENT_XHTML); + ContentMode.XHTML); // red.setCaption("cap"); // red.setSizeFull(); @@ -58,7 +59,7 @@ public class Ticket1225 extends Application { ts.getTab(red).setCaption("REd tab"); Label l = new Label("<div style='background:blue;'>sdf</div>", - Label.CONTENT_XHTML); + ContentMode.XHTML); el.addComponent(l); el.setComponentAlignment(l, Alignment.MIDDLE_RIGHT); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1230.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1230.java index fd859459c0..872084d436 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1230.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1230.java @@ -6,10 +6,10 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; -import com.vaadin.ui.Window; -public class Ticket1230 extends Application { +public class Ticket1230 extends Application.LegacyApplication { private static final Object PROPERTY_ID = new Object(); private static final Object NULL_ITEM_ID = new Object(); @@ -18,7 +18,7 @@ public class Ticket1230 extends Application { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); GridLayout layout = new GridLayout(5, 5); @@ -127,7 +127,6 @@ public class Ticket1230 extends Application { @SuppressWarnings("deprecation") private Select createSelect() { Select select = new Select(); - select.setMultiSelect(false); select.addContainerProperty(PROPERTY_ID, String.class, ""); select.setItemCaptionPropertyId(PROPERTY_ID); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket124.java b/tests/testbench/com/vaadin/tests/tickets/Ticket124.java index efd28d7f41..f1d33dca0b 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket124.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket124.java @@ -6,17 +6,19 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket124 extends Application { +public class Ticket124 extends Application.LegacyApplication { private TextField tf; private GridLayout gl; @Override public void init() { - Window w = new Window("#124: Insert & remove row for GridLayout"); + LegacyWindow w = new LegacyWindow( + "#124: Insert & remove row for GridLayout"); setMainWindow(w); setTheme("tests-tickets"); // gl = new GridLayout(4, 4); @@ -45,7 +47,7 @@ public class Ticket124 extends Application { gl.addComponent(new Label("0,0-1,0"), 0, 0, 1, 0); gl.addComponent(new Label("2,0-3,0"), 2, 0, 3, 0); Label l = new Label("Large cell 0,1-2,2<br/>yadayada<br/>lorem ipsum"); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); gl.addComponent(l, 0, 1, 2, 2); gl.addComponent(new Label("3-1"), 3, 1); gl.addComponent(new Label("3,2-3,3"), 3, 2, 3, 3); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1245.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1245.java index 2e8675de7b..a5aa8cd2ac 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1245.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1245.java @@ -5,20 +5,20 @@ import com.vaadin.data.Property; import com.vaadin.ui.AbstractSelect; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; import com.vaadin.ui.themes.Reindeer; -public class Ticket1245 extends com.vaadin.Application { +public class Ticket1245 extends com.vaadin.Application.LegacyApplication { TextField f = new TextField(); @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); main.addComponent(new TreeExample()); @@ -80,7 +80,9 @@ class TreeExample extends CustomComponent { // get the created item final Item item = tree.getItem(id); // set our "caption" property - final Property p = item.getItemProperty(CAPTION_PROPERTY); + @SuppressWarnings("unchecked") + final Property<String> p = (Property<String>) item + .getItemProperty(CAPTION_PROPERTY); p.setValue(caption); if (parent != null) { tree.setChildrenAllowed(parent, true); @@ -90,4 +92,4 @@ class TreeExample extends CustomComponent { return id; } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1362Login.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1362Login.java deleted file mode 100644 index d8fdefbd38..0000000000 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1362Login.java +++ /dev/null @@ -1,275 +0,0 @@ -package com.vaadin.tests.tickets; - -import java.io.ByteArrayInputStream; -import java.net.URL; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; - -import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.ParameterHandler; -import com.vaadin.terminal.URIHandler; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.CustomComponent; -import com.vaadin.ui.Embedded; -import com.vaadin.ui.Label; -import com.vaadin.ui.Panel; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; - -/** - * Proof of concept how to create a decent login screen that works with browsers - * PW managers. (Browsers don't autofill generated login forms) - * - * TODO generalize js to work inside iframes (if a Vaadin application is inside - * iframe) - * - * TODO extract login form to a external template. - * - * TODO theme - * - * TODO refine docs, make LoginBox a standard Vaadin component - * - * TODO article - * - */ -public class Ticket1362Login extends Application { - - public class LoginBox extends CustomComponent { - - Embedded iframe = new Embedded(); - - ApplicationResource loginPage = new ApplicationResource() { - - private byte[] loginHTML = ("" - + "<html>" - + "<head><script type='text/javascript'>" - + "var setTarget = function() {document.getElementById('loginf').action = top.location;};" - + "</script></head>" - + "<body onload='setTarget();'>" - + "Iframe generated by LoginBox. PW managers can autofill form. Form handled by LoginBox " - + "that will fire LoginEvents. Will post into another iframe, from where the script " - + "will find Vaadin client that will be force synced. <form id='loginf' target='logintarget'>" - + "Username : <input type='text' name='username'>" - + "Password : <input type='password' name='password'>" - + "<input type='submit' value='login'>" + "</form>" - + "<iframe name='logintarget'></iframe>" + "</body>" - + "</html>").getBytes(); - - public Application getApplication() { - return LoginBox.this.getApplication(); - } - - public int getBufferSize() { - return loginHTML.length; - } - - public long getCacheTime() { - return 0; - } - - public String getFilename() { - return "login.html"; - } - - public DownloadStream getStream() { - return new DownloadStream(new ByteArrayInputStream(loginHTML), - getMIMEType(), getFilename()); - } - - public String getMIMEType() { - return "text/html"; - } - }; - - private ParameterHandler paramHandler = new ParameterHandler() { - - public void handleParameters(Map<String, String[]> parameters) { - if (parameters.containsKey("username")) { - getWindow().addURIHandler(uriHandler); - - HashMap<String, String> params = new HashMap<String, String>(); - // expecting single params - for (Iterator<String> it = parameters.keySet().iterator(); it - .hasNext();) { - String key = it.next(); - String value = (parameters.get(key))[0]; - params.put(key, value); - } - LoginEvent event = new LoginEvent(params); - for (Iterator<LoginListener> iterator = listeners - .iterator(); iterator.hasNext();) { - LoginListener listener = iterator.next(); - listener.onLogin(event); - } - } - } - }; - - private URIHandler uriHandler = new URIHandler() { - public DownloadStream handleURI(URL context, String relativeUri) { - if (window != null) { - window.removeURIHandler(this); - } - return new DownloadStream( - new ByteArrayInputStream( - "<html><body>Login form handeled.<script type='text/javascript'>top.vaadin.forceSync();</script></body></html>" - .getBytes()), "text/html", - "loginSuccesfull.html"); - } - }; - - private LinkedList<LoginListener> listeners = new LinkedList<LoginListener>(); - - private Window window; - - LoginBox() { - iframe.setType(Embedded.TYPE_BROWSER); - iframe.setSizeFull(); - setCompositionRoot(iframe); - } - - @Override - public void attach() { - super.attach(); - getApplication().addResource(loginPage); - getWindow().addParameterHandler(paramHandler); - iframe.setSource(loginPage); - } - - @Override - public void detach() { - getApplication().removeResource(loginPage); - getWindow().removeParameterHandler(paramHandler); - // store window temporary to properly remove uri handler once - // response is handled. (May happen if login handler removes login - // box - window = getWindow(); - super.detach(); - } - - /** - * This event is sent when login form is submitted. - */ - public class LoginEvent { - - private Map<String, String> params; - - private LoginEvent(Map<String, String> params) { - this.params = params; - } - - /** - * Returns form value by field name. - * - * @param name - * @return value in given field - */ - public String getLoginParameter(String name) { - if (params.containsKey(name)) { - return params.get(name); - } else { - return null; - } - } - } - - /** - * Adds LoginListener to handle login logic - * - * @param listener - */ - public void addLoginListener(LoginListener listener) { - listeners.add(listener); - } - - /** - * Removes LoginListener - * - * @param listener - */ - public void removeLoginListener(LoginListener listener) { - listeners.remove(listener); - } - - } - - /** - * Login listener is a class capable to listen LoginEvents sent from - * LoginBox - */ - public interface LoginListener { - /** - * This method is fired on each login form post. - * - * @param event - */ - public void onLogin(LoginBox.LoginEvent event); - } - - final static String GUEST = "guest"; - - LoginBox loginBox = new LoginBox(); - - Label currentUser = new Label(GUEST); - - private Panel mainPanel; - - private VerticalLayout el; - - @Override - public void init() { - - final Window mainWin = new Window( - "Test app with password manager savvy login functionality"); - - el = new VerticalLayout(); - - currentUser.setCaption("Currennt user"); - el.addComponent(currentUser); - - el.addComponent(loginBox); - el.setExpandRatio(loginBox, 1); - - mainWin.setContent(el); - - setMainWindow(mainWin); - - mainPanel = new Panel("Test app"); - mainPanel.setSizeFull(); - mainPanel.addComponent(new Label("User is logged in")); - mainPanel.addComponent(new Button("Logout", new Button.ClickListener() { - - public void buttonClick(ClickEvent event) { - Ticket1362Login.this.close(); - } - })); - - loginBox.addLoginListener(new LoginListener() { - public void onLogin(LoginBox.LoginEvent event) { - String pw = event.getLoginParameter("password"); - String username = event.getLoginParameter("username"); - if (pw.equals("1234")) { - setUser(username); - currentUser.setValue(username); - currentUser.getWindow().showNotification( - "Logged in user: " + username); - getMainWindow().getContent().replaceComponent(loginBox, - mainPanel); - el.setExpandRatio(mainPanel, 1); - } else { - getMainWindow().showNotification( - "Wrong password. Hint, try '1234' ", - Notification.TYPE_WARNING_MESSAGE); - } - } - }); - - } - -}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1365.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1365.java index 9916ca634d..b35d185811 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1365.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1365.java @@ -4,10 +4,11 @@ import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.event.ShortcutAction; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1365 extends com.vaadin.Application implements Handler { +public class Ticket1365 extends com.vaadin.Application.LegacyApplication + implements Handler { TextField f = new TextField(); @@ -15,8 +16,8 @@ public class Ticket1365 extends com.vaadin.Application implements Handler { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); main.addComponent(f); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1368.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1368.java index 9df316fdcb..a1a5b449d1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1368.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1368.java @@ -3,19 +3,19 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.tests.TestForTablesInitialColumnWidthLogicRendering; import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; /** */ -public class Ticket1368 extends Application { +public class Ticket1368 extends Application.LegacyApplication { private Table t; @Override public void init() { - final Window mainWin = new Window("Test app to #1368"); + final LegacyWindow mainWin = new LegacyWindow("Test app to #1368"); setMainWindow(mainWin); t = TestForTablesInitialColumnWidthLogicRendering.getTestTable(3, 5); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1397.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1397.java index 282df33d89..dfccf31956 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1397.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1397.java @@ -10,18 +10,18 @@ import com.vaadin.ui.InlineDateField; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.PopupView; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1397 extends Application { +public class Ticket1397 extends Application.LegacyApplication { - Window main; + LegacyWindow main; @Override public void init() { setTheme("runo"); - main = new Window("PopupView test"); + main = new LegacyWindow("PopupView test"); setMainWindow(main); Panel panel = new Panel("PopupTest"); @@ -31,7 +31,7 @@ public class Ticket1397 extends Application { PopupView.Content content = new PopupView.Content() { public String getMinimizedValueAsHTML() { - return prop.toString(); + return String.valueOf(prop.getValue()); } public Component getPopupComponent() { @@ -69,7 +69,7 @@ public class Ticket1397 extends Application { panel2.addComponent(new myButton()); PopupView.Content content2 = new PopupView.Content() { public String getMinimizedValueAsHTML() { - return prop2.toString(); + return String.valueOf(prop2.getValue()); } public Component getPopupComponent() { @@ -90,7 +90,7 @@ public class Ticket1397 extends Application { PopupView.Content content3 = new PopupView.Content() { public String getMinimizedValueAsHTML() { - return op.toString(); + return String.valueOf(op.getValue()); } public Component getPopupComponent() { @@ -114,7 +114,7 @@ public class Ticket1397 extends Application { final InlineDateField df = new InlineDateField("", new Date()); PopupView pp = new PopupView(new PopupView.Content() { public String getMinimizedValueAsHTML() { - return df.toString(); + return String.valueOf(df.getValue()); } public Component getPopupComponent() { @@ -131,7 +131,8 @@ public class Ticket1397 extends Application { + " and see how the overview-version changes."); public String getMinimizedValueAsHTML() { - return "" + tf.toString().length() + " characters of info"; + return "" + String.valueOf(tf.getValue()).length() + + " characters of info"; } public Component getPopupComponent() { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1435.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1435.java index b961c0d6b1..c280be4e4a 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1435.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1435.java @@ -11,18 +11,19 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1435 extends Application { +public class Ticket1435 extends Application.LegacyApplication { private static final boolean useWorkaround = true; @Override public void init() { - final Window mainWin = new Window("ButtonPanel containing a table test"); + final LegacyWindow mainWin = new LegacyWindow( + "ButtonPanel containing a table test"); setMainWindow(mainWin); ((AbstractOrderedLayout) mainWin.getContent()).setSpacing(true); @@ -54,7 +55,7 @@ public class Ticket1435 extends Application { // Last known height before the panel was collapsed private float lastHeight = -1; - private int lastHeightUnit = -1; + private Unit lastHeightUnit = null; public ButtonPanel(String labelString) { setCompositionRoot(root); @@ -162,7 +163,7 @@ public class Ticket1435 extends Application { root.setExpandRatio(container, 1); } - public void setHeight(int height, int unit) { + public void setHeight(int height, Unit unit) { root.setHeight(height, unit); lastHeight = height; lastHeightUnit = unit; @@ -182,7 +183,7 @@ public class Ticket1435 extends Application { root.setWidth(width); } - public void setWidth(int width, int unit) { + public void setWidth(int width, Unit unit) { root.setWidth(width, unit); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1444.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1444.java index 003b50240b..5076e79996 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1444.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1444.java @@ -2,15 +2,16 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1444 extends Application { +public class Ticket1444 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window( + final LegacyWindow mainWin = new LegacyWindow( "Test app to break layout fuction in IE7"); setMainWindow(mainWin); @@ -20,7 +21,7 @@ public class Ticket1444 extends Application { Label red = new Label( "<div style='background:red;width:100%;height:100%;'>??</div>", - Label.CONTENT_XHTML); + ContentMode.XHTML); red.setSizeFull(); ol.addComponent(red); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1465ModalNotification.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1465ModalNotification.java index ff716aefc1..9459c7cc85 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1465ModalNotification.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1465ModalNotification.java @@ -4,14 +4,18 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; -public class Ticket1465ModalNotification extends Application { +public class Ticket1465ModalNotification extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window("ButtonPanel containing a table test"); + final LegacyWindow mainWin = new LegacyWindow( + "ButtonPanel containing a table test"); setMainWindow(mainWin); final Window modal = new Window("Modal window"); @@ -21,9 +25,9 @@ public class Ticket1465ModalNotification extends Application { new Button.ClickListener() { public void buttonClick(ClickEvent event) { - modal.showNotification( + Root.getCurrentRoot().showNotification( "Try clicking the button in main window!", - Window.Notification.TYPE_ERROR_MESSAGE); + Notification.TYPE_ERROR_MESSAGE); } }); @@ -33,9 +37,9 @@ public class Ticket1465ModalNotification extends Application { new Button.ClickListener() { public void buttonClick(ClickEvent event) { - modal.showNotification( + Root.getCurrentRoot().showNotification( "Try clicking the button in main window!", - Window.Notification.TYPE_WARNING_MESSAGE); + Notification.TYPE_WARNING_MESSAGE); } }); modal.addComponent(b); @@ -44,9 +48,9 @@ public class Ticket1465ModalNotification extends Application { new Button.ClickListener() { public void buttonClick(ClickEvent event) { - modal.showNotification( + Root.getCurrentRoot().showNotification( "Try clicking the button in main window!", - Window.Notification.TYPE_HUMANIZED_MESSAGE); + Notification.TYPE_HUMANIZED_MESSAGE); } }); modal.addComponent(b); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer.java index a0f3070988..616e40d917 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer.java @@ -65,7 +65,7 @@ public class Ticket1506_TestContainer implements Container { return a; } - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { if (items.isEmpty()) { loadItems(); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer2.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer2.java index 4b296d2eda..863ce907da 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer2.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1506_TestContainer2.java @@ -57,7 +57,7 @@ public class Ticket1506_TestContainer2 implements Container { return items.keySet(); } - public Property getContainerProperty(Object itemId, Object propertyId) { + public Property<?> getContainerProperty(Object itemId, Object propertyId) { if (items.isEmpty()) { loadItems(); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1519.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1519.java index ff6d340372..1c4156d7ff 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1519.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1519.java @@ -2,18 +2,18 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; -import com.vaadin.ui.Window; -public class Ticket1519 extends Application { +public class Ticket1519 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window("Test app to #1519"); + final LegacyWindow mainWin = new LegacyWindow("Test app to #1519"); setMainWindow(mainWin); - mainWin.setTheme("tests-tickets"); + setTheme("tests-tickets"); TabSheet ts = new TabSheet(); ts.addTab(new CustomLayout("Ticket1519_News"), "News", null); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1572.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1572.java index 425a3d5ee2..614c471d3e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1572.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1572.java @@ -6,9 +6,9 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1572 extends com.vaadin.Application { +public class Ticket1572 extends com.vaadin.Application.LegacyApplication { private Label state; private GridLayout gl; @@ -17,8 +17,8 @@ public class Ticket1572 extends com.vaadin.Application { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); Panel p = new Panel("Test wrapper for gridlayout margin/spacing"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1581.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1581.java index e87ad848ce..1efea99a0e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1581.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1581.java @@ -7,9 +7,9 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; import com.vaadin.ui.ProgressIndicator; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1581 extends com.vaadin.Application { +public class Ticket1581 extends com.vaadin.Application.LegacyApplication { private Label time; private ProgressIndicator poller; @@ -17,8 +17,8 @@ public class Ticket1581 extends com.vaadin.Application { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); main.addComponent(new Label("Test the second issue in ticket #1581")); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1589.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1589.java index 7074be65e4..7aba886133 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1589.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1589.java @@ -6,7 +6,6 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.net.URL; import java.util.Date; import javax.imageio.ImageIO; @@ -14,20 +13,22 @@ import javax.imageio.ImageIO; import com.vaadin.Application; import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.ExternalResource; -import com.vaadin.terminal.URIHandler; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.ui.Link; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1589 extends Application { +public class Ticket1589 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); MyDynamicResource res = new MyDynamicResource(); - w.addURIHandler(res); + addRequestHandler(res); w.addComponent(new Link( "Test (without Content-Disposition, should suggest generatedFile.png when saving, browser default for actual disposition)", @@ -39,7 +40,7 @@ public class Ticket1589 extends Application { } } -class MyDynamicResource implements URIHandler { +class MyDynamicResource implements RequestHandler { String textToDisplay = (new Date()).toString(); /** @@ -49,11 +50,14 @@ class MyDynamicResource implements URIHandler { * Returns null if the URI does not match. Otherwise returns a download * stream that contains the response from the server. */ - public DownloadStream handleURI(URL context, String relativeUri) { + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + String relativeUri = request.getRequestPathInfo(); // Catch the given URI that identifies the resource, otherwise let other // URI handlers or the Application to handle the response. if (!relativeUri.startsWith("myresource")) { - return null; + return false; } // Create an image and draw some background on it. @@ -86,9 +90,10 @@ class MyDynamicResource implements URIHandler { downloadStream.setParameter("Content-Disposition", "attachment; filename=\"downloadedPNG.png\""); } - return downloadStream; + downloadStream.writeTo(response); + return true; } catch (IOException e) { - return null; + return false; } } }
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1598.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1598.java index 20f1d4d985..0faf9b8afb 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1598.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1598.java @@ -8,11 +8,11 @@ import com.vaadin.terminal.ThemeResource; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1598 extends Application { +public class Ticket1598 extends Application.LegacyApplication { - Window main = new Window("MenuBar test"); + LegacyWindow main = new LegacyWindow("MenuBar test"); final MenuBar menuBar = new MenuBar(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket161.java b/tests/testbench/com/vaadin/tests/tickets/Ticket161.java index b2998c687d..1819076b32 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket161.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket161.java @@ -5,19 +5,19 @@ import com.vaadin.data.Container; import com.vaadin.tests.TestForTablesInitialColumnWidthLogicRendering; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; /** */ -public class Ticket161 extends Application { +public class Ticket161 extends Application.LegacyApplication { private Table t; @Override public void init() { - final Window mainWin = new Window("Test app to #1368"); + final LegacyWindow mainWin = new LegacyWindow("Test app to #1368"); setMainWindow(mainWin); t = TestForTablesInitialColumnWidthLogicRendering.getTestTable(3, 100); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1632.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1632.java index e156752450..1774000355 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1632.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1632.java @@ -4,19 +4,19 @@ import com.vaadin.Application; import com.vaadin.data.Item; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; /** */ -public class Ticket1632 extends Application { +public class Ticket1632 extends Application.LegacyApplication { private Table t; @Override public void init() { - final Window mainWin = new Window("Test app"); + final LegacyWindow mainWin = new LegacyWindow("Test app"); setMainWindow(mainWin); t = new Table(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1659.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1659.java index 8bba5a103e..d78a1d78af 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1659.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1659.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1659 extends Application { +public class Ticket1659 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window(); + final LegacyWindow mainWin = new LegacyWindow(); setMainWindow(mainWin); mainWin.addComponent(new Button( "Change URI using Application.getURL()", diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1663.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1663.java index 79bd22a96d..64d53e33f6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1663.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1663.java @@ -1,15 +1,15 @@ package com.vaadin.tests.tickets; import com.vaadin.terminal.SystemError; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1663 extends com.vaadin.Application { +public class Ticket1663 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - Window main = new Window("#1663"); + LegacyWindow main = new LegacyWindow("#1663"); setMainWindow(main); TextField tf = new TextField("First name"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1673.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1673.java index 7af141b972..891cdf9f21 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1673.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1673.java @@ -2,17 +2,22 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; -import com.vaadin.ui.Window; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1673 extends com.vaadin.Application { +public class Ticket1673 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window("#1673"); + final LegacyWindow main = new LegacyWindow("#1673"); setMainWindow(main); - main.addComponent(new Button("close", this, "close")); + main.addComponent(new Button("close", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + close(); + } + })); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1710.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1710.java index 176f2efdd2..827879d3c6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1710.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1710.java @@ -21,11 +21,11 @@ import com.vaadin.ui.Layout; import com.vaadin.ui.Layout.AlignmentHandler; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1710 extends com.vaadin.Application { +public class Ticket1710 extends com.vaadin.Application.LegacyApplication { @Override public void init() { @@ -33,7 +33,7 @@ public class Ticket1710 extends com.vaadin.Application { setTheme("tests-tickets"); VerticalLayout lo = new VerticalLayout(); - setMainWindow(new Window("#1710", lo)); + setMainWindow(new LegacyWindow("#1710", lo)); lo.setMargin(true); lo.setSpacing(true); lo.setWidth("100%"); @@ -99,7 +99,6 @@ public class Ticket1710 extends com.vaadin.Application { cb.setImmediate(true); hidingControls.addComponent(cb); elhp.setVisible(false); - elhp.setScrollable(true); elh.setWidth("2000px"); elh.setHeight("100px"); addFields(elh); @@ -139,9 +138,6 @@ public class Ticket1710 extends com.vaadin.Application { private Form getFormPanelExample() { Form f = new Form(); f.setCaption("Test form"); - Button fb1 = new Button("Test button"); - fb1.setComponentError(new SystemError("Test error")); - f.addField("fb1", fb1); CheckBox fb2 = new CheckBox("Test button", true); fb2.setComponentError(new SystemError("Test error")); f.addField("fb2", fb2); @@ -254,7 +250,6 @@ public class Ticket1710 extends com.vaadin.Application { Panel controlWrapper = new Panel(); controlWrapper.addComponent(controls); controlWrapper.setWidth("100%"); - controlWrapper.setScrollable(true); controlWrapper.setStyleName("controls"); internalLayout.addComponent(controlWrapper); Panel testPanel = new Panel(testPanelLayout); @@ -395,15 +390,13 @@ public class Ticket1710 extends com.vaadin.Application { } private void updateMarginsAndSpacing() { - testedLayout.setMargin( - ((Boolean) marginTop.getValue()).booleanValue(), - ((Boolean) marginRight.getValue()).booleanValue(), - ((Boolean) marginBottom.getValue()).booleanValue(), - ((Boolean) marginLeft.getValue()).booleanValue()); + testedLayout.setMargin(marginTop.getValue().booleanValue(), + marginRight.getValue().booleanValue(), marginBottom + .getValue().booleanValue(), marginLeft.getValue() + .booleanValue()); if (testedLayout instanceof Layout.SpacingHandler) { - ((Layout.SpacingHandler) testedLayout) - .setSpacing(((Boolean) spacing.getValue()) - .booleanValue()); + ((Layout.SpacingHandler) testedLayout).setSpacing(spacing + .getValue().booleanValue()); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1737.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1737.java index f45fe88889..ccd649c542 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1737.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1737.java @@ -7,10 +7,10 @@ import com.vaadin.terminal.Resource; import com.vaadin.ui.Embedded; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1737 extends Application { +public class Ticket1737 extends Application.LegacyApplication { Resource slowRes = new ClassResource(Ticket1737.class, "m-bullet-blue.gif", this) { @@ -28,8 +28,8 @@ public class Ticket1737 extends Application { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); VerticalLayout el = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1767.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1767.java index 92fbddeeb3..bf57118a8c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1767.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1767.java @@ -1,15 +1,15 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.ComboBox; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1767 extends com.vaadin.Application { +public class Ticket1767 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); ComboBox cb = new ComboBox(" '<' item is not seen in populist?"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1772.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1772.java index 7cf3483277..7ca90904f8 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1772.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1772.java @@ -3,16 +3,16 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1772 extends com.vaadin.Application { +public class Ticket1772 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); Button b = new Button("Add content"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1775.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1775.java index de841288e8..aed69056aa 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1775.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1775.java @@ -4,16 +4,16 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1775 extends com.vaadin.Application { +public class Ticket1775 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window("#1775"); + final LegacyWindow main = new LegacyWindow("#1775"); setMainWindow(main); - main.setTheme("tests-tickets"); + setTheme("tests-tickets"); String layoutName = "Ticket1775"; final CustomLayout layout = new CustomLayout(layoutName); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1804.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1804.java index e22fbe90ee..b659eff01e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1804.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1804.java @@ -10,17 +10,19 @@ import com.vaadin.ui.AbstractField; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; import com.vaadin.ui.Window; -public class Ticket1804 extends com.vaadin.Application { +public class Ticket1804 extends com.vaadin.Application.LegacyApplication { LinkedList<Select> listOfAllFields = new LinkedList<Select>(); @Override public void init() { - final Window main = new Window("#1804"); + final LegacyWindow main = new LegacyWindow("#1804"); setMainWindow(main); com.vaadin.ui.Select s; @@ -93,7 +95,7 @@ public class Ticket1804 extends com.vaadin.Application { StringBuffer msg = new StringBuffer(); for (Iterator<Select> i = listOfAllFields.iterator(); i .hasNext();) { - AbstractField af = i.next(); + AbstractField<?> af = i.next(); msg.append("<h1>" + af.getCaption() + "</h1>\n"); msg.append("Value=" + af.getValue() + "<br/>\n"); if (af.isValid()) { @@ -105,9 +107,8 @@ public class Ticket1804 extends com.vaadin.Application { } Window w = new Window("Status of the fields"); w.setModal(true); - w.setScrollable(true); w.setHeight("80%"); - w.addComponent(new Label(msg.toString(), Label.CONTENT_XHTML)); + w.addComponent(new Label(msg.toString(), ContentMode.XHTML)); main.addWindow(w); } }); @@ -127,7 +128,7 @@ public class Ticket1804 extends com.vaadin.Application { } /** Throws an exception when the string is empty or null. */ - class EmptyStringValidator implements Validator { + static class EmptyStringValidator implements Validator { String msg; @@ -135,12 +136,8 @@ public class Ticket1804 extends com.vaadin.Application { this.msg = msg; } - public boolean isValid(Object value) { - return !(value == null || value.toString().length() == 0); - } - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { + if (value == null || value.toString().length() == 0) { throw new InvalidValueException(msg); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1805.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1805.java index d2407aae39..d7eac667f0 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1805.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1805.java @@ -7,15 +7,15 @@ import com.vaadin.ui.Button; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1805 extends com.vaadin.Application { +public class Ticket1805 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); ((Layout) main.getContent()).setMargin(false); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1806.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1806.java index c403a8242c..c47ea49697 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1806.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1806.java @@ -3,15 +3,15 @@ package com.vaadin.tests.tickets; import com.vaadin.data.util.ObjectProperty; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1806 extends com.vaadin.Application { +public class Ticket1806 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); final ObjectProperty<String> prop = new ObjectProperty<String>(""); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1811.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1811.java index 6cbf37541c..7df9610e99 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1811.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1811.java @@ -8,17 +8,19 @@ import com.vaadin.data.validator.StringLengthValidator; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.Window; -public class Ticket1811 extends com.vaadin.Application { +public class Ticket1811 extends com.vaadin.Application.LegacyApplication { LinkedList<TextField> listOfAllFields = new LinkedList<TextField>(); @Override public void init() { - final Window main = new Window("#1811"); + final LegacyWindow main = new LegacyWindow("#1811"); setMainWindow(main); Validator strLenValidator = new StringLengthValidator( @@ -69,7 +71,7 @@ public class Ticket1811 extends com.vaadin.Application { } Window w = new Window("Status of the fields"); w.setModal(true); - w.addComponent(new Label(msg.toString(), Label.CONTENT_XHTML)); + w.addComponent(new Label(msg.toString(), ContentMode.XHTML)); main.addWindow(w); } }); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1819.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1819.java index 97357d8d2c..86325f35a9 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1819.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1819.java @@ -7,17 +7,19 @@ import com.vaadin.ui.AbstractField; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; import com.vaadin.ui.Window; -public class Ticket1819 extends com.vaadin.Application { +public class Ticket1819 extends com.vaadin.Application.LegacyApplication { LinkedList<Select> listOfAllFields = new LinkedList<Select>(); @Override public void init() { - final Window main = new Window("#1819"); + final LegacyWindow main = new LegacyWindow("#1819"); setMainWindow(main); com.vaadin.ui.Select s; @@ -49,13 +51,13 @@ public class Ticket1819 extends com.vaadin.Application { StringBuffer msg = new StringBuffer(); for (Iterator<Select> i = listOfAllFields.iterator(); i .hasNext();) { - AbstractField af = i.next(); + AbstractField<?> af = i.next(); msg.append("<h1>" + af.getCaption() + "</h1>\n"); msg.append("Value=" + af.getValue() + "<br/>\n"); } Window w = new Window("Status of the fields"); w.setModal(true); - w.addComponent(new Label(msg.toString(), Label.CONTENT_XHTML)); + w.addComponent(new Label(msg.toString(), ContentMode.XHTML)); main.addWindow(w); } }); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1834PanelScrolling.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1834PanelScrolling.java index 824447b6a9..912f5ba02d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1834PanelScrolling.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1834PanelScrolling.java @@ -6,9 +6,10 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1834PanelScrolling extends com.vaadin.Application { +public class Ticket1834PanelScrolling extends + com.vaadin.Application.LegacyApplication { private static final int ROWS = 50; @@ -18,8 +19,8 @@ public class Ticket1834PanelScrolling extends com.vaadin.Application { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); HorizontalLayout currentState = new HorizontalLayout(); @@ -68,7 +69,6 @@ public class Ticket1834PanelScrolling extends com.vaadin.Application { main.addComponent(b); p = new Panel("TestPanel"); - p.setScrollable(true); for (int i = 0; i < ROWS; i++) { p.addComponent(new Label( diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1857.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1857.java index f82467b519..2af5bf9c85 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1857.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1857.java @@ -7,11 +7,12 @@ import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.ui.CheckBox; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1857 extends Application implements Handler { +public class Ticket1857 extends Application.LegacyApplication implements + Handler { @Override public void init() { @@ -19,7 +20,7 @@ public class Ticket1857 extends Application implements Handler { setTheme("tests-tickets"); VerticalLayout el = new VerticalLayout(); - Window main = new Window("Testcase for #1857", el); + LegacyWindow main = new LegacyWindow("Testcase for #1857", el); setMainWindow(main); el.setMargin(true); el.setSpacing(true); @@ -41,7 +42,7 @@ public class Ticket1857 extends Application implements Handler { actionHandlerEnabler.setImmediate(true); actionHandlerEnabler.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - if (((Boolean) actionHandlerEnabler.getValue()).booleanValue()) { + if (actionHandlerEnabler.getValue().booleanValue()) { t.addActionHandler(Ticket1857.this); } else { t.removeActionHandler(Ticket1857.this); @@ -54,7 +55,7 @@ public class Ticket1857 extends Application implements Handler { cellStylesEnabler.setImmediate(true); cellStylesEnabler.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - if (((Boolean) cellStylesEnabler.getValue()).booleanValue()) { + if (cellStylesEnabler.getValue().booleanValue()) { t.setCellStyleGenerator(new Table.CellStyleGenerator() { public String getStyle(Object itemId, Object propertyId) { Object cell = t.getContainerProperty(itemId, diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1868.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1868.java index fe32dbc775..1af0ed2041 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1868.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1868.java @@ -1,14 +1,14 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1868 extends com.vaadin.Application { +public class Ticket1868 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - setMainWindow(new Window("#1868")); + setMainWindow(new LegacyWindow("#1868")); Panel p = new Panel( "This is a really long caption for the panel, too long in fact!"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1869.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1869.java index 9c2fdb762d..d51c0990ae 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1869.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1869.java @@ -4,16 +4,16 @@ import com.vaadin.ui.Button; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1869 extends com.vaadin.Application { +public class Ticket1869 extends com.vaadin.Application.LegacyApplication { @Override public void init() { GridLayout lo = new GridLayout(2, 1); - setMainWindow(new Window("#1869", lo)); + setMainWindow(new LegacyWindow("#1869", lo)); lo.setMargin(true); lo.setSpacing(true); @@ -32,7 +32,6 @@ public class Ticket1869 extends com.vaadin.Application { lo.addComponent(elp); elp.setWidth("300px"); elp.setHeight("300px"); - elp.setScrollable(true); HorizontalLayout elh = new HorizontalLayout(); Panel elph = new Panel( @@ -49,7 +48,6 @@ public class Ticket1869 extends com.vaadin.Application { lo.addComponent(elph); elph.setWidth("300px"); elph.setHeight("300px"); - elph.setScrollable(true); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1878.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1878.java index 0cacb603fc..6072782dc3 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1878.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1878.java @@ -23,11 +23,11 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.Layout.AlignmentHandler; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1878 extends Application { +public class Ticket1878 extends Application.LegacyApplication { private Layout orderedLayout; private Layout gridLayout; @@ -39,7 +39,7 @@ public class Ticket1878 extends Application { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); @@ -184,7 +184,7 @@ public class Ticket1878 extends Application { form.setItemDataSource(item); for (Iterator<?> i = item.getItemPropertyIds().iterator(); i.hasNext();) { Object property = i.next(); - Field f = form.getField(property); + Field<?> f = form.getField(property); f.setRequired(r.nextBoolean()); if (r.nextBoolean()) { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1900.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1900.java index 2047b4698c..fdbecf8eae 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1900.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1900.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Validator; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1900 extends Application { +public class Ticket1900 extends Application.LegacyApplication { TextField f[] = new TextField[5]; - Window main = new Window("#1900 test"); + LegacyWindow main = new LegacyWindow("#1900 test"); @Override public void init() { @@ -53,19 +53,15 @@ public class Ticket1900 extends Application { } - class ContainsValidator implements Validator { + static class ContainsValidator implements Validator { private final String c; public ContainsValidator(String c) { this.c = c; } - public boolean isValid(Object value) { - return value != null && value.toString().contains(c); - } - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { + if (value == null || !value.toString().contains(c)) { throw new InvalidValueException("Value does not contain " + c); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1904.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1904.java index 1d79158333..2837d71e67 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1904.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1904.java @@ -5,14 +5,14 @@ import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1904 extends Application { +public class Ticket1904 extends Application.LegacyApplication { @Override public void init() { - setMainWindow(new Window("#1904")); + setMainWindow(new LegacyWindow("#1904")); setTheme("tests-tickets"); addOL("defaults", null, false); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1916.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1916.java index d340bf144a..790d3aa931 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1916.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1916.java @@ -4,10 +4,10 @@ import com.vaadin.Application; import com.vaadin.terminal.UserError; import com.vaadin.ui.Alignment; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket1916 extends Application { +public class Ticket1916 extends Application.LegacyApplication { @Override public void init() { @@ -21,7 +21,7 @@ public class Ticket1916 extends Application { test.addComponent(tf); test.setComponentAlignment(tf, Alignment.MIDDLE_CENTER); - Window w = new Window("Test #1916", test); + LegacyWindow w = new LegacyWindow("Test #1916", test); setMainWindow(w); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1919.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1919.java index 70bc0e1211..68a2eaa2bc 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1919.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1919.java @@ -1,23 +1,24 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1919 extends com.vaadin.Application { +public class Ticket1919 extends com.vaadin.Application.LegacyApplication { private GridLayout lo; private boolean on = true; @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); - main.setTheme("tests-tickets"); + setTheme("tests-tickets"); lo = new GridLayout(2, 2); lo.setSizeFull(); @@ -46,8 +47,12 @@ public class Ticket1919 extends com.vaadin.Application { Panel p = new Panel(); p.setSizeFull(); - Button b = new Button("toggle Values", this, "toggleStyleName"); + Button b = new Button("toggle Values", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + toggleStyleName(); + } + }); p.addComponent(b); return p; } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1921.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1921.java index 71c45c34ce..c0a1c7d2c9 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1921.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1921.java @@ -1,15 +1,20 @@ package com.vaadin.tests.tickets; +import java.io.IOException; import java.util.Map; import com.vaadin.Application; -import com.vaadin.terminal.ParameterHandler; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1921 extends Application implements ParameterHandler { +public class Ticket1921 extends Application.LegacyApplication implements + RequestHandler { int state = -1; int round = 1; @@ -20,11 +25,15 @@ public class Ticket1921 extends Application implements ParameterHandler { public void init() { outer = new VerticalLayout(); - setMainWindow(new Window("#1921", outer)); + setMainWindow(new LegacyWindow("#1921", outer)); setTheme("tests-tickets"); inner = new VerticalLayout(); outer.addComponent(inner); - button = new Button("foo", this, "newState"); + button = new Button("foo", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + newState(); + } + }); inner.addComponent(button); outer.setStyleName("red"); @@ -32,7 +41,7 @@ public class Ticket1921 extends Application implements ParameterHandler { newState(); - getMainWindow().addParameterHandler(this); + addRequestHandler(this); } public void newState() { @@ -83,14 +92,17 @@ public class Ticket1921 extends Application implements ParameterHandler { } } - public void handleParameters(Map<String, String[]> parameters) { + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + Map<String, String[]> parameters = request.getParameterMap(); String[] s = parameters.get("state"); if (s == null || s.length != 1) { - return; + return false; } String v[] = s[0].split("\\."); if (v == null || v.length != 2) { - return; + return false; } try { int rr = Integer.parseInt(v[0]); @@ -98,12 +110,13 @@ public class Ticket1921 extends Application implements ParameterHandler { if (rr < round || (rr == round && rs < state)) { getMainWindow().showNotification( "Already past requested " + s[0]); - return; + return false; } while (round < rr || state < rs) { newState(); } } catch (NumberFormatException ignored) { } + return false; } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1923.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1923.java index 9ea952a2b5..17a7dacf26 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1923.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1923.java @@ -2,10 +2,10 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1923 extends com.vaadin.Application { +public class Ticket1923 extends com.vaadin.Application.LegacyApplication { private static final int ROWS = 50; @@ -13,13 +13,12 @@ public class Ticket1923 extends com.vaadin.Application { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); p = new Panel("TestPanel 250x300"); // p.getLayout().setWidth("100%"); - p.setScrollable(true); // p.setContent(new GridLayout(1, 100)); for (int i = 0; i < ROWS; i++) { p.addComponent(new Label( diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1924ThemeChanging.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1924ThemeChanging.java deleted file mode 100644 index 11621c7fa9..0000000000 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1924ThemeChanging.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.vaadin.tests.tickets; - -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.Label; -import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; - -public class Ticket1924ThemeChanging extends com.vaadin.Application { - - private Label l = new Label("Background should be red with test theme"); - - @SuppressWarnings("unused") - private Panel p; - - @Override - public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); - setMainWindow(main); - - l.setStyleName("red"); - main.addComponent(l); - - Button b = new Button("Toggle tests-tickets theme"); - b.addListener(new ClickListener() { - boolean flag = false; - - public void buttonClick(ClickEvent event) { - if (flag == !flag) { - main.setTheme("tests-tickets"); - } else { - main.setTheme(null); - } - } - }); - - main.addComponent(b); - - b = new Button("Modify caption (should not reload page)"); - b.addListener(new ClickListener() { - public void buttonClick(ClickEvent event) { - main.setCaption(main.getCaption() + "."); - } - }); - - main.addComponent(b); - - } -}
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1925.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1925.java index bb15f2c80e..91ea8c0c44 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1925.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1925.java @@ -1,13 +1,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1925 extends Application { +public class Ticket1925 extends Application.LegacyApplication { @Override public void init() { - Window mainWindow = new Window("Test åäö"); + LegacyWindow mainWindow = new LegacyWindow("Test åäö"); setMainWindow(mainWindow); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1939.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1939.java index 2970335d83..d24cace2c9 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1939.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1939.java @@ -3,15 +3,15 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1939 extends Application { +public class Ticket1939 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); final VerticalLayout l = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1940.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1940.java index a3264ecba4..10eebe4cba 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1940.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1940.java @@ -1,15 +1,15 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1940 extends Application { +public class Ticket1940 extends Application.LegacyApplication { @Override public void init() { - final Window w = new Window(getClass().getName()); + final LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); final VerticalLayout l = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1953.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1953.java index 43e7f10220..a832401cd0 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1953.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1953.java @@ -4,9 +4,9 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1953 extends Application { +public class Ticket1953 extends Application.LegacyApplication { public static final String cellStyle = "test-cell"; public static final String colHeadStyle = "test-col-head"; public static final String headingStyle = "test-heading"; @@ -16,11 +16,11 @@ public class Ticket1953 extends Application { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); - main.setTheme("tests-tickets"); + setTheme("tests-tickets"); GridLayout gl = new GridLayout(5, 5); gl.setStyleName("borders"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1966.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1966.java index 2245be0057..d461ffe4e3 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1966.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1966.java @@ -9,14 +9,14 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.Layout.AlignmentHandler; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1966 extends Application { +public class Ticket1966 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); // setTheme("tests-tickets"); w.setContent(new GridLayout(2, 2)); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1966_2.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1966_2.java index 2d287ecdd4..85b802d46c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1966_2.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1966_2.java @@ -9,14 +9,14 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.Layout.AlignmentHandler; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1966_2 extends Application { +public class Ticket1966_2 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); w.setContent(new GridLayout(2, 2)); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1966_3.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1966_3.java index e6953d4193..cfc9825b58 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1966_3.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1966_3.java @@ -6,15 +6,15 @@ import com.vaadin.terminal.UserError; import com.vaadin.ui.Alignment; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1966_3 extends Application { +public class Ticket1966_3 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1969.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1969.java index ffe099b067..aed322ca4d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1969.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1969.java @@ -5,17 +5,17 @@ import com.vaadin.tests.TestForTablesInitialColumnWidthLogicRendering; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1969 extends com.vaadin.Application { +public class Ticket1969 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); main.getContent().setSizeFull(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1970.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1970.java index 1442c9ea5b..beeda85c9f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1970.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1970.java @@ -6,10 +6,10 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.CloseEvent; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1970 extends Application { +public class Ticket1970 extends Application.LegacyApplication { @Override public void init() { @@ -17,10 +17,10 @@ public class Ticket1970 extends Application { } @Override - public Window getWindow(String name) { + public LegacyWindow getWindow(String name) { // If we already have the requested window, use it - Window w = super.getWindow(name); + LegacyWindow w = super.getWindow(name); if (w == null) { // If no window found, create it @@ -29,8 +29,8 @@ public class Ticket1970 extends Application { return w; } - private Window createExtraWindow(String name) { - final Window w = new Window("Extra window: " + name); + private LegacyWindow createExtraWindow(String name) { + final LegacyWindow w = new LegacyWindow("Extra window: " + name); w.setName(name); addWindow(w); w.addComponent(new Label( @@ -40,26 +40,21 @@ public class Ticket1970 extends Application { public void buttonClick(ClickEvent event) { String openWindows = ""; - for (Iterator<Window> i = getWindows().iterator(); i + for (Iterator<LegacyWindow> i = getWindows().iterator(); i .hasNext();) { - Window t = i.next(); + LegacyWindow t = i.next(); openWindows += (openWindows.length() > 0 ? "," : "") + t.getName(); } w.showNotification(openWindows); } })); - w.addListener(new Window.CloseListener() { - public void windowClose(CloseEvent e) { - removeWindow(w); - } - }); return w; } - private Window createWindow() { - final Window w = new Window(); + private LegacyWindow createWindow() { + final LegacyWindow w = new LegacyWindow(); w.addComponent(new Button("Show the name of the application", new Button.ClickListener() { public void buttonClick(ClickEvent event) { @@ -68,11 +63,11 @@ public class Ticket1970 extends Application { } })); w.addComponent(new Label("<a href='" + getURL().toExternalForm() + "'>" - + getURL().toExternalForm() + "</a>", Label.CONTENT_XHTML)); + + getURL().toExternalForm() + "</a>", ContentMode.XHTML)); w.addComponent(new Label( "<h2>How to reproduce</h2>Open the above link in another browser" + " window and then press the Show-button on this window.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); return w; } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1972.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1972.java index 62b001bbda..fd77343259 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1972.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1972.java @@ -3,13 +3,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1972 extends Application { +public class Ticket1972 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); setTheme("tests-ticket"); GridLayout layout = new GridLayout(3, 3); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1973.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1973.java index 9629c4507b..d4b1345eb1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1973.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1973.java @@ -4,13 +4,13 @@ import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1973 extends com.vaadin.Application { +public class Ticket1973 extends com.vaadin.Application.LegacyApplication { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); Table table = new Table(); @Override diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1973_2.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1973_2.java index 5cffdbd5db..d43aac9da0 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1973_2.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1973_2.java @@ -5,12 +5,12 @@ import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket1973_2 extends Application { - Window main = new Window(); +public class Ticket1973_2 extends Application.LegacyApplication { + LegacyWindow main = new LegacyWindow(); Table table = new Table(); @Override diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1975.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1975.java index 4f4376721a..d908cc567c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1975.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1975.java @@ -11,16 +11,16 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.GridLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1975 extends Application { +public class Ticket1975 extends Application.LegacyApplication { private CustomLayout cl1; private CustomLayout cl2; @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); setTheme("tests-tickets"); GridLayout layout = new GridLayout(1, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1982.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1982.java index 53e5630353..431c3a6b99 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1982.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1982.java @@ -10,15 +10,15 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket1982 extends Application { +public class Ticket1982 extends Application.LegacyApplication { private List<TitleBar> components = new ArrayList<TitleBar>(); @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); GridLayout gl = new GridLayout(2, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1983.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1983.java index fbab5c5244..5bd0cd2ae6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1983.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1983.java @@ -1,25 +1,26 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.util.IndexedContainer; import com.vaadin.terminal.Sizeable; import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * Test class for ticket 1983 */ -public class Ticket1983 extends Application { +public class Ticket1983 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window("Test for ticket 1983"); + LegacyWindow main = new LegacyWindow("Test for ticket 1983"); main.setContent(new TestLayout()); setMainWindow(main); } @@ -33,7 +34,6 @@ public class Ticket1983 extends Application { public TestLayout() { setSplitPosition(200, Sizeable.UNITS_PIXELS); - setMargin(false); setLocked(true); final HorizontalSplitPanel leftSide = initLeftSide(); @@ -114,11 +114,11 @@ public class Ticket1983 extends Application { ol.addComponent(button); leftSide.setFirstComponent(ol); - button = new CheckBox("Two col"); - button.addListener(new Button.ClickListener() { - public void buttonClick(ClickEvent event) { - Button b = event.getButton(); - if (((Boolean) b.getValue()).booleanValue()) { + CheckBox checkBox = new CheckBox("Two col"); + checkBox.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + if ((Boolean) event.getProperty().getValue()) { table.setVisibleColumns(new Object[] { propId, propId2 }); } else { table.setVisibleColumns(new Object[] { propId }); @@ -127,7 +127,7 @@ public class Ticket1983 extends Application { } }); - ol.addComponent(button); + ol.addComponent(checkBox); return leftSide; } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1986.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1986.java index 44d4632427..88ebad933f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1986.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1986.java @@ -8,15 +8,15 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.ListSelect; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.OptionGroup; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.TwinColSelect; -import com.vaadin.ui.Window; -public class Ticket1986 extends Application { +public class Ticket1986 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); int index = 1; diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1991.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1991.java index d2aca84848..72866a3ee8 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1991.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1991.java @@ -1,15 +1,15 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class Ticket1991 extends com.vaadin.Application { +public class Ticket1991 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); Table t = new Table("Test table"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket1995.java b/tests/testbench/com/vaadin/tests/tickets/Ticket1995.java index 8b66c7f012..23f377e89e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket1995.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket1995.java @@ -7,17 +7,17 @@ import com.vaadin.data.Item; import com.vaadin.data.util.filter.SimpleStringFilter; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class Ticket1995 extends Application { +public class Ticket1995 extends Application.LegacyApplication { private static final Object PROPERTY_1 = "Test"; private Table table; @Override public void init() { - final Window mainWin = new Window(getClass().getName()); + final LegacyWindow mainWin = new LegacyWindow(getClass().getName()); setMainWindow(mainWin); table = new Table(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket20.java b/tests/testbench/com/vaadin/tests/tickets/Ticket20.java index 55fee95de3..5c4779e69e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket20.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket20.java @@ -4,43 +4,29 @@ import com.vaadin.Application; import com.vaadin.data.Validator; import com.vaadin.data.util.MethodProperty; import com.vaadin.data.validator.CompositeValidator; +import com.vaadin.data.validator.CompositeValidator.CombinationMode; +import com.vaadin.data.validator.IntegerValidator; import com.vaadin.ui.Button; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket20 extends Application { +public class Ticket20 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window("Test app for #20"); + final LegacyWindow mainWin = new LegacyWindow("Test app for #20"); setMainWindow(mainWin); final TextField tx = new TextField("Integer"); mainWin.addComponent(tx); tx.setImmediate(true); CompositeValidator v = new CompositeValidator(); + v.addValidator(new IntegerValidator("{0} is not a number")); v.addValidator(new Validator() { - public boolean isValid(Object value) { - try { - Integer.parseInt("" + value); - return true; - } catch (NumberFormatException e) { - return false; - } - } - - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { - throw new InvalidValueException(value + " is not a number"); - } - } - }); - v.addValidator(new Validator() { - - public boolean isValid(Object value) { + private boolean isValid(Object value) { try { int i = Integer.parseInt("" + value); if (i < 0) { @@ -59,17 +45,12 @@ public class Ticket20 extends Application { } } }); - CompositeValidator v2 = new CompositeValidator( - CompositeValidator.MODE_OR, null); + CompositeValidator v2 = new CompositeValidator(CombinationMode.OR, null); v2.addValidator(v); v2.addValidator(new Validator() { - public boolean isValid(Object value) { - return "".equals("" + value); - } - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { + if (!"".equals("" + value)) { throw new InvalidValueException("Value is not empty string"); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2001.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2001.java index 4796451dc0..a14c881b85 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2001.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2001.java @@ -5,14 +5,14 @@ import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2001 extends Application { +public class Ticket2001 extends Application.LegacyApplication { @Override public void init() { - final Window w = new Window(getClass().getName()); + final LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); final VerticalLayout l = new VerticalLayout(); @@ -23,7 +23,7 @@ public class Ticket2001 extends Application { final CheckBox b = new CheckBox("fixed width: 30px", false); b.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - if (b.booleanValue()) { + if ((Boolean) b.getValue()) { l.setWidth("30px"); } else { l.setWidth(null); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2002.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2002.java index 2776fbc3b4..2c4a948cea 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2002.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2002.java @@ -3,10 +3,10 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.data.util.MethodProperty; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2002 extends Application { +public class Ticket2002 extends Application.LegacyApplication { private Long long1 = new Long(1L); private Long long2 = new Long(2L); @@ -28,7 +28,7 @@ public class Ticket2002 extends Application { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); GridLayout layout = new GridLayout(2, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2007.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2007.java index 84dafb41f3..6700267a25 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2007.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2007.java @@ -4,22 +4,22 @@ import com.vaadin.Application; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2007 extends Application { +public class Ticket2007 extends Application.LegacyApplication { int childs = 0; @Override public void init() { - final Window main = new Window("Main window for #2007"); + final LegacyWindow main = new LegacyWindow("Main window for #2007"); setMainWindow(main); main.addComponent(new Button("Open another (non-main) window", new Button.ClickListener() { public void buttonClick(ClickEvent event) { - Window c = new Window("Non-main browser window " - + (++childs)); + LegacyWindow c = new LegacyWindow( + "Non-main browser window " + (++childs)); addWindow(c); main.open(new ExternalResource(c.getURL()), "_new"); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2009.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2009.java index b1138acc08..7667d6190b 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2009.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2009.java @@ -8,20 +8,21 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; import com.vaadin.ui.Tree; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; -public class Ticket2009 extends com.vaadin.Application { +public class Ticket2009 extends com.vaadin.Application.LegacyApplication { TextField f = new TextField(); @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); HorizontalLayout ol = new HorizontalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2011.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2011.java index 0cfa642ff4..e8113b0cea 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2011.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2011.java @@ -2,14 +2,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; -import com.vaadin.ui.Window; -public class Ticket2011 extends Application { +public class Ticket2011 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); // setTheme("tests-ticket"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2014.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2014.java index e4cf36b084..538ebc4ccd 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2014.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2014.java @@ -9,9 +9,9 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2014 extends Application { +public class Ticket2014 extends Application.LegacyApplication { private HorizontalLayout innerLayout1; private Button b1; @@ -19,7 +19,7 @@ public class Ticket2014 extends Application { @Override public void init() { - Window w = new Window(getClass().getName()); + LegacyWindow w = new LegacyWindow(getClass().getName()); setMainWindow(w); // setTheme("tests-ticket"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2021.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2021.java index 9f37ddfef3..cab8fc261c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2021.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2021.java @@ -10,11 +10,11 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextArea; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2021 extends Application { +public class Ticket2021 extends Application.LegacyApplication { private TextArea tf1, tf2, tf3; @@ -26,7 +26,7 @@ public class Ticket2021 extends Application { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); w.setContent(new GridLayout(2, 2)); setMainWindow(w); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2022.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2022.java index 501f11e0b4..bc97f906b1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2022.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2022.java @@ -2,13 +2,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.CustomLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2022 extends Application { +public class Ticket2022 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); CustomLayout l; diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2023.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2023.java index ac80ef602b..238561ef47 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2023.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2023.java @@ -4,16 +4,16 @@ import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.GridLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2023 extends com.vaadin.Application implements - Button.ClickListener { +public class Ticket2023 extends com.vaadin.Application.LegacyApplication + implements Button.ClickListener { AbstractComponent c = new Button(); @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); String[] sizes = { "20", "100", "1", "0", "-1", "", "z" }; diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2024.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2024.java index 41c7fd96f1..e7cabbca95 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2024.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2024.java @@ -3,15 +3,15 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2024 extends Application { +public class Ticket2024 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(2, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2026.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2026.java index aa23572e0a..6d608ad529 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2026.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2026.java @@ -2,14 +2,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2026 extends Application { +public class Ticket2026 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); GridLayout layout = new GridLayout(2, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2029.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2029.java index f13b57d110..1eadd3d7bd 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2029.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2029.java @@ -11,12 +11,12 @@ import com.vaadin.ui.Component; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2029 extends Application { +public class Ticket2029 extends Application.LegacyApplication { int COMPONENTS; int DIM1, DIM2; @@ -28,7 +28,7 @@ public class Ticket2029 extends Application { DIM1 = 504; DIM2 = 100; - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); Panel p = createPanel(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2037.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2037.java index 782cbd06c2..86d9cf6d40 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2037.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2037.java @@ -4,14 +4,14 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2037 extends com.vaadin.Application { +public class Ticket2037 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); main.addComponent(new Label( diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2038.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2038.java index 85a5a4b701..a5c102b988 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2038.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2038.java @@ -4,15 +4,15 @@ import com.vaadin.Application; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; -public class Ticket2038 extends Application { +public class Ticket2038 extends Application.LegacyApplication { @Override public void init() { - final Window w = new Window("Testing for #2038"); + final LegacyWindow w = new LegacyWindow("Testing for #2038"); setMainWindow(w); final TextField tf = new TextField( @@ -36,7 +36,7 @@ public class Ticket2038 extends Application { b.setImmediate(true); b.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - tf.setRequiredError(b.booleanValue() ? "Field must not be empty" + tf.setRequiredError((Boolean) b.getValue() ? "Field must not be empty" : null); } }); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2040.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2040.java index 35210ebaa4..ac8928d110 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2040.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2040.java @@ -3,17 +3,17 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.Accordion; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2040 extends com.vaadin.Application { +public class Ticket2040 extends com.vaadin.Application.LegacyApplication { TextField f = new TextField(); @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); main.getContent().setSizeFull(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2042.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2042.java index 1714a93f82..c4eded63d7 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2042.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2042.java @@ -6,14 +6,14 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2042 extends Application { +public class Ticket2042 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(1, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2043.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2043.java index ce42699094..7238462397 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2043.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2043.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Link; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2043 extends Application { +public class Ticket2043 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2048.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2048.java index 92a08eced9..84978a42e1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2048.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2048.java @@ -10,10 +10,10 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2048 extends Application { +public class Ticket2048 extends Application.LegacyApplication { private Embedded embedded; private Panel p; @@ -21,7 +21,7 @@ public class Ticket2048 extends Application { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); // splitPanel = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2051.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2051.java index 29aeef21b1..bd098443f2 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2051.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2051.java @@ -7,18 +7,18 @@ import com.vaadin.ui.Component; import com.vaadin.ui.DateField; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2051 extends Application { +public class Ticket2051 extends Application.LegacyApplication { private static final Object P1 = new Object(); private static final Object P2 = new Object(); @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2053.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2053.java index f784b40aed..751dbbae01 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2053.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2053.java @@ -7,18 +7,17 @@ import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.CloseEvent; -public class Ticket2053 extends Application { +public class Ticket2053 extends Application.LegacyApplication { int childs = 0; @Override public void init() { - final Window main = new Window("#2053"); + final LegacyWindow main = new LegacyWindow("#2053"); setMainWindow(main); Button nothing = new Button("Do nothing"); main.addComponent(nothing); @@ -28,12 +27,8 @@ public class Ticket2053 extends Application { Button add = new Button("Add a window", new Button.ClickListener() { public void buttonClick(ClickEvent event) { final String name = "Child " + (++childs); - Window c = new Window(name); - c.addListener(new Window.CloseListener() { - public void windowClose(CloseEvent e) { - main.addComponent(new Label(name + " closed")); - } - }); + LegacyWindow c = new LegacyWindow(name); + addWindow(c); main.open(new ExternalResource(c.getURL()), "_new"); main.addComponent(new Label(name + " opened")); @@ -42,7 +37,7 @@ public class Ticket2053 extends Application { tf.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { main.addComponent(new Label(name + " send text:" - + tf.toString())); + + tf.getValue())); } }); for (int i = 0; i < 3; i++) { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2060.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2060.java index 061c71a509..b47fbc8818 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2060.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2060.java @@ -6,9 +6,9 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2060 extends Application { +public class Ticket2060 extends Application.LegacyApplication { private Button button1; private Button button2; @@ -16,7 +16,7 @@ public class Ticket2060 extends Application { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2061.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2061.java index c9cc3ce328..0881d141cb 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2061.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2061.java @@ -8,18 +8,18 @@ import com.vaadin.data.util.HierarchicalContainer; import com.vaadin.ui.Accordion; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2061 extends Application { +public class Ticket2061 extends Application.LegacyApplication { - private Window mainWindow; + private LegacyWindow mainWindow; @Override public void init() { - mainWindow = new Window("Ticket 2061"); + mainWindow = new LegacyWindow("Ticket 2061"); mainWindow.setSizeFull(); mainWindow.getContent().setSizeFull(); setMainWindow(mainWindow); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2061b.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2061b.java index 5dc6dde768..98badf36e8 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2061b.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2061b.java @@ -12,6 +12,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; import com.vaadin.ui.TabSheet.SelectedTabChangeListener; @@ -19,17 +20,16 @@ import com.vaadin.ui.Table; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; -public class Ticket2061b extends Application implements +public class Ticket2061b extends Application.LegacyApplication implements SelectedTabChangeListener { - private Window mainWindow; + private LegacyWindow mainWindow; private Panel p; @Override public void init() { - mainWindow = new Window("Ticket 2061b"); + mainWindow = new LegacyWindow("Ticket 2061b"); mainWindow.setSizeFull(); AbstractOrderedLayout mainLayout = (AbstractOrderedLayout) mainWindow .getContent(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2061c.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2061c.java index 4cca979268..a8188a4913 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2061c.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2061c.java @@ -10,22 +10,22 @@ import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; import com.vaadin.ui.TabSheet.SelectedTabChangeListener; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2061c extends Application implements +public class Ticket2061c extends Application.LegacyApplication implements SelectedTabChangeListener { - private Window mainWindow; + private LegacyWindow mainWindow; private Panel p; @Override public void init() { - mainWindow = new Window("Vaadin"); + mainWindow = new LegacyWindow("Vaadin"); mainWindow.setSizeFull(); mainWindow.getContent().setSizeFull(); setMainWindow(mainWindow); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2062.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2062.java index 5b6bbe71de..5d91240c6a 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2062.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2062.java @@ -2,17 +2,17 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.HorizontalSplitPanel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2062 extends Application { +public class Ticket2062 extends Application.LegacyApplication { private static final Object P1 = new Object(); @Override public void init() { - setMainWindow(new Window("Ticket2062")); + setMainWindow(new LegacyWindow("Ticket2062")); getMainWindow().setSizeFull(); HorizontalSplitPanel p = new HorizontalSplitPanel(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2083.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2083.java index 25ecfabbec..ea77b6f2e6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2083.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2083.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2083 extends Application { +public class Ticket2083 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(10, 10); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2090.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2090.java index 5bc69e0a64..b4171b9bac 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2090.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2090.java @@ -3,18 +3,17 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; -import com.vaadin.terminal.Sizeable; import com.vaadin.terminal.UserError; import com.vaadin.ui.Button; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2090 extends Application { +public class Ticket2090 extends Application.LegacyApplication { Label label = new Label(); Button target = new Button(); - Window w = new Window("#2090"); + LegacyWindow w = new LegacyWindow("#2090"); @Override public void init() { @@ -30,7 +29,7 @@ public class Ticket2090 extends Application { height.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { try { - target.setHeight(height.toString()); + target.setHeight(height.getValue()); height.setComponentError(null); updateLabel(); } catch (Exception e) { @@ -41,7 +40,7 @@ public class Ticket2090 extends Application { width.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { try { - target.setWidth(width.toString()); + target.setWidth(width.getValue()); width.setComponentError(null); updateLabel(); } catch (Exception e) { @@ -54,9 +53,8 @@ public class Ticket2090 extends Application { private void updateLabel() { label.setValue("width: " + target.getWidth() - + Sizeable.UNIT_SYMBOLS[target.getWidthUnits()] + ", height: " - + target.getHeight() - + Sizeable.UNIT_SYMBOLS[target.getHeightUnits()]); + + target.getWidthUnits().getSymbol() + ", height: " + + target.getHeight() + target.getHeightUnits().getSymbol()); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2095.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2095.java index 42486748d2..a27ae7ac4d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2095.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2095.java @@ -3,13 +3,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Embedded; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2095 extends Application { +public class Ticket2095 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // uncomment to workaround iorderedlayout bug in current trunk diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2098.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2098.java index 4d02862e4b..5dc741eff6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2098.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2098.java @@ -2,23 +2,23 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; -import com.vaadin.ui.Window; -public class Ticket2098 extends Application { +public class Ticket2098 extends Application.LegacyApplication { private static final String info = "First tab hidden, second should initially be selected"; @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); w.addComponent(new Label(info)); createUI(w); } - private void createUI(Window w) { + private void createUI(LegacyWindow w) { TabSheet ts = new TabSheet(); Label l1 = new Label("111"); Label l2 = new Label("222"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2099.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2099.java index d0021ae75f..6278f7d4df 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2099.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2099.java @@ -6,11 +6,12 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; -public class Ticket2099 extends Application { +public class Ticket2099 extends Application.LegacyApplication { private Label l1, l2, l3; private VerticalLayout ol1, ol2, ol3; @@ -18,7 +19,7 @@ public class Ticket2099 extends Application { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout layout = new GridLayout(10, 10); @@ -36,7 +37,7 @@ public class Ticket2099 extends Application { }); popup = createPopup(); - addWindow(popup); + getMainWindow().addWindow(popup); layout.addComponent(b); layout.addComponent(new Button("Hide label '222'", new ClickListener() { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2101.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2101.java index 7d3412bfd8..67c3c9f331 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2101.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2101.java @@ -2,13 +2,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2101 extends Application { +public class Ticket2101 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); Button b = new Button( diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2103.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2103.java index d65f4c1aec..1fb89eebc4 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2103.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2103.java @@ -5,16 +5,16 @@ import com.vaadin.data.Item; import com.vaadin.data.util.HierarchicalContainer; import com.vaadin.ui.Accordion; import com.vaadin.ui.Component; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2103 extends Application { - private Window mainWindow; +public class Ticket2103 extends Application.LegacyApplication { + private LegacyWindow mainWindow; @Override public void init() { - mainWindow = new Window(getClass().getSimpleName()); + mainWindow = new LegacyWindow(getClass().getSimpleName()); mainWindow.setContent(new VerticalLayout()); mainWindow.setSizeFull(); mainWindow.getContent().setSizeFull(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2104.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2104.java index 8b95fa35a2..4637b71fb4 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2104.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2104.java @@ -1,31 +1,32 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.util.MethodProperty; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.terminal.ExternalResource; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CheckBox; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.Tree; -import com.vaadin.ui.Window; -public class Ticket2104 extends Application { +public class Ticket2104 extends Application.LegacyApplication { private static final Label info = new Label( "Click event should _always_ come trough. Switching features on/off should immediatly affect the tree (verify w/ debug window)", - Label.CONTENT_RAW); + ContentMode.RAW); Tree tree = new Tree(); Table table = new Table(); @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); main.addComponent(info); @@ -48,8 +49,10 @@ public class Ticket2104 extends Application { "multiSelect")); cb.setImmediate(true); ol.addComponent(cb); - cb = new CheckBox("icon", new Button.ClickListener() { - public void buttonClick(ClickEvent event) { + cb = new CheckBox("icon"); + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { if (tree.getItemIconPropertyId() == null) { tree.setItemIconPropertyId("icon"); } else { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2106.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2106.java index 92908aa66d..0776f6c4a6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2106.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2106.java @@ -6,9 +6,9 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2106 extends Application { +public class Ticket2106 extends Application.LegacyApplication { private static CustomizedSystemMessages msgs = new Application.CustomizedSystemMessages(); static { @@ -24,7 +24,7 @@ public class Ticket2106 extends Application { @Override public void init() { - setMainWindow(new Window("#2106")); + setMainWindow(new LegacyWindow("#2106")); getMainWindow().addComponent( new Button("Do nothing", new Button.ClickListener() { public void buttonClick(ClickEvent event) { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2107.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2107.java index 199b278343..57926143eb 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2107.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2107.java @@ -5,15 +5,15 @@ import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Validator; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -import com.vaadin.ui.Window.Notification; -public class Ticket2107 extends Application { +public class Ticket2107 extends Application.LegacyApplication { @Override public void init() { - final Window w = new Window("Testing for #2107"); + final LegacyWindow w = new LegacyWindow("Testing for #2107"); setMainWindow(w); final TextField tf = new TextField( @@ -31,12 +31,8 @@ public class Ticket2107 extends Application { }); tf.addValidator(new Validator() { - public boolean isValid(Object value) { - return value != null && value.toString().length() > 3; - } - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { + if (value == null || value.toString().length() <= 3) { throw new InvalidValueException( "Text length must exceed 3 characters"); } @@ -51,7 +47,7 @@ public class Ticket2107 extends Application { b.setImmediate(true); b.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - tf.setRequiredError(b.booleanValue() ? "Field must not be empty" + tf.setRequiredError(b.getValue() ? "Field must not be empty" : null); } }); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2117.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2117.java index 974b3c4572..82241843df 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2117.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2117.java @@ -6,9 +6,10 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2117 extends Application { +public class Ticket2117 extends Application.LegacyApplication { @Override public void init() { @@ -16,10 +17,10 @@ public class Ticket2117 extends Application { } @Override - public Window getWindow(String name) { + public LegacyWindow getWindow(String name) { // If we already have the requested window, use it - Window w = super.getWindow(name); + LegacyWindow w = super.getWindow(name); if (w == null) { // If no window found, create it @@ -29,8 +30,8 @@ public class Ticket2117 extends Application { return w; } - private Window createExtraWindow(String name) { - final Window w = new Window("Extra window: " + name); + private LegacyWindow createExtraWindow(String name) { + final LegacyWindow w = new LegacyWindow("Extra window: " + name); w.setName(name); addWindow(w); w.addComponent(new Label( @@ -46,15 +47,15 @@ public class Ticket2117 extends Application { return w; } - private Window createWindow() { - final Window w = new Window(); + private LegacyWindow createWindow() { + final LegacyWindow w = new LegacyWindow(); w.addComponent(new Label( "Click this link: <a target=\"_blank\" href='" + getURL().toExternalForm() + "'>" + getURL().toExternalForm() + "</a> which opens new windows to this uri. They should end up having a separate Window and URL.", - Label.CONTENT_XHTML)); + ContentMode.XHTML)); return w; } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2119.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2119.java index c1e0d64dde..b7dc84b8ab 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2119.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2119.java @@ -6,32 +6,33 @@ import com.vaadin.data.util.ObjectProperty; import com.vaadin.terminal.ExternalResource; import com.vaadin.ui.Button; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; /** * Test case for Ticket 2119. */ -public class Ticket2119 extends Application { +public class Ticket2119 extends Application.LegacyApplication { private ObjectProperty<String> globalValue; @Override public void init() { globalValue = new ObjectProperty<String>(null, String.class); - Window main = createWindow(); + LegacyWindow main = createWindow(); setMainWindow(main); } @Override - public Window getWindow(String name) { + public LegacyWindow getWindow(String name) { if (!isRunning()) { return null; } // If we already have the requested window, use it - Window w = super.getWindow(name); + LegacyWindow w = super.getWindow(name); if (w == null) { // If no window found, create it w = createWindow(); @@ -41,8 +42,8 @@ public class Ticket2119 extends Application { return w; } - private Window createWindow() { - Window main = new Window("Test for ticket XXX"); + private LegacyWindow createWindow() { + LegacyWindow main = new LegacyWindow("Test for ticket XXX"); main.setContent(testLayout()); return main; } @@ -56,7 +57,7 @@ public class Ticket2119 extends Application { + " - Go to the second Window\n" + " - Click the arrow in the Select\n" + " --> The opened list correctly shows the new value but the old one is shown in the \"input\" part"); - label.setContentMode(Label.CONTENT_PREFORMATTED); + label.setContentMode(ContentMode.PREFORMATTED); layout.addComponent(label); final Select select = new Select("Test Select"); @@ -74,7 +75,9 @@ public class Ticket2119 extends Application { globalValue.addListener(new Property.ValueChangeListener() { public void valueChange(Property.ValueChangeEvent event) { - valueProperty.setValue(event.getProperty().getValue()); + Object value = event.getProperty().getValue(); + valueProperty.setValue((null != value) ? value.toString() + : null); } }); @@ -89,4 +92,4 @@ public class Ticket2119 extends Application { return layout; } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2125.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2125.java index b296a4ff46..cc81c787b2 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2125.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2125.java @@ -5,12 +5,12 @@ import com.vaadin.data.util.MethodProperty; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Component; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.Table.CellStyleGenerator; import com.vaadin.ui.Table.ColumnGenerator; -import com.vaadin.ui.Window; -public class Ticket2125 extends Application { +public class Ticket2125 extends Application.LegacyApplication { @Override public void init() { @@ -18,7 +18,7 @@ public class Ticket2125 extends Application { } - class MainWindow extends Window { + class MainWindow extends LegacyWindow { MainWindow(String caption) { super(caption); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2126.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2126.java index 4de873a7fc..abcca6d59c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2126.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2126.java @@ -5,8 +5,8 @@ import com.vaadin.data.util.IndexedContainer; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; /** * @@ -14,9 +14,9 @@ import com.vaadin.ui.Window; * client. * */ -public class Ticket2126 extends com.vaadin.Application { +public class Ticket2126 extends com.vaadin.Application.LegacyApplication { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); Table table = new Table(); @Override diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2151.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2151.java index 5a48156367..c2fbe1b4f7 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2151.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2151.java @@ -2,19 +2,21 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.data.util.ObjectProperty; +import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.AbstractField; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Button; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2151 extends Application { +public class Ticket2151 extends Application.LegacyApplication { private Label status; @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); @@ -38,30 +40,21 @@ public class Ticket2151 extends Application { layout.addComponent(new Label("b")); layout.addComponent(new Label("c")); - check(Button.class); - check(CheckBox.class); - checkDataBinding(Button.class); + checkButton(Button.class); + checkCheckBox(CheckBox.class); checkDataBinding(CheckBox.class); } - private void check(Class<? extends Button> class1) { + private void checkButton(Class<? extends Button> class1) { boolean ok = false; - Button b; + AbstractComponent b; try { b = class1.newInstance(); b.setCaption("Button of type " + class1.getSimpleName()); - try { - // This should throw an exception - b.setValue("ON"); - } catch (IllegalArgumentException e) { - ok = true; - } catch (Exception e) { - e.printStackTrace(); - } + ok = true; } catch (Exception e1) { e1.printStackTrace(); - return; } if (ok) { @@ -74,15 +67,30 @@ public class Ticket2151 extends Application { } - private void checkDataBinding(Class<? extends Button> class1) { + private void checkCheckBox(Class<? extends CheckBox> class1) { + boolean ok = false; + CheckBox b; + try { + b = class1.newInstance(); + } catch (Exception e1) { + e1.printStackTrace(); + return; + } + + b.setCaption("Button of type " + class1.getSimpleName()); + status.setValue(status.getValue() + " " + + class1.getClass().getSimpleName() + ": OK"); + + } + + private void checkDataBinding(Class<? extends AbstractField> class1) { boolean ok = false; - Button b; + AbstractField b; try { b = class1.newInstance(); b.setCaption("Button of type " + class1.getSimpleName()); try { - b.setWriteThrough(true); - b.setReadThrough(true); + b.setBuffered(false); ObjectProperty<String> prop = new ObjectProperty<String>( "ABC 123"); /* diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2157.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2157.java index 3d90907e50..23c5b0bcd5 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2157.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2157.java @@ -4,14 +4,14 @@ import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2157 extends Application { +public class Ticket2157 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2178.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2178.java index a3461dd8b6..6de42003b4 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2178.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2178.java @@ -4,14 +4,14 @@ import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2178 extends Application { +public class Ticket2178 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2179.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2179.java index 165e770307..ba4dd2ee46 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2179.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2179.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Validator; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2179 extends Application { +public class Ticket2179 extends Application.LegacyApplication { TextField f = new TextField("Test fiel ( must contain 1 & 2 )"); - Window main = new Window("Dual validator test"); + LegacyWindow main = new LegacyWindow("Dual validator test"); @Override public void init() { @@ -33,19 +33,15 @@ public class Ticket2179 extends Application { } - class ContainsValidator implements Validator { + static class ContainsValidator implements Validator { private final String c; public ContainsValidator(String c) { this.c = c; } - public boolean isValid(Object value) { - return value != null && value.toString().contains(c); - } - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { + if (value == null || !value.toString().contains(c)) { throw new InvalidValueException("Value does not contain " + c); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2180.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2180.java index 9f5e2a2de1..7b993cdf24 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2180.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2180.java @@ -3,17 +3,17 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; -import com.vaadin.ui.Window; -public class Ticket2180 extends Application { +public class Ticket2180 extends Application.LegacyApplication { - private Window mainWindow; + private LegacyWindow mainWindow; private TabSheet tabSheet; @Override public void init() { - mainWindow = new Window("Tabsheet should cause scrollbars"); + mainWindow = new LegacyWindow("Tabsheet should cause scrollbars"); setMainWindow(mainWindow); // mainWindow.getLayout().setSizeFull(); tabSheet = new TabSheet(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2181.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2181.java index ea3d996b98..c3219102f6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2181.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2181.java @@ -12,17 +12,18 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.OptionGroup; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2181 extends Application implements Button.ClickListener { +public class Ticket2181 extends Application.LegacyApplication implements + Button.ClickListener { // private static final Object PROPERTY_VALUE = new Object(); // private static final Object PROPERTY_CAPTION = new Object(); private static final String caption = "This is a caption which is very long and nice and perhaps sometimes should be clipped"; - Window main = new Window("#2181 test"); + LegacyWindow main = new LegacyWindow("#2181 test"); TextField tf1 = new TextField(caption, "Test field - undefined width"); TextField tf2 = new TextField(caption, "Test field - 150px wide"); Button setButton = new Button("Set", this); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2186.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2186.java index bc9ff8c27d..b7817d2ed7 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2186.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2186.java @@ -4,15 +4,15 @@ import com.vaadin.Application; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2186 extends Application { +public class Ticket2186 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window("Quick test"); + LegacyWindow main = new LegacyWindow("Quick test"); setMainWindow(main); HorizontalLayout base = new HorizontalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2204.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2204.java index 6a047cb626..eef13ca06c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2204.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2204.java @@ -26,12 +26,12 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; import com.vaadin.ui.RichTextArea; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; -public class Ticket2204 extends Application { +public class Ticket2204 extends Application.LegacyApplication { private final List<RichTextArea> textAreas = new ArrayList<RichTextArea>(); private TabSheet ts; @@ -52,7 +52,7 @@ public class Ticket2204 extends Application { classes.add(HorizontalSplitPanel.class); classes.add(Form.class); - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); @@ -128,7 +128,7 @@ public class Ticket2204 extends Application { Form f = (Form) cc; f.setFormFieldFactory(new FormFieldFactory() { - public Field createField(Item item, Object propertyId, + public Field<?> createField(Item item, Object propertyId, Component uiContext) { formTextArea = new RichTextArea(); formTextArea.setVisible(false); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2208.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2208.java index ff3d9e6ca1..ada9471f18 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2208.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2208.java @@ -4,18 +4,18 @@ import com.vaadin.Application; import com.vaadin.data.Item; import com.vaadin.ui.Component; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.Table.CellStyleGenerator; import com.vaadin.ui.Table.ColumnGenerator; -import com.vaadin.ui.Window; -public class Ticket2208 extends Application { +public class Ticket2208 extends Application.LegacyApplication { private Table t; @Override public void init() { - Window mainWindow = new Window(); + LegacyWindow mainWindow = new LegacyWindow(); setMainWindow(mainWindow); t = new Table("A table"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2209.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2209.java index c6b30fa52f..5ba69895b6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2209.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2209.java @@ -7,9 +7,9 @@ import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.ComboBox; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2209 extends Application { +public class Ticket2209 extends Application.LegacyApplication { private GridLayout gl; private ComboBox combo; @@ -17,7 +17,7 @@ public class Ticket2209 extends Application { @Override public void init() { - setMainWindow(new Window()); + setMainWindow(new LegacyWindow()); gl = new GridLayout(1, 2); gl.setStyleName("borders"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL.java index c7305bd0fb..4a45709ef6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL.java @@ -6,10 +6,10 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2209OL extends Application { +public class Ticket2209OL extends Application.LegacyApplication { private VerticalLayout gl; private ComboBox combo; @@ -17,7 +17,7 @@ public class Ticket2209OL extends Application { @Override public void init() { - setMainWindow(new Window()); + setMainWindow(new LegacyWindow()); getMainWindow().getContent().setWidth("250px"); gl = new VerticalLayout(); gl.setStyleName("borders"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL2.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL2.java index d7385562cd..e2e51d8101 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL2.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2209OL2.java @@ -6,10 +6,10 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.ComboBox; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2209OL2 extends Application { +public class Ticket2209OL2 extends Application.LegacyApplication { private VerticalLayout gl; private ComboBox combo; @@ -17,7 +17,7 @@ public class Ticket2209OL2 extends Application { @Override public void init() { - setMainWindow(new Window()); + setMainWindow(new LegacyWindow()); getMainWindow().getContent().setWidth("250px"); gl = new VerticalLayout(); gl.setSizeUndefined(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2215.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2215.java index 62ed69e433..5b98fe3af3 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2215.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2215.java @@ -3,15 +3,15 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; import com.vaadin.ui.themes.Reindeer; -public class Ticket2215 extends Application { +public class Ticket2215 extends Application.LegacyApplication { @Override public void init() { - setMainWindow(new Window()); + setMainWindow(new LegacyWindow()); VerticalLayout ol = new VerticalLayout(); Panel p = new Panel("Test"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2221.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2221.java index e6489da432..2b7d5ef6d1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2221.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2221.java @@ -9,15 +9,15 @@ import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Layout; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2221 extends Application { +public class Ticket2221 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2222.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2222.java index 86dccede69..51ac463a6e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2222.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2222.java @@ -5,14 +5,14 @@ import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2222 extends Application { +public class Ticket2222 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2227OrderedlayoutInTable.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2227OrderedlayoutInTable.java index c93b26bec2..e436bab283 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2227OrderedlayoutInTable.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2227OrderedlayoutInTable.java @@ -5,15 +5,16 @@ import com.vaadin.data.Item; import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2227OrderedlayoutInTable extends Application { +public class Ticket2227OrderedlayoutInTable extends + Application.LegacyApplication { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); Table t = new Table(); t.setWidth("500px"); t.setHeight("200px"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2231.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2231.java index ba12dd7abc..ab0cc82628 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2231.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2231.java @@ -3,13 +3,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2231 extends Application { +public class Ticket2231 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2232.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2232.java index ab4e83f0ba..ae8a4b0f51 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2232.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2232.java @@ -6,14 +6,14 @@ import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Layout.SpacingHandler; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2232 extends Application { +public class Ticket2232 extends Application.LegacyApplication { @Override public void init() { - setMainWindow(new Window()); + setMainWindow(new LegacyWindow()); setTheme("tests-tickets"); getMainWindow() diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2234.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2234.java index 5c6167fbfe..24a6d2ea77 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2234.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2234.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.data.Item; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.ComboBox; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2234 extends Application { +public class Ticket2234 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2235.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2235.java index 72a77e502e..10978cad30 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2235.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2235.java @@ -2,14 +2,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextArea; -import com.vaadin.ui.Window; -public class Ticket2235 extends Application { +public class Ticket2235 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2240.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2240.java index 6d70d89af8..bf01475809 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2240.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2240.java @@ -3,10 +3,11 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2240 extends Application { +public class Ticket2240 extends Application.LegacyApplication { public static final String txt = "<p>There are two main types of windows: application-level windows, and " + "\"sub windows\".</p><p>A sub window is rendered as a \"inline\" popup window" @@ -25,7 +26,7 @@ public class Ticket2240 extends Application { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); @@ -36,7 +37,7 @@ public class Ticket2240 extends Application { layout.setStyleName("borders"); // layout.setSizeFull(); final Label l = new Label(txt); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); // l.setWidth("100%"); TextField tf = new TextField("This is a textField"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2242.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2242.java index fa25ff55f1..15b2b630a5 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2242.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2242.java @@ -10,10 +10,11 @@ import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class Ticket2242 extends Application implements ValueChangeListener { +public class Ticket2242 extends Application.LegacyApplication implements + ValueChangeListener { private Object tableValue = null; private Table t; @@ -22,7 +23,7 @@ public class Ticket2242 extends Application implements ValueChangeListener { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2244.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2244.java index e9ae3ac720..8540960b30 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2244.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2244.java @@ -8,15 +8,15 @@ import com.vaadin.ui.Form; import com.vaadin.ui.FormLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2244 extends Application { +public class Ticket2244 extends Application.LegacyApplication { Form form; @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); GridLayout gl = new GridLayout(3, 3); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2245.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2245.java index bac85c95cd..1586a1966b 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2245.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2245.java @@ -2,13 +2,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.HorizontalSplitPanel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2245 extends Application { +public class Ticket2245 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window("The Main Window"); + LegacyWindow main = new LegacyWindow("The Main Window"); main.getContent().setSizeFull(); setMainWindow(main); HorizontalSplitPanel sp = new HorizontalSplitPanel(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2267.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2267.java index 020ea5c7c6..cf1d2f64d2 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2267.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2267.java @@ -6,15 +6,15 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2267 extends Application { +public class Ticket2267 extends Application.LegacyApplication { Label l = new Label("0"); @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); GridLayout gl = new GridLayout(4, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2271.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2271.java index 50a99edb7a..fb281f22b2 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2271.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2271.java @@ -4,14 +4,14 @@ import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Button; import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2271 extends Application { +public class Ticket2271 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2279.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2279.java deleted file mode 100644 index e3b446f242..0000000000 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2279.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.vaadin.tests.tickets; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.vaadin.Application; -import com.vaadin.terminal.gwt.client.ui.AlignmentInfo; -import com.vaadin.ui.AbstractOrderedLayout; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.Label; -import com.vaadin.ui.Layout; -import com.vaadin.ui.Layout.AlignmentHandler; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; - -// This tests the deprecated setComponentAlignment(Component,String) API -@SuppressWarnings("deprecation") -public class Ticket2279 extends Application { - - private Label label; - - private static Map<String, Integer> expected = new HashMap<String, Integer>(); - - private static Set<String> longHorizontalAlignments = new HashSet<String>(); - private static Set<String> shortHorizontalAlignments = new HashSet<String>(); - private static Set<String> longVerticalAlignments = new HashSet<String>(); - private static Set<String> shortVerticalAlignments = new HashSet<String>(); - - static { - expected.put("r", AlignmentInfo.Bits.ALIGNMENT_RIGHT); - expected.put("l", AlignmentInfo.Bits.ALIGNMENT_LEFT); - expected.put("c", AlignmentInfo.Bits.ALIGNMENT_HORIZONTAL_CENTER); - expected.put("t", AlignmentInfo.Bits.ALIGNMENT_TOP); - expected.put("b", AlignmentInfo.Bits.ALIGNMENT_BOTTOM); - expected.put("m", AlignmentInfo.Bits.ALIGNMENT_VERTICAL_CENTER); - - expected.put("right", AlignmentInfo.Bits.ALIGNMENT_RIGHT); - expected.put("left", AlignmentInfo.Bits.ALIGNMENT_LEFT); - expected.put("center", AlignmentInfo.Bits.ALIGNMENT_HORIZONTAL_CENTER); - expected.put("top", AlignmentInfo.Bits.ALIGNMENT_TOP); - expected.put("bottom", AlignmentInfo.Bits.ALIGNMENT_BOTTOM); - expected.put("middle", AlignmentInfo.Bits.ALIGNMENT_VERTICAL_CENTER); - - shortHorizontalAlignments.add("r"); - shortHorizontalAlignments.add("l"); - shortHorizontalAlignments.add("c"); - shortVerticalAlignments.add("t"); - shortVerticalAlignments.add("b"); - shortVerticalAlignments.add("m"); - - longHorizontalAlignments.add("right"); - longHorizontalAlignments.add("left"); - longHorizontalAlignments.add("center"); - longVerticalAlignments.add("top"); - longVerticalAlignments.add("bottom"); - longVerticalAlignments.add("middle"); - - } - - @Override - public void init() { - Window w = new Window(getClass().getSimpleName()); - setMainWindow(w); - setTheme("tests-tickets"); - AbstractOrderedLayout layout = (AbstractOrderedLayout) w.getContent(); - - createUI(layout); - } - - private void createUI(Layout layout) { - VerticalLayout vl = new VerticalLayout(); - vl.setWidth("500px"); - vl.setHeight("500px"); - vl.setStyleName("borders"); - label = new Label("<b>Error messages follows:</b><br/>", - Label.CONTENT_XHTML); - vl.addComponent(label); - layout.addComponent(vl); - - testAlignments(vl); - - GridLayout gl = new GridLayout(1, 1); - gl.setWidth("500px"); - gl.setHeight("500px"); - gl.setStyleName("borders"); - label = new Label("<b>Error messages follows:</b><br/>", - Label.CONTENT_XHTML); - gl.addComponent(label); - layout.addComponent(gl); - - testAlignments(gl); - - } - - private void testAlignments(AlignmentHandler layout) { - HashSet<String> horizontals = new HashSet<String>(); - horizontals.addAll(shortHorizontalAlignments); - horizontals.addAll(longHorizontalAlignments); - - for (String horiz : horizontals) { - // Test "l","r","left","right" etc - int expectedHoriz = expected.get(horiz); - checkAlignment(layout, horiz, AlignmentHandler.ALIGNMENT_TOP - | expectedHoriz); - - for (String vert : shortVerticalAlignments) { - int expectedVert = expected.get(vert); - - // Test "lt","rt" etc - if (horiz.length() == 1) { - checkAlignment(layout, horiz + vert, expectedHoriz - | expectedVert); - checkAlignment(layout, vert + horiz, expectedHoriz - | expectedVert); - } else { - boolean ok = false; - try { - checkAlignment(layout, horiz + vert, expectedHoriz - | expectedVert); - } catch (IllegalArgumentException e) { - // OK, "centert","rightb" etc are not valid - ok = true; - } - if (!ok) { - error("IllegalArgumentException was not thrown for " - + horiz + vert); - } - ok = false; - try { - checkAlignment(layout, vert + horiz, expectedHoriz - | expectedVert); - } catch (IllegalArgumentException e) { - // OK, "centert","rightb" etc are not valid - ok = true; - } - if (!ok) { - error("IllegalArgumentException was not thrown for " - + horiz + vert); - } - - } - - // Test "l t","r t" etc - checkAlignment(layout, horiz + " " + vert, expectedHoriz - | expectedVert); - checkAlignment(layout, vert + " " + horiz, expectedHoriz - | expectedVert); - } - - for (String vert : longVerticalAlignments) { - int expectedVert = expected.get(vert); - - // Test "right t","right b" etc - checkAlignment(layout, horiz + " " + vert, expectedHoriz - | expectedVert); - checkAlignment(layout, vert + " " + horiz, expectedHoriz - | expectedVert); - - // Three alignments should throw an exception - boolean ok = false; - try { - checkAlignment(layout, horiz + " " + vert + " " + horiz, - expectedHoriz | expectedVert); - } catch (IllegalArgumentException e) { - // OK, "centert","rightb" etc are not valid - ok = true; - } - if (!ok) { - error("IllegalArgumentException was not thrown for " - + horiz + " " + vert + " " + horiz); - } - } - } - - checkAlignment(layout, "left right", AlignmentHandler.ALIGNMENT_TOP - | AlignmentHandler.ALIGNMENT_RIGHT); - } - - private void checkAlignment(AlignmentHandler layout, - String alignmentString, int expected) { - layout.setComponentAlignment(label, AlignmentInfo.Bits.ALIGNMENT_TOP, - AlignmentInfo.Bits.ALIGNMENT_LEFT); - if (layout instanceof AbstractOrderedLayout) { - ((AbstractOrderedLayout) layout).setComponentAlignment(label, - alignmentString); - } else { - ((GridLayout) layout).setComponentAlignment(label, alignmentString); - } - - int actual = layout.getComponentAlignment(label).getBitMask(); - if (actual != expected) { - String error = "Error " + alignmentString - + " did not produce expected results"; - error(error); - } else { - String str = layout.getClass().getSimpleName() + "/" - + alignmentString + ": OK"; - System.out.println(str); - } - - } - - private void error(String error) { - label.setValue(label.getValue() + error + "<br/>"); - System.out.println(error); - } -} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2282.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2282.java index c63faf2cef..67fe3f9846 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2282.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2282.java @@ -5,16 +5,16 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.FormLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2282 extends Application { +public class Ticket2282 extends Application.LegacyApplication { private FormLayout layout1; private FormLayout layout2; @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); w.getContent().setSizeUndefined(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2283.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2283.java index 89b90eaa01..8375ca648f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2283.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2283.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.ui.Alignment; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2283 extends Application { +public class Ticket2283 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); GridLayout gl = new GridLayout(2, 2); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2287.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2287.java index 0942877947..66328fa4b9 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2287.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2287.java @@ -3,27 +3,28 @@ package com.vaadin.tests.tickets; import java.net.URL; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; public class Ticket2287 extends Ticket2292 { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); URL url = getURL(); main.addComponent(new Label( "Icon is built by servlet with a slow method, so it will show the bug (components not firing requestLayout).")); Label l = new Label(); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); l.setValue("This is a label with as slow image. <img src=\"" + url + "/icon.png\" />"); main.addComponent(l); l = new Label(); - l.setContentMode(Label.CONTENT_XHTML); + l.setContentMode(ContentMode.XHTML); l.setValue("This is a label with as slow image. <img src=\"" + url + "/icon.png\" />"); main.addComponent(l); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2289.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2289.java index 19574b50fb..4cd421e30d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2289.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2289.java @@ -7,11 +7,11 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2289 extends Application { +public class Ticket2289 extends Application.LegacyApplication { TabSheet ts = null; Accordion acc = null; @@ -19,7 +19,7 @@ public class Ticket2289 extends Application { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); VerticalLayout ol = new VerticalLayout(); w.setContent(ol); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2292.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2292.java index 8ddc6519f7..a413e87110 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2292.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2292.java @@ -6,24 +6,28 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.net.URL; import javax.imageio.ImageIO; +import com.vaadin.Application; import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.ExternalResource; +import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.WrappedRequest; +import com.vaadin.terminal.WrappedResponse; import com.vaadin.ui.Button; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Label; import com.vaadin.ui.Link; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2292 extends com.vaadin.Application { +public class Ticket2292 extends com.vaadin.Application.LegacyApplication + implements RequestHandler { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); ExternalResource icon = new ExternalResource("./icon.png"); @@ -40,12 +44,16 @@ public class Ticket2292 extends com.vaadin.Application { Link l = new Link("l", icon); main.addComponent(l); + addRequestHandler(this); } - @Override - public DownloadStream handleURI(URL context, String relativeUri) { + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + String relativeUri = request.getRequestPathInfo(); + if (!relativeUri.contains("icon.png")) { - return null; + return false; } // be slow to show bug @@ -78,9 +86,10 @@ public class Ticket2292 extends com.vaadin.Application { // Return a stream from the buffer. ByteArrayInputStream istream = new ByteArrayInputStream( imagebuffer.toByteArray()); - return new DownloadStream(istream, null, null); + new DownloadStream(istream, null, null).writeTo(response); + return true; } catch (IOException e) { - return null; + return false; } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2294.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2294.java index 37c29ca5e0..30392a245d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2294.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2294.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Alignment; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2294 extends Application { +public class Ticket2294 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((AbstractOrderedLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2296.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2296.java index 1503811341..31ff4a8353 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2296.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2296.java @@ -3,13 +3,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.CustomLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2296 extends Application { +public class Ticket2296 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); CustomLayout cl = new CustomLayout("Ticket2296"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2297.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2297.java index 8b425af136..1d1f0f1d74 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2297.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2297.java @@ -6,14 +6,14 @@ import java.net.URL; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; public class Ticket2297 extends Ticket2292 { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); URL url = getURL(); main.addComponent(new Label( diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2303.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2303.java index 3b8864bccc..bc11a7ea49 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2303.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2303.java @@ -6,14 +6,14 @@ import java.io.IOException; import com.vaadin.Application; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2303 extends Application { +public class Ticket2303 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window("main window"); + LegacyWindow w = new LegacyWindow("main window"); String customlayout = "<div location=\"test\"></div>"; CustomLayout cl = null; diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2304.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2304.java index 1b356c73fb..9484b4865f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2304.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2304.java @@ -2,16 +2,17 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.themes.Reindeer; -public class Ticket2304 extends Application { +public class Ticket2304 extends Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); Panel p = new Panel(); @@ -21,7 +22,7 @@ public class Ticket2304 extends Application { Label l = new Label( "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"); - l.setContentMode(Label.CONTENT_PREFORMATTED); + l.setContentMode(ContentMode.PREFORMATTED); p.addComponent(l); main.addComponent(new Label( "This text should be right below the panel, w/o spacing")); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2310.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2310.java index 6363fddcaf..36bda7095c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2310.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2310.java @@ -5,15 +5,15 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.themes.Reindeer; -public class Ticket2310 extends Application { +public class Ticket2310 extends Application.LegacyApplication { @Override public void init() { - final Window main = new Window(getClass().getName().substring( - getClass().getName().lastIndexOf(".") + 1)); + final LegacyWindow main = new LegacyWindow(getClass().getName() + .substring(getClass().getName().lastIndexOf(".") + 1)); setMainWindow(main); main.addComponent(new Label("Instructions: change label when panel is " diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2319.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2319.java index b8a2ba8db8..ec6d3be801 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2319.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2319.java @@ -6,15 +6,15 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; -public class Ticket2319 extends Application { +public class Ticket2319 extends Application.LegacyApplication { @Override public void init() { - Window mainw = new Window(); + LegacyWindow mainw = new LegacyWindow(); setMainWindow(mainw); mainw.addComponent(new Label( diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2323.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2323.java index 503878ecad..123c154e61 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2323.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2323.java @@ -2,13 +2,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.RichTextArea; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; -public class Ticket2323 extends Application { +public class Ticket2323 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); Window subWindow = new Window(""); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2325.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2325.java index 1245254fa0..c253eb70e6 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2325.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2325.java @@ -1,15 +1,16 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextArea; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; -public class Ticket2325 extends Application { +public class Ticket2325 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window("Testing...."); + LegacyWindow main = new LegacyWindow("Testing...."); setMainWindow(main); final VerticalLayout lo = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2329.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2329.java index 57dbeb4033..f1906d1492 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2329.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2329.java @@ -3,18 +3,18 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.Table.ColumnGenerator; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2329 extends Application { +public class Ticket2329 extends Application.LegacyApplication { private Table table; private VerticalLayout mainLo; @Override public void init() { - Window mainw = new Window(); + LegacyWindow mainw = new LegacyWindow(); setMainWindow(mainw); mainLo = (VerticalLayout) mainw.getContent(); table = new Table(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2337.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2337.java index 9277a01f96..f71492a96b 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2337.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2337.java @@ -5,15 +5,15 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.GridLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2337 extends Application { +public class Ticket2337 extends Application.LegacyApplication { GridLayout gl = new GridLayout(3, 1); @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); Button b = new Button("add", new Button.ClickListener() { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2339.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2339.java index 6476807ada..81dc3af40f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2339.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2339.java @@ -6,14 +6,15 @@ import java.io.IOException; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.CustomLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2339 extends Application { +public class Ticket2339 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window(getClass().getSimpleName()); + final LegacyWindow mainWin = new LegacyWindow(getClass() + .getSimpleName()); setMainWindow(mainWin); try { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2341.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2341.java index d7fbccfa4e..a35c27962f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2341.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2341.java @@ -3,13 +3,13 @@ package com.vaadin.tests.tickets; import com.vaadin.data.Item; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class Ticket2341 extends com.vaadin.Application { +public class Ticket2341 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); constructTables((Layout) main.getContent()); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2344.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2344.java index 26ef216940..d7b1eacd2c 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2344.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2344.java @@ -4,16 +4,16 @@ import java.util.Random; import com.vaadin.Application; import com.vaadin.ui.Button; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; import com.vaadin.ui.themes.BaseTheme; -public class Ticket2344 extends Application { +public class Ticket2344 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window("Quick test"); + LegacyWindow main = new LegacyWindow("Quick test"); setMainWindow(main); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2347.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2347.java index 76e59146db..207d6ee413 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2347.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2347.java @@ -5,16 +5,16 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CustomLayout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2347 extends Application { +public class Ticket2347 extends Application.LegacyApplication { private Button b1; @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); setTheme("tests-tickets"); createUI((VerticalLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2364.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2364.java index 7f7290dd80..8039609339 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2364.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2364.java @@ -2,16 +2,16 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Form; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Select; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2364 extends Application { +public class Ticket2364 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window("The Main Window!!!"); + LegacyWindow main = new LegacyWindow("The Main Window!!!"); setMainWindow(main); Form form = new Form(); VerticalLayout formLayout = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2365.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2365.java index 0c8a095ec9..19d473f970 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2365.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2365.java @@ -4,15 +4,16 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2365 extends Application { +public class Ticket2365 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window(getClass().getSimpleName()); + final LegacyWindow mainWin = new LegacyWindow(getClass() + .getSimpleName()); setMainWindow(mainWin); VerticalLayout lo = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2398.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2398.java index dee0417eff..054cc5f0cc 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2398.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2398.java @@ -3,15 +3,15 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.data.util.IndexedContainer; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class Ticket2398 extends Application { +public class Ticket2398 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window(); + final LegacyWindow mainWin = new LegacyWindow(); setMainWindow(mainWin); Table t = new Table(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2404.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2404.java index 478d8b7786..0da70301d1 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2404.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2404.java @@ -3,9 +3,9 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.GridLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2404 extends Application { +public class Ticket2404 extends Application.LegacyApplication { @Override public void init() { @@ -22,7 +22,7 @@ public class Ticket2404 extends Application { b.setSizeFull(); } - setMainWindow(new Window("GridLayout test", gl)); + setMainWindow(new LegacyWindow("GridLayout test", gl)); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2405.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2405.java index 9ab0d851ad..16a552e37a 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2405.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2405.java @@ -9,11 +9,11 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2405 extends Application { +public class Ticket2405 extends Application.LegacyApplication { private Label label; private HorizontalSplitPanel split; @@ -21,10 +21,9 @@ public class Ticket2405 extends Application { @Override public void init() { - final Window root = new Window("VaadinTunes"); + final LegacyWindow root = new LegacyWindow("VaadinTunes"); root.setWidth("90%"); root.setHeight("90%"); - root.center(); // We'll attach the window to the browser view already here, so we won't // forget it later. diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2406.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2406.java index b7c9f902d2..a121d93099 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2406.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2406.java @@ -4,16 +4,17 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; -public class Ticket2406 extends Application { +public class Ticket2406 extends Application.LegacyApplication { private Window w; @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // setTheme("tests-tickets"); createUI((VerticalLayout) w.getContent()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2407.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2407.java index f5ac1dc37f..51ab08188e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2407.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2407.java @@ -1,15 +1,15 @@ package com.vaadin.tests.tickets; import com.vaadin.ui.Form; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket2407 extends com.vaadin.Application { +public class Ticket2407 extends com.vaadin.Application.LegacyApplication { @Override public void init() { - final Window main = new Window("Ticket2407"); + final LegacyWindow main = new LegacyWindow("Ticket2407"); setMainWindow(main); Form form = new Form(new VerticalLayout()); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2411.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2411.java index 01bd4f0651..6801bfa88d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2411.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2411.java @@ -3,13 +3,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.GridLayout; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2411 extends Application { +public class Ticket2411 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); // VerticalLayout l = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2415.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2415.java index 5c1d0c2a51..0514e9bb39 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2415.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2415.java @@ -3,14 +3,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket2415 extends Application { +public class Ticket2415 extends Application.LegacyApplication { @Override public void init() { - final Window main = new Window(""); + final LegacyWindow main = new LegacyWindow(""); setMainWindow(main); final TextField tf = new TextField("Try to change me"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2420.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2420.java index e40d73877c..adca729c9e 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2420.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2420.java @@ -2,16 +2,16 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.ProgressIndicator; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2420 extends Application { +public class Ticket2420 extends Application.LegacyApplication { @Override public void init() { - final Window main = new Window("Hello window"); + final LegacyWindow main = new LegacyWindow("Hello window"); setMainWindow(main); - main.setTheme("tests-tickets"); + setTheme("tests-tickets"); ProgressIndicator pi = new ProgressIndicator(); pi.setCaption("Visible"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2425.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2425.java index 75810137ad..8c9be295a0 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2425.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2425.java @@ -3,14 +3,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TabSheet; -import com.vaadin.ui.Window; -public class Ticket2425 extends Application { +public class Ticket2425 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(getClass().getSimpleName()); + LegacyWindow w = new LegacyWindow(getClass().getSimpleName()); setMainWindow(w); w.addComponent(new Label("No scrollbars should be visible anywhere")); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2426.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2426.java index 90e2ce438d..a979b6711f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2426.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2426.java @@ -2,26 +2,26 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2426 extends Application { +public class Ticket2426 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); final String content = "<select/>"; w.addComponent(new Label("CONTENT_DEFAULT: " + content, - Label.CONTENT_DEFAULT)); + ContentMode.DEFAULT)); w.addComponent(new Label("CONTENT_PREFORMATTED: " + content, - Label.CONTENT_PREFORMATTED)); - w.addComponent(new Label("CONTENT_RAW: " + content, Label.CONTENT_RAW)); - w.addComponent(new Label("CONTENT_TEXT: " + content, Label.CONTENT_TEXT)); - w.addComponent(new Label("CONTENT_XML: " + content, Label.CONTENT_XML)); - w.addComponent(new Label("CONTENT_XHTML: " + content, - Label.CONTENT_XHTML)); + ContentMode.PREFORMATTED)); + w.addComponent(new Label("CONTENT_RAW: " + content, ContentMode.RAW)); + w.addComponent(new Label("CONTENT_TEXT: " + content, ContentMode.TEXT)); + w.addComponent(new Label("CONTENT_XML: " + content, ContentMode.XML)); + w.addComponent(new Label("CONTENT_XHTML: " + content, ContentMode.XHTML)); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2431.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2431.java index e1eb2531f2..b751488bae 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2431.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2431.java @@ -7,14 +7,14 @@ import com.vaadin.event.ShortcutAction; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutAction.ModifierKey; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2431 extends Application { +public class Ticket2431 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); Label help = new Label( "Use CTRL X to fire action, CTRL C to remove it (fails before fix)"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2432.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2432.java index 326f27d58a..2716038873 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2432.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2432.java @@ -8,14 +8,14 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.Layout.AlignmentHandler; import com.vaadin.ui.Layout.SpacingHandler; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2432 extends Application { +public class Ticket2432 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); w.getContent().setSizeFull(); ((SpacingHandler) w.getContent()).setSpacing(true); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2434.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2434.java index 5d4a884895..79e383393f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2434.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2434.java @@ -2,15 +2,15 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.tests.TestForTablesInitialColumnWidthLogicRendering; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class Ticket2434 extends Application { +public class Ticket2434 extends Application.LegacyApplication { @Override public void init() { - Window w = new Window(); + LegacyWindow w = new LegacyWindow(); setMainWindow(w); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2436.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2436.java index 0d8c5ad2dd..fc6445d62f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2436.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2436.java @@ -4,13 +4,13 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.PopupView; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket2436 extends Application { +public class Ticket2436 extends Application.LegacyApplication { @Override public void init() { - final Window main = new Window(); + final LegacyWindow main = new LegacyWindow(); setMainWindow(main); final Button remover = new Button("Remove PopupView"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2440.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2440.java deleted file mode 100644 index cd1e8e682e..0000000000 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2440.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.vaadin.tests.tickets; - -import java.net.URL; - -import com.vaadin.Application; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.ExternalResource; -import com.vaadin.terminal.URIHandler; -import com.vaadin.ui.Label; -import com.vaadin.ui.Link; -import com.vaadin.ui.Window; - -public class Ticket2440 extends Application { - - @Override - public void init() { - final Window main = new MainWindow(); - setMainWindow(main); - main.addComponent(new Label( - "Clicking the link should open a new window that should receive the URI 'msg/hello' and add that a a Label to it's ui. Currently the Label ends up in this (main) window (try reloading). Console intentionally spams during the window finding/uri handling - looks, uhm, interesting.")); - } - - @Override - public Window getWindow(String name) { - System.err.println("Looking for " + name); - if ("msg".equals(name)) { - System.err - .println(" rest uri, returning new MainWindow with message from uri"); - MainWindow restWindow = new MainWindow(); - addWindow(restWindow); - return restWindow; - } - // If we already have the requested window, use it - Window w = super.getWindow(name); - if (w == null) { - // If no window found, create it - System.err.println(" new win"); - w = new MainWindow(); - w.setName(name); - addWindow(w); - return w; - } else { - System.err.println(" found win"); - return w; - } - - } - - private class MainWindow extends Window { - public MainWindow() { - super("Main window"); - - addComponent(new Link("new mainwin", new ExternalResource( - Ticket2440.this.getURL() + "msg/hello"), "_blank", -1, -1, - Window.BORDER_DEFAULT)); - - addURIHandler(new URIHandler() { - public DownloadStream handleURI(URL context, String relativeUri) { - System.err - .println((getMainWindow() == getWindow() ? "mainwin: " - : "subwin: ") - + context + ", " + relativeUri); - addComponent(new Label(relativeUri)); - return null; - } - }); - } - - @Override - public DownloadStream handleURI(URL context, String relativeUri) { - System.err.println("MainWindow.handleURI();"); - return super.handleURI(context, relativeUri); - } - - } - -} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2526.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2526.java index 5fc06c27bf..8123fe1182 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2526.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2526.java @@ -3,13 +3,14 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Window; -public class Ticket2526 extends Application { +public class Ticket2526 extends Application.LegacyApplication { @Override public void init() { - final Window main = new Window(); + final LegacyWindow main = new LegacyWindow(); setMainWindow(main); Button b = new Button("Add windows"); b.addListener(new Button.ClickListener() { diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2742.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2742.java index d656b0205c..1003ea1c66 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2742.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2742.java @@ -6,13 +6,13 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.NativeSelect; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; /** * @author Risto Yrjänä / Vaadin Ltd. * */ -public class Ticket2742 extends Application { +public class Ticket2742 extends Application.LegacyApplication { /* * (non-Javadoc) @@ -21,7 +21,7 @@ public class Ticket2742 extends Application { */ @Override public void init() { - Window mainWindow = new Window(); + LegacyWindow mainWindow = new LegacyWindow(); setMainWindow(mainWindow); String shortString = "Short"; @@ -39,4 +39,4 @@ public class Ticket2742 extends Application { mainWindow.addComponent(hl); } -}
\ No newline at end of file +} diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2901.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2901.java index 9e28908c22..ab808501f7 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2901.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2901.java @@ -2,21 +2,22 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; -import com.vaadin.ui.Window; /** * With IE7 extra scrollbars appear in content area all though content fits * properly. Scrollbars will disappear if "shaking" content a bit, like * selecting tests in area. */ -public class Ticket2901 extends Application { +public class Ticket2901 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window("Test app to break layout in IE6"); + final LegacyWindow mainWin = new LegacyWindow( + "Test app to break layout in IE6"); setMainWindow(mainWin); VerticalSplitPanel sp = new VerticalSplitPanel(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket2998.java b/tests/testbench/com/vaadin/tests/tickets/Ticket2998.java index c37a9362d6..6cf5c8f754 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket2998.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket2998.java @@ -21,6 +21,7 @@ import com.vaadin.ui.FormLayout; import com.vaadin.ui.Layout; import com.vaadin.ui.ListSelect; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; @@ -35,7 +36,7 @@ import com.vaadin.ui.themes.Reindeer; * * Other browsers are much faster. */ -public class Ticket2998 extends Application { +public class Ticket2998 extends Application.LegacyApplication { private Table table; private VerticalLayout mainLayout; @@ -129,7 +130,7 @@ public class Ticket2998 extends Application { close(); } else { date.setValue(run.getDate()); - kilomiters.setValue(run.getKilometers()); + kilomiters.setValue(String.valueOf(run.getKilometers())); title.setValue(run.getTitle()); if (getParent() == null) { workoutLog.getMainWindow().addWindow(this); @@ -145,7 +146,7 @@ public class Ticket2998 extends Application { } @Override - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { /* @@ -162,7 +163,7 @@ public class Ticket2998 extends Application { return getSecondaryTypesList(itemId); } - final Field f = super.createField(container, itemId, propertyId, + final Field<?> f = super.createField(container, itemId, propertyId, uiContext); if (f != null) { if (f instanceof TextField) { @@ -172,24 +173,19 @@ public class Ticket2998 extends Application { if (propertyId.equals("kilometers")) { f.setWidth("4em"); f.addValidator(new Validator() { - public boolean isValid(Object value) { + public void validate(Object value) + throws InvalidValueException { + // FIXME this does not follow the standard pattern + // for validators and has side effects! try { @SuppressWarnings("unused") float f = Float.parseFloat((String) value); - return true; } catch (Exception e) { - f.getWindow().showNotification( - "Bad number value"); + f.getRoot() + .showNotification("Bad number value"); f.setValue(0); - return false; } } - - public void validate(Object value) - throws InvalidValueException { - // TODO Auto-generated method stub - - } }); } if (propertyId.equals("date")) { @@ -202,7 +198,7 @@ public class Ticket2998 extends Application { private Map<Object, ListSelect> workoutIdToList = new HashMap<Object, ListSelect>(); - private Field getSecondaryTypesList(Object itemId) { + private Field<?> getSecondaryTypesList(Object itemId) { ListSelect list = workoutIdToList.get(itemId); if (list == null) { list = new ListSelect(); @@ -221,7 +217,7 @@ public class Ticket2998 extends Application { private Map<Object, ComboBox> workoutIdToCombobox = new HashMap<Object, ComboBox>(); - private Field getTrainingTypeComboboxFor(Object itemId) { + private Field<?> getTrainingTypeComboboxFor(Object itemId) { ComboBox cb = workoutIdToCombobox.get(itemId); if (cb == null) { final ComboBox cb2 = new ComboBox(); @@ -250,7 +246,7 @@ public class Ticket2998 extends Application { */ private void buildView() { - final Window w = new Window("Workout Log"); + final LegacyWindow w = new LegacyWindow("Workout Log"); // set theme and some layout stuff setMainWindow(w); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket3146.java b/tests/testbench/com/vaadin/tests/tickets/Ticket3146.java index f4dc1d59e4..924b1318ab 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket3146.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket3146.java @@ -6,18 +6,18 @@ import java.util.HashSet; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket3146 extends Application { +public class Ticket3146 extends Application.LegacyApplication { Table table; TextField result; @Override public void init() { - Window mainWindow = new Window("Test"); + LegacyWindow mainWindow = new LegacyWindow("Test"); table = new Table(); table.addContainerProperty("Items", String.class, null); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket34.java b/tests/testbench/com/vaadin/tests/tickets/Ticket34.java index 7d3baf78fa..1c55bcbe7d 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket34.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket34.java @@ -9,46 +9,39 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root; +import com.vaadin.ui.Root.FragmentChangedEvent; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.UriFragmentUtility; -import com.vaadin.ui.UriFragmentUtility.FragmentChangedEvent; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Ticket34 extends Application { +public class Ticket34 extends Application.LegacyApplication { private Map<String, Component> views = new HashMap<String, Component>(); private VerticalLayout mainLayout; private Component currentView; - private UriFragmentUtility reader; @Override public void init() { buildViews(new String[] { "main", "view2", "view3" }); - reader = new UriFragmentUtility(); - reader.addListener(new UriFragmentUtility.FragmentChangedListener() { + mainLayout = new VerticalLayout(); + mainLayout.setSizeFull(); + final LegacyWindow mainWin = new LegacyWindow( + "Test app for URI fragment management/reading", mainLayout); + setMainWindow(mainWin); + + mainWin.addListener(new Root.FragmentChangedListener() { public void fragmentChanged(FragmentChangedEvent event) { getMainWindow().showNotification( - "Fragment now: " - + event.getUriFragmentUtility().getFragment()); + "Fragment now: " + event.getFragment()); // try to change to view mapped by fragment string - setView(event.getUriFragmentUtility().getFragment()); + setView(event.getFragment()); } }); - mainLayout = new VerticalLayout(); - mainLayout.setSizeFull(); - final Window mainWin = new Window( - "Test app for URI fragment management/reading", mainLayout); - setMainWindow(mainWin); - - // UriFragmentReader is 0px size by default, so it will not render - // anything on screen - mainLayout.addComponent(reader); - setView("main"); } @@ -100,7 +93,7 @@ public class Ticket34 extends Application { public void buttonClick(ClickEvent event) { String viewName = tf.getValue().toString(); // fragmentChangedListener will change the view if possible - reader.setFragment(viewName); + event.getButton().getRoot().setFragment(viewName); } }); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket5053.java b/tests/testbench/com/vaadin/tests/tickets/Ticket5053.java index 2f5bade03a..35f244e07f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket5053.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket5053.java @@ -2,16 +2,16 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.ComboBox; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; /** * #5053: Last ComboBox item may not be shown if null selection enabled */ -public class Ticket5053 extends Application { +public class Ticket5053 extends Application.LegacyApplication { @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); ComboBox combobox = new ComboBox("My ComboBox"); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket5157.java b/tests/testbench/com/vaadin/tests/tickets/Ticket5157.java index c5049f67c0..5902382d01 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket5157.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket5157.java @@ -5,8 +5,8 @@ import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutListener; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; /** * Key codes were converted to lower case on the server (overlapping special key @@ -14,11 +14,12 @@ import com.vaadin.ui.Window; * Therefore, registering e.g. F8 as a key code resulted in "w" being used as * the trigger and F8 being ignored. */ -public class Ticket5157 extends Application { +public class Ticket5157 extends Application.LegacyApplication { @Override public void init() { - final Window mainWindow = new Window("Forumtests Application"); + final LegacyWindow mainWindow = new LegacyWindow( + "Forumtests Application"); setMainWindow(mainWindow); Panel p = new Panel(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket5952.java b/tests/testbench/com/vaadin/tests/tickets/Ticket5952.java index cd2b3a70e6..3c0c549f1f 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket5952.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket5952.java @@ -2,29 +2,29 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; import com.vaadin.ui.Label; -import com.vaadin.ui.Window; +import com.vaadin.ui.Label.ContentMode; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket5952 extends Application { +public class Ticket5952 extends Application.LegacyApplication { @Override public void init() { - final Window mainWindow = new Window("Forumtests Application"); + final LegacyWindow mainWindow = new LegacyWindow( + "Forumtests Application"); setMainWindow(mainWindow); - - String mathml = - "<math mode='display' xmlns='http://www.w3.org/1998/Math/MathML'>"+ - "<mrow>"+ - " <msup>"+ - " <mi>x</mi>"+ - " <mn>2</mn>"+ - " </msup>"+ - " <msup>"+ - " <mi>c</mi>"+ - " <mn>2</mn>"+ - " </msup>"+ - " </mrow>"+ - "</math>"; - Label mathLabel = new Label(mathml, Label.CONTENT_XML); + + String mathml = "<math mode='display' xmlns='http://www.w3.org/1998/Math/MathML'>" + + "<mrow>" + + " <msup>" + + " <mi>x</mi>" + + " <mn>2</mn>" + + " </msup>" + + " <msup>" + + " <mi>c</mi>" + + " <mn>2</mn>" + + " </msup>" + + " </mrow>" + "</math>"; + Label mathLabel = new Label(mathml, ContentMode.XML); mainWindow.addComponent(mathLabel); } } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket6002.java b/tests/testbench/com/vaadin/tests/tickets/Ticket6002.java index bd6a8e2b7c..0875e3de48 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket6002.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket6002.java @@ -5,15 +5,15 @@ import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.util.ObjectProperty; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class Ticket6002 extends TestBase { @Override public void setup() { - Window main = new Window("The Main Window"); + LegacyWindow main = new LegacyWindow("The Main Window"); setMainWindow(main); final VerticalLayout mainLayout = new VerticalLayout(); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket677.java b/tests/testbench/com/vaadin/tests/tickets/Ticket677.java index f2a1ae1664..bf7aa7bc36 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket677.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket677.java @@ -15,12 +15,13 @@ import com.vaadin.ui.Form; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket677 extends Application { +public class Ticket677 extends Application.LegacyApplication { private static final Label info = new Label( "<li> keep debug window open to see variable changes" @@ -30,7 +31,7 @@ public class Ticket677 extends Application { + "<li> focusing should fail (try tabbing as well) [worked previousy]" + "<li> no variable changes should be sent from disabled fields [changed sent previously]" + "<li> try further toggling and tabbing around", - Label.CONTENT_RAW); + ContentMode.RAW); Panel root = new Panel("Enabled"); Panel one = new Panel("Enabled"); @@ -40,7 +41,7 @@ public class Ticket677 extends Application { @Override public void init() { - Window main = new Window(); + LegacyWindow main = new LegacyWindow(); setMainWindow(main); main.addComponent(info); @@ -111,9 +112,9 @@ public class Ticket677 extends Application { form.setFormFieldFactory(new DefaultFieldFactory() { @Override - public Field createField(Item item, Object propertyId, + public Field<?> createField(Item item, Object propertyId, Component uiContext) { - Field f = super.createField(item, propertyId, uiContext); + Field<?> f = super.createField(item, propertyId, uiContext); f.setEnabled(!"disabled".equals(propertyId)); return f; } @@ -127,19 +128,19 @@ public class Ticket677 extends Application { table.addContainerProperty("Text", String.class, null); for (int i = 0; i < 150; i++) { Item item = table.addItem("Item" + i); - Property p = item.getItemProperty("Text"); + Property<?> p = item.getItemProperty("Text"); p.setValue(i % 5 == 0 ? "enabled" : "disabled"); } table.setTableFieldFactory(new DefaultFieldFactory() { @Override - public Field createField(Container container, Object itemId, + public Field<?> createField(Container container, Object itemId, Object propertyId, Component uiContext) { - Field f = super.createField(container, itemId, propertyId, + Field<?> f = super.createField(container, itemId, propertyId, uiContext); Item item = container.getItem(itemId); - Property p = item.getItemProperty(propertyId); + Property<?> p = item.getItemProperty(propertyId); if ("disabled".equals(p.getValue())) { f.setEnabled(false); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket695.java b/tests/testbench/com/vaadin/tests/tickets/Ticket695.java index f122031b6e..11d643cd52 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket695.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket695.java @@ -7,14 +7,14 @@ import java.io.ObjectOutputStream; import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; @SuppressWarnings("serial") -public class Ticket695 extends Application { +public class Ticket695 extends Application.LegacyApplication { @Override public void init() { - final Window w = new Window("Serialization test #695"); + final LegacyWindow w = new LegacyWindow("Serialization test #695"); setMainWindow(w); Button b = new Button("Serialize ApplicationContext"); w.addComponent(b); diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket736.java b/tests/testbench/com/vaadin/tests/tickets/Ticket736.java index c530b7ca99..091e0c97af 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket736.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket736.java @@ -4,28 +4,30 @@ import com.vaadin.Application; import com.vaadin.data.Validator; import com.vaadin.data.util.BeanItem; import com.vaadin.data.util.MethodProperty; +import com.vaadin.data.validator.IntegerValidator; import com.vaadin.terminal.ThemeResource; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CheckBox; import com.vaadin.ui.Form; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root.LegacyWindow; -public class Ticket736 extends Application { +public class Ticket736 extends Application.LegacyApplication { Address address = new Address(); @Override public void init() { - final Window mainWin = new Window("Test app for #736"); + final LegacyWindow mainWin = new LegacyWindow("Test app for #736"); setMainWindow(mainWin); - mainWin.setTheme("runo"); + setTheme("runo"); // Create form for editing address final Form f = new Form(); @@ -37,10 +39,20 @@ public class Ticket736 extends Application { mainWin.addComponent(f); // Select to use buffered mode for editing to enable commit and discard - f.setWriteThrough(false); - f.setReadThrough(false); - Button commit = new Button("Commit", f, "commit"); - Button discard = new Button("Discard", f, "discard"); + f.setBuffered(true); + Button commit = new Button("Commit", new ClickListener() { + + public void buttonClick(ClickEvent event) { + f.commit(); + } + }); + Button discard = new Button("Discard", new ClickListener() { + + public void buttonClick(ClickEvent event) { + f.discard(); + } + + }); HorizontalLayout ol = new HorizontalLayout(); ol.setHeight("3em"); ol.addComponent(commit); @@ -49,8 +61,9 @@ public class Ticket736 extends Application { f.setFooter(ol); // Add some validators for the form - f.getField("zip").addValidator(new IsInteger()); - f.getField("zip").setDescription("Jepjep"); + f.getField("zip").addValidator( + new IntegerValidator("'{0}' is not a number")); + ((AbstractComponent) f.getField("zip")).setDescription("Jepjep"); ((AbstractComponent) f.getField("zip")).setIcon(new ThemeResource( "../runo/icons/16/folder.png")); f.getField("state").addValidator(new IsValidState()); @@ -84,7 +97,7 @@ public class Ticket736 extends Application { } /** Address pojo. */ - public class Address { + public static class Address { String name = ""; String street = ""; String zip = ""; @@ -148,44 +161,18 @@ public class Ticket736 extends Application { } - /** Simple validator for checking if the validated value is an integer */ - class IsInteger implements Validator { - - public boolean isValid(Object value) { - try { - Integer.parseInt("" + value); - return true; - } catch (NumberFormatException e) { - return false; - } - } - - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { - throw new InvalidValueException("'" + value - + "' is not a number"); - } - } - } - /** Simple state validator */ - class IsValidState implements Validator { + static class IsValidState implements Validator { - public boolean isValid(Object value) { + public void validate(Object value) throws InvalidValueException { // Empty and null are accepted values if (value == null || "".equals("" + value)) { - return true; + return; } // Otherwise state must be two capital letter combo - if (value.toString().length() != 2) { - return false; - } - return value.toString().equals(("" + value).toUpperCase()); - } - - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { + if (value.toString().length() != 2 + || !value.toString().equals(("" + value).toUpperCase())) { throw new InvalidValueException( "State must be either two capital letter abreviation or left empty"); } diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket846.java b/tests/testbench/com/vaadin/tests/tickets/Ticket846.java index 23f3134308..714b3c21ca 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket846.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket846.java @@ -1,41 +1,25 @@ package com.vaadin.tests.tickets; import com.vaadin.Application; -import com.vaadin.data.Validator; import com.vaadin.data.util.MethodProperty; +import com.vaadin.data.validator.IntegerValidator; import com.vaadin.ui.Button; import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket846 extends Application { +public class Ticket846 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window("Test app for #846"); + final LegacyWindow mainWin = new LegacyWindow("Test app for #846"); setMainWindow(mainWin); final TextField tx = new TextField("Integer"); mainWin.addComponent(tx); tx.setImmediate(true); - tx.addValidator(new Validator() { - - public boolean isValid(Object value) { - try { - Integer.parseInt("" + value); - return true; - } catch (NumberFormatException e) { - return false; - } - } - - public void validate(Object value) throws InvalidValueException { - if (!isValid(value)) { - throw new InvalidValueException(value + " is not a number"); - } - } - }); + tx.addValidator(new IntegerValidator("{0} is not a number")); final String[] visibleProps = { "required", "invalidAllowed", "readOnly", "readThrough", "invalidCommitted", diff --git a/tests/testbench/com/vaadin/tests/tickets/Ticket932.java b/tests/testbench/com/vaadin/tests/tickets/Ticket932.java index a9333b5e0f..bf6f6d1879 100644 --- a/tests/testbench/com/vaadin/tests/tickets/Ticket932.java +++ b/tests/testbench/com/vaadin/tests/tickets/Ticket932.java @@ -4,16 +4,17 @@ import com.vaadin.Application; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; -import com.vaadin.ui.Window; -public class Ticket932 extends Application { +public class Ticket932 extends Application.LegacyApplication { @Override public void init() { - final Window mainWin = new Window("Test app for max length feature"); + final LegacyWindow mainWin = new LegacyWindow( + "Test app for max length feature"); setMainWindow(mainWin); final TextField tx = new TextField( diff --git a/tests/testbench/com/vaadin/tests/util/Address.java b/tests/testbench/com/vaadin/tests/util/Address.java new file mode 100644 index 0000000000..5ef0669e1b --- /dev/null +++ b/tests/testbench/com/vaadin/tests/util/Address.java @@ -0,0 +1,66 @@ +package com.vaadin.tests.util; + +import java.io.Serializable; + +@SuppressWarnings("serial") +public class Address implements Serializable { + + private String streetAddress = ""; + private Integer postalCode = null; + private String city = ""; + + public Address() { + } + + public Address(String streetAddress, int postalCode, String city) { + setStreetAddress(streetAddress); + setPostalCode(postalCode); + setCity(city); + } + + /** + * @return the streetAddress + */ + public String getStreetAddress() { + return streetAddress; + } + + /** + * @param streetAddress + * the streetAddress to set + */ + public void setStreetAddress(String streetAddress) { + this.streetAddress = streetAddress; + } + + /** + * @return the postalCode + */ + public Integer getPostalCode() { + return postalCode; + } + + /** + * @param postalCode + * the postalCode to set + */ + public void setPostalCode(Integer postalCode) { + this.postalCode = postalCode; + } + + /** + * @return the city + */ + public String getCity() { + return city; + } + + /** + * @param city + * the city to set + */ + public void setCity(String city) { + this.city = city; + } + +} diff --git a/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java b/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java new file mode 100644 index 0000000000..ddb58999ee --- /dev/null +++ b/tests/testbench/com/vaadin/tests/util/AlwaysFailValidator.java @@ -0,0 +1,23 @@ +package com.vaadin.tests.util; + +import com.vaadin.data.validator.AbstractValidator; + +public class AlwaysFailValidator extends AbstractValidator<Object> { + public AlwaysFailValidator() { + super("Validation error"); + } + + public AlwaysFailValidator(String message) { + super(message); + } + + @Override + protected boolean isValidValue(Object value) { + return false; + } + + @Override + public Class getType() { + return Object.class; + } +} diff --git a/tests/testbench/com/vaadin/tests/util/Log.java b/tests/testbench/com/vaadin/tests/util/Log.java index 4eef48a789..fca858cb15 100644 --- a/tests/testbench/com/vaadin/tests/util/Log.java +++ b/tests/testbench/com/vaadin/tests/util/Log.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.VerticalLayout; public class Log extends VerticalLayout { @@ -49,7 +50,7 @@ public class Log extends VerticalLayout { } private Label createEventLabel() { - Label l = new Label(" ", Label.CONTENT_XHTML); + Label l = new Label(" ", ContentMode.XHTML); l.setWidth(null); return l; } diff --git a/tests/testbench/com/vaadin/tests/util/Millionaire.java b/tests/testbench/com/vaadin/tests/util/Millionaire.java new file mode 100644 index 0000000000..44d4def416 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/util/Millionaire.java @@ -0,0 +1,22 @@ +package com.vaadin.tests.util; + +import java.util.ArrayList; +import java.util.List; + +public class Millionaire extends Person { + private List<Address> secondaryResidences = new ArrayList<Address>(); + + public Millionaire() { + } + + public Millionaire(String firstName, String lastName, String email, + String phoneNumber, String streetAddress, int postalCode, + String city) { + super(firstName, lastName, email, phoneNumber, streetAddress, + postalCode, city); + } + + public List<Address> getSecondaryResidences() { + return secondaryResidences; + } +} diff --git a/tests/testbench/com/vaadin/tests/util/Person.java b/tests/testbench/com/vaadin/tests/util/Person.java index c3e7a69d56..72f6b7d20d 100644 --- a/tests/testbench/com/vaadin/tests/util/Person.java +++ b/tests/testbench/com/vaadin/tests/util/Person.java @@ -8,12 +8,10 @@ public class Person implements Serializable { private String lastName = ""; private String email = ""; private String phoneNumber = ""; - private String streetAddress = ""; - private Integer postalCode = null; - private String city = ""; + private Address address = new Address(); public Person() { - + address = new Address(); } public Person(String firstName, String lastName, String email, @@ -23,9 +21,7 @@ public class Person implements Serializable { setLastName(lastName); setEmail(email); setPhoneNumber(phoneNumber); - setStreetAddress(streetAddress); - setPostalCode(postalCode); - setCity(city); + address = new Address(streetAddress, postalCode, city); } /** @@ -89,48 +85,12 @@ public class Person implements Serializable { } /** - * @return the streetAddress - */ - public String getStreetAddress() { - return streetAddress; - } - - /** - * @param streetAddress - * the streetAddress to set - */ - public void setStreetAddress(String streetAddress) { - this.streetAddress = streetAddress; - } - - /** - * @return the postalCode - */ - public Integer getPostalCode() { - return postalCode; - } - - /** - * @param postalCode - * the postalCode to set - */ - public void setPostalCode(Integer postalCode) { - this.postalCode = postalCode; - } - - /** - * @return the city - */ - public String getCity() { - return city; - } - - /** - * @param city - * the city to set + * Returns the address where the person lives. + * + * @return address (not null) */ - public void setCity(String city) { - this.city = city; + public Address getAddress() { + return address; } }
\ No newline at end of file diff --git a/tests/testbench/com/vaadin/tests/util/PersonContainer.java b/tests/testbench/com/vaadin/tests/util/PersonContainer.java index 8195b4d5f0..a3cf28b083 100644 --- a/tests/testbench/com/vaadin/tests/util/PersonContainer.java +++ b/tests/testbench/com/vaadin/tests/util/PersonContainer.java @@ -13,8 +13,8 @@ public class PersonContainer extends BeanItemContainer<Person> implements * Natural property order for Person bean. Used in tables and forms. */ public static final Object[] NATURAL_COL_ORDER = new Object[] { - "firstName", "lastName", "email", "phoneNumber", "streetAddress", - "postalCode", "city" }; + "firstName", "lastName", "email", "phoneNumber", + "address.streetAddress", "address.postalCode", "address.city" }; /** * "Human readable" captions for properties in same order as in @@ -27,6 +27,9 @@ public class PersonContainer extends BeanItemContainer<Person> implements public PersonContainer() throws InstantiationException, IllegalAccessException { super(Person.class); + addNestedContainerProperty("address.streetAddress"); + addNestedContainerProperty("address.postalCode"); + addNestedContainerProperty("address.city"); } public static PersonContainer createWithTestData() { @@ -67,7 +70,7 @@ public class PersonContainer extends BeanItemContainer<Person> implements Person p = new Person(); p.setFirstName(fnames[r.nextInt(fnames.length)]); p.setLastName(lnames[r.nextInt(lnames.length)]); - p.setCity(cities[r.nextInt(cities.length)]); + p.getAddress().setCity(cities[r.nextInt(cities.length)]); p.setEmail(p.getFirstName().toLowerCase() + "." + p.getLastName().toLowerCase() + "@vaadin.com"); p.setPhoneNumber("+358 02 555 " + r.nextInt(10) + r.nextInt(10) @@ -76,8 +79,9 @@ public class PersonContainer extends BeanItemContainer<Person> implements if (n < 10000) { n += 10000; } - p.setPostalCode(n); - p.setStreetAddress(streets[r.nextInt(streets.length)]); + p.getAddress().setPostalCode(n); + p.getAddress().setStreetAddress( + streets[r.nextInt(streets.length)]); c.addItem(p); } } catch (InstantiationException e) { diff --git a/tests/testbench/com/vaadin/tests/util/Role.java b/tests/testbench/com/vaadin/tests/util/Role.java new file mode 100644 index 0000000000..83f63db4ab --- /dev/null +++ b/tests/testbench/com/vaadin/tests/util/Role.java @@ -0,0 +1,37 @@ +package com.vaadin.tests.util; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +public class Role implements Serializable { + private String name = ""; + private Set<User> users = new HashSet<User>(); + + public Role() { + } + + public Role(String name) { + setName(name); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * In this direction, the users for a role can be queried and the returned + * collection modified, but the whole collection of users cannot be set + * directly. + * + * @return set of users having the role (not null) + */ + public Set<User> getUsers() { + return users; + } + +} diff --git a/tests/testbench/com/vaadin/tests/util/SampleDirectory.java b/tests/testbench/com/vaadin/tests/util/SampleDirectory.java index f97c3c0740..a1f3202cea 100644 --- a/tests/testbench/com/vaadin/tests/util/SampleDirectory.java +++ b/tests/testbench/com/vaadin/tests/util/SampleDirectory.java @@ -9,7 +9,9 @@ import java.io.File; import com.vaadin.Application; import com.vaadin.terminal.SystemError; import com.vaadin.ui.Label; +import com.vaadin.ui.Label.ContentMode; import com.vaadin.ui.Panel; +import com.vaadin.ui.Root; /** * Provides sample directory based on application directory. If this fails then @@ -27,7 +29,7 @@ public class SampleDirectory { * @param application * @return file pointing to sample directory */ - public static File getDirectory(Application application) { + public static File getDirectory(Application application, Root root) { String errorMessage = "Access to application " + "context base directory failed, " + "possible security constraint with Application " @@ -63,11 +65,11 @@ public class SampleDirectory { errorPanel.setStyleName("strong"); errorPanel.setComponentError(new SystemError( "Cannot provide sample directory")); - errorPanel.addComponent(new Label(errorMessage, Label.CONTENT_XHTML)); + errorPanel.addComponent(new Label(errorMessage, ContentMode.XHTML)); // Remove all components from applications main window - application.getMainWindow().getContent().removeAllComponents(); + root.getContent().removeAllComponents(); // Add error panel - application.getMainWindow().getContent().addComponent(errorPanel); + root.getContent().addComponent(errorPanel); return null; } } diff --git a/tests/testbench/com/vaadin/tests/util/TestUtils.java b/tests/testbench/com/vaadin/tests/util/TestUtils.java index aed69055c7..551e7a7ed8 100644 --- a/tests/testbench/com/vaadin/tests/util/TestUtils.java +++ b/tests/testbench/com/vaadin/tests/util/TestUtils.java @@ -2,7 +2,7 @@ package com.vaadin.tests.util; import com.vaadin.data.Item; import com.vaadin.data.util.IndexedContainer; -import com.vaadin.ui.Window; +import com.vaadin.ui.Root; public class TestUtils { @@ -102,7 +102,7 @@ public class TestUtils { * * @param cssString */ - public static void injectCSS(Window w, String cssString) { + public static void injectCSS(Root w, String cssString) { String script = "if ('\\v'=='v') /* ie only */ {\n" + " document.createStyleSheet().cssText = '" + cssString diff --git a/tests/testbench/com/vaadin/tests/util/User.java b/tests/testbench/com/vaadin/tests/util/User.java new file mode 100644 index 0000000000..003f485017 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/util/User.java @@ -0,0 +1,54 @@ +package com.vaadin.tests.util; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class User implements Serializable { + private String name = ""; + private Set<Role> roles = new HashSet<Role>(); + + public User() { + } + + public User(String name) { + setName(name); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * Returns an unmodifiable set of roles. To modify the roles a user has, + * replace the whole set using {@link #setRoles(Set)}. + * + * @return set of roles (unmodifiable, not null) + */ + public Set<Role> getRoles() { + return Collections.unmodifiableSet(roles); + } + + /** + * Replaces the set of roles with another collection. User references in + * roles are automatically updated when setting the roles of a user. + * + * @param roles + * non-null set of roles + */ + public void setRoles(Set<Role> roles) { + for (Role role : this.roles) { + role.getUsers().remove(this); + } + this.roles = roles; + for (Role role : this.roles) { + role.getUsers().add(this); + } + } + +} diff --git a/tests/testbench/com/vaadin/tests/validation/EmptyFieldErrorIndicators.java b/tests/testbench/com/vaadin/tests/validation/EmptyFieldErrorIndicators.java index af48f92f5c..8fb0c3585d 100644 --- a/tests/testbench/com/vaadin/tests/validation/EmptyFieldErrorIndicators.java +++ b/tests/testbench/com/vaadin/tests/validation/EmptyFieldErrorIndicators.java @@ -3,8 +3,8 @@ package com.vaadin.tests.validation; import java.util.Date; import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.data.validator.AbstractValidator; import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.AlwaysFailValidator; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; @@ -45,7 +45,6 @@ public class EmptyFieldErrorIndicators extends TestBase { panel.setSizeFull(); panel.setStyleName(Reindeer.PANEL_LIGHT); panel.addComponent(hl); - panel.setScrollable(true); addComponent(panel); } @@ -77,16 +76,12 @@ public class EmptyFieldErrorIndicators extends TestBase { // hand-crafted form, not using form field factory final Form form = new Form() { @Override - public void addField(Object propertyId, Field field) { + public void addField(Object propertyId, Field<?> field) { super.addField(propertyId, field); field.setRequired(required); field.setRequiredError("Missing required value!"); if (failValidator && !(field instanceof Button)) { - field.addValidator(new AbstractValidator("Validation error") { - public boolean isValid(Object value) { - return false; - } - }); + field.addValidator(new AlwaysFailValidator()); } } }; @@ -98,7 +93,8 @@ public class EmptyFieldErrorIndicators extends TestBase { // same as basic DateField // form.addField("Popup Date", new PopupDateField("Date")); Button setDateButton = new Button("Set date"); - form.addField("Set Date", setDateButton); + form.getLayout().addComponent(setDateButton); + // form.addField("Set Date", setDateButton); setDateButton.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { form.getField("Date").setValue(new Date(0)); diff --git a/tests/testbench/com/vaadin/tests/validation/RequiredErrorMessage.java b/tests/testbench/com/vaadin/tests/validation/RequiredErrorMessage.java index 7f5048bd80..e18b8ffd4e 100644 --- a/tests/testbench/com/vaadin/tests/validation/RequiredErrorMessage.java +++ b/tests/testbench/com/vaadin/tests/validation/RequiredErrorMessage.java @@ -2,9 +2,9 @@ package com.vaadin.tests.validation; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Form; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; public class RequiredErrorMessage extends TestBase { @@ -21,7 +21,7 @@ public class RequiredErrorMessage extends TestBase { @Override public void setup() { - final Window main = new Window(getClass().getName()); + final LegacyWindow main = new LegacyWindow(getClass().getName()); setMainWindow(main); final Form form = new Form(new VerticalLayout()); diff --git a/tests/testbench/com/vaadin/tests/validation/TestValidators.java b/tests/testbench/com/vaadin/tests/validation/TestValidators.java index 5264d47c9d..a530dee852 100644 --- a/tests/testbench/com/vaadin/tests/validation/TestValidators.java +++ b/tests/testbench/com/vaadin/tests/validation/TestValidators.java @@ -3,6 +3,7 @@ package com.vaadin.tests.validation; import com.vaadin.data.Validator; import com.vaadin.data.validator.AbstractStringValidator; import com.vaadin.data.validator.CompositeValidator; +import com.vaadin.data.validator.CompositeValidator.CombinationMode; import com.vaadin.data.validator.DoubleValidator; import com.vaadin.data.validator.EmailValidator; import com.vaadin.data.validator.IntegerValidator; @@ -13,9 +14,9 @@ import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Form; +import com.vaadin.ui.Notification; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window.Notification; public class TestValidators extends TestBase { @@ -96,8 +97,7 @@ public class TestValidators extends TestBase { // TODO CompositeValidator tf = new TextField( "A field, must be a floating point number with 4-5 chars"); - CompositeValidator cv = new CompositeValidator( - CompositeValidator.MODE_AND, + CompositeValidator cv = new CompositeValidator(CombinationMode.AND, "The field must contain a floating point number with 4-5 characters"); cv.addValidator(new StringLengthValidator( "String length of '{0}' should be 4-5 characters", 4, 5, false)); @@ -109,7 +109,7 @@ public class TestValidators extends TestBase { tf = new TextField( "A field, must be a floating point number or 4-5 chars"); - cv = new CompositeValidator(CompositeValidator.MODE_OR, + cv = new CompositeValidator(CombinationMode.OR, "The field must contain a floating point or with 4-5 characters"); cv.addValidator(new StringLengthValidator( "String length of '{0}' should be 4-5 characters", 4, 5, false)); @@ -127,7 +127,7 @@ public class TestValidators extends TestBase { Validator postalCodeValidator = new AbstractStringValidator( "Postal code must be a number 10000-99999.") { @Override - protected boolean isValidString(String value) { + protected boolean isValidValue(String value) { return value.matches("[1-9][0-9]{4}"); } }; diff --git a/tests/testbench/com/vaadin/tests/validation/ValidationOfRequiredEmptyFields.html b/tests/testbench/com/vaadin/tests/validation/ValidationOfRequiredEmptyFields.html index 433ad04ada..cc594882dd 100644 --- a/tests/testbench/com/vaadin/tests/validation/ValidationOfRequiredEmptyFields.html +++ b/tests/testbench/com/vaadin/tests/validation/ValidationOfRequiredEmptyFields.html @@ -58,7 +58,7 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestsvalidationValidationOfRequiredEmptyFields::/VVerticalLayout[0]/domChild[0]/domChild[1]</td> + <td>vaadin=runcomvaadintestsvalidationValidationOfRequiredEmptyFields::/VVerticalLayout[0]</td> <td>34,186</td> </tr> <tr> diff --git a/tests/vaadin-server.xml b/tests/vaadin-server.xml new file mode 100644 index 0000000000..d4d23581ec --- /dev/null +++ b/tests/vaadin-server.xml @@ -0,0 +1,55 @@ +<?xml version="1.0"?> +<project xmlns:antcontrib="antlib:net.sf.antcontrib" + xmlns:ivy="antlib:org.apache.ivy.ant" + name="vaadin-server" + default="deploy-and-start" basedir="."> + + <!-- Import common targets --> + <import file="../build/common.xml" /> + + <target name="check-params"> + <fail unless="output-dir" message="The 'output-dir' (usually build/result/vaadin-xxx) should be given to test script." /> + <fail unless="package.name" message="The 'package.name' property must be defined." /> + <fail unless="package.filename" message="The 'package.filename' property must be defined." /> + <fail unless="testing.testarea" message="The 'testing.testarea' property must be defined." /> + <property name="webroot" value="${testing.testarea}/${package.name}/WebContent" /> + </target> + + <target name="prepare-testing-area" depends="check-params"> + <echo> Package name: ${package.name}</echo> + <echo> Package filename: ${package.filename}</echo> + <echo> Testing area: ${testing.testarea}</echo> + <echo> test-output-dir: ${test-output-dir}</echo> + + <delete dir="${testing.testarea}/${package.name}" /> + <mkdir dir="${testing.testarea}/${package.name}/WebContent" /> + <echo>Extracting Vaadin package ${package.filename} to testing area ${testing.testarea}</echo> + <unzip src="${package.filename}" dest="${testing.testarea}/${package.name}/WebContent" /> + </target> + + <target name="deploy-and-start" depends="init-deps, prepare-testing-area"> + <property name="webroot" value="${testing.testarea}/${package.name}/WebContent"></property> + + <ivy:resolve file="ivy.xml"/> + <ivy:cachepath pathid="server" conf="server" /> + <java classname="com.vaadin.launcher.DemoLauncher" fork="yes" dir="${testing.testarea}/${package.name}" resultproperty="server.start.result"> + <arg value="--nogui=1" /> + <classpath> + <path location="${webroot}/WEB-INF/classes" /> + <fileset dir="${webroot}/WEB-INF/lib/" includes="*.jar" /> + <path refid="server" /> + </classpath> + <jvmarg value="-Demma.coverage.out.file=${testing.testarea}/${package.name}/war.ec"/> + <jvmarg value="-Djava.awt.headless=true"/> + </java> + </target> + + <target name="wait-for-startup"> + <echo>Waiting for Servlet Container to start up.</echo> + <waitfor maxwait="60" maxwaitunit="second" checkevery="5" checkeveryunit="second" timeoutproperty="server.start.failed"> + <http url="http://localhost:8888"/> + </waitfor> + <fail if="server.start.failed" message="Server startup failed" /> + </target> + +</project> |